Week 11 | redundancy, parity checks, and how to check a qubit without looking at it | project proposals due this week | reading: Watrous Ch. 13; Roffe, Quantum Error Correction: An Introductory Guide, §1–3
Lecture 19 showed that mitigation cannot scale: it estimates, at exponentially growing cost, what an error-free run would have given. Error correction instead keeps the quantum state itself close to the intended one, for as long as needed, at a cost that grows slowly. This lecture builds the first quantum codes from classical ideas. By the end you should be able to compute the failure probability of a repetition code, encode and decode with the Hamming code, explain the three obstacles to quantum error correction and how syndromes get around them, find the syndromes of the 3-qubit phase-flip code, and explain why correcting a few discrete Pauli errors corrects every error.
The oldest error-correcting code: say everything several times.
The length-\(n\) repetition code (\(n\) odd) encodes \(0\mapsto0\cdots0\) and \(1\mapsto1\cdots1\) and decodes by majority vote. On the binary symmetric channel with error rate \(p\), each bit is flipped independently with probability \(p\).
Three copies are sent and decoded by majority vote. The decoded bit is wrong exactly when at least of the three copies are flipped.
Majority vote fails exactly when more than half the bits flip, so the logical error probability is
$$P_L(n,p)=\sum_{k=(n+1)/2}^{n}\binom nk p^k(1-p)^{n-k},$$ $$P_L(n,p)\approx\binom{n}{(n+1)/2}\,p^{(n+1)/2}\quad\text{for small }p.$$\(P_L(n,\tfrac12)=\tfrac12\) for every odd \(n\), and \(P_L(n,p)\lt p\) for \(p\lt\tfrac12\) when \(n\ge3\).
Proof. The number of flips is \(\mathrm{Bin}(n,p)\), which gives the sum; for small \(p\) its first term dominates. At \(p=\tfrac12\) the distribution is symmetric, so "more than half" has probability exactly \(\tfrac12\). For the last claim, \(P_L(1,p)=p\) and \(P_L(n,p)\) is decreasing in odd \(n\) when \(p\lt\tfrac12\), so \(P_L(n,p)\lt p\) for \(n\ge3\) (verify_L21.py checks this for \(n\le9\) on a grid of \(p\)).
For small \(p\), the seven-copy code has \(P_L(7,p)\approx c\,p^m\). Find \(c\) and \(m\).
Expand \(P_L(5,p)\) and evaluate it at \(p=0.01\).
\(P_L(5,p)=10p^3(1-p)^2+5p^4(1-p)+p^5=10p^3-15p^4+6p^5\). At \(p=0.01\): \(10^{-5}-1.5\times10^{-7}+6\times10^{-10}\approx9.85\times10^{-6}\), a thousand times smaller than \(p\). Each added pair of copies raises the exponent by one, another factor of about \(p\): the failure rate falls like \(p^{(n+1)/2}\).
Repetition is wasteful: one bit of information in \(n\). Linear codes do much better.
An \([n,k,d]\) linear code \(C\) is a \(k\)-dimensional subspace of \(\mathbb F_2^n\) whose nonzero words all have weight at least \(d\) (the distance). It can be given by a \(k\times n\) generator matrix \(G\) (the rows span \(C\); a message \(m\) is encoded as \(mG\)) or by an \((n-k)\times n\) parity-check matrix \(H\) with \(C=\{c:Hc=0\}\). For a received word \(r=c+e\), the syndrome \(Hr=He\) depends only on the error. A code of distance \(d\) corrects any \(\lfloor(d-1)/2\rfloor\) errors.
A linear code with distance \(d=5\) is guaranteed to correct any pattern of up to bit flips.
The repetition code is \([n,1,n]\). The Hamming code is \([7,4,3]\): four data bits in seven, correcting one error. Its parity-check matrix has as columns the numbers 1 to 7 in binary:
$$H=\begin{pmatrix}0&0&0&1&1&1&1\\0&1&1&0&0&1&1\\1&0&1&0&1&0&1\end{pmatrix}.$$If a codeword of the Hamming code suffers a single bit flip at position \(j\), the syndrome \(Hr\) is \(j\) written in binary. Hence the code corrects every single error, and its distance is 3.
Proof. \(Hr=He_j\) is the \(j\)th column of \(H\), which is \(j\) in binary. Distinct nonzero columns mean every single error has a distinct nonzero syndrome; no two columns are equal and none is zero, so no word of weight 1 or 2 is in \(C\), while \(1110000\) (columns 1, 2, 3 sum to zero) shows \(d=3\).
The Hamming word \(0101110\) is received. Which bit position should the decoder flip?
The word \(r=1010111\) is received. Find the syndrome, the error, and the codeword.
The rows of \(H\) check positions \(\{4,5,6,7\}\), \(\{2,3,6,7\}\), \(\{1,3,5,7\}\). The bits of \(r\) there are \(0,1,1,1\) (parity 1), \(0,1,1,1\) (parity 1), \(1,1,1,1\) (parity 0). The syndrome \(110\) is 6: flip bit 6 to get \(1010101\), which passes all three checks.
Decoding is easy for codes with structure, like Hamming's; for a random linear code it is NP-hard in general, and the best known algorithms, classical or quantum, take exponential time. Code-based cryptography hides a structured, efficiently decodable code behind a random-looking generator matrix: McEliece (1978) uses Goppa codes, and HQC, selected by NIST in March 2025 for standardization as a backup key-encapsulation method alongside ML-KEM (the standard was still in draft in 2026), uses quasi-cyclic codes. The same parity-check algebra protects quantum computers and resists them.
Three obstacles stand in the way of copying this to qubits:
The answers, in the next two sections: encode into an entangled state (redundancy without copying); measure only parities, which carry information about the error but none about the encoded state; and show that correcting a finite set of errors corrects all their linear combinations.
The bit-flip code encodes \(\alpha|0\rangle+\beta|1\rangle\mapsto\alpha|000\rangle+\beta|111\rangle\) (two CNOTs from the data qubit onto two fresh qubits). Its checks are the parities \(Z_1Z_2\) and \(Z_2Z_3\). The phase-flip code is the same code in the Hadamard basis: \(\alpha|0\rangle+\beta|1\rangle\mapsto\alpha|{+}{+}{+}\rangle+\beta|{-}{-}{-}\rangle\), with checks \(X_1X_2\) and \(X_2X_3\). Qubits are numbered 1, 2, 3 from the left.
For \(\alpha\beta\ne0\), the encoded state \(\alpha|000\rangle+\beta|111\rangle\) is
Note that \(\alpha|000\rangle+\beta|111\rangle\) is not three copies of anything: it is one entangled state, and no-cloning is not violated. The encoded state is a \(+1\) eigenvector of both checks, for every \(\alpha,\beta\). A check is measured with an ancilla qubit that collects the parity through CNOTs and is then read (figure below). The data qubits are never measured.
The phase-flip code protects against \(Z\) errors. \(Z\) maps \(|+\rangle\leftrightarrow|-\rangle\), and \(Z_j\) anticommutes with exactly the \(X\) checks that act on qubit \(j\), flipping their outcomes from \(+1\) to \(-1\).
A \(Z\) error hits the middle qubit of a phase-flip code state. The syndrome \((s_1,s_2)\) of the checks \(X_1X_2\), \(X_2X_3\) is .
Write the syndrome \((s_1,s_2)\) of the phase-flip code, \(s_i=1\) meaning check \(i\) returned \(-1\), for the errors \(I,Z_1,Z_2,Z_3\), and the decoder's correction for each.
\(Z_1\) anticommutes with \(X_1X_2\) only; \(Z_2\) with both; \(Z_3\) with \(X_2X_3\) only.
| error | \(I\) | \(Z_1\) | \(Z_2\) | \(Z_3\) |
|---|---|---|---|---|
| \((s_1,s_2)\) | 00 | 10 | 11 | 01 |
| correction | none | \(Z_1\) | \(Z_2\) | \(Z_3\) |
The four syndromes are distinct, so each single \(Z\) error is identified and undone. Why the syndrome cannot depend on the encoded \(\alpha,\beta\), and why that matters, is part of HW11 Problem 1.
The bit-flip code works the same way with \(X\) errors and \(Z\) checks; HW11 asks you to write its table and to compute its logical error rate.
The phase-flip code corrects \(Z_1\). Does it correct a small phase rotation, \(R_Z(\varepsilon)\) on qubit 1? It does, and the reason is the most important idea of the lecture.
If a code corrects each of the errors \(E_1,\dots,E_m\) (by a syndrome measurement followed by a correction), then it corrects every linear combination \(E=\sum_kc_kE_k\) acting on a code state. In particular, a code that corrects \(X_j\), \(Y_j\) and \(Z_j\) for every qubit \(j\) corrects every single-qubit error whatsoever, since every \(2\times2\) matrix is a combination of \(I,X,Y,Z\).
Idea of the proof. \(E|\psi_L\rangle=\sum_kc_kE_k|\psi_L\rangle\) is a superposition of correctable errors, and the syndrome measurement is a measurement like any other. Example 21.4 below shows what happens in the simplest case; HW11 Problem 2 carries out the general argument for Shor's code.
A phase-flip code state suffers \(e^{-i\theta Z_1}=\cos\theta\,I-i\sin\theta\,Z_1\) with \(\theta=\pi/6\). What is the probability that the syndrome measurement reports "\(Z_1\)"?
The bit-flip code state \(\sqrt{0.8}\,|000\rangle+\sqrt{0.2}\,|111\rangle\) suffers \(e^{-i\theta X_1}=\cos\theta\,I-i\sin\theta\,X_1\) with \(\theta=0.1\). Find the syndrome probabilities and the state after correction.
\(e^{-i\theta X_1}|\psi_L\rangle=\cos\theta\,|\psi_L\rangle-i\sin\theta\,X_1|\psi_L\rangle\). The first term has syndrome 00 and the second has the syndrome of \(X_1\), so the two are orthogonal. The syndrome measurement gives "no error" with probability \(\cos^2\theta\approx0.990\), leaving \(|\psi_L\rangle\); or "\(X_1\)" with probability \(\sin^2\theta\approx0.00997\), leaving \(X_1|\psi_L\rangle\) (up to a phase), which the decoder corrects. Either way the final state is exactly \(|\psi_L\rangle\). For comparison, the same rotation on an unencoded qubit in the state \(\sqrt{0.8}|0\rangle+\sqrt{0.2}|1\rangle\) leaves fidelity 0.996 (verify_L21.py): small, but it would accumulate, and the code removes it completely.
This is why error correction is possible at all, and why the Pauli errors of Lecture 19's twirling are not a simplification but the general case: correcting Paulis is correcting everything, provided only a few qubits are affected at once.
The bit-flip code corrects \(X\) but not \(Z\) (a \(Z\) on any qubit changes \(\alpha|000\rangle+\beta|111\rangle\) to \(\alpha|000\rangle-\beta|111\rangle\), a logical error the checks cannot see); the phase-flip code corrects \(Z\) but not \(X\). Shor (1995) concatenated them: encode with the phase-flip code, then encode each of its three qubits with the bit-flip code.
$$|0_L\rangle=\tfrac1{2\sqrt2}\big(|000\rangle+|111\rangle\big)^{\otimes3},\qquad|1_L\rangle=\tfrac1{2\sqrt2}\big(|000\rangle-|111\rangle\big)^{\otimes3}.$$Multiply out \(|0_L\rangle=\tfrac1{2\sqrt2}(|000\rangle+|111\rangle)^{\otimes3}\). How many nine-bit computational basis states appear with a nonzero amplitude?
Within each block of three, \(Z\)-parity checks find an \(X\) error. Across blocks, checks of the form \(X^{\otimes6}\) compare the signs of neighbouring blocks and find a \(Z\) error (up to which qubit in the block it hit, which turns out not to matter). HW11 Problem 2 shows how the two kinds of check together deal with every single-qubit Pauli error, and so, by Theorem 21.3, with every single-qubit error. Nine qubits for one is expensive; Lecture 22 builds a 7-qubit code with the same power from the Hamming code, and Lecture 23 the codes actually used in hardware.
import numpy as np from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister from qiskit_aer import AerSimulator from qiskit.quantum_info import Statevector, state_fidelity theta = 2 * np.arccos(np.sqrt(0.8)) # data qubit: sqrt(0.8)|0> + sqrt(0.2)|1> def phase_flip_code(err_angle): d, a, s = QuantumRegister(3, "d"), QuantumRegister(2, "a"), ClassicalRegister(2, "s") qc = QuantumCircuit(d, a, s) qc.ry(theta, d[0]); qc.cx(d[0], d[1]); qc.cx(d[0], d[2]); qc.h(d) # encode: |0> -> |+++>, |1> -> |---> qc.rz(err_angle, d[0]) # a coherent phase error on the first qubit qc.h(d) # measure X1X2 and X2X3 as Z-parities qc.cx(d[0], a[0]); qc.cx(d[1], a[0]); qc.cx(d[1], a[1]); qc.cx(d[2], a[1]) qc.h(d) qc.measure(a, s) with qc.if_test((s, 0b01)): qc.z(d[0]) # s[0] = X1X2 check, s[1] = X2X3 check; Qiskit's value is little-endian, so the text's (s1,s2) = 10 is 0b01 with qc.if_test((s, 0b11)): qc.z(d[1]) with qc.if_test((s, 0b10)): qc.z(d[2]) qc.h(d); qc.cx(d[0], d[2]); qc.cx(d[0], d[1]) # decode back onto d[0] qc.save_density_matrix([d[0]]) return qc target = Statevector([np.sqrt(0.8), np.sqrt(0.2)]) sim = AerSimulator(method="density_matrix", seed_simulator=21) for ang in (0.0, 0.6, np.pi): rho = sim.run(phase_flip_code(ang), shots=2000).result().data()["density_matrix"] q = QuantumCircuit(1); q.ry(theta, 0); q.h(0); q.rz(ang, 0); q.h(0) # no code: one qubit stored as H|psi>, same error print(f"error RZ({ang:.2f}) on qubit 1: fidelity with code {state_fidelity(rho, target):.4f}, without code {state_fidelity(Statevector(q), target):.4f}")
error RZ(0.00) on qubit 1: fidelity with code 1.0000, without code 1.0000 error RZ(0.60) on qubit 1: fidelity with code 1.0000, without code 0.9686 error RZ(3.14) on qubit 1: fidelity with code 1.0000, without code 0.6400
The circuit encodes, applies a coherent phase rotation to the first qubit, measures the two checks into ancillas, applies the correction with if_test, and decodes. The density-matrix simulator averages over the 2,000 shots' syndrome outcomes. With the code the fidelity is 1 for every rotation angle, including a full \(Z\) error (\(\pi\)); the unprotected qubit is damaged. (Errors on the ancillas or during the checks are not modelled here: that is fault tolerance, Lecture 23.)
import numpy as np, itertools H = np.array([[0, 0, 0, 1, 1, 1, 1], # Hamming [7,4,3]: column j is j in binary [0, 1, 1, 0, 0, 1, 1], [1, 0, 1, 0, 1, 0, 1]]) G = np.array([[1, 1, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0, 0], [0, 1, 0, 1, 0, 1, 0], [1, 1, 0, 1, 0, 0, 1]]) print("H G^T = 0 mod 2:", not (H @ G.T % 2).any()) codewords = [np.array(m) @ G % 2 for m in itertools.product((0, 1), repeat=4)] print("16 codewords, minimum weight", min(c.sum() for c in codewords if c.any())) def decode(r): s = H @ r % 2 pos = int("".join(map(str, s)), 2) # the syndrome IS the position of a single error r = r.copy() if pos: r[pos - 1] ^= 1 return pos, r r = np.array([1, 0, 1, 0, 1, 1, 1]) # codeword 1010101 with position 6 flipped print("received", r, "-> error at", *decode(r)) rng = np.random.default_rng(21); p, trials, fails = 0.05, 200_000, 0 for _ in range(trials): e = (rng.random(7) < p).astype(int) fails += decode(e)[1].any() # starting from the all-zero codeword, by linearity print(f"p = {p}: block failure rate {fails / trials:.4f} vs P(2 or more errors) = {1 - (1-p)**7 - 7*p*(1-p)**6:.4f}")
H G^T = 0 mod 2: True 16 codewords, minimum weight 3 received [1 0 1 0 1 1 1] -> error at 6 [1 0 1 0 1 0 1] p = 0.05: block failure rate 0.0441 vs P(2 or more errors) = 0.0444
Example 21.2, then a Monte Carlo check: the decoder fails exactly when two or more of the seven bits flip. By linearity it suffices to simulate errors on the all-zero codeword.
Next time: the stabilizer formalism, a compact language for all of these codes, and the Steane code. HW10 is due at the start of Week 12; project proposals are due this week (see the Lab 7 handout for the checklist).
all numbers and figures in these notes are computed in python (verify_L21.py) and follow the page theme