Error correction and mitigation join the version contract. An error-correction answer (wai.quantum.qec/1: a code, a decode or a threshold), a code's distance certificate (wai.quantum.distance/1) and a job's mitigation (wai.quantum.mitigation/1) are engine schemas; every answer engine::qec::call gives names the engine and its schema, inside what a host seals. The job request names mitigate, and a compile's options and certificate twirl and dd. qec_code, qec_decode and qec_threshold answer to output schemas on both servers; the strict tests call each, a mitigated run and a compile with both passes, the engine's test holds every decoder's answer and each mitigation method to its schema, the contract workflow requires it by name, and check_schemas.py holds the command line's answers too. Refusal codes: the set branch and this one had each taken J007. A set that does not read keeps J007; mitigation's refusals are J008 and error correction's J009, in the table, its page, the tests, the docs and the changelog. The basis rename reaches the new passes: compile::Options carries twirl and dd beside basis, and the command line's compile, both servers' compile options and their tests name the gate set basis. The service smoke test made 32 submissions with both branches' checks, past the 30 a client may make in a window (it is also run against production after a deploy). It now makes 28 (29 on a host with a GPU, whose single-precision run is held to the exact values instead of a second run): the code-capacity decode against its error, the changed estimate, the counts document and the classical shortcuts are left to the MCP servers' tests, which hold each. The agent docs are regenerated. Co-Authored-By: Claude Opus 5.5 <[email protected]>
160 lines
11 KiB
Markdown
160 lines
11 KiB
Markdown
# Error correction and mitigation
|
||
|
||
`engine::qec` answers three calls, the same on every surface: the command
|
||
line (`wai-quantum qec code|decode|threshold`), both MCP servers (`qec_code`,
|
||
`qec_decode`, `qec_threshold`), the job service (`POST /v1/qec/code`,
|
||
`/v1/qec/decode`, `/v1/qec/threshold`), the Studio's error-correction pane,
|
||
the desktop app and Python (`wai_quantum.qec_code`, `qec_decode`,
|
||
`qec_threshold`). Each answer is `{"request", "result"}`, the result sealed
|
||
in a job's receipt, so `wai-quantum verify` and `wai_quantum.verify` check
|
||
it. A request the engine cannot answer is refused with `J009`; the job
|
||
service's bounds on shots, points and distances refuse with `J031`.
|
||
|
||
Mitigation is part of a job: `"mitigate"` beside `"noise"` and
|
||
`"observables"` (`wai-quantum run --mitigate zne`, `wai_quantum.run(...,
|
||
mitigate="zne")`, the Studio's Noise section). Its refusals are `J008`.
|
||
|
||
## Codes
|
||
|
||
| Name | Code | Notes |
|
||
|---|---|---|
|
||
| `surface:D` | the rotated surface code, `[[D², 1, D]]`, odd `D` from 3 to 15 | |
|
||
| `toric:L` | the toric code, `[[2L², 2, L]]`, `L` from 2 to 12 | |
|
||
| `steane` | `[[7, 1, 3]]` | the `d = 3` colour code |
|
||
| `color:D` | the triangular 6.6.6 colour code, `[[(3D² + 1)/4, 1, D]]`, odd `D` from 3 to 15 | `quantum_color` |
|
||
| `bb:72`, `bb:90`, `bb:108`, `bb:144` (`gross`), `bb:288` | the bivariate-bicycle codes | `quantum_ldpc` |
|
||
|
||
A code's answer gives its checks (Z-type: they see X errors) and stabilizers
|
||
(X-type), `k` counted by rank, a layout to draw it, and the decoders it
|
||
takes.
|
||
|
||
### The distance certificate
|
||
|
||
`quantum_distance::certify` finds, in each sector, the least weight of a
|
||
logical operator: a support that commutes with every check and is not in the
|
||
span of the stabilizers. The search grows connected supports (a lightest
|
||
logical of these codes can always be taken connected in the graph where two
|
||
qubits meet when they share a check), branching on the first violated check,
|
||
barring siblings already tried, and pruning by the least number of qubits that
|
||
could still satisfy the violated checks. A code's symmetries (a
|
||
bivariate-bicycle code's translations) shrink the search to one support per
|
||
orbit; each symmetry is checked to map the checks onto themselves before it
|
||
is used.
|
||
|
||
The certificate (`wai.quantum.distance/1`) gives, per sector, the distance,
|
||
a witness of that weight, `no_logical_below` and the search's node count, and
|
||
a digest of the code's checks. Checking one (`"certificate"` in the request,
|
||
`--check FILE`, `certificate=` in Python) verifies each witness is a logical
|
||
of its stated weight and runs the search again, node for node. A search
|
||
stopped by `bound` says no logical is lighter than the bound and settles
|
||
nothing past it. The colour codes are certified to `d = 9` in the test suite
|
||
(`d = 7` in a debug build), the bivariate-bicycle codes from 72 to 144 qubits
|
||
in a release build; `bb:288` (`[[288, 12, 18]]`, 575 million search nodes, about
|
||
18 s in a release build) is certified on the command line, and the job
|
||
service refuses its certification as more work than one request takes.
|
||
|
||
## Decoders
|
||
|
||
Every decoder here is held to one test before any rate is measured: **every
|
||
error below half the distance is corrected to a trivial residual** (at
|
||
circuit level: every set of edges below half the matching graph's distance,
|
||
with every edge at one probability). That test has found bugs that aggregate
|
||
rates did not show.
|
||
|
||
### At code capacity (`"code"` with `"syndrome"` or `"error"`)
|
||
|
||
| Decoder | For | Guarantee |
|
||
|---|---|---|
|
||
| `matching` | codes whose qubits sit in at most two checks of a kind (surface, toric) | exact minimum-weight perfect matching: every error below half the distance corrected |
|
||
| `union_find` | the same codes | linear time in the fired checks; the same ground truth checked |
|
||
| `color` | colour codes | restriction to matching on the three restricted lattices, lifted at each colour, completed below half the distance by an exact search: every error below half the distance corrected (checked to `d = 9`) |
|
||
| `relay_bp` | any code | belief propagation with relayed memory; it can stall on a degenerate error of a topological code and then says it did not converge |
|
||
| `search` | any code | the lightest error with the syndrome, up to `max_weight` (at most 8) |
|
||
|
||
Given an `error`, the answer decodes its syndrome and judges the residual:
|
||
a product of stabilizers (the logical state is unharmed), a logical
|
||
operator, or a correction that does not explain the syndrome.
|
||
|
||
### At circuit level (`"memory"`, `"circuit"` or `"model"`)
|
||
|
||
`memory` is the rotated surface-code memory experiment (`distance`,
|
||
`rounds`, `p`); `circuit` is a noisy Clifford circuit in the ecosystem's
|
||
circuit text; `model` is a detector error model in its text. With
|
||
`detectors` the answer predicts which observables flipped; with `shots`
|
||
(a circuit is needed) it samples and decodes, and gives the failures, the
|
||
rate and its standard error, `(rate·(1 − rate)/shots)^½`.
|
||
|
||
| Decoder | What it does | Guarantee |
|
||
|---|---|---|
|
||
| `matching` | exact minimum-weight perfect matching (blossom, integer weights) | every edge set below half the graph's distance corrected |
|
||
| `correlated` | matches once, lowers the weight of the other parts of each decomposed fault the first matching used, matches again, and keeps the second answer only when the model's mechanisms explain it more cheaply | the same edge-set guarantee; on the `d = 5`, two-round experiment's 95,703 sets of one or two faults it misses 73 pairs where matching misses 103, and neither misses a single fault |
|
||
| `union_find` | union-find over the same graph | the edge-set ground truth checked |
|
||
| `bp_osd` | belief propagation with ordered-statistics post-processing | for models that are not graphlike |
|
||
| `window` | a sliding window as the syndrome arrives: `window: {commit, buffer}` rounds | a window that covers everything is the batch decoder on every shot; every edge set below half the distance is corrected once `buffer ≥ (d + 1)/2` |
|
||
|
||
The sliding window commits the matched edges that start in its first
|
||
`commit` rounds and decides the buffer's again in the next window. A buffer
|
||
shorter than the longest mechanism is refused; one round of buffer at
|
||
`d = 5` mispredicts 286 of the 166,176 sets of at most two edges, and a
|
||
buffer of `(d + 1)/2` rounds none. A stream states its **latency budget per
|
||
round** (`budget_ns`, the hardware's cycle time): a window must decode within
|
||
`commit × budget_ns` or work piles up behind it. `quantum_window::measure`
|
||
times every window on the machine it runs on and says which fit; the
|
||
prediction is the same bits everywhere, the timing is a measurement of that
|
||
machine and is labelled so.
|
||
|
||
## Thresholds
|
||
|
||
`threshold` measures logical failure rates over `distances` and physical
|
||
rates `p`: `family: "surface"` at circuit level (decoders `matching`,
|
||
`correlated`, `union_find`; the code model `P(d) = a·(p/p*)^((d+1)/2)` per
|
||
round fitted to the points), or `color`, `toric`, `surface_capacity` at code
|
||
capacity. Each point gives its shots, failures, rate and standard error;
|
||
`below_threshold` says, at each `p`, whether every larger distance failed
|
||
less. A crossing measured on few shots is not a threshold: quote rates with
|
||
their errors.
|
||
|
||
## The circuit and model texts
|
||
|
||
`quantum_qec_text` reads and writes the ecosystem's circuit text and detector
|
||
error model text, the subset the crate's circuits use and more: tags on
|
||
instructions (`DEPOLARIZE1[leak](0.01) 0`), Pauli-target observables
|
||
(`OBSERVABLE_INCLUDE(0) X0 Z3`), detector coordinates, `REPEAT` blocks,
|
||
`SHIFT_COORDS`, and in models `^`-separated decompositions, `detector` and
|
||
`logical_observable` declarations, `repeat` and `shift_detectors`. A
|
||
circuit's model written back keeps its tags and coordinates. What the reader
|
||
does not take it refuses with the line, never skipping it. The
|
||
[conformance vectors](../../quantum-conformance/qec-text/) hold each form,
|
||
the model each circuit gives, and each refusal.
|
||
|
||
## Mitigation
|
||
|
||
| Method | What it does | Bias | Variance |
|
||
|---|---|---|---|
|
||
| `zne` | zero-noise extrapolation: the program folded (`U U† U`) to odd noise scales (`factors`, default 1, 3, 5) and extrapolated to zero (`extrapolation`: `richardson`, `linear`, `exponential`) | assumes the value varies smoothly with the noise scale and that folding multiplies the noise by the factor; a curve of another shape leaves a bias the error bar does not include | each factor's shot noise carried through the extrapolation's coefficients, `(Σ c_i² σ_i²)^½`; a value outside [−1, 1] is reported as computed, not clipped |
|
||
| `pea` | error amplification: a sparse Pauli–Lindblad model learned from the device (here, from simulated benchmarking of the job's noise), its rates multiplied by each factor, and extrapolated | assumes the noise is the learned model under twirling; an error in the learned rates remains as bias (learned against true rates is in the details) | as `zne`; the learning's shot noise enters as model error, not in the error bar |
|
||
| `pec` | probabilistic error cancellation: each gate's learned channel inverted as a quasi-probability and sampled (`samples`) | unbiased when the learned model is the noise; `converges_to` says where the estimate goes for this learned model | grows as `γ²`; the error bar is the sampled circuits' signed, `γ`-scaled spread over `√samples` |
|
||
| `cdr` | Clifford data regression: near-Clifford circuits made from the program (`training`, keeping `keep` non-Clifford rotations) fit a line from noisy to ideal values | assumes one line relates noisy to ideal values for the program and its training circuits | the program's shot noise through the slope and the fit's residual spread |
|
||
| `vd` | virtual distillation: `Tr(ρ² O)/Tr(ρ²)` on two copies | the dominant eigenvector's distance from the ideal state remains | the ratio's, to first order, from shots on each |
|
||
| `readout` | the job's counts with each qubit's readout error inverted | assumes independent, symmetric misreads | amplified by `(1 − 2p)^−k`; negative quasi-probabilities kept |
|
||
|
||
Every mitigated value is reported beside the raw one, each with its error
|
||
bar, and labelled with the method, its options and its stated assumptions.
|
||
In simulation the ideal value is known and given too, so the bias can be
|
||
read; on a device it would not be. A job's own expectation values stay the
|
||
unmitigated ones; the mitigation sits beside them in the result and is
|
||
sealed with it. Mitigation needs a noise model and observables (counts, for
|
||
`readout`), refuses a program that measures in the middle, and is bounded at
|
||
8 qubits and a stated amount of work.
|
||
|
||
Pauli twirling and dynamical decoupling are compile passes, checked by the
|
||
equivalence ladder: see [the compiler page](compiler.md).
|
||
|
||
## What is not here
|
||
|
||
- A magic-state cultivation circuit generator. The architecture model
|
||
(`wai-quantum lab arch cultivate`) prices cultivation from published
|
||
rates; generating the circuits needs non-Clifford stages checked on state
|
||
vectors against a reproduced reference, which is not done.
|
||
- Decoders for hypergraph faults other than through decomposition
|
||
(`bp_osd` takes them undecomposed).
|