Chapter 13 — Key Takeaways (Error Mitigation)
The mitigation page. §13.7's ordering result is the thing to remember.
★ Mitigation is not correction
| Mitigation | Correction | |
|---|---|---|
| Fixes | the expectation value | the quantum state |
| Qubit overhead | none | 100–1000× |
| Shot overhead | large, grows with depth | modest |
| Deep circuits? | no | yes |
| Available today | yes | not at scale |
| Correct single shot? | no | yes |
Useless for Shor/Grover (they need one correct bitstring). Essential for VQE/QAOA.
Mitigation buys a constant factor of room in front of the exponential wall. It does not move the wall. Circuits mitigation rescues are usually classically simulable — do not call it a path to advantage.
★★ The headline: ORDER MATTERS
4-qubit GHZ, $\langle ZZZZ\rangle$, true value $+1$:
unmitigated + ZNE (linear)
raw +0.91772 (0.08228) +0.92950 (0.07050) -14.3%
readout-mitigated +0.97046 (0.02954) +0.98291 (0.01709) -42.1%
- Readout mitigation alone: −64% for 16 extra circuits.
- ZNE alone: −14% for 12× the two-qubit gate count.
- Both, in the right order: −79%.
ZNE is 3× more effective when it runs second — same technique, same scales, same shots.
$$\text{error}(\lambda) = \underbrace{\lambda\,\varepsilon_{\text{gate}}}_{\text{ZNE removes}} + \underbrace{\varepsilon_{\text{readout}}}_{\text{invariant under folding}}$$
RULE: remove the noise a technique CANNOT scale, before applying a technique that works by scaling noise.
Readout mitigation — the assignment matrix
$$\mathbf{p}_{\text{obs}} = A\,\mathbf{p}_{\text{true}} \Longrightarrow \mathbf{p}_{\text{true}} = A^{-1}\mathbf{p}_{\text{obs}}$$
Measurement error is classical — it acts after the state is gone — so it is an ordinary stochastic matrix. Build from $2^n$ gate-free calibration circuits.
qubits [122,123] 00 01 10 11 <- prepared
00 0.9897 0.0098 0.0115 0.0001
01 0.0046 0.9854 0.0001 0.0090
10 0.0056 0.0001 0.9851 0.0109
11 0.0000 0.0048 0.0033 0.9800
condition number 1.03
Diagonal ~0.985 · single flips ~0.01 · double flips ~0.0001 (100× rarer) → diagonally dominant → safe inversion.
Bell state L1 error: 0.0398 -> 0.0099 4.0x better
Use np.linalg.solve(A, raw), not inv(A) @ raw. Always check the condition number.
★ Three ways it fails
pair cond L1 raw L1 mitigated
GOOD [122,123] 1.03 0.0398 -> 0.0099 IMPROVED (4.0x)
BAD [9,8] 2.05 1.0305 -> 1.0654 *** WORSE ***
STUCK [84,83] 3.7e33 SINGULAR MATRIX
1. It can make things worse. Pair (9,8) has an ECR error of 1.0 — the state died at the gate, not the measurement. Readout mitigation only removes readout error; applied elsewhere it amplifies statistical noise and buys nothing.
2. It can be impossible. The stuck qubit's matrix:
00 0.0000 0.0000 0.0000 0.0000 <- rows 00,10 never occur
01 0.9685 0.9666 0.0159 0.0131 <- cols 00,01 IDENTICAL
10 0.0000 0.0000 0.0000 0.0000
11 0.0315 0.0334 0.9841 0.9869
det 0.0 rank 2 (should be 4)
Rank deficit = qubits whose information was destroyed. $A^{-1}$ does not exist. You cannot invert information that was destroyed. Compute the rank; if deficient, no shot count helps.
3. It does not scale. $2^n$ calibration circuits: n=10 → 1,024; n=20 → 1,048,576; n=50 → 10¹⁵. The exponential is in the calibration. Use tensored (2 circuits, assumes independence) or M3 (never forms the matrix).
ZNE — amplify deliberately, extrapolate to zero
$$U \longrightarrow U(U^\dagger U)^k \quad\text{(gate count} \times (2k{+}1))$$
scale ecr depth <ZZZZ>
1 3 13 +0.91772
3 7 25 +0.89392
5 11 37 +0.87012
7 15 49 +0.84668
linear +0.92950 quadratic +0.92975 exponential +0.93039
spread across extrapolators: 0.00090
⚠️ Fold the LOGICAL circuit, then transpile.
isa.inverse()emitssxdg:IBMInputValueError: The instruction sxdg on qubits (125,) is not supported.Agreement among extrapolators is THE diagnostic. Divergence = extrapolating past the data. Here they agreed to 0.0009 — the extrapolation was fine; the question was wrong.
★ Why it stalled at 0.930
GATE-FREE circuit: <ZZZZ> = +0.96228 -> readout floor 0.03772
total error 0.08228 = gate 0.04456 + readout 0.03772
Folding multiplies gates, not measurements, so readout error is identical at every scale. ZNE can only remove the noise it can scale — and it went after the smaller half.
Dynamical decoupling — verify it is doing anything
variant X added delays correct delta
(no DD) 0 0 0.9801 --
ALAP, skip_reset=True (default) 4 132 0.9801 +0.0000
ALAP, skip_reset=False 254 382 0.9178 -0.0623
ASAP, skip_reset=False 254 382 0.8796 -0.1005
The default did NOTHING — skip_reset_qubits=True + ALAP (schedules late) put the idle period at
the start, on still-in-reset qubits. DD skipped all of it.
added = isa_dd.count_ops().get("x", 0) - isa.count_ops().get("x", 0) # expect HUNDREDS
🔬 You CANNOT evaluate DD on a fake backend — in principle. DD works against correlated, slowly-varying noise.
from_backendis Markovian (Ch. 11 §11.6): memoryless, uncorrelated. Nothing for an echo to reverse, so the 254 pulses contribute only their own error. The simulator lacks the physics. Evaluate on hardware, against a control, or not at all.
⚠️ XY4 needs a Y gate — not in IBM's basis (TranspilerError: Duration of y ... not found).
PEC and twirling
PEC — learn the noise channel, express its inverse as a signed combination, sample and reweight. Unbiased and exact, and the overhead is $\propto \gamma^{2d}$, exponential in depth. Small circuits only.
Twirling — does not reduce error, reshapes it: coherent → stochastic Pauli noise. Coherent errors accumulate linearly and conspire; stochastic ones as a random walk. And ZNE/PEC both assume a noise model — twirling makes the real noise match it. Free. Leave it on.
★ The cost table
| Technique | Extra circuits | Removes | Measured | Verdict |
|---|---|---|---|---|
| Readout mitigation | $2^n$ / ~2 / M3 | measurement error | −64% | always |
| Twirling | none | coherent → stochastic | enables others | always |
| DD | none | idle dephasing | untestable locally | hardware + control |
| ZNE | 3–5× circuits, 3–12× gates | scalable gate error | −14% raw, −42% after | when accuracy matters |
| PEC | $\gamma^{2d}$ | everything, exactly | exact | small circuits only |
Each technique removes ONE thing. Applied to the wrong channel it costs shots and returns nothing — or makes things worse.
Procedure: diagnose (Ch. 11 §11.7 / Ch. 12 §12.7) → fix the layout first (Ch. 12 §12.3, free, 3.4× swing) → readout mitigation always → twirling always → ZNE when accuracy matters → PEC only small → report the stack.
🗝️ resilience_level does nothing locally
level 0: <ZZ> = +0.96387 level 1: +0.96387 level 2: +0.96387
UserWarning: The resilience_level option has no effect in local testing mode.
Resilience options are server-side. The one part of the workflow fake backends cannot rehearse — which is why this chapter builds everything by hand.
Common pitfalls
- Calling mitigation "correction," or a path to advantage.
- Mitigating before fixing the layout.
- Applying a technique to a channel it does not target.
invinstead ofsolve; not checking the condition number or rank.- Folding an ISA circuit.
- Reading extrapolator agreement on a wrong answer as failure of the fit.
- Assuming DD ran because it was enabled.
- Reporting a mitigated value without its stack.
Project piece added this chapter
vqelab/mitigation.py — AssignmentMatrix (caches; exposes .condition_number, .rank,
.dead_qubits(); refuses when singular), fold() (guards odd factors and ISA input),
extrapolate() (three methods + spread), MitigationRecord. 10 tests pass, including
test_zne_is_more_effective_after_readout_mitigation — the ordering result as an executable assertion.