Grover Search
Grover’s algorithm is the most famous quantum search algorithm. It finds a marked item in an unsorted database of \(N\) items in \(O(\sqrt{N})\) steps— quadratically faster than classical search.
The Problem
Given an unsorted list of \(N\) items, find the one marked “good.”
Classically: \(O(N)\) operations.
With Grover: \(O(\sqrt{N})\) operations.
The Quantum Insight
Rather than searching through items one by one, Grover’s algorithm:
- Creates uniform superposition over all items
- Uses an oracle to mark the target
- Amplifies the marked state’s amplitude (amplitude amplification)
The Circuit Structure
┌─────────────────────────────────────────────────────────────┐
│ │
│ H⊗n ──[Oracle]── H⊗n ──[Diffusion]── H⊗n ──[Oracle]── ...│
│ │
│ One Grover Iteration │
└─────────────────────────────────────────────────────────────┘
Building Grover’s Algorithm
Step 1: Uniform Superposition
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from math import pi
n = 2 # 2 qubits = 4 items
qc = QuantumCircuit(n)
qc.h(range(n))
print("Uniform superposition:", Statevector(qc))
Step 2: Oracle (Mark the Target)
For target \(|11\rangle\):
def oracle_11():
qc = QuantumCircuit(n)
qc.cz(0, 1) # Flip phase of |11⟩
return qc
qc.compose(oracle_11(), inplace=True)
print("After oracle:", Statevector(qc))
Step 3: Diffusion (Amplify)
def diffusion():
qc = QuantumCircuit(n)
qc.h(range(n))
qc.x(range(n))
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
qc.compose(diffusion(), inplace=True)
print("After diffusion:", Statevector(qc))
Step 4: Measure
qc.measure_all()
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()
result = sampler.run([qc], shots=256).result()
print(result[0].data.meas.get_counts())
The target \(|11\rangle\) should dominate.
Understanding the Amplification
| Stage | \(|11\rangle\) Amplitude | |—––|————————| | Start (uniform) | \(1/\sqrt{4} = 0.5\) | | After oracle | \(-0.5\) (flipped sign) | | After diffusion | \(\approx 1.0\) (amplified) |
The diffusion step reflects about the mean amplitude, boosting the negative amplitude.
Optimal Iteration Count
For \(N\) items with \(M\) marked items:
- Optimal iterations \(\approx \frac{\pi}{4}\sqrt{\frac{N}{M}}\)
- Too few: amplitude not fully amplified
- Too many: amplitude rotates past target
def grover_search(n, target, iterations=1):
qc = QuantumCircuit(n)
qc.h(range(n))
for _ in range(iterations):
# Oracle: flip phase of |target⟩
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
qc.h(n-1)
qc.mcx(list(range(n-1)), n-1)
qc.h(n-1)
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
# Diffusion: flip phase of all except |0...0⟩, then reflect
qc.h(range(n))
qc.x(range(n))
qc.h(n-1)
qc.mcx(list(range(n-1)), n-1)
qc.h(n-1)
qc.x(range(n))
qc.h(range(n))
qc.measure_all()
return qc
Testing on Different Targets
# Search for |01⟩ on 2 qubits
# Note: target string is 'q1 q0'
qc = grover_search(2, '01', iterations=1)
result = sampler.run([qc], shots=256).result()
print("Searching for |01⟩:", result[0].data.meas.get_counts())
Visualizing Amplitude Evolution
import matplotlib.pyplot as plt
def grover_amplitudes(n, target):
"""Return amplitudes after each iteration."""
amplitudes = []
qc = QuantumCircuit(n)
qc.h(range(n))
amplitudes.append(Statevector(qc))
for _ in range(3): # 3 iterations
# Oracle
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
qc.h(n-1)
qc.mcx(list(range(n-1)), n-1)
qc.h(n-1)
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
# Diffusion
qc.h(range(n))
qc.x(range(n))
qc.h(n-1)
qc.mcx(list(range(n-1)), n-1)
qc.h(n-1)
qc.x(range(n))
qc.h(range(n))
amplitudes.append(Statevector(qc))
return amplitudes
# Plot amplitudes for |11⟩ on 2 qubits
amplitudes = grover_amplitudes(2, '11')
for i, amp in enumerate(amplitudes):
print(f"Iteration {i}: |11⟩ amplitude = {amp[3]:.3f}")
Checkpoint Exercises
Exercise 1
Implement Grover’s search for \(|00\rangle\) on 2 qubits.
Exercise 2
Search for \(|101\rangle\) on 3 qubits.
Exercise 3
Compare 1, 2, and 3 iterations. What happens with too many?
Exercise 4
Search for one marked item among 8 (3 qubits). Verify speedup.
Exercise 5
Explain why Grover’s algorithm is optimal.
Summary
Key concepts:
- Grover searches unsorted data in \(O(\sqrt{N})\)
- Oracle marks target with phase flip
- Diffusion amplifies marked amplitude
- Optimal iterations \(\approx \pi/4\sqrt{N/M}\)
- Works by amplitude amplification, not parallelism
Grover’s algorithm is your first taste of quantum speedup. It shows how quantum mechanics can outperform classical computation.