Concepts Intermediate Free 15/53 in series 12 min read

Noise Mitigation with Mitiq

How to reduce the effect of quantum hardware noise using Mitiq's zero-noise extrapolation and probabilistic error cancellation techniques without full error correction.

What you'll learn

  • noise mitigation
  • zero-noise extrapolation
  • probabilistic error cancellation
  • Mitiq

Prerequisites

  • Python proficiency
  • Beginner quantum computing concepts (superposition, entanglement)
  • Linear algebra basics

The Gap Between NISQ and Fault-Tolerant

Current quantum hardware sits in an awkward middle ground. Devices have tens to hundreds of qubits, but gate error rates of 0.1% to 1% mean that circuits deeper than a few hundred gates produce outputs dominated by noise rather than signal. Full quantum error correction (QEC) would fix this, but it requires thousands of physical qubits per logical qubit and is years away at scale.

Error mitigation fills the gap. It cannot correct errors the way QEC does, because it operates at the software level without additional qubit overhead. What it can do is statistically reduce the bias in expectation value estimates by running slightly modified versions of the same circuit and combining the results cleverly.

The key distinction:

  • Error correction detects and fixes individual errors in real time. Outputs are (ideally) noiseless.
  • Error mitigation reduces systematic bias in expectation values. Outputs are still noisy, but the bias from hardware noise is reduced.
  • No mitigation gives you the raw noisy expectation value, which can be far from the ideal result.

Mitiq is an open-source Python library from Unitary Fund that implements several mitigation techniques and works with Cirq, Qiskit, PyQuil, and other frontends.

Installing Mitiq

pip install mitiq

Mitiq uses Cirq as its internal circuit representation but provides converters for Qiskit and other frameworks. For this tutorial, circuits are written directly in Cirq.

Zero-Noise Extrapolation

Zero-noise extrapolation (ZNE) is built on a simple idea: if you can run the same circuit at several different noise levels, you can extrapolate the results back to zero noise.

The procedure:

  1. Run the circuit at its natural noise level (scale factor 1).
  2. Artificially increase the noise by stretching gates (scale factors 2, 3, …).
  3. Fit a curve through the (noise level, expectation value) pairs.
  4. Extrapolate the fit to noise level 0.

The expectation value as a function of noise level lambda is approximately:

E(lambda) = E_ideal + a*lambda + b*lambda^2 + ...

Linear extrapolation uses two points; Richardson extrapolation uses more points and higher-order fits for better accuracy.

Gate folding is the standard way to amplify noise without changing the circuit’s mathematical operation. Replacing a gate G with G G+ G (gate, its inverse, gate again) is mathematically equivalent (same unitary) but passes through the gate three times, accumulating roughly three times the gate error. A scale factor of 2k+1 is achieved by folding k times.

ZNE Example in Mitiq

This example estimates the expectation value of Z on a two-qubit circuit and compares mitigated vs unmitigated results.

import cirq
import numpy as np
from mitiq import zne
from mitiq.zne.scaling import fold_gates_at_random

# Define qubits
q0, q1 = cirq.LineQubit.range(2)

# Build a simple circuit: Bell state preparation then partial rotation
# Ideal expectation value of Z0 is 0 for a Bell state
circuit = cirq.Circuit([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.rz(np.pi / 3)(q0),
])

print("Circuit:")
print(circuit)

# Define an executor: simulates the circuit with depolarizing noise
# and returns the expectation value of Z on q0
def noisy_executor(circuit, noise_level=0.01):
    """
    Simulate circuit with depolarizing noise and return <Z0>.
    noise_level: depolarizing probability per gate
    """
    noise_model = cirq.ConstantQubitNoiseModel(
        cirq.depolarize(noise_level)
    )
    simulator = cirq.DensityMatrixSimulator(noise=noise_model)
    result = simulator.simulate(circuit)
    # Expectation value of Z on q0
    rho = result.final_density_matrix
    Z = np.array([[1, 0], [0, -1]])
    # Partial trace over q1 to get q0 density matrix
    rho_q0 = cirq.partial_trace(rho, keep_indices=[0])
    return float(np.real(np.trace(rho_q0 @ Z)))

# Unmitigated result
unmitigated = noisy_executor(circuit)
print(f"\nUnmitigated <Z0>: {unmitigated:.4f}")

# Ideal result (zero noise for reference)
ideal = noisy_executor(circuit, noise_level=0.0)
print(f"Ideal <Z0>:       {ideal:.4f}")

# ZNE with linear extrapolation (scale factors 1, 2, 3)
mitigated = zne.execute_with_zne(
    circuit=circuit,
    executor=lambda c: noisy_executor(c, noise_level=0.01),
    factory=zne.LinearFactory(scale_factors=[1.0, 2.0, 3.0]),
    scale_noise=fold_gates_at_random,
)
print(f"Mitigated <Z0>:   {mitigated:.4f}")

# Example output:
# Unmitigated <Z0>: 0.3821
# Ideal <Z0>:       0.5000
# Mitigated <Z0>:   0.4913

The mitigated result is substantially closer to the ideal value. The quality of the extrapolation depends on how linear the noise model is across the scale factors chosen.

Choosing Scale Factors and Extrapolation Order

More scale factors allow higher-order polynomial fits (Richardson extrapolation), which can be more accurate when the noise-vs-expectation curve is nonlinear:

from mitiq.zne import RichardsonFactory

# Richardson extrapolation with 4 scale factors fits a degree-3 polynomial
mitigated_rich = zne.execute_with_zne(
    circuit=circuit,
    executor=lambda c: noisy_executor(c, noise_level=0.01),
    factory=RichardsonFactory(scale_factors=[1.0, 2.0, 3.0, 4.0]),
    scale_noise=fold_gates_at_random,
)
print(f"Richardson mitigated <Z0>: {mitigated_rich:.4f}")

As a rule of thumb, start with linear extrapolation (2-3 scale factors). Use Richardson extrapolation only if the noise level is high enough that the linear approximation is clearly wrong, because higher-order fits amplify shot noise more aggressively.

Probabilistic Error Cancellation

Probabilistic error cancellation (PEC) is a more powerful but more expensive technique. Rather than amplifying noise and extrapolating, PEC represents the ideal gate as a quasi-probability distribution over noisy operations:

Ideal gate = sum_i c_i * (noisy operation i)

where the c_i are real numbers that can be positive or negative and sum to 1. This quasi-probability representation always exists as long as the noise model is invertible.

To sample from this distribution, you randomly choose operations according to their weights |c_i| and track a sign flip when c_i is negative. Averaging over many shots cancels the noise contribution and recovers the ideal expectation value.

The overhead cost. The variance of the PEC estimator scales as gamma^{2n}, where gamma > 1 is a sampling overhead factor depending on the noise rate, and n is the number of gates. For a circuit with 50 gates each with 1% error, gamma^{2n} can be thousands, meaning you need thousands of times more shots than the unmitigated estimate to achieve the same statistical precision. PEC is therefore practical only for short circuits with low noise rates.

Mitiq provides PEC through mitiq.pec:

# Conceptual usage (requires a calibrated noise representation)
from mitiq import pec

# You would first characterize the noise:
# representations = pec.represent_operations_in_circuit_with_local_depolarizing_noise(
#     circuit, noise_level=0.01
# )
# Then:
# mitigated_pec = pec.execute_with_pec(circuit, executor, representations=representations)

In practice, PEC requires careful noise characterization of your specific hardware backend before it can be applied.

When to Use Each Technique

SituationRecommendation
Estimating expectation values on NISQ hardwareZNE
Circuit is short and noise model is well-characterizedPEC
Sampling from a distribution (not expectation values)Neither (mitigation does not help)
Circuit depth exceeds coherence limitNeither (mitigation overhead too large)
Need exact bitstring probabilitiesFull error correction only

ZNE is the practical starting point for most NISQ applications. It requires no prior knowledge of the noise model and adds only a constant factor of circuit repetitions (one per scale factor). PEC achieves better accuracy in principle but requires exponentially more shots and careful noise characterization.

Limitations

Shot noise amplification. Every mitigation technique increases the effective number of circuit evaluations needed to achieve a given statistical precision. ZNE multiplies the required shots roughly by the number of scale factors squared. PEC overhead grows exponentially with circuit size.

Coherent errors are not mitigated. ZNE works by amplifying incoherent (stochastic) noise and extrapolating. Coherent errors (systematic rotation miscalibrations) are not noise in the stochastic sense and do not extrapolate cleanly to zero.

Model dependence. Linear extrapolation assumes the noise scales linearly with the fold factor. If the actual noise model is nonlinear (which is common for cross-talk or leakage errors), the extrapolation is biased.

Circuit depth limits. Deep circuits have more noise to begin with, so gate folding at high scale factors produces circuits that are effectively random. The useful regime for ZNE is roughly circuits where the unmitigated result is within a factor of 2 of the ideal.

No guarantee of convergence. Mitigation reduces the expectation of bias but does not bound the error. On real hardware, calibration drift and non-stationary noise can cause mitigation to make results worse.

Summary

PropertyZNEPEC
PrincipleExtrapolate to zero noiseQuasi-probability distribution over noisy gates
Shot overheadLinear in scale factorsExponential in circuit size
Noise model required?NoYes
Handles coherent errors?NoPartially
Practical regimeShort to medium circuitsShort circuits, low noise

Mitiq makes both techniques accessible with a consistent Python API. For most NISQ experiments today, starting with ZNE using 3 scale factors is a good default, and comparing mitigated vs unmitigated results across multiple scale factors gives you a sense of how much residual noise remains.

Was this tutorial helpful?