Skip to main content
b01t programs are hardware-agnostic until you compile them to a backend. The Qiskit backend takes a b01t IRProgram and produces a Qiskit QuantumCircuit that you can simulate locally, transpile, or submit to real quantum hardware. For programs built with @coherent, there is a two-step path: first lower the ExactProgram to IRProgram, then emit to QuantumCircuit. For @parametric and @adaptive programs, skip the first step — they already produce IRProgram directly from .build().

Prerequisites

Install Qiskit before using the backend:
pip install qiskit
If Qiskit is not installed, calling QiskitBackend().emit() raises:
DSLValidationError: Qiskit is required for backend emission.
Install with 'pip install qiskit'.

Compiling a @coherent program

@coherent programs produce an ExactProgram. Before passing to the Qiskit backend, lower it to IRProgram with lower_exact_program():
from b01t import coherent, QReg, cx, z, Certification
from b01t import ancilla, compute, phase, uncompute
from b01t import lower_exact_program, QiskitBackend

@coherent
def oracle(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: z(anc[0]))
        uncompute()

# Step 1: build the certified ExactProgram
prog = oracle.build_exact(("sys", 1))
assert prog.certification == Certification.SAFE

# Step 2: lower to broad IR
ir = lower_exact_program(prog)

# Step 3: emit to Qiskit QuantumCircuit
circuit = QiskitBackend().emit(ir)
print(circuit)
lower_exact_program() handles ancilla coalescing — sequential ancilla registers share physical qubits to minimize qubit count. The returned IRProgram carries is_safe=True from the original certification.
Do not run is_safe_program() on an IR produced by lower_exact_program(). The broad-path safety checker does not understand the APPLY-pattern ancilla blocks that lowering may produce, and will give a false negative. Safety was already proven by the exact path.

Compiling @parametric and @adaptive programs

@parametric and @adaptive programs produce IRProgram directly from .build(), so you can pass them straight to the backend:
from b01t import adaptive, QReg, h, measure_all, QiskitBackend
from b01t.kit import repeat

@adaptive
def grover_search(sys: QReg):
    for q in sys:
        h(q)
    # ... oracle and diffusion iterations ...
    return measure_all(sys)

# Build IRProgram directly
ir = grover_search.build(("sys", 2))

# Emit to Qiskit QuantumCircuit
circuit = QiskitBackend().emit(ir)
print(circuit)

Complete example

Here is a full walkthrough from definition to printed circuit, using the Bernstein-Vazirani oracle as an example:
from b01t import coherent, QReg, cx
from b01t import lower_exact_program, QiskitBackend, Certification

@coherent
def bv_oracle(inp: QReg, tgt: QReg):
    """Oracle for hidden string [1, 0, 1]: CX on bits 0 and 2."""
    cx(inp[0], tgt[0])
    cx(inp[2], tgt[0])

# Build the certified program
prog = bv_oracle.build_exact(("inp", 3), ("tgt", 1))
assert prog.certification == Certification.SAFE

# Lower and emit
ir = lower_exact_program(prog)
circuit = QiskitBackend().emit(ir)

# Inspect
print(f"Qubits: {circuit.num_qubits}")
print(f"Gates:  {circuit.size()}")
print(circuit.draw())

Supported gates

The Qiskit backend maps b01t gate names to Qiskit circuit methods as follows:
b01t gateQiskit operationArity
xcircuit.x1
hcircuit.h1
zcircuit.z1
scircuit.s1
sdgcircuit.sdg1
tcircuit.t1
tdgcircuit.tdg1
rx(θ)circuit.rx1
ry(θ)circuit.ry1
rz(θ)circuit.rz1
cxcircuit.cx2
czcircuit.cz2
swapcircuit.swap2
cry(θ)circuit.cry2
crz(θ)circuit.crz2
ccxcircuit.ccx3
cczcircuit.ccz (or H+CCX+H decomposition on older Qiskit)3
mcxcircuit.mcxn
mczH + circuit.mcx + H decompositionn
Measurement operations (measure, measure_all) add classical registers automatically. Classical if_then is not supported in the current backend — attempting to emit an IfOp raises DSLValidationError.

Running the circuit

Once you have a QuantumCircuit, use any Qiskit-compatible runner:
from qiskit import transpile
from qiskit_aer import AerSimulator

simulator = AerSimulator()
transpiled = transpile(circuit, simulator)
job = simulator.run(transpiled, shots=1024)
result = job.result()
counts = result.get_counts()
print(counts)
Or submit to IBM Quantum hardware using qiskit-ibm-runtime. The QuantumCircuit produced by b01t is a standard Qiskit circuit — any Qiskit tutorial or documentation applies directly.
Use circuit.draw("mpl") to render a matplotlib diagram of your circuit, or circuit.draw("text") for a terminal-friendly ASCII diagram.