Quantum Fourier transform
Reference: the Quon constructs in this recipe are defined normatively — syntax, typing contract, constraints, and a minimal example — in the Language reference.
What we’re building and why
Section titled “What we’re building and why”The Quantum Fourier Transform (QFT) is the quantum analogue of the discrete Fourier transform: it maps a computational-basis state |x⟩ to a superposition whose phases encode the frequency content of x. It is a subroutine in Shor’s algorithm, quantum phase estimation, and many hidden-subgroup problems. Unlike the classical FFT which runs in O(n log n) for n bits, the QFT runs in O(n²) gates — but it produces a quantum state, not classical data.
The QFT has a beautiful recursive structure: QFT(n) consists of a
Hadamard on the first qubit, a sequence of controlled-R_z rotations with
geometrically decreasing angles (π/2, π/4, π/8, …), and then
QFT(n-1) on the remaining n-1 qubits, embedded into the high qubits
via on_high. A final bit-reversal permutation (swap_reverse) restores
conventional output ordering. This recursion is the reason QFT is Quon’s headline
example for value-dependent types: the circuit type Circuit<n, n, ...>
depends on the Nat parameter n, and the recursion match n { 0 => identity(0), _ => ... qft(n-1) ... } is elaborated by partial evaluation.
The verification strategy is a round-trip test: apply qft(n) |> adjoint(qft(n))
and check that any computational-basis input is returned unchanged. A measurement
histogram cannot directly observe QFT’s output phases, so this is the documented
deviation from the original “matches theoretical DFT” acceptance criterion — the
round trip is the only checkable proxy. It verifies that the QFT and its adjoint
are exact inverses — which exercises the same recursive, on_high,
swap_reverse, and controlled-rotation machinery as qft alone. If the round
trip returns the input with probability 1.0, the recursive structure is correct.
In practice the optimizer proves this structurally: gate_cancellation and
rotation_merging, running to fixpoint, cancel the entire qft |> adjoint(qft)
sequence down to nothing.
Typed annotations
Section titled “Typed annotations”fn apply_hadamard(n: Nat): Circuit<n, n, 1, Clifford> = circuit { H @0 }
fn controlled_rotations(n: Nat): Circuit<n, n, 2 * (n - 1), Universal> = circuit { for i in range(n - 1) { controlled(Rz(PI / (2.0 ^ (i + 1)))) @(0, i + 1) }}
fn qft(n: Nat): Circuit<n, n, 2 * n * n, Universal> = match n { 0 => identity(0), _ => apply_hadamard(n) |> controlled_rotations(n) |> (qft(n - 1) `on_high` n) |> swap_reverse(n) }
fn qft_roundtrip(n: Nat): Circuit<n, n, 4 * n * n, Universal> = circuit { qft(n) |> adjoint(qft(n))}The types here are genuinely value-dependent — the depth bound contains
arithmetic expressions in n:
apply_hadamardisCircuit<n, n, 1, Clifford>— a singleHon qubit 0. Depth 1 regardless ofnbecause only one gate is applied.controlled_rotationsisCircuit<n, n, 2 * (n - 1), Universal>— the depth is 2(n-1) because theforloop runs n-1 times, each iteration applying one controlled rotation (depth 2: the control and target are on different qubits, but controlled rotations count as depth 2 in the typechecker’s convention). The class isUniversalbecauseRzis not Clifford — it is a general rotation.qftisCircuit<n, n, 2 * n * n, Universal>— the depth bound is 2n², which the typechecker proves by induction: the base caseqft(0)isidentity(0)with depth 0, and the recursive case sums the depths ofapply_hadamard(1),controlled_rotations(2(n-1)),qft(n-1) on_high n(embedded, so 2(n-1)²), andswap_reverse(a permutation, constant depth). The typechecker verifies that the sum fits within 2n².qft_roundtripisCircuit<n, n, 4 * n * n, Universal>— depth 4n², exactly twice the QFT depth, becauseadjoint(qft(n))has the same depth asqft(n)and they are composed sequentially.
The Universal class reflects the controlled rotations: Rz(θ) is not a Clifford
gate for general θ, so the QFT as a whole is classified as Universal. The
subtyping Clifford ⊑ Universal means the apply_hadamard subcircuit (which is
Clifford) composes into the Universal QFT without issue.
Source
Section titled “Source”The page embeds
test/verify/qft.qn.
Unlike the typechecker stress fixture
frontend/tests/fixtures/corpus/recursive_qft.qn,
this program uses geometrically decreasing controlled-rotation angles — the
fixture’s angle is genuinely PI / 2^(i+1) as a physical QFT requires, not the
PI/4 constant the typechecker-only stress test fixes purely to exercise the
value-dependent machinery.
The recursive QFT is built from three helpers. apply_hadamard puts a Hadamard
on qubit 0 — the “first” qubit of the register. controlled_rotations then
applies a sequence of controlled Rz rotations from qubit 0 to each higher
qubit, with the rotation angle decreasing geometrically: the i-th rotation has
angle π/2^(i+1). This is the defining structure of the QFT — the
geometrically decreasing angles produce the interference pattern that encodes
the frequency content. The qft function itself is recursive: the base case
qft(0) is the identity on zero qubits, and the recursive case composes the
Hadamard, the controlled rotations, a smaller qft(n-1) embedded into the high
qubits via on_high, and a swap_reverse permutation to fix the bit-reversed
output ordering.
fn apply_hadamard(n: Nat): Circuit<n, n, 1, Clifford> = circuit { H @0 }
fn controlled_rotations(n: Nat): Circuit<n, n, 2 * (n - 1), Universal> = circuit { for i in range(n - 1) { controlled(Rz(PI / (2.0 ^ (i + 1)))) @(0, i + 1) }}
fn qft(n: Nat): Circuit<n, n, 2 * n * n, Universal> = match n { 0 => identity(0), _ => apply_hadamard(n) |> controlled_rotations(n) |> (qft(n - 1) `on_high` n) |> swap_reverse(n) }The verification program prepares a specific computational-basis state and runs
the round trip through it. prep_101 applies X to qubits 0 and 2, preparing
the asymmetric basis state |101⟩ — a deliberately non-trivial input that
is a stronger check than |000⟩, which every unitary trivially fixes up to
global phase. The qft_roundtrip function composes qft(n) with its adjoint
adjoint(qft(n)), which the compiler synthesizes by reversing the gate order and
negating all rotation angles. If the implementation is correct, this round trip
is the identity and |101⟩ is returned unchanged with probability 1.0.
fn prep_101(): Circuit<3, 3, 2, Clifford> = circuit { X @0 |> X @2}
fn qft_roundtrip(n: Nat): Circuit<n, n, 4 * n * n, Universal> = circuit { qft(n) |> adjoint(qft(n))}
fn main(): Q<List<Bit>> = run { q <- prep_101() @ qreg(3) q2 <- qft_roundtrip(3) @ q measure_all(q2)}Compile and simulate
Section titled “Compile and simulate”./target/release/quonc test/verify/qft.qn --emit-qasm > /tmp/qft.qasmQUONC=target/release/quonc python test/verify/qft.py--dump-ir MLIR excerpts
Section titled “--dump-ir MLIR excerpts”The round trip qft(3) |> adjoint(qft(3)) is the optimizer’s playground. The
fixpoint pipeline runs gate_cancellation and rotation_merging iteratively:
// After elaboration, qft(3) produces (schematically):// H @0 |> CRz(pi/2) @(0,1) |> CRz(pi/4) @(0,2) |> [qft(2) on_high 3] |> swap_reverse(3)// where qft(2) = H @1 |> CRz(pi/2) @(1,2) |> [qft(1) on_high 2] |> swap_reverse(2)// and qft(1) = H @2//// adjoint(qft(3)) is the reverse-ordered conjugate:// adjoint(swap_reverse) |> adjoint(qft(2)) |> adjoint(CRz) |> adjoint(H)// where adjoint(CRz(θ)) = CRz(-θ) and adjoint(H) = H (self-adjoint)//// gate_cancellation: H @0 |> ... |> H @0 at the boundary —// the last gate of qft(3) and the first gate of adjoint(qft(3)) may NOT// be adjacent if swap_reverse sits between them. But after swap_reverse// is lowered to SWAP gates, the circuit becomes a flat sequence.//// After swap_reverse lowering and gate_cancellation to fixpoint:// H·H → I (self-inverse, adjacent, same wire)// CRz(θ) · CRz(-θ) → I (not adjacent self-inverse, but rotation_merging// sees: Rz(θ) followed by Rz(-θ) on the same wire → Rz(0) → I)//// The ENTIRE qft |> adjoint(qft) sequence cancels to identity.// rotation_merging combines each Rz(θ) with its adjoint Rz(-θ) → Rz(0),// and gate_cancellation erases the resulting identity rotations and// adjacent H·H pairs. Running to fixpoint, every gate cancels.This is the strongest demonstration of the optimizer: a non-trivial recursive
circuit composed with its adjoint is structurally proven to be the identity.
No simulation is needed — the optimizer cancels it purely from gate algebra.
The qft.py verifier confirms this: the round trip returns 101 with
probability 1.0, and the optimizer’s output is the empty circuit (or just the
state preparation and measurement with nothing in between).
What the compiler proves
Section titled “What the compiler proves”- Recursive type checking. The
match n { 0 => ..., _ => ... }recursion is type-checked with value-dependent types. The typechecker proves that for alln, the recursive case’s depth (1 + 2(n-1) + 2(n-1)^2 + swap) fits within 2n². This is inductive verification of a symbolic depth bound. on_highembedding is well-typed.qft(n-1)has typeCircuit<n-1, n-1, 2(n-1)^2, Universal>. Embedding iton_highinto a circuit on n qubits extends the type toCircuit<n, n, ...>. The typechecker proves the qubit indices are valid and the depth is preserved.adjointpreserves type.adjoint(qft(n))has the same type asqft(n)— same input/output arity and depth. The typechecker proves this from the adjoint’s definition (reverse gate order, negate rotation angles).- Structural cancellation to identity. The optimizer’s
gate_cancellationandrotation_mergingpasses, run to fixpoint, prove thatqft(n) |> adjoint(qft(n))is structurally equivalent to the identity. This is a compiler proof of the mathematical fact that a unitary composed with its adjoint is the identity — not by simulation, but by gate algebra.
Expected result
Section titled “Expected result”A computational-basis histogram cannot directly reveal the phases produced by
a QFT. The fixture therefore prepares |101>, applies
qft(3) |> adjoint(qft(3)), and checks that the round trip returns 101 with
more than 99% fidelity. The
qft.py
verifier also reports whether optimization structurally cancels the inverse
pair.
What to try next
Section titled “What to try next”- Remove
swap_reverse. The QFT’s output is in bit-reversed order without the permutation. The round trip withoutswap_reverseon both sides should still cancel, but the measurement may show a different basis state. - Change the input state. Try
prep_000(justidentity(3)) orprep_111(X @0 |> X @1 |> X @2). The round trip should still return the input. - Apply
qft(3)without the adjoint. The output will be a superposition — the histogram will show a spread over all basis states, demonstrating that the QFT actually transforms the state (and that the round-trip cancellation was not trivial).
→ Next: Transverse-field Ising — Trotterize a model and verify its
t = 0 boundary.