def qc_alice_encoding(cb):
    from qiskit import QuantumCircuit
    qc = QuantumCircuit(1, name='AE')
    if cb == '00':
        qc.id(0)
    elif cb == '01':
        qc.x(0)
    elif cb == '10':
        qc.z(0)
    elif cb == '11':
        qc.x(0); qc.z(0)
    return qc
cb = '11'
qcae = qc_alice_encoding(cb)
qcae.draw('mpl')

from qiskit import QuantumCircuit # só pra mostrar o circuito quântico
qc = QuantumCircuit(2,2)
qc.h(0)
qc.cx(0,1)
qc.barrier()
qcae = qc_alice_encoding(cb)
qc.append(qcae, [0])
qc.barrier()
qc.cx(0,1)
qc.h(0)
qc.measure([0,1],[0,1])
qc.draw('mpl')

def qc_dense_coding(cb):    
    from qiskit import QuantumCircuit
    qc = QuantumCircuit(2, name='DC')
    qc.h(0); qc.cx(0,1) # compartilha o par emaranhado
    qcae = qc_alice_encoding(cb); qc.append(qcae, [0]) # codificação da Alice
    qc.cx(0,1); qc.h(0)#; qc.measure([0,1],[0,1]) # decodificação, medida na BB, do Bob
    # OBS. Não consegui incluir um subcircuito que contenha medidas
    return qc
from qiskit import QuantumCircuit
qc = QuantumCircuit(2,2)
qcdc = qc_dense_coding('00')
qc.append(qcdc, [0,1])
qc.draw('mpl')

from qiskit import Aer, execute, QuantumCircuit; simulator = Aer.get_backend('qasm_simulator')
nshots = 2**13; from qiskit import QuantumCircuit
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('00'); qc.append(qcdc, [0,1]); qc.measure([0,1],[0,1])
job = execute(qc, backend=simulator, shots=nshots); counts = job.result().get_counts()
from qiskit.tools.visualization import plot_histogram; plot_histogram(counts)

from qiskit import Aer, execute, QuantumCircuit
simulator = Aer.get_backend('qasm_simulator')
nshots = 2**13
from qiskit import QuantumCircuit
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('01'); qc.append(qcdc, [0,1])
qc.measure([0,1],[0,1])
job = execute(qc, backend=simulator, shots=nshots); counts = job.result().get_counts()
from qiskit.tools.visualization import plot_histogram
plot_histogram(counts)

from qiskit import Aer, execute, QuantumCircuit
simulator = Aer.get_backend('qasm_simulator')
nshots = 2**13
from qiskit import QuantumCircuit
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('10'); qc.append(qcdc, [0,1])
qc.measure([0,1],[0,1])
job = execute(qc, backend=simulator, shots=nshots); counts = job.result().get_counts()
from qiskit.tools.visualization import plot_histogram
plot_histogram(counts)

from qiskit import Aer, execute, QuantumCircuit
simulator = Aer.get_backend('qasm_simulator')
nshots = 2**13
from qiskit import QuantumCircuit
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('11'); qc.append(qcdc, [0,1])
qc.measure([0,1],[0,1])
job = execute(qc, backend=simulator, shots=nshots); counts = job.result().get_counts()
from qiskit.tools.visualization import plot_histogram
plot_histogram(counts)

import qiskit
qiskit.IBMQ.save_account('72f5d1e3769658b4908c384492eb3a9bd6d6ac4ab1fdf613d7fbe72884114d62728d6fd60a8bf8d0b6698f2f5463a605742658fee1ce3318181105c6acb8120e', 
                  overwrite = True)
qiskit.IBMQ.load_account()
provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')

from qiskit import QuantumCircuit, execute
device = provider.get_backend('ibm_nairobi')
nshots = 2**13
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('00'); qc.append(qcdc, [0,1]); qc.measure([0,1],[0,1])
job = execute(qc, backend=device, shots=nshots); jobid = job.job_id(); print(jobid)

job = device.retrieve_job('cmj6f1m0t6t00085y6r0')
from qiskit.tools.visualization import plot_histogram; plot_histogram(job.result().get_counts())

from qiskit import QuantumCircuit, execute
device = provider.get_backend('ibm_nairobi')
nshots = 2**13
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('01'); qc.append(qcdc, [0,1]); qc.measure([0,1],[0,1])
job = execute(qc, backend=device, shots=nshots); jobid = job.job_id(); print(jobid)

job = device.retrieve_job('cmj6f7c0t6t00085y6rg')
plot_histogram(job.result().get_counts())

from qiskit import QuantumCircuit, execute
device = provider.get_backend('ibm_nairobi')
nshots = 2**13
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('10'); qc.append(qcdc, [0,1]); qc.measure([0,1],[0,1])
job = execute(qc, backend=device, shots=nshots); jobid = job.job_id(); print(jobid)

job = device.retrieve_job('cmj6f9nstv5g008dwdb0')
plot_histogram(job.result().get_counts())

#provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')
provider = qiskit.IBMQ.get_provider(hub='ibm-q-research-2', group='federal-uni-sant-1', project='main')
from qiskit import QuantumCircuit, execute; device = provider.get_backend('ibm_nairobi'); nshots = 2**13
qc = QuantumCircuit(2,2); qcdc = qc_dense_coding('11'); qc.append(qcdc, [0,1]); qc.measure([0,1],[0,1])
job = execute(qc, backend=device, shots=nshots); jobid = job.job_id(); print(jobid)

job = device.retrieve_job('cmj6g3g0t6t00085y6sg')
plot_histogram(job.result().get_counts())

import qiskit
qiskit.IBMQ.save_account('e20d3045c7c23a3be753606794714e9b47d4331ec46a41b2281e2d601bae27b2b3c1baa0b5cb54f3282a8b5248e552b14c9c556699010660fb94b11d00ff1073', 
                  overwrite = True)
qiskit.IBMQ.load_account()
#provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')
provider = qiskit.IBMQ.get_provider(hub='ibm-q-research-2', group='federal-uni-sant-1', project='main')
device = provider.get_backend('ibm_nairobi')
nshots = 2**13

from qiskit import QuantumRegister, execute
from qiskit.ignis.mitigation.measurement import complete_meas_cal
qr_ = QuantumRegister(2)
qubit_list_ = [0, 1] # qubits para os quais aplicaremos calibracao de medidas
meas_calibs, state_labels = complete_meas_cal(qubit_list = qubit_list_, qr = qr_)
meas_calibs # circuitos que serão executados para mitigação dos erros

state_labels # estados que serão preparados/medidos/corrigidos

job = execute(meas_calibs, backend=device, shots=nshots)
print(job.job_id())

from qiskit.ignis.mitigation.measurement import CompleteMeasFitter
job = device.retrieve_job('cmm4vmyrcq000080ceqg')
cal_results = job.result()
# função que usaremos para corrigir resultados experimentais
meas_fitter = CompleteMeasFitter(cal_results, state_labels) 
# OBS. Uma vez feito isso para um chip e para uns certos qubits, depois é só usar

job = device.retrieve_job('cmj6f1m0t6t00085y6r0') # dados do experimento da codificação densa para '00'
unmitigated_counts = job.result().get_counts()
mitigated_results = meas_fitter.filter.apply(job.result()) # corrige os resultados usando mitigação
mitigated_counts = mitigated_results.get_counts()
from qiskit.tools.visualization import plot_histogram
plot_histogram([unmitigated_counts, mitigated_counts], legend=['sem mit', 'com mit'])

def prob_erro(counts, target, nshots): # Calcula a probabilidade de erro
    if target in counts:
        pacerto = counts[target]/nshots
        perro = 1 - pacerto
    return perro

print('Probabilidade de erro SEM mitigação: ',prob_erro(unmitigated_counts, '00', nshots))
print('Probabilidade de erro COM mitigação: ',prob_erro(mitigated_counts, '00',nshots))

job = device.retrieve_job('cmj6f7c0t6t00085y6rg') # dados do experimento da codificação densa para '01'
unmitigated_counts = job.result().get_counts()
mitigated_results = meas_fitter.filter.apply(job.result()) # corrige os resultados usando mitigação
mitigated_counts = mitigated_results.get_counts()
from qiskit.tools.visualization import plot_histogram
plot_histogram([unmitigated_counts, mitigated_counts], legend=['sem mit', 'com mit'])

print('Probabilidade de erro SEM mitigação: ',prob_erro(unmitigated_counts, '10', nshots))
print('Probabilidade de erro COM mitigação: ',prob_erro(mitigated_counts, '10',nshots))

job = device.retrieve_job('cmj6f9nstv5g008dwdb0'); unmitigated_counts = job.result().get_counts()
mitigated_results = meas_fitter.filter.apply(job.result()) # corrige os resultados usando mitigação
mitigated_counts = mitigated_results.get_counts(); from qiskit.tools.visualization import plot_histogram
plot_histogram([unmitigated_counts, mitigated_counts], legend=['sem mit', 'com mit'])

print('Probabilidade de erro SEM mitigação: ',prob_erro(unmitigated_counts, '01', nshots))
print('Probabilidade de erro COM mitigação: ',prob_erro(mitigated_counts, '01',nshots))

job = device.retrieve_job('cmj6g3g0t6t00085y6sg') # dados do experimento da codificação densa para '11'
unmitigated_counts = job.result().get_counts(); mitigated_results = meas_fitter.filter.apply(job.result())
mitigated_counts = mitigated_results.get_counts(); from qiskit.tools.visualization import plot_histogram
plot_histogram([unmitigated_counts, mitigated_counts], legend=['sem mit', 'com mit'])

print('Probabilidade de erro SEM mitigação: ',prob_erro(unmitigated_counts, '11', nshots))
print('Probabilidade de erro COM mitigação: ',prob_erro(mitigated_counts, '11',nshots))

def qc_Eswap():
    from qiskit import QuantumCircuit
    qc = QuantumCircuit(4, name='Eswap')
    qc.h([0,3]); qc.cx(0,1); qc.cx(3,2) # cria os pares emaranhados
    qc.barrier()
    qc.cx(1,2); qc.h(1) # muda da base computacional para a base de Bell 
    qc.barrier()
    qc.cx(2,3); qc.cz(1,3) # envia a informação 'clássica'
    return qc
qces = qc_Eswap(); qces.draw('mpl')

from qiskit import Aer, QuantumCircuit; import qiskit
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
from qiskit.visualization import plot_state_city
simulator = Aer.get_backend('qasm_simulator'); qc = QuantumCircuit(4); qces = qc_Eswap(); qc.append(qces, [0,1,2,3])
qstc = state_tomography_circuits(qc, [0,3]); job = execute(qstc, backend=simulator, shots=nshots)
qstf = StateTomographyFitter(job.result(), qstc); rho = qstf.fit(method='lstsq'); plot_state_city(rho)

from qiskit.quantum_info import state_fidelity
F = state_fidelity(rho,Phip); print('F = ',F)

import qiskit
qiskit.IBMQ.save_account('72f5d1e3769658b4908c384492eb3a9bd6d6ac4ab1fdf613d7fbe72884114d62728d6fd60a8bf8d0b6698f2f5463a605742658fee1ce3318181105c6acb8120e', 
                  overwrite = True)
qiskit.IBMQ.load_account()
#provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')
provider = qiskit.IBMQ.get_provider(hub='ibm-q-research-2', group='federal-uni-sant-1', project='main')
device = provider.get_backend('ibm_nairobi')
nshots = 2**13

from qiskit import QuantumCircuit, execute
qc = QuantumCircuit(4); qces = qc_Eswap(); qc.append(qces, [0,1,2,3])
qstc = state_tomography_circuits(qc, [0,3])
job = execute(qstc, backend=device, shots=nshots)
jobid = job.job_id(); print(jobid)

job = device.retrieve_job('cmjp9zf5mym0008dvmzg')
qstf = StateTomographyFitter(job.result(), qstc); rho = qstf.fit(method='lstsq')
from qiskit.visualization import plot_state_city; plot_state_city(rho)

rho

import math; import numpy as np
Phip = np.array([1/math.sqrt(2),0,0,1/math.sqrt(2)]); Phip

from qiskit.quantum_info import state_fidelity
F = state_fidelity(rho,Phip); print('F = ',F)

import qiskit
qiskit.IBMQ.save_account('dabd4674f7b3794f740813fec0c5478bfefdebb7d1dca9b7acd41e3f90ed2c8a8b80af26fb3236289fbfc70d0ea334829a836453ac46f96fee68abcb22495ef4', 
                  overwrite = True)
qiskit.IBMQ.load_account()
#provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')
provider = qiskit.IBMQ.get_provider(hub='ibm-q-research-2', group='federal-uni-sant-1', project='main')
device = provider.get_backend('ibm_nairobi')
nshots = 2**13

from qiskit import QuantumRegister, execute
from qiskit.ignis.mitigation.measurement import complete_meas_cal
qr = QuantumRegister(4)
qubit_list = [0, 3]
meas_calibs, state_labels = complete_meas_cal(qubit_list = qubit_list, qr = qr)

job = execute(meas_calibs, backend=device, shots=nshots)
print(job.job_id())

from qiskit.ignis.mitigation.measurement import CompleteMeasFitter
job = device.retrieve_job('cmr2snercp70008sfsw0')
cal_results = job.result()
meas_fitter = CompleteMeasFitter(cal_results, state_labels)

from qiskit import QuantumCircuit, execute
qc = QuantumCircuit(4); qces = qc_Eswap(); qc.append(qces, [0,1,2,3])
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
qstc = state_tomography_circuits(qc, [0,3])
job = device.retrieve_job('cmjp9zf5mym0008dvmzg')
mitigated_results = meas_fitter.filter.apply(job.result())
qstf = StateTomographyFitter(mitigated_results, qstc)
rho = qstf.fit(method='lstsq')
from qiskit.visualization import plot_state_city; plot_state_city(rho)

import numpy as np
import math
from qiskit.quantum_info import state_fidelity
Phip = np.array([1/math.sqrt(2),0,0,1/math.sqrt(2)])
F = state_fidelity(rho,Phip)
print('F = ',F)

