Tutorial 3: Grover's Search Algorithm
Grover's algorithm searches an unsorted database of elements in query steps, providing a provable quadratic speedup over the best possible classical algorithm ( queries).
In this tutorial, you will construct, execute, and verify a 3-qubit Grover search circuit targeting the specific marked element ( in decimal) using OpenQASM 3.0 and the Quantum Virtual Machine (QVM).
🎯 Learning Objectives
- Understand the geometry of Grover's algorithm: state space rotation via reflections.
- Implement a phase oracle that selectively flips the phase of .
- Construct the Grover diffusion operator (inversion about the average).
- Calculate the optimal iteration count .
- Validate QVM's simulated amplitudes against exact analytical formulas.
🔬 Mathematical Theory
1. Geometric Intuition
The search space of items is initialized into an equal superposition:
Let be the marked target state, and be the superposition of all non-target states. In the 2D plane spanned by , the initial state makes an angle with where:
2. The Phase Oracle ()
The oracle evaluates the boolean predicate and flips the sign of the target item:
For the target (where ):
- Qubit 1 is flipped with an gate so all controls become when the state is .
- A controlled phase flip is enacted using a Toffoli gate () flanked by Hadamards on the target.
- Qubit 1 is flipped back with an gate.
// Oracle for |101>
x q[1];
h q[1];
ccx q[0], q[2], q[1];
h q[1];
x q[1];3. The Diffusion Operator ()
The diffusion operator inverts probability amplitudes about their mean:
In circuit form for 3 qubits:
- Apply on all qubits.
- Apply on all qubits.
- Apply a multi-controlled- (realized as on , , followed by on ).
- Apply on all qubits.
- Apply on all qubits.
// Diffusion Operator
h q[0]; h q[1]; h q[2];
x q[0]; x q[1]; x q[2];
h q[2];
ccx q[0], q[1], q[2];
h q[2];
x q[0]; x q[1]; x q[2];
h q[0]; h q[1]; h q[2];4. Optimal Iteration Count
For :
After iterations, the probability of measuring the target reaches:
💻 Verified Python Implementation
import math
import numpy as np
from qvm.qasm3_parser import OpenQASM3Parser
from qvm.simulator import Simulator
ORACLE = "x q[1]; h q[1]; ccx q[0], q[2], q[1]; h q[1]; x q[1];"
DIFFUSER = (
"h q[0]; h q[1]; h q[2];"
"x q[0]; x q[1]; x q[2];"
"h q[2]; ccx q[0], q[1], q[2]; h q[2];"
"x q[0]; x q[1]; x q[2];"
"h q[0]; h q[1]; h q[2];"
)
N_ITER = int(math.floor(math.pi / 4 * math.sqrt(8))) # 2 iterations
# Construct the complete OpenQASM 3.0 program
qasm_source = f"""OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
// Equal superposition
h q[0];
h q[1];
h q[2];
// Grover Iterations
{(ORACLE + DIFFUSER) * N_ITER}
"""
grover_circuit = OpenQASM3Parser().parse(qasm_source)
state, _ = Simulator().simulate(grover_circuit)
probs = np.abs(state) ** 2
print("Significant measurement probabilities (P > 0.02):")
for idx, p in enumerate(probs):
if p > 0.02:
print(f"|{format(idx, '03b')}>: {p:.4f} ({p*100:.1f}%)")
# Compare against exact analytical Grover formula
amps = np.full(8, 1.0 / math.sqrt(8))
for _ in range(N_ITER):
amps[5] *= -1 # Target index 5 is |101>
amps = 2 * np.mean(amps) - amps # Inversion about mean
expected_probs = np.abs(amps) ** 2
assert np.allclose(probs, expected_probs, atol=1e-7), "Simulation diverged from theory!"
print("\nSuccess: QVM simulation matches the analytical Grover amplification exactly!")Verified Execution Output
Significant measurement probabilities (P > 0.02):
|101>: 0.9453 (94.5%)
Success: QVM simulation matches the analytical Grover amplification exactly!🌐 Running via QVM CLI & REST API
Running via CLI
Save the generated QASM to grover.qasm:
qvm grover.qasm --shots 1000 --seed 123Running via REST API (POST /run)
curl -X POST "http://127.0.0.1:8000/run" \
-H "Content-Type: application/json" \
-d '{
"source_type": "qasm",
"qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nh q[0]; h q[1]; h q[2];\nx q[1]; h q[1]; ccx q[0], q[2], q[1]; h q[1]; x q[1];\nh q[0]; h q[1]; h q[2]; x q[0]; x q[1]; x q[2]; h q[2]; ccx q[0], q[1], q[2]; h q[2]; x q[0]; x q[1]; x q[2]; h q[0]; h q[1]; h q[2];\nx q[1]; h q[1]; ccx q[0], q[2], q[1]; h q[1]; x q[1];\nh q[0]; h q[1]; h q[2]; x q[0]; x q[1]; x q[2]; h q[2]; ccx q[0], q[1], q[2]; h q[2]; x q[0]; x q[1]; x q[2]; h q[0]; h q[1]; h q[2];",
"shots": 2000,
"seed": 42
}'In the response:
counts["101"]will be approximately1890out of2000(~).- The
histogram_plotwill clearly show one dominant bar at index5().
Next tutorial: Tutorial 4: Quantum Teleportation.