@coherent requires. When you need arbitrary rotation angles — like rx(0.785, q) — use @parametric. When your program needs to measure qubits and branch on the results, use @adaptive. Both decorators produce an IRProgram via .build(), the broad-IR compilation path.
@parametric: coherent programs with rotations
@parametric marks a function as a coherent (unitary) program that may use rotation gates with arbitrary float angles. The gate set includes everything in @coherent plus rx, ry, rz, cry, and crz.
IRProgram with .build(), passing register specs for the QReg parameters. Classical parameters like theta and phi are regular Python values — you pass them at build time as additional arguments after the register specs.
@parametric and @coherent both produce unitary programs, but @coherent uses the exact gate set and provides a machine-checked safety certification. Use @parametric when you need rotation angles; use @coherent when you want the strongest correctness guarantees.@adaptive: measurement and classical feedback
@adaptive marks a function as a program that may measure qubits and branch on classical results. Use measure(q) to measure a single qubit or measure_all(reg) to measure all qubits in a register. Use if_then() from b01t.kit to branch on a measurement result.
@adaptive function the same way — with .build() and register specs:
Control flow
Theb01t.kit module provides three control-flow helpers for use inside @parametric and @adaptive functions.
repeat(count, body)
Repeat a body lambda a fixed number of times at build time. Useful for Grover iterations, variational circuit layers, or any fixed-repetition pattern.for_each(data, body)
Iterate over classical data at build time, emitting parameterized gates for each element. The body receives an index and the current data element.if_then(cond, then_body, else_body)
Branch on a classical condition — typically a measurement result from an earliermeasure() or measure_all() call. Only valid in @adaptive functions.
if_then() raises DSLValidationError if called inside a @coherent function. Classical branching is not allowed in unitary programs.Complete example: Grover search
The Grover search demo combines@parametric and @adaptive. The oracle and diffusion are @parametric (they are unitary subroutines), and the outer search loop is @adaptive (it measures at the end).
Calling @parametric from @adaptive
@parametric functions are unitary subroutines, so they can be called freely from inside @adaptive functions. The Grover example above shows this pattern: grover_step is @parametric and is called inside grover_search which is @adaptive.
The repeat() helper works in both @parametric and @adaptive contexts.