> ## Documentation Index
> Fetch the complete documentation index at: https://b01t.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compiling b01t Programs to Qiskit Circuits

> Lower an ExactProgram to IRProgram with lower_exact_program(), then emit a QuantumCircuit with QiskitBackend — ready to simulate or run on real hardware.

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:

```bash theme={null}
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()`:

```python theme={null}
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.

<Warning>
  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.
</Warning>

## Compiling @parametric and @adaptive programs

`@parametric` and `@adaptive` programs produce `IRProgram` directly from `.build()`, so you can pass them straight to the backend:

```python theme={null}
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:

```python theme={null}
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 gate | Qiskit operation                                         | Arity |
| --------- | -------------------------------------------------------- | ----- |
| `x`       | `circuit.x`                                              | 1     |
| `h`       | `circuit.h`                                              | 1     |
| `z`       | `circuit.z`                                              | 1     |
| `s`       | `circuit.s`                                              | 1     |
| `sdg`     | `circuit.sdg`                                            | 1     |
| `t`       | `circuit.t`                                              | 1     |
| `tdg`     | `circuit.tdg`                                            | 1     |
| `rx(θ)`   | `circuit.rx`                                             | 1     |
| `ry(θ)`   | `circuit.ry`                                             | 1     |
| `rz(θ)`   | `circuit.rz`                                             | 1     |
| `cx`      | `circuit.cx`                                             | 2     |
| `cz`      | `circuit.cz`                                             | 2     |
| `swap`    | `circuit.swap`                                           | 2     |
| `cry(θ)`  | `circuit.cry`                                            | 2     |
| `crz(θ)`  | `circuit.crz`                                            | 2     |
| `ccx`     | `circuit.ccx`                                            | 3     |
| `ccz`     | `circuit.ccz` (or H+CCX+H decomposition on older Qiskit) | 3     |
| `mcx`     | `circuit.mcx`                                            | n     |
| `mcz`     | H + `circuit.mcx` + H decomposition                      | n     |

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:

```python theme={null}
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.

<Tip>
  Use `circuit.draw("mpl")` to render a matplotlib diagram of your circuit, or `circuit.draw("text")` for a terminal-friendly ASCII diagram.
</Tip>
