DiracDirac

Part II · Algorithms and What They Really Buy · Chapter 8

Search and Amplitude Amplification

Given a needle hidden in a haystack of size N and no clue where it is, a classical searcher must, on average, look through half the hay. A quantum searcher looks through only about √N of it. That speedup is real and provably the best possible — and it is only quadratic. Being honest about that gap is the whole chapter.

Sources: Nielsen & Chuang, Ch. 6 · Grover 1996 · BBBV 1997

Chapter 7 built the Fourier machinery and, with it, Shor's exponential attack on factoring — an advantage that lives on the structure of the problem (periodicity). This chapter takes the opposite case: a problem with no structure at all, a black-box function that says “yes” on a hidden input and “no” everywhere else. Here quantum mechanics still helps, through Lov Grover's beautiful rotation of amplitudes toward the answer — but only quadratically, and, by a matching lower bound, not a step better. We will build Grover from its two moving parts, generalize it to amplitude amplification (a boost for any biased quantum subroutine), state the BBBV limit that makes optimal, and close with quantum walks, whose ballistic spreading is the same quadratic advantage wearing different clothes. The search law, the diffusion step that drives it, and the amplitude-amplification boost are each refereed against an independently computed form — the tolerances and the deviations actually achieved are in the Lab panel.

What this chapter covers

  • 8.1Unstructured search. The needle-in-a-haystack problem, the query model, and the phase-flip oracle that marks a solution without revealing it.
  • 8.2Grover's algorithm. Oracle then diffusion (inversion about the mean); the geometric picture as a rotation by 2θ; success sin²((2k+1)θ); the optimal k and the danger of over-rotating.
  • 8.3Amplitude amplification. The generalization: any algorithm A with success amplitude a is boosted to near-certainty in O(1/a) steps. Grover is the special case A = H⊗ⁿ.
  • 8.4The √N limit. The BBBV lower bound: no quantum algorithm searches an unstructured space in fewer than Ω(√N) queries. Grover is optimal; the speedup is quadratic, not exponential.
  • 8.5Quantum walks. A coined walk on a line spreads ballistically (σ ~ t) where a classical random walk only diffuses (σ ~ √t) — a search primitive in its own right.
  • 8.6The Lab. A fresh state-vector simulator running Grover, the multi-solution case, amplitude amplification, and a quantum walk — every claim refereed, including the diffusion step itself, with the whole scoreboard read live from the lab's JSON.

8.2Grover's algorithm

F · FormalismC · Concepts

A phase flip alone accomplishes nothing measurable: the marked amplitude is now instead of , but its magnitude — and so its measurement probability — is unchanged. Grover's insight is to follow the oracle with a second operation that converts that sign difference into a difference in magnitude: the diffusion operator, an inversion about the mean.

Start in the uniform superposition . The diffusion operator is the reflection

(8.2)

whose action on any state is wonderfully concrete: if is the mean of the amplitudes, then sends each amplitude — it reflects every amplitude through the average. After the oracle has pushed the marked amplitude below zero, the mean dips slightly; reflecting the lone negative amplitude about that mean sends it well above the crowd, while the many positive amplitudes each shrink a little. One Grover iteration is : oracle, then diffusion.

A rotation by 2θ|α⟩|β⟩non-sol.sol.|s⟩θG|s⟩Inversion about the meanN = 6, one marked item, to scale (73.5 px per unit)0all six started at 1/√6 = 0.4080.136 eachmarked−0.408mean ā = 0.2720.953
Figure 8.1. One Grover iteration, twice over. Left: in the plane spanned by the solution axis |β⟩ and the non-solution axis |α⟩, the oracle reflects the state across |α⟩ and the diffusion reflects it across the start |s⟩; two reflections compose to a rotation by 2θ toward the solution. Right: the same step drawn to scale for N = 6 with one marked item. All six amplitudes start at 1/√6 = 0.408 — the height the dashed outlines mark; the oracle sends the marked one to −0.408, which pulls the mean down to 0.272 (gold dashed); inverting about that mean lifts the marked amplitude to 2(0.272) + 0.408 = 0.953 (blue) while the five others shrink to 2(0.272) − 0.408 = 0.136 (solid). Every bar height in the panel is that arithmetic at 73.5 px per unit amplitude.

Why a rotation? Because the whole dance happens in a two-dimensional plane. Let be the (normalized) uniform superposition of the solutions and the uniform superposition of the non-solutions. The start state is with

(8.3)

a small angle when solutions are rare. The oracle is a reflection about (it flips the component); the diffusion is a reflection about . The composition of two reflections is a rotation by twice the angle between their axes — here a rotation by that carries the state toward . After iterations the state sits at angle , so the probability of measuring a solution is

(8.4)

This is the master law of the chapter, and the Lab referees the simulator against it at a tolerance of order (the achieved deviation is read live in the panel). To make — the top of the sine — we want

(8.5)

which for a single solution is the famous . Here is the trap that (8.4) makes vivid: the success probability is oscillatory. Run past and the state rotates beyond the solution axis; the probability falls again, all the way back to nearly zero near . More iterations are not better. A quantum searcher must stop at exactly the right time, which is why knowing (or estimating it) matters. Drive the amplitudes yourself. The explorer below holds a real array of amplitudes and does exactly what the lab does — flip the sign of the marked one, then send every amplitude to — so what you see is the mechanism running, not a plot of (8.4). You can stop it half-way through an iteration to catch the marked amplitude below the axis and the mean (gold dashed) dipping with it:

0mean ā = 0.250markedamplitudes after k = 0 iterations

search space

0k_opt8

apply, one stage at a time

0.0625

success P = |amarked

0.2500

amarked, from the array

Independent check: the closed form sin²((2k+1)θ) for k = 0 gives 0.062500, a deviation of 0.0e+0 from the evolved array. The lab runs this comparison across every k.
Each iteration reflects the marked amplitude's sign, then reflects all 16 amplitudes through their mean (gold) — and that alone rotates the state by 2θ toward the solution. Slide to k = 3 for the near-certain answer.

Notice how flat the marked bar starts — at it is just , the same as every other — and how steeply it climbs, then falls. The closed form (8.4) is never used to draw the bars, so the explorer can be compared against it, and it prints that comparison for the state on screen; the Lab does the same at every of every in its sweep, at machine precision.

Grover's trick does not depend on the start being the uniform superposition. Suppose any quantum subroutine (a state-prep circuit, with no measurements) produces

(8.6)

so that a plain measurement finds a “good” outcome with probability , perhaps small. (A phase convention hides in (8.6): we take to be real and , absorbing any phase into — automatically true for the lab's construction, where is a product of real rotations.) The amplitude amplification operator replaces Grover's two reflections with the analogous pair,

(8.7)

a reflection across the complement of the good subspace — flips the sign of the good component and fixes everything orthogonal to it, exactly as the oracle of §8.2 reflected across by flipping — followed by a reflection about the prepared state . Exactly as before, this rotates by in the two-dimensional plane, so after steps the good-outcome probability is again, reaching near 1 after

(8.8)

steps — a quadratic improvement over the repetitions a classical “prepare, measure, retry” loop would need. Grover's algorithm is the special case , where is exactly the diffusion operator. The Lab builds a deliberately biased — a product of rotations whose success amplitude is a few percent, printed live in the panel — and boosts it to near-certainty, verifying the same sin² law to the same machine-precision standard as Grover's own. This generalization is what makes Grover a building block: wrap it around any subroutine whose successes you can recognize, and you square the number of tries.

Could a cleverer quantum algorithm beat ? No — and this is provable. The BBBV theorem (Bennett, Bernstein, Brassard, and Vazirani) shows that any quantum algorithm that finds a marked item among using an unstructured oracle with bounded error — succeeding with probability at least, say, on every instance — must make at least

(8.9)

queries. The idea of the proof is a “hybrid” argument: each query can only nudge the state a little, and it takes such nudges before the algorithm's behaviour can depend appreciably on which item is marked. Grover meets this bound, so it is optimal: the quadratic speedup is the exact ceiling for unstructured search.

This deserves an honest scorecard. Grover's advantage is quadratic, not exponential. A million-item search drops from queries to — genuinely useful, but a far cry from the exponential collapse Shor gives factoring. And it comes with fine print: you need a real quantum oracle for (building one can cost as much as the search it saves), you need to know roughly how many solutions there are (to avoid over-rotating), and the whole run must stay coherent. The lesson to carry forward is that quantum speedups are problem-specific: exponential when there is structure to exploit (Chapter 7 and, next, simulation), quadratic and provably no more for pure unstructured search.

8.5Quantum walks

C · ConceptsF · Formalism

The same quadratic flavour appears in a different guise, one that has become a general-purpose algorithmic primitive: the quantum walk. Consider a walker on a line. A classical random walker flips a coin at each step and moves left or right; after steps its position is spread over a Gaussian of width — the familiar diffusive scaling of Brownian motion.

A quantum walker carries a “coin” qubit. Each step applies a Hadamard to the coin — putting it in superposition of left and right — and then a conditional shift that moves the left-amplitude left and the right-amplitude right. Because the amplitudes interfere rather than average, the distribution does not pile up in the middle; it races outward in two ballistic fronts, and the spread grows linearly,

(8.10)

That is again a quadratic separation — the quantum walker covers in steps what the classical walker needs to reach. The Lab evolves both walkers — the quantum one as amplitudes with a coin, the classical one as an exact probability distribution updated by — and fits the exponent of from each evolved dataset: it comes out for the quantum walk and for the classical one, refereed. Discrete- and continuous-time quantum walks underlie a whole family of algorithms — element distinctness, spatial search, and, in a sense, even Grover — where the walk's fast spreading is exactly what accelerates the search.

A fresh state-vector simulator — the same flat array of amplitudes from Chapter 2 — carries the whole chapter. The oracle is a sign flip on the marked indices; the diffusion is one pass computing the mean and reflecting through it:

ch08-grover/src/main.rs — the oracle and the diffusion operator
1impl State {
2// …
3 /// THE ORACLE. Mark solutions by a phase flip: |x> -> -|x> for x in
4 /// `marked`, and leave every other basis state alone. This is I - 2·P_good.
5 fn oracle(&mut self, marked: &[usize]) {
6 for &m in marked {
7 self.amps[m] = -self.amps[m];
8 }
9 }
10
11 /// THE DIFFUSION OPERATOR 2|s><s| - I: inversion about the mean amplitude.
12 /// Reflecting every amplitude through the average sends a -> 2·mean - a.
13 fn diffuse(&mut self) {
14 let dim = self.dim();
15 let mean: C = self.amps.iter().sum::<C>() / (dim as f64);
16 for a in self.amps.iter_mut() {
17 *a = 2.0 * mean - *a;
18 }
19 }
20
21 /// Total probability sitting on the marked set — the success probability.
22 fn success(&self, marked: &[usize]) -> f64 {
23 marked.iter().map(|&m| self.amps[m].norm_sqr()).sum()
24 }
25}

The headline referee never trusts the simulator on its own word: it computes the geometry independently — from , the success probability from , and the optimal from — and demands agreement at every step of every in the sweep, at a tolerance of (the deviation the run actually achieves is in the panel):

ch08-grover/src/main.rs — the closed-form law and the referee
1/// The half-angle θ of the search: sinθ = √(M/N).
2fn grover_theta(m: usize, n_dim: usize) -> f64 {
3 (m as f64 / n_dim as f64).sqrt().asin()
4}
5
6/// Success probability after k iterations, sin²((2k+1)θ).
7fn grover_law(k: usize, theta: f64) -> f64 {
8 let s = ((2 * k + 1) as f64 * theta).sin();
9 s * s
10}
11
12/// The optimal integer iteration count, round(π/(4θ) − 1/2).
13fn k_optimal(theta: f64) -> usize {
14 let x = PI / (4.0 * theta) - 0.5;
15 x.round().max(0.0) as usize
16}
17// …
18 let mut worst_law: f64 = 0.0;
19 for n in 2..=12 {
20 let big_n = 1usize << n;
21 let marked = vec![(0x2b_usize.wrapping_mul(n)) % big_n]; // an arbitrary target
22 let theta = grover_theta(1, big_n);
23 let k_max = 2 * k_optimal(theta) + 2;
24 let mut s = State::zero(n);
25 s.hadamard_all();
26 for k in 0..=k_max {
27 let dev = (s.success(&marked) - grover_law(k, theta)).abs();
28 worst_law = worst_law.max(dev);
29 s.oracle(&marked);
30 s.diffuse();
31 }
32 }
33 assert!(worst_law.is_finite());
34 referees.push(Referee {
35 name: "Grover P(k) = sin²((2k+1)θ), n=2..12".into(),
36 value: worst_law,
37 tol: 5e-13,
38 pass: worst_law < 5e-13,
39 });

That check grades a probability, and along Grover's own orbit every amplitude stays real — so a diffusion that mishandled the imaginary part of an amplitude would sail straight through it. That is not hypothetical: replacing the mean by the mean of the real parts alone leaves every other referee in this lab passing. A second referee therefore grades the mechanism of §8.2 directly, as an operator identity: the simulator's two in-place passes against an explicit dense matrix, applied to a deliberately lopsided state with unequal magnitudes and phases. It is the check that catches a dropped factor of 2 in :

ch08-grover/src/main.rs — the diffusion as an operator identity
1// =====================================================================
2 // Referee 2: the mechanism itself, as an operator identity. The simulator
3 // never builds a matrix — oracle() flips signs in place and diffuse() makes
4 // one O(N) pass computing the mean — so here the SAME single iteration is
5 // recomputed a second, independent way: the dense matrix
6 // G_ij = (2/N − δ_ij) · (−1)^{f(j)}
7 // read straight off G = (2|s><s| − I)(I − 2P_good), applied by an explicit
8 // matrix-vector product. It is run on a deliberately lopsided state (unequal
9 // magnitudes AND phases, two marked items), because along the symmetric
10 // Grover orbit a wrong mean or a dropped factor of 2 can hide.
11 // =====================================================================
12 let mech_n = 6usize;
13 let mech_dim = 1usize << mech_n;
14 let mech_marked = vec![9usize, 44usize];
15 let mut mech = State::zero(mech_n);
16// …
17 let mut mech_sim = mech.clone();
18 mech_sim.oracle(&mech_marked); // path A: the two in-place passes
19 mech_sim.diffuse();
20 let mut mech_mat = vec![c(0.0, 0.0); mech_dim]; // path B: the dense matrix
21 for i in 0..mech_dim {
22 let mut acc = c(0.0, 0.0);
23 for j in 0..mech_dim {
24 let sign = if mech_marked.contains(&j) { -1.0 } else { 1.0 };
25 let refl = 2.0 / mech_dim as f64 - if i == j { 1.0 } else { 0.0 };
26 acc += refl * sign * mech.amps[j];
27 }
28 mech_mat[i] = acc;
29 }
30 let mech_dev = mech_sim
31 .amps
32 .iter()
33 .zip(mech_mat.iter())
34 .map(|(a, b)| (a - b).norm())
35 .fold(0.0f64, f64::max);
36 assert!(mech_dev.is_finite());
37 referees.push(Referee {
38 name: "Iteration = (2|s><s|−I)(I−2P) matrix, max |Δa|".into(),
39 value: mech_dev,
40 tol: 2e-16, // roundoff-tight: the two paths agree to ~1e-16
41 pass: mech_dev < 2e-16,
42 });

The quantum walk is its own small engine: a coin Hadamard and a conditional shift, iterated, with the position spread measured at each step and its growth exponent fit by least squares. The line is sized so that nothing is ever shifted off its ends — and that, too, is refereed rather than asserted, by measuring the walker's total probability at every step:

ch08-grover/src/main.rs — one step of the coined quantum walk
1/// σ(t) of the quantum walker's position for t = 0..=steps, together with the
2/// total probability at each step. The line holds 2·steps+1 sites, which is
3/// exactly wide enough that no amplitude is ever shifted off either end during
4/// the run: the two ballistic fronts reach the outermost sites only at t =
5/// steps. Returning the totals lets a referee CHECK that containment rather
6/// than take it on trust.
7fn quantum_walk_sigma(steps: usize) -> (Vec<f64>, Vec<f64>) {
8// …
9 for _ in 0..steps {
10 // Coin: Hadamard mixing the two coin components at each position.
11 let mut b0 = vec![c(0.0, 0.0); width];
12 let mut b1 = vec![c(0.0, 0.0); width];
13 for p in 0..width {
14 b0[p] = inv * (amp0[p] + amp1[p]);
15 b1[p] = inv * (amp0[p] - amp1[p]);
16 }
17 // Shift: coin-0 moves left (p-1), coin-1 moves right (p+1).
18 let mut n0 = vec![c(0.0, 0.0); width];
19 let mut n1 = vec![c(0.0, 0.0); width];
20 for p in 0..width {
21 if p >= 1 {
22 n0[p - 1] = b0[p];
23 }
24 if p + 1 < width {
25 n1[p + 1] = b1[p];
26 }
27 }
28 amp0 = n0;
29 amp1 = n1;
30 sigmas.push(position_sigma(&amp0, &amp1, start));
31 totals.push(walk_total(&amp0, &amp1));
32 }
33 (sigmas, totals)
34}

Every referee writes its verdict to JSON, and the panel below reads the whole scoreboard live — the count, the achieved values, and the tolerances are all whatever the last run produced, not numbers typed into this page. The Grover law holds across the whole sweep; the diffusion matches its matrix definition to floating-point roundoff; the numeric peak lands on the predicted exactly; the multi-solution case obeys the same law with ; amplitude amplification boosts a biased subroutine to near-certainty on schedule; and the two evolved walkers separate cleanly into a slope-1 (ballistic) and a slope-½ (diffusive) line — both slopes fit from the data, neither asserted.

Loading /data/ch08/grover.json… (run cargo run --release in Rust-QML/ch08-grover)

Run it yourself with cargo run --release in Rust-QML/ch08-grover. Grover and Shor are the two celebrities of quantum algorithms, and between them they mark the boundary of the honest scorecard: quadratic where there is no structure, exponential where there is. The next chapter turns to the problem that started the field — and where the exponential advantage is least in doubt.

8.7Exercises

1. (F) Show directly that acts on an amplitude vector as , where . (Hint: write as the matrix every one of whose entries is .)

2. (C) In the amplitude explorer, set and step the slider one iteration at a time. At what is the success probability highest? Compare to . Now push past it — how many iterations until the probability has fallen back near zero, and does that match ? Then park the slider at and step through “+ oracle” and “+ diffusion”: read the mean off the gold line in each stage and check by hand, once for the marked bar and once for one of the others.

3. (P) Add a measure-and-count routine to the lab: run Grover to for , sample the outcome many times, and confirm the empirical success frequency matches within a few .

4. (F, hard) Derive carefully. Starting from , find the real that maximizes it, then explain why rounding to the nearest integer is the right thing to do and bound the resulting shortfall in terms of . Why does over-rotation make “when to stop” a genuine algorithmic problem when is unknown?

5. (P, hard) Implement amplitude amplification around a nontrivial subroutine of your own: an that prepares a biased distribution over qubits, with “good” a predicate you can check. Verify empirically that the number of amplification steps to reach success probability scales as as you shrink the initial amplitude — the quadratic win over classical retrying.

The bridgeChapter 9: Simulating Quantum Systems

Where you stand. You have Grover's search built from an oracle and a diffusion, the geometric rotation that explains it, amplitude amplification as the general boost, the BBBV proof that √N is optimal, and a quantum walk that spreads ballistically — with the search law refereed against an independent closed form, and the diffusion itself refereed against its matrix definition on a state chosen so that nothing could hide.

The open question. Grover and Shor are special cases: one quadratic on the structureless worst case, one exponential on a problem with hidden periodicity. But Feynman's original 1982 dream was neither factoring nor search — it was simulating quantum physics itself. Is that where the clearest, least-disputed exponential advantage actually lives?

What comes next. We return to the founding motivation: representing and evolving a many-body quantum system. Trotter–Suzuki product formulas break a Hamiltonian into simulable pieces, we bound the error and referee it, and we see why simulating quantum matter — chemistry, materials — is the application whose exponential speedup needs no oracle and no fine print.

Continue to Chapter 9