Grover's algorithm is one of two quantum algorithms with proven, unambiguous quantum speedup (the other being Shor's). It searches an unstructured database of N items in O(√N) time, compared to O(N) for classical algorithms. This is a quadratic speedup — not exponential, but provably optimal for unstructured search.
This tutorial builds Grover's algorithm from scratch: the problem it solves, the mathematical mechanism behind the speedup, the circuit implementation, and a complete Qiskit implementation.
The Problem
You have a function f: {0,1}ⁿ → {0,1} where exactly one input x satisfies f(x) = 1. You want to find x*.
Classically, with no structure to exploit, you must evaluate f on average N/2 times to find x* (where N = 2ⁿ). This is optimal — no classical algorithm can do better in the worst case.
Grover's algorithm finds x* in O(√N) evaluations of f. For N = 1,000,000 items, classical search requires ~500,000 evaluations. Grover requires ~1,000.
Concrete example: Suppose f checks whether a candidate password matches a target hash (brute-force attack). With a 256-bit key space, N = 2²⁵⁶. Classically: 2²⁵⁵ evaluations expected. With Grover's: 2¹²⁸ evaluations. This is why AES-256 is recommended for quantum-resistant symmetric encryption — Grover halves the effective key length.
The Core Mechanism
Grover's algorithm works by amplitude amplification — a technique that increases the probability amplitude of the target state while decreasing the amplitudes of all other states.
Step 1: Initialize a uniform superposition
Start with all n qubits in |0⟩ and apply Hadamard to each:
|s⟩ = H⊗ⁿ|0⟩ⁿ = (1/√N) Σ|x⟩Every possible input has equal amplitude 1/√N. The target state x* has amplitude 1/√N — no better than random guessing.
Step 2: Oracle application
The oracle Oₓ flips the sign of the target state's amplitude:
Oₓ|x⟩ = -|x⟩ if x = x*
Oₓ|x⟩ = |x⟩ if x ≠ x*In matrix form, this is a phase kickback operation. The oracle does not reveal which state x* is — it just negates that state's amplitude.
After oracle application, x has amplitude -1/√N. All other states still have amplitude +1/√N. The total probability of measuring x is still 1/N — we have not improved the measurement odds yet.
Step 3: Diffusion operator (inversion about the mean)
The diffusion operator D = 2|s⟩⟨s| - I reflects all amplitudes about their mean value.
Mean amplitude before diffusion:
μ = (1/N)[(N-1)(1/√N) + (-1/√N)]
= (1/N)[(N-2)/√N]
≈ 1/√N (for large N)After inversion about the mean, the target state's amplitude increases from -1/√N to approximately 3/√N, while all other amplitudes decrease slightly.
Repeat oracle + diffusion ~π√N/4 times
Each iteration amplifies x's amplitude by approximately 2/√N. After π√N/4 iterations, x's amplitude is close to 1, giving a measurement probability close to 1.
This is the √N speedup: you need O(√N) repetitions, each requiring one oracle call.
The Circuit
For a 3-qubit example searching for x* = |101⟩ among 8 states:
q₀: ──H──[Oracle]──[Diffusion]──[Oracle]──[Diffusion]──M──
q₁: ──H──[Oracle]──[Diffusion]──[Oracle]──[Diffusion]──M──
q₂: ──H──[Oracle]──[Diffusion]──[Oracle]──[Diffusion]──M──
ancilla: ──X──H──[Oracle]──────────────────────────────────For 3 qubits, the optimal number of iterations is π√8/4 ≈ 2.2, so 2 iterations.
The Oracle Implementation
The oracle marks x* = |101⟩ by applying a phase of -1 to that state. The standard technique uses a multi-controlled Z gate on the target state:
from qiskit import QuantumCircuit
import numpy as np
def grover_oracle(qc, target, n_qubits):
"""
Apply oracle for target bitstring.
target: string like '101'
"""
# Flip qubits where target has '0'
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
# Multi-controlled Z (MCZ)
qc.h(n_qubits - 1)
qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
qc.h(n_qubits - 1)
# Unflip qubits where target has '0'
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
return qcThe Diffusion Operator
The diffusion operator 2|s⟩⟨s| - I can be implemented as H⊗ⁿ · (2|0⟩⟨0| - I) · H⊗ⁿ:
def diffusion_operator(qc, n_qubits):
"""
Grover diffusion operator (inversion about mean).
"""
# Apply H to all qubits
qc.h(range(n_qubits))
# Apply X to all qubits
qc.x(range(n_qubits))
# Multi-controlled Z
qc.h(n_qubits - 1)
qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
qc.h(n_qubits - 1)
# Uncompute X
qc.x(range(n_qubits))
# Uncompute H
qc.h(range(n_qubits))
return qcComplete Qiskit Implementation
from qiskit import QuantumCircuit, transpile
from qiskit.primitives import StatevectorSampler
import numpy as np
import matplotlib.pyplot as plt
def build_grover_circuit(n_qubits, target, n_iterations=None):
"""
Build complete Grover's search circuit.
Args:
n_qubits: Number of search qubits
target: Target bitstring to find (e.g., '101')
n_iterations: Number of Grover iterations (default: optimal)
"""
N = 2 ** n_qubits
if n_iterations is None:
n_iterations = int(np.round(np.pi / 4 * np.sqrt(N)))
qc = QuantumCircuit(n_qubits, n_qubits)
# Step 1: Initialize uniform superposition
qc.h(range(n_qubits))
qc.barrier()
# Step 2: Grover iterations
for _ in range(n_iterations):
# Oracle
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
qc.h(n_qubits - 1)
qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
qc.h(n_qubits - 1)
for i, bit in enumerate(reversed(target)):
if bit == '0':
qc.x(i)
qc.barrier()
# Diffusion
qc.h(range(n_qubits))
qc.x(range(n_qubits))
qc.h(n_qubits - 1)
qc.mcx(list(range(n_qubits - 1)), n_qubits - 1)
qc.h(n_qubits - 1)
qc.x(range(n_qubits))
qc.h(range(n_qubits))
qc.barrier()
# Measure
qc.measure(range(n_qubits), range(n_qubits))
return qc, n_iterations
# Example: Search for '101' in 3-qubit space (8 items)
n = 3
target = '101'
qc, n_iter = build_grover_circuit(n, target)
print(f"Searching for: |{target}⟩")
print(f"Search space size: N = {2**n}")
print(f"Grover iterations: {n_iter}")
print(f"Classical expected evaluations: {2**(n-1)}")
print()
print(qc.draw())
# Simulate
sampler = StatevectorSampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result[0].data.meas.get_counts()
# Sort and display
sorted_counts = dict(sorted(counts.items(), key=lambda x: x[1], reverse=True))
print("\nMeasurement results (top 5):")
for state, count in list(sorted_counts.items())[:5]:
print(f" |{state}⟩: {count} ({count/1024*100:.1f}%)")
print(f"\nTarget state |{target}⟩ probability: {counts.get(target, 0)/1024*100:.1f}%")Expected output:
Searching for: |101⟩
Search space size: N = 8
Grover iterations: 2
Classical expected evaluations: 4
Measurement results (top 5):
|101⟩: 971 (94.8%)
|000⟩: 7 (0.7%)
|011⟩: 7 (0.7%)
...
Target state |101⟩ probability: 94.8%The target state is found with ~95% probability using only 2 oracle calls, versus 4 expected classical evaluations for this 8-item search space.
Limitations and Practical Considerations
The oracle must be efficient: Grover's speedup assumes oracle evaluation is O(1). If the oracle itself requires O(N) classical computation, there is no net speedup.
The speedup is quadratic: Grover reduces O(N) to O(√N), not O(log N). For N = 10¹² items, classical needs 10¹² evaluations, Grover needs 10⁶. Significant, but not the exponential speedup of Shor's algorithm.
NISQ circuit depth: For large search spaces, the number of iterations grows as √N, each requiring multi-controlled gates that are expensive on NISQ hardware. Practical Grover circuits are limited to small search spaces on current hardware.
Multiple solutions: If there are k solutions, optimal iterations is ~π√(N/k)/4. You can estimate k by running a short Grover circuit and measuring the success probability.
Where Grover's Algorithm Actually Matters
Despite being "only" quadratic, Grover's speedup is significant in several real contexts:
Symmetric key cryptography: Grover halves effective key length. AES-128 drops to 64-bit security. This is why NIST recommends AES-256 for post-quantum security.
Hash function preimage resistance: Grover reduces SHA-256 preimage resistance to 128-bit security — still safe, but worth noting in security planning.
Constraint satisfaction: Grover can be composed with classical preprocessing to speed up certain NP problem searches — not solving NP in polynomial time, but providing a √N speedup over exhaustive search.
Amplitude estimation: Grover's core technique (amplitude amplification) underlies quantum amplitude estimation algorithms used in financial modeling (Monte Carlo acceleration) and quantum chemistry. These are arguably the more practically important near-term applications.
The Bell State template in the playground demonstrates entanglement. Load the Grover's template to see the complete 3-qubit circuit and simulate it in the browser.