Compiler API

This page documents the primary user-facing classes for compiling quantum circuits with qb-compiler.

QBCompiler

The main entry point. Create an instance via from_backend() and call compile() to compile a circuit.

class qb_compiler.compiler.QBCompiler(backend: str | None = None, calibration: CalibrationProvider | None = None, strategy: str = 'fidelity_optimal', calibration_properties: BackendProperties | None = None, qiskit_target: Any | None = None)

Bases: object

High-level compiler for quantum circuits.

Parameters:
  • backend – Target backend key (e.g. "ibm_fez").

  • calibration – Optional live calibration provider for noise-aware compilation.

  • strategy"fidelity_optimal" (default) trades compilation time for estimated output fidelity. "depth_optimal" minimises depth. "budget_optimal" minimises estimated cost.

STRATEGIES = frozenset({'budget_optimal', 'depth_optimal', 'fidelity_optimal'})
compile(circuit: QBCircuit, *, strategy: str | None = None, budget_usd: float | None = None, qec_aware: bool = False) CompileResult

Compile circuit and return a CompileResult.

Parameters:
  • circuit – Input circuit to compile.

  • strategy – Override the compiler-level strategy for this call.

  • budget_usd – If set, the compiler raises BudgetExceededError when estimated cost at 1024 shots exceeds this amount.

  • qec_aware – Reserve ancilla qubits for QEC syndrome extraction (future).

compile_enhanced(qiskit_circuit: Any, qiskit_target: Any, *, n_seeds: int = 20, optimization_level: int = 3, dd_type: str | None = None, backend_props: BackendProperties | None = None) EnhancedCompileResult

Qiskit-first compilation with DD enhancement.

Let Qiskit handle layout + routing (best of n_seeds at optimization_level), then add Dynamical Decoupling on top. Qiskit does not enable DD at any optimization level by default, so this is a guaranteed improvement.

Parameters:
  • qiskit_circuit – Input Qiskit QuantumCircuit.

  • qiskit_target – Qiskit Target from the backend (provides gate durations, coupling map, and dt for scheduling).

  • n_seeds – Number of Qiskit transpiler seeds to try.

  • optimization_level – Qiskit optimization level (default 3 for best routing).

  • dd_type – DD sequence type: "XX" or "XY4". If None, auto-selects based on calibration data (XY4 if median T2 < 50 µs, else XX).

  • backend_props – Optional calibration data for calibration-aware DD selection and fidelity estimation.

estimate_cost(circuit: QBCircuit, shots: int) CostEstimate

Estimate execution cost in USD for circuit at shots.

Requires a backend to be configured; raises BackendNotSupportedError otherwise.

estimate_fidelity(circuit: QBCircuit) float

Estimate output-state fidelity for circuit on the target backend.

classmethod from_backend(backend: str, **kwargs: Any) QBCompiler

Create a compiler pre-configured for backend.

Validates that the backend is known and passes any extra kwargs through to the constructor.

Compilation Results

class qb_compiler.compiler.CompileResult(compiled_circuit: QBCircuit, original_depth: int, compiled_depth: int, estimated_fidelity: float, pass_log: tuple[PassResult, ...], compilation_time_ms: float, initial_layout: dict[int, int] | None = None)

Full result bundle returned by QBCompiler.compile().

When initial_layout is present, use it with Qiskit’s transpiler for routing:

result = compiler.compile(circuit)
transpiled = qiskit.transpile(
    qiskit_circuit, target=backend.target,
    initial_layout=result.initial_layout_list,
    optimization_level=3,
)
compilation_time_ms: float
compiled_circuit: QBCircuit
compiled_depth: int
property depth_reduction_pct: float
estimated_fidelity: float
initial_layout: dict[int, int] | None
property initial_layout_list: list[int] | None

Layout as an ordered list suitable for qiskit.transpile(initial_layout=...).

original_depth: int
pass_log: tuple[PassResult, ...]
class qb_compiler.compiler.PassResult(pass_name: str, elapsed_ms: float, depth_before: int, depth_after: int, gate_count_before: int, gate_count_after: int, detail: str = '')

Outcome of a single compiler pass.

depth_after: int
depth_before: int
detail: str
elapsed_ms: float
gate_count_after: int
gate_count_before: int
pass_name: str

Cost Estimation

class qb_compiler.compiler.CostEstimator(backend_spec: BackendSpec)

Estimates execution cost in USD for a compiled circuit.

Uses the backend’s cost_per_shot from BACKEND_CONFIGS as the baseline, then scales for gate count (rough proxy for execution time on pay-per-second platforms).

estimate(depth: int, n_qubits: int, shots: int) CostEstimate

Return a CostEstimate for the given workload.

class qb_compiler.compiler.CostEstimate(cost_per_shot_usd: float, total_usd: float, shots: int, depth: int, n_qubits: int, backend: str)

Result of a cost estimation.

backend: str
cost_per_shot_usd: float
depth: int
n_qubits: int
shots: int
total_usd: float
within_budget(budget_usd: float) bool

Configuration

class qb_compiler.config.CompilerConfig(backend: str | None = None, optimization_level: int = 2, target_basis_gates: tuple[str, ...] | None = None, coupling_map: list[tuple[int, int]] | None = None, calibration_max_age_hours: float = 24.0, enable_calibration_aware: bool = True, enable_noise_aware_scheduling: bool = True, seed: int | None = None)

Full configuration for a QBCompiler run.

Parameters:
  • backend (str | None) – Target backend key (must be in BACKEND_CONFIGS if not None).

  • optimization_level (int) – 0 = no optimisation, 1 = light, 2 = standard, 3 = aggressive.

  • target_basis_gates (tuple[str, ...] | None) – Override basis gate set. If None, inferred from backend.

  • coupling_map (list[tuple[int, int]] | None) – Override coupling map as adjacency list [(i, j), ...]. If None, the compiler assumes all-to-all connectivity.

  • calibration_max_age_hours (float) – Maximum age of calibration data before it is considered stale.

  • enable_calibration_aware (bool) – Use per-qubit/gate error rates from calibration data to guide routing.

  • enable_noise_aware_scheduling (bool) – Reorder commuting gates to prefer lower-error time slots.

  • seed (int | None) – Reproducibility seed for stochastic passes (routing, layout search).

backend: str | None = None
property backend_spec: BackendSpec | None

Resolved BackendSpec, or None when no backend is set.

calibration_max_age_hours: float = 24.0
coupling_map: list[tuple[int, int]] | None = None
property effective_basis_gates: tuple[str, ...] | None

Basis gates to target — explicit override wins, else from backend.

enable_calibration_aware: bool = True
enable_noise_aware_scheduling: bool = True
optimization_level: int = 2
seed: int | None = None
target_basis_gates: tuple[str, ...] | None = None
with_overrides(**kwargs: Any) CompilerConfig

Return a shallow copy with selected fields replaced.

class qb_compiler.config.BackendSpec(provider: str, n_qubits: int, basis_gates: tuple[str, ...], coupling_map: str, cost_per_shot: float, median_cx_error: float, median_readout_error: float, t1_us: float, t2_us: float)

Immutable hardware specification for a supported backend.

basis_gates: tuple[str, ...]
cost_per_shot: float
coupling_map: str
property max_circuit_depth_heuristic: int

Rough upper bound on useful depth before decoherence dominates.

Based on T2 / (2-qubit gate time ~400 ns for superconducting, ~200 us for trapped-ion). This is intentionally conservative.

median_cx_error: float
median_readout_error: float
n_qubits: int
provider: str
t1_us: float
t2_us: float
qb_compiler.config.BACKEND_CONFIGS: dict[str, BackendSpec] = {'ibm_fez': BackendSpec(provider='ibm', n_qubits=156, basis_gates=('id', 'rz', 'sx', 'x', 'cx', 'reset'), coupling_map='heavy-hex 156q (Heron r2)', cost_per_shot=0.00016, median_cx_error=0.005, median_readout_error=0.01, t1_us=300.0, t2_us=150.0), 'ibm_marrakesh': BackendSpec(provider='ibm', n_qubits=156, basis_gates=('id', 'rz', 'sx', 'x', 'cx', 'reset'), coupling_map='heavy-hex 156q (Heron r2)', cost_per_shot=0.00016, median_cx_error=0.0055, median_readout_error=0.011, t1_us=290.0, t2_us=140.0), 'ibm_torino': BackendSpec(provider='ibm', n_qubits=133, basis_gates=('id', 'rz', 'sx', 'x', 'cx', 'reset'), coupling_map='heavy-hex 133q (Heron r1)', cost_per_shot=0.00014, median_cx_error=0.006, median_readout_error=0.012, t1_us=280.0, t2_us=130.0), 'ionq_aria': BackendSpec(provider='ionq', n_qubits=25, basis_gates=('gpi', 'gpi2', 'ms'), coupling_map='all-to-all 25q (Aria-2)', cost_per_shot=0.3, median_cx_error=0.004, median_readout_error=0.003, t1_us=1000000.0, t2_us=500000.0), 'ionq_forte': BackendSpec(provider='ionq', n_qubits=36, basis_gates=('gpi', 'gpi2', 'ms'), coupling_map='all-to-all 36q (Forte-1)', cost_per_shot=0.3, median_cx_error=0.003, median_readout_error=0.003, t1_us=1000000.0, t2_us=500000.0), 'iqm_emerald': BackendSpec(provider='iqm', n_qubits=5, basis_gates=('prx', 'cz', 'measure'), coupling_map='star topology 5q (Emerald)', cost_per_shot=0.0002, median_cx_error=0.008, median_readout_error=0.015, t1_us=40.0, t2_us=20.0), 'iqm_garnet': BackendSpec(provider='iqm', n_qubits=20, basis_gates=('prx', 'cz', 'measure'), coupling_map='square lattice 20q (Garnet)', cost_per_shot=0.00045, median_cx_error=0.015, median_readout_error=0.02, t1_us=30.0, t2_us=15.0), 'quantinuum_h2': BackendSpec(provider='quantinuum', n_qubits=32, basis_gates=('rz', 'u1q', 'zz'), coupling_map='all-to-all 32q (H2-1)', cost_per_shot=8.0, median_cx_error=0.001, median_readout_error=0.002, t1_us=10000000.0, t2_us=1000000.0), 'rigetti_ankaa': BackendSpec(provider='rigetti', n_qubits=84, basis_gates=('rx', 'rz', 'cz', 'measure'), coupling_map='octagonal lattice 84q (Ankaa-3)', cost_per_shot=0.00035, median_cx_error=0.02, median_readout_error=0.03, t1_us=20.0, t2_us=10.0)}

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

qb_compiler.config.get_backend_spec(backend: str) BackendSpec

Return the BackendSpec for backend, raising on unknown names.

Circuit Representation

class qb_compiler.compiler.QBCircuit(n_qubits: int, ops: list[GateOp] | None = None)

Minimal quantum circuit representation.

Stores a flat list of GateOp instructions and derives depth / gate-count on the fly. This is deliberately backend-agnostic; Qiskit / Cirq interop is handled by converter utilities (not in this module).

add(name: str, qubits: tuple[int, ...], params: tuple[float, ...] = ()) QBCircuit

Append a gate and return self for chaining.

copy() QBCircuit

Deep copy of the circuit.

cx(control: int, target: int) QBCircuit
property depth: int

Circuit depth computed via a per-qubit occupancy scan.

property gate_count: int
property gate_names: set[str]
h(q: int) QBCircuit
measure_all() QBCircuit
metadata: dict[str, Any]
n_qubits
ops: list[GateOp]
rx(q: int, theta: float) QBCircuit
rz(q: int, theta: float) QBCircuit
property two_qubit_count: int
x(q: int) QBCircuit
class qb_compiler.compiler.GateOp(name: str, qubits: tuple[int, ...], params: tuple[float, ...] = ())

A single gate operation.

property is_two_qubit: bool
name: str
params: tuple[float, ...] = ()
qubits: tuple[int, ...]

Convenience Factory

qb_compiler.passmanager(backend: object = None, *, optimization_level: int = 2) object

Return a Qiskit PassManager configured for backend.

Convenience factory that builds a Qiskit StagedPassManager with QBCalibrationPass injected into the layout stage. Accepts a Qiskit Backend, Target, or qb-compiler backend name string.

Parameters:
  • backend – A Qiskit Backend instance, a Qiskit Target, or a qb-compiler backend name (e.g. "ibm_fez").

  • optimization_level – Qiskit optimization level (0-3). Default 2.

Returns:

A Qiskit StagedPassManager ready to .run() circuits.

Return type:

PassManager

Examples

>>> from qb_compiler import passmanager
>>> pm = passmanager(backend)
>>> compiled = pm.run(circuit)

Protocols

These runtime-checkable protocols define the extension points that calibration providers and noise models must satisfy.

class qb_compiler.compiler.CalibrationProvider(*args, **kwargs)

Supplies per-qubit / per-gate calibration data for a backend.

property age_hours: float

Hours since calibration data was fetched.

get_cx_error(qubit_pair: tuple[int, int]) float

Return the two-qubit gate error for (q0, q1).

get_readout_error(qubit: int) float

Return the readout assignment error for qubit.

get_t1(qubit: int) float

Return T1 (microseconds) for qubit.

get_t2(qubit: int) float

Return T2 (microseconds) for qubit.

class qb_compiler.compiler.NoiseModel(*args, **kwargs)

Abstract noise model consumed by noise-aware passes.

depolarizing_rate(gate: str, qubits: tuple[int, ...]) float

Return depolarizing error probability for gate on qubits.

Exceptions

Exception hierarchy for the qb-compiler package.

All public exceptions inherit from QBCompilerError so callers can catch the base class for blanket handling.

exception qb_compiler.exceptions.BackendNotSupportedError(backend: str, available: list[str] | None = None)

Bases: QBCompilerError

Raised when a requested backend is not in the known configuration.

exception qb_compiler.exceptions.BudgetExceededError(estimated_usd: float, budget_usd: float, *, shots: int | None = None)

Bases: QBCompilerError

Raised when estimated execution cost exceeds the caller’s budget.

exception qb_compiler.exceptions.CalibrationError(message: str, *, detail: str | None = None)

Bases: QBCompilerError

Base class for calibration-related errors.

exception qb_compiler.exceptions.CalibrationNotFoundError(backend: str)

Bases: CalibrationError

Raised when no calibration data exists for the requested backend.

exception qb_compiler.exceptions.CalibrationStaleError(backend: str, age_hours: float, max_hours: float)

Bases: CalibrationError

Raised when cached calibration data exceeds the configured max age.

exception qb_compiler.exceptions.CompilationError(message: str, *, detail: str | None = None)

Bases: QBCompilerError

Raised when circuit compilation fails.

exception qb_compiler.exceptions.InvalidCircuitError(message: str, *, gate: str | None = None)

Bases: CompilationError

Raised when the input circuit is malformed or contains unsupported ops.

exception qb_compiler.exceptions.QBCompilerError(message: str, *, detail: str | None = None)

Bases: Exception

Base exception for all qb-compiler errors.