<jupyter_start><jupyter_text>Trusted Notebook" align="middle">  Quantum State Tomography* **Last Updated:** March 8, 2019* **Requires:** qiskit-terra 0.8, qiskit-ignis 0.1.1, qiskit-aer 0.2 This notebook contains examples for using the ``ignis.verification.tomography`` state tomography module.<jupyter_code># Needed for functions
import numpy as np
import time
from copy import deepcopy

# Import Qiskit classes
import qiskit 
from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, Aer
from qiskit.quantum_info import state_fidelity
from qiskit.providers.aer import noise

# Tomography functions
from qiskit.ignis.verification.tomography import state_tomography_circuits, StateTomographyFitter
import qiskit.ignis.mitigation.measurement as mc<jupyter_output><empty_output><jupyter_text>2-Qubit state tomography Example In the below example we want to perform state tomography on a 2Q Bell state between qubits 3 and 5. To make the reference circuit we generate the expected statevector using ``statevector_simulator`` between qubits 0 and 1.<jupyter_code># Create the expected density matrix
q2 = QuantumRegister(2)
bell = QuantumCircuit(q2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])
print(bell)

job = qiskit.execute(bell, Aer.get_backend('statevector_simulator'))
psi_bell = job.result().get_statevector(bell)
print(psi_bell)
# Create the actual circuit 
q2 = QuantumRegister(6)
bell = QuantumCircuit(q2)
bell.h(q2[3])
bell.cx(q2[3], q2[5])
print(bell)<jupyter_output>q1_0: |0>──────────
                   
q1_1: |0>──────────
                   
q1_2: |0>──────────
         ┌───┐     
q1_3: |0>┤ H ├──■──
         └───┘  │  
q1_4: |0>───────┼──
              ┌─┴─┐
q1_5: |0>─────┤ X ├
              └───┘<jupyter_text>Here we are going to generate and run the state tomography circuits. By only passing in the 2 registers we want to measure the state tomography will only run on that reduced $2^2$ Hilbert space. However, if we pass the whole register in the state tomography module will try and fit the full $2^6$ space.<jupyter_code># Generate circuits and run on simulator
t = time.time()
# Generate the state tomography circuits. Only pass in the 
# registers we want to measure (in this case 3 and 5)
qst_bell = state_tomography_circuits(bell, [q2[3],q2[5]])
job = qiskit.execute(qst_bell, Aer.get_backend('qasm_simulator'), shots=5000)
print('Time taken:', time.time() - t)

tomo_bell = StateTomographyFitter(job.result(), qst_bell)<jupyter_output>Time taken: 0.969280481338501<jupyter_text>The fitter will output a density matrix ordered according to how we passed in the registers to ``state_tomography_circuits``.<jupyter_code># Perform the tomography fit
# which outputs a density matrix
rho_bell = tomo_bell.fit()
F_bell = state_fidelity(psi_bell, rho_bell)
print('Fit Fidelity =', F_bell)<jupyter_output>Fit Fidelity = 0.9998869435701019<jupyter_text>Repeat the Example with Measurement Noise<jupyter_code>#Add measurement noise
noise_model = noise.NoiseModel()
for qi in range(6):
    read_err = noise.errors.readout_error.ReadoutError([[0.75, 0.25],[0.1,0.9]])
    noise_model.add_readout_error(read_err,[qi])
    
#generate the calibration circuits
meas_calibs, state_labels = mc.complete_meas_cal(qubit_list=[3,5])

backend = Aer.get_backend('qasm_simulator')
job_cal = qiskit.execute(meas_calibs, backend=backend, shots=15000, noise_model=noise_model)
job_tomo = qiskit.execute(qst_bell, backend=backend, shots=15000, noise_model=noise_model)

meas_fitter = mc.CompleteMeasFitter(job_cal.result(),state_labels)

tomo_bell = StateTomographyFitter(job_tomo.result(), qst_bell)

#no correction
rho_bell = tomo_bell.fit()
F_bell = state_fidelity(psi_bell, rho_bell)
print('Fit Fidelity (no correction) =', F_bell)

#correct data
correct_tomo_results = meas_fitter.filter.apply(job_tomo.result(), method='least_squares')
tomo_bell = StateTomographyFitter(correct_tomo_results, qst_bell)
rho_bell = tomo_bell.fit()
F_bell = state_fidelity(psi_bell, rho_bell)
print('Fit Fidelity (w/ correction) =', F_bell)<jupyter_output>Fit Fidelity (no correction) = 0.575209285967832
Fit Fidelity (w/ correction) = 0.99620836914412<jupyter_text>Generating and fitting random statesWe now test the functions on state generated by a circuit consisting of a layer of random single qubit unitaries u3<jupyter_code>def random_u3_tomo(nq, shots):
    
    def rand_angles():
        return tuple(2 * np.pi * np.random.random(3) - np.pi)
    q = QuantumRegister(nq)
    circ = QuantumCircuit(q)
    for j in range(nq):
        circ.u3(*rand_angles(), q[j])
    job = qiskit.execute(circ, Aer.get_backend('statevector_simulator'))
    psi_rand = job.result().get_statevector(circ)
    
    qst_circs = state_tomography_circuits(circ, q)
    job = qiskit.execute(qst_circs, Aer.get_backend('qasm_simulator'),
                         shots=shots)
    tomo_data = StateTomographyFitter(job.result(), qst_circs)
    rho_cvx = tomo_data.fit(method='cvx')
    rho_lstsq = tomo_data.fit(method='lstsq')
    
    print('F fit (CVX) =', state_fidelity(psi_rand, rho_cvx))
    print('F fit (LSTSQ) =', state_fidelity(psi_rand, rho_lstsq))
for j in range(5):
    print('Random single-qubit unitaries: set {}'.format(j))
    random_u3_tomo(3, 5000)<jupyter_output>Random single-qubit unitaries: set 0
F fit (CVX) = 0.9976353975778117
F fit (LSTSQ) = 0.9979378974760655
Random single-qubit unitaries: set 1
F fit (CVX) = 0.9981626032815747
F fit (LSTSQ) = 0.9982212006778255
Random single-qubit unitaries: set 2
F fit (CVX) = 0.9980770834869439
F fit (LSTSQ) = 0.9972658871255538
Random single-qubit unitaries: set 3
F fit (CVX) = 0.9977178925981638
F fit (LSTSQ) = 0.9939750379438954
Random single-qubit unitaries: set 4
F fit (CVX) = 0.9986140574357163
F fit (LSTSQ) = 0.9973309153294724<jupyter_text>5-Qubit Bell State<jupyter_code># Create a state preparation circuit
q5 = QuantumRegister(5)
bell5 = QuantumCircuit(q5)
bell5.h(q5[0])
for j in range(4):
    bell5.cx(q5[j], q5[j + 1])

# Get ideal output state
job = qiskit.execute(bell5, Aer.get_backend('statevector_simulator'))
psi_bell5 = job.result().get_statevector(bell5)

# Generate circuits and run on simulator
t = time.time()
qst_bell5 = state_tomography_circuits(bell5, q5)
job = qiskit.execute(qst_bell5, Aer.get_backend('qasm_simulator'), shots=5000)

# Extract tomography data so that counts are indexed by measurement configuration
tomo_bell5 = StateTomographyFitter(job.result(), qst_bell5)
print('Time taken:', time.time() - t)
t = time.time()
rho_lstsq_bell5 = tomo_bell5.fit(method='lstsq')
print('Least-Sq Reconstruction')
print('Time taken:', time.time() - t)
print('Fit Fidelity:', state_fidelity(psi_bell5, rho_lstsq_bell5))
t = time.time()
rho_cvx_bell5 = tomo_bell5.fit(method='cvx')
print('CVX Reconstruction')
print('Time taken:', time.time() - t)
print('Fidelity:', state_fidelity(psi_bell5, rho_cvx_bell5))<jupyter_output>CVX Reconstruction
Time taken: 136.55148649215698
Fidelity: 0.999921728516101<jupyter_text>2-Qubit Conditional State Tomography  In this example, we have a three qubit system where one of the qubits will be an ancilla for performing state tomography, i.e., only perform tomography when the third qubit is in the state "1". The circuit is setup in such a way that after conditional tomography we will get a Bell state on the first two qubits.First make a 3Q GHZ State with no classical measurements.<jupyter_code># Create the actual circuit 
q2 = QuantumRegister(3)
ghz = QuantumCircuit(q2)
ghz.h(q2[0])
ghz.cx(q2[0], q2[1])
ghz.cx(q2[1], q2[2])
ghz.h(q2[2])
print(ghz)<jupyter_output>┌───┐               
q9_0: |0>┤ H ├──■────────────
         └───┘┌─┴─┐          
q9_1: |0>─────┤ X ├──■───────
              └───┘┌─┴─┐┌───┐
q9_2: |0>──────────┤ X ├┤ H ├
                   └───┘└───┘<jupyter_text>Here we are going to generate and run the state tomography circuits. Only pass the registers we want to perform state tomography on. The code will generate a new classical register for only those measurements.<jupyter_code>qst_ghz = state_tomography_circuits(ghz, [q2[0],q2[1]])
print(qst_ghz[0])<jupyter_output>┌───┐                ░ ┌───┐┌─┐   
q9_0: |0>┤ H ├──■─────────────░─┤ H ├┤M├───
         └───┘┌─┴─┐           ░ ├───┤└╥┘┌─┐
q9_1: |0>─────┤ X ├──■────────░─┤ H ├─╫─┤M├
              └───┘┌─┴─┐┌───┐ ░ └───┘ ║ └╥┘
q9_2: |0>──────────┤ X ├┤ H ├─░───────╫──╫─
                   └───┘└───┘ ░       ║  ║ 
 c8_0: 0 ═════════════════════════════╩══╬═
                                         ║ 
 c8_1: 0 ════════════════════════════════╩═<jupyter_text>Now make a copy of this circuit (we will need it for the fitter) and make a new circuit with an ancilla measurement attached (this is what will be run)<jupyter_code>#Make a copy without the ancilla register
qst_ghz_no_anc = deepcopy(qst_ghz)
ca = ClassicalRegister(1)
for qst_ghz_circ in qst_ghz:
    qst_ghz_circ.add_register(ca)
    qst_ghz_circ.measure(q2[2],ca[0])
#Run in Aer
job = qiskit.execute(qst_ghz, Aer.get_backend('qasm_simulator'), shots=10000)
raw_results = job.result()<jupyter_output><empty_output><jupyter_text>Before sending the results to the state tomography fitter we must strip the register for the Q2 measurement and only keep the results when that register is 1.<jupyter_code>new_result = deepcopy(raw_results)

for resultidx, _ in enumerate(raw_results.results):
    old_counts = raw_results.get_counts(resultidx)
    new_counts = {}
    
    #change the size of the classical register
    new_result.results[resultidx].header.creg_sizes = [new_result.results[resultidx].header.creg_sizes[0]]
    new_result.results[resultidx].header.clbit_labels = new_result.results[resultidx].header.clbit_labels[0:-1]
    new_result.results[resultidx].header.memory_slots = 2
    
    for reg_key in old_counts:
        reg_bits = reg_key.split(' ')
        if reg_bits[0]=='1':
            new_counts[reg_bits[1]]=old_counts[reg_key]

    new_result.results[resultidx].data.counts = \
        new_result.results[resultidx]. \
        data.counts.from_dict(new_counts)

tomo_bell = StateTomographyFitter(new_result, qst_ghz_no_anc)
# Perform the tomography fit
# which outputs a density matrix
rho_bell = tomo_bell.fit()
np.around(rho_bell,3)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1358663801523735, 'fraction_numerical': 0.04649345575307677, 'mean_word_length': 4.894645941278066, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '30641', 'license': 'Apache-2.0', 'n_tokens_mistral': 4136, 'n_tokens_neox': 3786, 'n_words': 926, 'path': 'qiskit/advanced/ignis/state_tomography.ipynb', 'repo_name': 'Sahar2/qiskit-tutorials', 'size': '10238'}