Skip to main content
Every b01t program starts with a decorator. The decorator you choose determines which gates are available, what safety guarantees the resulting program carries, and which build method you call to materialise the circuit. There are four decorators: @coherent and @primitive for the exact gate set, and @parametric and @adaptive for programs that require arbitrary-angle rotations or classical feedback.

Overview

@coherent is the primary decorator for safe quantum programming. It enforces the exact gate set, requires all ancillae to be managed through the compute/phase/uncompute discipline, and produces an ExactProgram with Certification.SAFE. Every @coherent program that builds successfully is a proven unitary channel.
Use @coherent when:
  • You are writing a quantum subroutine intended for production use
  • You need the Hero Theorem guarantee (proven unitary channel)
  • Your circuit uses only gates from the exact gate set
  • You want b01t to certify ancilla cleanliness for you

Comparison table

.build_exact() vs .build()

The build method you use depends on which decorator you used.

.build_exact() — for @coherent and @primitive

build_exact() is a method on ExactDSLFunction (the type returned by @coherent and @primitive). It takes one or more register specifications as (name, size) tuples, runs the validation pipeline, and returns an immutable ExactProgram.
The order of (name, size) tuples must match the order of the function’s register parameters. b01t binds each QReg argument by position.

.build() — for @parametric and @adaptive

build() is a method on DSLFunction (returned by @parametric and @adaptive). It has the same call signature as build_exact() but returns an IRProgram instead.
Do not call a @coherent or @primitive function with .build() — those are ExactDSLFunction instances and only expose .build_exact(). Likewise, .build_exact() is not available on @parametric or @adaptive functions.

Calling decorated functions inside other decorated functions

You can call one decorated function from inside another, with some restrictions:
  • A @coherent function can call another @coherent function freely.
  • A @coherent function cannot call a @primitive function outside a compute() or phase() block. If you need to use a @primitive subroutine at the top level, declare the caller @primitive as well.
  • A @parametric or @adaptive function can call @coherent and @primitive functions (they are subsumed).
  • A @parametric function cannot call an @adaptive function — coherent functions cannot contain measurements.