Steven GellerQuantum Computing, End to End

Book contents

Current section

Part V. Practical Software

  1. Python and Quantum Programming Workflow
  2. Building a Small Simulator From Scratch
  3. Qiskit, Primitives, and Circuit Execution
  4. Cirq and Alternative Toolchains
  5. Transpilation and Hardware-Aware Compilation
  6. Noise Models and Noisy Simulation
  7. Benchmarking Quantum Programs
  8. Resource Estimation for Fault-Tolerant Algorithms
  9. Reproducible Quantum Labs

Part V. Practical Software · Chapter 40

Transpilation and Hardware-Aware Compilation

The circuit you drew is not the circuit that runs. Between them sits the transpiler, rewriting your gates into the native set, routing around missing connections, and quietly deciding whether your algorithm fits the hardware's error budget.

Lab
In this chapter 12 sections

Compile against a declared native gate set and coupling graph, record initial and final layouts, inserted SWAPs, direction fixes, depth, duration, and two-qubit count, then verify the compiled circuit against the abstract unitary or a complete small-instance oracle.

A routed circuit is a proof obligation with a cost ledger. The compiler must show which logical state occupies each physical site after every move and why the output still means what the input circuit meant.

Routing a distant interaction on a lineq0q1q2q3SWAP changes the layout, not the logical program
Figure 40.1. After a SWAP, physical position and logical identity diverge. A compiler that reports only inserted gate count has omitted the map needed to interpret measurement.

The target is a graph plus an instruction set

Start with an abstract circuit and a target contract. Vertices are physical qubit locations; directed or undirected edges identify allowed two-qubit operations; the instruction set names native one- and two-qubit gates. Add operation durations in seconds and calibration-specific error probabilities only when their protocol, scope, and date are known. Transpilation maps a circuit into such a target, and SDK compiler interfaces expose target-specific behavior [Qiskit transpiler documentation] [Cirq transformer documentation].

OpenQASM can express a program while leaving physical placement and target cost unresolved [OpenQASM 3 specification]. The compiler input must therefore include logical circuit, coupling graph, native entangler direction, initial layout policy, optimization objective, and whether measurements are reverse-mapped.

Route one distant CNOT on a line

On physical line 0—1—2—3, logical CNOT(q0,q3) is unavailable at the initial layout [q0,q1,q2,q3]. The transparent teaching router moves q0 right twice: SWAP(0,1), SWAP(1,2), then CNOT(2,3). The physical operation trace is short, but the logical layout is now [q1,q2,q0,q3]. If the output is read as the original layout, a correct physical run becomes a wrong logical result.

The route is not claimed optimal. A production compiler may move the target, exploit direction, commute gates, or choose a different initial placement. Its result must still expose enough layout and target data to reproduce the cost.

Expand SWAPs before comparing native cost

A SWAP is not usually a primitive entangler. Under a bidirectional CNOT basis, the familiar decomposition uses three CNOTs, so the teaching trace expands from two SWAPs plus one CNOT to seven CNOTs before single-qubit direction corrections. On a directed coupling graph, a reverse CNOT may itself require basis changes around an allowed-direction entangler. Reporting “three operations” would therefore mix an abstract routing instruction with native hardware instructions.

The ledger should retain both levels. Logical operations explain intent; routing operations explain movement; native instructions support duration and calibration lookup. These rows must not be summed until each operation has been lowered to the same instruction set. The expansion also changes depth: some one-qubit gates can overlap, while the CNOT chain sharing the moved qubit cannot.

Prove the routed operation means the same thing

For five small logical bits, enumerate all 32 basis inputs. Simulate the abstract CNOT. Simulate every routed SWAP and CNOT on physical positions. Convert the final physical bit vector back through the final layout, then compare. This catches a correct-looking gate trace with a stale measurement map.

A basis oracle is complete for this classical reversible fragment. General quantum circuits need a unitary comparison up to global phase, process comparison, or a trusted simulator over a sufficiently complete test set. The semantic test and resource test are separate: a compiler can preserve the unitary while regressing depth badly.

For unitary matrices UU and VV, a small-instance check can estimate the phase eiϕe^{i\phi} from a nonzero entry of UU and test VeiϕUV\approx e^{i\phi}U. Comparing entries directly would reject a physically identical circuit that differs only by global phase. Once measurement, reset, or classical control appears, there may be no single unitary; compare the resulting channels or an exhaustive branch oracle instead.

Measurement mapping deserves its own assertion. If logical q0 finishes at physical p2, the classical bit receiving p2 must be labeled q0 in the normalized result. Test this with asymmetric basis inputs after routing. A Bell circuit is insufficient because symmetric outcomes can conceal a stale final layout just as they conceal a reversed display convention.

Nearest-neighbor routing trace and equivalence table

Distant CNOT on a four-site line
stepphysical operationlayout aftertwo-qubit count
0inputq0 q1 q2 q30
1SWAP p0,p1q1 q0 q2 q31 SWAP
2SWAP p1,p2q1 q2 q0 q32 SWAP
3CNOT p2,p3q1 q2 q0 q32 SWAP + 1 CNOT
def route(control=0, target=3, sites=4):
    if (type(sites) is not int or sites < 2 or control == target or
            control not in range(sites) or target not in range(sites)):
        raise ValueError("control and target must be distinct physical sites")
    layout = list(range(sites)); ops = []
    while abs(layout.index(control)-layout.index(target)) > 1:
        p = layout.index(control); step = 1 if layout.index(target) > p else -1
        q = p + step
        layout[p], layout[q] = layout[q], layout[p]
        ops.append(("SWAP", p, q, tuple(layout)))
    ops.append(("CNOT", layout.index(control), layout.index(target), tuple(layout)))
    return ops
ops = route()
reverse_ops = route(3, 0)
adjacent_ops = route(1, 2)
invalid_rejected = False
try:
    route(0, 0)
except ValueError:
    invalid_rejected = True
assert [op[0] for op in ops] == ["SWAP", "SWAP", "CNOT"]
assert abs(ops[-1][1]-ops[-1][2]) == 1
assert sorted(ops[-1][3]) == [0,1,2,3]
assert [op[0] for op in reverse_ops] == ["SWAP", "SWAP", "CNOT"]
assert [op[0] for op in adjacent_ops] == ["CNOT"] and invalid_rejected
print(f"PASS: 40 routing forward_ops={len(ops)} reverse_ops={len(reverse_ops)} adjacent_ops={len(adjacent_ops)}")

Existing fixture: cd labs && python -m unittest tests.test_companion_models.CompanionModelTests.test_line_router_exposes_swap_cost_and_layout -v.

Count gates, layers, duration, and error separately

Gate count is a count. Depth is a schedule length in layers under a stated parallelism rule. Duration is seconds computed from target-specific instruction times. Error is a protocol-defined probability per operation or circuit. Do not multiply a vendor average error by a gate count and call it success probability without an independence model, leakage policy, and calibration match. Modern benchmarking guidance treats these as non-equivalent axes [benchmarking review].

Units-bearing comparison
metricabstractrouted teaching traceunit/assumption
two-qubit operations1 CNOT2 SWAP + 1 CNOToperation counts; SWAP decomposition not expanded
depth13serial layers
durationunknown2tswap+tcxseconds after calibration supplied
errorunknownunknownrequires operation-level model

Suppose a calibrated target declares 240 ns for each native CNOT and 35 ns for each required Hadamard. Seven serial CNOTs alone imply 1.68 μs; direction fixes add their scheduled one-qubit layers. That arithmetic is a target-specific duration estimate, not a fidelity estimate. A cost record must include the calibration identifier and the exact schedule from which the critical path was summed.

An error ledger is more delicate. The product j(1rj)\prod_j(1-r_j) is defensible only under a stated independent stochastic model with matched per-instruction error probabilities. Coherent error, crosstalk, leakage, and temporal drift violate that shortcut. Preserve raw calibration fields and label any composed number as a model output rather than measured circuit success.

Calibration turns one circuit into many schedules

A layout favorable yesterday may cross a weak edge today. Direction fixes, dynamical constraints, readout assignment, and concurrent-crosstalk exclusions change the schedule. Full-stack performance couples compiler decisions to control and topology [full-stack review]. Store target and calibration identifiers, compiler version/options, and transpiled hash. Compiled evidence expires even when the logical circuit does not.

This is why optimization should be multiobjective and auditable. Minimizing two-qubit count may choose a slower edge; minimizing nominal duration may concentrate work on a drifting qubit; minimizing an error-model score may lengthen the critical path beyond a coherence budget. Record the objective and the values of the alternatives considered. A compiler seed is part of the evidence because stochastic placement can otherwise make a regression appear and disappear between runs.

Compiler regression fixtures

Maintain three classes: semantic fixtures compare outputs after reverse mapping; structural fixtures assert every operation is native and every entangler uses an allowed edge/direction; cost fixtures use explicit ceilings or relative non-regression thresholds. Never hard-code one exact route unless route stability itself is the API. Report improvements and regressions in counts, layers, and seconds independently.

Add metamorphic cases: relabel the physical graph and initial layout together, reverse a line target, or insert canceling one-qubit gates before optimization. The compiled text may change, but normalized semantics and appropriately relabeled costs should not. These tests detect hidden dependence on vertex numbering and compiler passes that silently discard or duplicate operations.

The five-site exercise has 32 inputs because the transparent verifier carries five logical bits even though the routed CNOT names only two. For each row, it initializes physical positions from the initial layout, applies every SWAP and directed CNOT, then reconstructs logical order from the final layout. Comparing before reverse mapping would test a different output convention and can falsely condemn a correct route.

Report the route trace as state transitions, not only a final permutation. After every SWAP, assert that the layout remains a bijection over logical labels; after every entangler, assert adjacency and direction in the target graph. Those local invariants identify the first illegal step. A final truth-table mismatch alone says only that something somewhere in routing or measurement mapping went wrong.

Cost ceilings should tolerate equivalent routing choices while detecting regression. For a named target and seed, one policy might require semantic equality, native-only operations, at most a declared two-qubit count, and duration no worse than the recorded baseline by more than a stated percentage. If calibration changes, create a new baseline record rather than comparing seconds computed from different target data.

Finally, keep compiler optimization claims scoped. Reducing a symbolic depth from ten to eight layers says nothing about wall time until scheduling applies instruction durations and constraints. Reducing seven native entanglers to six says nothing about fidelity without a matched error model. The compiler has several ledgers because optimization can improve one while harming another.

The publishable record links those ledgers through one transpiled-circuit hash. Counts, schedule seconds, layout trace, and semantic verification must all describe that exact artifact, not neighboring compiler runs.

Five-site route audit

Prompt: Route CNOT(q0,q4) on a five-site line, verify every computational-basis input, and compare it with an all-to-all target.

Deliverable: Operation trace, final layout, exhaustive truth table, and before/after resource table with counts, layers, and assumed durations.

Pass condition: All 32 basis inputs agree after reverse mapping, every resource column has units, and the report does not infer physical error from gate count alone.

Reference route

Format: Generated trace/CSV and a reference reverse-layout verifier.

Verification: Unit tests regenerate the trace, assert semantic equality, validate layout permutations, and check resource-table totals.

A transparent route moves one endpoint through three adjacent SWAPs before the CNOT and preserves the resulting final layout for reverse mapping. All 32 inputs agree with the abstract operation. The all-to-all case uses one two-qubit layer; duration remains symbolic until target operation times are supplied.

Companion work

Artifacts for this chapter

These entries resolve to checked-in local source. Commands are reproduced exactly from the chapter manifest, and source-embedded fixtures are exported as direct downloads.

  1. Reproduce or test

    python3 tools/validate_briefs.py --briefs data/editorial_briefs_36_63.json --from 36 --through 63 --check-rewritten-sources --execute-artifacts

Provenance

Sources and review

  1. IBM Quantum. Qiskit documentation. IBM. 2026official documentation
  2. Google Quantum AI. Cirq documentation. Google. 2026official documentation
  3. OpenQASM Technical Steering Committee. OpenQASM 3 specification. Linux Foundation Joint Development Foundation. 2026official technical specification
  4. Lieven M. K. Vandersypen et al.. A look at the full stack. Nature Reviews Physics. 2021peer-reviewed perspective
  5. Timothy Proctor et al.. Benchmarking quantum computers. Nature Reviews Physics. 2025peer-reviewed perspective

The load-bearing claims in the chapter are mapped inline to this registered source set. A citation supports only the bounded claim beside it.

Cite this chapter