Skip to content

Python API Reference

Compilation

clifft.compile

compile(
    stim_text: str,
    postselection_mask: list[int] | None = None,
    expected_detectors: list[int] | None = None,
    expected_observables: list[int] | None = None,
    normalize_syndromes: bool = False,
    hir_passes: HirPassManager
    | None
    | _DefaultPasses = _DEFAULT_PASSES,
    input_format: Literal["stim", "qasm2"] = "stim",
) -> Program

Compile a quantum circuit string to an executable sampling program.

Ordinary compilation runs parse -> trace -> [HIR optimize], then plans and prepares the result as a reusable sampling program.

When normalize_syndromes=True, a noiseless reference shot is executed internally to extract expected detector and observable parities. Detectors and observables are then XOR-normalized so that 0 means 'matches noiseless reference' and 1 means 'error'.

Parameters:

Name Type Description Default
stim_text str

Circuit text in the format selected by input_format.

required
postselection_mask list[int] | None

Optional list of uint8 flags, one per detector. Detectors where mask[i] != 0 become post-selection checks that abort the shot early if their parity is non-zero.

None
expected_detectors list[int] | None

Optional noiseless reference parities for detectors.

None
expected_observables list[int] | None

Optional noiseless reference parities for observables.

None
normalize_syndromes bool

If True, auto-compute reference parities from a noiseless reference shot (mutually exclusive with explicit parities).

False
hir_passes HirPassManager | None | _DefaultPasses

HirPassManager to run on the HIR before lowering. Defaults to default_hir_pass_manager(). Pass None to skip.

_DEFAULT_PASSES
input_format Literal['stim', 'qasm2']

"stim" for Clifft's Stim-compatible syntax or "qasm2" for the supported unitary OpenQASM 2 subset.

'stim'
Source code in clifft/__init__.py
def compile(
    stim_text: str,
    postselection_mask: list[int] | None = None,
    expected_detectors: list[int] | None = None,
    expected_observables: list[int] | None = None,
    normalize_syndromes: bool = False,
    hir_passes: HirPassManager | None | _DefaultPasses = _DEFAULT_PASSES,
    input_format: Literal["stim", "qasm2"] = "stim",
) -> Program:
    """Compile a quantum circuit string to an executable sampling program.

    Ordinary compilation runs parse -> trace -> [HIR optimize], then plans and
    prepares the result as a reusable sampling program.

    When ``normalize_syndromes=True``, a noiseless reference shot is
    executed internally to extract expected detector and observable
    parities. Detectors and observables are then XOR-normalized so
    that 0 means 'matches noiseless reference' and 1 means 'error'.

    Args:
        stim_text: Circuit text in the format selected by ``input_format``.
        postselection_mask: Optional list of uint8 flags, one per detector.
            Detectors where mask[i] != 0 become post-selection checks
            that abort the shot early if their parity is non-zero.
        expected_detectors: Optional noiseless reference parities for detectors.
        expected_observables: Optional noiseless reference parities for observables.
        normalize_syndromes: If True, auto-compute reference parities from a
            noiseless reference shot (mutually exclusive with explicit parities).
        hir_passes: HirPassManager to run on the HIR before lowering.
            Defaults to ``default_hir_pass_manager()``. Pass ``None`` to skip.
        input_format: ``"stim"`` for Clifft's Stim-compatible syntax or
            ``"qasm2"`` for the supported unitary OpenQASM 2 subset.
    """
    if isinstance(hir_passes, _DefaultPasses):
        hir_passes = default_hir_pass_manager()
    if input_format == "stim":
        compile_core = _compile_core
    elif input_format == "qasm2":
        compile_core = _compile_qasm2_core
    else:
        raise ValueError("input_format must be 'stim' or 'qasm2'")
    return compile_core(
        stim_text,
        postselection_mask if postselection_mask is not None else [],
        expected_detectors if expected_detectors is not None else [],
        expected_observables if expected_observables is not None else [],
        normalize_syndromes,
        hir_passes,
    )

clifft.parse

parse(text: str) -> Circuit
parse(text: str, max_ops: int) -> Circuit

parse(text: str) -> clifft._clifft_core.Circuit parse(text: str, max_ops: int) -> clifft._clifft_core.Circuit

Overloaded function.

  1. parse(text: str) -> clifft._clifft_core.Circuit

Parse a quantum circuit from a string.

  1. parse(text: str, max_ops: int) -> clifft._clifft_core.Circuit

Parse a quantum circuit from a string with an explicit AST node limit.

clifft.parse_file

parse_file(path: str) -> Circuit
parse_file(path: str, max_ops: int) -> Circuit

parse_file(path: str) -> clifft._clifft_core.Circuit parse_file(path: str, max_ops: int) -> clifft._clifft_core.Circuit

Overloaded function.

  1. parse_file(path: str) -> clifft._clifft_core.Circuit

Parse a quantum circuit from a file.

  1. parse_file(path: str, max_ops: int) -> clifft._clifft_core.Circuit

Parse a quantum circuit from a file with an explicit AST node limit.

clifft.parse_qasm2

parse_qasm2(text: str) -> Qasm2Import
parse_qasm2(text: str, max_ops: int) -> Qasm2Import

parse_qasm2(text: str) -> clifft._clifft_core.Qasm2Import parse_qasm2(text: str, max_ops: int) -> clifft._clifft_core.Qasm2Import

Overloaded function.

  1. parse_qasm2(text: str) -> clifft._clifft_core.Qasm2Import

Parse and lower a unitary OpenQASM 2 circuit.

  1. parse_qasm2(text: str, max_ops: int) -> clifft._clifft_core.Qasm2Import

Parse and lower a unitary OpenQASM 2 circuit with an explicit AST node limit.

clifft.parse_qasm2_file

parse_qasm2_file(path: str) -> Qasm2Import
parse_qasm2_file(path: str, max_ops: int) -> Qasm2Import

parse_qasm2_file(path: str) -> clifft._clifft_core.Qasm2Import parse_qasm2_file(path: str, max_ops: int) -> clifft._clifft_core.Qasm2Import

Overloaded function.

  1. parse_qasm2_file(path: str) -> clifft._clifft_core.Qasm2Import

Parse and lower a unitary OpenQASM 2 circuit file.

  1. parse_qasm2_file(path: str, max_ops: int) -> clifft._clifft_core.Qasm2Import

Parse and lower a unitary OpenQASM 2 file with an explicit AST node limit.

clifft.trace

trace(circuit: Circuit) -> HirModule

trace(circuit: clifft._clifft_core.Circuit) -> clifft._clifft_core.HirModule

Trace a parsed circuit through the Clifford front-end to produce the Heisenberg IR. Single-qubit rotations within 1e-12 half-turns of a Clifford angle are canonicalized.

clifft.lower

lower(
    hir: HirModule,
    postselection_mask: Sequence[int] = [],
    expected_detectors: Sequence[int] = [],
    expected_observables: Sequence[int] = [],
) -> Program

lower(hir: clifft._clifft_core.HirModule, postselection_mask: collections.abc.Sequence[int] = [], expected_detectors: collections.abc.Sequence[int] = [], expected_observables: collections.abc.Sequence[int] = []) -> clifft._clifft_core.Program

Lower a Heisenberg IR module to an executable sampling program.

Parameters:

Name Type Description Default
hir HirModule

The Heisenberg IR module to lower.

required
postselection_mask Sequence[int]

Optional list of uint8 flags, one per detector. Detectors where mask[i] != 0 become post-selection checks that abort the shot early if their parity is non-zero.

[]
expected_detectors Sequence[int]

Optional noiseless reference parities for detectors.

[]
expected_observables Sequence[int]

Optional noiseless reference parities for observables.

[]

clifft.ParseError

Bases: builtins.Exception

Sampling

The four fixed-plan functions share CPU batching and threading arguments. See CPU Execution and Tuning for their interaction and compatibility limits.

clifft.sample

sample(
    program: Program,
    shots: int,
    seed: int | None = None,
    threads: int | Literal["auto"] = 1,
    thread_layout: tuple[int, int] | None = None,
    intra_shot_min_active_width: int | None = None,
    batch_size: int | Literal["auto"] = "auto",
) -> clifft.SampleResult

sample(program: Program, shots: int, seed: int | None = None, threads: int | typing.Literal['auto'] = 1, thread_layout: tuple[int, int] | None = None, intra_shot_min_active_width: int | None = None, batch_size: int | typing.Literal['auto'] = 'auto') -> clifft.SampleResult

Run a compiled program and return a SampleResult.

Raises ValueError for post-selected programs because fixed-row output cannot represent discarded shots. Use sample_survivors() instead.

If seed is None (default), uses hardware entropy. threads is a positive total worker budget or 'auto' to use the implementation-reported hardware concurrency; it defaults to 1. Automatic scheduling uses either cross-shot or intra-shot workers. thread_layout=(shot_workers, intra_shot_workers) overrides that choice and ignores threads; intra-shot counts above 1 require OpenMP support. intra_shot_min_active_width overrides the default threshold of 18 for an explicit layout. batch_size='auto' uses the conservative plan policy; 1 forces scalar execution, and a positive integer requests a packed lane-capacity limit. Seeded results replay within one batching configuration, but individual rows may differ between scalar and packed modes or different capacities.

Returns a SampleResult with .measurements, .detectors, .observables attributes. Supports tuple unpacking: m, d, o = clifft.sample(prog, shots)

clifft.sample_survivors

sample_survivors(
    program: Program,
    shots: int,
    seed: int | None = None,
    keep_records: bool = False,
    threads: int | Literal["auto"] = 1,
    thread_layout: tuple[int, int] | None = None,
    intra_shot_min_active_width: int | None = None,
    batch_size: int | Literal["auto"] = "auto",
) -> clifft.SampleResult

sample_survivors(program: Program, shots: int, seed: int | None = None, keep_records: bool = False, threads: int | typing.Literal['auto'] = 1, thread_layout: tuple[int, int] | None = None, intra_shot_min_active_width: int | None = None, batch_size: int | typing.Literal['auto'] = 'auto') -> clifft.SampleResult

Sample shots and return results only for surviving (non-discarded) shots.

If seed is None (default), uses hardware entropy. threads is a positive total worker budget or 'auto' to use the implementation-reported hardware concurrency; it defaults to 1. thread_layout=(shot_workers, intra_shot_workers) overrides automatic scheduling. intra_shot_min_active_width overrides the default threshold of 18 for an explicit layout. batch_size='auto' uses the conservative plan policy and remains scalar when the program has postselection; 1 forces scalar execution, and a positive integer requests a packed lane-capacity limit.

Returns a SampleResult. Survivor metadata is always populated via .total_shots, .passed_shots, .discards, .logical_errors, and .observable_ones. Per-shot record arrays (.measurements, .detectors, .observables, .exp_vals) are only filled when keep_records=True; otherwise they are empty (rows=0).

clifft.sample_k

sample_k(
    program: Program,
    shots: int,
    k: int,
    seed: int | None = None,
    threads: int | Literal["auto"] = 1,
    thread_layout: tuple[int, int] | None = None,
    intra_shot_min_active_width: int | None = None,
    batch_size: int | Literal["auto"] = "auto",
) -> clifft.SampleResult

sample_k(program: Program, shots: int, k: int, seed: int | None = None, threads: int | typing.Literal['auto'] = 1, thread_layout: tuple[int, int] | None = None, intra_shot_min_active_width: int | None = None, batch_size: int | typing.Literal['auto'] = 'auto') -> clifft.SampleResult

Sample with exactly k forced faults per shot (importance sampling).

Sites are drawn from the exact conditional Poisson-Binomial distribution. Results are conditioned on K=k and must be combined across strata with P(K=k) weights for correct error rate estimation. Raises ValueError for post-selected programs because fixed-row output cannot represent discarded shots. Use sample_k_survivors() instead.

For post-selected circuits, weight numerator and denominator separately via sample_k_survivors(): p_fail = sum(P(K=k)errors_k/shots_k) / sum(P(K=k)passed_k/shots_k).

Raises ValueError if the k-fault stratum has zero probability mass (e.g. k exceeds the number of non-zero-probability sites).

When all site probabilities are equal, an O(k) Fisher-Yates sampler is used automatically. threads is a positive total worker budget or 'auto' to use the implementation-reported hardware concurrency; it defaults to 1. thread_layout=(shot_workers, intra_shot_workers) overrides automatic scheduling. intra_shot_min_active_width overrides the default threshold of 18 for an explicit layout. batch_size='auto' uses the conservative plan policy; 1 forces scalar execution, and a positive integer requests a packed lane-capacity limit.

Returns a SampleResult with .measurements, .detectors, .observables attributes. Supports tuple unpacking: m, d, o = clifft.sample_k(prog, shots, k)

clifft.sample_k_survivors

sample_k_survivors(
    program: Program,
    shots: int,
    k: int,
    seed: int | None = None,
    keep_records: bool = False,
    threads: int | Literal["auto"] = 1,
    thread_layout: tuple[int, int] | None = None,
    intra_shot_min_active_width: int | None = None,
    batch_size: int | Literal["auto"] = "auto",
) -> clifft.SampleResult

sample_k_survivors(program: Program, shots: int, k: int, seed: int | None = None, keep_records: bool = False, threads: int | typing.Literal['auto'] = 1, thread_layout: tuple[int, int] | None = None, intra_shot_min_active_width: int | None = None, batch_size: int | typing.Literal['auto'] = 'auto') -> clifft.SampleResult

Sample survivors with exactly k forced faults per shot.

Results are conditioned on K=k. To estimate the overall logical error rate across strata, weight numerator and denominator separately to account for k-dependent survival probability: p_fail = sum(P(K=k)logical_errors_k/shots_k) / sum(P(K=k)passed_k/shots_k)

Raises ValueError if the k-fault stratum has zero probability mass. threads is a positive total worker budget or 'auto' to use the implementation-reported hardware concurrency; it defaults to 1. thread_layout=(shot_workers, intra_shot_workers) overrides automatic scheduling. intra_shot_min_active_width overrides the default threshold of 18 for an explicit layout. batch_size='auto' uses the conservative plan policy and remains scalar when the program has postselection; 1 forces scalar execution, and a positive integer requests a packed lane-capacity limit.

Returns a SampleResult. Survivor metadata is always populated via .total_shots, .passed_shots, .discards, .logical_errors, and .observable_ones. Per-shot record arrays (.measurements, .detectors, .observables, .exp_vals) are only filled when keep_records=True; otherwise they are empty (rows=0).

Experimental Hardware Backends

Experimental

These APIs require backend-specific source builds and may change without compatibility guarantees. They are not selected by the regular CPU API.

See HIP Backend for the current hardware and workflow limits.

clifft.experimental.hip.is_built

is_built() -> bool

Return whether this Clifft installation contains the HIP extension.

Source code in clifft/experimental/hip.py
def is_built() -> bool:
    """Return whether this Clifft installation contains the HIP extension."""
    return _NATIVE_SPEC is not None

clifft.experimental.hip.is_available

is_available() -> bool

Return whether the extension loaded and can see an AMD GPU.

Source code in clifft/experimental/hip.py
def is_available() -> bool:
    """Return whether the extension loaded and can see an AMD GPU."""
    return _native is not None and bool(_native.is_available())

clifft.experimental.hip.backend_info

backend_info() -> str

Describe the optional extension and any devices visible to HIP.

Source code in clifft/experimental/hip.py
def backend_info() -> str:
    """Describe the optional extension and any devices visible to HIP."""
    if _NATIVE_SPEC is None:
        return "HIP backend not built; rebuild Clifft with CLIFFT_ENABLE_HIP=ON"
    if _native is None:
        return f"HIP extension failed to load: {_native_error}"
    return cast(str, _native.backend_info())

clifft.experimental.hip.compile

compile(
    stim_text: str,
    postselection_mask: list[int] | None = None,
    expected_detectors: list[int] | None = None,
    expected_observables: list[int] | None = None,
    normalize_syndromes: bool = False,
    hir_passes: HirPassManager
    | None
    | _DefaultPasses = _DEFAULT_PASSES,
) -> Program

Compile Stim text through the shared HIR and SamplingPlan pipeline.

Source code in clifft/experimental/hip.py
def compile(
    stim_text: str,
    postselection_mask: list[int] | None = None,
    expected_detectors: list[int] | None = None,
    expected_observables: list[int] | None = None,
    normalize_syndromes: bool = False,
    hir_passes: HirPassManager | None | _DefaultPasses = _DEFAULT_PASSES,
) -> Program:
    """Compile Stim text through the shared HIR and SamplingPlan pipeline."""
    if isinstance(hir_passes, _DefaultPasses):
        hir_passes = default_hir_pass_manager()
    prepared = _prepare_hir_for_lowering(
        stim_text,
        expected_detectors if expected_detectors is not None else [],
        expected_observables if expected_observables is not None else [],
        normalize_syndromes,
        hir_passes,
    )
    hir = cast(HirModule, prepared[0])
    detectors = cast(list[int], prepared[1])
    observables = cast(list[int], prepared[2])
    return lower(hir, postselection_mask, detectors, observables)

clifft.experimental.hip.Program

Program(native: Any)

An immutable, backend-private lowering of a SamplingPlan.

Source code in clifft/experimental/hip.py
def __init__(self, native: Any) -> None:
    self._native = native

num_records property

num_records: int

Return the visible plus hidden record width required by replay.

inspect

inspect() -> str

Return diagnostic text for the packed executable.

Source code in clifft/experimental/hip.py
def inspect(self) -> str:
    """Return diagnostic text for the packed executable."""
    return cast(str, self._native.inspect())

clifft.experimental.hip.Sampler

Sampler(
    program: Program,
    *,
    precision: Precision = "fp64",
    max_batch_shots: int | None = None,
)

A synchronous sampler with one uploaded program and retained workspace.

Calls on one instance must not overlap. Use a separate sampler per caller.

Source code in clifft/experimental/hip.py
def __init__(
    self,
    program: Program,
    *,
    precision: Precision = "fp64",
    max_batch_shots: int | None = None,
) -> None:
    native = _require_native()
    self.program = program
    native_precision = _precision_value(precision)
    if max_batch_shots is None:
        self._native = native.Sampler(program._native, native_precision)
    else:
        self._native = native.Sampler(program._native, native_precision, max_batch_shots)

replay_shot

replay_shot(forced_records: list[int]) -> ReplayResult

Force every record value to probe one measurement branch exactly.

Source code in clifft/experimental/hip.py
def replay_shot(self, forced_records: list[int]) -> ReplayResult:
    """Force every record value to probe one measurement branch exactly."""
    result = self._native.replay_shot(forced_records)
    return ReplayResult(
        reachable=cast(bool, result["reachable"]),
        survived=cast(bool, result["survived"]),
        log_probability=cast(float, result["log_probability"]),
        outputs=cast(SampleResult, result["outputs"]),
    )

sample

sample(
    shots: int,
    *,
    seed: int | None = None,
    block_size: int | None = None,
) -> SampleResult

Sample fixed rows while reusing the retained device workspace.

Source code in clifft/experimental/hip.py
def sample(
    self,
    shots: int,
    *,
    seed: int | None = None,
    block_size: int | None = None,
) -> SampleResult:
    """Sample fixed rows while reusing the retained device workspace."""
    if block_size is None:
        return cast(SampleResult, self._native.sample(shots, seed))
    return cast(SampleResult, self._native.sample(shots, seed, block_size))

sample_survivors

sample_survivors(
    shots: int,
    *,
    keep_records: bool = False,
    seed: int | None = None,
    block_size: int | None = None,
) -> SampleResult

Sample and retain only shots that pass postselection.

Source code in clifft/experimental/hip.py
def sample_survivors(
    self,
    shots: int,
    *,
    keep_records: bool = False,
    seed: int | None = None,
    block_size: int | None = None,
) -> SampleResult:
    """Sample and retain only shots that pass postselection."""
    if block_size is None:
        return cast(
            SampleResult,
            self._native.sample_survivors(shots, keep_records, seed),
        )
    return cast(
        SampleResult,
        self._native.sample_survivors(shots, keep_records, seed, block_size),
    )

clifft.experimental.hip.ReplayResult dataclass

ReplayResult(
    reachable: bool,
    survived: bool,
    log_probability: float,
    outputs: SampleResult,
)

Result of one forced-record path through the HIP interpreter.

Leakage and Loss

Sampling under a five-level leakage/loss model. See the Leakage and Loss guide.

clifft.noncomp.sample

sample(
    circuit: Circuit | str,
    model: Model,
    shots: int,
    seed: int | None = None,
    max_active_width: int | None = None,
    threads: int | Literal["auto"] = 1,
) -> NonComputationalSample

Sample circuit under model for shots shots.

On a leaked or lost site, M, MX, MY, MR, MRX, and MRY sample the classifier without regard to measurement basis. A model that can leak or lose sites requires a classifier when the circuit measures a physical site. Parity measurements (MPP) and EXP_VAL probes are not supported with such models.

Continuations are compiled with the default optimization passes that preserve measurement-record order and instrument-prefix stability, omitting StatevectorSqueezePass. Reordering can change the placement of internal collapse outcomes relative to later records. This API does not currently accept custom pass managers.

Parameters:

Name Type Description Default
circuit Circuit | str

Parsed clifft.Circuit or Stim-format circuit string.

required
model Model

Leakage and loss model.

required
shots int

Number of trajectories to sample.

required
seed int | None

Seed for reproducible sampling. The same seed and arguments produce identical results. When None, each call uses fresh OS entropy.

None
max_active_width int | None

Optional cap on the peak active width of every compiled continuation. The check is conservative because a continuation may contain branches that the current shot will not take.

None
threads int | Literal['auto']

Number of cross-shot workers. Defaults to 1. Pass "auto" to use the implementation-reported hardware concurrency. Seeded results are identical for every worker count.

1

Returns:

Type Description
NonComputationalSample
NonComputationalSample

containing measurement, detector, observable, herald, and final-status

NonComputationalSample

arrays.

Raises:

Type Description
ValueError

If a model or circuit contract is violated, an annotation is malformed, or a continuation exceeds max_active_width.

Source code in clifft/noncomp.py
def sample(
    circuit: Circuit | str,
    model: Model,
    shots: int,
    seed: int | None = None,
    max_active_width: int | None = None,
    threads: int | Literal["auto"] = 1,
) -> NonComputationalSample:
    """Sample ``circuit`` under ``model`` for ``shots`` shots.

    On a leaked or lost site, ``M``, ``MX``, ``MY``, ``MR``, ``MRX``, and
    ``MRY`` sample the classifier without regard to measurement basis. A model
    that can leak or lose sites requires a classifier when the circuit
    measures a physical site. Parity measurements (``MPP``) and ``EXP_VAL``
    probes are not supported with such models.

    Continuations are compiled with the default optimization passes that
    preserve measurement-record order and instrument-prefix stability, omitting
    [StatevectorSqueezePass][clifft.StatevectorSqueezePass]. Reordering can
    change the placement of internal collapse outcomes relative to later
    records. This API does not currently accept custom pass managers.

    Args:
        circuit: Parsed ``clifft.Circuit`` or Stim-format circuit string.
        model: Leakage and loss model.
        shots: Number of trajectories to sample.
        seed: Seed for reproducible sampling. The same seed and arguments
            produce identical results. When ``None``, each call uses fresh OS
            entropy.
        max_active_width: Optional cap on the peak active width of every compiled
            continuation. The check is conservative because a continuation
            may contain branches that the current shot will not take.
        threads: Number of cross-shot workers. Defaults to 1. Pass ``"auto"``
            to use the implementation-reported hardware concurrency. Seeded
            results are identical for every worker count.

    Returns:
        [NonComputationalSample][clifft.noncomp.NonComputationalSample]
        containing measurement, detector, observable, herald, and final-status
        arrays.

    Raises:
        ValueError: If a model or circuit contract is violated, an annotation
            is malformed, or a continuation exceeds ``max_active_width``.
    """
    return _sample_with(
        circuit,
        model,
        shots,
        seed,
        max_active_width,
        threads,
        _clifft_core._sample_noncomputational,
    )

clifft.noncomp.Model

Model(
    initial_state: Sequence[float] | None = None,
    transitions: Mapping[str, Matrix] | None = None,
    classifier: Classifier | None = None,
    reset_restores_lost: bool = False,
    damping: str = "exact",
)

A noncomputational trajectory model over the built-in five-level set.

Parameters:

Name Type Description Default
initial_state Sequence[float] | None

probability per level, P(level), summing to one. Defaults to [1.0, 0.0, 0.0, 0.0, 0.0] (all qubits start in the ground state).

None
transitions Mapping[str, Matrix] | None

maps a name to its T[to][from] matrix. A key that names a gate (e.g. "CZ") is a hook: it expands to a LEVEL_TRANSITION[key] annotation after every occurrence of that gate. A key naming a recognized instruction that cannot be hooked is rejected, since it would otherwise look like a hook that never fires. These include noise channels and annotations, as well as instructions that never parse into a node of their own: MXX/MYY/MZZ (desugared to MPP), CH/CCX/CCZ (decomposed by the parser), and identity no-ops. Annotate those positions explicitly instead. Any key -- whether an arbitrary name or a hookable gate name -- can be referenced directly from the circuit with LEVEL_TRANSITION[key] q. LEAKAGE(p) q applies source-preserving leakage inline, while LOSS(p) q applies uniform loss. A transition fires at its circuit position, with the source taken from the qubit's state there.

None
classifier Classifier | None

Optional Classifier supplying leaked/lost measurement outcomes and computational readout confusion.

None
reset_restores_lost bool

if true, a reset on a lost qubit restores it to a computational state; if false (default), the reset acts on the vacated site and is dropped.

False
damping str

handling of the no-transition update when the total transition probability differs between g and e for a coherent qubit that is not yet represented in the state vector. "exact" (the default) adds the qubit to the state vector at that site, increasing peak active width by one. "neglect" avoids the expansion but omits the state update caused by observing that no transition occurred. It is exact when g and e have the same total transition probability; otherwise the bias is of order |p_g - p_e|.

'exact'

An operation with no representable effect on a leaked or lost operand -- e.g. a two-qubit gate onto a vacated site -- is dropped, acting as the identity on the surviving operands. Single-qubit measurements (M, MX, MY) keep their record slot; once the qubit has left the computational subspace the readout basis is incidental and the classifier supplies the bit. A measure-and-reset (MR/MRX/MRY) keeps its record the same way; its reset half re-prepares the site only when the reset restores it (a leaked qubit always; a lost qubit only with reset_restores_lost). Parity measurements (MPP) are not supported when the model can leak or lose qubits -- they have no faithful single-bit classifier substitution -- and raise before sampling begins. A model that can leak or lose qubits also requires a classifier when the circuit measures a qubit.

Construction validates shapes, probabilities, gate keys, policy values, and level table consistency, raising ValueError on any problem.

Source code in clifft/noncomp.py
def __init__(
    self,
    initial_state: Sequence[float] | None = None,
    transitions: Mapping[str, Matrix] | None = None,
    classifier: Classifier | None = None,
    reset_restores_lost: bool = False,
    damping: str = "exact",
) -> None:
    if initial_state is None:
        initial_state = [1.0, 0.0, 0.0, 0.0, 0.0]
    transition_matrices = {
        str(gate): _as_matrix(matrix) for gate, matrix in (transitions or {}).items()
    }
    matrix = None if classifier is None else classifier.matrix
    self._handle = _clifft_core._build_noncomp_model(
        [float(p) for p in initial_state],
        transition_matrices,
        matrix,
        bool(reset_restores_lost),
        str(damping),
    )
    self._transition_keys: list[str] = sorted(transition_matrices.keys())
    self._classifier_rows: int | None = None if classifier is None else len(classifier.matrix)
    self._reset_restores_lost: bool = bool(reset_restores_lost)
    self._damping: str = str(damping)

clifft.noncomp.Classifier

Classifier(matrix: Matrix)

A measurement classifier: P[symbol][level] stochastic matrix.

The matrix must have two or three rows, and every level column must sum to one. The first two rows give the probabilities of recording 0 or 1. An optional third row heralds the measurement, typically for loss. NonComputationalSample.heralds reports that symbol separately while the binary measurement record receives a uniformly sampled placeholder.

For M and MR on a computational site, the g and e columns can model Z-basis readout confusion after the quantum measurement. Computational MX, MY, MRX, and MRY measurements do not use those columns. On a leaked or lost site, every supported single-site measurement uses the corresponding classifier column regardless of basis. A computational column may not assign probability to the herald symbol.

Source code in clifft/noncomp.py
def __init__(self, matrix: Matrix) -> None:
    self.matrix = _as_matrix(matrix)

clifft.noncomp.NonComputationalSample

NonComputationalSample(
    measurements: NDArray[uint8],
    detectors: NDArray[uint8],
    observables: NDArray[uint8],
    final_status: NDArray[uint8],
    heralds: NDArray[uint8],
    num_qubits: int,
    num_measurements: int,
    num_detectors: int,
    num_observables: int,
)

Measurement results and final site statuses returned by sample().

Attributes:

Name Type Description
measurements, (detectors, observables)

uint8 arrays, shape (shots, width).

final_status

uint8 array (shots, num_qubits) of QubitStatus values. Reports the definite noncomputational level per site and shot: LEAK_G and LEAK_E are individually distinguishable. Computational sites report as QubitStatus.COMPUTATIONAL rather than G or E because their state remains quantum in the executor and may not be a definite level.

heralds

uint8 array (shots, num_measurements); 1 where the classifier sampled the herald (third) symbol for that slot, else 0.

shots, (num_qubits, num_measurements, num_detectors, num_observables)

ints.

Source code in clifft/noncomp.py
def __init__(
    self,
    measurements: npt.NDArray[np.uint8],
    detectors: npt.NDArray[np.uint8],
    observables: npt.NDArray[np.uint8],
    final_status: npt.NDArray[np.uint8],
    heralds: npt.NDArray[np.uint8],
    num_qubits: int,
    num_measurements: int,
    num_detectors: int,
    num_observables: int,
) -> None:
    self.measurements = measurements
    self.detectors = detectors
    self.observables = observables
    self.final_status = final_status
    self.heralds = heralds
    self.shots = int(measurements.shape[0])
    self.num_qubits = int(num_qubits)
    self.num_measurements = int(num_measurements)
    self.num_detectors = int(num_detectors)
    self.num_observables = int(num_observables)

symbols

symbols() -> npt.NDArray[np.uint8]

Return measurement symbols, using 2 for heralded slots.

This returns a copy of measurements with each heralded placeholder replaced by 2.

Source code in clifft/noncomp.py
def symbols(self) -> npt.NDArray[np.uint8]:
    """Return measurement symbols, using 2 for heralded slots.

    This returns a copy of ``measurements`` with each heralded placeholder
    replaced by 2.
    """
    out = self.measurements.copy()
    out[self.heralds != 0] = 2
    return out

clifft.noncomp.Level

Bases: IntEnum

Indices of the built-in five-level model, for naming matrix rows/columns.

clifft.noncomp.QubitStatus

Bases: IntEnum

Per-site status stored in NonComputationalSample.final_status.

These are per-site status codes, not matrix indices. Level names matrix rows and columns (indices 0--4); QubitStatus names per-qubit outcomes (codes 0--3). The two enums share member names (LEAK_G, LEAK_E, LOST) with different integer values -- never substitute one for the other.

LEAK_G and LEAK_E are individually distinguishable in final_status, unlike the coarse leaked/lost grouping some tools use.

Strong Simulation

clifft.basis_probabilities

basis_probabilities(
    program: Program,
    bitstrings: BasisBitstrings,
    *,
    bit_order: str = "big",
    return_log: bool = False,
) -> npt.NDArray[np.float64]

Exact Born probabilities of computational-basis bitstrings.

Requires a unitary program (no measurements, feedback, noise, detectors, observables, or post-selection). For circuits with measurements, use :func:record_probabilities instead.

bit_order="big" maps the first character or array column to qubit 0. bit_order="little" maps the last character or array column to qubit 0.

Pass return_log=True to get natural-log probabilities. Zero probabilities map to -inf in log output.

Source code in clifft/__init__.py
def basis_probabilities(
    program: Program,
    bitstrings: BasisBitstrings,
    *,
    bit_order: str = "big",
    return_log: bool = False,
) -> npt.NDArray[np.float64]:
    """Exact Born probabilities of computational-basis bitstrings.

    Requires a unitary program (no measurements, feedback, noise, detectors,
    observables, or post-selection). For circuits with measurements, use
    :func:`record_probabilities` instead.

    ``bit_order="big"`` maps the first character or array column to qubit 0.
    ``bit_order="little"`` maps the last character or array column to qubit 0.

    Pass ``return_log=True`` to get natural-log probabilities. Zero
    probabilities map to ``-inf`` in log output.
    """
    probs = cast(
        npt.NDArray[np.float64],
        _basis_probabilities_from_bitmasks(
            program, _basis_masks_from_bitstrings(program, bitstrings, bit_order)
        ),
    )
    if return_log:
        # TODO: move logspace accumulation into the C++ amplitude walk so
        # very-rare-bitstring queries don't lose precision through the
        # linear->log conversion. Current path is symmetric with
        # record_probabilities() at the API surface but does not give the
        # precision benefit; that benefit only kicks in once the underlying
        # |amplitude|^2 sum is itself tracked in logspace.
        with np.errstate(divide="ignore"):
            return np.log(probs)
    return probs

clifft.record_probabilities

record_probabilities(
    program: Program,
    records: MeasurementRecords,
    *,
    return_log: bool = False,
) -> npt.NDArray[np.float64]

Exact joint probabilities of measurement records under sample().

Requires at least one measurement. For a purely unitary program with no measurements, use :func:basis_probabilities instead.

records is one of: a single record string (e.g. "010"), a sequence of record strings, or a 2D bool / uint8 array of shape (num_records, program.num_measurements). Each record is interpreted in measurement order -- position i is the i-th entry sample().measurements would emit.

Records the program cannot emit are reported as 0.0 (or -inf when return_log=True). For deep circuits whose probabilities underflow float64, pass return_log=True so the log-domain values survive.

Source code in clifft/__init__.py
def record_probabilities(
    program: Program,
    records: MeasurementRecords,
    *,
    return_log: bool = False,
) -> npt.NDArray[np.float64]:
    """Exact joint probabilities of measurement records under ``sample()``.

    Requires at least one measurement. For a purely unitary program with no
    measurements, use :func:`basis_probabilities` instead.

    ``records`` is one of: a single record string (e.g. ``"010"``), a
    sequence of record strings, or a 2D ``bool`` / ``uint8`` array of
    shape ``(num_records, program.num_measurements)``. Each record is
    interpreted in measurement order -- position ``i`` is the i-th entry
    sample().measurements would emit.

    Records the program cannot emit are reported as ``0.0`` (or ``-inf``
    when ``return_log=True``). For deep circuits whose probabilities
    underflow float64, pass ``return_log=True`` so the log-domain values
    survive.
    """
    # Reject zero-measurement programs up front so a user who passes a real
    # record string against a unitary program gets the right hint rather
    # than the wrapper's record-length mismatch error.
    if program.num_measurements == 0:
        raise ValueError(
            "record_probabilities() requires a program with at least one "
            "measurement; use clifft.basis_probabilities() for unitary circuits."
        )
    record_array = _records_from_outcomes(program, records)
    log_probs = cast(
        npt.NDArray[np.float64],
        _record_probabilities_from_records(program, record_array),
    )
    # C++ marks unreachable records with the finite sentinel
    # numpy.finfo(float64).min (-DBL_MAX). Translate it back to the
    # Pythonic -inf for log output, and rely on the natural underflow
    # to 0.0 under np.exp for the linear case.
    if return_log:
        return np.where(log_probs == np.finfo(np.float64).min, -np.inf, log_probs)
    return np.exp(log_probs)

State Inspection

clifft.get_statevector

get_statevector(
    program: Program,
) -> Annotated[NDArray[numpy.complex128], dict(order=C)]

get_statevector(program: clifft._clifft_core.Program) -> numpy.ndarray[dtype=complex128, order='C']

Return a dense representative of a compiled pure-unitary program's final state.

The result is normalized and defined only up to global phase. Relative amplitudes and phases are preserved, but the global phase may vary across equivalent source circuits, compiler pass configurations, or Clifft versions.

Result Types

clifft.SampleResult

SampleResult(
    measurements: NDArray[uint8],
    detectors: NDArray[uint8],
    observables: NDArray[uint8],
    total_shots: int | None = None,
    passed_shots: int | None = None,
    logical_errors: int | None = None,
    observable_ones: NDArray[uint64] | None = None,
    exp_vals: NDArray[float64] | None = None,
)

Structured result from Clifft sampling functions.

Common attributes

measurements: uint8 array, shape (shots, num_measurements) detectors: uint8 array, shape (shots, num_detectors) observables: uint8 array, shape (shots, num_observables)

Survivor-only attributes

total_shots: total number of shots attempted passed_shots: number of shots that survived post-selection discards: number of discarded shots (total_shots - passed_shots) logical_errors: number of surviving shots with at least one observable flipped observable_ones: uint64 array of per-observable error counts

Supports tuple unpacking for backward compatibility:

m, d, o = clifft.sample(prog, shots)
Source code in clifft/_sample_result.py
def __init__(
    self,
    measurements: npt.NDArray[np.uint8],
    detectors: npt.NDArray[np.uint8],
    observables: npt.NDArray[np.uint8],
    total_shots: int | None = None,
    passed_shots: int | None = None,
    logical_errors: int | None = None,
    observable_ones: npt.NDArray[np.uint64] | None = None,
    exp_vals: npt.NDArray[np.float64] | None = None,
) -> None:
    self.measurements = measurements
    self.detectors = detectors
    self.observables = observables
    self.exp_vals = (
        exp_vals
        if exp_vals is not None
        else np.empty((measurements.shape[0], 0), dtype=np.float64)
    )
    self.total_shots = total_shots
    self.passed_shots = passed_shots
    self.discards = (
        None if total_shots is None or passed_shots is None else total_shots - passed_shots
    )
    self.logical_errors = logical_errors
    self.observable_ones = observable_ones

Compiled Programs

clifft.Program

A reusable compiled sampling program

has_postselection property

has_postselection: bool

(self) -> bool

noise_site_probabilities property

noise_site_probabilities: Annotated[
    NDArray[float64], dict(order=C)
]

Per-site total fault probabilities: quantum noise sites followed by readout noise.

num_actions property

num_actions: int

(self) -> int

num_detectors property

num_detectors: int

(self) -> int

num_exp_vals property

num_exp_vals: int

(self) -> int

num_hidden_measurements property

num_hidden_measurements: int

(self) -> int

num_measurements property

num_measurements: int

(self) -> int

num_observables property

num_observables: int

(self) -> int

num_qubits property

num_qubits: int

(self) -> int

peak_active_width property

peak_active_width: int

Largest active width reached by the compiled program.

peak_rank property

peak_rank: int

Deprecated alias for peak_active_width.

inspect method descriptor

inspect() -> str

inspect(self) -> str

Deterministic human-readable diagnostic text for the whole lowered CPU program.

The format is diagnostic output for debugging and tooling, not a stable machine-readable interface.

inspect_action method descriptor

inspect_action(action: int) -> str

inspect_action(self, action: int) -> str

Deterministic human-readable diagnostic text for a single action in the lowered CPU program.

The format is diagnostic output for debugging and tooling, not a stable machine-readable interface.

Circuit and IR Inspection

clifft.Circuit

A parsed quantum circuit

nodes property

nodes: list[AstNode]

(self) -> list[clifft._clifft_core.AstNode]

num_measurements property

num_measurements: int

(self) -> int

num_qubits property

num_qubits: int

(self) -> int

clifft.Qasm2Import

A natively parsed unitary OpenQASM 2 circuit and its source phase correction

circuit property

circuit: Circuit

(self) -> clifft._clifft_core.Circuit

global_phase_half_turns property

global_phase_half_turns: float

Source phase correction t representing exp(i * pi * t).

num_qubits property

num_qubits: int

(self) -> int

clifft.AstNode

A single circuit operation

arg property

arg: float

(self) -> float

args property

args: list[float]

(self) -> list[float]

gate property

gate: GateType

(self) -> clifft._clifft_core.GateType

source_line property

source_line: int

(self) -> int

tag property

tag: str

(self) -> str

targets property

targets: list[Target]

(self) -> list[clifft._clifft_core.Target]

clifft.Target

Encoded quantum target

has_pauli property

has_pauli: bool

(self) -> bool

is_inverted property

is_inverted: bool

(self) -> bool

is_rec property

is_rec: bool

(self) -> bool

pauli property

pauli: int

(self) -> int

pauli_char property

pauli_char: str

(self) -> str

value property

value: int

(self) -> int

clifft.HirModule

Heisenberg Intermediate Representation

num_detectors property

num_detectors: int

(self) -> int

num_exp_vals property

num_exp_vals: int

(self) -> int

num_measurements property

num_measurements: int

(self) -> int

num_observables property

num_observables: int

(self) -> int

num_ops property

num_ops: int

(self) -> int

num_qubits property

num_qubits: int

(self) -> int

num_t_gates property

num_t_gates: int

(self) -> int

source_map property

source_map: list

Source line mapping parallel to ops (list of list of uint32).

as_dict method descriptor

as_dict() -> dict

as_dict(self) -> dict

Return a JSON-friendly dictionary representation.

clifft.HeisenbergOp

A single abstract operation in the Heisenberg IR

is_dagger property

is_dagger: bool

(self) -> bool

is_hidden property

is_hidden: bool

(self) -> bool

op_type property

op_type: OpType

(self) -> clifft._clifft_core.OpType

pauli_string property

pauli_string: str

(self) -> str

sign property

sign: bool

(self) -> bool

as_dict method descriptor

as_dict() -> dict

as_dict(self) -> dict

Return a JSON-friendly dictionary representation.

clifft.OpType

Bases: enum.Enum

Heisenberg IR operation types

clifft.GateType

Bases: enum.Enum

Quantum gate types

Pass Managers

clifft.HirPass

Abstract base class for HIR optimization passes.

clifft.HirPassManager

HirPassManager()

Runs a sequence of optimization passes over an HirModule.

init(self) -> None

add method descriptor

add(hir_pass: HirPass) -> None

add(self, hir_pass: clifft._clifft_core.HirPass) -> None

Add an optimization pass. Passes run in the order added.

run method descriptor

run(hir: HirModule) -> None

run(self, hir: clifft._clifft_core.HirModule) -> None

Run all passes on the HIR module in sequence.

clifft.default_hir_pass_manager

default_hir_pass_manager() -> HirPassManager

default_hir_pass_manager() -> clifft._clifft_core.HirPassManager

Return an HirPassManager pre-loaded with the default passes.

HIR Passes

clifft.PeepholeFusionPass

PeepholeFusionPass()

Bases: clifft._clifft_core.HirPass

Symplectic peephole optimization: cancels and fuses T/T-dag gates, canonicalizes rotations within 1e-12 half-turns, and removes terminal phases consumed by same-axis measurements.

init(self) -> None

cancellations property

cancellations: int

(self) -> int

fusions property

fusions: int

(self) -> int

clifft.StatevectorSqueezePass

StatevectorSqueezePass()

Bases: clifft._clifft_core.HirPass

Bidirectional bubble sort: moves measurements leftward and non-Clifford gates rightward to minimize peak active width.

init(self) -> None

clifft.RemoveNoisePass

RemoveNoisePass()

Bases: clifft._clifft_core.HirPass

Strips all stochastic noise and readout noise ops from the HIR. Not included in the default pass list. Used internally by compute_reference_syndrome() for noiseless reference shots.

init(self) -> None

clifft.DropNonUnitaryPass

DropNonUnitaryPass()

Bases: clifft._clifft_core.HirPass

Drops non-evolution HIR ops so the remaining program is a unitary skeleton. Not included in the default pass list and not semantics-preserving.

init(self) -> None

Utilities

clifft.version

version() -> str

version() -> str

Return the Clifft version string

clifft.runtime_isa

runtime_isa() -> str

runtime_isa() -> str

Return the resolved kernel ISA: 'scalar', 'neon', 'avx2', 'avx512', or a 'trap:...' value when CLIFFT_FORCE_ISA requests an unavailable backend

clifft.compute_reference_syndrome

compute_reference_syndrome(hir: HirModule) -> dict

compute_reference_syndrome(hir: clifft._clifft_core.HirModule) -> dict

Compute noiseless reference syndrome for an HirModule.

Returns a dict with 'detectors' and 'observables' lists.

Type Aliases

clifft.BasisBitstrings module-attribute

BasisBitstrings: TypeAlias = (
    str | Sequence[str] | NDArray[bool_] | NDArray[uint8]
)

clifft.MeasurementRecords module-attribute

MeasurementRecords: TypeAlias = (
    str | Sequence[str] | NDArray[bool_] | NDArray[uint8]
)