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.gas

This module implements the Grover Adaptive Search (GAS) algorithm for Combinatorial Polynomial Binary Optimization (CPBO).

The quantum optimization algorithm iteratively applies Grover’s search to find the minimum of the function. The GAS algorithm is designed to efficiently find the optimal solution by adaptively adjusting the search space based on previous iterations’ results.

Overview

FunctionDescription
diffusion_opApply the Grover diffusion operator on the input register.
grover_algorithmRun repeated Grover iterations for the QUBO GAS circuit.
qft_encodingEncode a scalar coefficient as phase rotations in the QFT basis.
zero_degree_qft_encodingApply an unconditional phase-encoding term.
ClassDescription
BinaryModel
ExecutableProgramA fully compiled program ready for execution.
GASConverterConverter for Grover Adaptive Search (GAS).
MathematicalProblemConverterBase class for converters that compile a problem into a circuit.
TranspilerBase class for engine-specific transpilers.

Functions

diffusion_op [source]

def diffusion_op(q_input: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]

Apply the Grover diffusion operator on the input register.

Implements the reflection 2|s><s| - I about the uniform superposition via the X^n C^{n-1}Z X^n circuit identity. A single-qubit register uses a bare Z instead, since that identity would degenerate into a controlled gate with no controls.

Parameters:

NameTypeDescription
q_inputqmc.Vector[qmc.Qubit]Input register to reflect around the uniform superposition.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated input register.


grover_algorithm [source]

def grover_algorithm(
    n: qmc.UInt,
    m: qmc.UInt,
    y: qmc.Float,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    iters: qmc.UInt = 1,
) -> tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]]

Run repeated Grover iterations for the QUBO GAS circuit.

Parameters:

NameTypeDescription
nqmc.UIntNumber of input qubits.
mqmc.UIntNumber of output qubits.
yqmc.FloatObjective threshold offset encoded as a constant term.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients indexed by variable.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients indexed by variable pairs.
itersqmc.UIntNumber of Grover iterations.

Returns:

tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]] — tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]]: Output and input qubit registers after all iterations.


qft_encoding [source]

def qft_encoding(q: qmc.Vector[qmc.Qubit], coef: qmc.Float) -> qmc.Vector[qmc.Qubit]

Encode a scalar coefficient as phase rotations in the QFT basis.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Output register represented in the Fourier basis.
coefqmc.FloatThe coefficient to encode as a phase.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: The output register with the QFT encoding of coef.


zero_degree_qft_encoding [source]

def zero_degree_qft_encoding(
    q_output: qmc.Vector[qmc.Qubit],
    q_input: qmc.Vector[qmc.Qubit],
    coef: qmc.Float,
) -> tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]]

Apply an unconditional phase-encoding term.

Parameters:

NameTypeDescription
q_outputqmc.Vector[qmc.Qubit]Output register in the Fourier basis.
q_inputqmc.Vector[qmc.Qubit]Input register carried through unchanged.
coefqmc.FloatCoefficient of the constant term to encode.

Returns:

tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]] — tuple[qmc.Vector[qmc.Qubit], qmc.Vector[qmc.Qubit]]: Updated output and input registers.

Classes

BinaryModel [source]

class BinaryModel(Generic[VT])

Constructor

def __init__(self, expr: BinaryExpr[VT]) -> None

Attributes

Methods

calc_energy
def calc_energy(self, state: list[int]) -> float

Calculate the energy for a given variable assignment.

Parameters:

NameTypeDescription
statelist[int]Variable values indexed by sequential (zero-origin) indices. For SPIN: values must be +1 or -1. For BINARY: values must be 0 or 1.

Returns:

float — The energy value.

Raises:

change_vartype
def change_vartype(self, vartype: VarType) -> 'BinaryModel'
decode_from_sampleresult
def decode_from_sampleresult(self, result: SampleResult[list[int]]) -> BinarySampleSet[VT]

Decode quantum measurement results into samples with energies.

Converts raw measurement bitstrings (0/1 from quantum hardware) into the model’s variable domain and calculates energies.

Parameters:

NameTypeDescription
resultSampleResult[list[int]]Measurement results with sequential bit indices

Returns:

BinarySampleSet[VT] — BinarySampleSet with samples in expression domain, using original indices

from_higher_ising
@classmethod
def from_higher_ising(
    cls,
    higher_ising: dict[tuple[int, ...], float],
    constant: float = 0.0,
    simplify: bool = False,
) -> 'BinaryModel'

Create a SPIN BinaryModel from higher-order Ising coefficients.

Accepts Ising-style terms of arbitrary order (linear, quadratic, cubic, quartic, and beyond) in a single coefficient dictionary. Duplicate indices within a term are reduced using the identity s_i**2 = 1 for SPIN variables: each pair of repeated indices cancels to a constant factor, so e.g. (0, 0, 2) becomes (2,) and (0, 0, 1, 1, 2) becomes (2,). A warning is emitted whenever such reduction occurs.

Parameters:

NameTypeDescription
higher_isingdict[tuple[int, ...], float]Higher-order Ising coefficients mapping index tuples to SPIN interaction strengths. Index tuples are sorted; repeated indices are reduced via s_i**2 = 1. Empty tuples (()) are accumulated into the constant term.
constantfloatConstant offset term. Defaults to 0.0.
simplifyboolIf True, remove near-zero coefficients after accumulation. Defaults to False.

Returns:

'BinaryModel' — BinaryModel with SPIN vartype whose coefficients encode the 'BinaryModel' — supplied higher-order Ising terms.

Example:

>>> model = BinaryModel.from_higher_ising(
...     {(0,): 1.0, (0, 1): -2.0, (0, 1, 2): 0.5},
...     constant=0.25,
... )
>>> model.vartype
<VarType.SPIN: 'SPIN'>
from_hubo
@classmethod
def from_hubo(
    cls,
    hubo: dict[tuple[int, ...], float],
    constant: float = 0.0,
    simplify: bool = False,
) -> 'BinaryModel'

Create a BINARY BinaryModel from HUBO coefficients.

Parameters:

NameTypeDescription
hubodict[tuple[int, ...], float]HUBO coefficients mapping index tuples to values. Index tuples are sorted and deduplicated. Duplicate indices in a single term (e.g., (0, 0, 2)) emit a warning and are normalized to unique indices ((0, 2)). Empty tuples (()) are accumulated into the constant term.
constantfloatConstant offset term.
simplifyboolIf True, remove near-zero coefficients.

Returns:

'BinaryModel' — BinaryModel with BINARY vartype.

from_ising
@classmethod
def from_ising(
    cls,
    linear: dict[int, float],
    quad: dict[tuple[int, int], float],
    constant: float = 0.0,
    simplify: bool = False,
) -> 'BinaryModel'
from_qubo
@classmethod
def from_qubo(
    cls,
    qubo: dict[tuple[int, int], float],
    constant: float = 0.0,
    simplify: bool = False,
) -> 'BinaryModel'
normalize_by_abs_max
def normalize_by_abs_max(self, replace: bool = False) -> BinaryModel[VT]

Normalize the BinaryModel by its absolute maximum coefficient.

Returns:

BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.

normalize_by_factor
def normalize_by_factor(self, factor: float, replace: bool = False) -> BinaryModel[VT]

Normalize the BinaryModel by a given factor.

Parameters:

NameTypeDescription
factorfloatThe normalization factor.

Returns:

BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.

normalize_by_rms
def normalize_by_rms(self, replace: bool = False) -> BinaryModel[VT]

Normalize the BinaryModel by its root mean square.

Returns:

BinaryModel[VT] — BinaryModel[VT]: The normalized binary model.


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)]

GASConverter [source]

class GASConverter(MathematicalProblemConverter)

Converter for Grover Adaptive Search (GAS).

Encodes the BINARY-domain model normalized by the base converter, so that the Grover QFT-arithmetic circuit receives the correct QUBO coefficients (binary variables take values in {0, 1}, not ±1).

Methods

approximate_real_valued_model
@staticmethod
def approximate_real_valued_model(
    binary_model: BinaryModel,
    quantization_parameter: int | None = None,
) -> tuple[BinaryModel, float]

Rescale and round all model coefficients to integers for QFT arithmetic.

Divides every coefficient (including the constant) by the maximum absolute value to map them into [-1, 1], then multiplies by 2^(quantization_parameter - 1) and rounds to the nearest integer. The resulting model has integer coefficients that the Grover QFT circuit can encode exactly.

The scale relating the two models is returned alongside the model rather than discarded: the quantized objective is scale × f(x), so any threshold expressed in the original scale is only comparable against it after being multiplied by scale.

Parameters:

NameTypeDescription
binary_modelBinaryModelThe original binary model with real-valued coefficients.
quantization_parameterint | NoneNumber of bits used for the fixed-point representation. 2^(quantization_parameter - 1) is the scale factor applied after normalisation. When None, the value is chosen automatically by _greedy_quantization_parameter.

Returns:

tuple[BinaryModel, float] — tuple[BinaryModel, float]: A new binary model whose coefficients are integers approximating the original up to the chosen precision, and the scale factor s such that each returned coefficient approximates s × its original counterpart. s is 1.0 when the model is returned unchanged.

get_cost_hamiltonian
def get_cost_hamiltonian(self) -> qm_o.Hamiltonian

Raise NotImplementedError because GAS is oracle-based and has no cost Hamiltonian.

GAS marks states via an oracle reflection rather than minimizing the expectation value of a cost Hamiltonian. This method always raises so that incorrect usage fails immediately rather than propagating a silent None that would cause a confusing error later.

Returns:

qm_o.Hamiltonian — qm_o.Hamiltonian: Never returns; declared for base-class qm_o.Hamiltonian — compatibility only.

Raises:

required_output_bits
def required_output_bits(self, y: float = 0.0) -> int

Return the output-register width transpile() would pick for y.

Exposes the automatic sizing so callers can reserve the register themselves — for drawing the circuit, estimating resources, or checking a width before passing it as output_bits.

Reports the width for the current effective_model. On a freshly built converter that is the un-quantized model, so for a model with real-valued coefficients the answer grows once transpile() has quantized them: call this again afterwards, or pass approximate_real_coefficients=False.

Parameters:

NameTypeDescription
yfloatOracle threshold in the model’s original (un-quantized) scale, exactly as it would be passed to transpile(). Defaults to 0.0.

Returns:

int — Minimum number of output qubits for the current effective_model and quantization_scale.

transpile
def transpile(
    self,
    transpiler: Transpiler,
    *,
    output_bits: int | None = None,
    y: float,
    num_iterations: int,
    approximate_real_coefficients: bool = True,
    quantization_parameter: int | None = None,
) -> ExecutableProgram

Transpile the model into an executable Grover circuit.

Dispatches to the quadratic-only path, with build-in function, when no higher-order terms are present. Otherwise uses the HUBO path with the qkernel factory.

Parameters:

NameTypeDescription
transpilerTranspilerBackend transpiler to use.
output_bitsint | NoneNumber of qubits in the arithmetic register holding f(x) - y. When None (default), the minimum sufficient size is computed automatically from the effective model and the threshold via required_output_bits. A manual value is rejected when it cannot represent the whole range of f(x) - y.
yfloatCurrent best known objective value. The oracle marks all states x where f(x) < y. Pass the QUBO objective directly, in the model’s original scale — the sign convention and any quantization rescaling are handled internally.
num_iterationsintNumber of Grover operator applications.
approximate_real_coefficientsboolWhen True (default) and the model has non-integer coefficients, quantize them to integers so the QFT arithmetic can encode them exactly. When False the real coefficients are encoded as-is.
quantization_parameterint | NoneBit width forwarded to approximate_real_valued_model when quantizing. None selects it automatically. Ignored unless quantization applies.

Returns:

ExecutableProgram — The compiled circuit program.

Raises:


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:


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: