Quantum Fourier Transform and Phase Estimation
The QFT is the quantum cousin of the classical discrete Fourier transform — but it runs in O(n²) instead of O(n·2ⁿ), which is where many quantum speedups ultimately come from. This tutorial derives the QFT circuit, explains Quantum Phase Estimation (the subroutine inside Shor, HHL, and VQE), and delivers complete Qiskit implementations.
Prerequisites: Tutorial 10: Grover and Amplitude Amplification
If you had to name the single most important quantum subroutine, it would be the Quantum Fourier Transform. It’s the engine under Shor’s algorithm (factoring), HHL (linear systems), quantum phase estimation (molecular simulation, VQE), quantum counting, and a dozen other algorithms. Classical DFT takes time on data points; QFT takes gates on a quantum state encoding those points — exponentially faster, with the caveat that you can’t read out all the Fourier coefficients (that’s where algorithms get creative).
Quantum Phase Estimation (QPE) uses the QFT as its final step to solve a specific problem: given a unitary and an eigenvector with eigenvalue , estimate . That sounds abstract; it’s actually the missing puzzle piece for Shor, for ground-state chemistry, and for half the “quantum advantage” demos.
The classical DFT, quickly
The discrete Fourier transform takes a sequence of complex numbers to another sequence via:
On points, the Fast Fourier Transform runs in time.
The Quantum Fourier Transform
The QFT is the same unitary, but applied to amplitudes of a quantum state rather than elements of a classical array. If the input state is , the QFT produces:
where the are the DFT of the . Equivalently, the action on a basis state is:
Deriving the circuit
Write as an -bit binary string and similarly. Substitute into the phase and expand. After some manipulation (see any intro QC textbook for full algebra) you get the product form:
where denotes a binary fraction. This expression tells you exactly how to build the circuit qubit-by-qubit.
The circuit recipe
For qubits, the QFT circuit is:
- For each qubit down to : a. Apply a Hadamard to qubit . b. For each qubit from down to , apply a controlled- gate with control qubit and target qubit , where is the phase gate .
- Reverse the qubit order (SWAPs), because the product form outputs qubits in reversed significance.
For this is:
q[2]: —H—R2—R3———————————SWAP(q[0], q[2])
| |
q[1]: ——————H—R2———
|
q[0]: ——————————H——
Total gates: controlled-phase gates + Hadamards + SWAPs = .
Concrete for :
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[3];
// Some input — say, |1⟩ in the low qubit
x q[0];
// QFT on 3 qubits (q[2] is most significant)
h q[2];
cu1(pi/2) q[1], q[2];
cu1(pi/4) q[0], q[2];
h q[1];
cu1(pi/2) q[0], q[1];
h q[0];
// Bit-reversal SWAP
cx q[0], q[2];
cx q[2], q[0];
cx q[0], q[2];
measure q -> c;
→ Try “QFT (3 qubits)” in the playground — already in the examples dropdown.
QFT in Qiskit
Qiskit ships a QFT circuit-library primitive. For learning purposes, roll your own at least once:
import numpy as np
from qiskit import QuantumCircuit
def qft_circuit(n: int, do_swaps: bool = True) -> QuantumCircuit:
qc = QuantumCircuit(n, name="QFT")
for q in reversed(range(n)):
qc.h(q)
for p in reversed(range(q)):
angle = np.pi / (2 ** (q - p))
qc.cp(angle, p, q)
if do_swaps:
for i in range(n // 2):
qc.swap(i, n - 1 - i)
return qc
# Compare to Qiskit's built-in
from qiskit.circuit.library import QFT
from qiskit.quantum_info import Operator
for n in [2, 3, 4, 5]:
ours = qft_circuit(n)
theirs = QFT(n, do_swaps=True)
print(f"n={n}: match = {np.allclose(Operator(ours).data, Operator(theirs).data)}")
# All True
Inverse QFT
The inverse QFT is the adjoint — reverse the circuit and negate every phase. Qiskit: QFT(n, inverse=True) or qc.inverse(). The IQFT is what actually appears as the final step of QPE, Shor, and most applications — QFT is typically used “in reverse” to convert a phase-encoded state back into a computational-basis readout.
Quantum Phase Estimation
Setup. You have:
- A unitary that acts on qubits.
- An eigenvector of with eigenvalue , where .
- The ability to apply as a controlled operation, for .
Goal. Output an -bit estimate of .
Circuit. Two registers:
- -qubit counting register, starting in .
- -qubit eigenstate register, holding .
Steps:
- Hadamard the counting register: each qubit in .
- For each counting qubit (from MSB to LSB), apply controlled- with the counting qubit as control and the eigenstate register as target.
- Apply inverse QFT to the counting register.
- Measure the counting register. The classical output, read as a fixed-point fraction, is an -bit estimate of .
Why it works (the quick derivation)
After the controlled powers of , using the identity and factoring out :
The state of the counting register is exactly the QFT of . Applying the inverse QFT recovers — or, if is not exactly an integer over , a peaked distribution around the closest such integer.
Precision and number of qubits
With counting qubits you get bits of precision in , i.e., resolution . Want 4-digit precision? Use at least counting qubits.
QPE in Qiskit: a minimal working example
Pick (the phase gate) with eigenvalue on eigenstate . We expect .
import numpy as np
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
def qpe_circuit(unitary: QuantumCircuit, eigenstate_prep: QuantumCircuit,
n_counting: int) -> QuantumCircuit:
"""QPE with a general controlled-unitary. `unitary` acts on `m` qubits."""
m = unitary.num_qubits
qc = QuantumCircuit(n_counting + m, n_counting)
# 1. Prepare eigenstate on register [n_counting ... n_counting+m)
eigen_qubits = list(range(n_counting, n_counting + m))
qc.compose(eigenstate_prep, eigen_qubits, inplace=True)
# 2. Hadamard the counting register
qc.h(range(n_counting))
# 3. Controlled powers of unitary
for k in range(n_counting):
power = 2 ** k
cU = unitary.power(power).control(1)
qc.compose(cU, [k] + eigen_qubits, inplace=True)
# 4. Inverse QFT on counting register (with swaps)
from qiskit.circuit.library import QFT
qc.compose(QFT(n_counting, inverse=True, do_swaps=True), range(n_counting), inplace=True)
# 5. Measure counting register
qc.measure(range(n_counting), range(n_counting))
return qc
# --- U = S gate, eigenvector |1⟩, eigenvalue e^(iπ/2) → φ = 0.25 ---
U = QuantumCircuit(1, name="S")
U.s(0)
prep = QuantumCircuit(1, name="prep")
prep.x(0) # set eigenstate register to |1⟩
n_counting = 4
qc = qpe_circuit(U, prep, n_counting)
counts = AerSimulator().run(qc, shots=4096).result().get_counts()
best = max(counts.items(), key=lambda kv: kv[1])[0]
phi_estimate = int(best, 2) / 2**n_counting
print(f"Most common measurement: {best} → φ ≈ {phi_estimate}")
# Most common measurement: 0100 → φ ≈ 0.25
The estimate is exactly 0.25 because happens to be representable in counting qubits. For phases that aren’t dyadic fractions, you see a peaked distribution — the closest representable fraction wins most shots, but there’s some leakage to neighbors.
QPE when isn’t dyadic
Try , eigenstate , so :
from qiskit.circuit.library import RZGate
U = QuantumCircuit(1, name="Rz(2π/7)")
U.p(2 * np.pi / 7, 0) # P gate = Rz up to global phase
prep = QuantumCircuit(1); prep.x(0)
n_counting = 6 # 2^6 = 64 bins; 1/7 ≈ 0.1428 falls between bins 9 (0.1406) and 10 (0.1562)
qc = qpe_circuit(U, prep, n_counting)
counts = AerSimulator().run(qc, shots=8192).result().get_counts()
top = sorted(counts.items(), key=lambda kv: -kv[1])[:5]
for bits, cnt in top:
phi = int(bits, 2) / 2 ** n_counting
print(f" {bits} → φ ≈ {phi:.4f} ({cnt/8192:.1%})")
# Top outcomes peak near 0.1406 and 0.1562, with ~40% mass between them combined
This peakiness is the basis of Kitaev’s phase estimation — with counting qubits, the probability of getting an estimate within of the true is at least , and grows rapidly with more qubits.
Why QPE is everywhere
Three big application areas:
-
Shor’s algorithm. is “multiply by mod ” on a register of qubits. The eigenvalues’ phases encode the multiplicative order of mod — and that’s what classical post-processing uses to factor . We build this next tutorial.
-
Quantum chemistry and materials (HHL-free VQE alternative). For a Hamiltonian , the unitary has eigenvalues whose phases encode energies. QPE gives you ground-state energy directly if you can prepare a good approximate eigenstate.
-
Quantum counting. Variant of QPE applied to Grover’s iteration operator ; the phase of encodes the number of marked items. Counts marked items without finding them.
Exercises
1. Hand-compute a 2-qubit QFT
Write out the matrix for QFT on qubits. Verify it maps .
Show answer
The first column is , so . Makes sense: the Fourier transform of an impulse is a uniform distribution.
2. QPE precision
Estimate (a non-terminating binary fraction) using QPE with 5 and 10 counting qubits. Compare how sharply the distribution peaks at the correct answer.
Hint
Use and eigenstate . With 5 qubits, bin width is ; with 10 qubits, . For each, plot the top-3 measurement outcomes and compare to .
3. QFT circuit gate count
For , exactly how many Hadamards and controlled-phase gates does the canonical QFT circuit use? What’s the depth?
Show answer
Hadamards = 10. controlled-phase gates. Depth (before bit-reversal SWAPs): layers. With SWAPs: . The approximate QFT (dropping phase gates with angle below some threshold) reduces the count meaningfully for large .
4. Build the eigenstate
For , the only eigenstate with eigenvalue is . What’s the eigenstate structure of ? What eigenvalue does give? Run QPE on with as eigenstate and confirm.
Show answer
has eigenstates with eigenvalue and with eigenvalue . QPE with should return (bits all zero). QPE with returns (MSB = 1, rest zero).
What you should take away
- QFT in gates vs classical . You can’t read all amplitudes, but you can use the Fourier-transformed state as the intermediate step of a larger algorithm.
- Circuit recipe: for each qubit, Hadamard + a cascade of controlled-phase gates from the higher-significance qubits, then bit-reversal SWAPs.
- Phase estimation: given and an eigenstate, recover the eigenvalue phase as a bit string. counting qubits give bits of precision.
- QPE is the workhorse inside Shor, HHL, VQE, and quantum counting. Mastering it is the gateway to the advanced-algorithm arc.
Next: Shor’s algorithm. Factoring large integers using QPE applied to modular exponentiation. The algorithm that gave post-quantum cryptography its reason to exist.