Week 4 | every classical function fits inside a quantum computer, if you clean up after yourself | reading: Watrous §3.1 and Ch. 6
Lectures 3 to 6 built the vocabulary: states, gates, entanglement, measurement. This lecture turns the vocabulary into a model of computation. By the end you should be able to measure the size and depth of a circuit, explain why classical logic has to be made reversible before a quantum computer can run it, write down the standard oracle \(U_f\) for any function \(f\), explain why leftover "garbage" qubits wreck quantum algorithms and how Bennett's trick removes them, and say precisely what it means for a gate set to be universal and why the \(T\) gate is the expensive one.
We have been drawing circuits since Lecture 4. Here is the official version.
A quantum circuit on \(n\) qubits is a finite sequence of gates, each a unitary acting on one, two or a few named qubits, possibly followed by measurements. Its width is \(n\). Its size is the number of gates. Its depth is the smallest number of layers into which the gates can be grouped, where the gates in a layer act on disjoint qubits (so they can run at the same time) and the layers are applied in order.
A four-qubit circuit applies, in this order, h(0), cx(0, 1), cx(1, 2), cx(2, 3), h(0). What are its size and depth?
cx(1, 2), so the depth is 4.cx(1, 2), so the two run in the same layer. Qiskit's size() and depth() methods return 6 and 3.The circuit in the figure applies \(H\) to qubits 0, 1 and 2, then cx(0, 1), then cx(1, 2), then \(T\) on qubit 0. Find its size, depth, number of two-qubit gates, and number of \(T\) gates.
There are six gates, so the size is 6. The three \(H\) gates act on different qubits and form layer 1. cx(0, 1) needs qubits 0 and 1, which are free after layer 1, so it forms layer 2. cx(1, 2) must wait for cx(0, 1) to release qubit 1, so it goes in layer 3, and the \(T\) on qubit 0 also waits for cx(0, 1), so it goes in layer 3 as well. Depth 3. Two gates act on two qubits, and there is one \(T\) gate.
The order of the last two gates in the gate list does not matter: gates on disjoint qubits commute (Lecture 5), so the depth counts only the chains of gates that genuinely wait for each other.
Size is total work. Depth is running time, and on today's hardware it also sets how long qubits must survive before they decohere. The two-qubit gate count matters because two-qubit gates are the noisiest operations (Lecture 6). The \(T\)-count, the number of \(T\) and \(T^\dagger\) gates, is the currency of fault-tolerant machines (Section 5). A good compiler trades these against each other; no single number captures "cost".
Quantum algorithms constantly need classical subroutines: adding numbers, comparing strings, evaluating a cipher. Can a quantum computer run a classical circuit? Not directly. Every gate is unitary, hence invertible, but the AND gate is not: it sends three different inputs \(00,01,10\) to the same output 0, so the input cannot be recovered from the output. Information is destroyed.
There is also a physical reason to care. Landauer's principle says that erasing one bit of information in an environment at temperature \(\mathcal T\) dissipates at least \(k_B\mathcal T\ln2\) of energy as heat. Reversible computation erases nothing, so in principle it has no such floor. For us the point is simpler: unitaries cannot erase, so we must compute without erasing.
Tick every map on two bits \((a,b)\) that could be the action of a quantum gate on the four basis states \(|a,b\rangle\).
The standard fix keeps the inputs and writes the answer into a fresh bit.
The Toffoli (controlled-controlled-NOT) gate acts on three qubits, flipping the target exactly when both controls are 1. With controls \(a,b\) and target \(c\),
$$|a,\,b,\,c\rangle\;\longmapsto\;|a,\,b,\,c\oplus ab\rangle .$$In Qiskit it is ccx(c1, c2, t). With controls on qubits 0 and 1 and the target on qubit 2, it exchanges \(|011\rangle\) and \(|111\rangle\) (written \(|q_2q_1q_0\rangle\), basis vectors 3 and 7) and fixes the other six basis states.
The Toffoli gate is a permutation of the eight basis states, it is its own inverse, and with the target initialised to 0 it computes \(a\wedge b\) while keeping \(a\) and \(b\).
Applying it twice gives \(|a,b,c\oplus ab\oplus ab\rangle=|a,b,c\rangle\), so it is its own inverse; a map that has an inverse is a bijection, so it permutes the basis states, and its matrix is a permutation matrix, which is unitary. With \(c=0\) the target becomes \(0\oplus ab=ab=a\wedge b\).
Qubits 0 and 1 are both in \(|+\rangle\) and qubit 2 is in \(|0\rangle\). After ccx(0, 1, 2), qubit 2 is measured. What is the probability of outcome 1?
Build a reversible circuit that maps \(|a,b,0\rangle\) to \(|a,b,a\vee b\rangle\) using one Toffoli and \(X\) gates.
De Morgan's law says \(a\vee b=\neg(\neg a\wedge\neg b)\). So: apply \(X\) to \(a\) and \(b\) (now they hold \(\neg a,\neg b\)); apply the Toffoli, which writes \(\neg a\wedge\neg b\) into the target; apply \(X\) to the target, giving \(\neg(\neg a\wedge\neg b)=a\vee b\); finally apply \(X\) to \(a\) and \(b\) again to restore them. Checking all eight inputs \(|a,b,c\rangle\) confirms the circuit maps them to \(|a,b,c\oplus(a\vee b)\rangle\) (verify_L07.py does this). The last two \(X\) gates are a tiny first example of uncomputation: undoing work we no longer need, so the inputs come out as they went in.
AND, OR and NOT (a single \(X\)) are not quite enough to run every classical circuit: classical circuits also copy bits (FANOUT), and copying an unknown bit must also be done reversibly. HW4 asks you to build NOT and FANOUT from Toffoli gates with constant inputs, which shows that the Toffoli gate by itself is universal for reversible classical computation.
Everything in Unit 2 of the course, from Deutsch–Jozsa to Grover to Shor, accesses a function \(f\) through one standard gate.
For a function \(f:\{0,1\}^n\to\{0,1\}^m\), the standard oracle is the gate on \(n+m\) qubits defined on basis states by
$$U_f\,|x\rangle|y\rangle=|x\rangle\,|y\oplus f(x)\rangle ,$$where \(x\) is an \(n\)-bit input register, \(y\) an \(m\)-bit output register, and \(\oplus\) is bitwise XOR. Extended by linearity, it acts on superpositions of inputs.
For every function \(f\), however irreversible, \(U_f\) is a permutation matrix and \(U_f^2=I\). In particular \(U_f\) is unitary.
Applying \(U_f\) twice gives \(|x\rangle|y\oplus f(x)\oplus f(x)\rangle=|x\rangle|y\rangle\), because \(z\oplus z=0\) bitwise. So \(U_f\) is its own inverse, hence a bijection of the \(2^{n+m}\) basis states, hence a permutation matrix. Permutation matrices have orthonormal columns, so they are unitary.
Let \(f(x_1x_0)=x_1\vee x_0\) (OR) with a one-bit output. The standard oracle sends \(|x\rangle|y\rangle=|10\rangle|1\rangle\) to \(|10\rangle\) followed by .
Several gates we already know are standard oracles. CNOT cx(0, 1) is \(U_f\) for the one-bit identity \(f(x)=x\); \(X\) on the output qubit is \(U_f\) for the constant \(f(x)=1\); and the Toffoli is \(U_f\) for \(f(a,b)=a\wedge b\). Notice that \(U_f\) is reversible even though \(f\) need not be: the trick is that it keeps \(x\).
The output register can also be prepared in \(|-\rangle\) instead of a basis state. Then the oracle changes nothing but a sign, which is exactly phase kickback from Lecture 6.
For \(f:\{0,1\}^n\to\{0,1\}\) and every input \(x\),
$$U_f\,|x\rangle|-\rangle=(-1)^{f(x)}\,|x\rangle|-\rangle .$$So on a superposition, \(U_f\big(\sum_x\alpha_x|x\rangle\big)|-\rangle=\big(\sum_x(-1)^{f(x)}\alpha_x|x\rangle\big)|-\rangle\): the function value is written into the phases of the input register.
If \(f(x)=0\), \(U_f\) does nothing. If \(f(x)=1\), it applies \(X\) to the output qubit, and \(X|-\rangle=-|-\rangle\). Both cases are \((-1)^{f(x)}|x\rangle|-\rangle\). The superposition statement follows by linearity.
How big is \(U_f\) as a circuit? If \(f\) has a classical circuit, not much bigger.
If \(f\) is computed by a classical circuit with \(g\) gates (AND, OR, NOT, FANOUT), then there is a circuit of \(O(g)\) Toffoli, CNOT and \(X\) gates, using \(O(g)\) extra qubits initialised to \(|0\rangle\), that maps
$$|x\rangle\,|0\cdots0\rangle\;\longmapsto\;|x\rangle\,|f(x)\rangle\,|\mathrm{garbage}(x)\rangle ,$$where the garbage register holds the intermediate values of the classical computation.
Replace each classical gate by its reversible version writing into a fresh qubit that starts at 0: AND by a Toffoli, OR as in Example 7.2, NOT by a CNOT into a fresh 0 followed by \(X\) on that qubit, and FANOUT by a CNOT into a fresh 0 (on basis states a CNOT into \(|0\rangle\) copies a bit). Each classical wire becomes a qubit that holds its value at the end, so the intermediate wires are the garbage. Each replacement uses a constant number of gates, which gives the \(O(g)\) bound.
Theorem 7.4 computes \(f\), but it leaves garbage behind. For a classical computer that would be harmless. For a quantum algorithm it is fatal, because the garbage depends on \(x\), so it becomes entangled with the input register, and entanglement with anything that records \(x\) destroys interference between different values of \(x\). Here is the smallest example.
Take \(f(x)=x\) on one bit, with the input \(x\) on qubit 0 and the output on qubit 1 prepared in \(|-\rangle\). Apply \(H\) to \(x\), then the phase oracle (a CNOT), then \(H\) again, and measure \(x\). Compare with a sloppy oracle that also leaves a copy of \(x\) in a garbage qubit \(g\).
Clean oracle. After the first \(H\), \(x\) is in \(|+\rangle\). By Proposition 7.3 the oracle turns \(\tfrac{1}{\sqrt2}(|0\rangle+|1\rangle)\) into \(\tfrac{1}{\sqrt2}(|0\rangle-|1\rangle)=|-\rangle\), and the final \(H\) turns that into \(|1\rangle\). The measurement gives \(x=1\) with certainty: the two "paths" \(x=0\) and \(x=1\) interfered completely.
Sloppy oracle. Now the oracle also copies \(x\) into \(g\), which starts in \(|0\rangle\). Before the final \(H\) the input and garbage are in
$$\frac{1}{\sqrt2}\Big(|0\rangle_x|0\rangle_g-|1\rangle_x|1\rangle_g\Big),$$an entangled state (the output qubit stays \(|-\rangle\) and plays no further role). Apply \(H\) to \(x\):
$$\begin{aligned}&\frac12\Big((|0\rangle+|1\rangle)|0\rangle_g-(|0\rangle-|1\rangle)|1\rangle_g\Big)\\[4pt] &\quad=\frac12\Big(|0\rangle|0\rangle_g+|1\rangle|0\rangle_g-|0\rangle|1\rangle_g+|1\rangle|1\rangle_g\Big).\end{aligned}$$By Rule 6.2, \(P(x=0)=\big|\tfrac12\big|^2+\big|{-\tfrac12}\big|^2=\tfrac12\). The two terms that should have cancelled carry different garbage values, \(|0\rangle_g\) and \(|1\rangle_g\), so they are orthogonal and cannot cancel. The garbage holds "which-path" information, and a path that has been recorded cannot interfere.
Repair. Apply the copying CNOT a second time before the final \(H\). It returns \(g\) to \(|0\rangle\) for both values of \(x\), the garbage factors out, and the answer \(x=1\) is certain again.
A reversible circuit computes \(f(x)\) cleanly but leaves one extra qubit in the basis state \(|g(x)\rangle\). Tick every choice of \(g\) for which interference between different inputs \(x\) still works as if there were no extra qubit.
The repair generalises. Bennett's trick runs the computation, copies out the answer, and then runs the computation backwards.
Let \(C\) be a reversible circuit with \(C|x\rangle|0\rangle=|x\rangle|f(x),\mathrm{garbage}(x)\rangle\), and let \(\mathrm{COPY}\) be \(m\) CNOTs from the \(f(x)\) part of the work register into an \(m\)-qubit output register. Then \(C^{-1}\,\mathrm{COPY}\,C\) implements the clean oracle:
$$|x\rangle|0\rangle|y\rangle\;\longmapsto\;|x\rangle|0\rangle|y\oplus f(x)\rangle .$$It uses twice the gates of \(C\) plus \(m\) CNOTs, and the work qubits can be reused afterwards.
Follow a basis state. \(C\) produces \(|x\rangle|f(x),\mathrm{garbage}(x)\rangle|y\rangle\). The copy step changes only the output register, to \(|y\oplus f(x)\rangle\), and leaves the other two registers exactly as \(C\) produced them. So \(C^{-1}\), which acts only on the first two registers, sees exactly the state that \(C\) created and undoes it, returning \(|x\rangle|0\rangle\). The output register is untouched by \(C^{-1}\). By linearity the same holds for every superposition of inputs, with no garbage entangled with \(x\).
A reversible circuit \(C\) of 40 gates computes a 3-bit value \(f(x)\) plus garbage. How many gates does the clean oracle \(C^{-1}\,\mathrm{COPY}\,C\) of Theorem 7.5 use?
Build the oracle \(|a\rangle|b\rangle|y\rangle\mapsto|a\rangle|b\rangle|y\oplus[a=b]\rangle\) for single bits \(a\) (qubit 0), \(b\) (qubit 1) and output \(y\) (qubit 2), where \([a=b]\) is 1 if \(a=b\) and 0 otherwise. Use no extra work qubits.
Compute in place. cx(0, 1) replaces \(b\) by \(a\oplus b\), which is 0 exactly when \(a=b\); then x(1) makes qubit 1 hold \(\neg(a\oplus b)=[a=b]\). Qubit 1 has served as its own work register, and \(b\) itself is temporarily lost: that is the garbage.
Copy. cx(1, 2) XORs \([a=b]\) into \(y\).
Uncompute. Undo the first two gates in reverse order: x(1), then cx(0, 1). Qubit 1 returns to \(b\). Five gates in all, and the truth table in Section 7 confirms every row. Without the last two gates, qubit 1 would be left holding \([a=b]\) instead of \(b\), and any later interference between inputs that differ in \(b\) would suffer exactly as in Example 7.3.
Real hardware offers a small menu of native gates, and every circuit must be compiled into it. When is a menu big enough?
A finite set \(\mathcal G\) of gates is universal if for every \(n\), every unitary \(U\) on \(n\) qubits and every \(\varepsilon>0\), some circuit built from gates in \(\mathcal G\) (acting on any of the qubits) implements a unitary within distance \(\varepsilon\) of \(U\), up to a global phase.
"Within \(\varepsilon\)" is unavoidable. A finite gate set generates only countably many circuits, while there are uncountably many unitaries, so exact universality with finitely many gates is impossible. For single-qubit gates we measure distance up to phase by \(d(U,V)=\sqrt{1-|\mathrm{tr}(U^\dagger V)|/2}\), which is 0 exactly when \(V=e^{i\theta}U\).
How far is the \(T\) gate from doing nothing? Compute \(d(I,T)\) to three decimal places.
Which of these circuits, started from \(|0\cdots0\rangle\) and measured in the standard basis, is guaranteed to be efficiently simulable on a classical computer?
The approximation in Fact 2 can be watched directly. The figure searches every product of \(H\) and \(T\) gates up to a given length for the best approximation of the phase gate \(P(\pi/8)=\mathrm{diag}(1,e^{i\pi/8})\), the "square root of \(T\)" that the quantum Fourier transform needs (Lecture 13).
Fault-tolerant quantum computers (Lecture 23) can perform Clifford gates on encoded qubits relatively cheaply, but by Gottesman–Knill those alone are classically simulable. The \(T\) gate is the missing ingredient, and on error-corrected hardware it is typically made by a costly procedure called magic-state distillation. That is why resource estimates for Shor's algorithm (Lecture 17) are quoted in \(T\) gates or Toffoli gates, and why compilers work hard to minimise the \(T\)-count.
Hardware does not offer a three-qubit Toffoli gate, so the compiler must decompose it. Qiskit's transpile does this for any target gate set. Here are the results for a single ccx(0, 1, 2), recorded from a run of the code in Section 7 with qiskit 2.5 (optimisation level 1).
| target gate set | gate counts | size | depth |
|---|---|---|---|
IBM-style: cx, rz, sx, x | 10 rz, 6 cx, 2 sx | 18 | 13 |
Clifford + T: h, t, tdg, cx | 4 t, 3 tdg, 6 cx, 2 h | 15 | 11 |
The Clifford + T version is the textbook ancilla-free decomposition: six CNOTs and a \(T\)-count of 7. (With an extra qubit and a measurement, cleverer constructions reduce the \(T\)-count to 4.) One Toffoli costs as much as fifteen elementary gates, and a classical circuit with \(g\) AND gates, made reversible by Theorem 7.4 and cleaned by Theorem 7.5, needs about \(2g\) Toffolis, so about \(14g\) \(T\) gates. Arithmetic is expensive on a quantum computer.
A circuit contains 3 Toffoli gates, 2 \(T\) gates, 1 \(T^\dagger\) gate and some Clifford gates. What is its \(T\)-count after each Toffoli is replaced by the ancilla-free Clifford + T decomposition above?
A block cipher such as AES is a classical circuit that maps a key \(k\) and a known plaintext \(m\) to a ciphertext \(E_k(m)\). By Theorems 7.4 and 7.5 it becomes a clean quantum oracle, and so does the test "does key \(k\) encrypt \(m\) to the ciphertext we intercepted?". Grover's algorithm (Lectures 11–12) searches over keys with such an oracle. Every call runs the whole cipher reversibly, twice. The first detailed resource estimate (Grassl, Langenberg, Roetteler and Steinwandt, 2016) built exactly such reversible AES circuits. Their oracle runs AES on \(r=3\) known plaintext–ciphertext pairs at once (one pair does not pin down a 128-bit key uniquely), and Grover needs about \(\tfrac\pi4\cdot2^{64}\approx1.4\times10^{19}\) oracle calls. Their totals for the whole attack:
| key size | logical qubits | \(T\) gates | \(T\)-depth |
|---|---|---|---|
| AES-128 | 2,953 | \(1.19\cdot2^{86}\) | \(1.06\cdot2^{80}\) |
| AES-192 | 4,449 | \(1.81\cdot2^{118}\) | \(1.21\cdot2^{112}\) |
| AES-256 | 6,681 | \(1.41\cdot2^{151}\) | \(1.44\cdot2^{144}\) |
The qubit counts are modest; the depth is not. A \(T\)-depth of \(1.06\cdot2^{80}\) sequential layers would take about 40 million years even at a billion layers per second (and today's error-corrected \(T\) gates are far slower than that), and Grover's iterations cannot be split across many machines without losing most of the quadratic speedup. Later papers have trimmed these numbers considerably, but not enough to change the picture: this is why Grover is a much weaker threat to symmetric cryptography than Shor is to RSA (Lecture 12, Lab 3), and why the standard advice is simply to prefer 256-bit keys.
from qiskit import QuantumCircuit, transpile
tof = QuantumCircuit(3)
tof.ccx(0, 1, 2) # controls q0, q1; target q2
for basis in (["cx", "rz", "sx", "x"], ["h", "t", "tdg", "cx"]):
t = transpile(tof, basis_gates=basis, optimization_level=1, seed_transpiler=1)
print(basis, dict(t.count_ops()), "depth", t.depth())
['cx', 'rz', 'sx', 'x'] {'rz': 10, 'cx': 6, 'sx': 2} depth 13
['h', 't', 'tdg', 'cx'] {'cx': 6, 't': 4, 'tdg': 3, 'h': 2} depth 11
Different Qiskit versions, optimisation levels or target devices can give different counts, so record your own rather than trusting a table. Real IBM devices currently use cz or ecr as their two-qubit gate; backend.target lists what a device supports.
from qiskit import QuantumCircuit from qiskit.quantum_info import Statevector eq = QuantumCircuit(3) # a = q0, b = q1, output y = q2 eq.cx(0, 1); eq.x(1) # compute: b <- NOT(a xor b) = [a == b] eq.cx(1, 2) # copy the answer into y eq.x(1); eq.cx(0, 1) # uncompute: restore b for i in range(8): label = format(i, "03b") # the basis state |y b a> p = Statevector.from_label(label).evolve(eq).probabilities_dict() print(label, "->", max(p, key=p.get), end=" " if i % 4 < 3 else "\n")
000 -> 100 001 -> 001 010 -> 010 011 -> 111 100 -> 000 101 -> 101 110 -> 110 111 -> 011
Labels are \(|y\,b\,a\rangle\). Exactly the inputs with \(a=b\) (\(000,011,100,111\)) have their \(y\) bit flipped, and \(a,b\) always come out unchanged.
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
def run(garbage, uncompute):
qc = QuantumCircuit(3) # x = q0, target = q1, garbage = q2
qc.x(1); qc.h(1) # target in |->
qc.h(0) # x in |+>
if garbage: qc.cx(0, 2) # a sloppy oracle also copies x into q2
qc.cx(0, 1) # the phase oracle for f(x) = x
if garbage and uncompute: qc.cx(0, 2) # clean up the garbage
qc.h(0)
p = Statevector.from_instruction(qc).probabilities([0])
return p.round(4)
print("clean oracle P(x=0), P(x=1):", run(False, False))
print("garbage left P(x=0), P(x=1):", run(True, False))
print("garbage uncomputed P(x=0), P(x=1):", run(True, True))
clean oracle P(x=0), P(x=1): [0. 1.] garbage left P(x=0), P(x=1): [0.5 0.5] garbage uncomputed P(x=0), P(x=1): [0. 1.]
Next time: what quantum information cannot do (no-cloning), and what entanglement can do: teleportation and superdense coding. Lab 2 launches. HW4 is due at the start of Week 5.
h(0), h(1), cx(0, 2), cx(1, 3), cx(2, 3), x(0), and list its layers.cx(0, 2) followed by cx(1, 2). Why is no Toffoli needed?h(0), h(1). Layer 2: cx(0, 2), cx(1, 3) (disjoint qubits). Layer 3: cx(2, 3), which needs qubits 2 and 3, and x(0), which waits for cx(0, 2). Depth 3, three two-qubit gates, \(T\)-count 0.x(0), cx(0, 1), x(0) (flip the control, CNOT, flip it back). Two gates: cx(0, 1) then x(1), since \(y\oplus x\oplus1\) is the CNOT followed by a NOT on the output.all numbers and figures in these notes are computed in python (verify_L07.py, ht_search.py) and follow the page theme