Skip to main content
Decorators are the entry point for every b01t program. You apply a decorator to a Python function that accepts QReg arguments, and b01t wraps it in a typed object — either an ExactDSLFunction or a DSLFunction — that you call .build_exact() or .build() on to produce a compiled program. Your choice of decorator determines which gates are allowed, what certification the program receives, and whether classical branching is permitted.

@coherent

@coherent wraps the decorated function in an ExactDSLFunction with Certification.SAFE. Use it for programs that must be fully ancilla-certified — every ancilla qubit is guaranteed to return to |0⟩ by construction. The compiler enforces the complete ancilla discipline (compute / phase / uncompute) and rejects any gate not in the exact gate set ({X, H, Z, S, S†, T, T†, CX, CZ, SWAP, CCX, CCZ, MCX, MCZ}). When to use: whenever you need a structurally certified unitary channel. The hero theorem applies: if .build_exact() succeeds, the program is provably safe. Key rules:
  • Only exact gates are allowed. rx, ry, rz, cry, crz raise DSLValidationError.
  • measure is forbidden.
  • if_then is forbidden.
  • Ancilla blocks must complete at least one full compute / phase (or apply) / uncompute cycle.
  • A @coherent function may not call a @primitive function outside of an ancilla compute or phase block.

@primitive

@primitive wraps the decorated function in an ExactDSLFunction with Certification.PRIMITIVE. The gate set and syntax rules are identical to @coherent, but scratch registers are caller-managed rather than certified by the compiler. Use @primitive for low-level building blocks where you manage ancilla cleanliness yourself, or where the ancilla is shared with the calling function. When to use: for subroutines that intentionally leave ancilla in a non-zero state for a caller to clean up, or for inner routines that are called from within a compute or phase block of a @coherent function. Key rules:
  • Same exact gate set as @coherent.
  • A @coherent function can call a @primitive function only from inside a compute(...) or phase(...) block.
  • Calling a @primitive function at the top level of a @coherent body raises DSLValidationError.

@parametric

@parametric wraps the decorated function in a DSLFunction with Effect.COHERENT. It unlocks the parametric rotation gates (rx, ry, rz, cry, crz) while keeping unitary semantics — no measurement, no classical branching. The resulting IRProgram has effect = Effect.COHERENT. When to use: variational algorithms (VQE, QAOA) and any circuit that needs continuous-angle rotations. Programs that pass the safety checker (is_safe_program) are marked is_safe = True in the returned IRProgram. Key rules:
  • All exact gates plus rx, ry, rz, cry, crz are allowed.
  • measure and if_then are forbidden.
  • A @parametric function cannot call an @adaptive function.

@adaptive

@adaptive wraps the decorated function in a DSLFunction with Effect.ADAPTIVE. Adaptive programs can measure qubits and branch on classical results via if_then. The returned IRProgram has effect = Effect.ADAPTIVE and is_safe = False (adaptive programs are never safe by the safety model). When to use: measurement-based protocols, quantum error correction, and teleportation circuits that require mid-circuit measurement and feed-forward. Key rules:
  • All gates from both the exact and parametric sets are allowed.
  • measure, measure_all, and if_then are allowed.
  • An @adaptive function can call @parametric functions, but not vice versa.

ExactDSLFunction.build_exact()

Compiles a @coherent or @primitive function into an ExactProgram.
arg_specs
tuple[str, int] | QReg
required
One argument per register in the decorated function. Each argument is either a ("name", size) tuple or an existing QReg object. Register names must be unique.
Returns: ExactProgram with fields name, regs, ops, and certification. Raises: DSLValidationError if any gate, ancilla, or structural rule is violated during the build.

DSLFunction.build()

Compiles a @parametric or @adaptive function into an IRProgram.
arg_specs
tuple[str, int] | QReg
required
One argument per register in the decorated function. Each argument is either a ("name", size) tuple or an existing QReg object. Register names must be unique.
Returns: IRProgram with fields name, effect, regs, ops, and is_safe. Raises: DSLValidationError if any rule is violated during the build.