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.qiskit.transpiler

Qiskit backend transpiler implementation.

This module provides QiskitTranspiler for converting Qamomile QKernels into Qiskit QuantumCircuits.

Overview

ClassDescription
CompOpComparison operation (EQ, NEQ, LT, LE, GT, GE).
CompOpKind
CondOpConditional logical operation (AND, OR).
CondOpKind
EmitErrorError during backend code emission.
EmitPassBase class for backend-specific emission passes.
ForOperationRepresents a for loop operation.
IfOperationRepresents an if-else conditional operation.
NotOp
PauliEvolveOpPauli evolution operation: exp(-i * gamma * H).
QiskitEmitPassQiskit-specific emission pass.
QiskitExecutorQiskit quantum executor using a safe local simulator or other backends.
QiskitGateEmitterGateEmitter implementation for Qiskit.
QiskitTranspilerQiskit backend transpiler.
RuntimeClassicalExprA classical expression known to require runtime evaluation.
RuntimeOpKindUnified kind for RuntimeClassicalExpr covering all classical
SegmentationPassSegment a block into a strategy-specific executable program plan.
StandardEmitPassStandard emit pass implementation using GateEmitter protocol.
TranspilerBase class for backend-specific transpilers.
WhileOperationRepresents a while loop operation.

Classes

CompOp [source]

class CompOp(BinaryOperationBase)

Comparison operation (EQ, NEQ, LT, LE, GT, GE).

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    kind: CompOpKind | None = None,
) -> None
Attributes

CompOpKind [source]

class CompOpKind(enum.Enum)
Attributes

CondOp [source]

class CondOp(BinaryOperationBase)

Conditional logical operation (AND, OR).

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    kind: CondOpKind | None = None,
) -> None
Attributes

CondOpKind [source]

class CondOpKind(enum.Enum)
Attributes

EmitError [source]

class EmitError(QamomileCompileError)

Error during backend code emission.

Constructor
def __init__(self, message: str, operation: str | None = None)
Attributes

EmitPass [source]

class EmitPass(Pass[ProgramPlan, ExecutableProgram[T]], Generic[T])

Base class for backend-specific emission passes.

Subclasses implement _emit_quantum_segment() to generate backend-specific quantum circuits.

Input: ProgramPlan Output: ExecutableProgram with compiled segments

Constructor
def __init__(
    self,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
)

Initialize with optional parameter bindings.

Parameters:

NameTypeDescription
bindingsdict[str, Any] | NoneValues to bind parameters to. If not provided, parameters must be bound at execution time.
parameterslist[str] | NoneList of parameter names to preserve as backend parameters.
Attributes
Methods
run
def run(self, input: ProgramPlan) -> ExecutableProgram[T]

Emit backend code from a program plan.


ForOperation [source]

class ForOperation(HasNestedOps, Operation)

Represents a for loop operation.

Example:

for i in range(start, stop, step):
    body
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    loop_var: str = '',
    loop_var_value: Value | None = None,
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Include loop_var_value so cloning/substitution stays consistent.

Without this override, UUIDRemapper would clone every body reference to the loop variable to a fresh UUID, but leave loop_var_value pointing at the un-cloned original — emit-time UUID-keyed lookups for the loop variable would then miss.

nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

IfOperation [source]

class IfOperation(HasNestedOps, Operation)

Represents an if-else conditional operation.

Example:

if condition:
    true_body
else:
    false_body
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    true_operations: list[Operation] = list(),
    false_operations: list[Operation] = list(),
    phi_ops: list[PhiOp] = list(),
) -> None
Attributes
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

NotOp [source]

class NotOp(Operation)
Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes

PauliEvolveOp [source]

class PauliEvolveOp(Operation)

Pauli evolution operation: exp(-i * gamma * H).

This operation applies the time evolution of a Pauli Hamiltonian to a quantum register.

Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes

QiskitEmitPass [source]

class QiskitEmitPass(StandardEmitPass['QuantumCircuit'])

Qiskit-specific emission pass.

Extends StandardEmitPass with Qiskit-specific control flow handling using context managers.

Constructor
def __init__(
    self,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
    use_native_composite: bool = True,
)

Initialize the Qiskit emit pass.

Parameters:

NameTypeDescription
bindingsdict[str, Any] | NoneParameter bindings for the circuit
parameterslist[str] | NoneList of parameter names to preserve as backend parameters
use_native_compositeboolIf True, use native Qiskit implementations for QFT/IQFT. If False, use manual decomposition.

QiskitExecutor [source]

class QiskitExecutor(QuantumExecutor['QuantumCircuit'])

Qiskit quantum executor using a safe local simulator or other backends.

Example:

executor = QiskitExecutor()  # Uses AerSimulator when available
counts = executor.execute(circuit, shots=1000)
# counts: {"00": 512, "11": 512}

# With expectation value estimation
from qamomile.qiskit.observable import QiskitExpectationEstimator
executor = QiskitExecutor(estimator=QiskitExpectationEstimator())
exp_val = executor.estimate(circuit, observable)
Constructor
def __init__(self, backend = None, estimator = None)

Initialize executor with backend and optional estimator.

Parameters:

NameTypeDescription
backend``Qiskit backend (defaults to AerSimulator if available)
estimator``Optional QiskitExpectationEstimator for expectation values
Attributes
Methods
bind_parameters
def bind_parameters(
    self,
    circuit: 'QuantumCircuit',
    bindings: dict[str, Any],
    parameter_metadata: ParameterMetadata,
) -> 'QuantumCircuit'

Bind parameter values to the Qiskit circuit.

Parameters:

NameTypeDescription
circuit'QuantumCircuit'The parameterized circuit
bindingsdict[str, Any]Dict mapping parameter names (indexed format) to values
parameter_metadataParameterMetadataMetadata about circuit parameters

Returns:

'QuantumCircuit' — New circuit with parameters bound

estimate
def estimate(
    self,
    circuit: 'QuantumCircuit',
    hamiltonian: 'qm_o.Hamiltonian',
    params: Sequence[float] | None = None,
) -> float

Estimate the expectation value of a Hamiltonian.

Parameters:

NameTypeDescription
circuit'QuantumCircuit'Qiskit QuantumCircuit (state preparation ansatz)
hamiltonian'qm_o.Hamiltonian'The qamomile.observable.Hamiltonian to measure
paramsSequence[float] | NoneOptional parameter values for parametric circuits

Returns:

float — The estimated expectation value

Raises:

execute
def execute(self, circuit: 'QuantumCircuit', shots: int) -> dict[str, int]

Execute circuit and return bitstring counts.

Parameters:

NameTypeDescription
circuit'QuantumCircuit'The quantum circuit to execute
shotsintNumber of measurement shots

Returns:

dict[str, int] — Dictionary mapping bitstrings to counts (e.g., {“00”: 512, “11”: 512})


QiskitGateEmitter [source]

class QiskitGateEmitter

GateEmitter implementation for Qiskit.

Emits individual quantum gates to Qiskit QuantumCircuit objects.

Attributes
Methods
append_gate
def append_gate(self, circuit: 'QuantumCircuit', gate: Any, qubits: list[int]) -> None

Append a gate to the circuit.

circuit_to_gate
def circuit_to_gate(self, circuit: 'QuantumCircuit', name: str = 'U') -> 'Gate | None'

Convert circuit to a reusable gate.

create_circuit
def create_circuit(self, num_qubits: int, num_clbits: int) -> 'QuantumCircuit'

Create a new Qiskit QuantumCircuit.

create_parameter
def create_parameter(self, name: str) -> Any

Create a Qiskit Parameter object.

emit_barrier
def emit_barrier(self, circuit: 'QuantumCircuit', qubits: list[int]) -> None
emit_ch
def emit_ch(self, circuit: 'QuantumCircuit', control: int, target: int) -> None
emit_cp
def emit_cp(
    self,
    circuit: 'QuantumCircuit',
    control: int,
    target: int,
    angle: float | Any,
) -> None
emit_crx
def emit_crx(
    self,
    circuit: 'QuantumCircuit',
    control: int,
    target: int,
    angle: float | Any,
) -> None
emit_cry
def emit_cry(
    self,
    circuit: 'QuantumCircuit',
    control: int,
    target: int,
    angle: float | Any,
) -> None
emit_crz
def emit_crz(
    self,
    circuit: 'QuantumCircuit',
    control: int,
    target: int,
    angle: float | Any,
) -> None
emit_cx
def emit_cx(self, circuit: 'QuantumCircuit', control: int, target: int) -> None
emit_cy
def emit_cy(self, circuit: 'QuantumCircuit', control: int, target: int) -> None
emit_cz
def emit_cz(self, circuit: 'QuantumCircuit', control: int, target: int) -> None
emit_else_start
def emit_else_start(self, circuit: 'QuantumCircuit', context: Any) -> None

Handled by context manager.

emit_for_loop_end
def emit_for_loop_end(self, circuit: 'QuantumCircuit', context: Any) -> None

End is handled by context manager exit.

emit_for_loop_start
def emit_for_loop_start(self, circuit: 'QuantumCircuit', indexset: range) -> Any

Start a native for loop using Qiskit’s for_loop context manager.

Note: The context manager must be used differently than a simple return. This method returns the indexset for use with _QiskitForLoopContext.

emit_h
def emit_h(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_if_end
def emit_if_end(self, circuit: 'QuantumCircuit', context: Any) -> None

Handled by context manager.

emit_if_start
def emit_if_start(self, circuit: 'QuantumCircuit', clbit: int, value: int = 1) -> Any

Start a native if using Qiskit’s if_test context manager.

emit_measure
def emit_measure(self, circuit: 'QuantumCircuit', qubit: int, clbit: int) -> None
emit_p
def emit_p(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> None
emit_rx
def emit_rx(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> None
emit_ry
def emit_ry(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> None
emit_rz
def emit_rz(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> None
emit_rzz
def emit_rzz(
    self,
    circuit: 'QuantumCircuit',
    qubit1: int,
    qubit2: int,
    angle: float | Any,
) -> None
emit_s
def emit_s(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_sdg
def emit_sdg(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_swap
def emit_swap(self, circuit: 'QuantumCircuit', qubit1: int, qubit2: int) -> None
emit_t
def emit_t(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_tdg
def emit_tdg(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_toffoli
def emit_toffoli(
    self,
    circuit: 'QuantumCircuit',
    control1: int,
    control2: int,
    target: int,
) -> None
emit_while_end
def emit_while_end(self, circuit: 'QuantumCircuit', context: Any) -> None

Handled by context manager.

emit_while_start
def emit_while_start(self, circuit: 'QuantumCircuit', clbit: int, value: int = 1) -> Any

Start a native while loop.

emit_x
def emit_x(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_y
def emit_y(self, circuit: 'QuantumCircuit', qubit: int) -> None
emit_z
def emit_z(self, circuit: 'QuantumCircuit', qubit: int) -> None
gate_controlled
def gate_controlled(self, gate: Any, num_controls: int) -> Any

Create controlled version of a gate.

gate_power
def gate_power(self, gate: Any, power: int) -> Any

Create gate raised to a power.

supports_for_loop
def supports_for_loop(self) -> bool

Qiskit supports native for loops.

supports_if_else
def supports_if_else(self) -> bool

Qiskit supports native if/else.

supports_while_loop
def supports_while_loop(self) -> bool

Qiskit supports native while loops.


QiskitTranspiler [source]

class QiskitTranspiler(Transpiler['QuantumCircuit'])

Qiskit backend transpiler.

Converts Qamomile QKernels into Qiskit QuantumCircuits.

Parameters:

NameTypeDescription
use_native_compositeboolIf True (default), use native Qiskit library implementations for QFT/IQFT. If False, use manual decomposition for all composite gates.

Example:

from qamomile.qiskit import QiskitTranspiler
import qamomile as qm

@qm.qkernel
def bell_state(q0: qm.Qubit, q1: qm.Qubit) -> tuple[qm.Bit, qm.Bit]:
    q0 = qm.h(q0)
    q0, q1 = qm.cx(q0, q1)
    return qm.measure(q0), qm.measure(q1)

transpiler = QiskitTranspiler()
circuit = transpiler.to_circuit(bell_state)
print(circuit.draw())
Constructor
def __init__(self, use_native_composite: bool = True)

Initialize the Qiskit transpiler.

Parameters:

NameTypeDescription
use_native_compositeboolIf True, use native Qiskit implementations for QFT/IQFT. If False, use manual decomposition.
Methods
executor
def executor(self, backend = None) -> QiskitExecutor

Create a Qiskit executor.

Parameters:

NameTypeDescription
backend``Qiskit backend (defaults to AerSimulator)

Returns:

QiskitExecutor — QiskitExecutor configured with the backend


RuntimeClassicalExpr [source]

class RuntimeClassicalExpr(Operation)

A classical expression known to require runtime evaluation.

Lowered from CompOp / CondOp / NotOp / BinOp by ClassicalLoweringPass when the op’s operand dataflow traces back to a MeasureOperation (i.e. cannot be folded at compile-time, by emit-time loop unrolling, or by compile_time_if_lowering). Backend emit translates this 1:1 to a backend-native runtime expression (e.g. qiskit.circuit.classical.expr.Expr).

Operand convention:

The single-node + unified-kind shape (vs four parallel subclasses) keeps the backend dispatch a single match op.kind instead of four parallel hooks, and makes the IR self-documenting: a single RuntimeClassicalExpr instance signals “runtime evaluation required” regardless of which classical family it came from.

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    kind: RuntimeOpKind | None = None,
) -> None
Attributes

RuntimeOpKind [source]

class RuntimeOpKind(enum.Enum)

Unified kind for RuntimeClassicalExpr covering all classical op families that can appear at runtime.

The split between this enum and the per-family BinOpKind / CompOpKind / CondOpKind is intentional: compile-time-foldable classical ops keep their original IR types so the existing fold pipeline (constant_foldcompile_time_if_lowering → emit-time evaluate_classical_predicate) is undisturbed. Only ops identified as runtime-evaluation-only by ClassicalLoweringPass get rewritten to RuntimeClassicalExpr with a member of this enum.

Attributes

SegmentationPass [source]

class SegmentationPass(Pass[Block, ProgramPlan])

Segment a block into a strategy-specific executable program plan.

This pass:

  1. Materializes return operations (syncs output_values from ReturnOperation)

  2. Splits the operation list into quantum and classical segments

  3. Builds a ProgramPlan via the configured segmentation strategy

Input: Block (typically ANALYZED or AFFINE) Output: ProgramPlan

Constructor
def __init__(self, strategy: SegmentationStrategy | None = None) -> None
Attributes
Methods
run
def run(self, input: Block) -> ProgramPlan

Segment the block into a ProgramPlan.


StandardEmitPass [source]

class StandardEmitPass(EmitPass[T], Generic[T])

Standard emit pass implementation using GateEmitter protocol.

This class provides the orchestration logic for circuit emission while delegating backend-specific operations to a GateEmitter.

Subclasses (QiskitEmitPass, CudaqEmitPass) override specific methods to provide native backend support. The thin wrappers here delegate to module functions in emit_support/ by default.

Parameters:

NameTypeDescription
gate_emitterGateEmitter[T]Backend-specific gate emitter
bindingsdict[str, Any] | NoneParameter bindings for the circuit
parameterslist[str] | NoneList of parameter names to preserve as backend parameters
composite_emitterslist[CompositeGateEmitter[T]] | NoneOptional list of CompositeGateEmitter for native implementations
Constructor
def __init__(
    self,
    gate_emitter: GateEmitter[T],
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
    composite_emitters: list[CompositeGateEmitter[T]] | None = None,
)

Transpiler [source]

class Transpiler(ABC, Generic[T])

Base class for backend-specific transpilers.

Provides the full compilation pipeline from QKernel to executable program.

Usage:

transpiler = QiskitTranspiler()

Option 1: Full pipeline

executable = transpiler.compile(kernel, bindings={“theta”: 0.5}) results = executable.run(transpiler.executor())

Option 2: Step-by-step

block = transpiler.to_block(kernel) substituted = transpiler.substitute(block) affine = transpiler.inline(substituted) validated = transpiler.affine_validate(affine) folded = transpiler.constant_fold(validated, bindings={“theta”: 0.5}) analyzed = transpiler.analyze(folded) plan = transpiler.plan(analyzed) executable = transpiler.emit(plan, bindings={“theta”: 0.5})

Option 3: Just get the circuit (no execution)

circuit = transpiler.to_circuit(kernel, bindings={“theta”: 0.5})

With configuration (strategy overrides)

config = TranspilerConfig.with_strategies({“qft”: “approximate”}) transpiler = QiskitTranspiler(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.

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 backend-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 backend parameters
executor
def executor(self, **kwargs: Any = {}) -> QuantumExecutor[T]

Create a quantum executor for this backend.

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

Pass 1: Inline all CallBlockOperations.

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

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
substitute
def substitute(self, block: Block) -> Block

Pass 0.5: Apply substitutions (optional).

This pass replaces CallBlockOperation targets and sets strategy names on CompositeGateOperations based on config.

Parameters:

NameTypeDescription
blockBlockBlock to transform

Returns:

Block — Block with substitutions applied

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

Convert a QKernel to a Block.

Parameters:

NameTypeDescription
kernelQKernelThe QKernel to convert
bindingsdict[str, Any] | NoneConcrete values to bind at trace time (resolves array shapes)
parameterslist[str] | NoneNames to keep as unbound parameters

When bindings or parameters are provided, uses kernel.build() to properly resolve array shapes from the bound data. Otherwise uses the cached hierarchical block for efficiency.

to_circuit
def to_circuit(self, kernel: QKernel, 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 backend circuit without the full executable.

Parameters:

NameTypeDescription
kernelQKernelThe QKernel to compile
bindingsdict[str, Any] | NoneParameter values to bind

Returns:

T — Backend-specific quantum circuit

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

Full compilation pipeline from QKernel to executable.

Parameters:

NameTypeDescription
kernelQKernelThe QKernel 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 backend parameters

Returns:

ExecutableProgram[T] — ExecutableProgram ready for execution

Raises:

Pipeline:

  1. to_block: Convert QKernel to Block

  2. substitute: Apply substitutions (if configured)

  3. resolve_parameter_shapes: Constant-fold symbolic Vector param dims

  4. inline: Inline CallBlockOperations

  5. affine_validate: Validate affine type semantics

  6. partial_eval: Fold constants and lower compile-time control flow

  7. analyze: Validate and analyze dependencies

  8. validate_symbolic_shapes: Reject unresolved parameter shape dims

  9. plan: Build ProgramPlan (segment into C->Q->C steps)

  10. emit: Generate backend-specific code

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

Fixed-point loop of inline ↔ partial_eval for self-recursive kernels.

Each iteration unrolls one layer of self-referential CallBlockOperation and then folds the base-case IfOperation via partial_eval. Terminates when no CallBlockOperation remains (success), when the call count stops decreasing (symbolic driver — self-calls are left in the IR and handled by downstream passes), or when MAX_UNROLL_DEPTH is reached (non-terminating recursion — raises).

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

Pass 2.5: Reject unresolved parameter shape dims in 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.


WhileOperation [source]

class WhileOperation(HasNestedOps, Operation)

Represents a while loop operation.

Only measurement-backed conditions are supported: the condition must be a Bit value produced by qmc.measure(). Non-measurement conditions (classical variables, constants, comparisons) are rejected by ValidateWhileContractPass before reaching backend emit.

Example::

bit = qmc.measure(q)
while bit:
    q = qmc.h(q)
    bit = qmc.measure(q)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    operations: list[Operation] = list(),
    max_iterations: int | None = None,
) -> None
Attributes
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation