<jupyter_start><jupyter_text>Trusted Notebook" width="500 px" align="left">  _*Measurement Error and Mitigation*_ *** Contributors<NAME>  IntroductionThe last step of a typical quantum experiment is to perform a measurement on the qubits in the circuit. Although the qubit state $|\Psi\rangle$ (or more generally the density matrix $\rho$) is the general description of the quantum state, in a typical strong projective measurement our measurement _projects_ the general state into a specific computational state $|x\rangle$ (where $x$ is a bitstring, e.g.,  `1001010`) The probability of measuring bitstring $x$ is given by:$$P_x = \mathrm{Trace}(\langle x|\rho|x \rangle)$$Therefore, the measurement process is stochastic. The above distribution of $x$ given a state $\rho$ is true only in the absence of measurement errors. There are multiple sources of possible measurement error, all of which are dependent on the physical mechanism of measurement in the system. For superconducting qubits coupled to readout cavities [[1](ref1),[2](ref2),[3](ref3),[4](ref4),[5](ref5)] the state of the qubit is determined by measurement the response of a microwave tone incident on the readout cavity. The cavity signal is measured for some time where $V(t)$ is the complex amplitude of the signal which is converted to a single complex number based on a measurement kernel $$V = \int_0^{T} V(t) K(t) dt $$which is then turned into a _bit_ by a nonlinear discriminator [[6](ref6)]. The simplest example being if $|V|<V_0$ then the qubit was in state 0 and otherwise the qubit was in state 1. As discussed in [[6](ref6)] there are classical sources of noise on the signal that lead to misidentification of the qubit state, but it can also happen that the qubit decays due to $T_1$ during the measurement. There are other sources of crosstalk (to numerous to enumerate) such as classical crosstalk on the lines and crosstalk between resonantors on chip. All of these issues lead to a new probability distribution $\tilde{P}_{\rho}$ for a given state. Given certain assumptions about these errors and appropriate calibration we can attempt to correct the skew in the probability distribution _on average_. **Contents**[Constructing a Full Calibration Matrix](sect1)[Correcting Results with the Calibration Matrix](sect2) References[1] <NAME>, <NAME>, <NAME>, <NAME>, and <NAME>, Cavity quantum electrodynamics for superconducting electrical circuits: An architecture for quantum computation, https://arxiv.org/abs/cond-mat/0402216[2] <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, and <NAME>. Qubit-photon interactions in a cavity: Measurement induced dephasing and number splittinghttps://arxiv.org/abs/cond-mat/0602322 [3] <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, and <NAME>. Quantum information processing with circuit quantum electrodynamics. https://arxiv.org/abs/cond-mat/0612038[4] <NAME>, <NAME>, <NAME>, <NAME>, <NAME>. Protocols for optimal readout of qubits using a continuous quantum nondemolition measurement. https://arxiv.org/abs/cond-mat/0701078[5] <NAME>, <NAME>, <NAME>, <NAME>, <NAME> and <NAME>. Quantum trajectory approach to circuit QED: Quantum jumps and the Zeno effect. https://arxiv.org/abs/0709.4264[6] <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME> and <NAME>. Tomography via Correlation of Noisy Measurement Records. https://arxiv.org/abs/1310.6448 Code imports==============<jupyter_code># Import general libraries (needed for functions)
import numpy as np
import time

# Import Qiskit classes
import qiskit 
from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, Aer
from qiskit.providers.aer import noise
from qiskit.tools.visualization import plot_histogram

# Import measurement calibration functions
from qiskit.ignis.mitigation.measurement import (complete_meas_cal,
                                                       CompleteMeasFitter, MeasurementFilter)<jupyter_output><empty_output><jupyter_text>Constructing a Full Calibration MatrixThe assumption of the error mitigation technique is that we can prepare each of the basis states with very low error. Given this assumption, in separate experiments we can prepare one of the $2^n$ states and then measure the outputs in all $2^n$ states. Normalizing these outputs and making each set of output probabilities for a given prepared state the columns of a matrix we obtain the matrix $\mathbf{A}$ which translates the ideal probability distribution of the state $\rho$ ($P_\rho$) into the experimental probability distribution $\tilde{P}_{\rho}$$$\tilde{P}_{\rho} = \mathbf{A} \cdot P_{\rho}$$**Code**The code below constructs the calibration matrix for 2 qubits with error artificially put into the Aer simulation.<jupyter_code># Generate the calibration circuits
qr = qiskit.QuantumRegister(2)
meas_calibs, state_labels = complete_meas_cal(qubit_list=[0,1], qr=qr)
# Generate a noise model for the 2 qubits
noise_model = noise.NoiseModel()
for qi in range(2):
    read_err = noise.errors.readout_error.ReadoutError([[0.9, 0.1],[0.25,0.75]])
    noise_model.add_readout_error(read_err, [qi])
backend = qiskit.Aer.get_backend('qasm_simulator')
job_no_noise = qiskit.execute(meas_calibs, backend=backend, shots=1000)
job_w_noise = qiskit.execute(meas_calibs, backend=backend, noise_model=noise_model, shots=1000)
cal_results = job_no_noise.result()
meas_fitter = CompleteMeasFitter(cal_results, state_labels)
print("Ideal calibration matrix:")
print(meas_fitter.cal_matrix)
cal_results = job_w_noise.result()
meas_fitter = CompleteMeasFitter(cal_results, state_labels)
print("Noisy calibration matrix:")
print(meas_fitter.cal_matrix)<jupyter_output>Ideal calibration matrix:
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]
Noisy calibration matrix:
[[0.803 0.22  0.221 0.059]
 [0.104 0.68  0.021 0.195]
 [0.084 0.028 0.674 0.182]
 [0.009 0.072 0.084 0.564]]<jupyter_text>We can see that with noise when we prepare the state $|11\rangle$ and measure we get counts in states other than $|11\rangle$<jupyter_code>plot_histogram([cal_results.get_counts('cal_11')], legend=[r'Preparing in $|11\rangle$'])<jupyter_output><empty_output><jupyter_text>Correcting Using the Calibration MatrixIf we have the calibration matrix $\mathbf{A}$ which gives the transformation between the distributions, $$\tilde{P}_{\rho} = \mathbf{A} \cdot P_{\rho}$$then to work back to $P_{\rho}$ we just need to invert $\mathbf{A}$,$$P_{\rho} = \mathbf{A}^{-1} \cdot \tilde{P}_{\rho}$$However, there are some issues to watch out for.Below, we simulate a calibration with 200 shots and then prepare the state $|11\rangle$ and measure with 2000 shots.<jupyter_code># Generate the calibration circuits
qr = qiskit.QuantumRegister(2)
meas_calibs, state_labels = complete_meas_cal(qubit_list=[0,1], qr=qr)
# Generate a noise model for the 2 qubits
noise_model = noise.NoiseModel()
for qi in range(2):
    read_err = noise.errors.readout_error.ReadoutError([[0.9, 0.1],[0.25,0.75]])
    noise_model.add_readout_error(read_err, [qi])
backend = qiskit.Aer.get_backend('qasm_simulator')
job_w_noise_cal = qiskit.execute(meas_calibs, backend=backend, noise_model=noise_model, shots=200)
job_for_correction = qiskit.execute(meas_calibs[-1], backend=backend, noise_model=noise_model, shots=2000)
cal_results = job_w_noise_cal.result()
raw_results = job_for_correction.result()
meas_fitter = CompleteMeasFitter(cal_results, state_labels)
meas_filter = meas_fitter.filter
print("Corrected Results using Matrix Inversion:")
print(meas_filter.apply(raw_results,method='pseudo_inverse').get_counts('cal_11'))<jupyter_output>Corrected Results using Matrix Inversion:
{'10': -92.91098988658939, '00': 46.80774751538827, '01': -22.521419828642696, '11': 2068.6246621998444}<jupyter_text>If you run the above code several times, you will likely see some negative counts. This is because there is some statistical noise in the calibration matrix which means that the corrected results will be unphysical. To correct for this we can find the $P_{\rho}$ which is closest to reproducing the measured output,$$\text{min}_{P_{\rho}} ||\tilde{P}_{\rho}-\mathbf{A}\cdot P_{\rho}||$$but where all elements of $P$ are non-zero.<jupyter_code>print("Corrected Results using Constrained Least Square:")
print(meas_filter.apply(raw_results).get_counts('cal_11'))<jupyter_output>Corrected Results using Constrained Least Square:
{'10': 7.279108826113712e-11, '00': 4.655538471194395, '01': 0.2706670283213603, '11': 1995.0737945004114}
{'fraction_non_alphanumeric': 0.10965995999529356, 'fraction_numerical': 0.04471114248735145, 'mean_word_length': 5.772908366533865, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 59, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '136232', 'license': 'Apache-2.0', 'n_tokens_mistral': 2832, 'n_tokens_neox': 2459, 'n_words': 926, 'path': 'community/ignis/measurement_error_mitigation.ipynb', 'repo_name': 'Chibikuri/qiskit-tutorials', 'size': '8791'}