Grover's Search and Amplitude Amplification
Grover's algorithm finds a marked element in an unstructured list of N items with O(√N) queries — a provable quadratic speedup. This tutorial derives the algorithm geometrically as a rotation in a 2D subspace, gives the exact optimal iteration count, and shows how amplitude amplification generalizes the trick far beyond search.
Prerequisites: Tutorial 9: Bernstein-Vazirani and Simon
Deutsch-Jozsa and Simon solved problems with a very specific algebraic structure. Grover’s algorithm solves a problem with no structure — and still beats classical algorithms. Given an unsorted list of items and a black-box test that recognizes the right one, Grover finds it in queries. Classical algorithms need in the worst case.
The speedup is “only” quadratic — not exponential like Shor — but it’s universally applicable. Any NP search problem whose verifier runs in polynomial time gets a quadratic quantum speedup. That includes SAT, graph coloring, hash preimage finding, and a long list of cryptographic primitives. Grover is the quantum algorithm that affects the broadest variety of real problems.
The problem
You have a function accessed as an oracle. There are “marked” inputs — those with — among total. Your job: find any marked input.
Classical bound. To have a constant probability of success, you need queries. In the single-solution worst case (), that’s .
Quantum bound. queries. For : .
The oracle
Same reversible oracle as before:
With phase kickback (target in ), this becomes a phase oracle:
The setup
Prepare the uniform superposition:
Every basis state has amplitude . If you measured now, each marked state would show up with probability — pointless.
Grover’s trick: amplify the amplitudes of marked states and suppress the others, by repeatedly applying a two-step “Grover iteration” that rotates the state vector toward the marked subspace.
The geometric picture
Split the state space into two orthogonal subspaces:
- — uniform superposition over marked (“good”) states, where is the set of marked inputs.
- — uniform superposition over unmarked (“bad”) states.
The initial state is:
Define . Then — a point on a 2D plane at angle from the axis.
Key realization: everything Grover does stays in this 2D plane. The whole -dimensional Hilbert space is irrelevant; only the angle matters.
The Grover iteration
Each iteration consists of two reflections:
Step 1: Oracle reflection. The phase oracle flips the sign of marked states. In the 2D picture, this is a reflection across the axis:
Step 2: Diffuser (reflection about the uniform superposition). Define . This reflects any state across the axis.
The product is a rotation by angle in the 2D plane. Two reflections = one rotation.
After iterations, the state is at angle from . When this angle reaches , the state is at and a measurement gives a marked element with probability 1.
Solve: , so
For , : → use 3 iterations.
Implementing the diffuser
The diffuser can be decomposed as:
The middle operator “reflect about ” is implemented as: flip all qubits (X gates) so that becomes ; apply a multi-controlled Z (which flips the sign only of ); flip back. Concretely:
def grover_diffuser(n: int) -> QuantumCircuit:
qc = QuantumCircuit(n, name="diffuser")
qc.h(range(n))
qc.x(range(n))
# Multi-controlled Z via H-CCZ-H pattern
qc.h(n - 1)
qc.mcx(list(range(n - 1)), n - 1)
qc.h(n - 1)
qc.x(range(n))
qc.h(range(n))
return qc
Full Grover circuit
import numpy as np
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
def phase_oracle(n: int, marked: list[int]) -> QuantumCircuit:
"""Phase oracle that flips the sign of every `x` in `marked`."""
qc = QuantumCircuit(n, name="oracle")
for x in marked:
bits = format(x, f"0{n}b")
# Flip zeros so the marked state becomes |11...1⟩
for i, b in enumerate(reversed(bits)):
if b == "0":
qc.x(i)
qc.h(n - 1)
qc.mcx(list(range(n - 1)), n - 1)
qc.h(n - 1)
for i, b in enumerate(reversed(bits)):
if b == "0":
qc.x(i)
return qc
def grover(n: int, marked: list[int], iterations: int | None = None) -> QuantumCircuit:
N = 2**n
k = len(marked)
if iterations is None:
theta = np.arcsin(np.sqrt(k / N))
iterations = max(1, round((np.pi / (4 * theta)) - 0.5))
qc = QuantumCircuit(n, n)
qc.h(range(n)) # uniform superposition
for _ in range(iterations):
qc.compose(phase_oracle(n, marked), inplace=True)
qc.compose(grover_diffuser(n), inplace=True)
qc.measure(range(n), range(n))
return qc
# --- Run ---
n = 4
marked = [0b1011] # find the state |1011⟩ = 11
qc = grover(n, marked)
counts = AerSimulator().run(qc, shots=2048).result().get_counts()
top = sorted(counts.items(), key=lambda kv: -kv[1])[:3]
for bits, count in top:
print(f"|{bits}⟩ → {count} shots ({count/2048:.1%})")
# |1011⟩ → 1997 shots (97.5%)
# |0000⟩ → 7 shots (0.3%)
# ...
For , , optimal iterations = 3, success probability ≈ 96%. The remaining 4% is spread over the 15 unmarked states.
→ Try the 3-qubit Grover in the playground — select “Grover (3 qubits)” from the examples dropdown.
Multiple marked items
If , amplitude amplification still works; the optimal iteration count just scales differently:
# Find one of {|1011⟩, |0110⟩} among 16
marked = [0b1011, 0b0110]
qc = grover(n, marked)
counts = AerSimulator().run(qc, shots=4096).result().get_counts()
hits = counts.get(format(marked[0], f"0{n}b"), 0) + counts.get(format(marked[1], f"0{n}b"), 0)
print(f"Found a marked state in {hits/4096:.1%} of shots")
# Found a marked state in ~99% of shots
With , , . Optimal iterations: → 2 iterations.
Amplitude amplification: the general pattern
Grover is a special case of a broader technique called amplitude amplification. The general setup:
- You have a quantum algorithm that produces , where is a “good” subspace and is “bad.”
- You have an oracle that reflects about (flips the sign of good states).
- You want to amplify the good-state amplitude from to near 1.
The recipe is exactly Grover’s: repeatedly apply , which is a rotation by in the same 2D plane. After iterations, the good-state amplitude is near 1.
Why this matters in practice: any classical Monte Carlo algorithm with success probability becomes a quantum algorithm with success probability near 1 after repetitions — a quadratic speedup, for free. This shows up in:
- SAT solving: quadratic speedup over backtracking
- Hash preimage search: SHA-256 preimage in instead of , forcing post-quantum protocol design
- Machine learning: quadratic speedup for Monte-Carlo-style estimators
- Optimization: quantum minimum finding in
Exercises
1. Iteration-count intuition
For and , how many Grover iterations are optimal? What’s the success probability after that many iterations?
Show answer
, rad. Optimal iterations: → round to 7. After 7 iterations, the angle from is rad, so → 99.6% success.
2. Over-iterating
Implement a 4-qubit Grover search for a single marked state and measure the success probability as a function of iteration count from 0 to 10. Verify you see the rotation pattern predicted by the geometric picture.
Show expected shape
For , , . Success probability at iteration : .
- t=0: 6.25% (sanity check — 1/16 = baseline)
- t=1: 47.3%
- t=2: 90.9%
- t=3: 96.1% (peak)
- t=4: 58.0% (over-rotated past the target)
- t=5: 11.2%
- t=6: 0.3% (almost back to )
3. Grover as hash preimage attack
Given a hash function and a target digest , how many Grover iterations do you need to find a preimage with , assuming 1 preimage exists? How does this scale to SHA-256?
Show answer
For 16-bit preimage: , , iterations . For SHA-256 preimage: , iterations — still astronomical, but “only” the square root of . This is the reason NIST recommends 256-bit hashes for post-quantum security: to retain 128-bit effective security against Grover attacks.
4. Amplitude amplification beyond search
Suppose you have a classical algorithm that samples a value from a distribution and returns “success” with probability . How many Grover-style amplifications turn this into a near-certain success, assuming you can run the algorithm reversibly as a quantum subroutine?
Show answer
, rad. Optimal iterations: → 7 iterations. Classical would need tries for the same confidence. The quadratic vs actual 7 matches theory.
What you should take away
- Grover finds a marked element in queries. Classical unstructured search is . The quadratic speedup is optimal — you cannot do better on unstructured problems.
- Geometric picture: Grover lives in a 2D plane, rotates by per iteration, hits after iterations.
- The diffuser is a Hadamard-sandwiched multi-controlled-Z. Same structure for every .
- Amplitude amplification generalizes Grover: any quantum algorithm with success probability gets amplified to near-1 in iterations.
- Implications for crypto: forces 256-bit hashes and -bit symmetric keys for post-quantum security. Doesn’t threaten public-key crypto — that’s Shor’s territory.
Next: Quantum Fourier Transform and Phase Estimation. The last two primitives you need before we tackle Shor.