#Qiskit Categories
#Terra - Foundation, where we build and test our circuit
#Aer - Simulator, simulation of circuit theoretically
#Ignis - Masks noise, helps understand/mitigate error

#energy relaxation - scenario - leave qbit in energized state, will eventually relax to zero state
#Measurement error mitigation

from qiskit import *

nqubits = 3
circuit = QuantumCircuit(nqubits, nqubits)
circuit.h(0)
circuit.cx(0,1)
circuit.cx(1,2)
circuit.measure([0,1,2], [0,1,2])

%matplotlib inline
circuit.draw(output='mpl')

#Aer Simulaton
simulator = Aer.get_backend('qasm_simulator')
sim_result = execute(circuit, backend=simulator, shots=1024).result()

from qiskit.visualization import plot_histogram
plot_histogram(sim_result.get_counts(circuit))

#Terra Real Hardware Execution
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q')
device = provider.get_backend('ibm_oslo')

job = execute(circuit, backend=device, shots=1024)
print(job.job_id())
from qiskit.tools.monitor import job_monitor
job_monitor(job)

device_result = job.result()
plot_histogram(device_result.get_counts(circuit))

#Ignis Error Mitigation
from qiskit.ignis.mitigation.measurement import (complete_meas_cal, CompleteMeasFitter)

cal_circuits, state_labels = complete_meas_cal(qr = circuit.qregs[0], circlabel='measerrormitigationcal')

cal_circuits[2].draw(output='mpl')

len(cal_circuits)

cal_job = execute(cal_circuits,
                 backend = device,
                  shots = 1024,
                  optimization_level = 0
                 )
print(cal_job.job_id())
job_monitor(cal_job)
cal_results = cal_job.result()

plot_histogram(
cal_results.get_counts(cal_circuits[3])
)

meas_fitter = CompleteMeasFitter(cal_results, state_labels)

meas_fitter.plot_calibration()

meas_filter = meas_fitter.filter

mitigated_result = meas_filter.apply(device_result)

device_counts = device_result.get_counts(circuit)
mitigated_counts = mitigated_result.get_counts(circuit)
plot_histogram([device_counts, mitigated_counts], legend =['device, noisy', 'device, mitigated'])

#Another example using a different circuit
circuit2 = QuantumCircuit(3,3)
circuit2.x(1)
circuit2.h(0)
circuit2.cx(0,1)
circuit2.cx(1,2)
circuit2.measure([0,1,2],[0,1,2])
circuit2.draw(output = 'mpl')

plot_histogram(
    execute(circuit2, backend=simulator, shots = 1024).result().get_counts(circuit2)
)

device_counts_2 = execute(circuit2, backend = device, shots=1024).result().get_counts(circuit2)

plot_histogram(device_counts_2)

device_mitigated_counts_2 = meas_filter.apply(device_counts_2)

plot_histogram(device_mitigated_counts_2)

