Compilation
The compiler takes a quantum circuit and a machine (the text of the Machine page), and writes the programme the machine runs: which ion holds each qubit, how ions are carried so that the two ions of every two-qubit gate stand in the same trap, and the laser operations, in order. Every example on this page can be played.
On this page
You have the hardware (Physics), the machine as a text (Machine), the language it is told what to do in (Language) and the rules it must keep (Rules). This page is the program that writes those programmes from an ordinary quantum circuit, and the checks that catch it when it is wrong. The first four sections are the story; the rest is the reference, for when you want to know exactly what a pass does.
- The problem (§1). A circuit names qubits and gates. The machine has ions in traps and three laser operations. Compiling is deciding which ion is which qubit, where ions must travel, and which pulses fire, so that the programme runs the circuit.
- The design (§2). Five ideas the compiler is built on, each answering one question; the first of them, untrusted heuristics, trusted checks, is the one to keep. Then the pipeline, nine steps.
- A worked example (§3). The smallest circuit that needs transport, a Bell pair, through every step, with the programme it became and its checks. Press Play on it.
- Every basic gate (§4). 14 gates compiled on four small machines, each with its programme, its ion map, its pulses and its verdicts.
- The algorithm (§5 onwards). What each pass computes, stated precisely, with a picture after every definition; and what is proved, what is only computed, and what the compiler cannot do.
A circuit says cx q[0],q[1]. On a trapped-ion machine the two qubits are two ions, possibly in different traps, and the only two-qubit operation needs both of them in one trap under one laser beam. What has to happen between reading that line and firing the beam?
Someone has to choose which ion plays which qubit and where each starts; carry the two together without breaking any rule of the machine; fire the right pulses; and, since all of that was decided by a heuristic, prove afterwards that it really happened and really computes a CNOT. That is the whole page, in one sentence.
1. The input, and the machine's three operations
The input is a circuit in OpenQASM 2.0, the standard text format for quantum circuits (its specification). A trapped-ion machine cannot apply most of its gates directly. This one has three operations, and every gate is rewritten into them:
| operation | acts on | what it does | as a matrix |
|---|---|---|---|
R(θ, φ) | one ion | One laser pulse. It rotates the qubit by the angle θ about an axis lying in the X–Y plane, at the angle φ from X: φ = 0 is a rotation about X, φ = π/2 about Y. Written Rx(θ) and Ry(θ) for those two. | cos(θ/2)·I − i sin(θ/2)·(cos φ·X + sin φ·Y) |
VZ(λ) | one ion | A rotation by the angle λ about Z, the one axis an R pulse cannot turn about. | diag(1, eiλ) |
MS(θ) | two ions in one trap | One laser pulse reaching both ions, which entangles the two qubits by the angle θ. It is the only way two qubits interact here, which is why the two ions of a two-qubit gate must first be carried into the same trap. | cos(θ/2)·I − i sin(θ/2)·X⊗X |
What a VZ costs. On a machine that can set the phase of the laser reaching each ion on its own, a rotation about Z is free: no laser fires, and the phase of that ion's later pulses is shifted instead. Here the beams are shared between ions, so the rotation has to be made with pulses: Rx(π/2)·Ry(λ)·Rx(−π/2), three R pulses (the rightmost first), equals VZ(λ) up to a global phase. The programme still writes it as one VZ, and the clock charges it the time of three pulses, unless the machine declares a gate that turns about Z in one pulse.
The two identities every gate is rewritten by. Each is proved, so the operations written for a gate are that gate (the rightmost factor happens first):
u3(θ, φ, λ) = VZ(φ + λ) · R(θ, π/2 − λ) CX = e−iπ/4 · [Ry(−π/2) ⊗ I] · [Rx(−π/2) ⊗ Rx(−π/2)] · MS(π/2) · [Ry(π/2) ⊗ I]
The first says any single-qubit gate is one pulse followed by one rotation about Z: u3 is OpenQASM's general single-qubit gate, and every named one is a u3 with fixed angles (h is u3(π/2, 0, π), t is u3(0, 0, π/4)). The second says a CNOT is one MS between four single-ion pulses. That the operations which actually fire are the ones for the gate you wrote is checked separately, by composing them back into the circuit (R10, below).
| what you write | which gates | what the machine does |
|---|---|---|
| single-qubit | 19 gatesid x y z h s sdg t tdg sx sxdg rx ry rz u1 p u2 u3 u | one R pulse, then one VZ |
| two-qubit | 7 gatescx cz cy ch swap cu1 cp | cx is one MS(π/2) between four R pulses; the others are cx with single-qubit gates around it |
| three-qubit | 1 gatesccx | the standard decomposition into six CNOTs and single-qubit gates |
| non-unitary | 3 gatesmeasure reset barrier | readout and preparation, in a trap equipped for them; a barrier only orders, and costs nothing |
The circuit this page walks through, as text and as the textbook draws it: a Hadamard, a CNOT, two measurements.
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q -> c;So every gate is a short recipe of R, VZ and MS pulses; that part is a table. The difficulty is not the pulses, it is geography: which ion is which qubit, and how do the pairs meet without breaking the rules? That is what the compiler is designed around.
2. How the compiler is designed
What should we trust?
Nothing the compiler says; everything the checks say. The two hard parts of compiling, choosing where ions start and finding their routes, are NP-hard problems (a quadratic assignment and a multi-agent path-finding problem), so the compiler solves them with heuristics that may be clumsy and may even be wrong. Its output is therefore checked by code that shares nothing with it: the rule checker for legality, a checker whose correctness is proved for “every gate happened where it was claimed”, and a computation for “the pulses make the right gate”. The insight: a bug in the compiler becomes a failed check on this page, never a wrong programme on a machine. The pipeline is untrusted heuristics followed by trusted decision procedures.
What does a programme cost?
Hops. Every hop heats the ion that makes it, a hot ion gates badly (R16) and may not gate at all until it is cooled (R7), and cooling takes time in which every other qubit decays. So the compiler places qubits that gate together close together, moves ions as little as it can, and cools only where a gate would otherwise be too hot.
What can run at the same time?
Independent gates, in lock-step. Gates on different qubits do not care about each other's order, so the circuit is cut into layers of independent gates, each gate of a layer gets its own trap, and the first pulse of every gate fires in one cycle, then the second of every gate, and so on. A layer of many gates then costs as much as one gate, and no trap is ever asked to do two things in a cycle (R12) by construction.
What does the hardware forbid?
Whatever the rule set says, and the router plans against exactly that. Capacity (R1), one ion through a junction at a time (R2), no head-on exchange (R5), and on a broadcast-wired machine one waveform per cycle (R22): the router's search space is the set of moves these rules allow, cycle by cycle. The last one matters most. It is why two ions heading in different directions cannot share a cycle, and much of why a ring beats a lattice on the leaderboard.
Whose order is it?
The circuit author's. The compiler never reorders a qubit's gates, not even two CNOTs that commute. Two gates that commute give the same unitary in either order, which is exactly why no semantic check could tell them apart; so the order is kept as written and checked as written.
The pipeline: nine steps
The five ideas, carried out in order. In short: read the circuit, rewrite every gate as the machine's operations, decide which ion plays which qubit, carry ions so that the pairs that must interact end up in the same trap, write out the instructions, add cooling where the ions would be too hot to gate — then check the result, twice. Steps 1–6 are the untrusted heuristics; steps 7 and 8 are the trusted checks.
- Read the circuitthe operations, and the order between themthe circuit becomes a list of operations, each with its qubits and its angles. Between them the compiler keeps the dependency graph: an arrow from each operation to the next one that uses the same qubit. An operation may run only after everything with a path of arrows to it; two operations with no path between them may run in either order, or at the same time.
- Rewritenative operations for each gateevery gate becomes the machine's operations by the two identities above: a single-qubit gate is one
Rand oneVZ, a CNOT oneMSbetween fourRpulses, and a gate on three qubits (a Toffoli) is first unfolded into one- and two-qubit gates. - Placewhich ion is which qubit, and where it startseach qubit is given an ion, and each ion a starting trap, so that qubits that gate together start close together (how, in §5.3).
- Route and schedulethe moves, in layersoperations run in layers of the dependency graph, and each qubit's operations keep the circuit's order exactly, even where two of them would commute. Before a two-qubit gate, its two ions are carried to one trap that can gate: one hop at a time on most machines, or, on a ring more than about half full, by turning the whole ring at once. This is this website's compiler. The papers on Reproduce use their own compilers, with their own ways of routing ions; there, each paper's schedules are replayed as its own code wrote them, and ours are set beside them under the same rules.
- Write outthe programme, and its certificatethe programme is one instruction per step, each marked with the operation of the circuit it carries out. Beside it the compiler writes a certificate: which ion is which qubit, where each ion starts, every move, and one witness per gate. A witness is the compiler's claim about one gate of the circuit: it happens at instruction k, in trap T, on ions a and b. The checks below test every claim instead of trusting it.
- Coolcooling where it is needed
- Check the rulesevery rule of the rule setthe cooled programme is replayed and every rule of the rule set is evaluated on it, exactly as on the Rules page: the standard rule set, unless the compiler was given another.
- Check what it computesR10, in two halvesO1, where every gate happens: the certificate's moves are replayed from the starting positions; every witness must name exactly the ions its gate's qubits are mapped to and find them together in a trap that can gate, every move must be one the machine allows, and every gate of the circuit must be witnessed once, in the circuit's order on each of its qubits. O1 is decided by a checker whose correctness is proved, and which reads the machine from its description, not from the compiler. O2, what the gates compute: the pulses are read out of the programme, composed through the qubit-to-ion map, and compared with the circuit as written, each measurement and reset in its place. A circuit of Clifford gates (H, S, CNOT and the Pauli gates, with measurement) is compared as a stabilizer tableau, whose size grows only with the square of the number of qubits, so circuits of any size are checked. Outside them (a T gate, an arbitrary angle) the exact matrices are compared, and those grow as 4n: up to 10 qubits, counting one more for each measurement in the middle of the circuit. Beyond that O2 is reported as not checked, never as passing. O2 is computed, not proved; it is the half that says which gates the programme applies.
- Drawthe pagethe page joins the programme and the circuit through the marks on the instructions, after checking each witness against the instruction it names; a disagreement refuses to draw.
Nine steps is a lot to hold in the head. Let us watch all of them on the smallest circuit that needs transport.
3. A worked example: the Bell pair, step by step
The ion mapping, verified
For the Bell pair, compiled here onto the four-site register, each qubit is given an ion and a starting trap. The CNOT needs both ions in one trap, and that happens in two steps: one ion is carried along the register until its trap sits right beside the other — the ion waiting there does not move — and then the two traps are merged into one. The waiting ion shifts by a couple of micrometres as the merge completes, against the hundreds it would move if it were the one being carried. The check recomputes every position from the starting positions and the list of moves, and checks that each gate's ions are where its witness says.
| qubit | ion | starts | ends |
| q0 | q0 | C1 | C0 |
| q1 | q1 | C0 | C0 |
moves recorded: q0 C1→C0
#0 init q0@C1, q1@C0
#1 cool all
#2 gate R q0 @C1 ← op 0 h
#3 gate VZ q0 @C1 ← op 0 h
#4 shuttle q0 C1→C0 ← op 1 cx
#5 gate R q0 @C0 ← op 1 cx
#11 cool all
#6 gate MS q0,q1 @C0 ← op 1 cx
#7 gate R q0 @C0 ← op 1 cx
#8 gate R q1 @C0 ← op 1 cx
#9 gate R q0 @C0 ← op 1 cx
#10 measure q0,q1 ← op 2 measure, 3 measureThe pulse sequence, matched to the gate
Each witness names the instruction that completes the gate, the trap, the ions and the operations, in the order they happen. Two checks meet here: the identities above say these operations are this gate, and O2 composes the operations the programme actually fires back into the circuit, so an operation that fires without a witness, or a witness without its operation, is caught.
op 0 (h) at C1, instruction #3: R(1.5708,-1.5708)@q0, VZ(3.14159)@q0op 1 (cx) at C0, instruction #9: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0Verdict for the Bell pair: 29 rules hold; R10 holds — O1 accepted by the proved checker; O2 by stabilizer tableau, composed from the emitted pulses, against the circuit as written.
The compiled Bell pair on the four-site register. Press Play: the page loads and plays the programme once; then step it, or scrub the slider. The names of the sites and ions are drawn on the picture. The full page shows the circuit stepping beside the programme.
One circuit is an anecdote. The next section puts every basic gate through the same nine steps, each on a different small machine, so that transport is seen on a line, a loop, a lattice and a dock.
4. Every basic gate, compiled and verified
One circuit per gate, each on one of four small machines named on its card, through the same steps: the input, the programme it became, the ion mapping, the operations witnessed, and the verdicts of the rules and of R10's two halves.
h q[0]; a half turn about the diagonal axis: one turn about z, then one pulse
machine: chain4, a four-site linear register C0–C3, every site a trap, no junctions
h q[0];| qubit | ion | starts | ends |
| q0 | q0 | C1 | C1 |
| q1 | q1 | C0 | C0 |
op 0 at C1: R(1.5708,-1.5708)@q0, VZ(3.14159)@q0#0 init q0@C1, q1@C0
#1 cool all
#2 gate R q0 @C1 ← op 0 h
#3 gate VZ q0 @C1 ← op 0 hx q[0]; a bit flip: 0 and 1 swap over. One pulse
machine: race8, an eight-site racetrack S0–S7: one loop of trap sites, no junctions
x q[0];| qubit | ion | starts | ends |
| q0 | q0 | S0 | S0 |
| q1 | q1 | S1 | S1 |
op 0 at S0: R(3.14159,-1.5708)@q0, VZ(3.14159)@q0#0 init q0@S0, q1@S1
#1 cool all
#2 gate R q0 @S0 ← op 0 x
#3 gate VZ q0 @S0 ← op 0 xy q[0]; a bit flip with a phase: one pulse, about a different axis
machine: grid2x3, a 2×3 lattice: T-junctions and corners, one trap on every wire
y q[0];| qubit | ion | starts | ends |
| q0 | q0 | T0_1h | T0_1h |
| q1 | q1 | T0_0h | T0_0h |
op 0 at T0_1h: R(3.14159,0)@q0, VZ(3.14159)@q0#0 init q0@T0_1h, q1@T0_0h
#1 cool all
#2 gate R q0 @T0_1h ← op 0 y
#3 gate VZ q0 @T0_1h ← op 0 yz q[0]; a phase flip: a half turn about z. Free on some machines, three pulses on this one
machine: ring6d, the six-site ring with two dock spurs
z q[0];| qubit | ion | starts | ends |
| q0 | q0 | A0 | A0 |
| q1 | q1 | A3 | A3 |
op 0 at A0: R(0,-1.5708)@q0, VZ(3.14159)@q0#0 init q0@A0, q1@A3
#1 cool all
#2 gate R q0 @A0 ← op 0 z
#3 gate VZ q0 @A0 ← op 0 zs q[0]; a quarter turn about z: three pulses here, for the same reason as z
machine: chain4, a four-site linear register C0–C3, every site a trap, no junctions
s q[0];| qubit | ion | starts | ends |
| q0 | q0 | C1 | C1 |
| q1 | q1 | C0 | C0 |
op 0 at C1: R(0,0)@q0, VZ(1.5708)@q0#0 init q0@C1, q1@C0
#1 cool all
#2 gate R q0 @C1 ← op 0 s
#3 gate VZ q0 @C1 ← op 0 st q[0]; an eighth of a turn about z. The check for this one compares the exact rotation, not a shortcut
machine: race8, an eight-site racetrack S0–S7: one loop of trap sites, no junctions
t q[0];| qubit | ion | starts | ends |
| q0 | q0 | S0 | S0 |
| q1 | q1 | S1 | S1 |
op 0 at S0: R(0,0.785398)@q0, VZ(0.785398)@q0#0 init q0@S0, q1@S1
#1 cool all
#2 gate R q0 @S0 ← op 0 t
#3 gate VZ q0 @S0 ← op 0 trx(0.5) q[0]; any angle at all, about x: one pulse
machine: grid2x3, a 2×3 lattice: T-junctions and corners, one trap on every wire
rx(0.5) q[0];| qubit | ion | starts | ends |
| q0 | q0 | T0_1h | T0_1h |
| q1 | q1 | T0_0h | T0_0h |
op 0 at T0_1h: R(0.5,0)@q0, VZ(0)@q0#0 init q0@T0_1h, q1@T0_0h
#1 cool all
#2 gate R q0 @T0_1h ← op 0 rx
#3 gate VZ q0 @T0_1h ← op 0 rxry(0.5) q[0]; any angle at all, about y: one pulse
machine: ring6d, the six-site ring with two dock spurs
ry(0.5) q[0];| qubit | ion | starts | ends |
| q0 | q0 | A0 | A0 |
| q1 | q1 | A3 | A3 |
op 0 at A0: R(0.5,1.5708)@q0, VZ(0)@q0#0 init q0@A0, q1@A3
#1 cool all
#2 gate R q0 @A0 ← op 0 ry
#3 gate VZ q0 @A0 ← op 0 ryrz(0.7854) q[0]; any angle about z, which this machine pays for in pulses
machine: chain4, a four-site linear register C0–C3, every site a trap, no junctions
rz(0.7854) q[0];| qubit | ion | starts | ends |
| q0 | q0 | C1 | C1 |
| q1 | q1 | C0 | C0 |
op 0 at C1: R(0,0.785396)@q0, VZ(0.7854)@q0#0 init q0@C1, q1@C0
#1 cool all
#2 gate R q0 @C1 ← op 0 rz
#3 gate VZ q0 @C1 ← op 0 rzcx q[0],q[1]; the entangler: carry one ion to the other, then one two-ion pulse with four single-ion pulses around it
machine: grid2x3, a 2×3 lattice: T-junctions and corners, one trap on every wire
cx q[0],q[1];| qubit | ion | starts | ends |
| q0 | q0 | T0_1h | T0_1h |
| q1 | q1 | T0_0v | T0_0v |
op 0 at T0_1h: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0#0 init q0@T0_1h, q1@T0_0v
#1 cool all
#2 shuttle q1 T0_0v→T0_1h ← op 0 cx
#3 gate R q0 @T0_1h ← op 0 cx
#9 cool all
#4 gate MS q0,q1 @T0_1h ← op 0 cx
#5 gate R q0 @T0_1h ← op 0 cx
#6 gate R q1 @T0_1h ← op 0 cx
#7 gate R q0 @T0_1h ← op 0 cx
#8 shuttle q1 T0_1h→T0_0v ← op 0 cxcz q[0],q[1]; a CNOT with two more pulses around it, on the same pair of ions
machine: race8, an eight-site racetrack S0–S7: one loop of trap sites, no junctions
cz q[0],q[1];| qubit | ion | starts | ends |
| q0 | q0 | S0 | S0 |
| q1 | q1 | S1 | S1 |
op 0 at S0: R(1.5708,-1.5708)@q1, VZ(3.14159)@q1, R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0, R(1.5708,-1.5708)@q1, VZ(3.14159)@q1#0 init q0@S0, q1@S1
#1 cool all
#2 shuttle q1 S1→S0 ← op 0 cz
#3 gate R q1 @S0 ← op 0 cz
#4 gate VZ q1 @S0 ← op 0 cz
#5 gate R q0 @S0 ← op 0 cz
#13 cool all
#6 gate MS q0,q1 @S0 ← op 0 cz
#7 gate R q0 @S0 ← op 0 cz
#8 gate R q1 @S0 ← op 0 cz
#9 gate R q0 @S0 ← op 0 cz
#10 gate R q1 @S0 ← op 0 cz
#11 gate VZ q1 @S0 ← op 0 cz
#12 shuttle q1 S0→S1 ← op 0 czswap q[0],q[1]; three CNOTs in a row, so three two-ion pulses at one trap
machine: ring6d, the six-site ring with two dock spurs
swap q[0],q[1];| qubit | ion | starts | ends |
| q0 | q0 | A0 | A0 |
| q1 | q1 | A3 | A3 |
op 0 at A0: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0, R(1.5708,1.5708)@q1, MS(1.5708)@q1,q0, R(-1.5708,0)@q1, R(-1.5708,0)@q0, R(-1.5708,1.5708)@q1, R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0#0 init q0@A0, q1@A3
#1 cool all
#2 shuttle q1 A3→S4 ← op 0 swap
#3 shuttle q1 S4→S5 ← op 0 swap
#4 shuttle q1 S5→A0 ← op 0 swap
#5 gate R q0 @A0 ← op 0 swap
#23 cool all
#6 gate MS q0,q1 @A0 ← op 0 swap
#7 gate R q0 @A0 ← op 0 swap
#8 gate R q1 @A0 ← op 0 swap
#9 gate R q0 @A0 ← op 0 swap
#10 gate R q1 @A0 ← op 0 swap
#24 cool all
#11 gate MS q1,q0 @A0 ← op 0 swap
#12 gate R q1 @A0 ← op 0 swap
#13 gate R q0 @A0 ← op 0 swap
#14 gate R q1 @A0 ← op 0 swap
#15 gate R q0 @A0 ← op 0 swap
#25 cool all
#16 gate MS q0,q1 @A0 ← op 0 swap
#17 gate R q0 @A0 ← op 0 swap
#18 gate R q1 @A0 ← op 0 swap
#19 gate R q0 @A0 ← op 0 swap
#20 shuttle q1 A0→S5 ← op 0 swap
#21 shuttle q1 S5→S4 ← op 0 swap
#22 shuttle q1 S4→A3 ← op 0 swapmeasure q[0] -> c[0]; reading the qubit out, in a trap that can do it: a laser asks the ion whether it is 0 or 1
machine: chain4, a four-site linear register C0–C3, every site a trap, no junctions
measure q[0] -> c[0];| qubit | ion | starts | ends |
| q0 | q0 | C1 | C1 |
| q1 | q1 | C0 | C0 |
#0 init q0@C1, q1@C0
#1 cool all
#2 measure q0 ← op 0 measurereset q[0]; putting the qubit back to 0, with a laser, in the same kind of trap
machine: race8, an eight-site racetrack S0–S7: one loop of trap sites, no junctions
reset q[0];| qubit | ion | starts | ends |
| q0 | q0 | S0 | S0 |
| q1 | q1 | S1 | S1 |
#0 init q0@S0, q1@S1
#1 cool all
#2 reset q0 ← op 0 resetUp to here everything was shown and nothing was defined. The rest of the page is the reference: what each pass computes, stated once and precisely, with a drawn example after every statement. Read it as far as your question takes you; the conclusion at the end stands on its own.
5. The algorithm, pass by pass
In this part
- Each of the nine pipeline steps of §2, as the problem it solves, the algorithm that solves it, and what is checked afterwards: the setting and the notation (5.1), lowering (5.2), placement (5.3), layering (5.4), where a gate happens (5.5), routing (5.6), the conveyor pass for rings (5.7), cooling (5.8), correctness (5.9), and what the compiler cannot do (5.10).
- Every formal statement is followed by a line in words and by a green Example drawn from a real compiled artefact, so no symbol is left without a picture.
- One notation, introduced once in 5.1 and shown on the three machines the examples run on; every symbol that appears later is in that table, and hovering a word anywhere on the page explains it.
- The four circuits of the examples can be played at the end (5.11).
The pipeline of §2 says what happens to a circuit, and the cards of §4 show the result for every basic gate. This part states the problem each pass solves, the algorithm that solves it, and the proposition the checker decides afterwards, for the compiler that produced every programme on this page and the leaderboard entries.
5.1 Setting and problem statement
Before any algorithm: what, exactly, is the compiler given, and what must it hand back?
It is given a machine (the text of the Machine page, of which it reads the trap graph: traps, junctions, rails, capacities, abilities, loops) and a circuit (gates on qubits, in order). It must hand back a programme the machine can run and a certificate that says where every gate happened. This section writes those four things down once, as symbols, and then shows every symbol on the three machines the examples use.
In words. The compiler reads the machine as a graph. Some nodes are traps (the set T), where ions can sit, up to a capacity, and in some of them be gated (the set gate) or measured (the set meas); the other nodes are junctions (J), where rails cross and no ion rests; the edges E are the rails. Some rails form named loops (L) that the control system can turn as a whole. Every part of this tuple is read off the machine text (the Machine page, section 6); the prices in that text are read only by cooling insertion (5.8), and nothing else about the hardware is ever read by the compiler.
| symbol | meaning | the register (chain4) | the lattice (grid2x3) | the ring (ring6d) |
|---|---|---|---|---|
| V = T ⊔ J | the nodes: traps and junctions together | 4 nodes | 13 nodes | 8 nodes |
| T | the traps, where ions rest | {C0, C1, C2, C3} | {T0_0h, T0_1h, T0_2h, T0_0v, T0_1v, T1_0v, T1_1v} | {S0, S1, S2, S3, S4, S5, A0, A3} |
| J | the junctions, where rails meet and no ion rests | ∅ | {J0_0, J0_1, J0_2, J1_0, J1_1, J1_2} | ∅ |
| E | the rails between nodes | 3 rails | 14 rails | 8 rails |
| cap(t) | how many ions trap t holds | 2 in every trap | 2 in every trap | 2 in every trap |
| gate | the traps in which a gate may happen | every trap | every trap | {A0, A3} |
| meas | the traps in which a measurement or reset may happen | every trap | every trap | {A0, A3} |
| L | the loops one instruction can turn as a whole | P0 = ⟨C0, C1, C2, C3⟩ | ∅ | L0 = ⟨S0, S1, S2, S3, S4, S5⟩ |
The notation of this part, read off the three machines the examples run on. Every later symbol is built from these: d(t, t′) counts hops between traps, π(a) is the trap qubit a starts in, post(i) is where ion i is at cycle t, and μ(a) is the ion that carries qubit a.
In words. A hop is what one machine cycle can do to an ion: carry it from a trap to a neighbouring trap, passing through junctions on the way without stopping, because an ion never rests on a junction (R2). The compiler plans on the graph of traps and hops, not on the raw rails. The distance between two traps is the fewest hops between them.
In words. Two operations must keep their order only if they touch a common qubit (or classical bit); otherwise they are independent. Drawing an arrow from each operation to the next one on each of its wires gives the dependency graph. The interaction graph forgets the order and only counts how many two-qubit gates each pair of qubits shares.
h q[0]; h q[2]; cx q[0],q[1]; cx q[2],q[3]; cx q[1],q[2]; measure q -> c;. Its dependency graph, laid out so that each column is one layer of §5.4: an arrow means "must come after". The two Hadamards depend on nothing; the third CNOT waits for both of the first two; each measurement waits for the last gate on its qubit.Its interaction graph is a path: three pairs, one CNOT each. Circuit 2 has the same interaction graph but a very different dependency graph, a single chain, because every CNOT shares a qubit with the next.
In words. Besides the programme, the compiler hands over a certificate: which ion plays which qubit, where each ion starts, every move it will make and when, and for every gate a claim of the form "this gate happened at this instruction, in this trap, on these ions". Replaying the moves from the start tells you where every ion is at every cycle, and each claim can be checked against that.
In words. Produce a programme the machine can run, a certificate that places every gate of the circuit once, in order, in a trap where its ions are together, and pulses that compute the right thing; and make it short. Hops are the cost that matters physically: each hop heats its ion, and a hot ion gates worse (R7, R16), so a programme that moves ions further is not only slower but less accurate.
Conditions (i)–(iii) are decided after the fact by checkers that share no code with the compiler (§5.9); the objective is pursued heuristically, because its two sub-problems are NP-hard: placement is a quadratic assignment problem and routing is multi-agent path finding under capacity constraints. The pipeline is therefore untrusted heuristics followed by a trusted decision procedure. At a glance:
| pass | problem | algorithm | cost | discharged by |
|---|---|---|---|---|
| §5.2 lowering | arity ≤ 2 | rewrite table | linear | §5.9 (iii), tableau route only |
| §5.3 placement | QAP on W, d | greedy + spectral, 2-swap descent | O(n²|W|) per sweep | none (objective only) |
| §5.4 layering | DAG scheduling | ASAP levels, round emission | linear | R12 by construction, §5.9 (ii) |
| §5.5 site selection | meeting trap | argmin over T | O(|T|) per gate | R6, R6b, R1 |
| §5.6 routing | MAPF with capacities and waveforms | prioritised space-time A* | O(|T|·H log) per ion | R1–R5, R8, R11, R22 |
| §5.7 conveyor | bipartite contacts on a loop | readiness batching, greedy sweep | linear in contacts | as §5.6, plus R4d |
| §5.8 cooling | R7 feasibility | replay and insert | one pass | R7, R7c |
5.2 Lowering
Every operation with |q(o)| ≥ 3 is replaced, before placement, by a sequence of one- and two-qubit operations from a composite table, and the DAG is rebuilt from the rewritten list. All later passes see the lowered circuit C′. The rewrite is checked wherever condition (iii) is checked, because (iii) compares the programme with the original C: by the stabilizer tableau for a Clifford circuit, and for a Toffoli, which is not Clifford, as exact matrices, the Toffoli at its own defining matrix. An incorrect table entry would therefore show as a mismatch.
Each of those is then rewritten into pulses (Theorem 1). The tool's own count for the whole Toffoli is 6 two-ion pulses, 33 single-ion pulses and 9 frame updates. Because the T gates are not Clifford, this circuit is checked against the exact 8×8 unitary; its card in §5.11 says so.
5.3 Placement
Where should each qubit's ion start?
Close to the ions it will gate with. Every hop later costs time and heat, so a good start saves both; a bad start cannot be repaired by routing. Choosing the start is an assignment problem that is NP-hard in general, so three cheap heuristics are tried and the best is kept.
In words. Give every qubit a starting trap so that qubits which will gate together start close together. The score of a layout adds up, over every pair of qubits, "how many gates they share" times "how many hops apart they start". Lower is better. Single-qubit gates do not count: where they happen is decided later, and on a machine where every trap gates they cost no transport at all.
Usable traps. Let T1 ⊇ T2 ⊇ … be the tiers {gate-capable, non-junction} ⊆ {non-junction} ⊆ {gate-capable} ⊆ T, each restricted to traps of positive capacity. Tu is the first tier whose total capacity ∑ cap(t) is at least n. The start limit is c(t) = 1 if |Tu| ≥ n, otherwise c(t) = cap(t). In words: prefer traps that can gate and are not junctions (a junction holds one ion, and an ion parked on one blocks every route through it for a whole layer); start one ion per trap when there are enough traps, and only pack two into a trap on a machine that is tight, which the compiler then reports.
seed a₀ ← argmaxa ∑b w(a,b); π(a₀) ← argmint ∈ Tu ecc(t) (the most central trap) repeat n − 1 times a ← argmaxa unplaced ∑b placed w(a,b) π(a) ← argmint free ∑b placed w(a,b) · d(t, π(b))A trap is free while it holds fewer than c(t) placed qubits. Ties: the seed is the lowest such qubit, the next qubit the highest-index one among equals, the trap the first in document order. Running time O(n · |Tu| · n).
In words. Start with the busiest qubit in the middle of the machine. Then, again and again, take the unplaced qubit with the most gates to qubits already placed, and put it in the free trap closest to its partners.
On the register the same rule goes wrong. After q1 is seeded at C1, q2 is placed before q0 (the tie rule prefers the higher index), and it takes C0, the first free trap next to C1. That leaves q0 the trap on the other side, C2, and then q3 has to go three hops from its partner q2. Score 5, exactly the score the compiler reports for its greedy layout. Greedy commits one qubit at a time and never reconsiders; the next two algorithms exist for this case.
In words. Instead of placing qubits one at a time, spread all of them along a line at once, so that qubits sharing many gates land next to each other (the Fiedler vector is the best such line, in the least-squares sense). Then walk the machine outward from its centre, and hand the traps out along that walk, in order.
π ← argmin { Φ(πgreedy), Φ(πspectral) }
for at most 40 sweeps, while some swap improved in the last sweep
for each pair a < b: if Φ(π ∘ (a b)) < Φ(π) then π ← π ∘ (a b)
return ⟨π, πgreedy, πspectral⟩ (a ranked list)
Φ is blind to routability, so the compiler tries the ranked candidates in turn and keeps the first that routes (§5.6).In words. Take whichever of the two layouts scores better, then keep swapping pairs of qubits whenever a swap lowers the score, until no swap does. Keep the other two layouts as spares: a layout can score well and still leave an ion somewhere the router cannot get past later.
the compiler on circuit 1seeded q1 (weight 2) at T0_1h
candidates: greedy 3, spectral 4 -> greedy
weighted interaction distance 3 over 3 distinct pairsthe compiler on circuit 2seeded q1 (weight 2) at C1
candidates: greedy 5, spectral 4 -> spectral
hill-climb 4 -> 3 in 2 rounds
weighted interaction distance 3 over 3 distinct pairs5.4 Layering and round emission
Which gates can happen at the same time, and how are they fired together?
Gates that do not depend on each other. The circuit is cut into layers of such gates, and within a layer the pulses are fired in rounds: first pulse of every gate, then second, and so on, each gate in its own trap.
In words. Every operation goes into the earliest layer it can: one layer after the latest operation it depends on. Layers run one after another; inside a layer, nothing depends on anything else, so everything in it may happen at the same time, as far as the hardware allows.
Within a layer, each gate g is decomposed into its pulse sequence pg,1, …, pg,ℓ(g) from the pulse table built on the identities of Theorem 1 (one beam and one frame update for a single-qubit gate; four beams around one two-ion pulse for a CNOT). Pulses are emitted in rounds: round k is the instruction set {pg,k : k ≤ ℓ(g)}, one instruction per pulse kind, all in one machine cycle.
In words. Gates in the same layer fire in lock-step: the first pulse of every gate together, then the second pulse of every gate, and so on. Because each gate is in its own trap, this never asks one trap to do two things in a cycle, so a layer of many gates takes as long as one gate.
The same happens in layer 0, where the two Hadamards share one beam instruction and one frame instruction (#2, #3), and in layer 2, where the two measurements share one readout instruction (#17), since measurements do not claim traps:
#2 gate R q0,q2 @T0_0v,T0_1v ← op 0 h, 1 h
#3 gate VZ q0,q2 @T0_0v,T0_1v ← op 0 h, 1 h
#5 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#6 gate MS q0,q1,q2,q3 @T0_0h,T0_1h ← op 2 cx, 3 cx
#7 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#8 gate R q1,q3 @T0_0h,T0_1h ← op 2 cx, 3 cx
#9 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#17 measure q0,q3 ← op 5 measure, 8 measureMeasurements and resets do not claim traps (R12 bounds gates), so a layer emits one readout instruction naming every ion it measures; a barrier orders and costs nothing. The scheme forgoes pipelining across layers: transport for the next layer starts only after the pulses of this one. §5.10 reports what that costs against an exact solver.
5.5 Site selection
Two ions must meet for a gate. In which trap?
In a trap that can gate, is not taken by another gate of this layer, has room for both, and is nearest to the pair counting both journeys. After the layer, an ion that is not needed next goes home, so the few gate-capable traps stay free.
Let pos be the current positions, K the traps already claimed in this layer, and occ(t) = |pos−1(t)| the number of ions in a trap.
In words. A two-qubit gate happens in the trap that can gate, is not already taken by another gate of this layer, has room for both ions once the ions already parked in it are counted, and is closest to the pair, counting both ions' journeys. Among equals, the first in the document wins.
cx q1,q2, at the start of layer 2. After layer 1, q0 and q1 both stand at T0_1h and q2, q3 at T0_0h; nobody went home, because every ion is used again in layer 2 (Definition 7). The two traps the operands stand in are nearest by distance but are full: two ions each, which is their capacity, and only one of the two is an operand, so they are struck out. Among the rest, the smallest total is two hops, reached by T0_0v and T1_0v; T0_0v comes first in the document. So the pair meets in the trap between them, one hop each.#10 shuttle q1 T0_1h→T0_0v ← op 4 cx
#11 shuttle q2 T0_0h→T0_0v ← op 4 cx
#12 gate R q1 @T0_0v ← op 4 cx
#13 gate MS q1,q2 @T0_0v ← op 4 cxIn words. When a layer is done, every ion that gated in it and is not needed by the very next layer is sent back to where it started. That keeps the few gate-capable traps of a machine free for the gates still to come, and the one-layer lookahead stops the rule from sending an ion home only to fetch it straight back.
cx q0,q1 at C2, q1 is wanted by cx q1,q2 and q0 by its measurement, so nobody moves back, and likewise at every layer. The whole circuit costs three hops, one per CNOT. Without the lookahead q1 would have gone back to C2 and set out again.The swap card above shows the other case: on the ring q1 rides 3 hops to the dock A0, the three CNOTs of the swap fire, and since nothing follows, q1 is returned along the same 3 hops to its starting trap.
5.6 Routing within a layer
Several ions must move at once through traps that other ions occupy. How are their paths found without breaking a rule at any cycle?
One ion at a time, in a priority order, each by a shortest-path search over (cycle, trap) that respects what earlier ions reserved and what every rule allows; then the orders are compared and the fewest cycles kept. The one-waveform rule R22 is what makes this harder than textbook routing.
In words. Some ions must get from where they are to the trap their gate was assigned; every other ion stands still and is in the way. Find each mover a route, one hop per cycle with waiting allowed, so that no rule is broken at any cycle, and finish as early as possible. This is multi-agent path finding, with the twist that ions share traps up to a capacity and that, on a broadcast-wired machine, everything moving in one cycle must move the same way.
The solver is prioritised planning with a space-time reservation table (cooperative A*): movers are planned one at a time in a priority order; each plan is found by A* over states (t, τ) with actions wait and hop, cost 1 per cycle and the admissible heuristic h(t) = d(t, goal); a finished plan reserves what it uses, and later movers plan around it. A hop h departing t at cycle τ is admissible iff all of the following hold, each of which is one rule of the Rules page:
occ(t′, τ+1) < cap(t′) R1 the destination has room
∀ j ∈ junc(h): transits(j, τ) < 1 R2 one transit per junction per cycle
∀ e ∈ via(h): load(e, τ) < cap(e) R3 segment capacity
(t′, t, τ) not reserved R5 no head-on exchange on a segment
one action per ion per cycle R8
act(h) = (ℓ, δ) ⇒ act(ℓ, τ) ∈ {⊥, δ} R4d, R11 one signed direction per loop per cycle
wave(τ) ∈ {⊥, sig(h)} (broadcast machines only) R22 one waveform per cycle
The waveform signature sig(h) is the movement class followed by one label per segment crossed: along a named loop the signed unit step on that loop; across a spur, inward or outward; otherwise the direction of the lab-frame displacement. It is computed by the same function the verifier uses for R22, so the two agree by construction. The first mover to reserve a cycle fixes its waveform; any other mover whose hop has a different signature waits. Arrival is not sufficient: an ion parks at its goal for the rest of the layer, so the goal must have room at every later cycle too.
Layer 2 is the instructive case. q1 and q2 both head for T0_0v, both one hop away, and the trap has room for both. But q1 turns left then down, and q2 turns left then up: two different waveforms. q1 is planned first and fixes the waveform of cycle 0, so q2 waits a cycle and hops in cycle 1. Every priority order gives two cycles here, so all four are tried and the first is kept, instructions #10 and #11. Nothing physical prevents the two hops sharing a cycle; the cost is R22, one waveform per cycle on a broadcast-wired machine.
#4 shuttle q0 T0_1v→T0_1h, q2 T0_0v→T0_0h ← op 2 cx, 3 cx
#10 shuttle q1 T0_1h→T0_0v ← op 4 cx
#11 shuttle q2 T0_0h→T0_0v ← op 4 cxLB ← maxi ∈ M d(pos(i), τ(i)); H ← 2·ecc(GT) + 8
for rung in ⟨(uniform, strict), (¬uniform, strict), (¬uniform, tolerant)⟩
for H′ in ⟨H, 2H⟩ (the third rung tries H only)
best ← ⊥
for order in ⟨farthest first, nearest first, program order, its reverse⟩
reserve every stationary ion at its trap for cycles 0..H′
for i in order: plan i by A*; if none, next order; reserve its walk and its parking
lay the hops out by departure cycle; if ¬uniform, split each cycle by signature
replay the emitted cycles against R1; if strict and a trap overflows, next order
if |cycles| < |best| then best ← cycles; if |best| ≤ LB then return best
if best ≠ ⊥ then return best
raise Unroutable
Rungs 1 and 2 guarantee R1 on what is emitted; rung 3 exists so that a layer no arrangement can make both uniform and legal still yields a programme, for the verifier to report.In words. Try four different orders of planning the movers and keep the plan with the fewest cycles, stopping early if a plan is provably as short as possible. If nothing routes within the search horizon, double it once. If the strict one-waveform search fails, relax it in two steps. Before anything is emitted, replay it and refuse a plan that would overfill a trap.
Failure is a result. When Algorithm 4 raises, or §5.5 leaves an operation unrealised, the compiler tries again with the next placement of Algorithm 3; when all three fail on a machine with a closed loop and docks, §5.7 is tried; otherwise the compiler declines with the reason. No branch emits a programme that violates a rule it knows about.
5.7 The conveyor pass
On a ring that is more than half full, ions cannot pass each other. How can gates happen at all?
By turning the whole ring, like a conveyor belt with workstations beside it. It works exactly when every gate pairs an ion riding the belt with one parked at a dock, which is the shape of a syndrome-extraction round.
In words. Think of the loop as a conveyor belt with a few workstations (the docks) beside it. Ions riding the belt keep their places on it; one instruction advances the whole belt by any number of slots, and it needs no empty slot to do so, because everything moves together.
In words. Two ions on the belt can never meet, so every gate must pair a rider with a docked ion. That works exactly when the qubits split into two groups with all gates running between the groups, one group small enough for the docks: the shape of a syndrome-extraction round, ancillas docked and data riding. It is also why the general router's limit, about half occupancy on a loop, does not apply here.
cx a,b; cx b,c; cx c,a, fails the first condition: whichever two ride the belt can never meet, and the pass says which.Layout. Docks are assigned to QD in order and riders spread at stride ⌊N/|QL|⌋, unless a layout is supplied from outside, as the code-aware leaderboard entries do; a supplied layout is validated (each dock exists, no slot or dock named twice, the partition respected) and otherwise treated as data.
Schedule. Operations are emitted by readiness: o is ready when every earlier o′ sharing a qubit with it is emitted, commuting or not. In words: every qubit sees its own operations in the circuit's order, and only operations on different qubits move relative to each other, which is what lets contacts of different ancillas share one batch. The order of a qubit's gates is the circuit author's to choose, so the compiler keeps it even where two CNOTs commute: one that shares only its control, or only its target, with another would give the same unitary in either order, which is exactly why no semantic check could tell, and why the order conjunct of §5.9 has no exemption for it.
while operations remain drain: emit every ready measurement, reset and single-qubit gate on a docked ion (no rotation needed) for each ready contact c = (rider i, dock Dc): θc ← rail(Dc) − σ(i) (mod N) θ* ← the θc with the largest batch (ties: nearest, either way) [monotone variant: nearest ahead] B ← a set of ready contacts at θ*, at most one per dock and one per rider emit rotate(θ* − θ, the shorter way); dock(B); the CNOT rounds of B together; undock(B)Invariant: the loop never turns while a dock is occupied. In the certificate a rotation is one event, and the checker's replay applies it to every ion on the loop and to no other.
In words. First do everything that needs no turn: measure, reset and single-qubit gates on docked ions. Then work out, for each gate that is ready, how far the belt would have to turn to bring its rider beside its dock, turn to the position where the most ready gates line up (the nearest, either way, when it is a tie), and do every ready gate there: pull the riders into their docks, fire, push them back out. The belt never turns while a rider is docked, since a docked ion is off the belt and would come back beside the wrong slot. Since every qubit's gates stay in the circuit's order, an ancilla has one gate ready at a time, and turning the shorter way to it costs fewer turns and fewer hops than always turning forward, which would lap the belt for each one; the forward-only rule is still there as an option.
cx q0,q2 with a turn of −2; that turn carries q3 from slot 4 to slot 2, so cx q0,q3 needs −2 more: two turns of two, four hops in all, three contacts, exactly as the compiler's note reads. Taking cx q0,q3 first is not an option: the order of q0's gates is the circuit's.| step | ready | turn | emitted |
|---|---|---|---|
| drain | h q0 (q0 is docked) | — | beam and frame update, #2–#3 |
| 1 | cx q0,q1 | none: q1 is already beside the dock | dock q1, five rounds, undock: #4–#10 |
| 2 | cx q0,q2 (needs −2) | −2 | rotate (#11), dock q2, rounds, undock: #12–#18 |
| 3 | cx q0,q3 (now needs −2) | −2 more | rotate (#19), dock q3, rounds, undock: #20–#26 |
| drain | h q0, measure q0 | — | #27–#29 |
#4 dock q1 S0→A0 ← op 1 cx
#6 gate MS q0,q1 @A0 ← op 1 cx
#10 undock q1 A0→S0 ← op 1 cx
#11 rotate_ccw rotate L0 by -2 ← op 2 cx
#12 dock q2 S0→A0 ← op 2 cx
#14 gate MS q0,q2 @A0 ← op 2 cx
#18 undock q2 A0→S0 ← op 2 cx
#19 rotate_ccw rotate L0 by -2 ← op 3 cx
#20 dock q3 S0→A0 ← op 3 cx
#22 gate MS q0,q3 @A0 ← op 3 cx
#26 undock q3 A0→S0 ← op 3 cx5.8 Cooling insertion
Every hop heated the ions. When is a cool inserted, and how do we know once is enough?
Just before any two-qubit gate whose ions would be over the budget, found by replaying the programme with the heating model; once is enough because a cool is global and heating only adds.
Let n̄i(t) be the motional quanta of ion i at cycle t under the heating model (each hop, split and merge adds a table value; a global cool sets every n̄i to zero). R7 requires, for every two-qubit gate g at cycle t, maxi ∈ g n̄i(t) ≤ budget. The pass replays P, inserts a global cool immediately before each violating gate, and replays once more.
In words. Moving an ion warms it up, and a warm ion makes a worse two-qubit gate. The pass walks through the programme with a thermometer, and wherever a two-qubit gate would fire too hot it inserts a cooling step just before it. Cooling is global, so one step cools every ion; that is why one walk is enough, and the pass checks the result by walking through again.
5.9 Correctness
The compiler is a pile of heuristics. Why believe its output?
Because its output is not believed: it is checked. Legality by the rule checker, “every gate happened where claimed” by a checker with a machine-checked proof, “the pulses compute the circuit” by a computation; and the gate rewrite rests on two proved identities.
The compiler is outside the trusted base. Conditions (i)–(iii) of the Problem are decided by three independent checkers, each reading only (A, C, P, κ). The checker for (ii) is proved correct (Theorem 2); the checkers for (i) and (iii) are executable and not proved (Checks 1 and 2). The gate rewrite rests on proved identities.
In words. Any single-qubit gate is one laser pulse plus a bookkeeping change of phase that costs nothing; a CNOT is one two-ion pulse with four single-ion pulses around it. Both facts are theorems, checked by a proof assistant, and the table is also tested numerically. The global phase is kept because it becomes visible once the gate is controlled, and a wrong phase convention is exactly the kind of error that hides until then.
In words. The same rule checker the studio runs on any hand-written programme is run on the compiled one, and it does not know or care how the programme was made. A router bug shows up as a failed rule on this page, not as a programme a machine would refuse.
- unrealised(κ) = ∅;
- μ is injective and total on Q;
- the events are sorted by cycle, so the replay is well defined;
- every rotation names a loop in loopsA;
- ∀ m ∈ moves: (m.src, m.dst) ∈ HA and posm.t(m.ion) = m.src;
- ∀ g ∈ gates: g.site ∈ gateA and ∀ i ∈ g.ions: posg.t(i) = g.site;
- ∀ g ∈ gates: the ions g names are, in some order, μ of the qubits of the operation it names;
- every operation of C′ other than measure, reset and barrier has exactly one witness;
- every witness names an operation of C′;
- for operations o before o′ sharing a qubit, the witness cycle of o precedes that of o′, whether or not the two commute.
In words. Nothing was left out; each qubit has its own ion; the moves can be replayed in order; every rotation is of a real loop; no ion ever teleports (every move is a real hop, starting from where the ion actually is); every claim names exactly the ions its operation's qubits live on, and finds them together in a trap that can gate; every gate of the circuit is claimed exactly once, and every claim names an operation of the circuit; and gates on a common qubit happen in the order written. A claim names an operation, never the gate applied there, so a claim on a barrier, a measurement or a reset passes too, and which gate fires is for Check 2 to decide.
In words. The checker is nothing but a decision procedure for Definition 9, and a machine-checked proof says that whenever it answers yes, the definition really holds. So the whole claim lives in the definition, which a reader can judge. The facts about the machine that the definition refers to (which traps gate, which pairs are one hop apart, how each loop is ordered) are read out of the document by code the compiler never runs, so the compiler cannot make the machine bigger by saying so; that is what makes the guarantee hold for any machine.
In words. Finally, does the programme compute the right thing? The checker reads the pulses back out of the programme and works out what they do to the qubits, then compares with what the circuit does. For Clifford circuits this is done with stabilizer tableaux, which scale; otherwise the full matrix is compared, up to ten qubits. A wrong angle, a dropped frame update, a swapped control and target, or one gate compiled as another all change the answer. It is the only check that sees which gate the pulses make.
Together: Check 1 gives (i), Theorem 2 gives (ii), Check 2 gives (iii), and Theorem 1 is why the compiler's pulse table can be right in the first place; that the pulses of P are the gates of C is what Check 2 establishes. The page's drawing is derived from the same certificate: the studio joins the programme to the circuit through the per-instruction stamps and refuses to draw if a witness disagrees with the stamp on the instruction it names.
5.10 Limitations and measured gaps
Optimality. Nothing above certifies minimality. The router's layer instances were re-solved exactly by a SAT encoding of the same problem on the same trap graph; the heuristic was optimal on every instance of the lattice and cyclone machines and lost on a racetrack, where a single priority order had cost 43 cycles against 5, which is the origin of the four orders in Algorithm 4. The placement relaxation of Algorithm 2 was predicted to dominate Algorithm 1 and did not; the 2-swap descent on Φ is what won, by up to 12 %.
Scope. Routing is planned within a layer; cross-layer pipelining is not attempted. R10 is reported partial for a non-Clifford circuit of more than ten qubits, where neither a tableau nor a dense unitary is available. Operations on three or more qubits are lowered, never executed as such. The general router runs out at about 46 % loop occupancy, and the conveyor pass covers only bipartite circuits. Whether the source circuit is the intended one (for a syndrome round, whether it measures the intended stabilizers) is outside R10 and is tested upstream. The physical model behind R7 and R16 is the subject of the Physics page.
Background.
- Quadratic assignment and its hardness: Sahni and Gonzalez, 1976. Spectral ordering by the second Laplacian eigenvector: Fiedler, 1973.
- Prioritised planning with space-time reservations (cooperative A*): Silver, 2005. Hardness of multi-agent path finding: Yu and LaValle, 2013.
- The Mølmer–Sørensen gate and the CNOT-from-MS identity in the trapped-ion literature; the identity is re-proved here under one fixed phase convention.
That is the whole algorithm. The four circuits every example above was drawn from are below, each playable, each through the same nine steps and the same checks as the basic gates of §4.
5.11 The four circuits, compiled and verified
The examples quoted above, through the same pipeline and the same checks as every gate: the input, the programme it became, the ion mapping, the pulses witnessed, and the verdicts. Press Play, or step the machine.
Circuit 1: two Bell pairs, then joined four layers: two Hadamards fire in one instruction, two CNOTs run side by side in two traps, then one CNOT joins the pairs
machine: grid2x3, a 2×3 lattice: T-junctions and corners, one trap on every wire
h q[0];
h q[2];
cx q[0],q[1];
cx q[2],q[3];
cx q[1],q[2];
measure q -> c;| qubit | ion | starts | ends |
| q0 | q0 | T0_1v | T0_1h |
| q1 | q1 | T0_1h | T0_0v |
| q2 | q2 | T0_0v | T0_0v |
| q3 | q3 | T0_0h | T0_0h |
op 0 at T0_1v: R(1.5708,-1.5708)@q0, VZ(3.14159)@q0op 1 at T0_0v: R(1.5708,-1.5708)@q2, VZ(3.14159)@q2op 2 at T0_1h: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0op 3 at T0_0h: R(1.5708,1.5708)@q2, MS(1.5708)@q2,q3, R(-1.5708,0)@q2, R(-1.5708,0)@q3, R(-1.5708,1.5708)@q2op 4 at T0_0v: R(1.5708,1.5708)@q1, MS(1.5708)@q1,q2, R(-1.5708,0)@q1, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q1#0 init q0@T0_1v, q1@T0_1h, q2@T0_0v, q3@T0_0h
#1 cool all
#2 gate R q0,q2 @T0_0v,T0_1v ← op 0 h, 1 h
#3 gate VZ q0,q2 @T0_0v,T0_1v ← op 0 h, 1 h
#4 shuttle q0 T0_1v→T0_1h, q2 T0_0v→T0_0h ← op 2 cx, 3 cx
#5 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#19 cool all
#6 gate MS q0,q1,q2,q3 @T0_0h,T0_1h ← op 2 cx, 3 cx
#7 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#8 gate R q1,q3 @T0_0h,T0_1h ← op 2 cx, 3 cx
#9 gate R q0,q2 @T0_0h,T0_1h ← op 2 cx, 3 cx
#10 shuttle q1 T0_1h→T0_0v ← op 4 cx
#11 shuttle q2 T0_0h→T0_0v ← op 4 cx
#12 gate R q1 @T0_0v ← op 4 cx
#20 cool all
#13 gate MS q1,q2 @T0_0v ← op 4 cx
#14 gate R q1 @T0_0v ← op 4 cx
#15 gate R q2 @T0_0v ← op 4 cx
#16 gate R q1 @T0_0v ← op 4 cx
#17 measure q0,q3 ← op 5 measure, 8 measure
#18 measure q1,q2 ← op 6 measure, 7 measureCircuit 2: a GHZ chain every CNOT shares a qubit with the next: the placer lays the chain along the register, and no ion is sent home while the next gate still needs it
machine: chain4, a four-site linear register C0–C3, every site a trap, no junctions
h q[0];
cx q[0],q[1];
cx q[1],q[2];
cx q[2],q[3];
measure q -> c;| qubit | ion | starts | ends |
| q0 | q0 | C3 | C2 |
| q1 | q1 | C2 | C1 |
| q2 | q2 | C1 | C0 |
| q3 | q3 | C0 | C0 |
op 0 at C3: R(1.5708,-1.5708)@q0, VZ(3.14159)@q0op 1 at C2: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0op 2 at C1: R(1.5708,1.5708)@q1, MS(1.5708)@q1,q2, R(-1.5708,0)@q1, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q1op 3 at C0: R(1.5708,1.5708)@q2, MS(1.5708)@q2,q3, R(-1.5708,0)@q2, R(-1.5708,0)@q3, R(-1.5708,1.5708)@q2#0 init q0@C3, q1@C2, q2@C1, q3@C0
#1 cool all
#2 gate R q0 @C3 ← op 0 h
#3 gate VZ q0 @C3 ← op 0 h
#4 shuttle q0 C3→C2 ← op 1 cx
#5 gate R q0 @C2 ← op 1 cx
#25 cool all
#6 gate MS q0,q1 @C2 ← op 1 cx
#7 gate R q0 @C2 ← op 1 cx
#8 gate R q1 @C2 ← op 1 cx
#9 gate R q0 @C2 ← op 1 cx
#10 shuttle q1 C2→C1 ← op 2 cx
#11 gate R q1 @C1 ← op 2 cx
#26 cool all
#12 gate MS q1,q2 @C1 ← op 2 cx
#13 gate R q1 @C1 ← op 2 cx
#14 gate R q2 @C1 ← op 2 cx
#15 gate R q1 @C1 ← op 2 cx
#16 measure q0 ← op 4 measure
#17 shuttle q2 C1→C0 ← op 3 cx
#18 gate R q2 @C0 ← op 3 cx
#27 cool all
#19 gate MS q2,q3 @C0 ← op 3 cx
#20 gate R q2 @C0 ← op 3 cx
#21 gate R q3 @C0 ← op 3 cx
#22 gate R q2 @C0 ← op 3 cx
#23 measure q1 ← op 5 measure
#24 measure q2,q3 ← op 6 measure, 7 measureCircuit 3: a parity check, by rotation the ancilla q0 sits at a dock, the data ride the loop; the loop turns twice and every CNOT is a contact at the dock
machine: ring6d, the six-site ring with two dock spurs
h q[0];
cx q[0],q[1];
cx q[0],q[2];
cx q[0],q[3];
h q[0];
measure q[0] -> c[0];| qubit | ion | starts | ends |
| q0 | q0 | A0 | A0 |
| q1 | q1 | S0 | S0 |
| q2 | q2 | S2 | S0 |
| q3 | q3 | S4 | S0 |
op 0 at A0: witnessed by instruction #3, pulses in the programmeop 1 at A0: witnessed by instruction #9, pulses in the programmeop 2 at A0: witnessed by instruction #17, pulses in the programmeop 3 at A0: witnessed by instruction #25, pulses in the programmeop 4 at A0: witnessed by instruction #28, pulses in the programme#0 init q0@A0, q1@S0, q2@S2, q3@S4
#1 cool all
#2 gate R q0 @ ← op 0 h
#3 gate VZ q0 @ ← op 0 h
#4 dock q1 S0→A0 ← op 1 cx
#5 gate R q0 @A0 ← op 1 cx
#30 cool all
#6 gate MS q0,q1 @A0 ← op 1 cx
#7 gate R q0 @A0 ← op 1 cx
#8 gate R q1 @A0 ← op 1 cx
#9 gate R q0 @A0 ← op 1 cx
#10 undock q1 A0→S0 ← op 1 cx
#11 rotate_ccw rotate L0 by -2 ← op 2 cx
#12 dock q2 S0→A0 ← op 2 cx
#13 gate R q0 @A0 ← op 2 cx
#31 cool all
#14 gate MS q0,q2 @A0 ← op 2 cx
#15 gate R q0 @A0 ← op 2 cx
#16 gate R q2 @A0 ← op 2 cx
#17 gate R q0 @A0 ← op 2 cx
#18 undock q2 A0→S0 ← op 2 cx
#19 rotate_ccw rotate L0 by -2 ← op 3 cx
#20 dock q3 S0→A0 ← op 3 cx
#21 gate R q0 @A0 ← op 3 cx
#32 cool all
#22 gate MS q0,q3 @A0 ← op 3 cx
#23 gate R q0 @A0 ← op 3 cx
#24 gate R q3 @A0 ← op 3 cx
#25 gate R q0 @A0 ← op 3 cx
#26 undock q3 A0→S0 ← op 3 cx
#27 gate R q0 @ ← op 4 h
#28 gate VZ q0 @ ← op 4 h
#29 measure q0 ← op 5 measureA Toffoli, lowered one three-qubit gate becomes six CNOTs and nine single-qubit gates before placement; R10 is decided against the exact unitary
machine: grid2x3, a 2×3 lattice: T-junctions and corners, one trap on every wire
ccx q[0],q[1],q[2];| qubit | ion | starts | ends |
| q0 | q0 | T0_1h | T0_1h |
| q1 | q1 | T0_1v | T0_1v |
| q2 | q2 | T0_0v | T0_1v |
op 0 at T0_0v: R(1.5708,-1.5708)@q2, VZ(3.14159)@q2op 1 at T0_0v: R(1.5708,1.5708)@q1, MS(1.5708)@q1,q2, R(-1.5708,0)@q1, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q1op 2 at T0_0v: R(0,2.35619)@q2, VZ(-0.785398)@q2op 3 at T0_1h: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q2, R(-1.5708,0)@q0, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q0op 4 at T0_1h: R(0,0.785398)@q2, VZ(0.785398)@q2op 5 at T0_1v: R(1.5708,1.5708)@q1, MS(1.5708)@q1,q2, R(-1.5708,0)@q1, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q1op 6 at T0_1v: R(0,2.35619)@q2, VZ(-0.785398)@q2op 8 at T0_1h: R(0,0.785398)@q1, VZ(0.785398)@q1op 7 at T0_1v: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q2, R(-1.5708,0)@q0, R(-1.5708,0)@q2, R(-1.5708,1.5708)@q0op 9 at T0_1v: R(0,0.785398)@q2, VZ(0.785398)@q2op 11 at T0_1h: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0op 10 at T0_1v: R(1.5708,-1.5708)@q2, VZ(3.14159)@q2op 12 at T0_1h: R(0,0.785398)@q0, VZ(0.785398)@q0op 13 at T0_0v: R(0,2.35619)@q1, VZ(-0.785398)@q1op 14 at T0_1h: R(1.5708,1.5708)@q0, MS(1.5708)@q0,q1, R(-1.5708,0)@q0, R(-1.5708,0)@q1, R(-1.5708,1.5708)@q0#0 init q0@T0_1h, q1@T0_1v, q2@T0_0v
#1 cool all
#2 gate R q2 @T0_0v ← op 0 h
#3 gate VZ q2 @T0_0v ← op 0 h
#4 shuttle q1 T0_1v→T0_0v ← op 1 cx
#5 gate R q1 @T0_0v ← op 1 cx
#53 cool all
#6 gate MS q1,q2 @T0_0v ← op 1 cx
#7 gate R q1 @T0_0v ← op 1 cx
#8 gate R q2 @T0_0v ← op 1 cx
#9 gate R q1 @T0_0v ← op 1 cx
#10 shuttle q1 T0_0v→T0_1v ← op 1 cx
#11 gate R q2 @T0_0v ← op 2 tdg
#12 gate VZ q2 @T0_0v ← op 2 tdg
#13 shuttle q2 T0_0v→T0_1h ← op 3 cx
#14 gate R q0 @T0_1h ← op 3 cx
#54 cool all
#15 gate MS q0,q2 @T0_1h ← op 3 cx
#16 gate R q0 @T0_1h ← op 3 cx
#17 gate R q2 @T0_1h ← op 3 cx
#18 gate R q0 @T0_1h ← op 3 cx
#19 gate R q2 @T0_1h ← op 4 t
#20 gate VZ q2 @T0_1h ← op 4 t
#21 shuttle q2 T0_1h→T0_1v ← op 5 cx
#22 gate R q1 @T0_1v ← op 5 cx
#55 cool all
#23 gate MS q1,q2 @T0_1v ← op 5 cx
#24 gate R q1 @T0_1v ← op 5 cx
#25 gate R q2 @T0_1v ← op 5 cx
#26 gate R q1 @T0_1v ← op 5 cx
#27 shuttle q1 T0_1v→T0_1h ← op 8 t
#28 gate R q2,q1 @T0_1h,T0_1v ← op 6 tdg, 8 t
#29 gate VZ q2,q1 @T0_1h,T0_1v ← op 6 tdg, 8 t
#30 shuttle q0 T0_1h→T0_1v ← op 7 cx
#31 gate R q0 @T0_1v ← op 7 cx
#56 cool all
#32 gate MS q0,q2 @T0_1v ← op 7 cx
#33 gate R q0 @T0_1v ← op 7 cx
#34 gate R q2 @T0_1v ← op 7 cx
#35 gate R q0 @T0_1v ← op 7 cx
#36 shuttle q0 T0_1v→T0_1h ← op 11 cx
#37 gate R q2,q0 @T0_1h,T0_1v ← op 9 t, 11 cx
#38 gate VZ q2 @T0_1v ← op 9 t
#57 cool all
#39 gate MS q0,q1 @T0_1h ← op 11 cx
#40 gate R q0 @T0_1h ← op 11 cx
#41 gate R q1 @T0_1h ← op 11 cx
#42 gate R q0 @T0_1h ← op 11 cx
#43 shuttle q1 T0_1h→T0_0v ← op 13 tdg
#44 gate R q2,q0,q1 @T0_0v,T0_1h,T0_1v ← op 10 h, 12 t, 13 tdg
#45 gate VZ q2,q0,q1 @T0_0v,T0_1h,T0_1v ← op 10 h, 12 t, 13 tdg
#46 shuttle q1 T0_0v→T0_1h ← op 14 cx
#47 gate R q0 @T0_1h ← op 14 cx
#58 cool all
#48 gate MS q0,q1 @T0_1h ← op 14 cx
#49 gate R q0 @T0_1h ← op 14 cx
#50 gate R q1 @T0_1h ← op 14 cx
#51 gate R q0 @T0_1h ← op 14 cx
#52 shuttle q1 T0_1h→T0_1v ← op 14 cxConclusion
What to remember
- Compiling a circuit for a QCCD machine is three decisions and one proof: which ion plays which qubit and where it starts (placement), how the pairs meet without breaking a rule (routing, in layers), which pulses fire (the two identities), and then evidence that all of it happened.
- The compiler is untrusted and its checks are trusted. Legality is decided by the rule checker, “every gate happened where claimed” by a checker whose correctness is proved in Lean, and “the pulses compute the circuit” by a stabilizer tableau or an exact matrix. A compiler bug is a red verdict on this page, not a wrong programme on a machine.
- Hops are the cost. Placement keeps interacting qubits close, routing moves few ions, and cooling is inserted only before a gate that would be too hot. One waveform per cycle (R22) is the rule that shapes the router most.
- Independent gates run in lock-step layers, so many gates cost one; a qubit's own gates keep the circuit's order, always.
- What is not done: no cross-layer pipelining, no optimality guarantee, and for a non-Clifford circuit of more than ten qubits the second half of R10 is reported as not checked rather than passed.
Every number and picture on this page came out of the real toolchain, and every example opens as the Studio page the compiler wrote. To compile a circuit of your own, open the Design page; to see these programmes ranked, the Leaderboard.