Tessera: Quantum Circuit Transpiler

Getting Started

Prerequisites

Tessera requires Python 3.10 or higher. The following packages are installed automatically as dependencies:

  • qiskit >= 2.3
  • qiskit-ibm-runtime >= 0.46
  • numpy >= 2.0
  • networkx >= 3.0

Installation

Clone the repository and install in editable mode:

git clone https://github.com/derrickboyer3/tessera.git
cd tessera
pip install -e .

To also install development dependencies for running tests and benchmarks:

pip install -e .[dev]

Your First Circuit

Once installed, you can transpile a circuit in a few lines. The transpile() function is the main entry point. Pass it a Qiskit circuit and a backend name and it handles everything else.

from qiskit import QuantumCircuit
from tessera.api.transpile import transpile

qc = QuantumCircuit(3)
qc.h(0)
qc.cx(0, 1)
qc.cx(1, 2)
qc.measure_all()

transpiled = transpile(qc, backend="IBM")
print(transpiled)

The output is a standard Qiskit QuantumCircuit with all gates decomposed to the IBM basis set (cx, rz, sx, x, u), qubits mapped to physical hardware positions, and routing SWAPs inserted where needed.

Choosing a Backend

Tessera supports three backends out of the box. Pass the backend name as a string:

# IBM basis: cx, rz, sx, x, u
transpiled = transpile(qc, backend="IBM")

# IonQ basis: rx, ry, rz, cx
transpiled = transpile(qc, backend="IONQ")

# Rigetti basis: rx, rz, cz
transpiled = transpile(qc, backend="RIGETTI")

Each backend uses a default coupling map based on real hardware. See the Backends page for the full list of devices and available coupling map overrides.

Overriding the Coupling Map

Each backend has a default coupling map but you can pass any named coupling map key or a custom TesseraCouplingMapregardless of which backend you're using. The backend controls gate decomposition, the coupling map controls routing topology. They are fully independent.

# Use any named coupling map key with any backend
transpiled = transpile(qc, backend="IBM", coupling_map="IBM_BRISBANE")
transpiled = transpile(qc, backend="IBM", coupling_map="IONQ_ARIA")

# Pass a custom coupling map
from tessera.hardware.coupling_map import TesseraCouplingMap

cm = TesseraCouplingMap(3, [(0, 1), (1, 0), (1, 2), (2, 1)])
transpiled = transpile(qc, backend="IBM", coupling_map=cm)

See the Coupling Maps page for the full list of available named keys.

Choosing a Layout Algorithm

Tessera ships three layout algorithms for mapping logical qubits onto physical positions. Pass one by name with the layout_algorithm parameter. The default is "dense", matching pre-v1.1 behavior.

# Dense (default): greedy placement by interaction frequency
transpiled = transpile(qc, backend="IBM", layout_algorithm="dense")

# SABRE: forward-backward trial routing
transpiled = transpile(qc, backend="IBM", layout_algorithm="sabre")

# Trivial: direct logical to physical mapping
transpiled = transpile(qc, backend="IBM", layout_algorithm="trivial")

You can also pass a custom callable of the form (circuit, coupling_map) -> dict[int, int] if you want to drop in your own algorithm. See the Layout Algorithms page for the details of each built-in algorithm and the custom-callable contract.

Choosing a Routing Algorithm

The routing algorithm controls how SWAP gates get inserted when two-qubit gates land on non-adjacent qubits. Pass one by name with the pathfinder parameter. The default is "bfs", matching pre-v1.1 behavior.

# BFS (default): pairwise shortest path
transpiled = transpile(qc, backend="IBM", pathfinder="bfs")

# A*: pairwise shortest path with an admissible heuristic
transpiled = transpile(qc, backend="IBM", pathfinder="a_star")

# SABRE: whole-circuit swap selection with front-layer lookahead
transpiled = transpile(qc, backend="IBM", pathfinder="sabre")

The parameter kept its original name for backwards compatibility. It still accepts a custom pairwise callable of the form (start: int, end: int) -> list[int], just like before. See the Routing Algorithms page for the details of each built-in algorithm and the custom-callable contract.

Running the Optimization Loop

Cancel Adjacent and Merge Rotations are wrapped in an optimization loop that can run them more than once. Use optimization_iterations to control how many times. The default is 1, matching pre-v1.1 behavior.

# Default: a single optimization pass
transpiled = transpile(qc, backend="IBM")

# Fixed number of iterations
transpiled = transpile(qc, backend="IBM", optimization_iterations=5)

# Iterate until gate count stabilizes (capped by max_iterations, default 1000)
transpiled = transpile(qc, backend="IBM", optimization_iterations=-1)

Convergence mode (-1) keeps iterating until the gate count stops decreasing. It is capped at max_iterations (default 1000) to prevent runaway loops on circuits that do not converge cleanly.

Debug Mode

Pass debug_on=True to print per-pass gate counts as the circuit moves through the pipeline. Useful for understanding where gates are being added or removed.

transpiled = transpile(qc, backend="IBM", debug_on=True)
[Tessera] Running pass: BasisTranslationPass | Gates: 6
[Tessera] Finished pass: BasisTranslationPass | Gates: 14
[Tessera] Running pass: LayoutPass | Gates: 14
[Tessera] Finished pass: LayoutPass | Gates: 14
[Tessera] Running pass: BasicSwapRouter | Gates: 14
[Tessera] Finished pass: BasicSwapRouter | Gates: 14
[Tessera] Running pass: BasisTranslationPass | Gates: 14
[Tessera] Finished pass: BasisTranslationPass | Gates: 14
[Tessera] Running pass: RemoveBarriersPass | Gates: 14
[Tessera] Finished pass: RemoveBarriersPass | Gates: 14
[Tessera] Running pass: OptimizationLoopPass | Gates: 14
[Tessera] Running pass: CancelAdjacentPass | Gates: 14
[Tessera] Finished pass: CancelAdjacentPass | Gates: 13
[Tessera] Running pass: MergeRotationsPass | Gates: 13
[Tessera] Finished pass: MergeRotationsPass | Gates: 12
[Tessera] Finished pass: OptimizationLoopPass | Gates: 12

The optimization loop wraps its inner passes, so you'll see them logged between the loop's start and finish markers. Each iteration of the loop prints another set of inner-pass logs.

Next Steps