Re-landed from PR #676 (branch wai/quantum-parse-depth, merged with mainf6e302665at 0cf954bfc) as one commit on main, under the land-it model. Six review rounds; round 6's 16 findings are fixed, each with a test that fails ond5564748e. The public, anonymous job service is hardened on every route: - The reader: QEC indices refused past 2^24 and decodes capped; operator runs, else-if ladders and switches read flat at any length; real nesting bounded (Q006: 64 levels in the text, 256 through calls); arrays at most 7 dimensions. - Every read of a client's program is counted first and runs in a child capped on memory, time and answer size, covering admission, dry runs, checks, engine calls, set receipts, MCP verdicts and /v1/verify. - A result-size bound that is a true upper bound for every job kind (sampled intents' fits, trajectories, diagnostics, RFC 8785 numbers), held by a property test over random jobs, and tight where the method knows better (the stabilizer method's outcomes, a loop's verdict). - Dry runs apply exactly the run's checks, MCP's verdict included. - Turns: reading and check shares per client, a lent turn given back when others wait, at most eight waiting, J032 past them; long polls past a client's holds answer 429/503 with Retry-After and the job's status. - JSON-RPC ids echoed as sent; header and body time limits; large bodies read on one of four large-body turns, one per client. - wasmQ's /v1/verify and MCP verify go through the same admission, turns and reading child; wasmQ's profile states this reader's nesting bound. Passed on the merged tree (Framework, linux; M3, macOS): the service suite under ulimit -Sn 256 (118/119), the wai-quantum library (1,458), the CLI, wai-wasmq (67) and its 83 vectors on three engines, the engine with and without receipts, clippy -D warnings, wai breaking against main (5 acknowledged changes), and every repository check. Co-Authored-By: Claude Opus 5.5 <[email protected]>
12 KiB
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, the axis-cycling gates C_XYZ and C_ZYX, correlated errors
(E(p) X1 Y2 Z3, also CORRELATED_ERROR) and one-qubit Pauli channels
(PAULI_CHANNEL_1(px, py, pz)), and in models ^-separated decompositions,
detector and logical_observable declarations, repeat and
shift_detectors. A correlated error is a flip on a qubit of its own, handed
to its targets, so a circuit with one holds one qubit more than its text
names. A Pauli channel becomes the independent X, Y and Z flips with its law,
a rate above 1/2 among them where the law needs one; a channel with no such
flips (PAULI_CHANNEL_1(0.1, 0.1, 0)) is refused, since a model of
independent mechanisms cannot state it. 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. Blocks nest at most 32 deep (MAX_BLOCK_DEPTH), a
circuit names qubits below 2²⁴ (MAX_QUBITS; with its correlated errors'
carrier, it holds at most that many) and a model detectors below 2²⁴
(MAX_DETECTORS, offsets counted): what is made for an index is as long as
the index, so each is refused on its line, as is a block nested deeper, on the
line that opens it, so neither reading, unrolling nor writing a text recurses
past that. Every pass through a block counts toward the bound on what a text
unrolls to, so a block repeated without end that writes nothing still ends,
refused. The
conformance vectors 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.
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_osdtakes them undecomposed).