
Quantum Uncomputation: Clean Up Ancilla Qubits Without Losing the Answer
Compute a useful result, use it, then reverse the calculation to return scratch qubits to |0> without erasing the answer.
Why scratch qubits need cleanup
In ordinary code, a temporary variable can be overwritten or discarded. A coherent quantum circuit works differently: its unitary gates must be reversible, so an intermediate value cannot simply disappear. If a calculation leaves a record in an ancilla, that extra qubit may remain correlated with the data and get in the way of later operations.
A standard solution is the compute-use-uncompute pattern. Compute a value into a clean ancilla, use it to update the answer register, then run the inverse calculation to return the ancilla to |0>. The answer stays because it was written to a different register. Nothing was erased; only the temporary computation was reversed.
A two-control example
Let the input bits be a and b, let s be a scratch qubit initialized to |0>, and let t be the output. A Toffoli gate computes a AND b into s. A CNOT uses s to flip t, which performs t = t XOR (a AND b). Apply the same Toffoli again and s returns to |0>, since a and b were left unchanged.
For basis states, the whole sequence is |a,b,0,t> -> |a,b,0,t XOR (a AND b)>. The same reversible sequence also works on superpositions, preserving their relative amplitudes. Do not measure the scratch qubit between the compute and uncompute steps, because measurement can disturb that coherent state.
Run the circuit in Qiskit
This example sets both inputs to 1 so the output flips to 1. The scratch qubit is measured too, making the cleanup visible. Install qiskit and qiskit-aer if they are not already available in your Python environment.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit(4, 2)
# q0 and q1 are inputs, q2 is scratch, and q3 is the answer.
qc.x(0)
qc.x(1)
qc.ccx(0, 1, 2) # compute a AND b into the scratch qubit
qc.cx(2, 3) # use it to update the answer bit
qc.ccx(0, 1, 2) # uncompute and restore the scratch qubit
qc.measure(2, 0) # classical bit 0 records scratch
qc.measure(3, 1) # classical bit 1 records the answer
simulator = AerSimulator()
counts = simulator.run(qc, shots=1024).result().get_counts()
print(counts)
On an ideal simulator, the result is {'10': 1024}. Qiskit displays the highest-index classical bit on the left, so this string means answer = 1 in c1 and scratch = 0 in c0. A real device can produce other outcomes because gates and measurements are noisy.
The key limitation
Uncomputation is useful whenever a circuit needs a temporary result but not the temporary record. It relies on keeping the inputs needed by the inverse calculation intact. If later operations overwrite those inputs, or if the intermediate value is still needed, you cannot just apply the inverse and expect the same cleanup. The extra inverse gates also cost circuit depth, so on noisy hardware it is worth balancing a clean workspace against the added operations.