Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

qamomile.optimization.qsvt_eigenstate_filter

Build QSVT eigenstate-filtering circuits for combinatorial problems.

The converter compiles a QUBO/HUBO problem into the sampling circuit of the Lin & Tong (2020, arXiv:2002.12508) ground-energy algorithm: the Ising cost Hamiltonian is block encoded, shifted by −μI-\mu I, filtered with a QSVT approximation of the sign function, and probed with one Hadamard-test qubit. The fraction of shots with all ancillas zero estimates ∥P<μ∣φ0⟩∥2\lVert P_{<\mu}\lvert\varphi_0\rangle\rVert^2, which is the predicate a classical binary search over μ\mu needs. The search itself stays outside the library — the converter only emits quantum programs.

By default the filter keeps the eigenspace below the threshold, so the search converges on the ground energy. That is the orientation every OMMX problem wants: Instance.to_hubo negates a maximization into a minimization before the converter ever sees it, so the optimum is always the smallest eigenvalue. Passing a positive scale to :meth:QSVTEigenstateFilterConverter.transpile inverts the filter into a largest-eigenvalue search; nothing else about the circuit changes.

Overview

FunctionDescription
qsvt_filter_probeBuild the sampling circuit of the Lin & Tong extremal-energy search.
ClassDescription
ExecutableProgramA fully compiled program ready for execution.
MathematicalProblemConverterBase class for converters that compile a problem into a circuit.
QSVTEigenstateFilterConverterConverter for QSVT eigenstate filtering (Lin & Tong ground-energy search).
SampleResultResult of a sample() execution.
TranspilerBase class for engine-specific transpilers.

Constants

Functions

qsvt_filter_probe [source]

def qsvt_filter_probe(encoding: LCUBlockEncoding) -> QKernel

Build the sampling circuit of the Lin & Tong extremal-energy search.

Prepares the uniform superposition ∣φ0⟩=H⊗n∣0⟩\lvert\varphi_0\rangle = H^{\otimes n}\lvert 0\rangle on the system register, applies :func:qsvt_filter_projector, and measures every register. The fraction of shots whose projector and signal bits are all zero estimates ∥Pμ∣φ0⟩∥2\lVert P_\mu\lvert\varphi_0\rangle\rVert^2; the system bits of those shots are samples of the projected state.

Parameters:

NameTypeDescription
encodingLCUBlockEncodingBlock-encoding descriptor of the shifted operator H−μIH - \mu I. Register widths are read from it.

Returns:

QKernel — A qkernel with signature (phi: Vector[Float]) -> tuple[Vector[Bit], Vector[Bit], Vector[Bit]] returning the projector, signal, and system measurements in that order.

Raises:

Classes

ExecutableProgram [source]

class ExecutableProgram(Generic[T])

A fully compiled program ready for execution.

Contains compiled quantum, classical, and expectation-value segments. Use sample() for multi-shot execution or run() for single execution.

Example:

executable = transpiler.compile(kernel)

# Sample: multiple shots, returns counts
job = executable.sample(executor, shots=1000)
result = job.result()  # SampleResult with counts

# Run: single shot, returns typed result
job = executable.run(executor)
result = job.result()  # Returns kernel's return type

Constructor

def __init__(
    self,
    plan: ProgramPlan | None = None,
    compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
    compiled_classical: list[CompiledClassicalSegment] = list(),
    compiled_expval: list[CompiledExpvalSegment] = list(),
    output_values: list[ValueLike] = list(),
) -> None

Attributes

Methods

get_circuits
def get_circuits(self) -> list[T]

Get all quantum circuits in execution order.

get_first_circuit
def get_first_circuit(self) -> T | None

Get the first quantum circuit, or None if no quantum segments.

restore
def restore(
    self,
    executor: QuantumExecutor[T],
    snapshot: JobSnapshot,
    bindings: dict[str, Any] | None = None,
) -> SampleJob[Any] | RunJob[Any] | ExpvalJob

Restore saved executions with this program’s typed result ABI.

Snapshots retain provider identifiers, completed local raw values, and ordered execution groups. Legacy flat provider snapshots remain supported. Reuse the same compiled program and pass the original runtime bindings explicitly to reproduce classical pre- and post-processing. Credentials, arbitrary bindings, and Python callables are not saved. Restoration reconnects to remote jobs without resubmitting or waiting for results; local values need no provider restoration support.

Parameters:

NameTypeDescription
executorQuantumExecutor[T]Engine adapter configured with the provider credentials and target used by the original job.
snapshotJobSnapshotSnapshot returned by the original public job’s snapshot() method.
bindingsdict[str, Any] | NoneOriginal runtime parameter bindings. Defaults to None for parameter-free programs.

Returns:

SampleJob[Any] | RunJob[Any] | ExpvalJob — SampleJob[Any] | RunJob[Any] | ExpvalJob: Restored lazy job with the same typed public result conversion as a new execution.

Raises:

Example:

>>> original = executable.sample(executor, shots=1000)
>>> snapshot = original.snapshot()
>>> restored = executable.restore(executor, snapshot)
>>> restored.result()
run
def run(
    self,
    executor: QuantumExecutor[T],
    bindings: dict[str, Any] | None = None,
    *,
    estimation: EstimationAccuracy | None = None,
) -> RunJob[Any] | ExpvalJob

Submit one execution and return its lazy result job.

Parameters:

NameTypeDescription
executorQuantumExecutor[T]Engine-specific quantum executor.
bindingsdict[str, Any] | NoneParameter bindings. Supports three formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Dict parameter: {“coeffs”: {0: 0.1, (0, 1): 0.2}}, decomposed per key onto the emitted parameters - Indexed: {“gammas[0]”: 0.1, “coeffs[(0, 1)]”: 0.2}
estimationEstimationAccuracy | NoneOptional per-execution expectation accuracy policy. Defaults to the executor’s configured behavior.

Returns:

RunJob[Any] | ExpvalJob — RunJob[Any] | ExpvalJob: A RunJob that resolves to the kernel’s return type, or an ExpvalJob when the program contains an expectation-value computation.

Raises:

Example:

job = executable.run(executor, bindings={"gamma": [0.5]})
result = job.result()
print(result)  # 0.25 (for QFixed) or (0, 1) (for bits)
sample
def sample(
    self,
    executor: QuantumExecutor[T],
    shots: int = 1024,
    bindings: dict[str, Any] | None = None,
) -> SampleJob[Any]

Submit a multi-shot execution and return its lazy job.

Parameters:

NameTypeDescription
executorQuantumExecutor[T]Engine-specific quantum executor.
shotsintNumber of shots to run.
bindingsdict[str, Any] | NoneParameter bindings. Supports three formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Dict parameter: {“coeffs”: {0: 0.1, (0, 1): 0.2}}, decomposed per key onto the emitted parameters - Indexed: {“gammas[0]”: 0.1, “coeffs[(0, 1)]”: 0.2}

Returns:

SampleJob[Any] — SampleJob[Any]: A job that resolves to a SampleResult with the per-bitstring counts.

Raises:

Example:

job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results)  # [(0.25, 500), (0.75, 500)]

MathematicalProblemConverter [source]

class MathematicalProblemConverter(abc.ABC)

Base class for converters that compile a problem into a circuit.

Constructor

def __init__(
    self,
    instance: ommx.v1.Instance | BinaryModel,
    *,
    uniform_penalty_weight: float | None = None,
    penalty_weights: dict[int, float] | None = None,
) -> None

Initialize a converter from an OMMX instance or binary model.

Parameters:

NameTypeDescription
instanceommx.v1.Instance | BinaryModelOptimization problem.
uniform_penalty_weightfloat | NoneUniform constraint penalty passed to OMMX. None delegates selection to OMMX.
penalty_weightsdict[int, float] | NoneOptional per-constraint penalty weights keyed by constraint ID.

Methods

decode
def decode(self, samples: SampleResult[list[int]]) -> BinarySampleSet | ommx.v1.SampleSet

Decode quantum measurement results.

The return type tracks the input that built this converter:

Parameters:

NameTypeDescription
samplesSampleResult[list[int]]Raw quantum measurement results from ExecutableProgram.sample(...).result().

Returns:

BinarySampleSet | ommx.v1.SampleSet — BinarySampleSet | ommx.v1.SampleSet: see method description.

See Also:

:meth:decode_to_binary_sampleset: always returns a :class:BinarySampleSet. Use it when you need the QUBO-domain (penalty-included) energy — e.g. to drive a classical optimizer that must penalize infeasibility.

Example:

>>> # OMMX in → OMMX out
>>> converter = QAOAConverter(ommx_instance)
>>> exe = converter.transpile(QiskitTranspiler(), p=2)
>>> result = exe.sample(QiskitTranspiler().executor(),
...                     shots=1024,
...                     bindings={"gammas": gs, "betas": bs}).result()
>>> sample_set = converter.decode(result)
>>> sample_set.best_feasible.objective
decode_to_binary_sampleset
def decode_to_binary_sampleset(self, samples: SampleResult[list[int]]) -> BinarySampleSet

Decode samples into a :class:BinarySampleSet.

Always returns a :class:BinarySampleSet, regardless of whether this converter was constructed with an :class:ommx.v1.Instance or a :class:BinaryModel. Use this when you need:

For most usage — feasibility, original-objective evaluation, per-constraint diagnostics — prefer the polymorphic :meth:decode, which returns an :class:ommx.v1.SampleSet for OMMX-backed converters.

Parameters:

NameTypeDescription
samplesSampleResult[list[int]]Raw quantum measurement results from ExecutableProgram.sample(...).result().

Returns:

BinarySampleSet — keyed by the SPIN model’s original variable BinarySampleSet — indices (the QUBO variable IDs for OMMX-backed converters) BinarySampleSet — in the converter’s original_vartype — BINARY for BinarySampleSet — OMMX-backed converters, the :class:BinaryModel’s declared BinarySampleSet — vartype otherwise.

get_cost_hamiltonian
def get_cost_hamiltonian(self) -> qm_o.Hamiltonian

Construct the cost Hamiltonian.

Subclasses must implement this method to build the appropriate Hamiltonian for their specific algorithm (e.g., Pauli-Z for QAOA, QRAC-encoded for QRAO). Oracle-based converters that do not use a cost Hamiltonian (e.g., GASConverter) should raise NotImplementedError.

Returns:

qm_o.Hamiltonian — qm_o.Hamiltonian: The cost Hamiltonian.

Raises:


QSVTEigenstateFilterConverter [source]

class QSVTEigenstateFilterConverter(MathematicalProblemConverter)

Converter for QSVT eigenstate filtering (Lin & Tong ground-energy search).

The problem’s Ising Hamiltonian HH is block encoded once with :func:~qamomile.circuit.ising_z_block_encoding. Each threshold μ\mu then composes a second LCU for H−μIH - \mu I and compiles its own probe circuit, because the LCU amplitudes — and hence μ\mu — are baked in at compile time.

A typical binary-search step therefore looks like: :meth:transpile for the current μ\mu, sample the program, read :meth:success_probability, and — once the search has converged — :meth:decode the same result to get the filtered states themselves.

Example:

>>> from qamomile.optimization.binary_model import BinaryModel
>>> from qamomile.optimization.qsvt_eigenstate_filter import (
...     QSVTEigenstateFilterConverter,
... )
>>> model = BinaryModel.from_higher_ising({(0,): 1.0, (0, 1): -1.0})
>>> converter = QSVTEigenstateFilterConverter(model)
>>> converter.normalization
2.0

Methods

decode
def decode(
    self,
    samples: SampleResult[tuple[list[int], list[int], list[int]]],
) -> BinarySampleSet | ommx.v1.SampleSet

Decode probe results, post-selecting before the base conversion.

Behaviour is the base class’s: an :class:ommx.v1.SampleSet for a converter built from an :class:ommx.v1.Instance, a :class:BinarySampleSet for one built from a :class:~qamomile.optimization.binary_model.BinaryModel. Only the accepted payload differs — this converter’s probe returns three registers per shot rather than one flat bitstring, so the base signature cannot describe it. The post-selection itself happens in :meth:decode_to_binary_sampleset, which the base implementation calls.

Parameters:

NameTypeDescription
samplesSampleResult[tuple[list[int], list[int], list[int]]]Raw probe results, each value holding the projector, signal, and system bits in that order.

Returns:

BinarySampleSet | ommx.v1.SampleSet — BinarySampleSet | ommx.v1.SampleSet: Post-selected samples, in whichever form matches the converter’s input.

Raises:

decode_to_binary_sampleset
def decode_to_binary_sampleset(
    self,
    samples: SampleResult[tuple[list[int], list[int], list[int]]],
) -> BinarySampleSet

Decode the post-selected system measurements into problem samples.

Shots whose projector or signal bits are non-zero missed the filtered block and carry no information about the retained subspace, so they are dropped before the usual SPIN/BINARY decoding runs. Use :meth:success_probability on the same result to recover how many were discarded.

The payload type narrows the base class’s flat list[int] per shot to the probe’s three-register tuple, which is what :func:~qamomile.circuit.algorithm.qsvt_filter_probe actually returns. The base signature therefore cannot type this override, and the shape is still validated at runtime by :meth:_postselect.

Parameters:

NameTypeDescription
samplesSampleResult[tuple[list[int], list[int], list[int]]]Raw probe results, each value holding the projector, signal, and system bits in that order, as returned by the kernel built by :func:~qamomile.circuit.algorithm.qsvt_filter_probe.

Returns:

BinarySampleSet — Post-selected samples in the converter’s original vartype, with energies from the problem’s model.

Raises:

get_cost_hamiltonian
def get_cost_hamiltonian(self) -> qm_o.Hamiltonian

Report that this converter exposes no cost Hamiltonian.

The Ising cost Hamiltonian is block encoded internally (see :meth:__post_init__) and consumed by the QSVT sign filter; it is never handed back as a Pauli observable. Following the base-class convention for converters that do not use a cost Hamiltonian, this always raises.

Returns:

qm_o.Hamiltonian — qm_o.Hamiltonian: Never returns.

Raises:

num_ancilla_bits
def num_ancilla_bits(self, mu: float) -> int

Width of the post-selected ancilla block for one threshold.

The probe circuit’s post-selected block is the projector qubit plus the signal register of the shifted encoding. It depends on mu: at μ=\mu = :attr:energy_offset the residual shift vanishes and the identity term drops out of the LCU (a zero-coefficient term is removed before normalization), leaving a narrower signal register than any other threshold. Pass the same mu that produced the results being interpreted.

Parameters:

NameTypeDescription
mufloatEnergy threshold, as passed to :meth:transpile.

Returns:

int — Number of leading measured bits that must all be zero for a shot to fall in the filtered block.

success_probability
def success_probability(self, samples: SampleResult[tuple[list[int], list[int], list[int]]]) -> float

Estimate ∥P<μ∣φ0⟩∥2\lVert P_{<\mu}\lvert\varphi_0\rangle\rVert^2.

This is the quantity the Lin & Tong binary search thresholds: it is bounded away from zero exactly when an eigenstate on the kept side of μ\mu — below it by default — carries weight in the uniform superposition.

Parameters:

NameTypeDescription
samplesSampleResult[tuple[list[int], list[int], list[int]]]Raw probe results for one threshold.

Returns:

float — Fraction of shots with all ancilla bits zero, or 0.0 when no shots were taken.

Raises:

transpile
def transpile(
    self,
    transpiler: Transpiler,
    *,
    mu: float,
    degree: int = DEFAULT_POLYNOMIAL_DEGREE,
    delta: float = DEFAULT_TRANSITION_WIDTH,
    scale: float = DEFAULT_POLYNOMIAL_SCALE,
    phi: list[float] | None = None,
) -> ExecutableProgram

Transpile the probe circuit for one energy threshold.

The emitted circuit prepares the uniform superposition on the system register, applies P<μP_{<\mu} through the QSVT sign filter, and measures the projector, signal, and system registers in that order.

Both mu and phi are compile-time data: the threshold sets the LCU amplitudes and the phase count sets the circuit structure, so each threshold needs its own transpile call.

Parameters:

NameTypeDescription
transpilerTranspilerBackend transpiler to use.
mufloatEnergy threshold. With the default scale the filter keeps eigenstates of the cost Hamiltonian with energy below mu; a positive scale keeps those above it.
degreeintDegree of the sign approximation, passed to :meth:_qsp_phases. Ignored when phi is given.
deltafloatTransition-width parameter, passed to :meth:_qsp_phases. Ignored when phi is given.
scalefloatPolynomial rescaling, passed to :meth:_qsp_phases. Ignored when phi is given.
philist[float] | NonePrecomputed reflection-convention phases. Defaults to None, meaning they are computed with pyqsp. When given it must hold an even number of at least two finite phases — the sign approximation is an odd polynomial, so its phase count is even, and an empty sequence describes no alternation at all. Values are angles in radians and are not wrapped, so any real magnitude is accepted.

Returns:

ExecutableProgram — Compiled probe circuit for this threshold. Its post-selected ancilla block is num_ancilla_bits(mu) wide.

Raises:


SampleResult [source]

class SampleResult(Generic[T])

Result of a sample() execution.

Contains results as a list of (value, count) tuples.

Example:

result.results  # [(0.25, 500), (0.75, 500)]

Constructor

def __init__(self, results: list[tuple[T, int]], shots: int) -> None

Attributes

Methods

most_common
def most_common(self, n: int = 1) -> list[tuple[T, int]]

Return the n most common results.

Parameters:

NameTypeDescription
nintNumber of results to return.

Returns:

list[tuple[T, int]] — List of (result, count) tuples sorted by count descending.

probabilities
def probabilities(self) -> list[tuple[T, float]]

Return probability distribution over results.

Returns:

list[tuple[T, float]] — List of (value, probability) tuples.


Transpiler [source]

class Transpiler(ABC, Generic[T])

Base class for engine-specific transpilers.

Provides the full compilation pipeline from qkernel-like frontend objects to executable programs.

Example:

>>> from qamomile.circuit.transpiler import TranspilerConfig
>>> from qamomile.qiskit import QiskitTranspiler
>>> transpiler = QiskitTranspiler()
>>> executable = transpiler.transpile(kernel, bindings={"theta": 0.5})
>>> circuit = executable.get_first_circuit()
>>> config = TranspilerConfig.with_strategies({"qft": "approximate_k2"})
>>> transpiler.set_config(config)

Attributes

Methods

affine_validate
def affine_validate(self, block: Block) -> Block

Pass 1.5: Validate affine type semantics.

This is a safety net to catch affine type violations that may have bypassed frontend checks. Validates that quantum values are used at most once.

analyze
def analyze(self, block: Block) -> Block

Pass 2: Validate and analyze dependencies.

array_bounds_check
def array_bounds_check(self, block: Block) -> Block

Pass 1.85: Reject reachable accesses outside resolved array bounds.

Runs after :meth:partial_eval so binding-dependent view extents and indices are concrete where possible, and before declarative slice operations are stripped. Statically zero-trip loop bodies are skipped because their element accesses are unreachable.

Parameters:

NameTypeDescription
blockBlockPost-fold affine or hierarchical block to validate.

Returns:

Block — The input block unchanged after successful validation.

Raises:

classical_lowering
def classical_lowering(self, block: Block) -> Block

Pass 2.25: Lower measurement-derived classical ops.

Identifies CompOp / CondOp / NotOp / BinOp instances whose operand dataflow traces back to a measurement and rewrites them to RuntimeClassicalExpr. Compile-time-foldable and emit-time-foldable (loop-bound, parameter-bound) classical ops are left unchanged.

Runs after analyze so the measurement-taint analysis has the full dependency graph available, and before validate_symbolic_shapes / plan / emit so downstream passes can rely on the cleaner IR (in particular: future segmentation work can dispatch on RuntimeClassicalExpr type instead of the BitType-only heuristic).

constant_fold
def constant_fold(self, block: Block, bindings: dict[str, Any] | None = None) -> Block

Pass 1.5: Fold constant expressions.

Evaluates BinOp operations when all operands are constants or bound parameters. This prevents quantum segment splitting from parametric expressions like phase * 2.

emit
def emit(
    self,
    separated: ProgramPlan,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
) -> ExecutableProgram[T]

Pass 4: Generate engine-specific code.

Parameters:

NameTypeDescription
separatedProgramPlanThe separated program to emit
bindingsdict[str, Any] | NoneParameter values to bind at compile time
parameterslist[str] | NoneParameter names to preserve as engine parameters

Raises:

executor
def executor(self, **kwargs: Any = {}) -> QuantumExecutor[T]

Create a quantum executor for this engine.

inline
def inline(self, block: Block) -> Block

Pass 1: Inline all inline-policy callable invocations.

lower_compile_time_ifs
def lower_compile_time_ifs(self, block: Block, bindings: dict[str, Any] | None = None) -> Block

Pass 1.75: Lower compile-time resolvable IfOperations.

Evaluates IfOperation conditions (including expression-derived conditions via CompOp/CondOp/NotOp) and replaces resolved ones with selected-branch operations. Merge outputs are substituted with selected-branch values throughout the block.

This prevents SegmentationPass from seeing classical-only compile-time IfOperations that would otherwise split quantum segments.

partial_eval
def partial_eval(self, block: Block, bindings: dict[str, Any] | None = None) -> Block

Pass 1.75: Fold constants and lower compile-time control flow.

plan
def plan(self, block: Block) -> ProgramPlan

Pass 3: Lower and split into a program plan.

Validates C→Q→C pattern with single quantum segment.

plan_circuit
def plan_circuit(
    self,
    prepared: PreparedModule,
    bindings: dict[str, Any] | None = None,
) -> ProgramPlan

Lower a prepared semantic module into the circuit execution model.

This is the destructive circuit-family path: inline-policy calls are flattened, compile-time structure is evaluated, affine and borrow invariants are checked, measurement-dependent classical expressions are classified, and the result is segmented into C-to-Q-to-C steps. Program-graph targets must compile :class:PreparedModule directly instead of invoking this method.

Parameters:

NameTypeDescription
preparedPreparedModuleHierarchical semantic program returned by :meth:prepare.
bindingsdict[str, Any] | NoneCompile-time bindings used for recursion unrolling and partial evaluation. Defaults to None.

Returns:

ProgramPlan — Circuit-family host-orchestrated execution plan.

Raises:

prepare
def prepare(
    self,
    kernel: QKernelLike,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
) -> PreparedModule

Prepare a qkernel for target-specific planning and lowering.

This phase preserves callable boundaries. It performs tracing, entrypoint validation, configured substitutions, and parameter-shape resolution, then collects the reachable callable graph into a program-level semantic view.

Parameters:

NameTypeDescription
kernelQKernelLikeQKernel or qkernel-like frontend object to prepare as a top-level entrypoint.
bindingsdict[str, Any] | NoneCompile-time values used while tracing and resolving parameter shapes. Defaults to None.
parameterslist[str] | NoneArgument names preserved as runtime parameters. Defaults to None.

Returns:

PreparedModule — Hierarchical entrypoint, reachable callables, call graph, and public ABI.

Raises:

resolve_parameter_shapes
def resolve_parameter_shapes(self, block: Block, bindings: dict[str, Any] | None = None) -> Block

Pass 0.75: Resolve symbolic Vector parameter shape dims.

Qamomile circuits are compile-time fixed-structure. Parameter Vector[Float] / Vector[UInt] inputs carry symbolic {name}_dim{i} shape Values so frontend code like arr.shape[0] returns a usable handle. This pass looks at bindings and, for every parameter array that has a concrete binding, substitutes those symbolic dims with constants so that downstream loop-bound resolution sees fixed lengths.

Parameters without a concrete binding are left as-is; their symbolic dims are harmless as long as no compile-time structure decision depends on them (the library QAOA pattern).

set_config
def set_config(self, config: TranspilerConfig) -> None

Set the transpiler configuration.

Parameters:

NameTypeDescription
configTranspilerConfigTranspiler configuration to use
slice_borrow_check
def slice_borrow_check(self, block: Block) -> Block

Pass 1.9: Post-fold slice-view linearity checker.

Runs after :meth:partial_eval has resolved slice bounds to concrete values. Catches the slice-view linearity violations that the trace-time frontend check cannot detect on its own — specifically, slices whose bounds were symbolic at trace time (so the frontend bulk-borrow tracker had to skip them) and aliasing scenarios that only become visible once those bounds are folded to constants:

  1. A view whose newly-concrete coverage overlaps another live view of the same root parent.

  2. A view whose newly-concrete coverage hits a slot that was consumed by a destructive operation earlier in the block.

  3. Slice ownership changes that cannot be represented safely across control-flow boundaries.

Creating a direct element borrow (q[i]) emits no IR operation, so this pass cannot observe the borrow site itself. Later uses of that element do appear as operation operands and are checked for conflicts with live slice views. Trace-time validation in :func:qamomile.circuit.frontend.func_to_block._validate_returned_arrays covers unreturned direct-element borrows that have no observable operand use.

The pass is a pass-through for the IR — it only raises on violations and leaves the block unchanged on success.

Parameters:

NameTypeDescription
blockBlockPost-fold affine or hierarchical block to validate.

Returns:

Block — The input block unchanged after successful validation.

Raises:

strip_slice_ops
def strip_slice_ops(self, block: Block) -> Block

Pass 1.95: Remove SliceArrayOperation nodes from the block.

PartialEvaluationPass keeps these declarative ops through constant folding so :meth:slice_borrow_check can use them as view-declaration markers. Once the linearity check has run, segmentation and downstream passes expect a classical-op-free quantum stream — this pass performs that cleanup.

substitute
def substitute(self, block: Block) -> Block

Pass 0.5: Apply substitutions (optional).

This pass rewrites inline callable targets and sets strategy names on boxed InvokeOperations based on config.

Parameters:

NameTypeDescription
blockBlockBlock to transform

Returns:

Block — Block with substitutions applied

to_block
def to_block(
    self,
    kernel: QKernelLike,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
) -> Block

Convert a qkernel-like frontend object to a Block.

Parameters:

NameTypeDescription
kernelQKernelLikeQKernel or qkernel-like frontend object to convert.
bindingsdict[str, Any] | NoneConcrete values to bind at trace time, including values used to resolve array shapes.
parameterslist[str] | NoneNames to keep as unbound runtime parameters.

Returns:

Block — Hierarchical block for the frontend object.

Raises:

Always uses kernel.build() so Python defaults, required arguments, runtime parameters, and array shapes follow one validated entry path.

to_circuit
def to_circuit(self, kernel: QKernelLike, bindings: dict[str, Any] | None = None) -> T

Compile and extract just the quantum circuit.

This is a convenience method for when you just want the engine circuit without the full executable.

Parameters:

NameTypeDescription
kernelQKernelLikeQKernel or qkernel-like frontend object to compile.
bindingsdict[str, Any] | NoneParameter values to bind.

Returns:

T — Engine-specific quantum circuit.

transpile
def transpile(
    self,
    kernel: QKernelLike,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
) -> ExecutableProgram[T]

Full compilation pipeline from a qkernel-like object to executable.

Parameters:

NameTypeDescription
kernelQKernelLikeQKernel or qkernel-like frontend object to compile.
bindingsdict[str, Any] | NoneParameter values to bind (also resolves array shapes). Names in bindings and parameters must be disjoint — a name is either compile-time bound or runtime symbolic, never both.
parameterslist[str] | NoneParameter names to preserve as engine parameters. Scalars/arrays of float/int/UInt are supported, plus Dict[K, Float]: each constant-key subscript lookup (d[key]) becomes one engine parameter named "d[<key>]", and the execution-time binding bindings={"d": {...}} is decomposed per key onto those parameters. A Dict runtime parameter is recorded in Block.param_slots as a slot whose type is a DictType (compile-time-bound Dicts and Tuple arguments stay out of the slot manifest); its emitted per-key parameters are visible via ExecutableProgram.parameter_names.

Returns:

ExecutableProgram[T] — ExecutableProgram[T]: Executable wrapping the engine circuit and the parameter metadata needed to re-bind runtime parameters, ready for execution.

Raises:

Pipeline:

  1. prepare: Trace and validate the entrypoint, apply configured substitutions, resolve parameter shapes, and preserve the reachable callable graph.

  2. plan_circuit: Inline inline-policy calls, unroll recursion, validate affine and borrow rules, partially evaluate compile-time structure, analyze dependencies, and segment the program into the host-orchestrated C-to-Q-to-C model.

  3. lower: Convert each quantum segment to immutable, engine-neutral CircuitProgram IR.

  4. legalize: Select native intrinsics and Pauli-evolution realizations from target capabilities and compilation policy.

  5. verify: Prove circuit structure and target legality before constructing engine objects.

  6. materialize: Convert the legalized circuit IR to engine-native artifacts and preserve the executable ABI.

unroll_recursion
def unroll_recursion(self, block: Block, bindings: dict[str, Any] | None = None) -> Block

Fixed-point loop of inline and branch lowering for recursion.

Each iteration unrolls one layer of self-referential inline callable invocation and then lowers its compile-time base-case IfOperation. Loop-carried Bit conditions remain visible until the final validation pass so first-iteration constants cannot erase a real backedge read. Terminates when no inline callable invocation remains (success), when every residual call is trapped inside an operation-owned block whose recursive callable contract is unsupported (control / inverse / select over a recursive kernel — raises a targeted error, see below), or when MAX_UNROLL_DEPTH is reached (genuinely non-terminating top-level recursion — raises).

Parameters:

NameTypeDescription
blockBlockThe block to unroll. May be HIERARCHICAL (still containing self-referential callable invocations) or already AFFINE (returned unchanged).
bindingsdict[str, Any] | NoneCompile-time bindings used by condition lowering to select the base case. Defaults to None, meaning no bindings are applied.

Returns:

Block — The fully unrolled, AFFINE block once no inline callable invocation remains. Returned unchanged when the input already has no calls.

Raises:

validate_symbolic_shapes
def validate_symbolic_shapes(self, block: Block) -> Block

Pass 2.5: Reject unresolvable ForOperation loop bounds.

Runs after analyze so dependency info is complete. Raises QamomileCompileError with an actionable message when a gamma_dim0-style symbolic Value reaches a ForOperation bound without being folded to a constant by ParameterShapeResolutionPass, or when a loop bound depends (directly or through classical arithmetic) on a runtime parameter — loop bounds are compile-time structure and must be provided via bindings, not parameters.

Parameters:

NameTypeDescription
blockBlockThe analyzed block to validate.

Returns:

Block — block, unchanged, when validation succeeds.

Raises: