Part III · Keeping Quanta Alive · Chapter 10
The Problem of Errors
Classical error correction copies a bit three times and takes a vote. Every step of that recipe is illegal for a qubit — you cannot copy an unknown state, you cannot look at it without destroying it, and its errors are not discrete flips but a continuum. And yet quantum error correction works. This chapter is the story of how three impossible objections are each turned into a tool.
Sources: Nielsen & Chuang 10.1–10.2 · Shor 1995
Chapter 4 gave us the enemy in full: bit-flips, phase-flips, depolarizing noise, amplitude damping — the channels that drag a pure state into the interior of the Bloch ball. A real device runs these on every qubit, every microsecond. If we cannot undo them, nothing else in this book survives contact with hardware. The classical fix — redundancy plus majority vote — seems flatly forbidden here. We will spend §10.1 taking the three objections seriously, then §§10.2–10.4 dismantling them one at a time, and by the end you will have, in Rust, a working 3-qubit code whose every claim is checked to machine precision: single errors corrected to fidelity 1, a continuous error digitized away, and the encoded failure rate matching its closed form exactly.
What this chapter covers
- 10.1Why it looks impossible. Three walls: no-cloning forbids copying, measurement collapses superpositions, and errors are continuous, not discrete flips.
- 10.2Encoding in entanglement. The 3-qubit bit-flip code α|000⟩+β|111⟩ — redundancy without copying, built from two CNOTs.
- 10.3Measuring the syndrome. Read the parities Z₀Z₁ and Z₁Z₂, not the data. The syndrome locates the error while the superposition survives.
- 10.4The digitization of errors. The key idea: syndrome measurement projects a continuous error onto a discrete Pauli. Fix X, Y, Z and you fix everything.
- 10.5The phase-flip code. The Hadamard-conjugate code that catches Z errors — and why three qubits can fix bit OR phase, never both.
- 10.6The Lab. An encode/syndrome/correct kit in Rust, refereed to machine precision — from digitization all the way to the 3p²−2p³ crossover.
10.1Why it looks impossible
F · FormalismClassical error correction is almost insultingly simple. To protect a bit, write it three times — , — send all three through the noisy channel, and on the far side take a majority vote. A single flipped bit is outvoted two-to-one and silently repaired. Try to lift this to a qubit and you hit three walls in a row, each looking fatal.
Wall 1 — no cloning. The very first step, “write it three times,” asks for a machine that takes to . No such machine exists. The no-cloning theorem says there is no unitary with for every — a one-line consequence of linearity (Exercise 1). Copying is out.
Wall 2 — measurement destroys. Majority voting needs you to look at the three copies and compare them. But reading a qubit collapses it: measure and you get one classical bit, the amplitudes gone for good. The act of checking for an error would itself destroy the information you are trying to protect.
Wall 3 — errors are continuous. A classical bit flips or it does not — a discrete event you can count. A qubit error is any small unwanted unitary: a rotation by an arbitrary tiny angle, a partial dephasing, a drift. There is a whole continuum of them, parametrized by real numbers. Even if you could somehow spot an error, how would you ever correct a continuum of them with a finite set of operations?
Every one of these walls is real. The genius of the theory — Shor and Steane, 1995–96 — is that each becomes, on inspection, exactly the resource the next step needs. Wall 1 forces us to store information in entanglement instead of copies (§10.2). Wall 2 is sidestepped by measuring an error syndrome rather than the data (§10.3). And Wall 3 — the deepest — collapses spectacularly: measuring the syndrome digitizes the continuous error, and fixing three discrete Pauli errors turns out to fix them all (§10.4).
10.2Encoding in entanglement
F · FormalismKeep the spirit of the classical code — spread the information across three qubits — but drop the illegal part, the copying. The 3-qubit bit-flip code encodes
which looks superficially like triplication but is nothing of the kind. Three copies would be the product , a state with eight nonzero amplitudes — and no-cloning says we cannot make it. Equation (10.1) has only two. It is a highly entangled state: the two logical basis states and are spread over all three qubits at once, and the amplitudes live on the whole triple, not on any single qubit. No qubit alone carries a copy of — trace any one out and you get noise. That is the loophole in no-cloning: we did not clone the state, we delocalized it.
Building (10.1) needs no forbidden operation, just two CNOTs from the data qubit onto two fresh ancillas prepared in : then . On the first CNOT gives , the second spreads it to (10.1). The left half of the circuit below is exactly this; the right half is the measurement we build in §10.3.
10.3Measuring the syndrome, not the data
F · FormalismC · ConceptsNow Wall 2. We must detect an error without measuring . The trick is to measure a relationship between qubits rather than any qubit's value. Consider the two observables
These are stabilizers in the sense of Chapter 5: both fix the code space, , because and each have even parity on every adjacent pair. Crucially, each asks only “do these two qubits agree?” — a question whose answer is the same for and , and therefore reveals nothing about versus . Measuring and yields two bits, the syndrome , while leaving the logical superposition perfectly intact.
Work out what a single bit-flip does. An on qubit 1 sends to : now qubits 0 and 1 disagree and qubits 1 and 2 disagree, so . Each error location leaves its own fingerprint:
The four syndromes are distinct, so the decoder reads , looks up the offending qubit, and applies an there to undo it. This is the quantum version of majority vote — but performed on parities, not values. Inject an error and watch the syndrome light up:
Toggle bit-flip (X) errors — try a single flip, then a double:
The panel is entirely deterministic — the syndrome is a lookup, not a coin flip. Two facts deserve emphasis. First, the correction is itself a Pauli , its own inverse, so “undoing” the error is a single clean gate. Second, and this is the whole point of Wall 2: nothing in depended on or . We learned where the error was without learning what we were protecting.
10.4The digitization of errors
F · FormalismC · ConceptsWall 3 is the deep one, and knocking it down is the single most important idea in this chapter. Real errors are continuous: instead of a clean , qubit 0 suffers a small rotation
a coherent superposition of “no error” and “a full bit-flip,” for some arbitrary real . Applied to it produces the entangled mess — the state is now a continuum away from any codeword. But watch what the syndrome measurement of §10.3 does to it. The first term lives in the syndrome sector; the second, carrying , lives in the sector. Measuring therefore projects onto one or the other:
The continuous parameter survived only as the probability of each branch. The state that emerges is, in both cases, exactly after correction — fidelity 1, no residual -dependence at all. The measurement digitized the error: a continuum rounded to one of two discrete outcomes, each of which we know how to fix. This is why a finite code can defeat an infinite family of errors.
The argument generalizes completely. Any single-qubit error, even a non-unitary one from Chapter 4, can be expanded in the Pauli basis . Syndrome measurement collapses this sum onto one Pauli term; so a code that corrects each of , , and on every qubit corrects any single-qubit error whatsoever. Discretize the enemy, and a handful of corrections suffices. (Our 3-qubit code only handles the part — hence the error above; §10.5 explains the gap and Chapter 11 closes it.)
The bit-flip code is blind to a error: since commutes with both stabilizers and , a phase-flip leaves the syndrome at and sails through undetected — yet flips the relative phase, turning into . To catch phase errors we simply rotate the whole problem into the basis, where a error is a bit-flip. Conjugating everything by Hadamards gives the phase-flip code:
built by the same two CNOTs followed by an on all three qubits, and decoded by the identical syndrome table (10.3) with corrections in place of (Exercise 4). It is the bit-flip code seen in a mirror — literally its Hadamard conjugate, since and . The lab verifies both codes with one piece of machinery.
And here is the catch that drives the rest of Part III. The bit-flip code fixes but not ; the phase-flip code fixes but not . Neither fixes both, and a general error has both parts. Three qubits buy you exactly one kind of protection. By the digitization argument, correcting a truly arbitrary single-qubit error requires catching , , and at once — and that, as Shor first saw, needs the two codes nested together, at a cost of nine qubits. That is the doorway to Chapter 11.
10.6The Lab — encode, syndrome, correct
P · PracticeThe lab is a fresh 3-qubit state-vector simulator — eight amplitudes, moved by hand — with encode, syndrome measurement, and correction for both codes. Encoding is two CNOTs (plus a layer of Hadamards for the phase-flip variant of §10.5), and it is worth seeing in code that this is entanglement, not copying:
1/// Encode a|0> + b|1> into the chosen 3-qubit code. Bit-flip:2/// a|000> + b|111> via CNOT(0->1), CNOT(0->2). Phase-flip: additionally H on3/// all three qubits -> a|+++> + b|--->.4fn encode(kind: Kind, a: C, b: C) -> State {5 let mut s = State::input(a, b);6 s.cnot(0, 1);7 s.cnot(0, 2);8 if kind == Kind::PhaseFlip {9 for q in 0..N {10 s.apply_1q(&g_h(), q);11 }12 }13 s14}1516/// CNOT(ctrl -> tgt): flip tgt on the branches where ctrl is set.17fn cnot(&mut self, ctrl: usize, tgt: usize) {18 let cbit = 1usize << ctrl;19 let tbit = 1usize << tgt;20 for i in 0..DIM {21 if i & cbit != 0 && i & tbit == 0 {22 self.amps.swap(i, i | tbit);23 }24 }25}
Syndrome measurement is an honest projective measurement onto the eigenspaces of a stabilizer, — which is why the logical amplitudes survive it — followed by the lookup table:
1/// Project onto the +/-1 eigenspaces of a single stabilizer S.2/// Returns [(prob_plus, |plus>), (prob_minus, |minus>)] with the branch states3/// renormalized (or left zero if the branch has vanishing probability).4fn project(psi: &State, stab: &[(usize, Pauli)]) -> [(f64, State); 2] {5 let s_psi = psi.pauli_string(stab);6 let (mut plus, pp) = combine(psi, &s_psi, 1.0);7 let (mut minus, pm) = combine(psi, &s_psi, -1.0);8 // …9 [(pp, plus), (pm, minus)]10}1112/// Map a syndrome (s1, s2) to the qubit to correct: 00 -> none, 10 -> q0,13/// 11 -> q1, 01 -> q2.14fn infer_qubit(s1: u8, s2: u8) -> Option<usize> {15 match (s1, s2) {16 (0, 0) => None,17 (1, 0) => Some(0),18 (1, 1) => Some(1),19 (0, 1) => Some(2),20 _ => unreachable!(),21 }22}
The sharpest referee is the digitization test. We apply a continuous rotation error, measure the syndrome, correct each branch, and confirm the branch-averaged fidelity is 1 to machine precision — independent of the rotation angle:
1// --- Referees 5-7: DIGITIZATION OF ERRORS (the conceptual heart) -------2// Apply the CONTINUOUS rotation error e^{-i theta X/2} on a data qubit.3// Syndrome measurement projects the continuum onto {no error, X error};4// BOTH branches, after correction, return the exact logical state. So the5// syndrome-averaged post-correction fidelity is 1 for EVERY theta.6// …7for &theta in &thetas {8 // the chart follows the error on q0; the referees sweep all three qubits9 let mut chart_uncorr = 1.0;10 let mut chart_corr = 1.0;11 for q in 0..N {12 let mut errored = psi_l.clone();13 errored.apply_1q(&g_rx(theta), q);1415 // uncorrected fidelity to the clean logical state16 let f_unc = fidelity(&psi_l, &errored);17 // …1819 // syndrome-averaged post-correction fidelity20 let branches = syndrome_and_correct(Kind::BitFlip, &errored);21 let mut avg_f = 0.0;22 let mut ptot = 0.0;23 for b in &branches {24 avg_f += b.prob * fidelity(&psi_l, &b.corrected);25 ptot += b.prob;26 }27 avg_f /= ptot.max(1e-300);28 worst_digit = worst_digit.max((avg_f - 1.0).abs());29 if q == 0 {30 chart_uncorr = f_unc;31 chart_corr = avg_f;32 }33 // …34 }35 digitization.push(DigitPoint { theta, uncorrected: chart_uncorr, corrected: chart_corr });36}
The referees run and write their results to JSON, which the panel reads live — nothing here is hardcoded. Single and errors are corrected to fidelity 1; the continuous rotation is digitized away (its computed corrected fidelity stays within the referee's tolerance of 1 across the whole sweep); and the encoded logical error rate matches the closed form both by exact enumeration and by Monte Carlo. That last curve carries the chapter's honest scorecard:
cargo run --release in Rust-QML/ch10-codes)Read the crossover carefully. For a per-qubit error rate the encoded rate sits below the bare rate : encoding helps, and helps quadratically when is small. But above the code makes things worse — three bad qubits outvote the truth. That there is a break-even point at all is the seed of the threshold theorem, the result that ultimately says large-scale quantum computing is possible, which Chapter 12 proves. Run it yourself with cargo run --release in Rust-QML/ch10-codes.
10.7Exercises
1. (F) Prove the no-cloning theorem. Suppose a unitary satisfies for two distinct non-orthogonal states and . Take the inner product of the two cloning equations and show it forces , a contradiction. Where exactly did linearity do the work?
2. (C) Using the syndrome explorer, confirm all four entries of table (10.3). Then reason out — before toggling both errors on — what happens for a double error : what syndrome does it show, which single correction does the decoder apply, and why does the result end up as a logical bit-flip rather than a repair? Check your prediction in the explorer.
3. (C) In the lab panel, read off where the encoded curve crosses the break-even line. Below it, by how much does encoding divide the error rate when ? (Compute and compare to .)
4. (P) Extend the lab's phase-flip path: encode a random logical state, apply a on each qubit in turn, and verify the syndromes and the -corrections restore fidelity 1. Then show explicitly that the phase-flip code is the Hadamard conjugate of the bit-flip code: maps one encoder, stabilizer set, and correction into the other.
5. (F, hard) Derive the logical error rate from scratch. Under an i.i.d. bit-flip channel of rate , majority vote fails exactly when two or three of the three qubits flip. Sum the binomial probabilities, simplify, and prove the crossover: show for all , with equality at . (Hint: factor .)
The bridge → Chapter 11: Quantum Error Correction
Where you stand. You have defeated all three objections to quantum error correction: information stored in entanglement (not copies) dodges no-cloning; syndrome measurement reads the error, not the data, so superpositions survive; and that same measurement digitizes a continuous error into a discrete Pauli — so fixing X, Y, Z fixes everything. A Rust kit checks it all, including a continuous error corrected to fidelity 1 and the 3p²−2p³ crossover.
The open question. But a 3-qubit code protects against only one error type at a time — bit OR phase, never both — and a real qubit suffers both. How do we correct an arbitrary single-qubit error, and then scale to the millions of qubits a useful computation needs, without the correction machinery introducing more errors than it removes?
What comes next. We nest the bit-flip and phase-flip codes into Shor's 9-qubit code, which corrects any single-qubit error at once; abstract the pattern into the CSS construction and the full stabilizer formalism; and arrive at the surface code — a 2D lattice of qubits, local checks, and a high error threshold — the leading candidate for building a real fault-tolerant machine.