Compiling Circuits¶
Clifft compiles a supported circuit input into a reusable Program. Compilation resolves Clifford coordinates, symbolic dependencies, active-state transitions, and executable actions before sampling starts.
Most users only need clifft.compile(). The lower-level functions expose the same pipeline for inspecting intermediate representations or supplying a custom optimization sequence.
Default path¶
Pass circuit text directly to clifft.compile():
The returned program can be reused by ordinary sampling, survivor sampling, fixed-fault importance sampling, or an exact-query API when the circuit meets that API's requirements:
Compilation options such as postselection_mask, normalize_syndromes, expected_detectors, and expected_observables define the result contract used during sampling.
For detector-based post-selection, set normalize_syndromes=True unless raw measurement parities are intentional. Clifft computes the noiseless detector and observable reference once during compilation and stores the normalization in the program. sample_survivors() then applies the post-selection mask to those normalized detector values; it does not recompute the reference per call.
Circuits containing LEAKAGE, LOSS, or LEVEL_TRANSITION annotations take a trajectory-specific path. Pass the circuit and model to clifft.noncomp.sample() rather than compiling one fixed program first; see Leakage and Loss.
Inspect or customize the pipeline¶
The following APIs are intended for power users working on compiler behavior, custom optimization, or intermediate-representation inspection.
Parse the circuit¶
clifft.parse() returns a Circuit without tracing or lowering it:
Use clifft.parse_file() for a file, or the format-specific parsing functions listed on Circuit Inputs for OpenQASM 2.
Trace to the Heisenberg IR¶
clifft.trace() absorbs Clifford operations into an offline tableau and emits explicit non-Clifford operations, measurements, noise, and classical outputs in the Heisenberg frame:
Optimize the HIR¶
The default pass manager applies the same HIR optimization sequence used by clifft.compile():
import clifft
hir = clifft.trace(clifft.parse("H 0\nCNOT 0 1\nT 0\nM 0 1"))
clifft.default_hir_pass_manager().run(hir)
Construct a focused pipeline when individual passes need to be controlled:
import clifft
hir = clifft.trace(clifft.parse("H 0\nT 0\nM 0"))
passes = clifft.HirPassManager()
passes.add(clifft.PeepholeFusionPass())
passes.run(hir)
Pass hir_passes=None to clifft.compile() to skip HIR optimization while keeping the one-step API.
Plan and prepare execution¶
clifft.lower() converts an optimized HirModule into the same public Program type returned by clifft.compile():
import clifft
hir = clifft.trace(clifft.parse("H 0\nT 0\nM 0"))
clifft.default_hir_pass_manager().run(hir)
program = clifft.lower(hir)
Internally, lowering first creates a semantic sampling plan that selects active coordinates and records expressions, rotations, measurements, width transitions, and outputs. Executable preparation then creates the immutable descriptors and dependency tables used by the executor and selects supported scalar or SIMD kernels.
These decisions happen before execution. Runtime kernels do not evolve a tableau, choose coordinates, localize Paulis, or discover dependencies. See Software Architecture for the contracts between HIR, semantic planning, executable preparation, and shot execution.