DiracDirac

Part III · Keeping Quanta Alive · Chapter 11

Quantum Error Correction

A qubit that cannot be copied, whose errors form a continuum, and which is destroyed by the very act of looking, seems impossible to protect. The resolution is one of the deepest ideas in the field: store the information not in any qubit but in the correlations among many, and measure only what is wrong, never what is stored.

Sources: Nielsen & Chuang, Ch. 10 · Gottesman (1997) · Fowler et al. (2012)

Chapter 10 built the three-qubit codes and showed the trick that makes quantum error correction possible at all: you can measure a stabilizer — a parity of several qubits — and learn that an error happened, and where, without ever measuring the protected state itself. This chapter scales that trick into something a real machine can run. We generalize to the full stabilizer codes, meet the historic Shor and Steane codes, and then arrive at the surface code — a flat grid of qubits with only nearest-neighbour checks, the code every serious quantum-hardware effort is now building. Its decoding turns out to be a classic combinatorial problem, minimum-weight perfect matching, and its defining feature is a threshold: a physical error rate below which adding qubits makes the logical qubit better, without limit. We do not assert that threshold — the lab measures it, and the curves cross exactly where they must.

What this chapter covers

  • 11.1Stabilizer codes. The general recipe: a code space is the joint +1 eigenspace of n−k commuting Paulis; errors are diagnosed by the syndrome. The [[n,k,d]] notation.
  • 11.2The Shor code. Nine qubits, phase-flip ∘ bit-flip concatenated, correcting any single-qubit error — the first proof that QEC is possible at all.
  • 11.3CSS and Steane. Codes built from two classical linear codes, so X and Z errors are handled separately; the seven-qubit Steane code as the clean example.
  • 11.4The surface code. A 2-D lattice with local X- and Z-checks, logical operators as non-contractible strings, distance = lattice size. Why hardware loves it.
  • 11.5Decoding as matching. Errors make pairs of syndrome defects; the best correction is a minimum-weight perfect matching of them. A residual loop is a logical failure.
  • 11.6The Lab. A toric-code decoder with exact MWPM in Rust, refereed for correctness and for the threshold crossing across distances d = 3, 5, 7.

11.1Stabilizer codes

F · Formalism

Chapter 5 gave us the language; now we use it to protect. A stabilizer code encodes logical qubits into physical ones by choosing a set of independent, mutually commuting Pauli operators — the stabilizer generators — and declaring the code space to be their simultaneous eigenspace:

(11.1)

One requirement hides in plain sight: the group the generate must not contain , for no state satisfies — a stabilizer group containing stabilizes nothing at all. With that guaranteed, the generators each halve the space, so the code space has dimension — room for logical qubits. Now suppose an error (a Pauli) strikes. Each generator either commutes or anticommutes with (Chapter 5's dichotomy), so measuring all generators returns a bit string — the syndrome — whose -th bit is 0 if and 1 if they anticommute. Crucially, measuring on a code state reveals only this parity; it does not touch the logical information, because the logical operators are chosen to commute with every generator.

A code is rated by three numbers, : physical qubits, logical qubits, and the distance — the weight of the smallest Pauli error that is undetectable (commutes with every generator yet acts nontrivially on the code space). A distance- code corrects any error on up to qubits. The precise condition, due to Knill and Laflamme (1997), is that a set of errors is correctable on the code with projector exactly when

(11.2)

for some Hermitian matrix . When is invertible the code is nondegenerate, and — exactly as for a classical distance- code — two distinct correctable errors carry distinct syndromes. When is singular the code is degenerate: two distinct errors can share a syndrome, but harmlessly, because their product then lies in the stabilizer and so acts identically on the code space — one recovery fixes both. Shor's code in the next section is degenerate, so beware the tempting half-truth that correctable errors can never collide: they can, and the code loses nothing for it. The whole game of this chapter is building codes with large out of simple, local checks.

11.2The Shor code

F · Formalism

The first quantum code, and still the clearest, is Peter Shor's nine-qubit code (1995). It confronts the two ways a qubit can go wrong — a bit flip and a phase flip — and beats them by concatenation: nesting one code inside another. Start with the three-qubit repetition code of Chapter 10, which corrects a single bit flip by encoding

(11.3)

Its Hadamard-conjugate, encoding , corrects a single phase flip instead. Shor's insight: nest them. Encode the qubit first in the phase-flip code, then encode each of those three qubits in the bit-flip code. The result uses qubits and its logical states are

(11.4)

Now any single-qubit error is caught. A bit flip is corrected inside its block of three; a phase flip is corrected across the three blocks. And here is the part that first looked like magic: a small continuous rotation is also corrected, because the syndrome measurement digitizes it — projecting the state onto either “no error” or “a clean ,” each of which the code handles. The continuum of quantum errors, which seemed to doom the whole enterprise, collapses to a finite set the moment you measure the stabilizers. That single fact is why quantum error correction is possible.

Shor's code hints at a general construction. If bit flips and phase flips can be handled separately, why not build a quantum code out of two classical codes — one to catch errors, one to catch errors? This is the idea of CSS codes, after Calderbank, Shor, and Steane. Take two classical linear codes with . The -type stabilizers are the parity checks of (they detect errors), and the -type stabilizers come from the dual of (they detect errors). Because these two check sets are built to be orthogonal over , every -check commutes with every -check — the stabilizer requirement is met automatically.

The Steane code is the jewel of the family: take to be the Hamming code and its dual — the simplex code, which the Hamming code contains, so holds — and you get a quantum code — seven physical qubits, one logical qubit, distance three, correcting any single-qubit error with six stabilizer generators (three -type, three -type), each a weight-four parity. It is more efficient than Shor's nine and, because its and checks have the same form, it admits especially clean logical gates. CSS codes remain the backbone of the field — the surface code we turn to next is itself a CSS code, just laid out on a grid so that every check is local.

11.4The surface code

C · ConceptsF · Formalism

The Steane code is beautiful but its checks are non-local — a weight-four parity may involve qubits scattered anywhere, which no two-dimensional chip can wire up cheaply. The surface code (Kitaev, 1997) fixes this with a layout so simple it looks like graph paper. Put data qubits on the edges of a square lattice. On each vertex place a -type check (a star: the product of on the four incident edges); on each face place an -type check (a plaquette: the product of on the four bordering edges). At a boundary a check simply loses the edges that are not there. Every check touches only its few nearest neighbours — perfectly local, perfectly 2-D. This is the convention the lab and every widget in this chapter use: -checks on vertices catch errors, -checks on faces catch errors.

A distance-5 surface-code patch — the [[41, 1, 5]] code41 data qubits on edges · 20 Z-checks on vertices · 20 X-checks on faces40 independent generators on 41 qubits ⇒ k = 41 − 40 = 1 logical qubitrough boundary — the lattice ends in dangling qubitsrough boundary — the X-checks here have weight 3, not 4XXXXXXXXXXXXXXXXXXXXZZZZZZZZZZZZZZZZZZZZX̄ (gold): 5 qubits, rough boundary to rough boundary — commutes with all 20 Z-starsZ̄ (violet): 5 qubits, smooth to smooth — commutes with all 20 X-plaquettesThey share exactly one qubit (ringed), so X̄ Z̄ = −Z̄ X̄: a conjugate logical pair. Both have weight 5 = d.Z-check (star)X-check (plaquette)data qubitlogical X̄ stringlogical Z̄ stringEvery check touches only nearby qubits — a flat, nearest-neighbour 2-D layout. Four smooth boundaries would give k = 0.
Figure 11.1. A distance-5 planar surface-code patch — a [[41, 1, 5]] code. Data qubits (dots) sit on the 41 edges, including the ten dangling half-edges of the two rough boundaries at top and bottom; Z-checks (stars) sit on the 20 vertices and X-checks (plaquettes) on the 20 faces, the eight faces along the rough boundaries having weight 3 instead of 4. All 40 generators are independent, so k = 41 − 40 = 1 logical qubit. The gold logical X̄ is a string of five qubits running from rough boundary to rough boundary: it overlaps every Z-star on an even number of edges, so it commutes with every check, yet it is not a product of stabilizers. The violet Z̄ runs smooth-to-smooth across the dual lattice; the two strings share exactly one qubit, so they anticommute — a conjugate logical pair. The code distance d = 5 is the weight of the shortest such string. With four smooth boundaries the same counting gives k = 0: the rough boundaries are what buy the logical qubit.

What is a logical qubit here? The stars and plaquettes leave a few degrees of freedom unfixed, and those are the logical operators: strings of or that run all the way across the lattice from one boundary to the other (or, on a torus, all the way around). Such a string commutes with every local check — it crosses each check an even number of times — so it is invisible to the syndrome, yet it acts nontrivially on the encoded state. Its length is the code distance , equal to the lattice size. Make the lattice bigger and the shortest logical string gets longer: the distance grows with the lattice's linear size , while the qubit count grows with its area — qubits buy — all with only local checks. That is the surface code's decisive advantage, and why it is the front-runner for real hardware — high tolerance to error, a flat nearest-neighbour layout, and a distance you scale just by adding qubits.

An error on one edge anticommutes with the two -stars at its endpoints, so it lights up the two adjacent vertex checks — two defects. A whole chain of errors lights up only its two endpoints: the checks in the interior of the chain each see two errors and stay silent. So the syndrome never shows you the error — it shows you the endpoints of error chains, in pairs. The decoder's job is to guess a chain that could have produced those endpoints. That is the problem of the next section.

11.5Decoding as minimum-weight matching

C · ConceptsF · Formalism

The defects come in pairs, and any error chain joining two defects would reproduce them. Which chain actually happened? We cannot know — but under independent noise, a shorter chain is exponentially more likely than a longer one (each extra errored qubit costs a factor ). So the maximum-likelihood guess is the shortest set of chains that pairs up all the defects. Pairing up points to minimize total path length is a classic combinatorial problem: minimum-weight perfect matching (MWPM). Give every pair of defects a weight equal to the lattice distance between them, and ask for the perfect matching of least total weight.

Apply the correction along the matched paths and one of two things happens. The correction chain plus the true error chain together form closed loops (they share the same endpoints). If every loop is contractible — shrinkable to a point — it is a product of stabilizers and acts as the identity on the code space: success. But if the true error was long and the decoder paired the defects the other way around the lattice, the combined loop is non-contractible — it wraps the code — and that is a logical operator: a logical error. The decoder fails precisely when the error chain is long enough to fool it about which way to close the loop. Toggle errors below and watch the matching form; the “spanning chain” preset shows a chain long enough to flip the logical qubit:

Click any data qubit (a dot on an edge) to toggle an X error. The lattice is a torus: the faded row and column are wrap-around copies of the first, so an edge reaching a ghost is the same qubit as on the opposite side.

X errors

0

syndrome defects

0

no error — nothing to correct

X error  inferred correction  defect  residual

Notice the structure the widget makes visible. A single error, or any short chain, is matched by a correction that cancels it exactly — the residual is nothing. Only when a chain spans more than half the lattice does the nearest matching go the wrong way and leave a loop around the torus. This is why distance matters: must exceed twice the longest likely error chain for correction to win. And it is why there is a threshold — a physical error rate below which long chains are so rare that a bigger lattice always helps, and above which errors are so dense that a bigger lattice only gives them more room to fail.

The lab implements the toric code — the surface code on a torus, chosen because its periodic boundary makes the matching perfectly clean: defects always pair with each other, with no boundary special-casing, so the decoder's correctness is easy to pin down. Data qubits live on the edges of a torus; the syndrome is the parity at each vertex. This is the heart of it — read the defects straight off the four incident edges:

ch11-surface/src/main.rs — Z-check syndrome extraction
1/// The Z-check syndrome: vertex (r,c) is lit (a "defect") when an odd number
2/// of its four incident edges carry an X error.
3fn syndrome(&self) -> Vec<(usize, usize)> {
4 let d = self.d;
5 let mut defects = Vec::new();
6 for r in 0..d {
7 for c in 0..d {
8 let mut parity = false;
9 parity ^= self.h[r][c]; // right edge out of (r,c)
10 parity ^= self.h[r][(c + d - 1) % d]; // left edge into (r,c)
11 parity ^= self.v[r][c]; // down edge out of (r,c)
12 parity ^= self.v[(r + d - 1) % d][c]; // up edge into (r,c)
13 if parity {
14 defects.push((r, c));
15 }
16 }
17 }
18 defects
19}

Exact minimum-weight perfect matching in general is Edmonds' blossom algorithm, which is intricate; since correctness matters more than speed here, the lab instead does an exhaustive branch-and-bound that is obviously exact and, thanks to an admissible lower bound, fast on the metric instances the code produces (30-plus defects resolve in milliseconds):

ch11-surface/src/main.rs — exact MWPM by branch-and-bound
1/// Admissible lower bound on the cost to finish matching the unmatched defects:
2/// half the sum, over unmatched defects, of each one's nearest unmatched-
3/// neighbour weight. Since ½(nn(a)+nn(b)) ≤ dist(a,b) for every pair, it never
4/// overestimates — so pruning with it never discards the optimum.
5fn match_lb(dist: &[Vec<i64>], n: usize, matched: &[usize]) -> i64 {
6 let mut sum = 0i64;
7 for v in 0..n {
8 if matched[v] != usize::MAX {
9 continue;
10 }
11 let mut nearest = i64::MAX;
12 for w in 0..n {
13 if w != v && matched[w] == usize::MAX && dist[v][w] < nearest {
14 nearest = dist[v][w];
15 }
16 }
17 if nearest != i64::MAX {
18 sum += nearest;
19 }
20 }
21 sum / 2
22}
23
24/// Exact minimum-weight perfect matching by branch-and-bound: always match the
25/// lowest-indexed unmatched defect, try partners nearest-first, prune with
26/// `match_lb`.
27fn bnb(
28 dist: &[Vec<i64>],
29 n: usize,
30 matched: &mut Vec<usize>,
31 cur: i64,
32 best: &mut i64,
33 best_match: &mut Vec<usize>,
34) {
35 let i = match (0..n).find(|&k| matched[k] == usize::MAX) {
36 Some(x) => x,
37 None => {
38 if cur < *best {
39 *best = cur;
40 best_match.clone_from(matched);
41 }
42 return;
43 }
44 };
45 if cur + match_lb(dist, n, matched) >= *best {
46 return; // cannot beat the incumbent — prune
47 }
48 let mut cand: Vec<usize> = (i + 1..n).filter(|&j| matched[j] == usize::MAX).collect();
49 cand.sort_by_key(|&j| dist[i][j]);
50 for j in cand {
51 matched[i] = j;
52 matched[j] = i;
53 bnb(dist, n, matched, cur + dist[i][j], best, best_match);
54 matched[i] = usize::MAX;
55 matched[j] = usize::MAX;
56 }
57}

The decoder is not trusted on faith. A first referee pits the branch-and-bound matcher against an independent exact bitmask dynamic program on hundreds of random instances — identical optimal costs, every time. A second replays a battery of hand-built error patterns with known corrections and confirms the residual is trivial, while planted non-contractible loops correctly trip the logical-error detector. Then the decisive referee measures the threshold: for it Monte-Carlos the logical error rate across physical , carrying a binomial one- uncertainty on every point, and checks that the ordering of the curves flips across the crossing — below a bigger code protects better, above it a bigger code protects worse. Each ordering gap is a z-score and must clear , so no pass can be a statistical fluke of unstated size. Sanity holds at the ends: zero logical failures at , and a coin-flip rate within of exactly at . Every number below is whatever your last cargo run --release produced:

Loading /data/ch11/surface.json… (run cargo run --release in Rust-QML/ch11-surface)

One pair of numbers needs an honest reconciliation. The referee table pins the crossing between and and estimates it live above — the known value for this exact model is — while §11.5's history note quoted Fowler's for the very same code. Both are right, because they price different noise models. The lab measures the code-capacity threshold: data qubits fail independently with probability , but the syndrome is read out perfectly, free of charge. In a real machine syndrome extraction is itself a circuit of faulty CNOTs and measurements — each round can lie, so it must be repeated times and decoded in three dimensions (space time), and every faulty two-qubit gate spreads errors onto fresh qubits. Charging honestly for all that machinery — circuit-level noise — costs roughly a factor of ten in threshold: that is Fowler et al.'s . Same code, same matching decoder; the tenfold gap is purely how much of the correction machinery is allowed to fail.

Run it yourself with cargo run --release in Rust-QML/ch11-surface. The crossing — the panel above reports its live value from your own run — is the whole point of error correction made quantitative: it is the promise that if your hardware is good enough — below threshold — you can buy any logical fidelity you like simply by making the lattice bigger. What that promise costs, and how it composes into arbitrarily long computations, is Chapter 12.

11.7Exercises

1. (F) Verify that the Steane code's six generators pairwise commute. Show more generally that in any CSS code, an -type generator (a row of the check matrix ) and a -type generator (a row of ) commute iff those two rows overlap in an even number of positions — and that this is exactly the CSS orthogonality condition over .

2. (C) Using the decoder explorer, place two well-separated single errors. Confirm the matcher pairs each error's own two defects (four defects, two short corrections) rather than cross-matching. Then move them until the two natural pairings tie in total length — what does the decoder do at the tie, and is either choice a logical error?

3. (C) In the explorer, build the shortest chain of errors you can that still produces a logical error. How long is it, relative to the lattice size ? Explain the relationship to .

4. (P) Extend the lab to track both logical operators (horizontal and vertical winding) and count a shot as a failure if either flips. Re-run the threshold sweep. How does the logical error rate at change, and why? (Hint: count the homology classes.)

5. (F, hard) Prove that a distance- code corrects any error on at most qubits. Suppose two weight- errors share a syndrome. Show is then undetectable and has weight , so by the definition of distance it cannot be a logical operator — it must lie in the stabilizer. Conclude the Knill–Laflamme condition (11.2): and act identically on the code space, so one recovery corrects both (the code is degenerate at that syndrome). Only for a nondegenerate code do distinct correctable errors always carry distinct syndromes. Where does the factor of two come from?

6. (P, hard) Count the qubits and checks of a distance- toric code exactly: show it uses data qubits and has plaquette checks and star checks, of which one of each is redundant (their product is the identity), leaving independent generators — hence logical qubits, a code. Confirm the numbers against the lab's reported qubit counts for .

The bridgeChapter 12: Thresholds and Fault Tolerance

Where you stand. You can encode a logical qubit in a 2-D lattice of physical ones, read a syndrome without disturbing the data, decode it by exact minimum-weight matching, and — the crux — you have measured a threshold: below p_th, a larger surface code has a strictly lower logical error rate, and the curves for d = 3, 5, 7 cross exactly where the ordering flips.

The open question. A single round of correction below threshold suppresses errors. But a real computation is a long sequence of gates and measurements, each itself faulty — including the syndrome extraction. Can error correction keep pace with a computation of arbitrary length, when the correction machinery is as unreliable as the thing it corrects?

What comes next. Chapter 12 states and proves the threshold theorem: if the physical error rate is below a constant threshold, any quantum computation can be made arbitrarily reliable with only polylogarithmic overhead. We build fault-tolerant gadgets that keep errors from spreading, and pay honest attention to the cost — the qubit and time overhead that stands between today's machines and a useful one.

Continue to Chapter 12