Quantum error mitigation
Experimenting with Mitiq
A very recent work published in Nature [1] has again put the spotlight on a very interesting topic for near-term quantum devices: how to reduce the errors arising from calculations running on faulty hardware. And why those errors arise? That’s our old friend noise coming back to make research always more fun! The researchers in [1] have used one of the biggest quantum hardware currently available to run computations on circuits for which classical techniques break down. They have shown that existing quantum error mitigation (QEM) techniques allow one to obtain reliable results despite the presence of noise, concluding that:
[…] there is indeed merit to pursuing research towards deriving a practical computational advantage from noise-limited quantum circuits.
In this article we will take a quick tour to understand the importance of QEM, how one among the several existing techniques works, and finally, how we can play with it using some simple code!
1. How is error mitigation different from error correction and why it is important?
A related field much more explored than error mitigation is quantum error correction (QEC). As the names indicate, the former aims at reducing the errors, while the latter at completely removing them; in fact, fault tolerant quantum computing is reachable when the errors stay under a certain threshold (see [2] if you want to learn more about this threshold theorem). If the qubit demand of QEC was not that high, we would always apply QEC schemes to correct the results of noisy simulations; unfortunately, the number of qubits needed to do that overcomes currently available resources (some experiments showing the benefits of QEC schemes can be found in [3,4]). The need for simpler and more practical techniques started then the work around error mitigation (for a recent review on the topic see [5]), which instead does not require additional qubits, at the cost of more samples and partial error suppression. Let’s dive a bit deeper!
2. How does Zero Noise Extrapolation work?
QEM techniques mostly rely on the post-processing of the results obtained from noisy devices and deal with expectation values of an observable. Among the most known and used we find Zero-Noise Extrapolation (ZNE) and Probabilistic Error Cancellation [6], Clifford Data Regression [7], Readout-Error Mitigation [8] and many others. We’ll have a look at the ZNE since it was the one used in [1]. A great feature of this method is that it can be applied even if the noise model is not known in detail (i.e. without tomographic knowledge of the hardware gates) and the main idea behind it is quite fun: we have noise which ruins the results of the great simulations we are running (not cool), but we do not despair! On the contrary, we embrace it and increase it higher and higher… and then we extrapolate the ideal result from those noisy measurements! There is a very important point to keep in mind when using this technique:
Errors cannot be arbitrarily suppressed increasing noise indefinitely [5].
To see why, we need to think about the resource overhead that this entails; we will follow [9] in the reasoning and equations below. Let  be the observable we want to measure and 𝒩 the noise process which introduces a small error ε. Then we can expand the expectation value of  as a function of ε according to Taylor expansion:
To estimate the ideal expectation value ⟨Â⟩(0), we consider different error rates and run several different noisy measurements; using Richardson extrapolation we can write an approximation of it as:
In the expression above, all the a coefficients are greater than 1 (we are increasing the error rate) and the γ coefficients must be chosen such that:
Doing so, we can estimate ⟨Â⟩(0) suppressing the error to
This results in the method being very efficient when ε is small! But wait, why were we doing all this (not that math is not fun…)? Let’s refocus on the cost of the error mitigation method outlined above and let us look at the variance of the approximated expectation value:
The variance above is bigger than the one of ⟨Â⟩, meaning that we need to take more samples (or equivalently to allow for more “shots”) in order to achieve the same accuracy as in the ideal case!
Until now we have neglected another essential step of the ZNE method: how do we increase noise in practice? We’ll keep it very simple here consider the case of a quantum circuit where we increase the noise at the gate level: we can do that intentionally increasing its depth, a technique which is known as unitary folding [10].
3. Pieces of implementation with Mitiq
True, we have seen very little theory, but we’ll take here a more hands-on approach and directly test some error mitigation techniques on the “Hello World” of quantum computing: a circuit to create a Bell state. We’ll do that with an open-source toolkit called Mitiq [11], which allows you to use many different SDKs and backends (simulators and real hardware) and compare different methods and performances! The language used is Python (with no surprises ;)). The documentation of this package is rich of examples and starts with a very clear and coincise explanation of QEM objective:
Current quantum computers are noisy due to interactions with the environment, imperfect gate applications, state preparation and measurement errors, etc. Error mitigation seeks to reduce these effects at the software level by compiling quantum programs in clever ways.
In the following, we’ll use a bit of braket and a bit of qiskit with corresponding available hardware or simulators. As observable, we’ll use the fidelity (following definition in [12]) between the Bell state output of the noisy circuit and the ideal one; this quantity measures how close two quantum states are (for two identical states the fidelity is 1). We can give a visual representation of the distance between two quantum states in the 1-qubit case thanks to the Bloch ball representation:
In our case, the fidelity will tell us how well the hardware can prepare an entangled pair despite the noise. Let’s start!
We begin with testing ZNE on the available simulator via braket. We need to import the needed packages and define circuit and observable:
################################################# mitiq functions
from mitiq import zne
from mitiq.zne import mitigate_executor
from mitiq.zne.inference import RichardsonFactory
################################################# braket functions
import braket
from braket.devices import LocalSimulator
from braket.circuits import Circuit, Noise, Observable
################################################# other packages
import numpy as np
################################################# ideal density matrix |ψ⟩⟨ψ|
def density_matrix_pure(state_vector: np.ndarray) -> np.ndarray:
return np.outer(state_vector, np.transpose(np.conjugate(state_vector)))
bell_state = np.array([1/np.sqrt(2),0,0,1/np.sqrt(2)])
ideal_target_bell = density_matrix_pure(bell_state)
################################################# circuit for Bell state
circuit = Circuit()
circuit.h(0).cnot(0,1)
print(circuit)
T : |0|1|
q0 : -H-C-
|
q1 : ---X-
T : |0|1|
In the following block of code we define the Executor, one of the fundamental classes in Mitiq, which takes a circuit as input and outputs an expectation value (the simulator and the observable are specified inside the function). The noisy executor makes use of the noiseless one; as type of noise here we chose the depolarizing one:
def noiseless_executor(circ: Circuit) -> float:
device = LocalSimulator('braket_dm')
circ.expectation(observable=Observable.Hermitian(matrix=ideal_target_bell), target=range(2))
task = device.run(circ)
result = task.result()
return result.values
def executor_with_noise(circ: Circuit) -> float:
noise = Noise.Depolarizing(probability=0.04)
circ.apply_gate_noise(noise)
return noiseless_executor(circ)
noise_fidelity = np.sqrt(executor_with_noise(circuit))
print(noise_fidelity)
0.94775274
# Noisy result. The ideal value is 1, giving a discrepancy of ~0.05.
As we can see, the fidelity is smaller than one! Let’s see now what happens if we mitigate with ZNE. We use three different noise levels, as specified in the RichardsonFactory function:
fac = RichardsonFactory(scale_factors=[1, 3, 5])
mitigated_executor = mitigate_executor(executor_with_noise, factory=fac)
mitigated_fidelity = np.sqrt(mitigated_executor(circuit))
print(mitigated_fidelity)
0.9915175318851517 # mitigated
UserWarning: The input circuit is very short.
This may reduce the accuracy of noise scaling.
Yay! The result has indeed improved and it is now much closer to 1. But, we got a warning ⚠ We should not worry, but it is useful to understand why it appears. We are increasing the noise by increasing the depth of the circuit, and we are using the default method in Mitiq to do so; if we have very few gates in our circuit, the precision of this scaling is affected because “the folded circuit has a number of gates approximately equal to scale_factor * n where n is the number of gates in the input circuit” [11]. This means that the scaled circuits are not that deep in the end for very small circuits!
If you want to make a more pondered decision — instead of using the default methods — it is possible to run a calibration of the ZNE technique on a benchmark circuit to see which combination of scaling and extrapolation methods works best (see this example to know how to do that).
Warning! This is not a simulation!
Like in video games when you reach the last level and you need to defeat the final boss, we have now arrived at the ultimate test of this small QEM adventure: run our circuit on a real quantum computer. There, you don’t get to choose the type of noise or the intensity, you have the whole noisy package to deal with! To see how ZNE performs, we’ll use the available IBM devices. Here we go!
################################################# qiskit functions
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Options, Estimator
################################################# ideal density matrix |ψ⟩⟨ψ|
observable = SparsePauliOp("XX", coeffs = 1/4)+
SparsePauliOp("YY", coeffs = -1/4)+
SparsePauliOp("ZZ", coeffs = 1/4)+
SparsePauliOp("II", coeffs = 1/4)
################################################# circuit for Bell state
circuit = qiskit.QuantumCircuit(2)
circuit.h(0)
circuit.cx(0,1)
As we can see, while the circuit construction remains untouched, we need to facilitate the “reading” of the observable for the hardware decomposing it in Pauli terms.
When running an observable job on an IBM real device, the easiest thing to do is to use the primitives of Qiskit Runtime. In this case, we will not make use of Mitiq, but we’ll directly set the “resilience level” option (ZNE corresponds to resilience_level = 2). As backend, we choose ibmq_manila, a 5-qubit device:
backend = "ibmq_manila"
service = QiskitRuntimeService()
with Session(service=service, backend=backend) as session:
options = Options()
options.resilience_level = 2
est = Estimator(session=session, options=options)
job = est.run(circuit, observable)
result = job.result()
print(f" > Expectation value: {result.values[0]}")
> Expectation value: 0.9354479166666667
Usually, when submitting a job to a Qiskit Runtime session, the job will first go to the queue and once your session is opened, it will run until you get the final result (you can have additional information on the job calling for the whole result output).
Here, the fidelity we got is quite low, despite ZNE. Let’s see if we can do better with another device (we chose this time ibm_lagos, a 7-qubit device):
backend = "ibm_lagos"
service = QiskitRuntimeService()
with Session(service=service, backend=backend) as session:
options = Options()
options.resilience_level = 2
est = Estimator(session=session, options=options)
job = est.run(circuit, observable)
result = job.result()
print(f" > Expectation value: {result.values[0]}")
> Expectation value: 0.9639375000000004
The result has indeed improved! The two hardware have though the same quantum volume, so there is no unique or straightforward criterium that tells us that one is better than the other.
A last remark here is essential: each quantum device of the IBM Quantum Resources has associated calibration data containing the details of the errors (single- and 2-qubit gates, readout and so on). We can check those data every time before running a simulation to choose the device with smaller errors, but due to the queue, sometimes after the job is completed the data have changed and errors are not the same anymore. So always keep an eye on those data and enjoy your quantum runs!
Code
You can find the code seen in this article here!
At ColibrITD
To achieve a practical advantage in the near future for real use cases, it is essential to explore noise mitigation methods. The interest for us as a quantum software company in quantum error mitigation goes without saying! ;)
References
[1] Kim, Y., Eddins, A., Anand, S. et al. Evidence for the utility of quantum computing before fault tolerance. Nature 618, 500–505 (2023).
[2] Aharonov, Dorit, and Michael Ben-Or. Fault-tolerant quantum computation with constant error. Proceedings of the twenty-ninth annual ACM symposium on Theory of computing (1997).
[3] Google Quantum AI. Exponential suppression of bit or phase errors with cyclic error correction. Nature 595, 383–387 (2021).
[4] Google Quantum AI. Suppressing quantum errors by scaling a surface code logical qubit. Nature 614, 676–681 (2023).
[5] Endo, Suguru, et al. Hybrid quantum-classical algorithms and quantum error mitigation. Journal of the Physical Society of Japan 90.3 (2021).
[6] Kristan Temme, Sergey Bravyi, and Jay M. Gambetta, Error Mitigation for Short-Depth Quantum Circuits, Phys. Rev. Lett. 119 (2017).
[7] Czarnik, Piotr, et al. Error mitigation with Clifford quantum-circuit data, Quantum 5 (2021).
[8] Sergey Bravyi, Sarah Sheldon, Abhinav Kandala, David C. Mckay, and Jay M. Gambetta, Mitigating measurement errors in multiqubit experiments, Phys. Rev. A 103 (2021).
[9] Endo, S., Hybrid Quantum-Classical Algorithms and Error Mitigation, PhD thesis, University of Oxford, (2019).
[10] T. Giurgica-Tiron, Y. Hindy, R. LaRose, A. Mari and W. J. Zeng, Digital zero noise extrapolation for quantum error mitigation, IEEE International Conference on Quantum Computing and Engineering (QCE) pp. 306–316, (2020).
[11] LaRose, Ryan, et al., Mitiq: A software package for error mitigation on noisy quantum computers., Quantum 6, 774 (2022).
[12] Nielsen, Michael A., and Isaac L. Chuang. Quantum computation and quantum information., Phys. Today 54.2: 60 (2001).