Part I · The Machinery of Quantum Information · Chapter 1
Bits to Qubits
A classical bit is a switch: one of two values. A qubit is a direction on a sphere — a continuum of states that nonetheless hands you exactly one bit when you look. Understanding that gap is understanding the whole field.
Sources: Nielsen & Chuang, Chs. 1–2 · Wilde, Ch. 3 · Dancing with Qubits, Chs. 2–5
A promise before we start, inherited from the first book. Nothing here is asserted on authority. We will define information the way an engineer must — as a countable resource — then let physics hand us an object that stores it strangely: a qubit. Everything about that object in this chapter is something you can compute, and by the end you will have, in Rust, a working single-qubit machine that agrees with the mathematics down to the last bits of double precision. Resist one temptation as we go: do not ask what the qubit “really is” between preparations and measurements. The honest answer is that it is a vector of amplitudes, and that answer is enough to build a computer.
What this chapter covers
- 1.1The classical bit. Shannon's measure of information: the bit as the unit of surprise, and entropy as the average of it.
- 1.2The qubit. A unit vector in ℂ², superposition, amplitudes, normalization, and why global phase does not count.
- 1.3The Bloch sphere. Every pure qubit as a point on a sphere; the angles θ, φ; and a live sphere you can steer.
- 1.4Measurement. The Born rule as a squared length, collapse, and the frequency that assembles it out of coin flips.
- 1.5One bit out. How much a qubit can store versus reveal: the Holevo quantity χ, computed for the four BB84 states, against what a real measurement extracts.
- 1.6The Lab. A single-qubit state-vector kit in Rust, refereed against independent code paths and against the accessible-information ceiling.
1.1The classical bit
F · FormalismBefore a quantum bit, be precise about a classical one. A bit is the answer to a single yes/no question: a switch that is 0 or 1, a coin that is heads or tails. Its power is not that it holds a symbol but that it measures information. Claude Shannon made this exact in 1948: the information content of an event of probability is bits — a certain event () surprises you not at all, a one-in-a-million event carries about twenty bits of surprise.
Average that surprise over a two-outcome source and you get the binary entropy,
which is 0 for a rigged coin and rises to exactly 1 bit for a fair one. That number — one bit, the most information a single yes/no channel can carry — is the yardstick we will hold the qubit against. Keep it in mind: it will turn out to be a ceiling the qubit cannot beat at readout, even though the qubit is a far richer object underneath.
1.2The qubit
F · FormalismNow the leap. A classical bit's state is a label, 0 or 1. A qubit's state is a unit vector in a two-dimensional complex vector space, , spanned by two distinguished states we write in Dirac's ket notation as and :
The complex numbers are probability amplitudes. A qubit that is neither cleanly 0 nor cleanly 1 but a weighted complex combination of both is in a superposition — the word simply means a vector sum. In the standard basis the state is the column vector , and , .
Two constraints in (1.2) earn comment. The normalization will be the total probability of the two measurement outcomes, so it must be 1. And a subtler fact: an overall phase does not count. The states and are physically identical — no measurement can tell them apart — because probabilities depend only on and , which the phase leaves untouched. Only relative phase between and is real. This is why, in the next section, a two-complex-number object (four real numbers, minus normalization, minus global phase) collapses to just two real angles.
1.3The Bloch sphere
C · ConceptsF · FormalismCount the freedom in (1.2). Two complex amplitudes are four real numbers; normalization removes one; the irrelevance of global phase removes another. Two remain — and they are naturally the two angles of a point on a sphere. Writing them out,
places every pure qubit on the surface of the unit Bloch sphere. The north pole () is , the south pole is , and the equator holds the equal superpositions like and . The physical direction of the qubit is the Bloch vector , whose components are the expectation values of the three Pauli observables (defined properly in Chapter 2); for a pure state exactly. Steer it:
0.500
P(0) = |α|²
0.500
P(1) = |β|²
1.000
entropy (bits)
Bloch vector r = (1.00, 0.00, 0.00), length 1.000. A global phase on |ψ⟩ would move nothing here — only the direction is physical.
Notice what the sliders confirm. Moving — the relative phase — sweeps the state around the equator without changing at all; phase is invisible to a -measurement yet utterly physical, as Chapter 6 will exploit to compute. Moving tilts between the poles and changes the odds. The whole of quantum computing is learning to move this vector — and, for many qubits at once, vectors in spaces too large to draw.
1.4Measurement and the Born rule
F · FormalismC · ConceptsA qubit in superposition is a rich object, but a measurement is brutal. Measure in the computational basis and you get a single classical bit: outcome 0 with probability , outcome 1 with probability . This is the Born rule — a probability is a squared amplitude,
and afterwards the state collapses onto whichever outcome occurred: a second measurement returns the same bit with certainty. The continuum of (1.3) is gone, spent to produce one bit. Run it as a frequency and watch it converge — the left panel is the lab's seeded shot sweep, reported in standard deviations; the right lets you fire your own:
The amplitudes are not probabilities themselves — they are their square roots, carrying a phase. That extra structure (a negative or complex amplitude) is exactly what a classical probability lacks, and exactly what lets quantum computations interfere alternatives to cancel wrong answers, the trick behind every algorithm in Part II. But at the instant of readout, the phase is discarded and only survives.
cargo run --release in Rust-QML/ch01-qubit)1.5One bit out
F · FormalismC · ConceptsHere is the paradox to sit with. Equation (1.3) says a qubit holds a continuous infinity of distinct states — two real angles' worth. Naively you might hope to hide a whole book in the trailing digits of . You cannot. A single measurement returns one bit, and the state collapses, so the digits are unrecoverable. In fact a theorem of Alexander Holevo (1973) makes the ceiling exact: one qubit can carry no more than one classical bit of accessible information.
That sentence is easy to nod along to and easy to state loosely, so we are going to turn it into a computation. It needs one new object and one new number.
The object is the ensemble average. Suppose a sender picks the state with probability . Rewrite each state as its outer product — a matrix instead of a column vector, carrying the same information but insensitive to global phase — and average:
is what a receiver who does not know which state was sent is holding. (Chapter 4 develops these matrices in earnest, under the name density matrix; here we need only the average.)
The number is Holevo's . Let be Shannon's of (1.1) applied to the eigenvalues of — for a single pure state those eigenvalues are 1 and 0, so — and define
Holevo's theorem says that the mutual information between the label the sender chose and the outcome any measurement reports satisfies . Both sides are now things we can evaluate.
So evaluate them. Take the four states that the BB84 key-distribution protocol sends down a fibre — — each with probability . The two poles average to and so do the two equatorial states, so
whose eigenvalues are both . Hence bit, every member is pure so every vanishes, and bit. A whole bit is in there. The lab certifies the matrix (1.7) entry by entry and then the number, taking the eigenvalues rather than assuming them.
How much of that bit comes out? Fix a measurement axis on the Bloch sphere, which by §1.3 gives outcome “+” with probability for a state with Bloch vector , and compute . The lab sweeps thousands of axes over the whole sphere; here is the slice through the – plane:
cargo run --release in Rust-QML/ch01-qubit)Read that honestly. The axis wins, and it wins by telling you everything about two of the four states and nothing about the other two. Tilt to the symmetric compromise at 45°, where all four states are equally distinguishable and none is perfectly distinguishable, and you do worse. A four-outcome measurement that tries to name the state outright — the symmetric POVM the lab also builds and checks for completeness — gets no further.
So Holevo's ceiling holds, and for this ensemble it is not even reached: says one bit and the best readout we can find yields half of it. We do not prove that half a bit is optimal over every conceivable measurement — that is a harder claim, and Exercise 5 sends you hunting for a counterexample. What the lab certifies is narrower and still decisive: across the whole sphere of two-outcome projective measurements and across the symmetric four-outcome POVM, nothing beats half a bit. The gap between what a qubit is and what one measurement reveals is not a rounding error. It is the subject of the book.
So what is the continuum for, if not storage? It is for processing. Between preparation and measurement, a qubit can be rotated, entangled with others, and interfered — and it is there, in the space of transformations, that the exponential richness of quantum mechanics lives. A qubit is a poor safe and a remarkable gear. The rest of Part I builds the gears; Part II runs them.
1.6The Lab — a single-qubit kit
P · PracticeEverything above becomes a small, sharp Rust program. A qubit is two complex numbers; a gate is a matrix; a measurement is a squared length and a collapse. Here is the core of the kit:
1use num_complex::Complex64;2// …3type C = Complex64;45fn c(re: f64, im: f64) -> C {6 C::new(re, im)7}89/// A single-qubit pure state |psi> = a|0> + b|1>, stored as amplitudes.10#[derive(Clone, Copy)]11struct Qubit {12 a: C,13 b: C,14}1516type Gate = [[C; 2]; 2];1718impl Qubit {19 // …2021 /// The standard Bloch parametrization: cos(t/2)|0> + e^{i p} sin(t/2)|1>.22 fn from_angles(theta: f64, phi: f64) -> Self {23 Qubit {24 a: c((theta / 2.0).cos(), 0.0),25 b: C::from_polar((theta / 2.0).sin(), phi),26 }27 }2829 // …3031 /// Apply a 2x2 gate: |psi> -> U|psi>.32 fn apply(&self, u: &Gate) -> Qubit {33 Qubit {34 a: u[0][0] * self.a + u[0][1] * self.b,35 b: u[1][0] * self.a + u[1][1] * self.b,36 }37 }3839 /// Born-rule probability of measuring 0 in the computational basis.40 fn p0(&self) -> f64 {41 self.a.norm_sqr()42 }4344 /// The three Bloch coordinates (expectation values of X, Y, Z).45 fn bloch(&self) -> (f64, f64, f64) {46 let x = 2.0 * (self.a.conj() * self.b).re;47 let y = 2.0 * (self.a.conj() * self.b).im;48 let z = self.a.norm_sqr() - self.b.norm_sqr();49 (x, y, z)50 }5152 // …53}
Now measurement, and the Born rule verified as a frequency rather than accepted as an axiom. One detail in the excerpt below is the difference between a real check and a decorative one. The state being measured is not built from the closed form of (1.3); it is built by applying a gate, the rotation by about the axis,
so that the measured frequency and the target reach the comparison down two different roads: one multiplies a matrix into a vector, the other evaluates a cosine. Had we prepared the state from the closed form instead, the referee would have compared with itself and reported a healthy number while testing nothing but the random number generator.
1impl Qubit {2 // …34 /// One measurement in the Z basis: returns the bit and collapses.5 fn measure(&self, rng: &mut StdRng) -> (u8, Qubit) {6 if rng.gen::<f64>() < self.p0() {7 (0, Qubit { a: c(1.0, 0.0), b: c(0.0, 0.0) })8 } else {9 (1, Qubit { a: c(0.0, 0.0), b: c(1.0, 0.0) })10 }11 }12}1314// …1516 // --- Referee family 3: the Born rule by Monte Carlo --------------------17 let theta_demo = 1.0_f64; // arbitrary tilt18 let theory_demo = (theta_demo / 2.0).cos().powi(2); // cos^2(theta/2)19 // Prepare the demo state with a GATE, so the thing being measured is not20 // the closed form it is about to be graded against.21 let psi = Qubit::ket0().apply(&g_ry(theta_demo));2223 // A convergence sweep for the chart, and the big-N referee at the end.24 let ns = [10usize, 30, 100, 300, 1_000, 3_000, 10_000, 30_000, 100_000, 1_000_000];25 let mut convergence = Vec::new();26 let mut big_dev = 0.0;27 for &n in &ns {28 let mut zeros = 0usize;29 for _ in 0..n {30 let (bit, _) = psi.measure(&mut rng);31 if bit == 0 {32 zeros += 1;33 }34 }35 let freq = zeros as f64 / n as f64;36 let sigma = (theory_demo * (1.0 - theory_demo) / n as f64).sqrt();37 let dev = if sigma > 0.0 { (freq - theory_demo).abs() / sigma } else { 0.0 };38 convergence.push(ConvergencePoint { n, freq, theory: theory_demo, sigma_dev: dev });39 if n == 1_000_000 {40 big_dev = dev;41 }42 }43 assert!(big_dev.is_finite());44 referees.push(Referee {45 name: format!("Born rule: |freq − cos²(θ/2)| at N={:e}, in σ", *ns.last().unwrap() as f64),46 // A statistical threshold, not a precision: 4 sigma is a false-alarm47 // rate near 1 in 16000. Achieved 0.716 sigma. Tightening this to the48 // achieved value would be tightening onto one seed, not onto physics.49 value: big_dev,50 tol: 4.0,51 pass: big_dev < 4.0,52 });
That is the design rule for every referee in both books: it must be able to fail. A check that compares a formula against itself, or that asserts something guaranteed by the way the data was constructed, will pass forever and warn you of nothing. The accessible-information block is built the same way — the probability of each outcome is computed twice, once by rotating the measurement axis onto with real gates and reading the Born rule, and once from the Bloch geometry of §1.3, with the two routes sharing no arithmetic:
The gate-algebra referee is worth one aside, because it certifies something genuinely strange. Among its identities is the spinor signature : rotating a qubit through a full turn — all the way around, back to where it started — does not return the state, it returns . It takes , two full turns, to come home, and the lab checks too. Nothing observable distinguishes from on its own — that is §1.2's global phase again — but put one arm of an interferometer through a single turn and the sign becomes a measurable shift in the fringes. This is the half-integer spin of the first book, showing up here as an algebraic fact about a matrix.
1/// Probability of the "+" outcome of a projective measurement along the Bloch2/// direction n(theta_m, phi_m), computed THROUGH THE KIT: rotate that axis3/// onto z with real gates, then read the Born probability of outcome 0.4fn p_plus_kit(psi: &Qubit, theta_m: f64, phi_m: f64) -> f64 {5 psi.apply(&g_rz(-phi_m)).apply(&g_ry(-theta_m)).p0()6}78/// The same probability from Bloch geometry: (1 + r.n)/2. No gate is applied9/// and no amplitude is touched — an independent route to the same number.10fn p_plus_bloch(psi: &Qubit, theta_m: f64, phi_m: f64) -> f64 {11 let (x, y, z) = psi.bloch();12 let (nx, ny, nz) = (13 theta_m.sin() * phi_m.cos(),14 theta_m.sin() * phi_m.sin(),15 theta_m.cos(),16 );17 0.5 * (1.0 + x * nx + y * ny + z * nz)18}1920/// I(X;Y) in bits for a UNIFORM ensemble read by a two-outcome measurement:21/// H(Y) - H(Y|X), where p_plus[i] is P(+ | state i) for state i.22fn mutual_info_binary(p_plus: &[f64]) -> f64 {23 let n = p_plus.len() as f64;24 let py = p_plus.iter().sum::<f64>() / n;25 let cond = p_plus.iter().map(|&p| shannon(p)).sum::<f64>() / n;26 shannon(py) - cond27}2829// …3031 // (b) The BB84 four-state ensemble, each member with probability 1/4.32 // These are exactly the four states BB84 sends down the fibre, and they33 // are the cleanest ensemble for which the Holevo bound is loose.34 let bb84 = [35 ("|0⟩", 0.0, 0.0),36 ("|1⟩", PI, 0.0),37 ("|+⟩", PI / 2.0, 0.0),38 ("|−⟩", PI / 2.0, PI),39 ];40 let bb84_states: Vec<Qubit> =41 bb84.iter().map(|(_, th, ph)| Qubit::from_angles(*th, *ph)).collect();42 let pr = 1.0 / bb84_states.len() as f64;4344// …4546 // (c) chi = S(rho_bar) - sum_i p_i S(rho_i), from EIGENVALUES both times.47 // We do not assume the members are pure; their entropies are computed.48 let s_bar = von_neumann_bits(&rho_bar);49 let s_members: f64 = bb84_states.iter().map(|s| pr * von_neumann_bits(&outer(s))).sum();50 let chi = s_bar - s_members;5152// …5354 let info_at = |theta_m: f64, phi_m: f64| -> (f64, f64, f64, f64) {55 let pk: Vec<f64> = bb84_states.iter().map(|s| p_plus_kit(s, theta_m, phi_m)).collect();56 let pb: Vec<f64> = bb84_states.iter().map(|s| p_plus_bloch(s, theta_m, phi_m)).collect();57 let dp = pk.iter().zip(&pb).fold(0.0f64, |m, (a, b)| m.max((a - b).abs()));58 let ik = mutual_info_binary(&pk);59 let ib = mutual_info_binary(&pb);60 (ik, ib, dp, (ik - ib).abs())61 };6263// …6465 // (e) THE GAP. chi says a full bit is in there; the best measurement66 // anywhere on the sphere pulls out exactly half of it.67 let gap = chi - i_max;68 let gap_err = (gap - 0.5).abs();69 assert!(gap.is_finite() && gap_err.is_finite());70 referees.push(Referee {71 name: "Holevo bound holds and is LOOSE: χ − I_acc = ½ bit".into(),72 value: gap_err,73 tol: 2e-16, // achieved 1.110e-1674 pass: gap_err < 2e-16,75 });
The referees write their results to JSON, which the panel below reads live. Nothing here is hardcoded: every value, tolerance and verdict is whatever your last cargo run --release produced, and the count of checks is the length of the array the lab emitted. Each tolerance in the source sits at the accuracy the run actually achieves, recorded in a comment beside it — with two deliberate exceptions: the Monte-Carlo referee, whose tolerance is a threshold in standard deviations rather than a precision, and the Holevo check, whose tolerance is the margin on an analytic identity. The assertion runs before the file is written, so the data the page displays can only ever come from a run in which every referee passed.
Run it yourself with cargo run --release in Rust-QML/ch01-qubit. This kit is not a toy we discard — Chapter 2 grows it into a full multi-qubit simulator by replacing “two amplitudes” with of them, and that simulator is the laboratory for the entire rest of the book.
1.7Exercises
1. (F) Show that the states and give identical measurement probabilities in every basis, not just the computational one. (Hint: a measurement basis is a pair of orthonormal kets; compute both overlaps.) Then show the same thing in one line using the outer product of §1.5.
2. (F) Starting from two complex amplitudes, carry out the counting of §1.3 explicitly and derive the parametrization (1.3). Where exactly does the (rather than ) come from?
3. (C) Using the Bloch explorer, find two distinct states with . How many such states are there? What single measurement axis would tell them apart?
4. (P) Add a method measure_x to the kit that measures in the basis by first applying and then measuring in . Verify that gives 0 and 1 with equal frequency. Then check your method against p_plus_kit at .
5. (P, hard) Go hunting for the counterexample §1.5 declines to rule out. The lab shows that no two-outcome projective measurement, and not the symmetric four-outcome POVM, extracts more than half a bit from the BB84 ensemble. Extend mutual_info_general to an arbitrary POVM — parametrize each element as , enforce and , and search numerically over three, four and six outcomes. Report the best you find and how close it comes to .
6. (F, hard) Prove the closed form the lab uses as its independent check on : for an ensemble of exactly two pure states, each with probability ,
(Hint: the Bloch vector of is , its eigenvalues are , and .) Then explain why the BB84 ensemble's referee reports an error of exactly zero while this one does not.
The bridge → Chapter 2: Gates and Circuits
Where you stand. You have a qubit — a unit vector in ℂ² on the Bloch sphere — plus the Born rule, collapse, and the hard limit that one qubit yields one bit. You have seen that limit measured: the four BB84 states hold a full bit of Holevo χ and give up half of it to the best readout on the sphere. And you have a Rust kit that checks every piece of it against independent code paths, to tolerances set at the accuracy it achieves.
The open question. A single qubit can be rotated but not made to compute anything. Computation needs operations that act on many qubits together and combine them. What are the legal operations, and how few of them do you need to build all the rest?
What comes next. We promote gates to a first principle: unitary matrices, a small universal set from which every operation is assembled, the circuit model, and the tensor product that binds n qubits into one 2ⁿ-dimensional state. Then we grow the single-qubit kit into a from-scratch multi-qubit simulator — the workhorse for all of Part II.