%run init.ipynb

from qiskit import *
nshots = 8192
qiskit.IBMQ.load_account()
provider = qiskit.IBMQ.get_provider(hub = 'ibm-q-research-2', group = 'federal-uni-sant-1', project = 'main')
simulator = Aer.get_backend('qasm_simulator')
device = provider.get_backend('ibmq_lima')
from qiskit.tools.visualization import plot_histogram
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
from qiskit.tools.monitor import job_monitor, backend_overview, backend_monitor

def qc_ent_dist():
    qc = QuantumCircuit(2, name = 'E dist')
    qc.h([0]); qc.cx(0, 1)
    return qc
qc_ent_dist_ = qc_ent_dist(); qc_ent_dist_.draw(output = 'mpl')

def qc_bb_cb():
    qc = QuantumCircuit(2, name = 'BB->CB')
    qc.cx(0,1); qc.h(0)
    return qc
qc_bb_cb_ = qc_bb_cb(); qc_bb_cb_.draw(output = 'mpl')

def qc_teleport(th, ph, lb):
    qc = QuantumCircuit(3)
    qc_ent_dist_ = qc_ent_dist(); qc.append(qc_ent_dist_, [1, 2]) # distribuição de emaranhamento
    qc.barrier()
    qc.u(th, ph, lb, [0]) # Preparação do estado a ser teletransportado
    qc.barrier()
    qc_bb_cb_ = qc_bb_cb(); qc.append(qc_bb_cb_, [0, 1]) # Base de Bell para base computacional
    qc.barrier()
    qc.cx(1, 2); qc.cz(0, 2) # infor clássica + unitária de Bob
    return qc
qc_teleport_ = qc_teleport(0.1, 0.5, 0); qc_teleport_.decompose().draw(output = 'mpl')

import numpy as np
import math
th, ph, lb = 0, 0, 0; 
rho_teo = np.array([[math.cos(th/2)**2, (math.cos(ph)+1j*math.sin(ph))*math.sin(th/2)*math.cos(th/2)],
                 [(math.cos(ph)+1j*math.sin(ph))*math.sin(th/2)*math.cos(th/2), math.sin(th/2)**2]])
qc_teleport_ = qc_teleport(0.1, 0.5, 0)
qstc = state_tomography_circuits(qc_teleport_, [2])
# simulação
job = qiskit.execute(qstc, Aer.get_backend('qasm_simulator'), shots = nshots)
qstf = StateTomographyFitter(job.result(), qstc)
rho_sim = qstf.fit(method='lstsq')
print('rho_teo = ', rho_teo)
print('rho_sim = ', rho_sim)

# experimento
job = qiskit.execute(qstc, backend = device, shots = nshots)
job_monitor(job)
qstf = StateTomographyFitter(job.result(), qstc)
rho_exp = qstf.fit(method = 'lstsq')
print('rho_exp = ', rho_exp)

F = qiskit.quantum_info.state_fidelity(rho_teo, rho_exp); print('F = ', F)

# variar th em cos(th/2)|0>+exp(i*ph)sin(th/2)|1>

