Passes Reference
This page documents each pass individually. For the high-level flow of how passes chain together, see The Pipeline. For how to write your own pass, see Adding a Pass.
BasisTranslationPass
Constructor
BasisTranslationPass(backend="IBM")| Parameter | Type | Default | Description |
|---|---|---|---|
backend | str | "IBM" | Backend name matching a key in the backend registry |
What it does
Walks the circuit instruction by instruction. If a gate is already in the backend's basis set, it passes through unchanged. If it isn't, the pass looks it up in the backend's decomposition map and substitutes it with the decomposed sequence, remapping qubit indices appropriately. Measurements and barriers always pass through unchanged.
Architecture note: This pass is single-pass. It walks the instruction list exactly once with no recursion. Decomposition map entries must produce only basis gate instructions. Entries that produce intermediate gates which themselves need further decomposition will not be caught.
Normalization: The gate name cnot is normalized to cx before any lookup, so circuits using either name are handled correctly.
ValueError if a gate is encountered that has no decomposition defined for the target backend.LayoutPass
Constructor
LayoutPass(coupling_map, layout_algorithm="dense")| Parameter | Type | Default | Description |
|---|---|---|---|
coupling_map | TesseraCouplingMap | required | The hardware topology to map qubits onto |
layout_algorithm | str | callable | "dense" | Either a registered algorithm name ("dense", "sabre", "trivial") or a custom callable (circuit, coupling_map) -> dict[int, int] |
What it does
Resolves the layout algorithm from the registry (or accepts a custom callable), then delegates to it. The algorithm receives the circuit and the coupling map and returns a dict mapping logical qubit indices to physical qubit indices. That mapping is written to TesseraCircuit.layout. No instructions are modified, only the layout field is set.
Architecture note: LayoutPass itself is a thin shell. It resolves the algorithm in its constructor and calls it in run(). The actual placement logic lives in modules under tessera/layouts/. This separation keeps the pass itself stable while the algorithm set grows.
For algorithm-by-algorithm details (how dense, SABRE, and trivial each work and when to pick which), see the Layout Algorithms page.
ValueErroriflayout_algorithmis a string that isn't registered in the layout registry (the error message lists the available keys)ValueErroriflayout_algorithmis neither a string nor a callableValueError(from the algorithm at run time) if the circuit has more qubits than the coupling map supports
DenseLayoutPass deprecated
DenseLayoutPass still exists as a backwards-compatibility shim. It delegates to LayoutPass(coupling_map, "dense") internally and emits a DeprecationWarning on construction. New code should use LayoutPass directly.
Constructor
DenseLayoutPass(coupling_map) # deprecatedRemoval timeline: the class is functional today but may be removed in a future release. Migrate any direct callers to LayoutPass(coupling_map, "dense").
BasicSwapRouter
Constructor
BasicSwapRouter(coupling_map, path_finder="bfs")| Parameter | Type | Default | Description |
|---|---|---|---|
coupling_map | TesseraCouplingMap | required | The hardware topology used to check adjacency and find paths |
path_finder | str | callable | None | "bfs" | Either a registered algorithm name ("bfs", "a_star", "sabre"), a custom pairwise callable (start: int, end: int) -> list[int], or None (treated as "bfs" for backwards compatibility) |
What it does
Resolves the routing algorithm from the registry (or accepts a custom pairwise callable), applies the layout already set on the circuit, and routes the circuit to be compatible with the hardware's physical connectivity constraints.
For pairwise algorithms ("bfs", "a_star", and custom callables), the router maintains two tracking dicts: current_positions (logical → physical) and inverse_positions (physical → logical), which start equal to the initial layout and are updated every time a SWAP is inserted. For each instruction:
- Single-qubit gates and measurements are emitted with their qubit index translated to the current physical position
- Two-qubit gates whose physical qubits are directly connected are emitted as-is
- Two-qubit gates whose physical qubits are not connected trigger SWAP insertion. The router finds a path between them using the selected algorithm, inserts SWAPs along all but the last edge of the path to bring the qubits adjacent, updates both tracking dicts after each SWAP, then emits the gate at the final two adjacent positions
For the whole-circuit algorithm ("sabre"), routing is handled differently: SABRE maintains a front layer of executable gates and a lookahead window of upcoming gates, then picks each SWAP by scoring candidates against a heuristic across that window.
Architecture note: BasicSwapRouter itself is a thin shell. It resolves the algorithm in its constructor and calls it in run(). Pairwise algorithms share a common engine (tessera/routing/pairwise.py); SABRE implements its own loop.
For algorithm-by-algorithm details and the custom pairwise callable contract, see the Routing Algorithms page.
ValueErrorifpath_finderis a string that isn't registered in the routing registry (the error message lists the available keys)ValueErrorifpath_finderis neither a string nor a callableValueError(at run time) if the circuit has no layout (i.e.LayoutPasshas not run)ValueError(at run time) if a gate with more than 2 qubits is encountered. RunBasisTranslationPassfirst to decompose all gates to at most 2 qubits before routing
RemoveBarriersPass
Constructor
RemoveBarriersPass()No parameters.
What it does
Strips all instructions with name "barrier" from the circuit. Everything else passes through unchanged. The layout is preserved.
This pass exists because barriers prevent the optimization passes from seeing cancellation and merging opportunities across their boundaries. Since barriers have no physical effect on hardware, removing them before optimization is always safe.
OptimizationLoopPass
Constructor
OptimizationLoopPass(
passes,
optimization_iterations=1,
max_iterations=1000,
debug_on=False
)| Parameter | Type | Default | Description |
|---|---|---|---|
passes | list[TranspilerPass] | required | The inner passes to wrap. In the default Tessera pipeline this is [CancelAdjacentPass(...), MergeRotationsPass(...)] |
optimization_iterations | int | 1 | 1 is a single iteration; any positive integer runs that many iterations; -1 iterates until gate count stops decreasing |
max_iterations | int | 1000 | Safety cap on iterations when optimization_iterations=-1. Ignored when a fixed positive integer is used |
debug_on | bool | False | If True, logs per-iteration gate counts for the inner passes |
What it does
Wraps a list of inner passes and runs them more than once. On each iteration, the loop runs every inner pass in order. After all inner passes have run, the loop decides whether to continue based on the iteration mode:
- Fixed mode (positive integer): the loop runs exactly that many iterations regardless of whether the gate count is still changing.
- Convergence mode (
-1): the loop continues as long as the gate count is strictly decreasing between iterations. Once an iteration fails to reduce the gate count, the loop stops. Bounded bymax_iterationsas a safety valve against pathological circuits that never converge cleanly.
At optimization_iterations=1 the loop is equivalent to running the inner passes once in sequence, which matches the pre-v1.1 default behavior.
Composability: the loop is a regular TranspilerPassand can be used standalone or with a different set of inner passes if you're building a custom pipeline. There's nothing special-cased about Cancel Adjacent and Merge Rotations; they just happen to be the two passes Tessera's default pipeline wraps.
ValueErrorifoptimization_iterationsis0or less than-1ValueErrorifmax_iterationsis not a positive integer
CancelAdjacentPass
In Tessera's default pipeline this pass runs as an inner pass of OptimizationLoopPass, but it works standalone as well.
Constructor
CancelAdjacentPass(strict=True)| Parameter | Type | Default | Description |
|---|---|---|---|
strict | bool | True | If True, uses strict adjacency mode. If False, uses commutative mode |
Supported self-inverse gates: x, cx, y, h, cz, swap
Strict mode
Scans the instruction list for pairs of identical self-inverse gates on the same qubits that are directly adjacent. Both gates are removed.
X(q0) X(q0) → (removed)
H(q0) X(q1) H(q0) → H(q0) X(q1) H(q0) (no cancellation; not adjacent)Commutative mode
Extends cancellation to gates separated by instructions on non-overlapping qubits. When a self-inverse gate is found, the pass scans forward until it hits an instruction that shares a qubit with it. If that instruction is the same gate on the same qubits, both cancel. If it's a different gate on a shared qubit, cancellation stops.
H(q0) X(q1) H(q0) → X(q1) (H gates cancel because nothing between them touches q0)
H(q0) X(q0) H(q0) → X(q0) (no cancellation because X(q0) is on a shared qubit)MergeRotationsPass
Like CancelAdjacentPass, this pass runs as an inner pass of OptimizationLoopPassin Tessera's default pipeline but works standalone as well.
Constructor
MergeRotationsPass(strict=True, epsilon=1e-9)| Parameter | Type | Default | Description |
|---|---|---|---|
strict | bool | True | If True, uses strict adjacency mode. If False, uses commutative mode |
epsilon | float | 1e-9 | Merged angles smaller than this threshold are treated as zero and the gate is dropped |
Supported mergeable gates: rz, rx, ry
Strict mode
Scans for pairs of identical rotation gates on the same qubit that are directly adjacent. Merges their angles additively. If the merged angle is within epsilon of zero, the gate is dropped entirely.
Rz(0.3, q0) Rz(0.5, q0) → Rz(0.8, q0)
Rz(0.5, q0) Rz(-0.5, q0) → (dropped)
Rz(0.3, q0) Rx(0.5, q1) Rz(0.5, q0) → Rz(0.3, q0) Rx(0.5, q1) Rz(0.5, q0) (no merge; not adjacent)Three-or-more rotations: a single iteration of this pass only looks one step ahead at a time, so three consecutive rotations of the same type will leave one unmerged. Rz(a) Rz(b) Rz(c) becomes Rz(a+b) Rz(c) after one iteration, then collapses to Rz(a+b+c) on the next. Running the pass inside OptimizationLoopPass(the default in Tessera's pipeline) handles this automatically.
Commutative mode
Extends merging to rotation gates separated by instructions on non-overlapping qubits. When a rotation gate is found, the pass scans forward until it hits an instruction on a shared qubit. If that instruction is the same rotation gate on the same qubit, their angles are merged.
Rz(0.3, q0) Rx(0.5, q1) Rz(0.5, q0) → Rz(0.8, q0) Rx(0.5, q1)