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

# Writing Certified-Safe Quantum Programs

> Learn how to use @coherent to write quantum programs that are proven unitary at build time, with ancilla discipline enforced by the DSL.

The `@coherent` decorator is b01t's primary tool for writing quantum circuits that are certified safe by construction. When you call `.build_exact()` on a coherent function, b01t validates the entire program structure — gate types, ancilla discipline, and uncomputation — before producing an `ExactProgram` with `certification == Certification.SAFE`. No simulation required.

## The full workflow

<Steps>
  <Step title="Import and define a @coherent function">
    Decorate a Python function with `@coherent`. Each parameter must be annotated as `QReg` — these become the quantum registers your function operates on.

    ```python theme={null}
    from b01t import coherent, QReg, cx, z
    from b01t import ancilla, compute, phase, uncompute

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

    You cannot call a `@coherent` function directly — it must be built via `.build_exact()`.
  </Step>

  <Step title="Use ancilla for scratch qubits">
    Allocate scratch qubits with the `ancilla(n)` context manager. All scratch qubits allocated this way are automatically verified to return to |0⟩ at the end of the block.

    Inside the `with ancilla(...) as anc:` block, you must structure your operations as one or more complete `compute / phase / uncompute` cycles:

    * **`compute(fn)`** — apply permutation gates (X, CX, CCX, SWAP, MCX) to copy system information into the ancilla. Superposition gates like H are not allowed here.
    * **`phase(fn)`** — apply diagonal gates (Z, S, T, CZ, CCZ, MCZ) to accumulate phase. Only gates that are diagonal in the computational basis are allowed.
    * **`uncompute()`** — automatically generates and appends the inverse of the compute block.

    You can also use **`apply(fn)`** instead of `phase(fn)` for the "CMA pattern": any exact gates are allowed, but they must operate on wires disjoint from the compute block's wires.

    ```python theme={null}
    @coherent
    def multi_phase(sys: QReg):
        with ancilla(1) as anc:
            # First cycle
            compute(lambda: cx(sys[0], anc[0]))
            phase(lambda: z(anc[0]))
            uncompute()
            # Second cycle in the same ancilla block
            compute(lambda: cx(sys[1], anc[0]))
            phase(lambda: z(anc[0]))
            uncompute()
    ```
  </Step>

  <Step title="Build with build_exact()">
    Call `.build_exact()` with register specifications — tuples of `(name, size)` matching the function's parameters in order.

    ```python theme={null}
    prog = oracle.build_exact(("sys", 1))
    ```

    For functions with multiple registers, pass multiple specs:

    ```python theme={null}
    prog = multi_oracle.build_exact(("inp", 3), ("tgt", 1))
    ```

    `build_exact()` returns an `ExactProgram`. If any rule is violated, it raises `DSLValidationError` before returning.
  </Step>

  <Step title="Check certification">
    A program built with `@coherent` always has `certification == Certification.SAFE`. You can assert this to make the guarantee explicit in your code:

    ```python theme={null}
    from b01t import Certification

    assert prog.certification == Certification.SAFE
    ```

    Programs built with `@primitive` have `certification == Certification.PRIMITIVE` — they use the same closed gate set but do not enforce ancilla cleanliness.
  </Step>
</Steps>

## Complete example: phase oracle

This is the canonical example from the b01t README. It computes the phase oracle `U_f|x⟩ = (-1)^{f(x)}|x⟩` for a single-qubit function.

```python theme={null}
from b01t import coherent, QReg, cx, z, Certification
from b01t import ancilla, compute, phase, uncompute

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

prog = oracle.build_exact(("sys", 1))
assert prog.certification == Certification.SAFE
print(prog.name, prog.regs)  # oracle (QReg(sys, 1), QReg(anc0, 1))
```

The ancilla qubit `anc0` starts at |0⟩, the CX gate copies `sys[0]` into it, the Z gate applies a phase, and `uncompute()` generates the inverse CX to restore `anc0` to |0⟩.

## Parallel composition with par()

Use `par()` to compose two sub-programs that operate on **disjoint** registers simultaneously. b01t enforces wire-disjointness at build time.

```python theme={null}
from b01t import coherent, QReg, h, z
from b01t import par

@coherent
def hadamard_pair(a: QReg, b: QReg):
    par(
        lambda: h(a[0]),
        lambda: h(b[0]),
    )

prog = hadamard_pair.build_exact(("a", 1), ("b", 1))
assert prog.certification == Certification.SAFE
```

If the two lambdas touch the same wire, `build_exact()` raises `DSLValidationError: par() requires disjoint wires`.

## Inverse operations with adjoint()

Use `adjoint()` to append the inverse of another `@coherent` or `@primitive` function into the current program body. This is useful for uncomputing a subroutine at the top level (outside an ancilla block).

```python theme={null}
from b01t import coherent, QReg, h, cx
from b01t import adjoint

@coherent
def entangle(a: QReg, b: QReg):
    h(a[0])
    cx(a[0], b[0])

@coherent
def entangle_then_undo(a: QReg, b: QReg):
    entangle(a, b)
    adjoint(entangle, a, b)

prog = entangle_then_undo.build_exact(("a", 1), ("b", 1))
assert prog.certification == Certification.SAFE
```

<Note>
  `adjoint()` cannot be used inside an ancilla block's compute/phase/uncompute cycle. It is only valid at the top level of a `@coherent` function body.
</Note>

## Common errors

### Wrong gate in a compute block

```python theme={null}
@coherent
def broken(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: h(anc[0]))  # H is not a permutation gate
        phase(lambda: z(anc[0]))
        uncompute()

# DSLValidationError: gate H is not allowed in exact compute blocks
```

**Fix:** Use only permutation gates in `compute()`: `x`, `cx`, `ccx`, `swap`, `mcx`.

### Wrong gate in a phase block

```python theme={null}
@coherent
def broken(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: h(anc[0]))  # H is not diagonal
        uncompute()

# DSLValidationError: gate H is not allowed in exact phase blocks
```

**Fix:** Use only diagonal gates in `phase()`: `z`, `s`, `sdg`, `t`, `tdg`, `cz`, `ccz`, `mcz`.

### Missing uncompute

```python theme={null}
@coherent
def broken(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: z(anc[0]))
        # forgot uncompute()

# DSLValidationError: ancilla block exited with incomplete cycle
```

**Fix:** Every `compute / phase` cycle must be closed with `uncompute()`.

### Parameterized rotation in @coherent

```python theme={null}
@coherent
def broken(sys: QReg):
    rx(0.5, sys[0])  # arbitrary rotation not in the exact gate set

# DSLValidationError: gate 'rx' is not allowed in @coherent
```

**Fix:** Use `@parametric` instead of `@coherent` when you need arbitrary rotation angles like `rx`, `ry`, `rz`, `cry`, or `crz`.

### Calling @coherent outside build context

```python theme={null}
oracle(my_reg)  # called directly, not inside build_exact

# DSLValidationError: oracle is an exact DSL function;
# use oracle.build_exact(...) to produce an ExactProgram
```

**Fix:** Always call `.build_exact(("name", size), ...)` to produce a program.

## Exact gate set

The following gates are available in `@coherent` programs:

| Gate               | Single-qubit | Multi-qubit |
| ------------------ | ------------ | ----------- |
| Pauli X            | `x`          | —           |
| Hadamard           | `h`          | —           |
| Pauli Z            | `z`          | —           |
| S / S†             | `s`, `sdg`   | —           |
| T / T†             | `t`, `tdg`   | —           |
| Controlled-X       | —            | `cx`        |
| Controlled-Z       | —            | `cz`        |
| SWAP               | —            | `swap`      |
| Toffoli            | —            | `ccx`       |
| CCZ                | —            | `ccz`       |
| Multi-controlled X | —            | `mcx`       |
| Multi-controlled Z | —            | `mcz`       |

Parameterized rotations (`rx`, `ry`, `rz`, `cry`, `crz`) are not part of the exact gate set. Use `@parametric` for those.
