English
Languages
English
Japanese
Spanish

Error suppression and error mitigation with Qiskit Runtime

Pedro Rivero
Quantum Developer @ IBM Quantum
Mariana Bernagozzi
Software Engineer @ IBM Quantum
[1]:
import datetime
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

plt.rcParams.update({"text.usetex": True})
plt.rcParams["figure.figsize"] = (6, 4)
mpl.rcParams["figure.dpi"] = 200

from qiskit_ibm_runtime import Estimator, Session, QiskitRuntimeService, Options
from qiskit.quantum_info import SparsePauliOp
from qiskit import QuantumCircuit

service = QiskitRuntimeService()

Introduction

To illustrate the need for error suppression and mitigation, we will start by taking a look at some results without error suppression or error mitigation. First, we are going to use a noiseless simulator to get an idea of what ideal results look like. Next, we are going to run the same experiment in a real backend without using error suppression or error mitigation.

The following code cell defines a list of Trotter circuits for use in the experiments.

Create a Trotter circuit

[2]:
backend_simulator = "ibmq_qasm_simulator"
backend = "ibmq_montreal"

qubits = 4
trotter_layer = QuantumCircuit(qubits)
trotter_layer.rx(0.1, range(qubits))
trotter_layer.cx(0, 1)
trotter_layer.cx(2, 3)
trotter_layer.rz(-0.2, [1, 3])
trotter_layer.cx(0, 1)
trotter_layer.cx(2, 3)
trotter_layer.cx(1, 2)
trotter_layer.rz(-0.2, 2)
trotter_layer.cx(1, 2)

num_steps = 6
trotter_circuit_list = []
for i in range(1, num_steps):
    trotter_circuit = QuantumCircuit(qubits)
    for _ in range(i):
        trotter_circuit = trotter_circuit.compose(trotter_layer)
    trotter_circuit_list.append(trotter_circuit)
    print(f"Trotter circuit with {i} Trotter steps")
    display(trotter_circuit.draw(fold=-1))

obs = SparsePauliOp("Z" * qubits)
obs_list = [obs] * len(trotter_circuit_list)
Trotter circuit with 1 Trotter steps
     ┌─────────┐
q_0: ┤ Rx(0.1) ├──■────────────────■────────────────────────
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐
q_1: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──■────────────────■──
     ├─────────┤└───┘└──────────┘└───┘┌─┴─┐┌──────────┐┌─┴─┐
q_2: ┤ Rx(0.1) ├──■────────────────■──┤ X ├┤ Rz(-0.2) ├┤ X ├
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐└───┘└──────────┘└───┘
q_3: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──────────────────────
     └─────────┘└───┘└──────────┘└───┘                      
Trotter circuit with 2 Trotter steps
     ┌─────────┐                      ┌─────────┐
q_0: ┤ Rx(0.1) ├──■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■────────────────────────
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐
q_1: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──■────────────────■──
     ├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘┌─┴─┐┌──────────┐┌─┴─┐
q_2: ┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■──┤ X ├┤ Rz(-0.2) ├┤ X ├
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐└───┘└──────────┘└───┘
q_3: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├──────────────────────
     └─────────┘└───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘                      
Trotter circuit with 3 Trotter steps
     ┌─────────┐                      ┌─────────┐                                                  ┌─────────┐
q_0: ┤ Rx(0.1) ├──■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■────────────────────────
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐
q_1: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──■────────────────■──
     ├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘┌─┴─┐┌──────────┐┌─┴─┐
q_2: ┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■──┤ X ├┤ Rz(-0.2) ├┤ X ├
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐└───┘└──────────┘└───┘
q_3: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├──────────────────────
     └─────────┘└───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘                      
Trotter circuit with 4 Trotter steps
     ┌─────────┐                      ┌─────────┐                                                  ┌─────────┐                                                  ┌─────────┐
q_0: ┤ Rx(0.1) ├──■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■────────────────────────
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐
q_1: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──■────────────────■──
     ├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘┌─┴─┐┌──────────┐┌─┴─┐
q_2: ┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■──┤ X ├┤ Rz(-0.2) ├┤ X ├
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐└───┘└──────────┘└───┘
q_3: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├──────────────────────
     └─────────┘└───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘                      
Trotter circuit with 5 Trotter steps
     ┌─────────┐                      ┌─────────┐                                                  ┌─────────┐                                                  ┌─────────┐                                                  ┌─────────┐
q_0: ┤ Rx(0.1) ├──■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■──┤ Rx(0.1) ├──────────────────────────────■────────────────■────────────────────────
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐└─────────┘                 ┌─────────┐┌─┴─┐┌──────────┐┌─┴─┐
q_1: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├─────■───────────────────■──┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├──■────────────────■──
     ├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘   ┌─┴─┐   ┌──────────┐┌─┴─┐├─────────┤└───┘└──────────┘└───┘┌─┴─┐┌──────────┐┌─┴─┐
q_2: ┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■─────┤ X ├───┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├──■────────────────■──┤ X ├┤ Rz(-0.2) ├┤ X ├
     ├─────────┤┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐┌──┴───┴──┐└──────────┘└───┘└─────────┘┌─┴─┐┌──────────┐┌─┴─┐└───┘└──────────┘└───┘
q_3: ┤ Rx(0.1) ├┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├┤ Rx(0.1) ├────────────────────────────┤ X ├┤ Rz(-0.2) ├┤ X ├──────────────────────
     └─────────┘└───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘└─────────┘                            └───┘└──────────┘└───┘                      

Simulator run

[4]:
options = Options()
options.execution.shots = 1000
options.optimization_level = 0  # No optimization
options.resilience_level = 0  # No mitigation

with Session(service=service, backend=backend_simulator) as session:
    estimator_sim = Estimator(session=session, options=options)
    job_sim = estimator_sim.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_sim.job_id)
    print(job_sim.result())

expvals_ideal = job_sim.result().values
expvals_ideal_variance = [
    metadata["variance"] / metadata["shots"] for metadata in job_sim.result().metadata
]
std_error_ideal = np.sqrt(expvals_ideal_variance)
job id: cdkrpbpg1234sbmtrt3g
EstimatorResult(values=array([0.98 , 0.926, 0.872, 0.796, 0.68 ]), metadata=[{'variance': 0.03960000000000008, 'shots': 1000}, {'variance': 0.14252399999999987, 'shots': 1000}, {'variance': 0.23961600000000005, 'shots': 1000}, {'variance': 0.36638399999999993, 'shots': 1000}, {'variance': 0.5375999999999999, 'shots': 1000}])

Unmitigated, real backend

[5]:
options = Options()
options.execution.shots = 1000
options.optimization_level = 0  # No optimization
options.resilience_level = 0  # No error mitigation

with Session(service=service, backend=backend) as session:
    estimator = Estimator(session=session, options=options)
    job = estimator.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job.job_id)
    print(job.result())

expvals_unmit = job.result().values
expvals_unmit_variance = [
    metadata["variance"] / metadata["shots"] for metadata in job.result().metadata
]
std_error_unmit = np.sqrt(expvals_unmit_variance)
job id: cdkrpeaan60ka16e8340
EstimatorResult(values=array([0.786, 0.74 , 0.636, 0.562, 0.446]), metadata=[{'variance': 0.382204, 'shots': 1000}, {'variance': 0.4524, 'shots': 1000}, {'variance': 0.595504, 'shots': 1000}, {'variance': 0.684156, 'shots': 1000}, {'variance': 0.801084, 'shots': 1000}])

Theory and background

IBM Quantum

We want to build a tool which, beginning in 2024, is capable of estimating noise-free observables of 100-qubit circuits, with depth 100, within one day.

Although this is not a promise for quantum advantage per-se, the goal is to get to the point where we can solve interesting or relevant problems faster, more accurately, or more cheaply in a practical time frame as compared to efficient classical computations.

The threshold for simulability seems to be at around 100 qubits. However, this is not enough qubits, as we also need a sufficiently complex quantum circuit to ensure that it cannot be reproduced classically. For example, deep, non-clifford.

f6903d1f0ae34d94bcd24f516c2ebc5f

With errors per gate of order 1E-3, we estimate a final fidelity of such a computation of about 1E-6, which implies totally meaningless results.

Fault tolerant quantum computing

Errors are a natural occurrence in any computer. In quantum computers, these errors are usually more complex and happen when the quantum states are not prepared exactly how they should. For example, overshooting their target values or drifting away. Furthermore, the disturbances that generate these issues are typically unavoidable.

There are several ways to handle these errors. The terminology can get confusing, as there is disagreement even within the field. We will break it into three core pieces:

  1. Suppression

  2. Mitigation

  3. Correction

Let’s start with the error correction, since it was the first one to be formally discovered within the field.

Error correction

Error correction in classical computers is the standard procedure of encoding information in redundant ways to make it resilient to unwanted noise —allowing us to detect and correct errors as they occur.

It has being known for a long time that the coupling of quantum systems to their environment sets a limit for any quantum computation, both in time and size. Nonetheless, theoretical discoveries in the form of Quantum error correction solved this issue early on.

THRESHOLD THEOREM

If errors in quantum computers can be reduced below certain (finite) level, a fault-tolerant quantum computation could be carried out arbitrarily long even in noisy hardware.

Reference: M.A. Nielsen, and I.L. Chuang, Quantum Computation and Quantum Information.

This is how we hope to achieve the ultimate goal of fault-tolerant quantum computation. However, even if we build hardware that can achieve the prescribed threshold, the overhead for performing full error correction, such as the necessary qubit count, makes it infeasible in the short term; as we will try to encode single qubit logical values across multiple physical qubits:

\[n/d = 100/100 \quad\]
\[p = \text{1E-3} \quad\]
\[p = \text{1E-4} \quad\]
\[p = \text{1E-5} \quad\]

Runtime [\(s\)]

2.3

1.2

0.8

Physical qubits

140k

40k

16k

Distance

21

11

7

These surface code resources* are well beyond our 2025 roadmap plans, although we are working hard in this area to make it feasible as soon as possible.

* The data in the previous table is based on simulations for surface codes with certain conditions. The code distance was chosen so that none of the T-gates, or 100 logical qubits at the end of runtime, had error greater than \(1\text{E}-2\). The number of T-gates is \(n \times d\) and each parity check cycle takes \(1 \mu s\).

Reference: Daniel Litinski, A Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery, arXiv:1808.02892

Error suppression

Error suppression is the most basic level of error handling. It often refers to a set of techniques performed close to hardware, such as altering control signals (that is, at Qiskit Pulse level). To make it simpler, we define these techniques as introducing classical overhead, usually within the transpilation/compilation process.

These techniques are very old and were first developed outside of the field at the same time as some of the first controllable quantum systems such as magnetic resonance imaging devices.

Dynamical decoupling (DD)

Quantum computers have adopted some of these techniques like spin echos (a sequence of pulses that can help refocus the state of a qubit). As a matter of fact, spin echos play a big role in a class of techniques known as Dynamical Decoupling (DD), which sends pulses to idle qubits to reset their value to their original states, undoing the potentially harmful effects of nearby qubits that are being used for the calculation.

Reference: Lorenza Viola, and Seth Lloyd , Dynamical suppression of decoherence in two-state quantum systems, arXiv:quant-ph/9803057

[6]:
options = Options()
options.execution.shots = 1000
options.optimization_level = 3  # Dynamical decoupling
options.resilience_level = 0  # No error mitigation

with Session(service=service, backend=backend) as session:
    estimator = Estimator(session=session, options=options)
    job_dd = estimator.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_dd.job_id)
    print(job_dd.result())

expvals_unmit_dd = job_dd.result().values
expvals_unmit_dd_variance = [
    metadata["variance"] / metadata["shots"] for metadata in job_dd.result().metadata
]
std_error_dd = np.sqrt(expvals_unmit_dd_variance)
job id: cdkrpk5f14jb6brgbmt0
EstimatorResult(values=array([0.87 , 0.752, 0.598, 0.484, 0.396]), metadata=[{'variance': 0.24309999999999998, 'shots': 1000}, {'variance': 0.434496, 'shots': 1000}, {'variance': 0.642396, 'shots': 1000}, {'variance': 0.765744, 'shots': 1000}, {'variance': 0.8431839999999999, 'shots': 1000}])
[7]:
plt.title("Trotter circuits expectation value")
plt.errorbar(
    range(1, num_steps),
    expvals_ideal,
    std_error_ideal,
    fmt="o",
    linestyle="--",
    capsize=4,
    c="red",
    label="Ideal",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit,
    std_error_unmit,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="green",
    label="No mitigation",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit_dd,
    std_error_dd,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="blue",
    label="Dynamical decoupling",
)

plt.ylabel(f"$\langle ZZZZ \\rangle$")
plt.xlabel("No. Trotter Steps")
plt.xticks([1, 2, 3, 4, 5])
plt.legend()
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_16_0.png

Error mitigation

Error mitigation introduces quantum overhead to our calculations.

Typically, error correction uses the outputs of multiple ensembles of noisy calculations to reduce or eliminate the noise in estimating quantities like expectation values — commonly by using classical post-processing. In this regard, error mitigation is different from error correction. Rather than fixing errors in every circuit run, errors are allowed to occur, then better results are inferred from several of these noisy calculations.

Since there is no threshold that one must surpass before quantum error mitigation becomes practical, we see error mitigation as the key to realizing useful quantum computers in the near term.

We are developing a portfolio of different error mitigation techniques, looking for three main things:

  • Small overhead (speed)

  • Improved accuracy (quality)

  • Few assumptions (scale)

Each method come with their own associated overhead: a trade-off between the number of quantum computations needed (time) and the accuracy of our results. The level of accuracy that can be achieved is also specific to each method, and is usually inversely proportional to the previously mentioned overhead. Defining \(\lambda\) as the base noise in our computation:

Methods

T-REx

ZNE

PEC

Assumptions

None

Ability to scale the noise

Full knowledge of the noise

Qubit overhead

\(1\)

\(1\)

\(1\)

Sampling overhead

\(2\)

\(N_\text{noise-factors}\)

\(\mathcal{O}(e^{\lambda N_\text{layers}})\)

Bias

\(0\)

\(\mathcal{O}(\lambda^{N_\text{noise-factors}})\)

\(0\)

More detailed information is available at:

By having a portfolio of methods, users can choose which technique makes the most sense for their problem of interest, based on accuracy demands and how much overhead they are willing to accept. We are excited about this because, in the best scenarios, we can achieve unbiased results (that is, noise-free); and we want to make this capability accessible all across the stack: from kernel to algorithm and model developers.

Why is error mitigation important?

We need improvements in scale, quality, and speed.

The promise of error mitigation is to translate the continuous progress in quantum hardware into continuous improvements in quantum computations and quantum information processing. We expect that, while insufficient to fully overcome imperfections, every advancement should incrementally push the frontier of what can be achieved practically; as opposed to a scenario where little to no progress is made until we suddenly overcome the fault-tolerant threshold.

5e12cf8974b04929aa75e07921f6634b

Beyond the 100x100 circuit, we envision a future where error correction and error mitigation can work in a hybrid way. In that regard, this approach has proven to be both practically effective and intellectually challenging.

Concepts

The following terms are used in this section.

TERMINOLOGY

As with every nascent field, terminology is sometimes incosistent: people use the same terms to refer to (slightly) different things.

  • Estimators: Strategies for approximating certain physical values that are fundamentally unknown.

  • Sampling: The process of taking several measurements of one or several things.

  • Overhead: Extra costs introduced by new techniques, relative to a base implementation.

  • Bias: A systematic drift in the measured quantities, usually caused by errors.

  • Shot/sample noise: Uncertainty in the obtained results due to a lack of infinite precision (that is, a finite number of samples).

Implications

When implementing any error mitigation technique, we expect the bias in our results to be reduced with respect to the previous, unmitigated, bias; in some cases even disappearing. However, this comes at a cost. As we reduce the bias in our estimated quantities, the statistical variability will increase (that is, variance), which we can account for by further increasing the number of shots per circuit in our sampling process. This will introduce overhead beyond that needed to reduce the bias, therefore it is not done by default. The user can easily opt in to this behavior by adjusting the amount of shots per circuit in run_options.

In mathematical terms, we expect our error mitigated estimator to be such that:

\[\begin{split}0 \leq | \text{Bias}[{\langle}O{\rangle}_\text{em}] | \leq | \text{Bias}[{\langle}O{\rangle}_\text{noisy}] | \\ | \text{Var}[{\langle}O{\rangle}_\text{em}] | \geq | \text{Var}[{\langle}O{\rangle}_\text{noisy}] | > 0\end{split}\]

6102d534b41a4c619f3dc383e2c5e949

Twirled readout error extinction

Twirled readout error extinction (T-REx) uses a technique known as Pauli twirling to reduce the noise introduced during the process of quantum measurement. This technique assumes no specific form of noise, which makes it very general and effective.

Overall workflow

  1. Acquire data for the zero state with randomized bit flips (Pauli X before measurement)

  2. Acquire data for the desired (noisy) state with randomized bit flips (Pauli X before measurement)

  3. Compute the special function for each data set, and divide.

5873742608cf42bc9f0a55f4fe788f6e

Reference: E. van den Berg, Z. Minev, and K. Temme, Model-free readout-error mitigation for quantum expectation values arXiv:2012.09738

[8]:
options = Options()
options.resilience_level = 1  # T-REx
options.optimization_level = 0  # No optimization
options.execution.shots = 1000

with Session(service=service, backend=backend) as session:
    estimator = Estimator(session=session, options=options)
    job_trex = estimator.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_trex.job_id)
    print(job_trex.result())

expvals_unmit_trex = job_trex.result().values
expvals_unmit_trex_variance = [
    metadata["variance"] / metadata["shots"] for metadata in job_trex.result().metadata
]
std_error_trex = np.sqrt(expvals_unmit_trex_variance)
job id: cdkrpq7tlcfkm5f0demg
EstimatorResult(values=array([0.95941791, 0.81652588, 0.68894371, 0.55625825, 0.45674416]), metadata=[{'variance': 0.733385959939609, 'shots': 1008, 'readout_mitigation_num_twirled_circuits': 16, 'readout_mitigation_shots_calibration': 8192}, {'variance': 0.9871541699414397, 'shots': 1008, 'readout_mitigation_num_twirled_circuits': 16, 'readout_mitigation_shots_calibration': 8192}, {'variance': 1.1792252443219302, 'shots': 1008, 'readout_mitigation_num_twirled_circuits': 16, 'readout_mitigation_shots_calibration': 8192}, {'variance': 1.3444454335924159, 'shots': 1008, 'readout_mitigation_num_twirled_circuits': 16, 'readout_mitigation_shots_calibration': 8192}, {'variance': 1.4452534486647257, 'shots': 1008, 'readout_mitigation_num_twirled_circuits': 16, 'readout_mitigation_shots_calibration': 8192}])
[9]:
plt.title("Trotter circuits expectation value")
plt.errorbar(
    range(1, num_steps),
    expvals_ideal,
    std_error_ideal,
    fmt="o",
    linestyle="--",
    capsize=4,
    c="red",
    label="Ideal",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit,
    std_error_unmit,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="green",
    label="No mitigation",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit_trex,
    std_error_trex,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="violet",
    label="T-REx",
)

plt.ylabel(f"$\langle ZZZZ \\rangle$")
plt.xlabel("No. Trotter Steps")
plt.xticks([1, 2, 3, 4, 5])
plt.legend()
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_26_0.png

Zero noise extrapolation

Zero noise extrapolation (ZNE) works by first amplifying the noise in the circuit that is preparing the desired quantum state, obtaining measurements for several different levels of noise, and using those measurements to infer the noiseless result.

Overall workflow

  1. Amplify circuit noise for several noise factors

  2. Run every noise amplified circuit

  3. Extrapolate back to the zero noise limit

8496cb549ad84e3e95da677ea09c2d4b

[10]:
options = Options()
options.execution.shots = 1000
options.optimization_level = 0  # No optimization
options.resilience_level = 2  # ZNE

with Session(service=service, backend=backend) as session:
    estimator = Estimator(session=session, options=options)
    job_zne = estimator.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_zne.job_id)
    print(job_zne.result())

expvals_unmit_zne = job_zne.result().values
# Standard error: coming soon!
job id: cdkrq4i2h6kvivdb2an0
EstimatorResult(values=array([0.896     , 0.86833333, 0.82716667, 0.63116667, 0.58366667]), metadata=[{'zne': {'noise_amplification': {'noise_amplifier': "<TwoQubitAmplifier:{'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 3, 5], 'values': [0.84, 0.788, 0.664], 'variance': [0.2944000000000001, 0.37905599999999995, 0.5591039999999999], 'shots': [1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'LinearExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<TwoQubitAmplifier:{'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 3, 5], 'values': [0.778, 0.614, 0.43], 'variance': [0.39471599999999996, 0.623004, 0.8151], 'shots': [1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'LinearExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<TwoQubitAmplifier:{'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 3, 5], 'values': [0.718, 0.498, 0.28], 'variance': [0.484476, 0.751996, 0.9216], 'shots': [1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'LinearExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<TwoQubitAmplifier:{'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 3, 5], 'values': [0.54, 0.376, 0.19], 'variance': [0.7083999999999999, 0.858624, 0.9639], 'shots': [1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'LinearExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<TwoQubitAmplifier:{'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 3, 5], 'values': [0.498, 0.31, 0.142], 'variance': [0.751996, 0.9039, 0.979836], 'shots': [1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'LinearExtrapolator'}}}])
[11]:
plt.title("Trotter circuits expectation value")
plt.errorbar(
    range(1, num_steps),
    expvals_ideal,
    std_error_ideal,
    fmt="o",
    linestyle="--",
    capsize=4,
    c="red",
    label="Ideal",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit,
    std_error_unmit,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="green",
    label="No mitigation",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit_zne,
    [0] * (num_steps - 1),
    fmt="o",
    linestyle="-",
    capsize=4,
    c="cyan",
    label="ZNE",
)

plt.xlabel("No. Trotter Steps")
plt.ylabel(f"$\langle ZZZZ \\rangle$")
plt.xticks([1, 2, 3, 4, 5])
plt.legend()
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_29_0.png

Probabilistic error cancellation

Probabilistic error cancellation (PEC) samples for a collection of circuits that, on average mimics a noise inverting channel to cancel out the noise in the desired computation. This process is a bit like how noise-cancelling headphones work, and produces great results; however, it is not as general as other methods, and the sampling overhead is exponential.

Reference: E. van den Berg, Z. Minev, A. Kandala, and K. Temme, Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors arXiv:2201.09866

Overall workflow

d8380c2b1c15480ba9bc4c0d91d5e0c4

Step 1: Pauli twirling

83c1fbee768243559bc78407872f5541

Step 2: Repeat layer and learn the noise

6dd6f3dee9f543cfa59d1930b0115267

Step 3: Derive a fidelity (error for each noise channel)

b885104a24db4d67bfa1c1c4652107d4

[ ]:
def interim_results_callback(job_id, result):
    now = datetime.datetime.now()
    print(now, "*** Callback ***", result, "\n")


options = Options()
options.optimization_level = 0  # No optimization
options.execution.shots = 100
options.resilience_level = 3  # PEC
options.environment.callback = interim_results_callback

with Session(service=service, backend=backend) as session:
    estimator_pec = Estimator(session=session, options=options)
    job_pec = estimator_pec.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_pec.job_id)

expvals_pec = job_pec.result().values
std_error_pec = [metadata["standard_error"] for metadata in job_pec.result().metadata]
job id: cdkqv522h6kvivdat0vg
2022-11-07 20:23:43.013816 *** Callback *** {'unique_layers_detected': 2, 'total_layers': 60}

2022-11-07 20:30:41.251325 *** Callback *** {'msg': 'Sampling overhead for layer 1/2: 1.0263820029324646'}

2022-11-07 20:37:38.920151 *** Callback *** {'msg': 'Sampling overhead for layer 2/2: 1.0692954781746'}

2022-11-07 20:37:39.334815 *** Callback *** {'sampling_overhead_by_layer': [1.0692954781746, 1.0263820029324646], 'unique_layers': 2, 'total_sampling_overhead': 1.4508651011392564}

2022-11-07 20:37:39.336883 *** Callback *** {'sampling_overhead_by_layer': [1.0692954781746, 1.0263820029324646], 'unique_layers': 2, 'total_sampling_overhead': 1.2045186180127132}

2022-11-07 20:37:39.336983 *** Callback *** {'sampling_overhead_by_layer': [1.0692954781746, 1.0263820029324646], 'unique_layers': 2, 'total_sampling_overhead': 1.7475940265471324}

2022-11-07 20:37:39.337099 *** Callback *** {'sampling_overhead_by_layer': [1.0692954781746, 1.0263820029324646], 'unique_layers': 2, 'total_sampling_overhead': 2.105009541703825}

2022-11-07 20:37:39.338120 *** Callback *** {'sampling_overhead_by_layer': [1.0692954781746, 1.0263820029324646], 'unique_layers': 2, 'total_sampling_overhead': 2.5355231840766654}

2022-11-07 20:44:17.157534 *** Callback *** {'values': array([0.96681631, 0.96346463, 0.81458917, 0.83279075, 0.71165489]), 'metadata': [{'standard_error': 0.04741526161355738, 'confidence_interval': [0.6946850904749993, 1.2389475260753755], 'confidence_level': 0.95, 'shots': 15360, 'samples': 120, 'sampling_overhead': 1.2045186180127132, 'total_mitigated_layers': 4}, {'standard_error': 0.06003453067758544, 'confidence_interval': [0.6917633123010369, 1.235165948939192], 'confidence_level': 0.95, 'shots': 18560, 'samples': 145, 'sampling_overhead': 1.4508651011392564, 'total_mitigated_layers': 8}, {'standard_error': 0.07893102265063534, 'confidence_interval': [0.5423767896024972, 1.086801560321982], 'confidence_level': 0.95, 'shots': 22272, 'samples': 174, 'sampling_overhead': 1.7475940265471324, 'total_mitigated_layers': 12}, {'standard_error': 0.08198342212333354, 'confidence_interval': [0.5608466609152284, 1.104734830411759], 'confidence_level': 0.95, 'shots': 26880, 'samples': 210, 'sampling_overhead': 2.105009541703825, 'total_mitigated_layers': 16}, {'standard_error': 0.08955468433998504, 'confidence_interval': [0.43973826826406204, 0.9835715192472465], 'confidence_level': 0.95, 'shots': 32384, 'samples': 253, 'sampling_overhead': 2.5355231840766654, 'total_mitigated_layers': 20}]}

[ ]:
plt.title("Trotter circuits expectation value")
plt.errorbar(
    range(1, num_steps),
    expvals_ideal,
    std_error_ideal,
    fmt="o",
    linestyle="--",
    capsize=4,
    c="red",
    label="Ideal",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit,
    std_error_unmit,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="green",
    label="No mitigation",
)
plt.errorbar(
    range(1, num_steps),
    expvals_pec,
    std_error_pec,
    fmt="d",
    linestyle="-",
    capsize=4,
    c="orange",
    label="PEC",
)

plt.ylabel(f"$\langle ZZZZ \\rangle$")
plt.xlabel("No. Trotter Steps")
plt.xticks([1, 2, 3, 4, 5])
plt.legend()
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_35_0.png

PEC callback messages explained

Layers detected:

2022-11-07 20:23:43.013816 *** Callback *** {'unique_layers_detected': 2, 'total_layers': 60}

In the list of circuits passed to the Estimator, a total of 60 layers were detected and two of them were unique. Qiskit Runtime will learn the noise model for the two unique layers.

Sampling overhead for layers:

2022-11-07 20:30:41.251325 *** Callback *** {'msg': 'Sampling overhead for layer 1/2: 1.0263820029324646'}

2022-11-07 20:37:38.920151 *** Callback *** {'msg': 'Sampling overhead for layer 2/2: 1.0692954781746'}

These messages show the sampling overhead for each of the unique layers. Notice that it took roughly 7 minutes to learn the noise model of each layer.

PEC callback messages explained

Layers detected:

2022-11-07 20:23:43.013816 *** Callback *** {'unique_layers_detected': '2, total_layers: 60'}

In the list of circuits passed to Estimator, a total of 60 layers were detected and two of them were unique. Qiskit Runtime will learn the noise model for the two unique layers.

Sampling overhead for layers:

2022-11-07 20:30:41.251325 *** Callback *** {'msg': 'Sampling overhead for layer 1/2: 1.0263820029324646'} 2022-11-07 20:37:38.920151 *** Callback *** {'msg': 'Sampling overhead for layer 2/2: 1.0692954781746'}

These messages show the sampling overhead for each of the unique layers. Notice that it took roughly 7 minutes to learn the noise model of each layer.

Circuit total sampling overhead

  • Circuit 1 total sampling overhead: 1.2045186180127132

    2022-11-07 20:37:39.336883 *** Callback *** {sampling_overhead_by_layer: [1.0692954781746, 1.0263820029324646], unique_layers: 2, total_sampling_overhead: 1.2045186180127132}

  • Circuit 2 total sampling overhead: 1.4508651011392564

    2022-11-07 20:37:39.334815 *** Callback *** {sampling_overhead_by_layer: [1.0692954781746, 1.0263820029324646], unique_layers: 2, total_sampling_overhead: 1.4508651011392564}

  • Circuit 3 total sampling overhead: 1.7475940265471324

    2022-11-07 20:37:39.336983 *** Callback *** {sampling_overhead_by_layer: [1.0692954781746, 1.0263820029324646], unique_layers: 2, total_sampling_overhead: 1.7475940265471324}

  • Circuit 4 total sampling overhead: 2.105009541703825

    2022-11-07 20:37:39.337099 *** Callback *** {sampling_overhead_by_layer: [1.0692954781746, 1.0263820029324646], unique_layers: 2, total_sampling_overhead: 2.105009541703825}

  • Circuit 5 total sampling overhead: 2.5355231840766654

    2022-11-07 20:37:39.338120 *** Callback *** {sampling_overhead_by_layer: [1.0692954781746, 1.0263820029324646], unique_layers: 2, total_sampling_overhead: 2.5355231840766654}

The sampling overhead increases when there are more layers to mitigate.

[ ]:
print(job_pec.result())
EstimatorResult(values=array([0.96681631, 0.96346463, 0.81458917, 0.83279075, 0.71165489]), metadata=[{'standard_error': 0.04741526161355738, 'confidence_interval': [0.6946850904749993, 1.2389475260753755], 'confidence_level': 0.95, 'shots': 15360, 'samples': 120, 'sampling_overhead': 1.2045186180127132, 'total_mitigated_layers': 4}, {'standard_error': 0.06003453067758544, 'confidence_interval': [0.6917633123010369, 1.235165948939192], 'confidence_level': 0.95, 'shots': 18560, 'samples': 145, 'sampling_overhead': 1.4508651011392564, 'total_mitigated_layers': 8}, {'standard_error': 0.07893102265063534, 'confidence_interval': [0.5423767896024972, 1.086801560321982], 'confidence_level': 0.95, 'shots': 22272, 'samples': 174, 'sampling_overhead': 1.7475940265471324, 'total_mitigated_layers': 12}, {'standard_error': 0.08198342212333354, 'confidence_interval': [0.5608466609152284, 1.104734830411759], 'confidence_level': 0.95, 'shots': 26880, 'samples': 210, 'sampling_overhead': 2.105009541703825, 'total_mitigated_layers': 16}, {'standard_error': 0.08955468433998504, 'confidence_interval': [0.43973826826406204, 0.9835715192472465], 'confidence_level': 0.95, 'shots': 32384, 'samples': 253, 'sampling_overhead': 2.5355231840766654, 'total_mitigated_layers': 20}])

PEC metadata

  • Circuit 1:

{
  "standard_error": 0.04741526161355738,
  "confidence_interval": [
    0.6946850904749993,
    1.2389475260753755
  ],
  "confidence_level": 0.95,
  "shots": 15360,
  "samples": 120,
  "sampling_overhead": 1.2045186180127132,
  "total_mitigated_layers": 4
}
  • Circuit 2:

{
  "standard_error": 0.06003453067758544,
  "confidence_interval": [
    0.6917633123010369,
    1.235165948939192
  ],
  "confidence_level": 0.95,
  "shots": 18560,
  "samples": 145,
  "sampling_overhead": 1.4508651011392564,
  "total_mitigated_layers": 8
}
  • Circuit 3:

{
  "standard_error": 0.07893102265063534,
  "confidence_interval": [
    0.5423767896024972,
    1.086801560321982
  ],
  "confidence_level": 0.95,
  "shots": 22272,
  "samples": 174,
  "sampling_overhead": 1.7475940265471324,
  "total_mitigated_layers": 12
}
  • Circuit 4:

{
  "standard_error": 0.08198342212333354,
  "confidence_interval": [
    0.5608466609152284,
    1.104734830411759
  ],
  "confidence_level": 0.95,
  "shots": 26880,
  "samples": 210,
  "sampling_overhead": 2.105009541703825,
  "total_mitigated_layers": 16
}
  • Circuit 5

{
  "standard_error": 0.08955468433998504,
  "confidence_interval": [
    0.43973826826406204,
    0.9835715192472465
  ],
  "confidence_level": 0.95,
  "shots": 32384,
  "samples": 253,
  "sampling_overhead": 2.5355231840766654,
  "total_mitigated_layers": 20
}
[ ]:
pec_metadata = job_pec.result().metadata
fig, ax = plt.subplots()
fig.subplots_adjust(right=0.75)

twin1 = ax.twinx()
twin2 = ax.twinx()
twin3 = ax.twinx()

twin2.spines.right.set_position(("axes", 1.2))
twin3.spines.right.set_position(("axes", 1.4))

(p1,) = ax.plot(
    range(1, num_steps),
    [m["total_mitigated_layers"] for m in pec_metadata],
    "b-",
    label="Total mitigated layers",
)
(p2,) = twin1.plot(
    range(1, num_steps),
    [m["sampling_overhead"] for m in pec_metadata],
    "r-",
    label="Sampling overhead",
)
(p3,) = twin2.plot(
    range(1, num_steps), [m["samples"] for m in pec_metadata], "g-", label="Samples"
)
(p4,) = twin3.plot(
    range(1, num_steps), [m["shots"] for m in pec_metadata], "c-", label="Shots"
)

ax.set_ylim(0, 20)
twin1.set_ylim(0, 2.8)
twin2.set_ylim(0, 300)
twin3.set_ylim(0, 35000)

ax.set_xlabel("No. Trotter Steps")
ax.set_ylabel("Total mitigated layers")
twin1.set_ylabel("Sampling overhead")
twin2.set_ylabel("Samples")
twin3.set_ylabel("Shots")

ax.yaxis.label.set_color(p1.get_color())
twin1.yaxis.label.set_color(p2.get_color())
twin2.yaxis.label.set_color(p3.get_color())
twin3.yaxis.label.set_color(p4.get_color())

tkw = dict(size=4, width=1.5)
ax.tick_params(axis="y", colors=p1.get_color(), **tkw)
twin1.tick_params(axis="y", colors=p2.get_color(), **tkw)
twin2.tick_params(axis="y", colors=p3.get_color(), **tkw)
twin3.tick_params(axis="y", colors=p4.get_color(), **tkw)
plt.xticks([1, 2, 3, 4, 5])

ax.legend(handles=[p1, p2, p3, p4])

plt.title("PEC metadata")
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_41_0.png

Combined plot

[ ]:
from matplotlib.pyplot import figure

plt.errorbar(
    range(1, num_steps),
    expvals_ideal,
    std_error_ideal,
    fmt="o",
    linestyle="--",
    capsize=4,
    c="red",
    label="Ideal",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit,
    std_error_unmit,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="green",
    label="No mitigation",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit_trex,
    std_error_trex,
    fmt="o",
    linestyle="-",
    capsize=4,
    c="violet",
    label="T-REx",
)
plt.errorbar(
    range(1, num_steps),
    expvals_unmit_zne,
    [0] * (num_steps - 1),
    fmt="o",
    linestyle="-",
    capsize=4,
    c="cyan",
    label="ZNE",
)
plt.errorbar(
    range(1, num_steps),
    expvals_pec,
    std_error_pec,
    fmt="d",
    linestyle="-",
    capsize=4,
    c="orange",
    label="PEC",
)

plt.title("Trotter circuits expectation value")
plt.ylabel(f"$\langle ZZZZ \\rangle$")
plt.xlabel("No. Trotter Steps")
plt.xticks([1, 2, 3, 4, 5])
plt.legend()
plt.show()
../_images/tutorials_Error-Suppression-and-Error-Mitigation_43_0.png

Advanced ZNE options

Noise amplification

As a first approach, we provide a noise amplification technique known as unitary folding.

Reference: Tudor Giurgica-Tiron, Yousef Hindy, Ryan LaRose, Andrea Mari, and William J. Zeng, Digital zero noise extrapolation for quantum error mitigation arXiv:2005.10921.

Digital vs analog

ee52cad195694f0a9fe5752ed85ddb89

Local vs global

c22e2e41293e4038a06082fab1d49b13

Extrapolation

Useful noise profiles

93287b4d54c5424da31ac95363a35da3

Useless noise profiles

b4091f4119dd4572b039a98b4a616ebe

[ ]:
options = Options()
options.execution.shots = 1000
options.optimization_level = 0  # no optimization
options.resilience_level = 2  # ZNE
options.resilience.noise_factors = [1, 2, 3, 4]
options.resilience.noise_amplifier = "LocalFoldingAmplifier"
options.resilience.extrapolator = "QuadraticExtrapolator"

with Session(service=service, backend="ibmq_montreal") as session:
    estimator = Estimator(session=session, options=options)
    job_zne_options = estimator.run(circuits=trotter_circuit_list, observables=obs_list)
    print("job id:", job_zne_options.job_id)
    print(job_zne_options.result())
job id: cdkrqbdf14jb6brgbrl0
EstimatorResult(values=array([0.9285, 0.8165, 0.835 , 0.6815, 0.4945]), metadata=[{'zne': {'noise_amplification': {'noise_amplifier': "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 2, 3, 4], 'values': [0.838, 0.798, 0.738, 0.752], 'variance': [0.297756, 0.36319599999999996, 0.455356, 0.434496], 'shots': [1000, 1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'QuadraticExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 2, 3, 4], 'values': [0.732, 0.676, 0.572, 0.522], 'variance': [0.46417600000000003, 0.543024, 0.6728160000000001, 0.727516], 'shots': [1000, 1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'QuadraticExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 2, 3, 4], 'values': [0.674, 0.51, 0.436, 0.328], 'variance': [0.5457239999999999, 0.7399, 0.809904, 0.892416], 'shots': [1000, 1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'QuadraticExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 2, 3, 4], 'values': [0.512, 0.372, 0.266, 0.188], 'variance': [0.7378560000000001, 0.8616159999999999, 0.929244, 0.964656], 'shots': [1000, 1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'QuadraticExtrapolator'}}}, {'zne': {'noise_amplification': {'noise_amplifier': "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>", 'noise_factors': [1, 2, 3, 4], 'values': [0.442, 0.35, 0.268, 0.13], 'variance': [0.804636, 0.8775000000000001, 0.928176, 0.9831], 'shots': [1000, 1000, 1000, 1000]}, 'extrapolation': {'extrapolator': 'QuadraticExtrapolator'}}}])
{
  "values": [
    0.928499999999999,
    0.8165,
    0.835,
    0.6815000000000001,
    0.49449999999999983
  ],
  "metadata": [
    {
      "zne": {
        "noise_amplification": {
          "noise_amplifier": "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>",
          "noise_factors": [
            1,
            2,
            3,
            4
          ],
          "values": [
            0.838,
            0.798,
            0.738,
            0.752
          ],
          "variance": [
            0.297756,
            0.36319599999999996,
            0.455356,
            0.434496
          ],
          "shots": [
            1000,
            1000,
            1000,
            1000
          ]
        },
        "extrapolation": {
          "extrapolator": "QuadraticExtrapolator"
        }
      }
    },
    {
      "zne": {
        "noise_amplification": {
          "noise_amplifier": "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>",
          "noise_factors": [
            1,
            2,
            3,
            4
          ],
          "values": [
            0.732,
            0.676,
            0.572,
            0.522
          ],
          "variance": [
            0.46417600000000003,
            0.543024,
            0.6728160000000001,
            0.727516
          ],
          "shots": [
            1000,
            1000,
            1000,
            1000
          ]
        },
        "extrapolation": {
          "extrapolator": "QuadraticExtrapolator"
        }
      }
    },
    {
      "zne": {
        "noise_amplification": {
          "noise_amplifier": "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>",
          "noise_factors": [
            1,
            2,
            3,
            4
          ],
          "values": [
            0.674,
            0.51,
            0.436,
            0.328
          ],
          "variance": [
            0.5457239999999999,
            0.7399,
            0.809904,
            0.892416
          ],
          "shots": [
            1000,
            1000,
            1000,
            1000
          ]
        },
        "extrapolation": {
          "extrapolator": "QuadraticExtrapolator"
        }
      }
    },
    {
      "zne": {
        "noise_amplification": {
          "noise_amplifier": "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>",
          "noise_factors": [
            1,
            2,
            3,
            4
          ],
          "values": [
            0.512,
            0.372,
            0.266,
            0.188
          ],
          "variance": [
            0.7378560000000001,
            0.8616159999999999,
            0.929244,
            0.964656
          ],
          "shots": [
            1000,
            1000,
            1000,
            1000
          ]
        },
        "extrapolation": {
          "extrapolator": "QuadraticExtrapolator"
        }
      }
    },
    {
      "zne": {
        "noise_amplification": {
          "noise_amplifier": "<LocalFoldingAmplifier:{'gates_to_fold': None, 'noise_factor_relative_tolerance': 0.01, 'random_seed': None, 'sub_folding_option': 'from_first'}>",
          "noise_factors": [
            1,
            2,
            3,
            4
          ],
          "values": [
            0.442,
            0.35,
            0.268,
            0.13
          ],
          "variance": [
            0.804636,
            0.8775000000000001,
            0.928176,
            0.9831
          ],
          "shots": [
            1000,
            1000,
            1000,
            1000
          ]
        },
        "extrapolation": {
          "extrapolator": "QuadraticExtrapolator"
        }
      }
    }
  ]
}
[ ]:
from qiskit.tools import jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.2
qiskit-aer0.11.0
qiskit-ibmq-provider0.19.2
System information
Python version3.10.4
Python compilerClang 12.0.0
Python buildmain, Mar 31 2022 03:38:35
OSDarwin
CPUs4
Memory (Gb)16.0
Tue Nov 08 12:15:46 2022 EST

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.