qamomile.circuit.transpiler.capabilities¶
Backend capability definitions for transpiler optimization.
Overview¶
| Class | Description |
|---|---|
BackendCapability | Capabilities that a backend may support natively. |
CapableBackend | Protocol for backends that declare their capabilities. |
Classes¶
BackendCapability [source]¶
class BackendCapability(enum.Flag)Capabilities that a backend may support natively.
Use these flags to indicate which composite gates and features a backend supports, allowing the transpiler to use native implementations when available.
Attributes¶
BASIC_COMPOSITECLASSICAL_FEEDFORWARDDYNAMIC_CIRCUITSFOR_LOOPFULL_COMPOSITEFULL_CONTROL_FLOWNATIVE_IQFTNATIVE_QFTNATIVE_QPENONEWHILE_LOOP
CapableBackend [source]¶
class CapableBackend(Protocol)Protocol for backends that declare their capabilities.
Implement this protocol in backend-specific EmitPass classes to enable capability-based optimizations.
Attributes¶
capabilities: BackendCapability Return the capabilities this backend supports.
Methods¶
has_capability¶
def has_capability(self, cap: BackendCapability) -> boolCheck if this backend has a specific capability.
Parameters:
| Name | Type | Description |
|---|---|---|
cap | BackendCapability | The capability to check for. |
Returns:
bool — True if the backend has the capability, False otherwise.
qamomile.circuit.transpiler.classical_executor¶
Classical segment executor for Python-based classical operations.
Overview¶
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
ClassicalExecutor | Executes classical segments in Python. |
ClassicalSegment | A segment of pure classical operations. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CondOp | Conditional logical operation (AND, OR). |
DecodeQFixedOperation | Decode measured bits to float (classical operation). |
DictValue | A dictionary value stored as stable ordered entries. |
ExecutionContext | Holds global state during program execution. |
ExecutionError | Error during program execution. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
NotOp | |
PhiOp | SSA Phi function: merge point after conditional branch. |
TupleValue | A tuple of IR values for structured data. |
Value | A typed SSA value in the IR. |
WhileOperation | Represents a while loop operation. |
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
ClassicalExecutor [source]¶
class ClassicalExecutorExecutes classical segments in Python.
Methods¶
execute¶
def execute(self, segment: ClassicalSegment, context: ExecutionContext) -> dict[str, Any]Execute classical operations and return outputs.
Interprets the operations list directly using Python.
ClassicalSegment [source]¶
class ClassicalSegment(Segment)A segment of pure classical operations.
Contains arithmetic, comparisons, and control flow. Will be executed directly in Python.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
kind: SegmentKind
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
DecodeQFixedOperation [source]¶
class DecodeQFixedOperation(Operation)Decode measured bits to float (classical operation).
This operation converts a sequence of classical bits from qubit measurements into a floating-point number using fixed-point encoding.
The decoding formula:
float_value = Σ bit[i] * 2^(int_bits - 1 - i)
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Example:
bits = [1, 0, 1] with int_bits=0
→ 0.101 (binary) = 0.5 + 0.125 = 0.625operands: [ArrayValue of bits (vec[bit])] results: [Float value]
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
DictValue [source]¶
class DictValue(_MetadataValueMixin)A dictionary value stored as stable ordered entries.
Constructor¶
def __init__(
self,
name: str,
entries: tuple[tuple[TupleValue | Value, Value], ...] = tuple(),
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
) -> NoneAttributes¶
entries: tuple[tuple[TupleValue | Value, Value], ...]logical_id: strmetadata: ValueMetadataname: strtype: DictTypeuuid: str
Methods¶
is_constant¶
def is_constant(self) -> boolnext_version¶
def next_version(self) -> DictValueExecutionContext [source]¶
class ExecutionContextHolds global state during program execution.
Constructor¶
def __init__(self, initial_bindings: dict[str, Any] | None = None)Methods¶
copy¶
def copy(self) -> 'ExecutionContext'Clone the execution context.
get¶
def get(self, key: str) -> Anyget_many¶
def get_many(self, keys: list[str]) -> dict[str, Any]has¶
def has(self, key: str) -> boolset¶
def set(self, key: str, value: Any) -> Noneupdate¶
def update(self, values: dict[str, Any]) -> NoneExecutionError [source]¶
class ExecutionError(QamomileCompileError)Error during program execution.
ForItemsOperation [source]¶
class ForItemsOperation(HasNestedOps, Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
key_vars: list[str] = list(),
value_var: str = '',
key_is_vector: bool = False,
key_var_values: tuple[Value, ...] | None = None,
value_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
key_is_vector: boolkey_var_values: tuple[Value, ...] | Nonekey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: strvalue_var_value: Value | None
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]Include the per-key/value Value fields for cloning/substitution.
Same rationale as ForOperation.all_input_values: keep the IR
identity fields in lockstep with body references so UUID-keyed
lookups stay valid after inline cloning.
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationHasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationNotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
PhiOp [source]¶
class PhiOp(Operation)SSA Phi function: merge point after conditional branch.
This operation selects one of two values based on a condition. Used to merge values from different branches of an if-else statement.
Example:
if condition:
x = x + 1 # true_value
else:
x = x + 2 # false_value
# x is now PhiOp(condition, true_value, false_value)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
condition: Valuefalse_value: Valueoperation_kind: OperationKindoutput: Valuesignature: Signaturetrue_value: Value
TupleValue [source]¶
class TupleValue(_MetadataValueMixin)A tuple of IR values for structured data.
Constructor¶
def __init__(
self,
name: str,
elements: tuple[Value, ...] = tuple(),
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
) -> NoneAttributes¶
elements: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strtype: ‘TupleType’uuid: str
Methods¶
is_constant¶
def is_constant(self) -> boolnext_version¶
def next_version(self) -> TupleValueValue [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.compile_check¶
Overview¶
| Function | Description |
|---|---|
is_block_compilable | Check if a Block is compilable. |
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
Functions¶
is_block_compilable [source]¶
def is_block_compilable(block: Block) -> boolCheck if a Block is compilable.
A Block is considered compilable if all its operations are compilable. This function checks each operation in the block’s operations list.
Parameters:
| Name | Type | Description |
|---|---|---|
block | Block | The Block to check. |
Returns: bool: True if the block is compilable, False otherwise.
Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
qamomile.circuit.transpiler.compiled_segments¶
Compiled segment structures for transpiled quantum circuits.
Overview¶
| Class | Description |
|---|---|
ClassicalSegment | A segment of pure classical operations. |
CompiledClassicalSegment | A classical segment ready for Python execution. |
CompiledExpvalSegment | A compiled expectation value segment with concrete Hamiltonian. |
CompiledQuantumSegment | A quantum segment with emitted backend circuit. |
ExpvalSegment | A segment for expectation value computation. |
ParameterMetadata | Metadata for all parameters in a compiled segment. |
QuantumSegment | A segment of pure quantum operations. |
Classes¶
ClassicalSegment [source]¶
class ClassicalSegment(Segment)A segment of pure classical operations.
Contains arithmetic, comparisons, and control flow. Will be executed directly in Python.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
kind: SegmentKind
CompiledClassicalSegment [source]¶
class CompiledClassicalSegmentA classical segment ready for Python execution.
Constructor¶
def __init__(self, segment: ClassicalSegment) -> NoneAttributes¶
segment: ClassicalSegment
CompiledExpvalSegment [source]¶
class CompiledExpvalSegmentA compiled expectation value segment with concrete Hamiltonian.
This segment computes <psi|H|psi> where psi is the quantum state from a quantum circuit and H is a qamomile.observable.Hamiltonian.
Constructor¶
def __init__(
self,
segment: ExpvalSegment,
hamiltonian: 'qm_o.Hamiltonian',
quantum_segment_index: int = 0,
result_ref: str = '',
qubit_map: dict[int, int] = dict(),
) -> NoneAttributes¶
hamiltonian: ‘qm_o.Hamiltonian’quantum_segment_index: intqubit_map: dict[int, int]result_ref: strsegment: ExpvalSegment
CompiledQuantumSegment [source]¶
class CompiledQuantumSegment(Generic[T])A quantum segment with emitted backend circuit.
Constructor¶
def __init__(
self,
segment: QuantumSegment,
circuit: T,
qubit_map: QubitMap = dict(),
clbit_map: ClbitMap = dict(),
measurement_qubit_map: dict[int, int] = dict(),
parameter_metadata: ParameterMetadata = ParameterMetadata(),
) -> NoneAttributes¶
circuit: Tclbit_map: ClbitMapmeasurement_qubit_map: dict[int, int]parameter_metadata: ParameterMetadataqubit_map: QubitMapsegment: QuantumSegment
ExpvalSegment [source]¶
class ExpvalSegment(Segment)A segment for expectation value computation.
Represents computing <psi|H|psi> where psi is the quantum state and H is a Hamiltonian observable.
This segment bridges a quantum circuit (state preparation) to a classical expectation value.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
hamiltonian_value: Value | None = None,
qubits_value: Value | None = None,
result_ref: str = '',
) -> NoneAttributes¶
hamiltonian_value: Value | Nonekind: SegmentKindqubits_value: Value | Noneresult_ref: str
ParameterMetadata [source]¶
class ParameterMetadataMetadata for all parameters in a compiled segment.
Tracks parameter information for runtime binding.
Constructor¶
def __init__(self, parameters: list[ParameterInfo] = list()) -> NoneAttributes¶
parameters: list[ParameterInfo]
Methods¶
get_array_names¶
def get_array_names(self) -> set[str]Get unique array/scalar parameter names.
get_ordered_params¶
def get_ordered_params(self) -> list[Any]Get backend parameter objects in definition order.
Useful for backends that require positional parameter binding (e.g., QURI Parts).
Returns:
list[Any] — List of backend_param objects in the order they were defined.
Example:
# For QURI Parts that uses positional binding:
param_values = [bindings[p.name] for p in metadata.parameters]
bound_circuit = circuit.bind_parameters(param_values)get_param_by_name¶
def get_param_by_name(self, name: str) -> ParameterInfo | NoneGet parameter info by full name.
to_binding_dict¶
def to_binding_dict(self, bindings: dict[str, Any]) -> dict[Any, Any]Convert indexed bindings to backend parameter bindings.
Transforms user-provided bindings (with indexed names like “gammas[0]”) into a dictionary mapping backend parameter objects to values. Useful for backends that use dict-based parameter binding (e.g., Qiskit).
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | Dictionary mapping parameter names to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2, “theta”: 0.5} |
Returns:
dict[Any, Any] — Dictionary mapping backend_param objects to values.
Example:
# For Qiskit that uses dict-based binding:
qiskit_bindings = metadata.to_binding_dict(bindings)
bound_circuit = circuit.assign_parameters(qiskit_bindings)QuantumSegment [source]¶
class QuantumSegment(Segment)A segment of pure quantum operations.
Contains quantum gates and qubit allocations. Will be emitted to a quantum circuit.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
qubit_values: list[Value] = list(),
num_qubits: int = 0,
) -> NoneAttributes¶
kind: SegmentKindnum_qubits: intqubit_values: list[Value]
qamomile.circuit.transpiler.decompositions¶
Shared gate decomposition recipes for backend emitters.
This module defines the canonical decomposition of controlled gates (CH, CY,
CP, CRY, CRZ) into primitive operations (RY, RZ, CNOT, S, SDG). Each recipe
is a frozen sequence of :class:DecompStep instances that encode:
Which primitive gate to apply,
Which qubit role receives the gate (
"control"or"target"),An optional angle expression (e.g.
"theta/2","-pi/4").
The recipes are the single source of truth for how Qamomile decomposes controlled gates when a backend cannot use a native controlled-U operation.
Why data-only (no shared execution helper)¶
Each backend has its own emission dialect:
Qiskit uses native
circuit.ch()/circuit.cy()and never needs this decomposition.QURI Parts represents angles as parametric dicts (name -> coefficient); primitive
emit_*methods take those dicts, not plain floats, so a generic “loop over the recipe and callemitter.emit_ry(angle)” helper does not compose.CUDA-Q emits Python source as strings. A generic helper that calls
self.emit_ryinteracts poorly with the tracing test emitter, which wraps everyemit_*method and would double-record each call.
Because no single helper absorbs all three styles cleanly, backends inline
their decomposition using their own idiomatic emission, and reference the
recipe constants below from the emit_ch / emit_cy / ... docstrings to
document equivalence. When changing a recipe, update the constant here and
ensure every backend’s inline implementation matches.
Overview¶
| Class | Description |
|---|---|
DecompStep | A single step in a decomposition recipe. |
PrimitiveGate | Gate primitives used in decomposition recipes. |
Constants¶
CH_DECOMPOSITION:list[DecompStep]CP_DECOMPOSITION:list[DecompStep]CRY_DECOMPOSITION:list[DecompStep]CRZ_DECOMPOSITION:list[DecompStep]CY_DECOMPOSITION:list[DecompStep]
Classes¶
DecompStep [source]¶
class DecompStepA single step in a decomposition recipe.
Constructor¶
def __init__(self, gate: PrimitiveGate, target: str, angle: str | None = None) -> NoneAttributes¶
angle: str | Nonegate: PrimitiveGatetarget: str
PrimitiveGate [source]¶
class PrimitiveGate(Enum)Gate primitives used in decomposition recipes.
Attributes¶
CNOTRYRZSSDG
qamomile.circuit.transpiler.emit_context¶
Typed bindings container for the emit pipeline.
Background — what was wrong with the bare dict[str, Any]:
The pre-EmitContext design used a single bindings: dict[str, Any]
threaded through every emit-pipeline function. That dict served at least
seven distinct semantic purposes simultaneously:
User-supplied kernel parameters (keyed by parameter name).
Loop iteration variables (keyed by loop_var name; pushed on entry, restored on exit).
Emit-time-computed intermediates —
BinOp/CompOp/CondOp/NotOpresults (keyed by Value UUID after Fix B; originally also keyed by Value name, which collided across tmps).Phi-output aliases (keyed by phi-output UUID; written by
register_classical_phi_aliases).Backend runtime expressions (e.g.
qiskit.circuit.classical.expr.Exprfor compound runtime if-conditions).Array data (keyed by array name; bound iterables passed by user).
Dict data (keyed by dict name; bound iterables passed by user).
Pauli observables (keyed by observable name).
This overloading was the structural cause of every name-collision bug
class seen in this codebase: "bit_tmp" chained predicates,
j_phi_4 phi aliases, the inline-pass DictValue drop, and the
type-blind bool(...) coercion in resolve_operand. Each was
patched locally; the structural overloading remained.
What EmitContext does (root-cause fix):
EmitContext is a dict subclass — flat [key] access still
works for migration compatibility. On top of dict semantics, every
binding kind has a separate, semantically-typed slot with the
appropriate identity key:
_params— user parameters, keyed by name (user-facing)._loop_vars— loop iteration variables, keyed by Value UUID._values— emit-time intermediates, keyed by UUID._runtime_exprs— backend Expr objects, keyed by UUID._array_data— array bindings, keyed byArrayValue.uuid._dict_data— dict bindings, keyed byDictValue.uuid._observables— Pauli observables, keyed byValue.uuid.
The key invariant: after the migration, the dict-baseclass writes
disappear. All writers go through typed setters (push_loop_var,
set_array_data, etc.); all readers go through typed getters.
EmitContext retains dict-protocol read-compat for legacy callers
during migration, but new code should never touch ctx[key].
Identity policy:
UUID: everything compiler-internal (loop vars, intermediates, runtime exprs, array/dict/observable bindings).
Name: only at the user-API boundary (parameter names supplied by
transpile(bindings={...})).
This eliminates the name-collision bug class entirely: empty/duplicate names cannot resolve to anything because lookups never go through the name path.
Overview¶
| Class | Description |
|---|---|
EmitContext | Bindings container with semantic slots, dict-compatible. |
Classes¶
EmitContext [source]¶
class EmitContext(dict)Bindings container with semantic slots, dict-compatible.
All emit-pipeline functions that take bindings: dict[str, Any]
accept an EmitContext unchanged because it inherits from dict.
Use the typed methods (bind_param, set_value, etc.) when
writing new code so the slot tracking stays accurate; existing
ctx[key] = value writes still work but bypass the slots.
Slots:
_params: User-supplied kernel parameters, keyed by parameter
name. Stable across the run. Name-keyed because the user
supplies parameters by name at the public API boundary.
_loop_vars: Currently-bound loop iteration variables, keyed by
ForOperation.loop_var_value.uuid /
ForItemsOperation.value_var_value.uuid etc. Pushed on
loop entry, restored on exit. UUID-keyed so identical
user-chosen variable names in nested or sibling loops never
collide.
_values: Emit-time-computed intermediate values (BinOp
results, CompOp/CondOp/NotOp results, phi
aliases), keyed by Value UUID.
_runtime_exprs: Backend runtime-expression objects (e.g. Qiskit
expr.Expr for compound classical conditions), keyed by
Value UUID.
_array_data: Bound array data (e.g. Vector[Float] parameter
values), keyed by ArrayValue.uuid.
_dict_data: Bound dict data (e.g. Dict[Tuple[UInt, UInt], Float]
ising coefficients), keyed by DictValue.uuid.
_observables: Bound Pauli observables (used by PauliEvolveOp
and gate counting), keyed by observable Value UUID.
Example:
>>> ctx = EmitContext.from_user_bindings({"theta": 0.5, "n": 3})
>>> ctx["theta"] # dict-style read still works
0.5
>>> ctx.bind_param("phi", 1.5)
>>> "phi" in ctx and ctx["phi"] == 1.5
True
>>> ctx.set_value(some_uuid, 42)
>>> ctx[some_uuid] == 42 and some_uuid in ctx._values
TrueConstructor¶
def __init__(self, *args: Any = (), **kwargs: Any = {}) -> NoneMethods¶
bind_param¶
def bind_param(self, name: str, value: Any) -> NoneRegister a kernel parameter binding (by name).
bind_params¶
def bind_params(self, params: dict[str, Any]) -> NoneRegister multiple kernel parameter bindings.
copy¶
def copy(self) -> 'EmitContext'Return a shallow copy preserving all semantic slots.
The dict baseclass copy() returns a plain dict, dropping
the slot-tracking metadata. Loop unrollers call bindings.copy()
to make a per-iteration child scope; without this override the
child would lose the params/loop_vars/values/runtime_exprs
partitioning and become a flat dict, defeating the whole point of
EmitContext. We override to return an EmitContext with
slot dicts independently copied so child mutations (e.g. pushing
a new loop var) don’t bleed back to the parent.
describe¶
def describe(self) -> strReturn a multi-line summary suitable for debug printing.
from_user_bindings¶
@classmethod
def from_user_bindings(cls, user_bindings: dict[str, Any] | None) -> 'EmitContext'Build an EmitContext seeded with user-supplied parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
user_bindings | dict[str, Any] | None | The dict passed by the user to transpile(); None is treated as empty. |
Returns:
'EmitContext' — A fresh EmitContext with all entries registered as parameters.
get_array_data¶
def get_array_data(self, uuid: str) -> AnyGet array data by ArrayValue.uuid, or None.
get_dict_data¶
def get_dict_data(self, uuid: str) -> AnyGet dict data by DictValue.uuid, or None.
get_loop_var¶
def get_loop_var(self, uuid: str) -> AnyGet a loop variable binding by Value UUID, or None if absent.
get_observable¶
def get_observable(self, uuid: str) -> AnyGet a Pauli observable by Value UUID, or None.
get_runtime_expr¶
def get_runtime_expr(self, uuid: str) -> AnyGet a backend runtime expression by Value UUID, or None.
iter_values¶
def iter_values(self) -> Iterator[tuple[str, Any]]Iterate over UUID-keyed emit-time intermediates only.
push_loop_var¶
def push_loop_var(self, uuid: str, value: Any, display_name: str | None = None) -> NoneBind a loop iteration variable, keyed by Value UUID.
Parameters:
| Name | Type | Description |
|---|---|---|
uuid | str | loop_var_value.uuid (or per-key/value UUID for ForItemsOperation). Different loops with identical user-chosen names (e.g. nested for i) get distinct UUIDs and therefore never collide here. |
value | Any | The bound iteration value (int / Hamiltonian item / etc.). |
display_name | str | None | Reserved for future debug-only use. Currently unused — loop variables are looked up exclusively by UUID, so the display name is never written into the bindings dict. Defaults to None. |
Note: this adds a binding to the existing context. Loop unrollers typically copy the parent context first so the binding is local to one iteration; this method does not copy.
set_array_data¶
def set_array_data(self, uuid: str, data: Any, display_name: str | None = None) -> NoneBind array data by ArrayValue.uuid.
Parameters:
| Name | Type | Description |
|---|---|---|
uuid | str | The array Value’s UUID. |
data | Any | The bound iterable / sequence / Vector handle. |
display_name | str | None | Migration shim — also writes the flat-dict view under the array’s user-facing name. Remove once Phase 3 of #7 lands. |
set_dict_data¶
def set_dict_data(self, uuid: str, data: Any, display_name: str | None = None) -> NoneBind dict data by DictValue.uuid.
Parameters:
| Name | Type | Description |
|---|---|---|
uuid | str | The dict Value’s UUID. |
data | Any | The bound dict / iterable. |
display_name | str | None | Migration shim — see set_array_data. |
set_observable¶
def set_observable(self, uuid: str, observable: Any, display_name: str | None = None) -> NoneBind a Pauli observable by Value UUID.
Parameters:
| Name | Type | Description |
|---|---|---|
uuid | str | The observable Value’s UUID. |
observable | Any | A qm_o.Hamiltonian (or backend-equivalent). |
display_name | str | None | Migration shim — see set_array_data. |
set_runtime_expr¶
def set_runtime_expr(self, uuid: str, expr: Any) -> NoneBind a backend runtime expression by Value UUID.
Backends (e.g. Qiskit) call this when they construct a
runtime-evaluable expression for a classical predicate that
wasn’t compile-time-foldable. _emit_if / _emit_while
consult the runtime-expr slot first when resolving conditions.
set_value¶
def set_value(self, uuid: str, value: Any) -> NoneBind an emit-time-computed intermediate by Value UUID.
Use for BinOp / CompOp / CondOp / NotOp results,
phi aliases, and other UUID-identified intermediates.
qamomile.circuit.transpiler.errors¶
Compilation error classes for Qamomile transpiler.
Overview¶
| Class | Description |
|---|---|
AffineTypeError | Base class for affine type violations. |
DependencyError | Error when quantum operation depends on non-parameter classical value. |
EmitError | Error during backend code emission. |
EntrypointValidationError | Error when a top-level transpilation entrypoint has unsupported I/O. |
ExecutionError | Error during program execution. |
FrontendTransformError | Error during frontend AST-to-builder lowering. |
InliningError | Error during inline pass (inlining CallBlockOperations). |
OperandResolutionInfo | Detailed information about a single operand that failed to resolve. |
QamomileCompileError | Base class for all Qamomile compilation errors. |
QubitAliasError | Same qubit used multiple times in one operation. |
QubitBorrowConflictError | Qubit slot inaccessible because another live handle borrows it. |
QubitConsumedError | Qubit handle used after being consumed by a previous operation. |
QubitIndexResolutionError | Error when qubit indices cannot be resolved during emission. |
QubitRebindError | Quantum variable reassigned from a different quantum source. |
ResolutionFailureReason | Categorizes why qubit index resolution failed. |
SeparationError | Error during quantum/classical separation. |
SliceBorrowViolationError | Aliasing detected between a slice view and a direct parent access. |
UnreturnedBorrowError | Borrowed array element not returned before array use. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Classes¶
AffineTypeError [source]¶
class AffineTypeError(QamomileCompileError)Base class for affine type violations.
Affine types enforce that quantum resources (qubits) are used at most once. This prevents common errors such as reusing a consumed qubit or aliasing.
Constructor¶
def __init__(
self,
message: str,
handle_name: str | None = None,
operation_name: str | None = None,
first_use_location: str | None = None,
)Attributes¶
first_use_locationhandle_nameoperation_name
DependencyError [source]¶
class DependencyError(QamomileCompileError)Error when quantum operation depends on non-parameter classical value.
This error indicates that the program requires JIT compilation which is not yet supported.
Constructor¶
def __init__(
self,
message: str,
quantum_op: str | None = None,
classical_value: str | None = None,
)Attributes¶
classical_valuequantum_op
EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
EntrypointValidationError [source]¶
class EntrypointValidationError(ValidationError)Error when a top-level transpilation entrypoint has unsupported I/O.
ExecutionError [source]¶
class ExecutionError(QamomileCompileError)Error during program execution.
FrontendTransformError [source]¶
class FrontendTransformError(QamomileCompileError)Error during frontend AST-to-builder lowering.
InliningError [source]¶
class InliningError(QamomileCompileError)Error during inline pass (inlining CallBlockOperations).
OperandResolutionInfo [source]¶
class OperandResolutionInfoDetailed information about a single operand that failed to resolve.
Constructor¶
def __init__(
self,
operand_name: str,
operand_uuid: str,
is_array_element: bool,
parent_array_name: str | None,
element_indices_names: list[str],
failure_reason: ResolutionFailureReason,
failure_details: str,
) -> NoneAttributes¶
element_indices_names: list[str]failure_details: strfailure_reason: ResolutionFailureReasonis_array_element: booloperand_name: stroperand_uuid: strparent_array_name: str | None
QamomileCompileError [source]¶
class QamomileCompileError(Exception)Base class for all Qamomile compilation errors.
QubitAliasError [source]¶
class QubitAliasError(AffineTypeError)Same qubit used multiple times in one operation.
Operations like cx() require distinct qubits for control and target. Using the same qubit in both positions is physically impossible and indicates a programming error.
Example of incorrect code:
q1, q2 = qm.cx(q, q) # ERROR: same qubit as control and target
Correct code:
q1, q2 = qm.cx(control, target) # Use distinct qubits
QubitBorrowConflictError [source]¶
class QubitBorrowConflictError(AffineTypeError)Qubit slot inaccessible because another live handle borrows it.
Raised when a qubit slot cannot be accessed because another live
handle currently borrows it — a slice view that has not been
returned, an outstanding element borrow, or any future borrow form
Qamomile may add. Unlike :class:QubitConsumedError, the slot is
not destroyed: releasing the borrowing handle (slice assignment,
element write-back, etc.) restores access.
Example of incorrect code (overlapping slice views)::
a = q[0:3] # q[0..2] now borrowed by ``a``
b = q[2:5] # ERROR: q[2] is still borrowed by ``a``Correct code::
a = q[0:3]
q[0:3] = a # return ``a`` first
b = q[2:5] # now safeExample of incorrect code (element borrow not returned before borrowing a neighbour)::
q0 = qubits[0]
q0 = qmc.h(q0)
q1 = qubits[1] # ERROR: q0 is still borrowedCorrect code::
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0 # return the element first
q1 = qubits[1] # now safeQubitConsumedError [source]¶
class QubitConsumedError(AffineTypeError)Qubit handle used after being consumed by a previous operation.
Each qubit handle can only be used once. After a gate operation, you must reassign the result to use the new handle.
Example of incorrect code:
q1 = qm.h(q) q2 = qm.x(q) # ERROR: q was already consumed by h()
Correct code:
q = qm.h(q) # Reassign to capture new handle q = qm.x(q) # Use the reassigned handle
QubitIndexResolutionError [source]¶
class QubitIndexResolutionError(EmitError)Error when qubit indices cannot be resolved during emission.
This error provides detailed diagnostic information about why qubit index resolution failed and suggests remediation steps.
Constructor¶
def __init__(
self,
gate_type: str,
operand_infos: list[OperandResolutionInfo],
available_bindings_keys: list[str],
available_qubit_map_keys: list[str],
)Attributes¶
available_bindings_keysavailable_qubit_map_keysgate_typeoperand_infos
QubitRebindError [source]¶
class QubitRebindError(AffineTypeError)Quantum variable reassigned from a different quantum source.
When a quantum variable is reassigned, the RHS must consume the same variable (self-update pattern). Reassigning from a different quantum variable would silently discard the original quantum state.
The check runs at qkernel decoration time as a static AST analysis
(see qamomile.circuit.frontend.ast_transform.collect_quantum_rebind_violations)
and raises immediately — the wrapped QKernel object is never
constructed when a violation is present. The check is run
unconditionally for every decorated kernel: kernel-level quantum
parameters (Qubit / Vector[Qubit]) seed origins from the
signature, and the analyzer’s recognition of internal quantum
constructors (qubit(...) / qubit_array(...)) seeds further
origins from inside the body so kernels that derive all of their
quantum state from internal allocations are also covered.
Branch-internal rebinds (assignments inside an if / for /
while body) are NOT flagged at decoration time: compile-time
conditional branches legitimately rebind quantum names (the
compile-time-if lowering pass selects one branch and discards the
other), and the single-pass AST analyzer cannot distinguish
compile-time from runtime branches. To keep those compile-time
patterns working, branch-internal violations are suppressed.
This is a known coverage gap. AffineValidationPass in the IR
layer only enforces “consumed at most once” and does NOT detect
“never consumed” / “silent discard” patterns, so a genuine runtime
if cond: q = qm.qubit("fresh") that discards a parameter is
currently not raised by either layer. A dedicated IR-level
silent-discard pass (or a flow-sensitive frontend analyzer) would
be needed to close it; this is tracked as follow-up. Top-level
(non-branch-internal) bypasses continue to raise at decoration
time.
Example of incorrect code:
a = qm.h(b) # ERROR: ‘a’ was quantum, now overwritten from ‘b’ a = b # ERROR: ‘a’ was quantum, now overwritten from ‘b’
Correct patterns:
a = qm.h(a) # Self-update (OK) new = qm.h(b) # New binding (OK, ‘new’ wasn’t quantum before)
ResolutionFailureReason [source]¶
class ResolutionFailureReason(Enum)Categorizes why qubit index resolution failed.
Attributes¶
ARRAY_ELEMENT_NOT_IN_QUBIT_MAPDIRECT_UUID_NOT_FOUNDINDEX_NOT_NUMERICNEGATIVE_INDEXNESTED_ARRAY_RESOLUTION_FAILEDSYMBOLIC_INDEX_NOT_BOUNDUNKNOWN
SeparationError [source]¶
class SeparationError(QamomileCompileError)Error during quantum/classical separation.
SliceBorrowViolationError [source]¶
class SliceBorrowViolationError(AffineTypeError)Aliasing detected between a slice view and a direct parent access.
Raised by :class:SliceBorrowCheckPass at transpile time when
a parent array slot is simultaneously held by a VectorView and
accessed directly, or when two overlapping views cover the same
slot. For slices with constant bounds this is normally caught at
trace time; this error covers the post-fold case when slice bounds
were symbolic UInt parameters resolved by bindings.
Example of incorrect code (detected only after bindings resolve
lo/hi to concrete values)::
region = q[lo:hi] # bindings give lo=0, hi=4 → covers {0,1,2,3}
qa = region[0] # borrows parent slot 0 via the view
qb = q[0] # borrows parent slot 0 directly
# SliceBorrowViolationError: slot 0 is held by a slice viewUnreturnedBorrowError [source]¶
class UnreturnedBorrowError(AffineTypeError)Borrowed array element not returned before array use.
When you borrow an element from a qubit array, you must return it (write it back) before using other elements or the array itself.
Example of incorrect code:
q0 = qubits[0] q0 = qmc.h(q0) q1 = qubits[1] # ERROR: q0 not returned yet
Correct code:
q0 = qubits[0] q0 = qmc.h(q0) qubits[0] = q0 # Return the borrowed element q1 = qubits[1] # Now safe to borrow another
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
qamomile.circuit.transpiler.executable¶
Executable program structure for compiled quantum-classical programs.
Overview¶
| Class | Description |
|---|---|
ClassicalExecutor | Executes classical segments in Python. |
CompiledClassicalSegment | A classical segment ready for Python execution. |
CompiledExpvalSegment | A compiled expectation value segment with concrete Hamiltonian. |
CompiledQuantumSegment | A quantum segment with emitted backend circuit. |
ExecutableProgram | A fully compiled program ready for execution. |
ExecutionContext | Holds global state during program execution. |
ExecutionError | Error during program execution. |
ExpvalJob | Job for expectation value computation. |
ParameterInfo | Information about a single unbound parameter in the circuit. |
ParameterMetadata | Metadata for all parameters in a compiled segment. |
ProgramPlan | Execution plan for a hybrid quantum/classical program. |
QuantumExecutor | Abstract base class for quantum backend execution. |
RunJob | Job for single execution. |
SampleJob | Job for sampling execution (multiple shots). |
Classes¶
ClassicalExecutor [source]¶
class ClassicalExecutorExecutes classical segments in Python.
Methods¶
execute¶
def execute(self, segment: ClassicalSegment, context: ExecutionContext) -> dict[str, Any]Execute classical operations and return outputs.
Interprets the operations list directly using Python.
CompiledClassicalSegment [source]¶
class CompiledClassicalSegmentA classical segment ready for Python execution.
Constructor¶
def __init__(self, segment: ClassicalSegment) -> NoneAttributes¶
segment: ClassicalSegment
CompiledExpvalSegment [source]¶
class CompiledExpvalSegmentA compiled expectation value segment with concrete Hamiltonian.
This segment computes <psi|H|psi> where psi is the quantum state from a quantum circuit and H is a qamomile.observable.Hamiltonian.
Constructor¶
def __init__(
self,
segment: ExpvalSegment,
hamiltonian: 'qm_o.Hamiltonian',
quantum_segment_index: int = 0,
result_ref: str = '',
qubit_map: dict[int, int] = dict(),
) -> NoneAttributes¶
hamiltonian: ‘qm_o.Hamiltonian’quantum_segment_index: intqubit_map: dict[int, int]result_ref: strsegment: ExpvalSegment
CompiledQuantumSegment [source]¶
class CompiledQuantumSegment(Generic[T])A quantum segment with emitted backend circuit.
Constructor¶
def __init__(
self,
segment: QuantumSegment,
circuit: T,
qubit_map: QubitMap = dict(),
clbit_map: ClbitMap = dict(),
measurement_qubit_map: dict[int, int] = dict(),
parameter_metadata: ParameterMetadata = ParameterMetadata(),
) -> NoneAttributes¶
circuit: Tclbit_map: ClbitMapmeasurement_qubit_map: dict[int, int]parameter_metadata: ParameterMetadataqubit_map: QubitMapsegment: QuantumSegment
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 typeConstructor¶
def __init__(
self,
plan: ProgramPlan | None = None,
compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
compiled_classical: list[CompiledClassicalSegment] = list(),
compiled_expval: list[CompiledExpvalSegment] = list(),
output_refs: list[str] = list(),
num_output_bits: int = 0,
) -> NoneAttributes¶
compiled_classical: list[CompiledClassicalSegment]compiled_expval: list[CompiledExpvalSegment]compiled_quantum: list[CompiledQuantumSegment[T]]has_parameters: bool Check if this program has unbound parameters.num_output_bits: intoutput_refs: list[str]parameter_names: list[str] Get list of parameter names that need binding.plan: ProgramPlan | Nonequantum_circuit: T Get the single quantum circuit.
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 | NoneGet the first quantum circuit, or None if no quantum segments.
run¶
def run(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None = None,
) -> RunJob[Any] | ExpvalJobExecute once and return single result.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
RunJob[Any] | ExpvalJob — RunJob that resolves to the kernel’s return type, or
RunJob[Any] | ExpvalJob — ExpvalJob if the program contains expectation value computation.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
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]Execute with multiple shots and return counts.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
shots | int | Number of shots to run. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
SampleJob[Any] — SampleJob that resolves to SampleResult with results.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
Example:
job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results) # [(0.25, 500), (0.75, 500)]ExecutionContext [source]¶
class ExecutionContextHolds global state during program execution.
Constructor¶
def __init__(self, initial_bindings: dict[str, Any] | None = None)Methods¶
copy¶
def copy(self) -> 'ExecutionContext'Clone the execution context.
get¶
def get(self, key: str) -> Anyget_many¶
def get_many(self, keys: list[str]) -> dict[str, Any]has¶
def has(self, key: str) -> boolset¶
def set(self, key: str, value: Any) -> Noneupdate¶
def update(self, values: dict[str, Any]) -> NoneExecutionError [source]¶
class ExecutionError(QamomileCompileError)Error during program execution.
ExpvalJob [source]¶
class ExpvalJob(Job[float])Job for expectation value computation.
Returns a single float representing <psi|H|psi>.
Constructor¶
def __init__(self, exp_val: float)Initialize expval job.
Parameters:
| Name | Type | Description |
|---|---|---|
exp_val | float | The computed expectation value |
Methods¶
result¶
def result(self) -> floatReturn the expectation value.
status¶
def status(self) -> JobStatusReturn job status.
ParameterInfo [source]¶
class ParameterInfoInformation about a single unbound parameter in the circuit.
Constructor¶
def __init__(
self,
name: str,
array_name: str,
index: int | None,
backend_param: Any,
source_ref: str | None = None,
) -> NoneAttributes¶
array_name: strbackend_param: Anyindex: int | Nonename: strsource_ref: str | None
ParameterMetadata [source]¶
class ParameterMetadataMetadata for all parameters in a compiled segment.
Tracks parameter information for runtime binding.
Constructor¶
def __init__(self, parameters: list[ParameterInfo] = list()) -> NoneAttributes¶
parameters: list[ParameterInfo]
Methods¶
get_array_names¶
def get_array_names(self) -> set[str]Get unique array/scalar parameter names.
get_ordered_params¶
def get_ordered_params(self) -> list[Any]Get backend parameter objects in definition order.
Useful for backends that require positional parameter binding (e.g., QURI Parts).
Returns:
list[Any] — List of backend_param objects in the order they were defined.
Example:
# For QURI Parts that uses positional binding:
param_values = [bindings[p.name] for p in metadata.parameters]
bound_circuit = circuit.bind_parameters(param_values)get_param_by_name¶
def get_param_by_name(self, name: str) -> ParameterInfo | NoneGet parameter info by full name.
to_binding_dict¶
def to_binding_dict(self, bindings: dict[str, Any]) -> dict[Any, Any]Convert indexed bindings to backend parameter bindings.
Transforms user-provided bindings (with indexed names like “gammas[0]”) into a dictionary mapping backend parameter objects to values. Useful for backends that use dict-based parameter binding (e.g., Qiskit).
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | Dictionary mapping parameter names to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2, “theta”: 0.5} |
Returns:
dict[Any, Any] — Dictionary mapping backend_param objects to values.
Example:
# For Qiskit that uses dict-based binding:
qiskit_bindings = metadata.to_binding_dict(bindings)
bound_circuit = circuit.assign_parameters(qiskit_bindings)ProgramPlan [source]¶
class ProgramPlanExecution plan for a hybrid quantum/classical program.
Structure:
[Optional] Classical preprocessing (parameter computation, etc.)
Single quantum segment (REQUIRED)
[Optional] Expval segment OR classical postprocessing
This plan enforces Qamomile’s current execution model: all quantum operations must be in a single quantum circuit.
Constructor¶
def __init__(
self,
steps: list[ProgramStep] = list(),
abi: ProgramABI = ProgramABI(),
boundaries: list[HybridBoundary] = list(),
parameters: dict[str, Value] = dict(),
) -> NoneAttributes¶
abi: ProgramABIboundaries: list[HybridBoundary]parameters: dict[str, Value]steps: list[ProgramStep]
QuantumExecutor [source]¶
class QuantumExecutor(ABC, Generic[T])Abstract base class for quantum backend execution.
To implement a custom executor:
execute() [Required] Execute circuit and return bitstring counts as dict[str, int]. Keys are bitstrings in big-endian format (e.g., “011” means q2=0, q1=1, q0=1).
bind_parameters() [Optional] Bind parameter values to parametric circuits. Override if your executor supports parametric circuits (e.g., QAOA variational circuits). Use ParameterMetadata.to_binding_dict() for easy conversion.
estimate() [Optional] Compute expectation values <psi|H|psi>. Override if your executor supports estimation primitives (e.g., Qiskit Estimator, QURI Parts).
Example (Minimal): class MyExecutor(QuantumExecutor[QuantumCircuit]): def init(self): from qiskit_aer import AerSimulator self.backend = AerSimulator()
def execute(self, circuit, shots):
from qiskit import transpile
if circuit.num_clbits == 0:
circuit = circuit.copy()
circuit.measure_all()
transpiled = transpile(circuit, self.backend)
return self.backend.run(transpiled, shots=shots).result().get_counts()Example (With Parameter Binding): def bind_parameters(self, circuit, bindings, metadata): # metadata.to_binding_dict() converts indexed names to backend params return circuit.assign_parameters(metadata.to_binding_dict(bindings))
Methods¶
bind_parameters¶
def bind_parameters(
self,
circuit: T,
bindings: dict[str, Any],
parameter_metadata: ParameterMetadata,
) -> TBind parameter values to the circuit.
Default implementation returns the circuit unchanged. Override for backends that support parametric circuits.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The parameterized circuit |
bindings | dict[str, Any] | Dict mapping parameter names (indexed format) to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
parameter_metadata | ParameterMetadata | Metadata about circuit parameters |
Returns:
T — New circuit with parameters bound
estimate¶
def estimate(
self,
circuit: T,
hamiltonian: 'qm_o.Hamiltonian',
params: Sequence[float] | None = None,
) -> floatEstimate the expectation value of a Hamiltonian.
This method computes <psi|H|psi> where psi is the quantum state prepared by the circuit and H is the Hamiltonian.
Backends can override this method to provide optimized implementations using their native estimator primitives.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit (state preparation ansatz) |
hamiltonian | 'qm_o.Hamiltonian' | The qamomile.observable.Hamiltonian to measure |
params | Sequence[float] | None | Optional parameter values for parametric circuits |
Returns:
float — The estimated expectation value
Raises:
NotImplementedError— If the executor does not support estimation
execute¶
def execute(self, circuit: T, shots: int) -> dict[str, int]Execute the circuit and return bitstring counts.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit to execute |
shots | int | Number of measurement shots |
Returns:
dict[str, int] — Dictionary mapping bitstrings to counts.
dict[str, int] — {“00”: 512, “11”: 512}
RunJob [source]¶
class RunJob(Job[T], Generic[T])Job for single execution.
Returns a single result value matching the kernel’s return type.
Constructor¶
def __init__(self, raw_counts: dict[str, int], result_converter: Callable[[str], T])Initialize run job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (should have single entry) |
result_converter | Callable[[str], T] | Function to convert bitstring to typed result |
Methods¶
result¶
def result(self) -> TReturn the single result.
status¶
def status(self) -> JobStatusReturn job status.
SampleJob [source]¶
class SampleJob(Job[SampleResult[T]], Generic[T])Job for sampling execution (multiple shots).
Returns a SampleResult containing counts for each unique result.
Constructor¶
def __init__(
self,
raw_counts: dict[str, int],
result_converter: Callable[[dict[str, int]], list[tuple[T, int]]],
shots: int,
)Initialize sample job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (e.g., {“00”: 512, “11”: 512}) |
result_converter | Callable[[dict[str, int]], list[tuple[T, int]]] | Function to convert raw counts to typed results |
shots | int | Number of shots executed |
Methods¶
result¶
def result(self) -> SampleResult[T]Return the sample result.
status¶
def status(self) -> JobStatusReturn job status.
qamomile.circuit.transpiler.execution_context¶
Execution context for quantum-classical program execution.
Overview¶
| Class | Description |
|---|---|
ExecutionContext | Holds global state during program execution. |
Classes¶
ExecutionContext [source]¶
class ExecutionContextHolds global state during program execution.
Constructor¶
def __init__(self, initial_bindings: dict[str, Any] | None = None)Methods¶
copy¶
def copy(self) -> 'ExecutionContext'Clone the execution context.
get¶
def get(self, key: str) -> Anyget_many¶
def get_many(self, keys: list[str]) -> dict[str, Any]has¶
def has(self, key: str) -> boolset¶
def set(self, key: str, value: Any) -> Noneupdate¶
def update(self, values: dict[str, Any]) -> Noneqamomile.circuit.transpiler.gate_emitter¶
GateEmitter protocol for backend-agnostic gate emission.
This module defines the GateEmitter protocol that backends implement to emit individual quantum gates. The StandardEmitPass uses this protocol to orchestrate circuit generation without backend-specific code.
Overview¶
| Function | Description |
|---|---|
default_combine_symbolic | Default combine_symbolic for backends with arithmetic-capable Parameters. |
| Class | Description |
|---|---|
BinOpKind | |
GateEmitter | Protocol for backend-specific gate emission. |
GateKind | Classification of gates for emission. |
GateSpec | Specification for a gate type. |
MeasurementMode | How a backend handles measurement operations. |
Constants¶
GATE_SPECS:dict[GateKind, GateSpec]
Functions¶
default_combine_symbolic [source]¶
def default_combine_symbolic(kind: 'BinOpKind', lhs: Any, rhs: Any) -> AnyDefault combine_symbolic for backends with arithmetic-capable Parameters.
Performs Python operator dispatch on the operands. Used by
evaluate_binop whenever the active emitter does not define its
own combine_symbolic method — the typical case for Qiskit
(ParameterExpression overloads __add__ etc.) and CUDA-Q
parameters. Backends whose Parameter type lacks Python operators
(e.g. QURI Parts) define their own combine_symbolic on the
emitter class to return a backend-native symbolic representation
instead.
Parameters:
| Name | Type | Description |
|---|---|---|
kind | 'BinOpKind' | The BinOpKind to apply. |
lhs | Any | Left operand (numeric or backend Parameter / expression). |
rhs | Any | Right operand (same shape). |
Returns:
Any — lhs OP rhs for the matching operator. 0.0 / 0 for
Any — division-by-zero in the symbolic path so the caller can finish
Any — emission without aborting on a numerically degenerate case.
Any — None for unrecognised kind values, which the caller
Any — treats as a no-op.
Classes¶
BinOpKind [source]¶
class BinOpKind(enum.Enum)Attributes¶
ADDDIVFLOORDIVMINMODMULPOWSUB
GateEmitter [source]¶
class GateEmitter(Protocol[T])Protocol for backend-specific gate emission.
Each backend implements this protocol to emit individual gates to their circuit representation.
Type parameter T is the backend’s circuit type (e.g., QuantumCircuit).
Attributes¶
measurement_mode: MeasurementMode Return the measurement mode for this backend.
Methods¶
append_gate¶
def append_gate(self, circuit: T, gate: Any, qubits: list[int]) -> NoneAppend a gate to the circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to append to |
gate | Any | The gate to append (from circuit_to_gate) |
qubits | list[int] | Target qubit indices |
circuit_to_gate¶
def circuit_to_gate(self, circuit: T, name: str = 'U') -> AnyConvert a circuit to a reusable gate.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to convert |
name | str | Label for the gate |
Returns:
Any — Backend-specific gate object, or None if not supported
create_circuit¶
def create_circuit(self, num_qubits: int, num_clbits: int) -> TCreate a new empty circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
num_qubits | int | Number of qubits in the circuit |
num_clbits | int | Number of classical bits in the circuit |
Returns:
T — A new backend-specific circuit object
create_parameter¶
def create_parameter(self, name: str) -> AnyCreate a symbolic parameter for the backend.
Parameters:
| Name | Type | Description |
|---|---|---|
name | str | Parameter name (e.g., “gammas[0]”) |
Returns:
Any — Backend-specific parameter object
emit_barrier¶
def emit_barrier(self, circuit: T, qubits: list[int]) -> NoneEmit barrier on specified qubits.
emit_ch¶
def emit_ch(self, circuit: T, control: int, target: int) -> NoneEmit controlled-Hadamard gate.
emit_cp¶
def emit_cp(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-Phase gate.
emit_crx¶
def emit_crx(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RX gate.
emit_cry¶
def emit_cry(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RY gate.
emit_crz¶
def emit_crz(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RZ gate.
emit_cx¶
def emit_cx(self, circuit: T, control: int, target: int) -> NoneEmit CNOT gate.
emit_cy¶
def emit_cy(self, circuit: T, control: int, target: int) -> NoneEmit controlled-Y gate.
emit_cz¶
def emit_cz(self, circuit: T, control: int, target: int) -> NoneEmit CZ gate.
emit_else_start¶
def emit_else_start(self, circuit: T, context: Any) -> NoneStart the else branch.
emit_for_loop_end¶
def emit_for_loop_end(self, circuit: T, context: Any) -> NoneEnd a native for loop context.
emit_for_loop_start¶
def emit_for_loop_start(self, circuit: T, indexset: range) -> AnyStart a native for loop context.
Returns a context manager or loop parameter, depending on backend.
emit_h¶
def emit_h(self, circuit: T, qubit: int) -> NoneEmit Hadamard gate.
emit_if_end¶
def emit_if_end(self, circuit: T, context: Any) -> NoneEnd the if/else block.
emit_if_start¶
def emit_if_start(self, circuit: T, clbit: int, value: int = 1) -> AnyStart a native if context.
Returns context for the if/else block.
emit_measure¶
def emit_measure(self, circuit: T, qubit: int, clbit: int) -> NoneEmit measurement operation.
emit_p¶
def emit_p(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit Phase gate (P(θ) = diag(1, e^(iθ))).
emit_rx¶
def emit_rx(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RX rotation gate.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to emit to |
qubit | int | Target qubit index |
angle | float | Any | Rotation angle (float or backend parameter) |
emit_ry¶
def emit_ry(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RY rotation gate.
emit_rz¶
def emit_rz(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RZ rotation gate.
emit_rzz¶
def emit_rzz(self, circuit: T, qubit1: int, qubit2: int, angle: float | Any) -> NoneEmit RZZ gate (exp(-i * θ/2 * Z⊗Z)).
emit_s¶
def emit_s(self, circuit: T, qubit: int) -> NoneEmit S gate (√Z).
emit_sdg¶
def emit_sdg(self, circuit: T, qubit: int) -> NoneEmit S-dagger gate (inverse of S).
emit_swap¶
def emit_swap(self, circuit: T, qubit1: int, qubit2: int) -> NoneEmit SWAP gate.
emit_t¶
def emit_t(self, circuit: T, qubit: int) -> NoneEmit T gate (√S).
emit_tdg¶
def emit_tdg(self, circuit: T, qubit: int) -> NoneEmit T-dagger gate (inverse of T).
emit_toffoli¶
def emit_toffoli(self, circuit: T, control1: int, control2: int, target: int) -> NoneEmit Toffoli (CCX) gate.
emit_while_end¶
def emit_while_end(self, circuit: T, context: Any) -> NoneEnd the while loop context.
emit_while_start¶
def emit_while_start(self, circuit: T, clbit: int, value: int = 1) -> AnyStart a native while loop context.
emit_x¶
def emit_x(self, circuit: T, qubit: int) -> NoneEmit Pauli-X gate.
emit_y¶
def emit_y(self, circuit: T, qubit: int) -> NoneEmit Pauli-Y gate.
emit_z¶
def emit_z(self, circuit: T, qubit: int) -> NoneEmit Pauli-Z gate.
gate_controlled¶
def gate_controlled(self, gate: Any, num_controls: int) -> AnyCreate controlled version of a gate.
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | The gate to control |
num_controls | int | Number of control qubits |
Returns:
Any — New controlled gate
gate_inverse¶
def gate_inverse(self, gate: Any) -> AnyCreate a backend-native inverse gate when supported.
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | Backend-specific gate object returned by circuit_to_gate. |
Returns:
Any — Backend-specific inverse gate object, or None when the
Any — backend cannot invert reusable gates natively.
gate_power¶
def gate_power(self, gate: Any, power: int) -> AnyCreate gate raised to a power (U^n).
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | The gate to raise to a power |
power | int | The power to raise to |
Returns:
Any — New gate representing gate^power
supports_for_loop¶
def supports_for_loop(self) -> boolCheck if backend supports native for loops.
supports_gate_inverse¶
def supports_gate_inverse(self) -> boolReturn whether reusable gates can be inverted natively.
Returns:
bool — True when gate_inverse can return a backend-native
inverse for gates produced by circuit_to_gate. Defaults
to False.
supports_if_else¶
def supports_if_else(self) -> boolCheck if backend supports native if/else.
supports_reusable_gates¶
def supports_reusable_gates(self) -> boolReturn whether circuit_to_gate can produce reusable gates.
Returns:
bool — True when the backend can convert emitted sub-circuits to
reusable gate objects. Defaults to False so emit paths can
avoid building throwaway sub-circuits for backends that only
support inline fallback emission.
supports_while_loop¶
def supports_while_loop(self) -> boolCheck if backend supports native while loops.
GateKind [source]¶
class GateKind(Enum)Classification of gates for emission.
Attributes¶
CHCPCRXCRYCRZCXCYCZHMEASUREPRXRYRZRZZSSDGSWAPTTDGTOFFOLIXYZ
GateSpec [source]¶
class GateSpecSpecification for a gate type.
Constructor¶
def __init__(
self,
kind: GateKind,
num_qubits: int,
has_angle: bool = False,
num_controls: int = 0,
) -> NoneAttributes¶
has_angle: boolkind: GateKindnum_controls: intnum_qubits: int
MeasurementMode [source]¶
class MeasurementMode(Enum)How a backend handles measurement operations.
Attributes¶
NATIVERUNNABLESTATIC
qamomile.circuit.transpiler.job¶
Job classes for quantum execution results.
Overview¶
| Class | Description |
|---|---|
ExpvalJob | Job for expectation value computation. |
Job | Abstract base class for quantum execution jobs. |
JobStatus | Status of a quantum job. |
RunJob | Job for single execution. |
SampleJob | Job for sampling execution (multiple shots). |
SampleResult | Result of a sample() execution. |
Classes¶
ExpvalJob [source]¶
class ExpvalJob(Job[float])Job for expectation value computation.
Returns a single float representing <psi|H|psi>.
Constructor¶
def __init__(self, exp_val: float)Initialize expval job.
Parameters:
| Name | Type | Description |
|---|---|---|
exp_val | float | The computed expectation value |
Methods¶
result¶
def result(self) -> floatReturn the expectation value.
status¶
def status(self) -> JobStatusReturn job status.
Job [source]¶
class Job(ABC, Generic[T])Abstract base class for quantum execution jobs.
A Job represents a quantum execution that can be awaited for results.
Methods¶
result¶
def result(self) -> TWait for and return the result.
Blocks until the job completes.
Returns:
T — The execution result with the appropriate type.
Raises:
ExecutionError— If the job failed.
status¶
def status(self) -> JobStatusReturn the current job status.
JobStatus [source]¶
class JobStatus(Enum)Status of a quantum job.
Attributes¶
COMPLETEDFAILEDPENDINGRUNNING
RunJob [source]¶
class RunJob(Job[T], Generic[T])Job for single execution.
Returns a single result value matching the kernel’s return type.
Constructor¶
def __init__(self, raw_counts: dict[str, int], result_converter: Callable[[str], T])Initialize run job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (should have single entry) |
result_converter | Callable[[str], T] | Function to convert bitstring to typed result |
Methods¶
result¶
def result(self) -> TReturn the single result.
status¶
def status(self) -> JobStatusReturn job status.
SampleJob [source]¶
class SampleJob(Job[SampleResult[T]], Generic[T])Job for sampling execution (multiple shots).
Returns a SampleResult containing counts for each unique result.
Constructor¶
def __init__(
self,
raw_counts: dict[str, int],
result_converter: Callable[[dict[str, int]], list[tuple[T, int]]],
shots: int,
)Initialize sample job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (e.g., {“00”: 512, “11”: 512}) |
result_converter | Callable[[dict[str, int]], list[tuple[T, int]]] | Function to convert raw counts to typed results |
shots | int | Number of shots executed |
Methods¶
result¶
def result(self) -> SampleResult[T]Return the sample result.
status¶
def status(self) -> JobStatusReturn job status.
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) -> NoneAttributes¶
results: list[tuple[T, int]] List of (value, count) tuples.shots: int Total number of shots executed.
Methods¶
most_common¶
def most_common(self, n: int = 1) -> list[tuple[T, int]]Return the n most common results.
Parameters:
| Name | Type | Description |
|---|---|---|
n | int | Number 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.
qamomile.circuit.transpiler.parameter_binding¶
Parameter binding structures for compiled quantum circuits.
Overview¶
| Class | Description |
|---|---|
ParameterInfo | Information about a single unbound parameter in the circuit. |
ParameterMetadata | Metadata for all parameters in a compiled segment. |
Classes¶
ParameterInfo [source]¶
class ParameterInfoInformation about a single unbound parameter in the circuit.
Constructor¶
def __init__(
self,
name: str,
array_name: str,
index: int | None,
backend_param: Any,
source_ref: str | None = None,
) -> NoneAttributes¶
array_name: strbackend_param: Anyindex: int | Nonename: strsource_ref: str | None
ParameterMetadata [source]¶
class ParameterMetadataMetadata for all parameters in a compiled segment.
Tracks parameter information for runtime binding.
Constructor¶
def __init__(self, parameters: list[ParameterInfo] = list()) -> NoneAttributes¶
parameters: list[ParameterInfo]
Methods¶
get_array_names¶
def get_array_names(self) -> set[str]Get unique array/scalar parameter names.
get_ordered_params¶
def get_ordered_params(self) -> list[Any]Get backend parameter objects in definition order.
Useful for backends that require positional parameter binding (e.g., QURI Parts).
Returns:
list[Any] — List of backend_param objects in the order they were defined.
Example:
# For QURI Parts that uses positional binding:
param_values = [bindings[p.name] for p in metadata.parameters]
bound_circuit = circuit.bind_parameters(param_values)get_param_by_name¶
def get_param_by_name(self, name: str) -> ParameterInfo | NoneGet parameter info by full name.
to_binding_dict¶
def to_binding_dict(self, bindings: dict[str, Any]) -> dict[Any, Any]Convert indexed bindings to backend parameter bindings.
Transforms user-provided bindings (with indexed names like “gammas[0]”) into a dictionary mapping backend parameter objects to values. Useful for backends that use dict-based parameter binding (e.g., Qiskit).
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | Dictionary mapping parameter names to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2, “theta”: 0.5} |
Returns:
dict[Any, Any] — Dictionary mapping backend_param objects to values.
Example:
# For Qiskit that uses dict-based binding:
qiskit_bindings = metadata.to_binding_dict(bindings)
bound_circuit = circuit.assign_parameters(qiskit_bindings)qamomile.circuit.transpiler.passes¶
Base classes for compiler passes.
Overview¶
| Class | Description |
|---|---|
AffineTypeError | Base class for affine type violations. |
AffineValidationPass | Validate affine type semantics at IR level. |
CompileTimeIfLoweringPass | Lowers compile-time resolvable IfOperations before separation. |
ConstantFoldingPass | Evaluates constant expressions at compile time. |
ControlFlowVisitor | Base class for visiting operations with control flow handling. |
DependencyError | Error when quantum operation depends on non-parameter classical value. |
OperationCollector | Collects operations matching a predicate. |
OperationTransformer | Base class for transforming operations with control flow handling. |
Pass | Base class for all compiler passes. |
QamomileCompileError | Base class for all Qamomile compilation errors. |
SliceBorrowCheckPass | Post-fold linearity checker for sliced views and borrow state. |
UUIDRemapper | Clones values and operations with fresh UUIDs and logical_ids. |
ValidateWhileContractPass | Validates that all WhileOperation conditions are measurement-backed. |
ValidationError | Error during validation (e.g., non-classical I/O). |
ValueCollector | Collects Value UUIDs from operation operands and results. |
Classes¶
AffineTypeError [source]¶
class AffineTypeError(QamomileCompileError)Base class for affine type violations.
Affine types enforce that quantum resources (qubits) are used at most once. This prevents common errors such as reusing a consumed qubit or aliasing.
Constructor¶
def __init__(
self,
message: str,
handle_name: str | None = None,
operation_name: str | None = None,
first_use_location: str | None = None,
)Attributes¶
first_use_locationhandle_nameoperation_name
AffineValidationPass [source]¶
class AffineValidationPass(Pass[Block, Block])Validate affine type semantics at IR level.
This pass serves as a safety net to catch affine type violations that may have bypassed the frontend checks. It verifies:
Each quantum value is used (consumed) at most once
Quantum values are not silently discarded
Input: Block (any kind) Output: Same Block (unchanged, validation only)
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockValidate affine type semantics in the block.
Raises:
ValidationError— If the block kind is not AFFINE.AffineTypeError— If a quantum value is consumed multiple times.
CompileTimeIfLoweringPass [source]¶
class CompileTimeIfLoweringPass(Pass[Block, Block])Lowers compile-time resolvable IfOperations before separation.
After constant folding, some IfOperation conditions are statically
known but remain as control-flow nodes. SegmentationPass treats them
as segment boundaries, causing MultipleQuantumSegmentsError for
classical-only compile-time if after quantum init.
This pass:
Evaluates conditions including expression-derived ones (
CompOp,CondOp,NotOpchains).Replaces resolved
IfOperations with selected-branch operations.Substitutes phi output UUIDs with selected-branch values in all subsequent operations and block outputs.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun the compile-time if lowering pass.
ConstantFoldingPass [source]¶
class ConstantFoldingPass(Pass[Block, Block])Evaluates constant expressions at compile time.
This pass folds BinOp operations when all operands are constants or bound parameters, eliminating unnecessary classical operations that would otherwise split quantum segments.
Example:
Before (with bindings={"phase": 0.5}):
BinOp(phase * 2) -> classical segment split
After:
Constant 1.0 -> no segment splitConstructor¶
def __init__(self, bindings: dict[str, Any] | None = None, *, strip_slice_ops: bool = True)Create a constant-folding pass.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Compile-time parameter bindings used when folding BinOps that reference declared parameters. |
strip_slice_ops | bool | When True (default), removes SliceArrayOperation nodes after folding. Set to False when a downstream pass — notably SliceBorrowCheckPass — still needs to observe slice declaration points in program order to decide view liveness. A separate strip pass must then run after the linearity check so segmentation still sees a pure quantum-op stream. |
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun constant folding on the block.
ControlFlowVisitor [source]¶
class ControlFlowVisitor(ABC)Base class for visiting operations with control flow handling.
Subclasses override visit_operation to define per-operation behavior.
Control flow recursion is handled automatically by the base class.
Example:
class MeasurementCounter(ControlFlowVisitor):
def __init__(self):
self.count = 0
def visit_operation(self, op: Operation) -> None:
if isinstance(op, MeasureOperation):
self.count += 1Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneProcess a single operation. Override in subclasses.
visit_operations¶
def visit_operations(self, operations: list[Operation]) -> NoneVisit all operations including nested control flow.
DependencyError [source]¶
class DependencyError(QamomileCompileError)Error when quantum operation depends on non-parameter classical value.
This error indicates that the program requires JIT compilation which is not yet supported.
Constructor¶
def __init__(
self,
message: str,
quantum_op: str | None = None,
classical_value: str | None = None,
)Attributes¶
classical_valuequantum_op
OperationCollector [source]¶
class OperationCollector(ControlFlowVisitor)Collects operations matching a predicate.
Example:
collector = OperationCollector(lambda op: isinstance(op, MeasureOperation))
collector.visit_operations(block.operations)
measurements = collector.collectedConstructor¶
def __init__(self, predicate: Callable[[Operation], bool])Attributes¶
collected: list[Operation]
Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneOperationTransformer [source]¶
class OperationTransformer(ABC)Base class for transforming operations with control flow handling.
Subclasses override transform_operation to define per-operation transformation.
Control flow recursion and rebuilding is handled automatically.
Example:
class OperationRenamer(OperationTransformer):
def transform_operation(self, op: Operation) -> Operation:
# Return modified operation
return dataclasses.replace(op, ...)Methods¶
transform_operation¶
def transform_operation(self, op: Operation) -> Operation | NoneTransform a single operation. Return None to remove it.
transform_operations¶
def transform_operations(self, operations: list[Operation]) -> list[Operation]Transform all operations including nested control flow.
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
QamomileCompileError [source]¶
class QamomileCompileError(Exception)Base class for all Qamomile compilation errors.
SliceBorrowCheckPass [source]¶
class SliceBorrowCheckPass(Pass[Block, Block])Post-fold linearity checker for sliced views and borrow state.
Runs after :class:ConstantFoldingPass (so slice bounds are
concrete where possible) and before segmentation / emit. Walks
the operations of the root block in order, maintaining a borrow
state map modelled on the frontend’s
:attr:ArrayBase._borrowed_indices — a single dict whose
values are slice-view ArrayValue owners or the
_ConsumedSlotMarker sentinel. Direct element borrows
(q[i]) emit no IR operation and are left to the trace-time
validator.
The pass does not flag a leftover slice view at block end —
slice views are affine at the kernel boundary, mirroring how
element borrows behave on a locally-allocated register (the
frontend’s _validate_returned_arrays covers the genuine
leak: returning the parent with a live borrow). Anything that
actually clashes with a live view (direct slot access,
destructive parent consume, overlapping views, use-after-
destroy) is rejected at the eager check points listed in the
module docstring.
Constructor¶
def __init__(self) -> NoneInitialize per-run mutable state to safe defaults.
Attributes¶
name: str Return the pass identifier for tracing/logging.
Methods¶
run¶
def run(self, input: Block) -> BlockRun the borrow tracker over input.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block to check. Expected to be in AFFINE or HIERARCHICAL kind — post-fold but pre-segmentation. |
Returns:
Block — The same Block unchanged (pass-through).
Raises:
ValidationError— If called on an unexpected block kind.SliceBorrowViolationError— If a slice view and a direct access collide, two views overlap, or a use-after- destroy is observed.
UUIDRemapper [source]¶
class UUIDRemapperClones values and operations with fresh UUIDs and logical_ids.
Used during inlining to create unique identities for values when a block is called multiple times.
Constructor¶
def __init__(self)Attributes¶
logical_id_remap: dict[str, str] Get the mapping from old logical_ids to new logical_ids.uuid_remap: dict[str, str] Get the mapping from old UUIDs to new UUIDs.
Methods¶
clone_operation¶
def clone_operation(self, op: Operation) -> OperationClone an operation with fresh UUIDs for all values.
Cloning goes through the Operation.all_input_values() /
Operation.replace_values() protocol so every Value-typed
field — including subclass extras (ControlledUOperation.power,
ForOperation.loop_var_value, ForItemsOperation.key_var_values
etc.) — is cloned consistently with the body references that
point to it. Without this, a subclass field could keep an old
UUID while body operands referencing the same logical Value got
fresh UUIDs, breaking identity-by-UUID lookups at emit time.
Parameters:
| Name | Type | Description |
|---|---|---|
op | Operation | Operation to clone. |
Returns:
Operation — A clone of op with every owned Value (operands,
results, subclass-extra fields) and every nested-body Value
reassigned a fresh UUID / logical_id, and with
CastOperation.qubit_mapping carrier keys remapped.
clone_operations¶
def clone_operations(self, operations: list[Operation]) -> list[Operation]Clone a list of operations with fresh UUIDs.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to clone in order. |
Returns:
list[Operation] — list[Operation]: Cloned operations, each with fresh UUIDs, in the
same order as operations.
clone_value¶
def clone_value(self, value: ValueBase) -> ValueBaseClone any value type with a fresh UUID and logical_id.
Handles Value, ArrayValue, TupleValue, and DictValue through
the unified ValueBase protocol. Nested values (tuple elements, dict
entries, parent_array / element_indices / shape / slice
fields) and embedded metadata references are cloned consistently.
Results are cached by source UUID so a repeated clone returns the
same instance.
Parameters:
| Name | Type | Description |
|---|---|---|
value | ValueBase | The value to clone. |
Returns:
ValueBase — The cloned value of the same concrete type, with a
fresh UUID / logical_id and its nested values and metadata
references remapped through this remapper.
ValidateWhileContractPass [source]¶
class ValidateWhileContractPass(Pass[Block, Block])Validates that all WhileOperation conditions are measurement-backed.
Builds a producer map (result UUID → producing Operation instance) and checks every WhileOperation operand against it. A valid condition must be:
A
ValuewithBitTypeMeasurement-backed: produced by
MeasureOperationdirectly, or byIfOperation/PhiOpwhere every reachable leaf source is itself measurement-backed.
Both operands[0] (initial condition) and operands[1]
(loop-carried condition) are validated.
Raises ValidationError for any non-measurement while pattern.
Attributes¶
name: str
Methods¶
run¶
def run(self, block: Block) -> BlockValidate all WhileOperations and return block unchanged.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
ValueCollector [source]¶
class ValueCollector(ControlFlowVisitor)Collects Value UUIDs from operation operands and results.
Constructor¶
def __init__(self)Attributes¶
operand_uuids: set[str]result_uuids: set[str]
Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> Noneqamomile.circuit.transpiler.passes.affine_validate¶
Affine type validation pass: Verify quantum resources are used correctly.
Overview¶
| Class | Description |
|---|---|
AffineTypeError | Base class for affine type violations. |
AffineValidationPass | Validate affine type semantics at IR level. |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
Pass | Base class for all compiler passes. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
Classes¶
AffineTypeError [source]¶
class AffineTypeError(QamomileCompileError)Base class for affine type violations.
Affine types enforce that quantum resources (qubits) are used at most once. This prevents common errors such as reusing a consumed qubit or aliasing.
Constructor¶
def __init__(
self,
message: str,
handle_name: str | None = None,
operation_name: str | None = None,
first_use_location: str | None = None,
)Attributes¶
first_use_locationhandle_nameoperation_name
AffineValidationPass [source]¶
class AffineValidationPass(Pass[Block, Block])Validate affine type semantics at IR level.
This pass serves as a safety net to catch affine type violations that may have bypassed the frontend checks. It verifies:
Each quantum value is used (consumed) at most once
Quantum values are not silently discarded
Input: Block (any kind) Output: Same Block (unchanged, validation only)
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockValidate affine type semantics in the block.
Raises:
ValidationError— If the block kind is not AFFINE.AffineTypeError— If a quantum value is consumed multiple times.
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationPass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
qamomile.circuit.transpiler.passes.analyze¶
Analyze pass: Validate and analyze dependencies in an affine block.
Overview¶
| Function | Description |
|---|---|
build_dependency_graph | Build a map from each value UUID to the UUIDs it depends on. |
find_measurement_derived_values | Forward-propagate measurement taint through the dependency graph. |
find_measurement_results | Find all value UUIDs that are direct results of measurement ops. |
| Class | Description |
|---|---|
AnalyzePass | Analyze and validate an affine block. |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
ControlFlowVisitor | Base class for visiting operations with control flow handling. |
DependencyError | Error when quantum operation depends on non-parameter classical value. |
MeasureOperation | |
MeasureVectorOperation | Measure a vector of qubits. |
OperationKind | Classification of operations for classical/quantum separation. |
Pass | Base class for all compiler passes. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Functions¶
build_dependency_graph [source]¶
def build_dependency_graph(operations: list[Operation]) -> dict[str, set[str]]Build a map from each value UUID to the UUIDs it depends on.
Walks operations recursively (through HasNestedOps) and records,
for each result UUID, the set of operand UUIDs that produced it. Also
seeds an edge from each ArrayValue element (Value carrying
parent_array) to its parent array UUID, and walks the parent’s
slice_of chain so that a sliced view (e.g. s[0:4:2][i] for
s = qmc.measure(register)) inherits taint from the root measured
array. StripSliceArrayOpsPass removes the explicit
SliceArrayOperation boundary before this pass runs, so the
slice_of link is the only remaining connection between a view and
its root in the IR. Used downstream by measurement-taint analysis.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
dict[str, set[str]] — dict[str, set[str]]: Mapping result_uuid -> set(operand_uuid, ...).
find_measurement_derived_values [source]¶
def find_measurement_derived_values(dependency_graph: dict[str, set[str]], measurement_uuids: set[str]) -> set[str]Forward-propagate measurement taint through the dependency graph.
Parameters:
| Name | Type | Description |
|---|---|---|
dependency_graph | dict[str, set[str]] | result_uuid -> set(operand_uuid, ...) as produced by build_dependency_graph, including the parent-array / slice-of edges that connect measured-vector elements to the root measured array. |
measurement_uuids | set[str] | Seed set (results of MeasureOperation / MeasureVectorOperation collected by find_measurement_results). |
Returns:
set[str] — set[str]: The set of all UUIDs transitively derived from a
measurement, including the seeds themselves.
find_measurement_results [source]¶
def find_measurement_results(operations: list[Operation]) -> set[str]Find all value UUIDs that are direct results of measurement ops.
Walks operations recursively (through HasNestedOps) and collects
every measurement result’s UUID, covering both scalar
MeasureOperation and vector MeasureVectorOperation. The
returned set is the seed for taint propagation; Vector[Bit]
element accesses inherit the parent array’s taint through the
parent-array edges added by build_dependency_graph.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
set[str] — set[str]: Result UUIDs of every measurement operation.
Classes¶
AnalyzePass [source]¶
class AnalyzePass(Pass[Block, Block])Analyze and validate an affine block.
This pass:
Builds a dependency graph between values (used locally for validation)
Validates that quantum ops don’t depend on non-parameter classical results
Checks that block inputs/outputs are classical
Input: Block with BlockKind.AFFINE Output: Block with BlockKind.ANALYZED
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockAnalyze the block and validate dependencies.
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
ControlFlowVisitor [source]¶
class ControlFlowVisitor(ABC)Base class for visiting operations with control flow handling.
Subclasses override visit_operation to define per-operation behavior.
Control flow recursion is handled automatically by the base class.
Example:
class MeasurementCounter(ControlFlowVisitor):
def __init__(self):
self.count = 0
def visit_operation(self, op: Operation) -> None:
if isinstance(op, MeasureOperation):
self.count += 1Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneProcess a single operation. Override in subclasses.
visit_operations¶
def visit_operations(self, operations: list[Operation]) -> NoneVisit all operations including nested control flow.
DependencyError [source]¶
class DependencyError(QamomileCompileError)Error when quantum operation depends on non-parameter classical value.
This error indicates that the program requires JIT compilation which is not yet supported.
Constructor¶
def __init__(
self,
message: str,
quantum_op: str | None = None,
classical_value: str | None = None,
)Attributes¶
classical_valuequantum_op
MeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
OperationKind [source]¶
class OperationKind(enum.Enum)Classification of operations for classical/quantum separation.
This enum is used to categorize operations during compilation to determine which parts run on classical hardware vs quantum hardware.
Values:
QUANTUM: Pure quantum operations (gates, qubit allocation) CLASSICAL: Pure classical operations (arithmetic, comparisons) HYBRID: Operations that bridge classical and quantum (measurement, encode/decode) CONTROL: Control flow structures (for, while, if)
Attributes¶
CLASSICALCONTROLHYBRIDQUANTUM
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.classical_lowering¶
Classical-op lowering pass: identify runtime-evaluation classical ops.
Walks the block, identifies CompOp / CondOp / NotOp / BinOp
instances whose 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), and replaces them with the equivalent
RuntimeClassicalExpr.
Why this pass exists:
The pre-RuntimeClassicalExpr design left runtime classical ops in
their compile-time IR form (CompOp etc.) all the way to emit, where
the emit pass had to fold-or-translate via evaluate_classical_predicate
_build_runtime_predicate_expr. This put backend-specific lowering logic inside the emit pass and used thebindingsdict as a polymorphic slot holding either Python scalars (fold result) or backendExprobjects.
By identifying runtime classical ops at IR level and giving them their own node type, we:
Make “runtime evaluation required” structurally explicit in the IR.
Move backend lowering to a dedicated emit hook (
_emit_runtime_classical_expr).Preserve the existing fold path for ops that can fold at compile or emit time (loop-bound or parameter-bound) — those are not measurement- derived and stay as
CompOp/CondOp/NotOp/BinOp.
Overview¶
| Function | Description |
|---|---|
build_dependency_graph | Build a map from each value UUID to the UUIDs it depends on. |
find_measurement_derived_values | Forward-propagate measurement taint through the dependency graph. |
find_measurement_results | Find all value UUIDs that are direct results of measurement ops. |
runtime_kind_from_binop | Map a BinOpKind to its RuntimeOpKind counterpart. |
runtime_kind_from_compop | Map a CompOpKind to its RuntimeOpKind counterpart. |
runtime_kind_from_condop | Map a CondOpKind to its RuntimeOpKind counterpart. |
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
ClassicalLoweringPass | Lower measurement-derived classical ops to RuntimeClassicalExpr. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CondOp | Conditional logical operation (AND, OR). |
HasNestedOps | Mixin for operations that contain nested operation lists. |
NotOp | |
Pass | Base class for all compiler passes. |
RuntimeClassicalExpr | A classical expression known to require runtime evaluation. |
ValueBase | Protocol for IR values with typed metadata. |
Functions¶
build_dependency_graph [source]¶
def build_dependency_graph(operations: list[Operation]) -> dict[str, set[str]]Build a map from each value UUID to the UUIDs it depends on.
Walks operations recursively (through HasNestedOps) and records,
for each result UUID, the set of operand UUIDs that produced it. Also
seeds an edge from each ArrayValue element (Value carrying
parent_array) to its parent array UUID, and walks the parent’s
slice_of chain so that a sliced view (e.g. s[0:4:2][i] for
s = qmc.measure(register)) inherits taint from the root measured
array. StripSliceArrayOpsPass removes the explicit
SliceArrayOperation boundary before this pass runs, so the
slice_of link is the only remaining connection between a view and
its root in the IR. Used downstream by measurement-taint analysis.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
dict[str, set[str]] — dict[str, set[str]]: Mapping result_uuid -> set(operand_uuid, ...).
find_measurement_derived_values [source]¶
def find_measurement_derived_values(dependency_graph: dict[str, set[str]], measurement_uuids: set[str]) -> set[str]Forward-propagate measurement taint through the dependency graph.
Parameters:
| Name | Type | Description |
|---|---|---|
dependency_graph | dict[str, set[str]] | result_uuid -> set(operand_uuid, ...) as produced by build_dependency_graph, including the parent-array / slice-of edges that connect measured-vector elements to the root measured array. |
measurement_uuids | set[str] | Seed set (results of MeasureOperation / MeasureVectorOperation collected by find_measurement_results). |
Returns:
set[str] — set[str]: The set of all UUIDs transitively derived from a
measurement, including the seeds themselves.
find_measurement_results [source]¶
def find_measurement_results(operations: list[Operation]) -> set[str]Find all value UUIDs that are direct results of measurement ops.
Walks operations recursively (through HasNestedOps) and collects
every measurement result’s UUID, covering both scalar
MeasureOperation and vector MeasureVectorOperation. The
returned set is the seed for taint propagation; Vector[Bit]
element accesses inherit the parent array’s taint through the
parent-array edges added by build_dependency_graph.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
set[str] — set[str]: Result UUIDs of every measurement operation.
runtime_kind_from_binop [source]¶
def runtime_kind_from_binop(kind: BinOpKind) -> RuntimeOpKindMap a BinOpKind to its RuntimeOpKind counterpart.
runtime_kind_from_compop [source]¶
def runtime_kind_from_compop(kind: CompOpKind) -> RuntimeOpKindMap a CompOpKind to its RuntimeOpKind counterpart.
runtime_kind_from_condop [source]¶
def runtime_kind_from_condop(kind: CondOpKind) -> RuntimeOpKindMap a CondOpKind to its RuntimeOpKind counterpart.
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
ClassicalLoweringPass [source]¶
class ClassicalLoweringPass(Pass[Block, Block])Lower measurement-derived classical ops to RuntimeClassicalExpr.
Input: Block with BlockKind.ANALYZED.
Output: Block with BlockKind.ANALYZED (same kind; only op rewrites).
The pass:
Builds a measurement-taint set using the same dataflow utilities as
AnalyzePass(forward propagation fromMeasureOperationresults through the dependency graph).Walks operations recursively (through
HasNestedOps).For each
CompOp/CondOp/NotOp/BinOpwhose result UUID is in the taint set, replaces it with an equivalentRuntimeClassicalExpr(same operands and result Value, only the op type and kind enum change).Non-tainted classical ops are left unchanged so the existing fold paths (compile-time fold in
compile_time_if_lowering, emit-time fold inevaluate_classical_predicate) continue to handle them.
The dependency graph and taint set are computed once, walked once, so the pass is O(N) where N is the number of operations.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockCompOp [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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
NotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
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:
Binary kinds (EQ/NEQ/LT/LE/GT/GE/AND/OR/ADD/SUB/MUL/DIV/FLOORDIV/MOD/POW):
operands = [lhs, rhs].Unary kind (NOT):
operands = [val].Result:
results = [output_value].
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,
) -> NoneAttributes¶
kind: RuntimeOpKind | Noneoperation_kind: OperationKindsignature: Signature
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.compile_time_if_lowering¶
Compile-time IfOperation lowering pass.
Lowers compile-time resolvable IfOperations before the segmentation pass,
replacing them with selected-branch operations and substituting phi outputs
with selected-branch values throughout the block.
This prevents SegmentationPass from seeing classical-only compile-time
IfOperations that would otherwise split quantum segments.
Overview¶
| Function | Description |
|---|---|
fold_classical_op | Fold a classical op to a concrete value, respecting the given policy. |
resolve_root_array_index | Fold a view-local element index into the root array’s index space. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CompileTimeIfLoweringPass | Lowers compile-time resolvable IfOperations before separation. |
CondOp | Conditional logical operation (AND, OR). |
FoldPolicy | Policy controlling how fold_classical_op treats parameters. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
NotOp | |
Pass | Base class for all compiler passes. |
PhiOp | SSA Phi function: merge point after conditional branch. |
UnifiedValueResolver | Resolve IR Values to concrete Python values. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Functions¶
fold_classical_op [source]¶
def fold_classical_op(
op: 'BinOp | CompOp | CondOp | NotOp',
operand_resolver: Callable[[Any], Any],
parameters: set[str],
policy: FoldPolicy,
) -> Any | NoneFold a classical op to a concrete value, respecting the given policy.
The caller supplies an operand_resolver callable that knows how
to look up a Value in the caller’s context (a concrete_values
map, an emit bindings dict + ValueResolver, or any other
source). This function handles:
The parameter guard (skips folding when an operand is a runtime parameter or parameter-array element under
EMIT_RESPECT_PARAMS).Strict scalar-only typing (rejects backend
Exprobjects and other non-numeric values that would spuriously fold toTrue).Kind dispatch via the underlying
evaluate_*_valuesprimitives.
Parameters:
| Name | Type | Description |
|---|---|---|
op | 'BinOp | CompOp | CondOp | NotOp' | The classical op to fold. Must be one of BinOp, CompOp, CondOp, NotOp. |
operand_resolver | Callable[[Any], Any] | Callable mapping each operand Value to a resolved Python scalar (or None when unresolvable). |
parameters | set[str] | Set of runtime parameter names. Used only when policy is EMIT_RESPECT_PARAMS. |
policy | FoldPolicy | Folding policy. See FoldPolicy docstring. |
Returns:
Any | None — The folded value (numeric for BinOp, bool for predicates),
Any | None — or None when any operand is symbolic, missing, or a runtime
Any | None — parameter under the policy.
resolve_root_array_index [source]¶
def resolve_root_array_index(array: 'ArrayValue', index: int) -> tuple['ArrayValue', int] | NoneFold a view-local element index into the root array’s index space.
Walks the slice_of chain root-ward, composing each strided view’s
affine map parent_index = start + step * local_index. This is the
array-level counterpart of :func:resolve_root_qubit_address (which
starts from an array-element Value); both must stay consistent with
the composite carrier keys "<root_uuid>_<root_index>" registered by
QInitOperation at emit time.
Parameters:
| Name | Type | Description |
|---|---|---|
array | ArrayValue | Array the index is local to. May be a root array (slice_of unset) or an arbitrarily nested strided view. |
index | int | Element index in array’s own index space. |
Returns:
tuple['ArrayValue', int] | None — tuple[ArrayValue, int] | None: (root_array, composed_index) when
every slice bound on the chain is compile-time constant and
satisfies the frontend contract (non-negative slice_start,
positive slice_step). None when any slice_start /
slice_step on the chain is missing, symbolic, or violates
that contract; callers must then defer resolution rather than
guess. Out-of-contract bounds would compose index onto a
wrong root slot, so they are refused here too (the frontend
rejects them at trace time; this guard covers programmatically
constructed IR).
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
CompileTimeIfLoweringPass [source]¶
class CompileTimeIfLoweringPass(Pass[Block, Block])Lowers compile-time resolvable IfOperations before separation.
After constant folding, some IfOperation conditions are statically
known but remain as control-flow nodes. SegmentationPass treats them
as segment boundaries, causing MultipleQuantumSegmentsError for
classical-only compile-time if after quantum init.
This pass:
Evaluates conditions including expression-derived ones (
CompOp,CondOp,NotOpchains).Replaces resolved
IfOperations with selected-branch operations.Substitutes phi output UUIDs with selected-branch values in all subsequent operations and block outputs.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun the compile-time if lowering pass.
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
FoldPolicy [source]¶
class FoldPolicy(enum.Enum)Policy controlling how fold_classical_op treats parameters.
COMPILE_TIME is for passes that have no notion of runtime
parameters (e.g. compile_time_if_lowering); every operand the
resolver returns is treated as a real value to fold.
EMIT_RESPECT_PARAMS is for emit-time passes where some Values
may correspond to runtime backend parameters whose concrete values
are placeholders or absent. Operands whose Value or
parent_array.name is in the active parameters set are
treated as symbolic and the fold returns None rather than
producing an incorrect concrete result.
Attributes¶
COMPILE_TIMEEMIT_RESPECT_PARAMS
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationNotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
PhiOp [source]¶
class PhiOp(Operation)SSA Phi function: merge point after conditional branch.
This operation selects one of two values based on a condition. Used to merge values from different branches of an if-else statement.
Example:
if condition:
x = x + 1 # true_value
else:
x = x + 2 # false_value
# x is now PhiOp(condition, true_value, false_value)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
condition: Valuefalse_value: Valueoperation_kind: OperationKindoutput: Valuesignature: Signaturetrue_value: Value
ValueResolver [source]¶
class ValueResolverResolve IR Values to concrete Python values.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already resolved values. The values may be either raw Python scalars or Value objects; if a Value is found its get_const() is extracted automatically. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user at transpile time. |
Constructor¶
def __init__(
self,
context: dict[str, Any] | None = None,
bindings: dict[str, Any] | None = None,
)Create a resolver with optional context and bindings.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already-resolved values. Defaults to None. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user. Defaults to None. |
Methods¶
resolve¶
def resolve(self, value: Any) -> Any | NoneResolve a Value-like object to a concrete Python value.
If value is not a Value-like object (no uuid attribute) it
is returned as-is — the caller already has a concrete value.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Any | The Value-like object or already concrete value to resolve. |
Returns:
Any | None — Any | None: The resolved concrete value, the original
concrete value for non-Value inputs, or None when no
resolution rule applies.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.constant_fold¶
Constant folding pass for compile-time expression evaluation.
Overview¶
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
BinOpKind | |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
ConcreteControlledU | Controlled-U with concrete (int) number of controls. |
ConstantFoldingPass | Evaluates constant expressions at compile time. |
ControlledUOperation | Base class for controlled-U operations. |
OperationTransformer | Base class for transforming operations with control flow handling. |
Pass | Base class for all compiler passes. |
SymbolicControlledU | Controlled-U with symbolic (Value) number of controls. |
UnifiedValueResolver | Resolve IR Values to concrete Python values. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
BinOpKind [source]¶
class BinOpKind(enum.Enum)Attributes¶
ADDDIVFLOORDIVMINMODMULPOWSUB
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
ConcreteControlledU [source]¶
class ConcreteControlledU(ControlledUOperation)Controlled-U with concrete (int) number of controls.
Operand layout: [ctrl_0, ..., ctrl_n, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_0', ..., ctrl_n', tgt_0', ..., tgt_m']
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int = 1,
) -> NoneAttributes¶
control_operands: list[Value]num_controls: intparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
ConstantFoldingPass [source]¶
class ConstantFoldingPass(Pass[Block, Block])Evaluates constant expressions at compile time.
This pass folds BinOp operations when all operands are constants or bound parameters, eliminating unnecessary classical operations that would otherwise split quantum segments.
Example:
Before (with bindings={"phase": 0.5}):
BinOp(phase * 2) -> classical segment split
After:
Constant 1.0 -> no segment splitConstructor¶
def __init__(self, bindings: dict[str, Any] | None = None, *, strip_slice_ops: bool = True)Create a constant-folding pass.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Compile-time parameter bindings used when folding BinOps that reference declared parameters. |
strip_slice_ops | bool | When True (default), removes SliceArrayOperation nodes after folding. Set to False when a downstream pass — notably SliceBorrowCheckPass — still needs to observe slice declaration points in program order to decide view liveness. A separate strip pass must then run after the linearity check so segmentation still sees a pure quantum-op stream. |
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun constant folding on the block.
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationOperationTransformer [source]¶
class OperationTransformer(ABC)Base class for transforming operations with control flow handling.
Subclasses override transform_operation to define per-operation transformation.
Control flow recursion and rebuilding is handled automatically.
Example:
class OperationRenamer(OperationTransformer):
def transform_operation(self, op: Operation) -> Operation:
# Return modified operation
return dataclasses.replace(op, ...)Methods¶
transform_operation¶
def transform_operation(self, op: Operation) -> Operation | NoneTransform a single operation. Return None to remove it.
transform_operations¶
def transform_operations(self, operations: list[Operation]) -> list[Operation]Transform all operations including nested control flow.
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
SymbolicControlledU [source]¶
class SymbolicControlledU(ControlledUOperation)Controlled-U with symbolic (Value) number of controls.
Operand layout: [ctrl_arg_0, ..., ctrl_arg_{k-1}, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_arg_0', ..., ctrl_arg_{k-1}', tgt_0', ..., tgt_m']
The number of control arguments k is recorded in
num_control_args; the default k = 1 corresponds to the
historical single-pool form (operands[0] is a
Vector[Qubit] / VectorView whose length equals
num_controls, or whose control_indices-selected subset
does). When k > 1 the control prefix is a heterogeneous
sequence of scalar Qubit values and ArrayValues whose
total qubit count is num_controls; the emit pass walks them
in order to recover the per-physical-qubit control set.
When control_indices is None the entire control prefix
is used as active controls (one-arg form: len(ctrl_vector) == num_controls; multi-arg form: the qubit-count sum of the
prefix args equals num_controls). When non-None, the
listed indices select exactly num_controls slots from a
single-arg pool to act as controls; combining
control_indices with the multi-arg control prefix is
rejected at frontend time.
Each control_indices entry is stored as a Value of
UIntType regardless of whether the frontend passed an
int literal or a UInt handle, so all downstream
value-substitution passes see a uniform shape.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: Value = (lambda: Value(type=(UIntType()), name=''))(),
control_indices: tuple[Value, ...] | None = None,
num_control_args: int = 1,
) -> NoneAttributes¶
control_indices: tuple[Value, ...] | Nonecontrol_operands: list[Value]is_symbolic_num_controls: boolnum_control_args: intnum_controls: Valueparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationValueResolver [source]¶
class ValueResolverResolve IR Values to concrete Python values.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already resolved values. The values may be either raw Python scalars or Value objects; if a Value is found its get_const() is extracted automatically. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user at transpile time. |
Constructor¶
def __init__(
self,
context: dict[str, Any] | None = None,
bindings: dict[str, Any] | None = None,
)Create a resolver with optional context and bindings.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already-resolved values. Defaults to None. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user. Defaults to None. |
Methods¶
resolve¶
def resolve(self, value: Any) -> Any | NoneResolve a Value-like object to a concrete Python value.
If value is not a Value-like object (no uuid attribute) it
is returned as-is — the caller already has a concrete value.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Any | The Value-like object or already concrete value to resolve. |
Returns:
Any | None — Any | None: The resolved concrete value, the original
concrete value for non-Value inputs, or None when no
resolution rule applies.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.control_flow_visitor¶
Control flow visitor for operation traversal.
Overview¶
| Class | Description |
|---|---|
ControlFlowVisitor | Base class for visiting operations with control flow handling. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
OperationCollector | Collects operations matching a predicate. |
OperationTransformer | Base class for transforming operations with control flow handling. |
ValueCollector | Collects Value UUIDs from operation operands and results. |
Classes¶
ControlFlowVisitor [source]¶
class ControlFlowVisitor(ABC)Base class for visiting operations with control flow handling.
Subclasses override visit_operation to define per-operation behavior.
Control flow recursion is handled automatically by the base class.
Example:
class MeasurementCounter(ControlFlowVisitor):
def __init__(self):
self.count = 0
def visit_operation(self, op: Operation) -> None:
if isinstance(op, MeasureOperation):
self.count += 1Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneProcess a single operation. Override in subclasses.
visit_operations¶
def visit_operations(self, operations: list[Operation]) -> NoneVisit all operations including nested control flow.
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
OperationCollector [source]¶
class OperationCollector(ControlFlowVisitor)Collects operations matching a predicate.
Example:
collector = OperationCollector(lambda op: isinstance(op, MeasureOperation))
collector.visit_operations(block.operations)
measurements = collector.collectedConstructor¶
def __init__(self, predicate: Callable[[Operation], bool])Attributes¶
collected: list[Operation]
Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneOperationTransformer [source]¶
class OperationTransformer(ABC)Base class for transforming operations with control flow handling.
Subclasses override transform_operation to define per-operation transformation.
Control flow recursion and rebuilding is handled automatically.
Example:
class OperationRenamer(OperationTransformer):
def transform_operation(self, op: Operation) -> Operation:
# Return modified operation
return dataclasses.replace(op, ...)Methods¶
transform_operation¶
def transform_operation(self, op: Operation) -> Operation | NoneTransform a single operation. Return None to remove it.
transform_operations¶
def transform_operations(self, operations: list[Operation]) -> list[Operation]Transform all operations including nested control flow.
ValueCollector [source]¶
class ValueCollector(ControlFlowVisitor)Collects Value UUIDs from operation operands and results.
Constructor¶
def __init__(self)Attributes¶
operand_uuids: set[str]result_uuids: set[str]
Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> Noneqamomile.circuit.transpiler.passes.emit¶
Emit pass: Generate backend-specific code from separated program.
Overview¶
| Function | Description |
|---|---|
resolve_root_qubit_address | Resolve an array-element value to its root (array_uuid, index). |
| Class | Description |
|---|---|
ClassicalSegment | A segment of pure classical operations. |
ClassicalStep | A classical execution step. |
CompositeGateEmitter | Protocol for backend-specific CompositeGate emitters. |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
CompositeGateType | Registry of known composite gate types. |
EmitPass | Base class for backend-specific emission passes. |
ExecutableProgram | A fully compiled program ready for execution. |
ExpvalSegment | A segment for expectation value computation. |
ExpvalStep | An expectation-value execution step. |
Pass | Base class for all compiler passes. |
ProgramPlan | Execution plan for a hybrid quantum/classical program. |
QuantumSegment | A segment of pure quantum operations. |
QuantumStep | A quantum execution step. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolves Value objects to concrete indices or values. |
Functions¶
resolve_root_qubit_address [source]¶
def resolve_root_qubit_address(value: 'Value') -> tuple[str, int] | NoneResolve an array-element value to its root (array_uuid, index).
Walks the parent_array / slice_of chain and composes the nested
affine slice maps, so view[i] resolves to
(root_uuid, start + step * i) for the composed (start, step). The
returned pair is the build-stable identity of the physical qubit slot: the
root array’s QInitOperation always registers it as
QubitAddress(root_uuid, index), so this address resolves even when the
element’s own (per-version) UUID was never registered.
The transpiler’s resource allocator uses the same walk to resolve gate and measurement operands; this shared helper keeps both call sites consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Value | The value to resolve. Expected to be an array element (parent_array set with a single constant element_indices entry). |
Returns:
tuple[str, int] | None — tuple[str, int] | None: (root_array_uuid, composed_index) when
value is an array element with a constant index whose entire
slice_of chain has constant slice_start / slice_step.
None when value is not an array element, when its index is
non-constant, or when any slice bound in the chain is non-constant
(those cases are deferred to the emit-time resolver, which has
bindings available). Also None for a negative constant index
or a chain frame with negative slice_start / non-positive
slice_step — composing those would silently address a wrong
root slot, so they are refused rather than guessed (the frontend
rejects them at trace time; this guard covers programmatically
constructed IR).
Classes¶
ClassicalSegment [source]¶
class ClassicalSegment(Segment)A segment of pure classical operations.
Contains arithmetic, comparisons, and control flow. Will be executed directly in Python.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
kind: SegmentKind
ClassicalStep [source]¶
class ClassicalStepA classical execution step.
Constructor¶
def __init__(self, segment: ClassicalSegment, role: str = 'classical') -> NoneAttributes¶
role: strsegment: ClassicalSegment
CompositeGateEmitter [source]¶
class CompositeGateEmitter(Protocol[C])Protocol for backend-specific CompositeGate emitters.
Each backend can implement emitters for specific composite gate types (QPE, QFT, IQFT, etc.) using native backend libraries.
The emitter pattern allows:
Backends to use native implementations when available (e.g., Qiskit QFT)
Fallback to manual decomposition when native is unavailable
Easy addition of new backends without modifying core code
Example:
class QiskitQFTEmitter:
def can_emit(self, gate_type: CompositeGateType) -> bool:
return gate_type in (CompositeGateType.QFT, CompositeGateType.IQFT)
def emit(self, circuit, op, qubit_indices, bindings) -> bool:
from qiskit.circuit.library import QFTGate
qft_gate = QFTGate(len(qubit_indices))
circuit.append(qft_gate, qubit_indices)
return TrueMethods¶
can_emit¶
def can_emit(self, gate_type: CompositeGateType) -> boolCheck if this emitter can handle the given gate type.
Parameters:
| Name | Type | Description |
|---|---|---|
gate_type | CompositeGateType | The CompositeGateType to check |
Returns:
bool — True if this emitter supports native emission for the gate type
emit¶
def emit(
self,
circuit: C,
op: CompositeGateOperation,
qubit_indices: list[int],
bindings: dict[str, Any],
) -> boolEmit the composite gate to the circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | C | The backend-specific circuit to emit to |
op | CompositeGateOperation | The CompositeGateOperation to emit |
qubit_indices | list[int] | Physical qubit indices for the operation |
bindings | dict[str, Any] | Parameter bindings for the operation |
Returns:
bool — True if emission succeeded, False to fall back to manual decomposition
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
CompositeGateType [source]¶
class CompositeGateType(enum.Enum)Registry of known composite gate types.
Attributes¶
CUSTOMIQFTQFTQPE
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:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Values to bind parameters to. If not provided, parameters must be bound at execution time. |
parameters | list[str] | None | List of parameter names to preserve as backend parameters. |
Attributes¶
bindingsname: strparameters
Methods¶
run¶
def run(self, input: ProgramPlan) -> ExecutableProgram[T]Emit backend code from a program plan.
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 typeConstructor¶
def __init__(
self,
plan: ProgramPlan | None = None,
compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
compiled_classical: list[CompiledClassicalSegment] = list(),
compiled_expval: list[CompiledExpvalSegment] = list(),
output_refs: list[str] = list(),
num_output_bits: int = 0,
) -> NoneAttributes¶
compiled_classical: list[CompiledClassicalSegment]compiled_expval: list[CompiledExpvalSegment]compiled_quantum: list[CompiledQuantumSegment[T]]has_parameters: bool Check if this program has unbound parameters.num_output_bits: intoutput_refs: list[str]parameter_names: list[str] Get list of parameter names that need binding.plan: ProgramPlan | Nonequantum_circuit: T Get the single quantum circuit.
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 | NoneGet the first quantum circuit, or None if no quantum segments.
run¶
def run(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None = None,
) -> RunJob[Any] | ExpvalJobExecute once and return single result.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
RunJob[Any] | ExpvalJob — RunJob that resolves to the kernel’s return type, or
RunJob[Any] | ExpvalJob — ExpvalJob if the program contains expectation value computation.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
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]Execute with multiple shots and return counts.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
shots | int | Number of shots to run. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
SampleJob[Any] — SampleJob that resolves to SampleResult with results.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
Example:
job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results) # [(0.25, 500), (0.75, 500)]ExpvalSegment [source]¶
class ExpvalSegment(Segment)A segment for expectation value computation.
Represents computing <psi|H|psi> where psi is the quantum state and H is a Hamiltonian observable.
This segment bridges a quantum circuit (state preparation) to a classical expectation value.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
hamiltonian_value: Value | None = None,
qubits_value: Value | None = None,
result_ref: str = '',
) -> NoneAttributes¶
hamiltonian_value: Value | Nonekind: SegmentKindqubits_value: Value | Noneresult_ref: str
ExpvalStep [source]¶
class ExpvalStepAn expectation-value execution step.
Constructor¶
def __init__(self, segment: ExpvalSegment, quantum_step_index: int = 0) -> NoneAttributes¶
quantum_step_index: intsegment: ExpvalSegment
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ProgramPlan [source]¶
class ProgramPlanExecution plan for a hybrid quantum/classical program.
Structure:
[Optional] Classical preprocessing (parameter computation, etc.)
Single quantum segment (REQUIRED)
[Optional] Expval segment OR classical postprocessing
This plan enforces Qamomile’s current execution model: all quantum operations must be in a single quantum circuit.
Constructor¶
def __init__(
self,
steps: list[ProgramStep] = list(),
abi: ProgramABI = ProgramABI(),
boundaries: list[HybridBoundary] = list(),
parameters: dict[str, Value] = dict(),
) -> NoneAttributes¶
abi: ProgramABIboundaries: list[HybridBoundary]parameters: dict[str, Value]steps: list[ProgramStep]
QuantumSegment [source]¶
class QuantumSegment(Segment)A segment of pure quantum operations.
Contains quantum gates and qubit allocations. Will be emitted to a quantum circuit.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
qubit_values: list[Value] = list(),
num_qubits: int = 0,
) -> NoneAttributes¶
kind: SegmentKindnum_qubits: intqubit_values: list[Value]
QuantumStep [source]¶
class QuantumStepA quantum execution step.
Constructor¶
def __init__(self, segment: QuantumSegment) -> NoneAttributes¶
segment: QuantumSegment
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)qamomile.circuit.transpiler.passes.emit_support¶
Shared helpers for backend emission.
Overview¶
| Function | Description |
|---|---|
map_phi_outputs | Register phi output UUIDs to the same physical resources as their sources. |
remap_static_phi_outputs | Remap phi outputs for a compile-time constant IfOperation. |
resolve_condition_address | Resolve a runtime control-flow condition to its clbit_map key. |
resolve_if_condition | Resolve an if-condition to a compile-time boolean. |
resolve_qubit_key | Resolve a qubit Value to its allocation key. |
| Class | Description |
|---|---|
CompositeDecomposer | Decomposes composite gates into primitive operations. |
LoopAnalyzer | Analyzes loop structures to determine emission strategy. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
QubitResolutionResult | Result of attempting to resolve a qubit index. |
ResourceAllocator | Allocates qubit and classical bit indices from operations. |
ValueResolver | Resolves Value objects to concrete indices or values. |
Functions¶
map_phi_outputs [source]¶
def map_phi_outputs(
phi_ops: list,
qubit_map: QubitMap,
clbit_map: ClbitMap,
resolve_scalar_qubit: Any = None,
) -> NoneRegister phi output UUIDs to the same physical resources as their sources.
remap_static_phi_outputs [source]¶
def remap_static_phi_outputs(
phi_ops: list,
condition_value: bool,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneRemap phi outputs for a compile-time constant IfOperation.
resolve_condition_address [source]¶
def resolve_condition_address(
condition: Value,
bindings: dict[str, Any],
resolver: ValueResolver | None,
) -> QubitAddressResolve a runtime control-flow condition to its clbit_map key.
Scalar measurement results carry their own UUID and the clbit allocator
registers them under QubitAddress(bit.uuid). Vector[Bit] element
accesses (s[i] where s = qmc.measure(register)) instead live
under QubitAddress(root_array.uuid, root_index). The element index
and every slice_start / slice_step along the parent’s
slice_of chain are resolved the same way — taken directly when
constant, otherwise folded through bindings via resolver so
that loop-variable indices and runtime-valued slice bounds (s[j:k]
where j/k are loop variables) both work. The chain composes
into a root-space index via the standard affine map
root_index = start + step * view_local_index repeated along the
chain — matching ResourceAllocator._resolve_root_qubit_address /
ValueResolver.resolve_slice_chain. Falls back to the scalar
address when no parent array is set, or when the index or any slice
bound cannot be resolved to a concrete int (e.g. a backend runtime
parameter, which cannot index a static classical register, or any
symbolic value with no resolver), deferring the diagnostic to the
caller’s clbit_map lookup. Used by both the default if/while
emission path and the Qiskit / CUDA-Q backends when looking up a
measurement-derived clbit for a runtime predicate.
Parameters:
| Name | Type | Description |
|---|---|---|
condition | Value | Condition operand of an IfOperation or WhileOperation, or an operand of a measurement-derived classical predicate (e.g. inside RuntimeClassicalExpr). |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic indices and slice bounds (loop variables, compile-time-bound parameters). |
resolver | ValueResolver | None | The active ValueResolver exposing resolve_int_value. None is accepted for early-emit pre-scans (e.g. CUDA-Q’s loop-carried clbit collector) that run before runtime bindings exist — only the constant path is taken in that case; symbolic indices and symbolic slice bounds fall through to the scalar UUID. |
Returns:
QubitAddress — Key suitable for looking up the condition in
clbit_map.
resolve_if_condition [source]¶
def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | NoneResolve an if-condition to a compile-time boolean.
resolve_qubit_key [source]¶
def resolve_qubit_key(qubit: 'Value') -> tuple[QubitAddress | None, bool]Resolve a qubit Value to its allocation key.
Parameters:
| Name | Type | Description |
|---|---|---|
qubit | Value | Qubit value to resolve. Array elements with a constant index are resolved through their full slice_of chain to the root array address. |
Returns:
tuple[QubitAddress | None, bool] — tuple[QubitAddress | None, bool]: (address, is_array_element).
address is the root-space address for a resolvable array
element, None for an array element whose index or slice
bounds are symbolic at this binding-free stage, and a scalar
UUID address for non-array qubits. A negative constant index
(or an out-of-contract slice bound) also yields None:
resolve_root_qubit_address refuses it rather than letting it
silently address a wrong root slot.
Classes¶
CompositeDecomposer [source]¶
class CompositeDecomposerDecomposes composite gates into primitive operations.
Methods¶
iqft_structure¶
@staticmethod
def iqft_structure(n: int) -> list[tuple[str, tuple[int, ...], float | None]]qft_structure¶
@staticmethod
def qft_structure(n: int) -> list[tuple[str, tuple[int, ...], float | None]]LoopAnalyzer [source]¶
class LoopAnalyzerAnalyzes loop structures to determine emission strategy.
Methods¶
should_unroll¶
def should_unroll(self, op: ForOperation, bindings: dict[str, object]) -> boolQubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
QubitResolutionResult [source]¶
class QubitResolutionResultResult of attempting to resolve a qubit index.
Constructor¶
def __init__(
self,
success: bool,
index: int | None = None,
failure_reason: ResolutionFailureReason | None = None,
failure_details: str = '',
) -> NoneAttributes¶
failure_details: strfailure_reason: ResolutionFailureReason | Noneindex: int | Nonesuccess: bool
ResourceAllocator [source]¶
class ResourceAllocatorAllocates qubit and classical bit indices from operations.
This class handles the first pass of circuit emission: determining how many physical qubits and classical bits are needed and mapping Value UUIDs to their physical indices.
New physical indices are assigned via monotonic counters
(_next_qubit_index / _next_clbit_index) so that alias
entries — which reuse an existing physical index — never inflate
the counter. Using len(map) would cause sparse (gapped)
physical indices because alias keys increase the map size without
adding new physical resources.
Constructor¶
def __init__(self, resolver: ValueResolver | None = None) -> NoneInitialize allocator state.
Parameters:
| Name | Type | Description |
|---|---|---|
resolver | ValueResolver | None | Emit value resolver that carries runtime parameter names and binding lookup rules. Defaults to None, which creates a resolver without runtime parameters. |
Methods¶
allocate¶
def allocate(
self,
operations: list[Operation],
bindings: dict[str, Any] | None = None,
initial_qubit_map: QubitMap | None = None,
initial_clbit_map: ClbitMap | None = None,
) -> tuple[QubitMap, ClbitMap]Allocate qubit and clbit indices for all operations.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to allocate resources for. |
bindings | dict[str, Any] | None | Optional variable bindings for resolving dynamic sizes. Defaults to None (treated as an empty mapping). |
initial_qubit_map | QubitMap | None | Optional pre-populated qubit address mapping. Used by callers that need to seed the allocator with bindings established outside the operation list — for instance, the inner-block emitter in blockvalue_to_gate pre-allocates Vector[Qubit] input elements (the inner block has no QInitOperation for inputs, so per-element entries must be supplied here or the assertion in _allocate_gate fires). The map is copied; allocation continues from max(values) + 1 so new QInitOperation allocations inside operations do not collide. Defaults to None (treated as empty). |
initial_clbit_map | ClbitMap | None | Optional pre-populated clbit address mapping. Same semantics as initial_qubit_map but for classical bits. Defaults to None. |
Returns:
tuple[QubitMap, ClbitMap] — tuple[QubitMap, ClbitMap]: (qubit_map, clbit_map) where
each maps QubitAddress to a physical index. If an
initial map was supplied, its entries are preserved
verbatim in the returned map.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)qamomile.circuit.transpiler.passes.emit_support.cast_binop_emission¶
Cast and binary-operation emission helpers for StandardEmitPass.
Extracted from standard_emit.py to keep the main class focused on
gate-level dispatch. Each function mirrors the original method but takes
an explicit emit_pass parameter instead of self.
Overview¶
| Function | Description |
|---|---|
default_combine_symbolic | Default combine_symbolic for backends with arithmetic-capable Parameters. |
evaluate_binop | Evaluate a BinOp and store the result in bindings. |
evaluate_classical_predicate | Evaluate a CompOp/CondOp/NotOp at emit time and bind its boolean result. |
fold_classical_op | Fold a classical op to a concrete value, respecting the given policy. |
handle_cast | Handle CastOperation - update qubit_map without emitting gates. |
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
CastOperation | Type cast operation for creating aliases over the same quantum resources. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CondOp | Conditional logical operation (AND, OR). |
FoldPolicy | Policy controlling how fold_classical_op treats parameters. |
NotOp | |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Functions¶
default_combine_symbolic [source]¶
def default_combine_symbolic(kind: 'BinOpKind', lhs: Any, rhs: Any) -> AnyDefault combine_symbolic for backends with arithmetic-capable Parameters.
Performs Python operator dispatch on the operands. Used by
evaluate_binop whenever the active emitter does not define its
own combine_symbolic method — the typical case for Qiskit
(ParameterExpression overloads __add__ etc.) and CUDA-Q
parameters. Backends whose Parameter type lacks Python operators
(e.g. QURI Parts) define their own combine_symbolic on the
emitter class to return a backend-native symbolic representation
instead.
Parameters:
| Name | Type | Description |
|---|---|---|
kind | 'BinOpKind' | The BinOpKind to apply. |
lhs | Any | Left operand (numeric or backend Parameter / expression). |
rhs | Any | Right operand (same shape). |
Returns:
Any — lhs OP rhs for the matching operator. 0.0 / 0 for
Any — division-by-zero in the symbolic path so the caller can finish
Any — emission without aborting on a numerically degenerate case.
Any — None for unrecognised kind values, which the caller
Any — treats as a no-op.
evaluate_binop [source]¶
def evaluate_binop(emit_pass: 'StandardEmitPass', op: BinOp, bindings: dict[str, Any]) -> NoneEvaluate a BinOp and store the result in bindings.
Tries the shared fold_classical_op first for a clean concrete
fold (which already encapsulates the runtime-parameter guard).
Falls back to creating backend Parameter symbols and doing
symbolic arithmetic when one or both operands are runtime
parameters — that’s the path that lets rx(q, gamma * 2) produce
a circuit with a single Parameter("gamma") * 2 expression rather
than baking in a placeholder.
evaluate_classical_predicate [source]¶
def evaluate_classical_predicate(
emit_pass: 'StandardEmitPass',
op: 'CompOp | CondOp | NotOp',
bindings: dict[str, Any],
) -> NoneEvaluate a CompOp/CondOp/NotOp at emit time and bind its boolean result.
Mirrors the predicate evaluation already done by
compile_time_if_lowering and classical_executor so that an
IfOperation whose condition reaches emit unfolded — typically
because its operands depend on a loop variable bound only at emit time
by emit_for_items / emit_for_unrolled — can still be resolved
via resolve_if_condition.
Delegates the actual fold (including runtime-parameter guard and
strict scalar typing) to fold_classical_op so that all three
callers of the same kind dispatch share one implementation. There
is no symbolic-Parameter fallback for predicates: a runtime classical
expression cannot be expressed as a folded scalar, so the op is left
unbound and downstream emit handles it as a runtime condition.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The active emit pass (for resolver access). |
op | 'CompOp | CondOp | NotOp' | The predicate op to evaluate. |
bindings | dict[str, Any] | Current parameter/loop-variable bindings; mutated in place on successful evaluation. No-op when operands are unresolvable (e.g. measurement bits) or evaluation raises. |
Returns:
None — None.
fold_classical_op [source]¶
def fold_classical_op(
op: 'BinOp | CompOp | CondOp | NotOp',
operand_resolver: Callable[[Any], Any],
parameters: set[str],
policy: FoldPolicy,
) -> Any | NoneFold a classical op to a concrete value, respecting the given policy.
The caller supplies an operand_resolver callable that knows how
to look up a Value in the caller’s context (a concrete_values
map, an emit bindings dict + ValueResolver, or any other
source). This function handles:
The parameter guard (skips folding when an operand is a runtime parameter or parameter-array element under
EMIT_RESPECT_PARAMS).Strict scalar-only typing (rejects backend
Exprobjects and other non-numeric values that would spuriously fold toTrue).Kind dispatch via the underlying
evaluate_*_valuesprimitives.
Parameters:
| Name | Type | Description |
|---|---|---|
op | 'BinOp | CompOp | CondOp | NotOp' | The classical op to fold. Must be one of BinOp, CompOp, CondOp, NotOp. |
operand_resolver | Callable[[Any], Any] | Callable mapping each operand Value to a resolved Python scalar (or None when unresolvable). |
parameters | set[str] | Set of runtime parameter names. Used only when policy is EMIT_RESPECT_PARAMS. |
policy | FoldPolicy | Folding policy. See FoldPolicy docstring. |
Returns:
Any | None — The folded value (numeric for BinOp, bool for predicates),
Any | None — or None when any operand is symbolic, missing, or a runtime
Any | None — parameter under the policy.
handle_cast [source]¶
def handle_cast(emit_pass: 'StandardEmitPass', op: CastOperation, qubit_map: QubitMap) -> NoneHandle CastOperation - update qubit_map without emitting gates.
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
CastOperation [source]¶
class CastOperation(Operation)Type cast operation for creating aliases over the same quantum resources.
This operation does NOT allocate new qubits. It creates a new Value that references the same underlying quantum resources with a different type.
Use cases:
Vector[Qubit] -> QFixed (after QPE, for phase measurement)
Vector[Qubit] -> QUInt (for quantum arithmetic)
QUInt -> QFixed (reinterpret bits with different encoding)
QFixed -> QUInt (reinterpret bits with different encoding)
operands: [source_value] - The value being cast results: [cast_result] - The new value with target type (same physical qubits)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
source_type: ValueType | None = None,
target_type: ValueType | None = None,
qubit_mapping: list[str] = list(),
) -> NoneAttributes¶
num_qubits: int Number of qubits involved in the cast.operation_kind: OperationKind Cast stays in the same segment as its source (QUANTUM for quantum types).qubit_mapping: list[str]signature: Signature Return the type signature of this cast operation.source_type: ValueType | Nonetarget_type: ValueType | None
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
FoldPolicy [source]¶
class FoldPolicy(enum.Enum)Policy controlling how fold_classical_op treats parameters.
COMPILE_TIME is for passes that have no notion of runtime
parameters (e.g. compile_time_if_lowering); every operand the
resolver returns is treated as a real value to fold.
EMIT_RESPECT_PARAMS is for emit-time passes where some Values
may correspond to runtime backend parameters whose concrete values
are placeholders or absent. Operands whose Value or
parent_array.name is in the active parameters set are
treated as symbolic and the fold returns None rather than
producing an incorrect concrete result.
Attributes¶
COMPILE_TIMEEMIT_RESPECT_PARAMS
NotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)qamomile.circuit.transpiler.passes.emit_support.composite_decomposer¶
Composite gate decomposition helpers.
Overview¶
| Class | Description |
|---|---|
CompositeDecomposer | Decomposes composite gates into primitive operations. |
Classes¶
CompositeDecomposer [source]¶
class CompositeDecomposerDecomposes composite gates into primitive operations.
Methods¶
iqft_structure¶
@staticmethod
def iqft_structure(n: int) -> list[tuple[str, tuple[int, ...], float | None]]qft_structure¶
@staticmethod
def qft_structure(n: int) -> list[tuple[str, tuple[int, ...], float | None]]qamomile.circuit.transpiler.passes.emit_support.composite_gate_emission¶
Composite gate emission helpers extracted from StandardEmitPass.
This module provides module-level functions for emitting composite gates
(QFT, IQFT, QPE) and their approximate variants. Each function takes an
emit_pass parameter (a StandardEmitPass instance) in place of
self.
Overview¶
| Function | Description |
|---|---|
emit_approximate_iqft | Emit approximate IQFT with truncated rotations matching stdlib convention. |
emit_approximate_qft | Emit approximate QFT with truncated rotations matching stdlib convention. |
emit_composite_fallback | Emit composite gate using decomposition. |
emit_composite_gate | Emit a composite gate operation. |
emit_iqft_manual | Emit inverse QFT using decomposition matching stdlib convention. |
emit_iqft_with_strategy | Emit IQFT considering strategy selection. |
emit_qft_manual | Emit QFT using decomposition matching stdlib convention. |
emit_qft_with_strategy | Emit QFT considering strategy selection. |
emit_qpe_manual | Emit QPE using manual decomposition. |
extract_phase_from_params | Extract a concrete phase parameter from a QPE operation. |
update_composite_result_mapping | Update qubit_map for composite gate results. |
| Class | Description |
|---|---|
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
CompositeGateType | Registry of known composite gate types. |
EmitError | Error during backend code emission. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Functions¶
emit_approximate_iqft [source]¶
def emit_approximate_iqft(
emit_pass: 'StandardEmitPass',
circuit: Any,
qubit_indices: list[int],
truncation_depth: int,
) -> NoneEmit approximate IQFT with truncated rotations matching stdlib convention.
IQFT = QFT†. SWAP comes first (undoing QFT’s trailing SWAP), then for each qubit j (low-to-high), applies inverse controlled-phase rotations with lower-indexed qubits first (omitting exponents > truncation_depth), then H.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The StandardEmitPass instance. |
circuit | Any | Target circuit |
qubit_indices | list[int] | Qubit indices |
truncation_depth | int | Maximum exponent for controlled phase gates |
emit_approximate_qft [source]¶
def emit_approximate_qft(
emit_pass: 'StandardEmitPass',
circuit: Any,
qubit_indices: list[int],
truncation_depth: int,
) -> NoneEmit approximate QFT with truncated rotations matching stdlib convention.
Processes qubits from highest index to lowest (same as exact QFT), applying H then controlled-phase rotations with lower-indexed qubits. Rotations with exponent > truncation_depth are omitted. Finishes with bit-reversal SWAPs.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The StandardEmitPass instance. |
circuit | Any | Target circuit |
qubit_indices | list[int] | Qubit indices |
truncation_depth | int | Maximum exponent for controlled phase gates |
emit_composite_fallback [source]¶
def emit_composite_fallback(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit composite gate using decomposition.
If the operation has a strategy_name set, it attempts to use the corresponding strategy from the CompositeGate class.
emit_composite_gate [source]¶
def emit_composite_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a composite gate operation.
Resolves each qubit operand through resolve_qubit_index_detailed
so that view-local operands (qft(q[1::2])) walk the slice_of
chain and map to the root parent’s physical qubits. Raises
EmitError if any operand cannot be resolved, rather than
silently dropping it (previously qft(view) emitted zero gates).
Raises:
EmitError— If any control or target qubit operand fails to resolve to a physical qubit index.
emit_iqft_manual [source]¶
def emit_iqft_manual(emit_pass: 'StandardEmitPass', circuit: Any, qubit_indices: list[int]) -> NoneEmit inverse QFT using decomposition matching stdlib convention.
IQFT = QFT†. SWAP comes first (undoing QFT’s trailing SWAP), then for each qubit j (low-to-high), applies inverse controlled-phase rotations with all lower-indexed qubits k (angle = -π/2^(j-k)) first, then H.
emit_iqft_with_strategy [source]¶
def emit_iqft_with_strategy(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_indices: list[int],
) -> NoneEmit IQFT considering strategy selection.
If a strategy is specified and ‘approximate’, uses truncated rotations. Otherwise falls back to standard IQFT.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The active emit pass whose emitter should receive decomposed IQFT gates. |
circuit | Any | Backend circuit being emitted. |
op | CompositeGateOperation | Composite operation expected to be an IQFT. |
qubit_indices | list[int] | Physical qubit indices for the IQFT target register. |
Raises:
EmitError— Ifopis not an IQFT composite operation.
emit_qft_manual [source]¶
def emit_qft_manual(emit_pass: 'StandardEmitPass', circuit: Any, qubit_indices: list[int]) -> NoneEmit QFT using decomposition matching stdlib convention.
Processes qubits from highest index to lowest: for each qubit j, applies H then controlled-phase rotations with all lower-indexed qubits k (angle = π/2^(j-k)). Finishes with bit-reversal SWAPs.
emit_qft_with_strategy [source]¶
def emit_qft_with_strategy(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_indices: list[int],
) -> NoneEmit QFT considering strategy selection.
If a strategy is specified and ‘approximate’, uses truncated rotations. Otherwise falls back to standard QFT.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The active emit pass whose emitter should receive decomposed QFT gates. |
circuit | Any | Backend circuit being emitted. |
op | CompositeGateOperation | Composite operation expected to be a QFT. |
qubit_indices | list[int] | Physical qubit indices for the QFT target register. |
Raises:
EmitError— Ifopis not a QFT composite operation.
emit_qpe_manual [source]¶
def emit_qpe_manual(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit QPE using manual decomposition.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The active emit pass whose emitter should receive decomposed QPE gates. |
circuit | Any | Backend circuit being emitted. |
op | CompositeGateOperation | Composite operation expected to be a QPE. |
qubit_indices | list[int] | Physical qubit indices for counting and target registers, in operation operand order. |
bindings | dict[str, Any] | Emit-time concrete bindings used to resolve QPE block parameters or phase operands. |
Raises:
EmitError— Ifopis not a QPE composite operation.
extract_phase_from_params [source]¶
def extract_phase_from_params(
emit_pass: 'StandardEmitPass',
op: CompositeGateOperation,
bindings: dict[str, Any],
) -> float | NoneExtract a concrete phase parameter from a QPE operation.
Scans the operation’s parameter operands. The block-free QPE fallback models a single phase parameter, so more than one concrete numeric parameter is ambiguous and rejected instead of guessed.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The active emit pass whose resolver should resolve bound scalar and array-element operands. |
op | CompositeGateOperation | The QPE composite operation. |
bindings | dict[str, Any] | Emit-time concrete bindings keyed by parameter name, value UUID, or loop-local variable name. |
Returns:
float | None — float | None: The resolved phase angle, or None when the phase
operand remains symbolic.
Raises:
EmitError— Ifopis not a QPE composite operation, or if multiple concrete numeric phase parameters are present.
update_composite_result_mapping [source]¶
def update_composite_result_mapping(
op: CompositeGateOperation,
qubit_indices: list[int],
qubit_map: QubitMap,
) -> NoneUpdate qubit_map for composite gate results.
Classes¶
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
CompositeGateType [source]¶
class CompositeGateType(enum.Enum)Registry of known composite gate types.
Attributes¶
CUSTOMIQFTQFTQPE
EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)qamomile.circuit.transpiler.passes.emit_support.condition_resolution¶
Helpers for compile-time condition resolution and phi remapping.
Overview¶
| Function | Description |
|---|---|
array_element_mapping | Collect physical indices for the elements of an array value. |
array_element_mappings | Collect array element mappings for multiple source arrays. |
copy_array_element_aliases | Copy array element aliases from a source array to a result array. |
map_array_element_aliases | Map explicit array element aliases to a result array. |
map_phi_outputs | Register phi output UUIDs to the same physical resources as their sources. |
remap_static_phi_outputs | Remap phi outputs for a compile-time constant IfOperation. |
resolve_condition_address_detailed | Resolve a condition / source Value to its clbit_map key. |
resolve_if_condition | Resolve an if-condition to a compile-time boolean. |
resolve_qubit_key | Resolve a qubit Value to its allocation key. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
BitType | Type representing a classical bit. |
PhiOp | SSA Phi function: merge point after conditional branch. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolves Value objects to concrete indices or values. |
Functions¶
array_element_mapping [source]¶
def array_element_mapping(source_uuid: str, index_map: Mapping[QubitAddress, int]) -> dict[int, int]Collect physical indices for the elements of an array value.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuid | str | UUID of the array whose element addresses should be collected. |
index_map | Mapping[QubitAddress, int] | Physical-index map to read. |
Returns:
dict[int, int] — dict[int, int]: Mapping from element index to physical index.
array_element_mappings [source]¶
def array_element_mappings(
source_uuids: set[str],
index_map: Mapping[QubitAddress, int],
) -> dict[str, dict[int, int]]Collect array element mappings for multiple source arrays.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuids | set[str] | UUIDs of the arrays whose element addresses should be collected. |
index_map | Mapping[QubitAddress, int] | Physical-index map to read. |
Returns:
dict[str, dict[int, int]] — dict[str, dict[int, int]]: Mapping from each requested source UUID to
its element-index-to-physical-index mapping.
copy_array_element_aliases [source]¶
def copy_array_element_aliases(source_uuid: str, result_uuid: str, index_map: PhysicalIndexMap) -> NoneCopy array element aliases from a source array to a result array.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuid | str | UUID of the source array whose element addresses are already present in index_map. |
result_uuid | str | UUID of the result array that should alias the same physical resources element by element. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with any missing result element addresses and the result base address. |
map_array_element_aliases [source]¶
def map_array_element_aliases(
result_uuid: str,
element_mapping: Mapping[int, int],
index_map: PhysicalIndexMap,
*,
map_base_address: bool = True,
) -> NoneMap explicit array element aliases to a result array.
Parameters:
| Name | Type | Description |
|---|---|---|
result_uuid | str | UUID of the result array that should receive the element aliases. |
element_mapping | Mapping[int, int] | Physical indices keyed by result element index. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with missing result element addresses and, when requested, the result base address. |
map_base_address | bool | Whether to map the scalar base address for the result array to its lowest-index element. Defaults to True. |
map_phi_outputs [source]¶
def map_phi_outputs(
phi_ops: list,
qubit_map: QubitMap,
clbit_map: ClbitMap,
resolve_scalar_qubit: Any = None,
) -> NoneRegister phi output UUIDs to the same physical resources as their sources.
remap_static_phi_outputs [source]¶
def remap_static_phi_outputs(
phi_ops: list,
condition_value: bool,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneRemap phi outputs for a compile-time constant IfOperation.
resolve_condition_address_detailed [source]¶
def resolve_condition_address_detailed(
condition: Value,
bindings: dict[str, Any],
resolver: ValueResolver | None = None,
) -> tuple[QubitAddress, bool]Resolve a condition / source Value to its clbit_map key.
Single source of truth (shared by control_flow_emission.emit_if /
emit_while, the Qiskit / CUDA-Q backends, ResourceAllocator’s
loop-carried / phi aliasing, and the phi-output mapping helpers here)
for turning a runtime control-flow condition — or a phi source Value —
into the address its classical bit is registered under.
Scalar measurement results register under QubitAddress(bit.uuid),
while a Vector[Bit] element s[i] (s = qmc.measure(register))
registers under QubitAddress(root_array.uuid, root_index). The
element index and every slice_start / slice_step along the
parent’s slice_of chain are resolved the same way — taken directly
when constant, otherwise folded through bindings via resolver —
and composed into the root index via root_index = start + step * view_local_index repeated along the chain.
Parameters:
| Name | Type | Description |
|---|---|---|
condition | Value | The condition operand or phi source Value. |
bindings | dict[str, Any] | Active emit-time bindings used to fold symbolic indices / slice bounds. May be empty for callers that only have constant addresses to resolve (e.g. the allocator’s pre-emit pass). |
resolver | ValueResolver | None | Resolver exposing resolve_int_value; None restricts resolution to constants. Defaults to None. |
Returns:
tuple[QubitAddress, bool] — tuple[QubitAddress, bool]: (address, resolved_as_element).
resolved_as_element is True only when condition is a
Vector[Bit] element whose index (and any slice bounds)
resolved to concrete ints, giving the root-space
QubitAddress(root.uuid, root_index). It is False for a
plain scalar, or when an element’s index / slice bound could
not be resolved (the scalar UUID fallback). Callers that mutate
clbit_map should trust the address as a vector key only when
this flag is True, to avoid aliasing an unresolved element
onto an unrelated scalar slot.
resolve_if_condition [source]¶
def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | NoneResolve an if-condition to a compile-time boolean.
resolve_qubit_key [source]¶
def resolve_qubit_key(qubit: 'Value') -> tuple[QubitAddress | None, bool]Resolve a qubit Value to its allocation key.
Parameters:
| Name | Type | Description |
|---|---|---|
qubit | Value | Qubit value to resolve. Array elements with a constant index are resolved through their full slice_of chain to the root array address. |
Returns:
tuple[QubitAddress | None, bool] — tuple[QubitAddress | None, bool]: (address, is_array_element).
address is the root-space address for a resolvable array
element, None for an array element whose index or slice
bounds are symbolic at this binding-free stage, and a scalar
UUID address for non-array qubits. A negative constant index
(or an out-of-contract slice bound) also yields None:
resolve_root_qubit_address refuses it rather than letting it
silently address a wrong root slot.
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]BitType [source]¶
class BitType(ClassicalTypeMixin, ValueType)Type representing a classical bit.
PhiOp [source]¶
class PhiOp(Operation)SSA Phi function: merge point after conditional branch.
This operation selects one of two values based on a condition. Used to merge values from different branches of an if-else statement.
Example:
if condition:
x = x + 1 # true_value
else:
x = x + 2 # false_value
# x is now PhiOp(condition, true_value, false_value)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
condition: Valuefalse_value: Valueoperation_kind: OperationKindoutput: Valuesignature: Signaturetrue_value: Value
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)qamomile.circuit.transpiler.passes.emit_support.control_flow_emission¶
Control flow emission helpers for StandardEmitPass.
Extracted from standard_emit.py to keep the main class focused on
gate-level dispatch. Each function mirrors the original method but takes
an explicit emit_pass parameter instead of self.
These are the default implementations. Backend-specific emit passes
(e.g., QiskitEmitPass) may override the corresponding methods on
StandardEmitPass; calling super()._emit_for(...) etc. will
ultimately delegate here.
Overview¶
| Function | Description |
|---|---|
emit_for | Emit a for loop. |
emit_for_items | Emit for-items loop (always unrolled). |
emit_for_unrolled | Emit for loop by unrolling. |
emit_if | Emit if/else operation. |
emit_while | Emit while loop operation. |
map_phi_outputs | Register phi output UUIDs to the same physical resources as their sources. |
register_classical_phi_aliases | Bind classical phi outputs to a concrete value when resolvable. |
register_phi_outputs | Register phi output UUIDs via the shared map_phi_outputs utility. |
remap_static_phi_outputs | Remap phi outputs for a compile-time constant IfOperation. |
resolve_condition_address | Resolve a runtime control-flow condition to its clbit_map key. |
resolve_condition_address_detailed | Resolve a condition / source Value to its clbit_map key. |
resolve_dict_entries | Resolve DictValue to concrete (key, value) pairs. |
resolve_if_condition | Resolve an if-condition to a compile-time boolean. |
resolve_loop_bounds | Resolve for-loop bounds (start, stop, step) from operands. |
| Class | Description |
|---|---|
EmitError | Error during backend code emission. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
IfOperation | Represents an if-else conditional operation. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolves Value objects to concrete indices or values. |
WhileOperation | Represents a while loop operation. |
Functions¶
emit_for [source]¶
def emit_for(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ForOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
force_unroll: bool = False,
) -> NoneEmit a for loop.
emit_for_items [source]¶
def emit_for_items(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ForItemsOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit for-items loop (always unrolled).
This handles iteration over Dict items, e.g.: for (i, j), Jij in qmc.items(ising): ...
emit_for_unrolled [source]¶
def emit_for_unrolled(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ForOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit for loop by unrolling.
emit_if [source]¶
def emit_if(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: IfOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit if/else operation.
Handles two condition types:
Compile-time constant (plain Python
int/boolfrom@qkernelAST transformer closure variables, constant-folded Values, or Values resolvable viabindings): the active branch is emitted unconditionally, the inactive branch is discarded. No backendc_if/if_testis needed.Runtime condition (measurement
Valuethat cannot be resolved at compile time): delegates to the backend’semit_if_start/emit_else_start/emit_if_endprotocol.
emit_while [source]¶
def emit_while(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: WhileOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit while loop operation.
map_phi_outputs [source]¶
def map_phi_outputs(
phi_ops: list,
qubit_map: QubitMap,
clbit_map: ClbitMap,
resolve_scalar_qubit: Any = None,
) -> NoneRegister phi output UUIDs to the same physical resources as their sources.
register_classical_phi_aliases [source]¶
def register_classical_phi_aliases(
emit_pass: 'StandardEmitPass',
phi_ops: list,
bindings: dict[str, Any],
resolved: bool | None,
) -> NoneBind classical phi outputs to a concrete value when resolvable.
The frontend creates a phi for every variable referenced in an
if-branch, including read-only ones (e.g. a for-loop index j that
is read but not assigned in the branch). These read-only phis have
true_value is false_value — both inputs reference the same IR
Value — so the phi output is deterministically equal to that input.
For classical types (UInt / Float / Bit) the phi outputs are not
captured by map_phi_outputs / remap_static_phi_outputs (which
only handle qubit / clbit phys-resource mapping). Without this
binding, downstream uses like data[j_phi_4] cannot resolve the
index and emit fails with symbolic_index_not_bound.
The alias is written to bindings by both UUID and (when present)
name, mirroring the pattern used by emit_for_unrolled for the
original loop variable.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The active emit pass (for resolver access). |
phi_ops | list | IfOperation.phi_ops. |
bindings | dict[str, Any] | Current bindings; mutated in place to bind phi outputs. |
resolved | bool | None | True / False if the if was compile-time resolved (use the selected branch’s input); None if it was a runtime if (only bind when both inputs resolve to the same value). |
Returns:
None — None.
register_phi_outputs [source]¶
def register_phi_outputs(
emit_pass: 'StandardEmitPass',
op: IfOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any] | None = None,
) -> NoneRegister phi output UUIDs via the shared map_phi_outputs utility.
Uses the full ValueResolver.resolve_qubit_index_detailed for
scalar qubit resolution (handles array element operands).
remap_static_phi_outputs [source]¶
def remap_static_phi_outputs(
phi_ops: list,
condition_value: bool,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneRemap phi outputs for a compile-time constant IfOperation.
resolve_condition_address [source]¶
def resolve_condition_address(
condition: Value,
bindings: dict[str, Any],
resolver: ValueResolver | None,
) -> QubitAddressResolve a runtime control-flow condition to its clbit_map key.
Scalar measurement results carry their own UUID and the clbit allocator
registers them under QubitAddress(bit.uuid). Vector[Bit] element
accesses (s[i] where s = qmc.measure(register)) instead live
under QubitAddress(root_array.uuid, root_index). The element index
and every slice_start / slice_step along the parent’s
slice_of chain are resolved the same way — taken directly when
constant, otherwise folded through bindings via resolver so
that loop-variable indices and runtime-valued slice bounds (s[j:k]
where j/k are loop variables) both work. The chain composes
into a root-space index via the standard affine map
root_index = start + step * view_local_index repeated along the
chain — matching ResourceAllocator._resolve_root_qubit_address /
ValueResolver.resolve_slice_chain. Falls back to the scalar
address when no parent array is set, or when the index or any slice
bound cannot be resolved to a concrete int (e.g. a backend runtime
parameter, which cannot index a static classical register, or any
symbolic value with no resolver), deferring the diagnostic to the
caller’s clbit_map lookup. Used by both the default if/while
emission path and the Qiskit / CUDA-Q backends when looking up a
measurement-derived clbit for a runtime predicate.
Parameters:
| Name | Type | Description |
|---|---|---|
condition | Value | Condition operand of an IfOperation or WhileOperation, or an operand of a measurement-derived classical predicate (e.g. inside RuntimeClassicalExpr). |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic indices and slice bounds (loop variables, compile-time-bound parameters). |
resolver | ValueResolver | None | The active ValueResolver exposing resolve_int_value. None is accepted for early-emit pre-scans (e.g. CUDA-Q’s loop-carried clbit collector) that run before runtime bindings exist — only the constant path is taken in that case; symbolic indices and symbolic slice bounds fall through to the scalar UUID. |
Returns:
QubitAddress — Key suitable for looking up the condition in
clbit_map.
resolve_condition_address_detailed [source]¶
def resolve_condition_address_detailed(
condition: Value,
bindings: dict[str, Any],
resolver: ValueResolver | None = None,
) -> tuple[QubitAddress, bool]Resolve a condition / source Value to its clbit_map key.
Single source of truth (shared by control_flow_emission.emit_if /
emit_while, the Qiskit / CUDA-Q backends, ResourceAllocator’s
loop-carried / phi aliasing, and the phi-output mapping helpers here)
for turning a runtime control-flow condition — or a phi source Value —
into the address its classical bit is registered under.
Scalar measurement results register under QubitAddress(bit.uuid),
while a Vector[Bit] element s[i] (s = qmc.measure(register))
registers under QubitAddress(root_array.uuid, root_index). The
element index and every slice_start / slice_step along the
parent’s slice_of chain are resolved the same way — taken directly
when constant, otherwise folded through bindings via resolver —
and composed into the root index via root_index = start + step * view_local_index repeated along the chain.
Parameters:
| Name | Type | Description |
|---|---|---|
condition | Value | The condition operand or phi source Value. |
bindings | dict[str, Any] | Active emit-time bindings used to fold symbolic indices / slice bounds. May be empty for callers that only have constant addresses to resolve (e.g. the allocator’s pre-emit pass). |
resolver | ValueResolver | None | Resolver exposing resolve_int_value; None restricts resolution to constants. Defaults to None. |
Returns:
tuple[QubitAddress, bool] — tuple[QubitAddress, bool]: (address, resolved_as_element).
resolved_as_element is True only when condition is a
Vector[Bit] element whose index (and any slice bounds)
resolved to concrete ints, giving the root-space
QubitAddress(root.uuid, root_index). It is False for a
plain scalar, or when an element’s index / slice bound could
not be resolved (the scalar UUID fallback). Callers that mutate
clbit_map should trust the address as a vector key only when
this flag is True, to avoid aliasing an unresolved element
onto an unrelated scalar slot.
resolve_dict_entries [source]¶
def resolve_dict_entries(
emit_pass: 'StandardEmitPass',
dict_value: Any,
bindings: dict[str, Any],
) -> list[tuple[Any, Any]] | NoneResolve DictValue to concrete (key, value) pairs.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The StandardEmitPass instance (for resolver access) |
dict_value | Any | The DictValue IR node being iterated |
bindings | dict[str, Any] | Current parameter bindings |
Returns:
list[tuple[Any, Any]] | None — List of (key, value) tuples, or None if cannot be resolved
resolve_if_condition [source]¶
def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | NoneResolve an if-condition to a compile-time boolean.
resolve_loop_bounds [source]¶
def resolve_loop_bounds(
resolver: Any,
op: ForOperation,
bindings: dict[str, Any],
) -> tuple[int | None, int | None, int | None]Resolve for-loop bounds (start, stop, step) from operands.
Missing operands use defaults: start=0, stop=1, step=1. Returns None for bounds that cannot be resolved to concrete ints.
Classes¶
EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
ForItemsOperation [source]¶
class ForItemsOperation(HasNestedOps, Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
key_vars: list[str] = list(),
value_var: str = '',
key_is_vector: bool = False,
key_var_values: tuple[Value, ...] | None = None,
value_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
key_is_vector: boolkey_var_values: tuple[Value, ...] | Nonekey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: strvalue_var_value: Value | None
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]Include the per-key/value Value fields for cloning/substitution.
Same rationale as ForOperation.all_input_values: keep the IR
identity fields in lockstep with body references so UUID-keyed
lookups stay valid after inline cloning.
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationIfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationQubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.passes.emit_support.controlled_emission¶
Controlled operation emission helpers extracted from StandardEmitPass.
This module provides module-level functions for emitting controlled-U
operations, controlled gates, and related helpers. Each function takes an
emit_pass parameter (a StandardEmitPass instance) in place of
self.
Note: emit_controlled_fallback and blockvalue_to_gate are called
via emit_pass._emit_controlled_fallback(...) and
emit_pass._blockvalue_to_gate(...) respectively, so that subclass
overrides (e.g. CudaqEmitPass) are respected.
Overview¶
| Function | Description |
|---|---|
blockvalue_to_gate | Convert a Block to a backend gate. |
build_controlled_block_qubit_map | Build a block-local qubit map backed by physical target indices. |
emit_controlled_block | Emit a controlled version of a block via the mapped walker. |
emit_controlled_composite_at_indices | Emit a composite gate under already-resolved outer controls. |
emit_controlled_fallback | Fallback emission for controlled-U when gate conversion fails. |
emit_controlled_gate | Emit a controlled version of a gate. |
emit_controlled_operations | Emit controlled versions of operations with operand mapping. |
emit_controlled_pauli_evolve | Emit exp(-i * gamma * H) under accumulated controls. |
emit_controlled_powers | Emit controlled-U^(2^k) operations. |
emit_controlled_u | Emit a ControlledUOperation. |
emit_controlled_u_multi_arg | Emit a SymbolicControlledU whose control prefix is multi-arg. |
emit_controlled_u_with_symbolic_indices | Emit a SymbolicControlledU whose control_indices is set. |
emit_custom_composite | Emit a custom composite gate with implementation. |
emit_multi_controlled_gate | Emit one gate under an arbitrary number of accumulated controls. |
evaluate_binop | Evaluate a BinOp and store the result in bindings. |
map_array_result_group | Map an array-valued result to a physical index group. |
map_nested_controlled_u_results | Map a nested controlled-U’s result values to physical qubits. |
resolve_controlled_u_call | Resolve a (possibly nested) controlled-U call site to physical qubits. |
resolve_power | Resolve ControlledUOperation.power to a concrete int. |
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
ConcreteControlledU | Controlled-U with concrete (int) number of controls. |
ControlledUOperation | Base class for controlled-U operations. |
EmitError | Error during backend code emission. |
ForOperation | Represents a for loop operation. |
GateOperation | Quantum gate operation. |
GateOperationType | |
HasNestedOps | Mixin for operations that contain nested operation lists. |
InverseBlockOperation | Represent an inverse qkernel/block as a first-class IR operation. |
PauliEvolveOp | Pauli evolution operation: exp(-i * gamma * H). |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
ResolvedControlledU | Physical resolution of one ControlledUOperation call site. |
ReturnOperation | Explicit return operation marking the end of a block with return values. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
SymbolicControlledU | Controlled-U with symbolic (Value) number of controls. |
Value | A typed SSA value in the IR. |
Functions¶
blockvalue_to_gate [source]¶
def blockvalue_to_gate(
emit_pass: 'StandardEmitPass',
block_value: Any,
num_qubits: int,
bindings: dict[str, Any],
input_operands: list[Any] | None = None,
operation_name: str = 'ControlledUOperation',
) -> AnyConvert a Block to a backend gate.
Pre-populates local_qubit_map with one entry per quantum input in
declaration order, then runs the allocator over the block’s body.
For Vector[Qubit] inputs (ArrayValue with a quantum element
type) the entry expands into per-element QubitAddress(uuid, i)
keys — the inner block has no QInitOperation for inputs, so
without these the allocator’s element-resolution assertion fires for
every qs[i] reference in the body.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The emit pass driving the conversion. Used for its _allocator, _emitter, _resolver, and _emit_operations. |
block_value | Any | The inner block to convert. Expected to expose operations and input_values; anything else returns None (the caller falls back to gate-by-gate decomposition). |
num_qubits | int | Total physical qubits the resulting gate will occupy in the parent circuit. Used as the fallback length for a single Vector[Qubit] input whose shape is symbolic and unresolvable from bindings, and as the sub-circuit width when the block has no qubit-producing operations. |
bindings | dict[str, Any] | Parameter bindings forwarded to the allocator and _emit_operations. Also consulted when resolving Vector[Qubit] input shapes. |
input_operands | list[Any] | None | Optional call-site operands corresponding to block_value.input_values. Quantum operands propagate actual Vector[Qubit] shapes into the nested block before the vector-aware input qubit map is populated; classical operands are resolved into local bindings before the nested block is emitted. Defaults to None. |
operation_name | str | Operation name used in diagnostics when input binding fails. Defaults to "ControlledUOperation". |
Returns:
Any — A backend gate object produced by
emit_pass._emitter.circuit_to_gate, or None when the
conversion is unable to proceed (missing operations,
allocator / emitter exception, etc.) so the caller can fall
back to gate-by-gate emission.
build_controlled_block_qubit_map [source]¶
def build_controlled_block_qubit_map(
emit_pass: 'StandardEmitPass',
block_value: Any,
target_indices: list[int],
bindings: dict[str, Any],
) -> QubitMapBuild a block-local qubit map backed by physical target indices.
Seeds one entry per formal quantum input of block_value —
scalar Qubit inputs map to one physical index,
Vector[Qubit] inputs map per-element — positionally matching
target_indices in declaration order.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Emit pass used to resolve symbolic vector input shapes against bindings. |
block_value | Any | Inner block whose input_values define the quantum formal arguments. Objects without input_values yield an empty map. |
target_indices | list[int] | Physical qubit indices supplied at the controlled call site, one per flattened quantum input qubit. |
bindings | dict[str, Any] | Bindings used while resolving vector input shapes. |
Returns:
QubitMap — Mapping from the inner block’s formal quantum input
addresses to physical parent-circuit qubit indices.
Raises:
EmitError— If a vector input length cannot be resolved, is negative, or the block’s quantum input footprint exceedslen(target_indices).
emit_controlled_block [source]¶
def emit_controlled_block(
emit_pass: 'StandardEmitPass',
circuit: Any,
block_value: Any,
control_idx: int,
target_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit a controlled version of a block via the mapped walker.
Builds a block-local qubit map from the block’s formal quantum
inputs to target_indices and walks the block body, so inner
gates land on the physical qubit their operand actually refers to
rather than on target_indices[0].
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
block_value | Any | Inner block whose operations are controlled. Objects without operations are silently skipped. |
control_idx | int | Physical control qubit index. |
target_indices | list[int] | Physical target qubits covering the block’s quantum inputs in declaration order. |
bindings | dict[str, Any] | Local block bindings. |
Raises:
EmitError— If the block’s quantum inputs cannot be mapped ontotarget_indicesor an inner operation cannot be emitted.
emit_controlled_composite_at_indices [source]¶
def emit_controlled_composite_at_indices(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
control_indices: list[int],
qubit_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit a composite gate under already-resolved outer controls.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
op | CompositeGateOperation | Composite operation to emit. |
control_indices | list[int] | Physical outer control qubits. |
qubit_indices | list[int] | Physical qubits occupied by op’s own control and target operands. |
bindings | dict[str, Any] | Active emit bindings. |
Returns:
None — None.
Raises:
EmitError— If the composite has no implementation block or the fallback cannot represent the controlled composite.
emit_controlled_fallback [source]¶
def emit_controlled_fallback(
emit_pass: 'StandardEmitPass',
circuit: Any,
block_value: Any,
num_controls: int,
control_indices: list[int],
target_indices: list[int],
power: int,
bindings: dict[str, Any],
) -> NoneFallback emission for controlled-U when gate conversion fails.
Decomposes the block body gate-by-gate under the full control set.
A block-local qubit map ties the block’s formal quantum inputs to
target_indices, so every inner gate is emitted on the physical
qubit its operand resolves to — multi-target inner blocks are
supported. Nested ControlledUOperations compose their controls
with the outer ones; irreducible multi-controlled single-qubit
gates route through the backend’s
_emit_irreducible_multi_controlled_gate hook. Subclasses may
still override this method to emit controlled blocks natively
(e.g. CUDA-Q’s cudaq.control helper kernels).
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The StandardEmitPass instance. |
circuit | Any | The backend circuit being built. |
block_value | Any | The block value containing operations to control. |
num_controls | int | Number of control qubits. |
control_indices | list[int] | Physical indices of control qubits. |
target_indices | list[int] | Physical indices of target qubits. |
power | int | Number of times to repeat the controlled operation. |
bindings | dict[str, Any] | Parameter bindings. |
Raises:
EmitError— Ifnum_controlsdisagrees withcontrol_indices, the block’s quantum inputs cannot be mapped ontotarget_indices, or an inner operation cannot be lowered under the accumulated controls (e.g. an irreducible multi-controlled gate on a backend without the multi-control hook).
emit_controlled_gate [source]¶
def emit_controlled_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: GateOperation,
control_idx: int,
target_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit a controlled version of a gate.
emit_controlled_operations [source]¶
def emit_controlled_operations(
emit_pass: 'StandardEmitPass',
circuit: Any,
operations: list[Operation],
control_indices: list[int],
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit controlled versions of operations with operand mapping.
Walks operations under the accumulated control_indices,
resolving every quantum operand through qubit_map so gates land
on the physical qubit their operand refers to. Nested
ControlledUOperations are not rejected: their own controls are
resolved and composed with the outer controls, lowering e.g. an
inner qmc.control(qmc.x, num_controls=k) under one outer
control to a (k+1)-controlled X.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
operations | list[Operation] | Block operations to walk. |
control_indices | list[int] | Accumulated physical control qubits. |
qubit_map | QubitMap | Mutable block-local qubit map seeded by :func:build_controlled_block_qubit_map; updated in place with gate / nested-op result addresses. |
bindings | dict[str, Any] | Bindings visible inside the block, including loop-iteration values during unrolling. |
Raises:
EmitError— If an operand cannot be resolved to a physical qubit, aForOperationbound cannot be resolved at transpile time, or an operation kind is unsupported in controlled decomposition.
emit_controlled_pauli_evolve [source]¶
def emit_controlled_pauli_evolve(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: PauliEvolveOp,
control_indices: list[int],
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit exp(-i * gamma * H) under accumulated controls.
Lowers a controlled Pauli evolution by exploiting that each Pauli
term’s evolution exp(-i * theta * P) factors as
U_dagger * RZ(2 * theta) * U where U (the basis change onto
the Z axis followed by the parity CX ladder) is Clifford and thus
control-independent. Controlling a conjugated gate is
U_dagger * C[RZ] * U with U / U_dagger applied
unconditionally: when every control is 0 the central RZ
becomes the identity and U_dagger * I * U = I. Only the central
RZ therefore carries the controls, which keeps the dense
multi-controlled cost to a single rotation per Hamiltonian term
instead of controlling every basis-change and ladder gate.
The basis-change (H / SDG / S) and CX-ladder gates are
emitted uncontrolled through emit_pass._emitter; the central
RZ is routed through :func:_emit_mc_rotation, which dispatches
to emit_crz for a single control and to the backend’s
_emit_irreducible_multi_controlled_gate hook for two or more.
A constant (identity) Hamiltonian term c * I is a global phase
exp(-i * gamma * c) for the uncontrolled evolution (correctly
dropped by :func:emit_pauli_evolve), but under controls it becomes
an observable relative phase on the all-controls-on subspace, so it
MUST be emitted here. It is realized as a P(-gamma * c) on one
control conditioned on the remaining controls (emit_p for a single
control, a controlled / dense P for more), matching Qiskit’s
native PauliEvolutionGate whose SparsePauliOp carries the
constant.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass; provides the value resolver, gate emitter, and the multi-controlled rotation hook. |
circuit | Any | Backend circuit being emitted into. |
op | PauliEvolveOp | The Pauli evolution operation inside the controlled block. |
control_indices | list[int] | Accumulated physical control qubits. Must be non-empty. |
qubit_map | QubitMap | Block-local qubit map the operation’s quantum operands resolve against; updated in place with the evolved-register result addresses. |
bindings | dict[str, Any] | Bindings visible inside the block, used to resolve the Hamiltonian, gamma, and register shape. |
Raises:
EmitError— Ifcontrol_indicesis empty, the observable does not resolve to a Hamiltonian, gamma cannot be resolved, the Hamiltonian is non-Hermitian (a term or the constant has a non-real coefficient), the register size does not match the Hamiltonian, a term qubit cannot be resolved, or (for two or more controls, or a nonzero constant term) the angle is runtime-parametric and the backend’s dense multi-controlled path requires a compile-time-numeric angle.
emit_controlled_powers [source]¶
def emit_controlled_powers(
emit_pass: 'StandardEmitPass',
circuit: Any,
block_value: Any,
counting_indices: list[int],
target_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit controlled-U^(2^k) operations.
emit_controlled_u [source]¶
def emit_controlled_u(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ControlledUOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a ControlledUOperation.
emit_controlled_u_multi_arg [source]¶
def emit_controlled_u_multi_arg(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: SymbolicControlledU,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a SymbolicControlledU whose control prefix is multi-arg.
The multi-arg form (num_control_args > 1) carries a
heterogeneous control prefix: a mix of scalar Value
(single-qubit) and ArrayValue (whole Vector / slice
VectorView) operands whose qubit-count sum equals
num_controls once bindings resolves the lengths.
ConstantFoldingPass cannot promote this shape to
ConcreteControlledU (the per-control-qubit operand layout
would lose the array-grouping the resource allocator needs), so
it survives intact and lands here.
The function expands every control operand into physical qubit
indices via the §12.1 helper, asserts the resulting count
matches the resolved num_controls, expands the target side
the same way, and threads the rest through the standard
gate_controlled + append_gate pipeline (with the
per-gate fallback for backends whose circuit_to_gate returns
None).
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The emit pass driving the conversion. |
circuit | Any | The backend circuit being built. |
op | SymbolicControlledU | The IR op with num_control_args > 1 and control_indices is None. |
qubit_map | QubitMap | The active QubitAddress -> physical qubit map; mutated in place with the result-side mappings. |
bindings | dict[str, Any] | Caller bindings used to resolve num_controls and any symbolic-length control / target operand. |
Raises:
EmitError—num_controlscannot be resolved, is non- positive, or does not match the sum of expanded control operand sizes.
emit_controlled_u_with_symbolic_indices [source]¶
def emit_controlled_u_with_symbolic_indices(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: SymbolicControlledU,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a SymbolicControlledU whose control_indices is set.
Routed from :func:emit_controlled_u when the constant-folding
pass has left the op as SymbolicControlledU because
control_indices carries pass-through semantics that the
ConcreteControlledU promotion cannot represent in its scalar
control-operand layout (see §12.5 of the design).
The function resolves the symbolic num_controls and every
control_indices entry to concrete ints, walks the control
pool’s slice_of chain to look up physical qubits per element,
builds control_phys from the selected pool slots, expands the
sub-kernel quantum operands via the §12.1 helper
_expand_quantum_operands_to_phys for the target side, and
threads the rest through the standard gate_controlled +
append_gate pipeline (with the per-gate fallback for backends
whose circuit_to_gate returns None).
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The emit pass driving the conversion; provides _resolver, _emitter, _blockvalue_to_gate, and _emit_controlled_fallback. |
circuit | Any | The backend circuit being built. |
op | SymbolicControlledU | The IR op with control_indices not None. Callers must guarantee this; the control_indices is None branch is handled by the constant-folding promotion to ConcreteControlledU. |
qubit_map | QubitMap | The active QubitAddress -> physical qubit map; mutated in place with the result-side mappings. |
bindings | dict[str, Any] | Caller bindings used to resolve num_controls, control_indices Values, c_qs length, and slice bounds. |
Raises:
EmitError— Surfaces under any of the following conditions:
num_controlscannot be resolved or is<= 0;the control-vector length cannot be resolved, is shorter than
num_controls, or is shorter than the largest listed index;a
control_indicesentry cannot be resolved, is negative, or repeats;len(control_indices) != num_controls;a sub-quantum operand cannot be expanded to physical qubits (delegated to :func:
_expand_quantum_operands_to_phys).
emit_custom_composite [source]¶
def emit_custom_composite(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: Any,
impl: Any,
qubit_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit a custom composite gate with implementation.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
op | Any | Composite gate operation. |
impl | Any | Fallback implementation block to emit. |
qubit_indices | list[int] | Physical qubits for the operation. |
bindings | dict[str, Any] | Active emit bindings. |
emit_multi_controlled_gate [source]¶
def emit_multi_controlled_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: GateOperation,
control_indices: list[int],
target_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit one gate under an arbitrary number of accumulated controls.
Structurally reduces multi-qubit gate types to single-target forms
by absorbing their own control qubits into the control set
(CX -> X, CZ -> Z, CP -> P, TOFFOLI -> X; SWAP
and RZZ via their standard CX conjugations), then emits:
one control: via :func:
emit_controlled_gate(the existing single-control dispatch),two controls on X / Z: via
emit_toffoli(Z conjugated by H),anything else: via the backend’s
_emit_irreducible_multi_controlled_gatehook, whose base implementation raises a descriptiveEmitError.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. Subclass overrides of _emit_irreducible_multi_controlled_gate are respected for the irreducible tail. |
circuit | Any | Backend circuit being emitted into. |
op | GateOperation | Gate operation whose operands are already resolved to target_indices. |
control_indices | list[int] | Physical control qubits. Must be non-empty. |
target_indices | list[int] | Physical qubits for the gate’s own operands, in operand order. |
bindings | dict[str, Any] | Bindings used to resolve rotation angles. |
Raises:
EmitError— Ifcontrol_indicesis empty, the gate has fewer resolved targets than its type requires, or the reduction bottoms out on a backend without multi-control support.
evaluate_binop [source]¶
def evaluate_binop(emit_pass: 'StandardEmitPass', op: BinOp, bindings: dict[str, Any]) -> NoneEvaluate a BinOp and store the result in bindings.
Tries the shared fold_classical_op first for a clean concrete
fold (which already encapsulates the runtime-parameter guard).
Falls back to creating backend Parameter symbols and doing
symbolic arithmetic when one or both operands are runtime
parameters — that’s the path that lets rx(q, gamma * 2) produce
a circuit with a single Parameter("gamma") * 2 expression rather
than baking in a placeholder.
map_array_result_group [source]¶
def map_array_result_group(result_uuid: str, index_group: list[int], index_map: PhysicalIndexMap) -> NoneMap an array-valued result to a physical index group.
Parameters:
| Name | Type | Description |
|---|---|---|
result_uuid | str | UUID of the array-valued result whose element addresses should be registered. |
index_group | list[int] | Physical indices for the result elements, in result-local element order. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with element addresses and, when available, the base result address. |
map_nested_controlled_u_results [source]¶
def map_nested_controlled_u_results(
op: ControlledUOperation,
resolved: ResolvedControlledU,
qubit_map: QubitMap,
) -> NoneMap a nested controlled-U’s result values to physical qubits.
The result layout mirrors the operand layout for every controlled-U
shape: one result per control operand slot followed by one result
per sub-kernel quantum operand. Controlled gates only add a
relative phase — no qubit moves — so each result keeps the physical
slots of its operand. For the control_indices pool form the
whole pool passes through, selected controls included.
Parameters:
| Name | Type | Description |
|---|---|---|
op | ControlledUOperation | The operation whose results need mapping. |
resolved | ResolvedControlledU | Physical resolution returned by :func:resolve_controlled_u_call for this operation. |
qubit_map | QubitMap | Mutable qubit map updated in place. |
resolve_controlled_u_call [source]¶
def resolve_controlled_u_call(
emit_pass: 'StandardEmitPass',
op: ControlledUOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> ResolvedControlledUResolve a (possibly nested) controlled-U call site to physical qubits.
Handles all three operand layouts:
ConcreteControlledU: one scalar operand per control qubit.SymbolicControlledUwithcontrol_indices is None: a control prefix ofnum_control_argsscalar / vector operands whose flattened qubit count equals the resolvednum_controls.SymbolicControlledUwithcontrol_indicesset: a single control pool whose listed elements act as controls while the rest pass through.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass; provides the value resolver. |
op | ControlledUOperation | The controlled-U operation to resolve. |
qubit_map | QubitMap | Qubit map the operands resolve against (block-local when called from a controlled walker). |
bindings | dict[str, Any] | Bindings visible at the call site, including loop-iteration values during unrolling. |
Returns:
ResolvedControlledU — Physical controls / targets and the
inner-block bindings.
Raises:
EmitError— If the operation has no inner block,num_controlsor acontrol_indicesentry cannot be resolved, indices repeat or fall outside the pool, the flattened control count does not matchnum_controls, or an operand cannot be expanded to physical qubits.
resolve_power [source]¶
def resolve_power(
emit_pass: 'StandardEmitPass',
op: ControlledUOperation,
bindings: dict[str, Any],
) -> intResolve ControlledUOperation.power to a concrete int.
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
ConcreteControlledU [source]¶
class ConcreteControlledU(ControlledUOperation)Controlled-U with concrete (int) number of controls.
Operand layout: [ctrl_0, ..., ctrl_n, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_0', ..., ctrl_n', tgt_0', ..., tgt_m']
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int = 1,
) -> NoneAttributes¶
control_operands: list[Value]num_controls: intparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationEmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
ForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationGateOperation [source]¶
class GateOperation(Operation)Quantum gate operation.
For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is
stored as the last element of operands. Use the theta
property for typed read access and the rotation / fixed factory
class-methods for type-safe construction.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: GateOperationType | None = None,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindqubit_operands: list[Value] Qubit operands (excluding the theta parameter if present).signature: Signaturetheta: Value | None Angle parameter for rotation gates, orNonefor fixed gates.
Methods¶
fixed¶
@classmethod
def fixed(
cls,
gate_type: GateOperationType,
qubits: list[Value],
results: list[Value],
) -> 'GateOperation'Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.
rotation¶
@classmethod
def rotation(
cls,
gate_type: GateOperationType,
qubits: list[Value],
theta: Value,
results: list[Value],
) -> 'GateOperation'Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.
GateOperationType [source]¶
class GateOperationType(enum.Enum)Attributes¶
CPCXCZHPRXRYRZRZZSSDGSWAPTTDGTOFFOLIXYZ
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
InverseBlockOperation [source]¶
class InverseBlockOperation(Operation)Represent an inverse qkernel/block as a first-class IR operation.
The operation stores both the original forward block and a Qamomile-built
inverse implementation block. Emitters may use source_block with a
backend-native inverse/adjoint primitive, then fall back to
implementation_block when native inversion is unavailable.
Operands are ordered as control qubits, target quantum operands, then
classical/object parameters. Results mirror the quantum operand layout:
control results first, then one target result per target operand. Vector
target operands therefore count as one operand/result while contributing
their scalar width to num_target_qubits.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
source_block: Block | None = None,
implementation_block: Block | None = None,
) -> NoneAttributes¶
control_qubits: list[‘Value’] Return control quantum operands.custom_name: strimplementation_block: Block | Nonename: str Return a human-readable inverse operation name.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind.parameters: list[‘Value’] Return classical/object parameter operands.signature: Signature Return the operation signature.source_block: Block | Nonetarget_qubits: list[‘Value’] Return target quantum operands.
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()) -> NoneAttributes¶
evolved_qubits: Value The evolved quantum register result.gamma: Value The evolution time parameter.observable: Value The Observable parameter operand.operation_kind: OperationKind PauliEvolveOp is QUANTUM - transforms quantum state.qubits: Value The quantum register operand.signature: Signature
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
ResolvedControlledU [source]¶
class ResolvedControlledUPhysical resolution of one ControlledUOperation call site.
Produced by :func:resolve_controlled_u_call for every concrete and
symbolic operand layout, so walkers can lower nested controlled-U
operations without shape-specific branching.
Constructor¶
def __init__(
self,
control_phys: list[int],
control_operand_groups: list[list[int]],
target_qubit_operands: list[Any],
target_index_groups: list[list[int]],
target_phys: list[int],
block: Any,
local_bindings: dict[str, Any],
) -> NoneAttributes¶
block: Anycontrol_operand_groups: list[list[int]]control_phys: list[int]local_bindings: dict[str, Any]target_index_groups: list[list[int]]target_phys: list[int]target_qubit_operands: list[Any]
ReturnOperation [source]¶
class ReturnOperation(Operation)Explicit return operation marking the end of a block with return values.
This operation represents an explicit return statement in the IR. It takes the values to be returned as operands and produces no results (it is a terminal operation that transfers control flow back to the caller).
operands: [Value, ...] - The values to return (may be empty for void returns) results: [] - Always empty (terminal operation)
Example:
A function that returns two values (a UInt and a Float):
ReturnOperation(
operands=[uint_value, float_value],
results=[],
)
The signature would be:
operands=[ParamHint("return_0", UIntType()), ParamHint("return_1", FloatType())]
results=[]Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKind Return CLASSICAL as this is a control flow operation without quantum effects.signature: Signature Return the signature with operands for each return value and no results.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)SymbolicControlledU [source]¶
class SymbolicControlledU(ControlledUOperation)Controlled-U with symbolic (Value) number of controls.
Operand layout: [ctrl_arg_0, ..., ctrl_arg_{k-1}, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_arg_0', ..., ctrl_arg_{k-1}', tgt_0', ..., tgt_m']
The number of control arguments k is recorded in
num_control_args; the default k = 1 corresponds to the
historical single-pool form (operands[0] is a
Vector[Qubit] / VectorView whose length equals
num_controls, or whose control_indices-selected subset
does). When k > 1 the control prefix is a heterogeneous
sequence of scalar Qubit values and ArrayValues whose
total qubit count is num_controls; the emit pass walks them
in order to recover the per-physical-qubit control set.
When control_indices is None the entire control prefix
is used as active controls (one-arg form: len(ctrl_vector) == num_controls; multi-arg form: the qubit-count sum of the
prefix args equals num_controls). When non-None, the
listed indices select exactly num_controls slots from a
single-arg pool to act as controls; combining
control_indices with the multi-arg control prefix is
rejected at frontend time.
Each control_indices entry is stored as a Value of
UIntType regardless of whether the frontend passed an
int literal or a UInt handle, so all downstream
value-substitution passes see a uniform shape.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: Value = (lambda: Value(type=(UIntType()), name=''))(),
control_indices: tuple[Value, ...] | None = None,
num_control_args: int = 1,
) -> NoneAttributes¶
control_indices: tuple[Value, ...] | Nonecontrol_operands: list[Value]is_symbolic_num_controls: boolnum_control_args: intnum_controls: Valueparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationValue [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
qamomile.circuit.transpiler.passes.emit_support.gate_emission¶
Gate emission helper extracted from StandardEmitPass.
Provides emit_gate and resolve_angle as module-level functions so
they can be tested and reused independently of the class.
Overview¶
| Function | Description |
|---|---|
emit_gate | Emit a single gate operation. |
resolve_angle | Resolve angle parameter for rotation gates. |
| Class | Description |
|---|---|
GateOperation | Quantum gate operation. |
GateOperationType | |
OperandResolutionInfo | Detailed information about a single operand that failed to resolve. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
QubitIndexResolutionError | Error when qubit indices cannot be resolved during emission. |
ResolutionFailureReason | Categorizes why qubit index resolution failed. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
UnifiedValueResolver | Resolve IR Values to concrete Python values. |
Functions¶
emit_gate [source]¶
def emit_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: GateOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a single gate operation.
resolve_angle [source]¶
def resolve_angle(
emit_pass: 'StandardEmitPass',
op: GateOperation,
bindings: dict[str, Any],
) -> float | AnyResolve angle parameter for rotation gates.
theta is always a Value stored as the last element of operands for rotation gates.
Classes¶
GateOperation [source]¶
class GateOperation(Operation)Quantum gate operation.
For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is
stored as the last element of operands. Use the theta
property for typed read access and the rotation / fixed factory
class-methods for type-safe construction.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: GateOperationType | None = None,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindqubit_operands: list[Value] Qubit operands (excluding the theta parameter if present).signature: Signaturetheta: Value | None Angle parameter for rotation gates, orNonefor fixed gates.
Methods¶
fixed¶
@classmethod
def fixed(
cls,
gate_type: GateOperationType,
qubits: list[Value],
results: list[Value],
) -> 'GateOperation'Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.
rotation¶
@classmethod
def rotation(
cls,
gate_type: GateOperationType,
qubits: list[Value],
theta: Value,
results: list[Value],
) -> 'GateOperation'Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.
GateOperationType [source]¶
class GateOperationType(enum.Enum)Attributes¶
CPCXCZHPRXRYRZRZZSSDGSWAPTTDGTOFFOLIXYZ
OperandResolutionInfo [source]¶
class OperandResolutionInfoDetailed information about a single operand that failed to resolve.
Constructor¶
def __init__(
self,
operand_name: str,
operand_uuid: str,
is_array_element: bool,
parent_array_name: str | None,
element_indices_names: list[str],
failure_reason: ResolutionFailureReason,
failure_details: str,
) -> NoneAttributes¶
element_indices_names: list[str]failure_details: strfailure_reason: ResolutionFailureReasonis_array_element: booloperand_name: stroperand_uuid: strparent_array_name: str | None
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
QubitIndexResolutionError [source]¶
class QubitIndexResolutionError(EmitError)Error when qubit indices cannot be resolved during emission.
This error provides detailed diagnostic information about why qubit index resolution failed and suggests remediation steps.
Constructor¶
def __init__(
self,
gate_type: str,
operand_infos: list[OperandResolutionInfo],
available_bindings_keys: list[str],
available_qubit_map_keys: list[str],
)Attributes¶
available_bindings_keysavailable_qubit_map_keysgate_typeoperand_infos
ResolutionFailureReason [source]¶
class ResolutionFailureReason(Enum)Categorizes why qubit index resolution failed.
Attributes¶
ARRAY_ELEMENT_NOT_IN_QUBIT_MAPDIRECT_UUID_NOT_FOUNDINDEX_NOT_NUMERICNEGATIVE_INDEXNESTED_ARRAY_RESOLUTION_FAILEDSYMBOLIC_INDEX_NOT_BOUNDUNKNOWN
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)ValueResolver [source]¶
class ValueResolverResolve IR Values to concrete Python values.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already resolved values. The values may be either raw Python scalars or Value objects; if a Value is found its get_const() is extracted automatically. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user at transpile time. |
Constructor¶
def __init__(
self,
context: dict[str, Any] | None = None,
bindings: dict[str, Any] | None = None,
)Create a resolver with optional context and bindings.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already-resolved values. Defaults to None. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user. Defaults to None. |
Methods¶
resolve¶
def resolve(self, value: Any) -> Any | NoneResolve a Value-like object to a concrete Python value.
If value is not a Value-like object (no uuid attribute) it
is returned as-is — the caller already has a concrete value.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Any | The Value-like object or already concrete value to resolve. |
Returns:
Any | None — Any | None: The resolved concrete value, the original
concrete value for non-Value inputs, or None when no
resolution rule applies.
qamomile.circuit.transpiler.passes.emit_support.inverse_emission¶
Inverse block emission helpers extracted from StandardEmitPass.
Emits :class:InverseBlockOperation with a three-tier strategy: try the
backend-native inverse of the forward source_block first (reusable
gate + gate_inverse), then a reusable gate built from the
implementation_block fallback, and finally inline the fallback
gate by gate. Each function takes an emit_pass parameter (a
StandardEmitPass instance) in place of self so subclass
overrides (e.g. backend emit passes) are respected, mirroring
:mod:.controlled_emission.
Overview¶
| Function | Description |
|---|---|
emit_inverse_block | Emit a first-class inverse block operation. |
emit_inverse_block_at_indices | Emit an inverse block after physical qubits have been resolved. |
map_array_result_group | Map an array-valued result to a physical index group. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
EmitError | Error during backend code emission. |
InverseBlockOperation | Represent an inverse qkernel/block as a first-class IR operation. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Functions¶
emit_inverse_block [source]¶
def emit_inverse_block(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: InverseBlockOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a first-class inverse block operation.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
op | InverseBlockOperation | Inverse block operation to emit. |
qubit_map | QubitMap | Current quantum value to physical qubit map. |
bindings | dict[str, Any] | Active emit bindings. |
Raises:
EmitError— If an inverse block has missing blocks, unresolved qubit operands, or no available native/fallback emission path.
emit_inverse_block_at_indices [source]¶
def emit_inverse_block_at_indices(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: InverseBlockOperation,
control_indices: list[int],
target_indices: list[int],
bindings: dict[str, Any],
) -> NoneEmit an inverse block after physical qubits have been resolved.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
op | InverseBlockOperation | Inverse block operation to emit. |
control_indices | list[int] | Physical control qubits. |
target_indices | list[int] | Physical target qubits. |
bindings | dict[str, Any] | Active emit bindings. |
Raises:
EmitError— If required source/fallback blocks are missing or no emission path can represent the operation.SliceBorrowViolationError— If a nested block’s slice usage fails the borrow check run by_normalize_inverse_block_op.
map_array_result_group [source]¶
def map_array_result_group(result_uuid: str, index_group: list[int], index_map: PhysicalIndexMap) -> NoneMap an array-valued result to a physical index group.
Parameters:
| Name | Type | Description |
|---|---|---|
result_uuid | str | UUID of the array-valued result whose element addresses should be registered. |
index_group | list[int] | Physical indices for the result elements, in result-local element order. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with element addresses and, when available, the base result address. |
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
InverseBlockOperation [source]¶
class InverseBlockOperation(Operation)Represent an inverse qkernel/block as a first-class IR operation.
The operation stores both the original forward block and a Qamomile-built
inverse implementation block. Emitters may use source_block with a
backend-native inverse/adjoint primitive, then fall back to
implementation_block when native inversion is unavailable.
Operands are ordered as control qubits, target quantum operands, then
classical/object parameters. Results mirror the quantum operand layout:
control results first, then one target result per target operand. Vector
target operands therefore count as one operand/result while contributing
their scalar width to num_target_qubits.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
source_block: Block | None = None,
implementation_block: Block | None = None,
) -> NoneAttributes¶
control_qubits: list[‘Value’] Return control quantum operands.custom_name: strimplementation_block: Block | Nonename: str Return a human-readable inverse operation name.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind.parameters: list[‘Value’] Return classical/object parameter operands.signature: Signature Return the operation signature.source_block: Block | Nonetarget_qubits: list[‘Value’] Return target quantum operands.
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)qamomile.circuit.transpiler.passes.emit_support.loop_analyzer¶
Loop analysis helpers for emission.
Identity policy: loop variables are identified by their IR Value
UUID (ForOperation.loop_var_value.uuid), not by their display
name. Two nested or sibling loops with identical user-chosen names
(e.g. for i in range(N): for i in range(M):) are distinct here
because each ForOperation carries its own loop_var_value with
a fresh UUID, and UUIDRemapper clones that field consistently with
body references via the all_input_values / replace_values
protocol.
There is no name fallback: if loop_var_value is None (legacy
IR built before the field existed) we skip the loop-var checks entirely.
Comparing by name was the soil for nested-loop name-collision bugs.
Overview¶
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
ControlledUOperation | Base class for controlled-U operations. |
ForOperation | Represents a for loop operation. |
GateOperation | Quantum gate operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
LoopAnalyzer | Analyzes loop structures to determine emission strategy. |
PauliEvolveOp | Pauli evolution operation: exp(-i * gamma * H). |
RuntimeClassicalExpr | A classical expression known to require runtime evaluation. |
Value | A typed SSA value in the IR. |
WhileOperation | Represents a while loop operation. |
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationGateOperation [source]¶
class GateOperation(Operation)Quantum gate operation.
For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is
stored as the last element of operands. Use the theta
property for typed read access and the rotation / fixed factory
class-methods for type-safe construction.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: GateOperationType | None = None,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindqubit_operands: list[Value] Qubit operands (excluding the theta parameter if present).signature: Signaturetheta: Value | None Angle parameter for rotation gates, orNonefor fixed gates.
Methods¶
fixed¶
@classmethod
def fixed(
cls,
gate_type: GateOperationType,
qubits: list[Value],
results: list[Value],
) -> 'GateOperation'Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.
rotation¶
@classmethod
def rotation(
cls,
gate_type: GateOperationType,
qubits: list[Value],
theta: Value,
results: list[Value],
) -> 'GateOperation'Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationLoopAnalyzer [source]¶
class LoopAnalyzerAnalyzes loop structures to determine emission strategy.
Methods¶
should_unroll¶
def should_unroll(self, op: ForOperation, bindings: dict[str, object]) -> boolPauliEvolveOp [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()) -> NoneAttributes¶
evolved_qubits: Value The evolved quantum register result.gamma: Value The evolution time parameter.observable: Value The Observable parameter operand.operation_kind: OperationKind PauliEvolveOp is QUANTUM - transforms quantum state.qubits: Value The quantum register operand.signature: Signature
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:
Binary kinds (EQ/NEQ/LT/LE/GT/GE/AND/OR/ADD/SUB/MUL/DIV/FLOORDIV/MOD/POW):
operands = [lhs, rhs].Unary kind (NOT):
operands = [val].Result:
results = [output_value].
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,
) -> NoneAttributes¶
kind: RuntimeOpKind | Noneoperation_kind: OperationKindsignature: Signature
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.passes.emit_support.measurement_emission¶
Measurement emission helpers extracted from StandardEmitPass.
Provides emit_measure, emit_measure_vector and
emit_measure_qfixed as module-level functions.
Overview¶
| Function | Description |
|---|---|
emit_measure | Emit a single measurement. |
emit_measure_qfixed | Emit QFixed measurement. |
emit_measure_vector | Emit vector measurement. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
EmitError | Error during backend code emission. |
MeasureOperation | |
MeasureQFixedOperation | Measure a quantum fixed-point number. |
MeasureVectorOperation | Measure a vector of qubits. |
MeasurementMode | How a backend handles measurement operations. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Functions¶
emit_measure [source]¶
def emit_measure(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any] | None = None,
) -> NoneEmit a single measurement.
Resolves the qubit operand using the full resolver (handles both scalar qubits and array element qubits with composite keys).
Raises:
warnings.warn— If the qubit or clbit cannot be resolved, a warning is emitted instead of silently dropping the measurement.
emit_measure_qfixed [source]¶
def emit_measure_qfixed(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureQFixedOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneEmit QFixed measurement.
emit_measure_vector [source]¶
def emit_measure_vector(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureVectorOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit vector measurement.
Resolves the qubit operand’s slice_of chain so that measuring a
view (measure(q[1::2])) correctly targets the root parent’s
physical qubits.
Behaviour for unresolvable inputs differs by case:
Unknown vector length (
_resolve_sizereturnsNone) — the function defers silently. This handles transpile-only paths (e.g. unbound parameter-size arrays) where downstream late- binding callers still handle the emit correctly.Resolvable length but a sliced view that resolves to zero physical qubits — raises
EmitError. Previously this produced executions returning[(None, N)], a data-integrity hazard, so the silent path is intentionally narrowed to view-on-empty cases only.Resolvable length but slice bounds are themselves symbolic — raises
EmitErrorfromresolve_slice_chain.
Raises:
EmitError— When a sliced view resolves to zero physical qubits, or when slice bounds remain symbolic at emit time.
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
MeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureQFixedOperation [source]¶
class MeasureQFixedOperation(Operation)Measure a quantum fixed-point number.
This operation measures all qubits in a QFixed register and produces a Float result. During transpilation, this is lowered to individual MeasureOperations plus a DecodeQFixedOperation.
operands: [QFixed value (contains qubit_values in params)] results: [Float value]
Encoding:
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasurementMode [source]¶
class MeasurementMode(Enum)How a backend handles measurement operations.
Attributes¶
NATIVERUNNABLESTATIC
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)qamomile.circuit.transpiler.passes.emit_support.pauli_evolve_emission¶
Pauli evolution emission helper for StandardEmitPass.
Extracted from standard_emit.py to isolate the Hamiltonian
decomposition logic from the main emit dispatch.
The emit_pauli_evolve function is the default implementation.
Backend-specific emit passes (e.g., QiskitEmitPass) may override
the corresponding _emit_pauli_evolve method; calling
super()._emit_pauli_evolve(...) will ultimately delegate here.
Overview¶
| Function | Description |
|---|---|
emit_pauli_evolve | Emit Pauli evolution: exp(-i * gamma * H). |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
EmitError | Error during backend code emission. |
PauliEvolveOp | Pauli evolution operation: exp(-i * gamma * H). |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Functions¶
emit_pauli_evolve [source]¶
def emit_pauli_evolve(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: PauliEvolveOp,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit Pauli evolution: exp(-i * gamma * H).
Resolves the Hamiltonian from bindings and decomposes each term using the Pauli gadget technique:
Basis change per qubit (X->H, Y->Sdg*H, Z->identity)
CNOT ladder + RZ
Undo basis change
Subclasses can override this for backend-native implementations (e.g., Qiskit PauliEvolutionGate).
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
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()) -> NoneAttributes¶
evolved_qubits: Value The evolved quantum register result.gamma: Value The evolution time parameter.observable: Value The Observable parameter operand.operation_kind: OperationKind PauliEvolveOp is QUANTUM - transforms quantum state.qubits: Value The quantum register operand.signature: Signature
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)qamomile.circuit.transpiler.passes.emit_support.physical_index_map¶
Helpers for mutating physical-index maps during emission.
Overview¶
| Function | Description |
|---|---|
array_element_mapping | Collect physical indices for the elements of an array value. |
array_element_mappings | Collect array element mappings for multiple source arrays. |
copy_array_element_aliases | Copy array element aliases from a source array to a result array. |
map_array_element_aliases | Map explicit array element aliases to a result array. |
map_array_result_group | Map an array-valued result to a physical index group. |
| Class | Description |
|---|---|
QubitAddress | Typed key for qubit/clbit physical-index maps. |
Functions¶
array_element_mapping [source]¶
def array_element_mapping(source_uuid: str, index_map: Mapping[QubitAddress, int]) -> dict[int, int]Collect physical indices for the elements of an array value.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuid | str | UUID of the array whose element addresses should be collected. |
index_map | Mapping[QubitAddress, int] | Physical-index map to read. |
Returns:
dict[int, int] — dict[int, int]: Mapping from element index to physical index.
array_element_mappings [source]¶
def array_element_mappings(
source_uuids: set[str],
index_map: Mapping[QubitAddress, int],
) -> dict[str, dict[int, int]]Collect array element mappings for multiple source arrays.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuids | set[str] | UUIDs of the arrays whose element addresses should be collected. |
index_map | Mapping[QubitAddress, int] | Physical-index map to read. |
Returns:
dict[str, dict[int, int]] — dict[str, dict[int, int]]: Mapping from each requested source UUID to
its element-index-to-physical-index mapping.
copy_array_element_aliases [source]¶
def copy_array_element_aliases(source_uuid: str, result_uuid: str, index_map: PhysicalIndexMap) -> NoneCopy array element aliases from a source array to a result array.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuid | str | UUID of the source array whose element addresses are already present in index_map. |
result_uuid | str | UUID of the result array that should alias the same physical resources element by element. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with any missing result element addresses and the result base address. |
map_array_element_aliases [source]¶
def map_array_element_aliases(
result_uuid: str,
element_mapping: Mapping[int, int],
index_map: PhysicalIndexMap,
*,
map_base_address: bool = True,
) -> NoneMap explicit array element aliases to a result array.
Parameters:
| Name | Type | Description |
|---|---|---|
result_uuid | str | UUID of the result array that should receive the element aliases. |
element_mapping | Mapping[int, int] | Physical indices keyed by result element index. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with missing result element addresses and, when requested, the result base address. |
map_base_address | bool | Whether to map the scalar base address for the result array to its lowest-index element. Defaults to True. |
map_array_result_group [source]¶
def map_array_result_group(result_uuid: str, index_group: list[int], index_map: PhysicalIndexMap) -> NoneMap an array-valued result to a physical index group.
Parameters:
| Name | Type | Description |
|---|---|---|
result_uuid | str | UUID of the array-valued result whose element addresses should be registered. |
index_group | list[int] | Physical indices for the result elements, in result-local element order. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with element addresses and, when available, the base result address. |
Classes¶
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
qamomile.circuit.transpiler.passes.emit_support.qubit_address¶
Typed key for qubit/clbit physical-index maps.
Replaces the ad-hoc f"{uuid}_{index}" string convention with an
explicit, hashable value object that makes the construction/parsing
contract type-safe.
Overview¶
| Class | Description |
|---|---|
QubitAddress | Typed key for qubit/clbit physical-index maps. |
Classes¶
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
qamomile.circuit.transpiler.passes.emit_support.resource_allocator¶
Resource allocation helpers for emission.
Overview¶
| Function | Description |
|---|---|
copy_array_element_aliases | Copy array element aliases from a source array to a result array. |
map_phi_outputs | Register phi output UUIDs to the same physical resources as their sources. |
remap_static_phi_outputs | Remap phi outputs for a compile-time constant IfOperation. |
resolve_condition_address_detailed | Resolve a condition / source Value to its clbit_map key. |
resolve_if_condition | Resolve an if-condition to a compile-time boolean. |
resolve_qubit_key | Resolve a qubit Value to its allocation key. |
resolve_root_qubit_address | Resolve an array-element value to its root (array_uuid, index). |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
CastOperation | Type cast operation for creating aliases over the same quantum resources. |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
ConcreteControlledU | Controlled-U with concrete (int) number of controls. |
ControlledUOperation | Base class for controlled-U operations. |
GateOperation | Quantum gate operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
InverseBlockOperation | Represent an inverse qkernel/block as a first-class IR operation. |
MeasureOperation | |
MeasureQFixedOperation | Measure a quantum fixed-point number. |
MeasureVectorOperation | Measure a vector of qubits. |
PauliEvolveOp | Pauli evolution operation: exp(-i * gamma * H). |
PhiOp | SSA Phi function: merge point after conditional branch. |
QInitOperation | Initialize the qubit |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
ResourceAllocator | Allocates qubit and classical bit indices from operations. |
SymbolicControlledU | Controlled-U with symbolic (Value) number of controls. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolves Value objects to concrete indices or values. |
WhileOperation | Represents a while loop operation. |
Functions¶
copy_array_element_aliases [source]¶
def copy_array_element_aliases(source_uuid: str, result_uuid: str, index_map: PhysicalIndexMap) -> NoneCopy array element aliases from a source array to a result array.
Parameters:
| Name | Type | Description |
|---|---|---|
source_uuid | str | UUID of the source array whose element addresses are already present in index_map. |
result_uuid | str | UUID of the result array that should alias the same physical resources element by element. |
index_map | PhysicalIndexMap | Mutable physical-index map updated in place with any missing result element addresses and the result base address. |
map_phi_outputs [source]¶
def map_phi_outputs(
phi_ops: list,
qubit_map: QubitMap,
clbit_map: ClbitMap,
resolve_scalar_qubit: Any = None,
) -> NoneRegister phi output UUIDs to the same physical resources as their sources.
remap_static_phi_outputs [source]¶
def remap_static_phi_outputs(
phi_ops: list,
condition_value: bool,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneRemap phi outputs for a compile-time constant IfOperation.
resolve_condition_address_detailed [source]¶
def resolve_condition_address_detailed(
condition: Value,
bindings: dict[str, Any],
resolver: ValueResolver | None = None,
) -> tuple[QubitAddress, bool]Resolve a condition / source Value to its clbit_map key.
Single source of truth (shared by control_flow_emission.emit_if /
emit_while, the Qiskit / CUDA-Q backends, ResourceAllocator’s
loop-carried / phi aliasing, and the phi-output mapping helpers here)
for turning a runtime control-flow condition — or a phi source Value —
into the address its classical bit is registered under.
Scalar measurement results register under QubitAddress(bit.uuid),
while a Vector[Bit] element s[i] (s = qmc.measure(register))
registers under QubitAddress(root_array.uuid, root_index). The
element index and every slice_start / slice_step along the
parent’s slice_of chain are resolved the same way — taken directly
when constant, otherwise folded through bindings via resolver —
and composed into the root index via root_index = start + step * view_local_index repeated along the chain.
Parameters:
| Name | Type | Description |
|---|---|---|
condition | Value | The condition operand or phi source Value. |
bindings | dict[str, Any] | Active emit-time bindings used to fold symbolic indices / slice bounds. May be empty for callers that only have constant addresses to resolve (e.g. the allocator’s pre-emit pass). |
resolver | ValueResolver | None | Resolver exposing resolve_int_value; None restricts resolution to constants. Defaults to None. |
Returns:
tuple[QubitAddress, bool] — tuple[QubitAddress, bool]: (address, resolved_as_element).
resolved_as_element is True only when condition is a
Vector[Bit] element whose index (and any slice bounds)
resolved to concrete ints, giving the root-space
QubitAddress(root.uuid, root_index). It is False for a
plain scalar, or when an element’s index / slice bound could
not be resolved (the scalar UUID fallback). Callers that mutate
clbit_map should trust the address as a vector key only when
this flag is True, to avoid aliasing an unresolved element
onto an unrelated scalar slot.
resolve_if_condition [source]¶
def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | NoneResolve an if-condition to a compile-time boolean.
resolve_qubit_key [source]¶
def resolve_qubit_key(qubit: 'Value') -> tuple[QubitAddress | None, bool]Resolve a qubit Value to its allocation key.
Parameters:
| Name | Type | Description |
|---|---|---|
qubit | Value | Qubit value to resolve. Array elements with a constant index are resolved through their full slice_of chain to the root array address. |
Returns:
tuple[QubitAddress | None, bool] — tuple[QubitAddress | None, bool]: (address, is_array_element).
address is the root-space address for a resolvable array
element, None for an array element whose index or slice
bounds are symbolic at this binding-free stage, and a scalar
UUID address for non-array qubits. A negative constant index
(or an out-of-contract slice bound) also yields None:
resolve_root_qubit_address refuses it rather than letting it
silently address a wrong root slot.
resolve_root_qubit_address [source]¶
def resolve_root_qubit_address(value: 'Value') -> tuple[str, int] | NoneResolve an array-element value to its root (array_uuid, index).
Walks the parent_array / slice_of chain and composes the nested
affine slice maps, so view[i] resolves to
(root_uuid, start + step * i) for the composed (start, step). The
returned pair is the build-stable identity of the physical qubit slot: the
root array’s QInitOperation always registers it as
QubitAddress(root_uuid, index), so this address resolves even when the
element’s own (per-version) UUID was never registered.
The transpiler’s resource allocator uses the same walk to resolve gate and measurement operands; this shared helper keeps both call sites consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Value | The value to resolve. Expected to be an array element (parent_array set with a single constant element_indices entry). |
Returns:
tuple[str, int] | None — tuple[str, int] | None: (root_array_uuid, composed_index) when
value is an array element with a constant index whose entire
slice_of chain has constant slice_start / slice_step.
None when value is not an array element, when its index is
non-constant, or when any slice bound in the chain is non-constant
(those cases are deferred to the emit-time resolver, which has
bindings available). Also None for a negative constant index
or a chain frame with negative slice_start / non-positive
slice_step — composing those would silently address a wrong
root slot, so they are refused rather than guessed (the frontend
rejects them at trace time; this guard covers programmatically
constructed IR).
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]CastOperation [source]¶
class CastOperation(Operation)Type cast operation for creating aliases over the same quantum resources.
This operation does NOT allocate new qubits. It creates a new Value that references the same underlying quantum resources with a different type.
Use cases:
Vector[Qubit] -> QFixed (after QPE, for phase measurement)
Vector[Qubit] -> QUInt (for quantum arithmetic)
QUInt -> QFixed (reinterpret bits with different encoding)
QFixed -> QUInt (reinterpret bits with different encoding)
operands: [source_value] - The value being cast results: [cast_result] - The new value with target type (same physical qubits)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
source_type: ValueType | None = None,
target_type: ValueType | None = None,
qubit_mapping: list[str] = list(),
) -> NoneAttributes¶
num_qubits: int Number of qubits involved in the cast.operation_kind: OperationKind Cast stays in the same segment as its source (QUANTUM for quantum types).qubit_mapping: list[str]signature: Signature Return the type signature of this cast operation.source_type: ValueType | Nonetarget_type: ValueType | None
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
ConcreteControlledU [source]¶
class ConcreteControlledU(ControlledUOperation)Controlled-U with concrete (int) number of controls.
Operand layout: [ctrl_0, ..., ctrl_n, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_0', ..., ctrl_n', tgt_0', ..., tgt_m']
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int = 1,
) -> NoneAttributes¶
control_operands: list[Value]num_controls: intparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationGateOperation [source]¶
class GateOperation(Operation)Quantum gate operation.
For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is
stored as the last element of operands. Use the theta
property for typed read access and the rotation / fixed factory
class-methods for type-safe construction.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: GateOperationType | None = None,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindqubit_operands: list[Value] Qubit operands (excluding the theta parameter if present).signature: Signaturetheta: Value | None Angle parameter for rotation gates, orNonefor fixed gates.
Methods¶
fixed¶
@classmethod
def fixed(
cls,
gate_type: GateOperationType,
qubits: list[Value],
results: list[Value],
) -> 'GateOperation'Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.
rotation¶
@classmethod
def rotation(
cls,
gate_type: GateOperationType,
qubits: list[Value],
theta: Value,
results: list[Value],
) -> 'GateOperation'Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationInverseBlockOperation [source]¶
class InverseBlockOperation(Operation)Represent an inverse qkernel/block as a first-class IR operation.
The operation stores both the original forward block and a Qamomile-built
inverse implementation block. Emitters may use source_block with a
backend-native inverse/adjoint primitive, then fall back to
implementation_block when native inversion is unavailable.
Operands are ordered as control qubits, target quantum operands, then
classical/object parameters. Results mirror the quantum operand layout:
control results first, then one target result per target operand. Vector
target operands therefore count as one operand/result while contributing
their scalar width to num_target_qubits.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
source_block: Block | None = None,
implementation_block: Block | None = None,
) -> NoneAttributes¶
control_qubits: list[‘Value’] Return control quantum operands.custom_name: strimplementation_block: Block | Nonename: str Return a human-readable inverse operation name.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind.parameters: list[‘Value’] Return classical/object parameter operands.signature: Signature Return the operation signature.source_block: Block | Nonetarget_qubits: list[‘Value’] Return target quantum operands.
MeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureQFixedOperation [source]¶
class MeasureQFixedOperation(Operation)Measure a quantum fixed-point number.
This operation measures all qubits in a QFixed register and produces a Float result. During transpilation, this is lowered to individual MeasureOperations plus a DecodeQFixedOperation.
operands: [QFixed value (contains qubit_values in params)] results: [Float value]
Encoding:
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
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()) -> NoneAttributes¶
evolved_qubits: Value The evolved quantum register result.gamma: Value The evolution time parameter.observable: Value The Observable parameter operand.operation_kind: OperationKind PauliEvolveOp is QUANTUM - transforms quantum state.qubits: Value The quantum register operand.signature: Signature
PhiOp [source]¶
class PhiOp(Operation)SSA Phi function: merge point after conditional branch.
This operation selects one of two values based on a condition. Used to merge values from different branches of an if-else statement.
Example:
if condition:
x = x + 1 # true_value
else:
x = x + 2 # false_value
# x is now PhiOp(condition, true_value, false_value)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
condition: Valuefalse_value: Valueoperation_kind: OperationKindoutput: Valuesignature: Signaturetrue_value: Value
QInitOperation [source]¶
class QInitOperation(Operation)Initialize the qubit
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
ResourceAllocator [source]¶
class ResourceAllocatorAllocates qubit and classical bit indices from operations.
This class handles the first pass of circuit emission: determining how many physical qubits and classical bits are needed and mapping Value UUIDs to their physical indices.
New physical indices are assigned via monotonic counters
(_next_qubit_index / _next_clbit_index) so that alias
entries — which reuse an existing physical index — never inflate
the counter. Using len(map) would cause sparse (gapped)
physical indices because alias keys increase the map size without
adding new physical resources.
Constructor¶
def __init__(self, resolver: ValueResolver | None = None) -> NoneInitialize allocator state.
Parameters:
| Name | Type | Description |
|---|---|---|
resolver | ValueResolver | None | Emit value resolver that carries runtime parameter names and binding lookup rules. Defaults to None, which creates a resolver without runtime parameters. |
Methods¶
allocate¶
def allocate(
self,
operations: list[Operation],
bindings: dict[str, Any] | None = None,
initial_qubit_map: QubitMap | None = None,
initial_clbit_map: ClbitMap | None = None,
) -> tuple[QubitMap, ClbitMap]Allocate qubit and clbit indices for all operations.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to allocate resources for. |
bindings | dict[str, Any] | None | Optional variable bindings for resolving dynamic sizes. Defaults to None (treated as an empty mapping). |
initial_qubit_map | QubitMap | None | Optional pre-populated qubit address mapping. Used by callers that need to seed the allocator with bindings established outside the operation list — for instance, the inner-block emitter in blockvalue_to_gate pre-allocates Vector[Qubit] input elements (the inner block has no QInitOperation for inputs, so per-element entries must be supplied here or the assertion in _allocate_gate fires). The map is copied; allocation continues from max(values) + 1 so new QInitOperation allocations inside operations do not collide. Defaults to None (treated as empty). |
initial_clbit_map | ClbitMap | None | Optional pre-populated clbit address mapping. Same semantics as initial_qubit_map but for classical bits. Defaults to None. |
Returns:
tuple[QubitMap, ClbitMap] — tuple[QubitMap, ClbitMap]: (qubit_map, clbit_map) where
each maps QubitAddress to a physical index. If an
initial map was supplied, its entries are preserved
verbatim in the returned map.
SymbolicControlledU [source]¶
class SymbolicControlledU(ControlledUOperation)Controlled-U with symbolic (Value) number of controls.
Operand layout: [ctrl_arg_0, ..., ctrl_arg_{k-1}, tgt_0, ..., tgt_m, params...]
Result layout: [ctrl_arg_0', ..., ctrl_arg_{k-1}', tgt_0', ..., tgt_m']
The number of control arguments k is recorded in
num_control_args; the default k = 1 corresponds to the
historical single-pool form (operands[0] is a
Vector[Qubit] / VectorView whose length equals
num_controls, or whose control_indices-selected subset
does). When k > 1 the control prefix is a heterogeneous
sequence of scalar Qubit values and ArrayValues whose
total qubit count is num_controls; the emit pass walks them
in order to recover the per-physical-qubit control set.
When control_indices is None the entire control prefix
is used as active controls (one-arg form: len(ctrl_vector) == num_controls; multi-arg form: the qubit-count sum of the
prefix args equals num_controls). When non-None, the
listed indices select exactly num_controls slots from a
single-arg pool to act as controls; combining
control_indices with the multi-arg control prefix is
rejected at frontend time.
Each control_indices entry is stored as a Value of
UIntType regardless of whether the frontend passed an
int literal or a UInt handle, so all downstream
value-substitution passes see a uniform shape.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: Value = (lambda: Value(type=(UIntType()), name=''))(),
control_indices: tuple[Value, ...] | None = None,
num_control_args: int = 1,
) -> NoneAttributes¶
control_indices: tuple[Value, ...] | Nonecontrol_operands: list[Value]is_symbolic_num_controls: boolnum_control_args: intnum_controls: Valueparam_operands: list[Value]signature: Signaturetarget_operands: list[Value]
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationValue [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.passes.emit_support.value_resolver¶
Value resolution helpers for emission.
Overview¶
| Function | Description |
|---|---|
resolve_qubit_key | Resolve a qubit Value to its allocation key. |
resolve_root_qubit_address | Resolve an array-element value to its root (array_uuid, index). |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
EmitError | Error during backend code emission. |
QubitAddress | Typed key for qubit/clbit physical-index maps. |
QubitResolutionResult | Result of attempting to resolve a qubit index. |
ResolutionFailureReason | Categorizes why qubit index resolution failed. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolves Value objects to concrete indices or values. |
Functions¶
resolve_qubit_key [source]¶
def resolve_qubit_key(qubit: 'Value') -> tuple[QubitAddress | None, bool]Resolve a qubit Value to its allocation key.
Parameters:
| Name | Type | Description |
|---|---|---|
qubit | Value | Qubit value to resolve. Array elements with a constant index are resolved through their full slice_of chain to the root array address. |
Returns:
tuple[QubitAddress | None, bool] — tuple[QubitAddress | None, bool]: (address, is_array_element).
address is the root-space address for a resolvable array
element, None for an array element whose index or slice
bounds are symbolic at this binding-free stage, and a scalar
UUID address for non-array qubits. A negative constant index
(or an out-of-contract slice bound) also yields None:
resolve_root_qubit_address refuses it rather than letting it
silently address a wrong root slot.
resolve_root_qubit_address [source]¶
def resolve_root_qubit_address(value: 'Value') -> tuple[str, int] | NoneResolve an array-element value to its root (array_uuid, index).
Walks the parent_array / slice_of chain and composes the nested
affine slice maps, so view[i] resolves to
(root_uuid, start + step * i) for the composed (start, step). The
returned pair is the build-stable identity of the physical qubit slot: the
root array’s QInitOperation always registers it as
QubitAddress(root_uuid, index), so this address resolves even when the
element’s own (per-version) UUID was never registered.
The transpiler’s resource allocator uses the same walk to resolve gate and measurement operands; this shared helper keeps both call sites consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Value | The value to resolve. Expected to be an array element (parent_array set with a single constant element_indices entry). |
Returns:
tuple[str, int] | None — tuple[str, int] | None: (root_array_uuid, composed_index) when
value is an array element with a constant index whose entire
slice_of chain has constant slice_start / slice_step.
None when value is not an array element, when its index is
non-constant, or when any slice bound in the chain is non-constant
(those cases are deferred to the emit-time resolver, which has
bindings available). Also None for a negative constant index
or a chain frame with negative slice_start / non-positive
slice_step — composing those would silently address a wrong
root slot, so they are refused rather than guessed (the frontend
rejects them at trace time; this guard covers programmatically
constructed IR).
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]EmitError [source]¶
class EmitError(QamomileCompileError)Error during backend code emission.
Constructor¶
def __init__(self, message: str, operation: str | None = None)Attributes¶
operation
QubitAddress [source]¶
class QubitAddressTyped key for qubit/clbit physical-index maps.
For scalar qubits: QubitAddress(uuid="abc123")
For array elements: QubitAddress(uuid="abc123", element_index=2)
This replaces the f"{uuid}_{i}" string key pattern throughout
the emit pipeline, making the key format explicit and preventing
format-string bugs.
Constructor¶
def __init__(self, uuid: str, element_index: int | None = None) -> NoneAttributes¶
element_index: int | Noneis_array_element: bool True if this address refers to an array element.uuid: str
Methods¶
from_composite_key¶
@classmethod
def from_composite_key(cls, key: str) -> QubitAddressParse a legacy composite key string into a QubitAddress.
The frontend stores qubit references as composite strings in
the format "{array_uuid}_{element_index}" (e.g., cast
operation qubit mappings, element UUIDs). This helper converts
such strings to proper QubitAddress instances.
If the key does not match the composite format (i.e., the
suffix after the last _ is not a non-negative integer),
it is treated as a plain scalar UUID.
matches_array¶
def matches_array(self, array_uuid: str) -> boolTrue if this address belongs to the given array.
with_element¶
def with_element(self, index: int) -> QubitAddressCreate an array-element address from this array’s base UUID.
QubitResolutionResult [source]¶
class QubitResolutionResultResult of attempting to resolve a qubit index.
Constructor¶
def __init__(
self,
success: bool,
index: int | None = None,
failure_reason: ResolutionFailureReason | None = None,
failure_details: str = '',
) -> NoneAttributes¶
failure_details: strfailure_reason: ResolutionFailureReason | Noneindex: int | Nonesuccess: bool
ResolutionFailureReason [source]¶
class ResolutionFailureReason(Enum)Categorizes why qubit index resolution failed.
Attributes¶
ARRAY_ELEMENT_NOT_IN_QUBIT_MAPDIRECT_UUID_NOT_FOUNDINDEX_NOT_NUMERICNEGATIVE_INDEXNESTED_ARRAY_RESOLUTION_FAILEDSYMBOLIC_INDEX_NOT_BOUNDUNKNOWN
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolves Value objects to concrete indices or values.
Constructor¶
def __init__(self, parameters: set[str] | None = None)Attributes¶
parameters
Methods¶
bind_block_params¶
def bind_block_params(
self,
block_value: Any,
param_operands: list['Value'],
bindings: dict[str, Any],
) -> dict[str, Any]Create local bindings by matching block parameter inputs to operands.
get_parameter_key¶
def get_parameter_key(self, value: 'Value', bindings: dict[str, Any]) -> str | NoneGet parameter key if this value should be a symbolic parameter.
lookup_in_bindings¶
def lookup_in_bindings(
self,
value: 'Value',
bindings: dict[str, Any],
*,
index_array: bool = False,
) -> AnyCanonical resolution chain for a Value against bindings.
All other resolver methods (resolve_bound_value,
resolve_classical_value, resolve_int_value,
resolve_operand_for_binding) wrap this single chain. Centralizing
precedence here prevents the historical drift where one resolver
checked is_parameter before UUID and another checked it after,
which manifested as obscure binding failures when name-keyed writes
were dropped from the emit pass.
Resolution order (each step returns immediately on a hit):
valueis already a concrete Python scalar (nouuid).value.is_constant()— returnvalue.get_const().value.is_parameter()and its parameter name is inbindings— return that.value.uuidis inbindings— return that. This is where emit-time-computed intermediates (evaluate_binop/evaluate_classical_predicateresults) and phi aliases live.value.nameis inbindings— return that. This is where kernel parameters and loop iteration variables live. NOT a reliable channel for auto-generated tmp names like"uint_tmp"— those are intentionally written by UUID only.(When
index_array=True)valueis an array element with a resolvable parent inbindings— index into it.
Parameters:
| Name | Type | Description |
|---|---|---|
value | 'Value' | The IR Value (or already-concrete Python scalar) to resolve. |
bindings | dict[str, Any] | The active bindings dict. |
index_array | bool | When True, also resolve array-element accesses via parent_array indexing. Off by default because not all callers want to index into bound containers. |
Returns:
Any — The resolved Python value, or None if no step matched.
resolve_bound_value¶
def resolve_bound_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a Value to its raw bound Python object.
Wraps :meth:lookup_in_bindings with index_array=True so that
arr[i] accesses against a bound container resolve to the
element. Does not coerce the result — callers that need a
numeric scalar should go through :meth:resolve_classical_value.
resolve_classical_value¶
def resolve_classical_value(self, value: 'Value', bindings: dict[str, Any]) -> AnyResolve a classical Value to a concrete Python value.
Numeric bindings are normalized to native Python scalars
regardless of whether they come from a direct binding or from
array-element indexing, so downstream isinstance(x, (int, float)) checks are stable when callers bind np.pi/4 or
the like. bool is preserved (not coerced to int).
Non-numeric values (Hamiltonians, strings, dict values, …)
pass through unchanged.
resolve_int_value¶
def resolve_int_value(self, val: Any, bindings: dict[str, Any]) -> int | NoneResolve a value to an integer, or None when unresolvable.
Unresolvable symbolic Values must return None. The previous
return 0 fallback caused silent loop elision when parameter
shape dims (gamma_dim0) reached this resolver without being
folded into constants — downstream loop-bound resolution saw 0 and
quietly emitted an empty loop. Returning None propagates the
failure to emit_for_unrolled, which converts it into a hard
compile error.
resolve_operand_for_binding¶
def resolve_operand_for_binding(self, operand: 'Value', bindings: dict[str, Any]) -> AnyResolve an operand to a concrete value for block parameter binding.
Used when calling a sub-block (e.g. a controlled-U body): each param operand at the call site must resolve to a value to seed the callee’s parameter bindings.
resolve_qubit_index¶
def resolve_qubit_index(self, v: 'Value', qubit_map: QubitMap, bindings: dict[str, Any]) -> int | Noneresolve_qubit_index_detailed¶
def resolve_qubit_index_detailed(
self,
v: 'Value',
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> QubitResolutionResultResolve a Value to a physical qubit index with detailed failure info.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Value | The qubit Value to resolve. May be a scalar qubit or an array element (possibly through a sliced view chain). |
qubit_map | QubitMap | Mapping from QubitAddress to physical qubit indices built by the resource allocator. |
bindings | dict[str, Any] | Active emit-time bindings used to resolve symbolic element indices and slice bounds. |
Returns:
QubitResolutionResult — Success with the physical index, or a
failure carrying a ResolutionFailureReason — including
NEGATIVE_INDEX when a resolved element index is negative
or a resolved slice bound violates the frontend contract
(non-negative start, positive step); composing those through
the affine map would silently address a wrong root slot.
resolve_slice_chain¶
def resolve_slice_chain(
self,
av: 'ArrayValue',
bindings: dict[str, Any],
*,
operation: str = 'emit',
) -> tuple['ArrayValue', int, int]Walk an ArrayValue’s slice_of chain and return root + affine map.
Composes the nested affine maps so that a view-local index i
corresponds to the root-space index start + step * i. For a
root ArrayValue (no slice_of chain), returns (av, 0, 1)
so callers can always apply the same formula uniformly.
Parameters:
| Name | Type | Description |
|---|---|---|
av | 'ArrayValue' | The possibly-sliced ArrayValue whose root and affine mapping should be resolved. |
bindings | dict[str, Any] | Compile-time parameter bindings; required when any slice_start / slice_step in the chain is symbolic. |
operation | str | Human-readable name of the enclosing emit operation. Used only in the EmitError message when a symbolic slice bound cannot be resolved. Defaults to "emit". |
Returns:
'ArrayValue' — Tuple (root_array, start, step) where root_array is
int — the underlying non-sliced ArrayValue, and start/step
int — are Python int values satisfying
tuple['ArrayValue', int, int] — view[i] == root_array[start + step * i].
Raises:
EmitError— If anyslice_startorslice_stepin the chain resolves to a non-numeric or unbound value, or to bounds violating the frontend contract (negative start or non-positive step).
Example:
>>> # For ``view = q[1::2]`` where ``q`` has 4 qubits:
>>> resolver.resolve_slice_chain(view_av, bindings={})
(q_av, 1, 2)qamomile.circuit.transpiler.passes.entrypoint_validation¶
Entrypoint validation pass for top-level transpilation.
Overview¶
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
EntrypointValidationError | Error when a top-level transpilation entrypoint has unsupported I/O. |
EntrypointValidationPass | Validate top-level entrypoint constraints. |
Pass | Base class for all compiler passes. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
EntrypointValidationError [source]¶
class EntrypointValidationError(ValidationError)Error when a top-level transpilation entrypoint has unsupported I/O.
EntrypointValidationPass [source]¶
class EntrypointValidationPass(Pass[Block, Block])Validate top-level entrypoint constraints.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockPass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
qamomile.circuit.transpiler.passes.eval_utils¶
Shared evaluation utilities for transpiler passes.
This module is the single source of truth for kind-dispatched
classical-op evaluation. Three transpiler passes need to evaluate the
same family of ops (CompOp, CondOp, NotOp, BinOp):
compile_time_if_lowering— folds ops at compile time when operands resolve to constants.classical_executor— evaluates ops at runtime over a results dict.cast_binop_emission(emit pass) — folds ops at emit time for inlining loop variables and parameter bindings intoifconditions.
The low-level evaluate_*_values functions take fully resolved Python
operands and return the computed value (or None if the op cannot be
evaluated, e.g. division by zero, unknown kind, type mismatch). They
never touch bindings or resolvers — those responsibilities stay with the
caller.
The high-level fold_classical_op adds a uniform parameter-respecting
policy on top: callers supply a resolver callable and a FoldPolicy,
and the function returns either the folded scalar or None. This is
the layer that prevents the silent miscompilation class of bugs (Issue
#354 B-series): the parameter-array-element guard is now structurally
inside this function rather than re-implemented per call site.
Overview¶
| Function | Description |
|---|---|
evaluate_binop_values | Evaluate a binary arithmetic operation on two concrete values. |
evaluate_compop_values | Evaluate a comparison operation on two concrete values. |
evaluate_condop_values | Evaluate a logical and/or operation on two concrete values. |
evaluate_notop_value | Evaluate a logical-not operation on a concrete value. |
fold_classical_op | Fold a classical op to a concrete value, respecting the given policy. |
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
BinOpKind | |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CompOpKind | |
CondOp | Conditional logical operation (AND, OR). |
CondOpKind | |
FoldPolicy | Policy controlling how fold_classical_op treats parameters. |
NotOp |
Functions¶
evaluate_binop_values [source]¶
def evaluate_binop_values(
kind: BinOpKind | None,
left: float | int,
right: float | int,
) -> float | int | NoneEvaluate a binary arithmetic operation on two concrete values.
Parameters:
| Name | Type | Description |
|---|---|---|
kind | BinOpKind | None | The BinOpKind to apply. |
left | float | int | Left operand (numeric). |
right | float | int | Right operand (numeric). |
Returns:
float | int | None — The result, or None on division by zero, unknown kind, or
float | int | None — arithmetic error.
evaluate_compop_values [source]¶
def evaluate_compop_values(kind: CompOpKind | None, left: Any, right: Any) -> bool | NoneEvaluate a comparison operation on two concrete values.
Parameters:
| Name | Type | Description |
|---|---|---|
kind | CompOpKind | None | The CompOpKind to apply. |
left | Any | Left operand. |
right | Any | Right operand. |
Returns:
bool | None — The boolean result, or None on unknown kind or type
bool | None — incompatibility.
evaluate_condop_values [source]¶
def evaluate_condop_values(kind: CondOpKind | None, left: Any, right: Any) -> bool | NoneEvaluate a logical and/or operation on two concrete values.
Parameters:
| Name | Type | Description |
|---|---|---|
kind | CondOpKind | None | The CondOpKind to apply. |
left | Any | Left operand. |
right | Any | Right operand. |
Returns:
bool | None — The boolean result, or None on unknown kind.
evaluate_notop_value [source]¶
def evaluate_notop_value(operand: Any) -> bool | NoneEvaluate a logical-not operation on a concrete value.
Parameters:
| Name | Type | Description |
|---|---|---|
operand | Any | The operand to negate. |
Returns:
bool | None — The boolean negation, or None on type error.
fold_classical_op [source]¶
def fold_classical_op(
op: 'BinOp | CompOp | CondOp | NotOp',
operand_resolver: Callable[[Any], Any],
parameters: set[str],
policy: FoldPolicy,
) -> Any | NoneFold a classical op to a concrete value, respecting the given policy.
The caller supplies an operand_resolver callable that knows how
to look up a Value in the caller’s context (a concrete_values
map, an emit bindings dict + ValueResolver, or any other
source). This function handles:
The parameter guard (skips folding when an operand is a runtime parameter or parameter-array element under
EMIT_RESPECT_PARAMS).Strict scalar-only typing (rejects backend
Exprobjects and other non-numeric values that would spuriously fold toTrue).Kind dispatch via the underlying
evaluate_*_valuesprimitives.
Parameters:
| Name | Type | Description |
|---|---|---|
op | 'BinOp | CompOp | CondOp | NotOp' | The classical op to fold. Must be one of BinOp, CompOp, CondOp, NotOp. |
operand_resolver | Callable[[Any], Any] | Callable mapping each operand Value to a resolved Python scalar (or None when unresolvable). |
parameters | set[str] | Set of runtime parameter names. Used only when policy is EMIT_RESPECT_PARAMS. |
policy | FoldPolicy | Folding policy. See FoldPolicy docstring. |
Returns:
Any | None — The folded value (numeric for BinOp, bool for predicates),
Any | None — or None when any operand is symbolic, missing, or a runtime
Any | None — parameter under the policy.
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
BinOpKind [source]¶
class BinOpKind(enum.Enum)Attributes¶
ADDDIVFLOORDIVMINMODMULPOWSUB
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
CompOpKind [source]¶
class CompOpKind(enum.Enum)Attributes¶
EQGEGTLELTNEQ
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
CondOpKind [source]¶
class CondOpKind(enum.Enum)Attributes¶
ANDOR
FoldPolicy [source]¶
class FoldPolicy(enum.Enum)Policy controlling how fold_classical_op treats parameters.
COMPILE_TIME is for passes that have no notion of runtime
parameters (e.g. compile_time_if_lowering); every operand the
resolver returns is treated as a real value to fold.
EMIT_RESPECT_PARAMS is for emit-time passes where some Values
may correspond to runtime backend parameters whose concrete values
are placeholders or absent. Operands whose Value or
parent_array.name is in the active parameters set are
treated as symbolic and the fold returns None rather than
producing an incorrect concrete result.
Attributes¶
COMPILE_TIMEEMIT_RESPECT_PARAMS
NotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
qamomile.circuit.transpiler.passes.inline¶
Inline pass: Inline CallBlockOperations to create an affine block.
Overview¶
| Function | Description |
|---|---|
count_call_blocks | Count all CallBlockOperations reachable from an operation list. |
count_unrollable_call_blocks | Count CallBlockOperations the inline/partial-eval loop can still resolve. |
find_return_operation | Find the ReturnOperation in a list of operations (expected at the end). |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CallBlockOperation | |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
CompositeGateType | Registry of known composite gate types. |
ControlledUOperation | Base class for controlled-U operations. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
InlinePass | Inline all CallBlockOperations to create an affine block. |
InliningError | Error during inline pass (inlining CallBlockOperations). |
InverseBlockOperation | Represent an inverse qkernel/block as a first-class IR operation. |
Pass | Base class for all compiler passes. |
ReturnOperation | Explicit return operation marking the end of a block with return values. |
UUIDRemapper | Clones values and operations with fresh UUIDs and logical_ids. |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Functions¶
count_call_blocks [source]¶
def count_call_blocks(operations: list[Operation]) -> intCount all CallBlockOperations reachable from an operation list.
Recurses into InverseBlockOperation / ControlledUOperation
nested blocks and into IfOperation / HasNestedOps bodies, so
calls hidden inside control flow or operation-owned blocks are
counted. unroll_recursion uses this as the primary termination
signal (count == 0 means the block is fully inlined).
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to scan. |
Returns:
int — Total number of CallBlockOperations reachable from
operations, including nested ones.
count_unrollable_call_blocks [source]¶
def count_unrollable_call_blocks(operations: list[Operation]) -> intCount CallBlockOperations the inline/partial-eval loop can still resolve.
This mirrors :func:count_call_blocks but does not descend into
a ControlledUOperation.block or an InverseBlockOperation’s
nested blocks. A call trapped inside one of those operation-owned
blocks cannot be resolved by the unroll_recursion fixed-point
loop: partial_eval (ConstantFoldingPass /
CompileTimeIfLoweringPass) only recurses into HasNestedOps
bodies, never into operation-owned blocks, so a self-recursive
kernel’s base-case if is never folded there. Such a call is
therefore not unrollable. Calls at the top level or inside
For / If / While bodies are unrollable and are counted.
The unroll loop uses this to tell two failure modes apart: a non-zero
:func:count_call_blocks with a zero count_unrollable_call_blocks
means every residual call is trapped inside a controlled / inverted
block (i.e. a recursive @qkernel was passed to qmc.control /
qmc.inverse), as opposed to a genuinely non-terminating top-level
recursion.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to scan. |
Returns:
int — Number of CallBlockOperations reachable without entering a
ControlledUOperation.block or InverseBlockOperation
nested block.
find_return_operation [source]¶
def find_return_operation(operations: list[Operation]) -> ReturnOperation | NoneFind the ReturnOperation in a list of operations (expected at the end).
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CallBlockOperation [source]¶
class CallBlockOperation(Operation)Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
block: Block | None = None,
) -> NoneAttributes¶
block: Block | Noneoperation_kind: OperationKindsignature: Signature
Methods¶
is_self_reference_to¶
def is_self_reference_to(self, block: Block) -> boolReturn True if this call points to the given block (self-ref).
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
CompositeGateType [source]¶
class CompositeGateType(enum.Enum)Registry of known composite gate types.
Attributes¶
CUSTOMIQFTQFTQPE
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationHasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationInlinePass [source]¶
class InlinePass(Pass[Block, Block])Inline all CallBlockOperations to create an affine block.
This pass recursively inlines function calls while preserving control flow structures (For, If, While).
Input: Block with BlockKind.HIERARCHICAL (may contain CallBlockOperations) Output: Block with BlockKind.AFFINE (no CallBlockOperations)
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockInline all CallBlockOperations.
Self-recursive CallBlockOperations (ones whose .block is the
block currently being expanded) are unrolled one level per
call: the inner self-call is substituted but left intact so
that the outer fixed-point loop (inline ↔ partial_eval in
Transpiler.transpile) can fold the base-case if between
iterations. The output kind is AFFINE when no
CallBlockOperations remain, otherwise HIERARCHICAL.
InliningError [source]¶
class InliningError(QamomileCompileError)Error during inline pass (inlining CallBlockOperations).
InverseBlockOperation [source]¶
class InverseBlockOperation(Operation)Represent an inverse qkernel/block as a first-class IR operation.
The operation stores both the original forward block and a Qamomile-built
inverse implementation block. Emitters may use source_block with a
backend-native inverse/adjoint primitive, then fall back to
implementation_block when native inversion is unavailable.
Operands are ordered as control qubits, target quantum operands, then
classical/object parameters. Results mirror the quantum operand layout:
control results first, then one target result per target operand. Vector
target operands therefore count as one operand/result while contributing
their scalar width to num_target_qubits.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
source_block: Block | None = None,
implementation_block: Block | None = None,
) -> NoneAttributes¶
control_qubits: list[‘Value’] Return control quantum operands.custom_name: strimplementation_block: Block | Nonename: str Return a human-readable inverse operation name.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind.parameters: list[‘Value’] Return classical/object parameter operands.signature: Signature Return the operation signature.source_block: Block | Nonetarget_qubits: list[‘Value’] Return target quantum operands.
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ReturnOperation [source]¶
class ReturnOperation(Operation)Explicit return operation marking the end of a block with return values.
This operation represents an explicit return statement in the IR. It takes the values to be returned as operands and produces no results (it is a terminal operation that transfers control flow back to the caller).
operands: [Value, ...] - The values to return (may be empty for void returns) results: [] - Always empty (terminal operation)
Example:
A function that returns two values (a UInt and a Float):
ReturnOperation(
operands=[uint_value, float_value],
results=[],
)
The signature would be:
operands=[ParamHint("return_0", UIntType()), ParamHint("return_1", FloatType())]
results=[]Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKind Return CLASSICAL as this is a control flow operation without quantum effects.signature: Signature Return the signature with operands for each return value and no results.
UUIDRemapper [source]¶
class UUIDRemapperClones values and operations with fresh UUIDs and logical_ids.
Used during inlining to create unique identities for values when a block is called multiple times.
Constructor¶
def __init__(self)Attributes¶
logical_id_remap: dict[str, str] Get the mapping from old logical_ids to new logical_ids.uuid_remap: dict[str, str] Get the mapping from old UUIDs to new UUIDs.
Methods¶
clone_operation¶
def clone_operation(self, op: Operation) -> OperationClone an operation with fresh UUIDs for all values.
Cloning goes through the Operation.all_input_values() /
Operation.replace_values() protocol so every Value-typed
field — including subclass extras (ControlledUOperation.power,
ForOperation.loop_var_value, ForItemsOperation.key_var_values
etc.) — is cloned consistently with the body references that
point to it. Without this, a subclass field could keep an old
UUID while body operands referencing the same logical Value got
fresh UUIDs, breaking identity-by-UUID lookups at emit time.
Parameters:
| Name | Type | Description |
|---|---|---|
op | Operation | Operation to clone. |
Returns:
Operation — A clone of op with every owned Value (operands,
results, subclass-extra fields) and every nested-body Value
reassigned a fresh UUID / logical_id, and with
CastOperation.qubit_mapping carrier keys remapped.
clone_operations¶
def clone_operations(self, operations: list[Operation]) -> list[Operation]Clone a list of operations with fresh UUIDs.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to clone in order. |
Returns:
list[Operation] — list[Operation]: Cloned operations, each with fresh UUIDs, in the
same order as operations.
clone_value¶
def clone_value(self, value: ValueBase) -> ValueBaseClone any value type with a fresh UUID and logical_id.
Handles Value, ArrayValue, TupleValue, and DictValue through
the unified ValueBase protocol. Nested values (tuple elements, dict
entries, parent_array / element_indices / shape / slice
fields) and embedded metadata references are cloned consistently.
Results are cached by source UUID so a repeated clone returns the
same instance.
Parameters:
| Name | Type | Description |
|---|---|---|
value | ValueBase | The value to clone. |
Returns:
ValueBase — The cloned value of the same concrete type, with a
fresh UUID / logical_id and its nested values and metadata
references remapped through this remapper.
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.parameter_shape_resolution¶
Compile-time resolution of symbolic Vector parameter shape dimensions.
Qiskit / CUDA-Q / QuriParts circuits are fixed-structure at compile time:
loop bounds and array lengths must be concrete to emit a valid circuit.
Top-level Vector[Float] / Vector[UInt] parameters are created with
symbolic {name}_dim{i} Values (see
qamomile.circuit.frontend.func_to_block.create_dummy_input), so when a
kernel queries arr.shape[i] the IR references those symbolic Values in
loop operands, array allocations, etc.
This pass walks the HIERARCHICAL block before inlining and, for every
input array whose name is bound to a concrete array-like value in
bindings, replaces its symbolic shape dim Values with constant Values
holding the runtime length. After this pass the downstream pipeline can
unroll for i in qmc.range(arr.shape[0]) loops normally.
Parameters without a concrete binding (e.g. the library QAOA pattern where
only p is bound and gammas.shape is never queried) are left
untouched — their symbolic dims simply do not flow into any compile-time
structure decision, so they are harmless.
Overview¶
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
ParameterShapeResolutionPass | Substitute symbolic parameter array shape dims with concrete constants. |
Pass | Base class for all compiler passes. |
UIntType | Type representing an unsigned integer. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
ParameterShapeResolutionPass [source]¶
class ParameterShapeResolutionPass(Pass[Block, Block])Substitute symbolic parameter array shape dims with concrete constants.
Input: BlockKind.HIERARCHICAL (runs before InlinePass).
Output: same block kind, with matching shape dim Values constant-folded.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None) -> NoneAttributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockPass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
UIntType [source]¶
class UIntType(ClassicalTypeMixin, ValueType)Type representing an unsigned integer.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.partial_eval¶
Partial evaluation pass for compile-time simplification.
Overview¶
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CompileTimeIfLoweringPass | Lowers compile-time resolvable IfOperations before separation. |
ConstantFoldingPass | Evaluates constant expressions at compile time. |
PartialEvaluationPass | Fold constants and lower compile-time control flow. |
Pass | Base class for all compiler passes. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CompileTimeIfLoweringPass [source]¶
class CompileTimeIfLoweringPass(Pass[Block, Block])Lowers compile-time resolvable IfOperations before separation.
After constant folding, some IfOperation conditions are statically
known but remain as control-flow nodes. SegmentationPass treats them
as segment boundaries, causing MultipleQuantumSegmentsError for
classical-only compile-time if after quantum init.
This pass:
Evaluates conditions including expression-derived ones (
CompOp,CondOp,NotOpchains).Replaces resolved
IfOperations with selected-branch operations.Substitutes phi output UUIDs with selected-branch values in all subsequent operations and block outputs.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun the compile-time if lowering pass.
ConstantFoldingPass [source]¶
class ConstantFoldingPass(Pass[Block, Block])Evaluates constant expressions at compile time.
This pass folds BinOp operations when all operands are constants or bound parameters, eliminating unnecessary classical operations that would otherwise split quantum segments.
Example:
Before (with bindings={"phase": 0.5}):
BinOp(phase * 2) -> classical segment split
After:
Constant 1.0 -> no segment splitConstructor¶
def __init__(self, bindings: dict[str, Any] | None = None, *, strip_slice_ops: bool = True)Create a constant-folding pass.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Compile-time parameter bindings used when folding BinOps that reference declared parameters. |
strip_slice_ops | bool | When True (default), removes SliceArrayOperation nodes after folding. Set to False when a downstream pass — notably SliceBorrowCheckPass — still needs to observe slice declaration points in program order to decide view liveness. A separate strip pass must then run after the linearity check so segmentation still sees a pure quantum-op stream. |
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun constant folding on the block.
PartialEvaluationPass [source]¶
class PartialEvaluationPass(Pass[Block, Block])Fold constants and lower compile-time control flow.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockPass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
qamomile.circuit.transpiler.passes.separate¶
Segmentation pass: Split a block into executable program steps.
Overview¶
| Function | Description |
|---|---|
build_dependency_graph | Build a map from each value UUID to the UUIDs it depends on. |
find_measurement_derived_values | Forward-propagate measurement taint through the dependency graph. |
find_measurement_results | Find all value UUIDs that are direct results of measurement ops. |
lower_measure_qfixed | Lower MeasureQFixedOperation to MeasureVectorOperation + decode. |
lower_operations | Lower high-level operations like MeasureQFixedOperation. |
materialize_return | Synchronize output_values from ReturnOperation. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
BitType | Type representing a classical bit. |
Block | Unified block representation for all pipeline stages. |
ClassicalSegment | A segment of pure classical operations. |
ClassicalStep | A classical execution step. |
ControlFlowVisitor | Base class for visiting operations with control flow handling. |
DecodeQFixedOperation | Decode measured bits to float (classical operation). |
ExpvalOp | Expectation value operation. |
ExpvalSegment | A segment for expectation value computation. |
ExpvalStep | An expectation-value execution step. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
HybridBoundary | Represents a measurement or encode operation at quantum/classical boundary. |
MeasureQFixedOperation | Measure a quantum fixed-point number. |
MeasureVectorOperation | Measure a vector of qubits. |
MultipleQuantumSegmentsError | Raised when program has multiple quantum segments. |
NisqSegmentationStrategy | Single-quantum-segment planning strategy for current Qamomile runtimes. |
OperationKind | Classification of operations for classical/quantum separation. |
Pass | Base class for all compiler passes. |
ProgramABI | Runtime-visible ABI for a segmented program. |
ProgramPlan | Execution plan for a hybrid quantum/classical program. |
QuantumSegment | A segment of pure quantum operations. |
QuantumStep | A quantum execution step. |
QubitType | Type representing a quantum bit (qubit). |
ReturnOperation | Explicit return operation marking the end of a block with return values. |
RuntimeClassicalExpr | A classical expression known to require runtime evaluation. |
Segment | Base class for separated computation segments. |
SegmentationPass | Segment a block into a strategy-specific executable program plan. |
SegmentationStrategy | Execution-model-specific strategy for building a ProgramPlan. |
UIntType | Type representing an unsigned integer. |
ValidateWhileContractPass | Validates that all WhileOperation conditions are measurement-backed. |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Functions¶
build_dependency_graph [source]¶
def build_dependency_graph(operations: list[Operation]) -> dict[str, set[str]]Build a map from each value UUID to the UUIDs it depends on.
Walks operations recursively (through HasNestedOps) and records,
for each result UUID, the set of operand UUIDs that produced it. Also
seeds an edge from each ArrayValue element (Value carrying
parent_array) to its parent array UUID, and walks the parent’s
slice_of chain so that a sliced view (e.g. s[0:4:2][i] for
s = qmc.measure(register)) inherits taint from the root measured
array. StripSliceArrayOpsPass removes the explicit
SliceArrayOperation boundary before this pass runs, so the
slice_of link is the only remaining connection between a view and
its root in the IR. Used downstream by measurement-taint analysis.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
dict[str, set[str]] — dict[str, set[str]]: Mapping result_uuid -> set(operand_uuid, ...).
find_measurement_derived_values [source]¶
def find_measurement_derived_values(dependency_graph: dict[str, set[str]], measurement_uuids: set[str]) -> set[str]Forward-propagate measurement taint through the dependency graph.
Parameters:
| Name | Type | Description |
|---|---|---|
dependency_graph | dict[str, set[str]] | result_uuid -> set(operand_uuid, ...) as produced by build_dependency_graph, including the parent-array / slice-of edges that connect measured-vector elements to the root measured array. |
measurement_uuids | set[str] | Seed set (results of MeasureOperation / MeasureVectorOperation collected by find_measurement_results). |
Returns:
set[str] — set[str]: The set of all UUIDs transitively derived from a
measurement, including the seeds themselves.
find_measurement_results [source]¶
def find_measurement_results(operations: list[Operation]) -> set[str]Find all value UUIDs that are direct results of measurement ops.
Walks operations recursively (through HasNestedOps) and collects
every measurement result’s UUID, covering both scalar
MeasureOperation and vector MeasureVectorOperation. The
returned set is the seed for taint propagation; Vector[Bit]
element accesses inherit the parent array’s taint through the
parent-array edges added by build_dependency_graph.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Top-level operations of the block. |
Returns:
set[str] — set[str]: Result UUIDs of every measurement operation.
lower_measure_qfixed [source]¶
def lower_measure_qfixed(op: MeasureQFixedOperation) -> list[Operation]Lower MeasureQFixedOperation to MeasureVectorOperation + decode.
Returns:
list[Operation] — List of operations: [MeasureVectorOperation, DecodeQFixedOperation]
lower_operations [source]¶
def lower_operations(block: Block) -> BlockLower high-level operations like MeasureQFixedOperation.
MeasureQFixedOperation is lowered to:
MeasureVectorOperation for each qubit (HYBRID -> QUANTUM segment)
DecodeQFixedOperation to convert bits to float (CLASSICAL segment)
materialize_return [source]¶
def materialize_return(block: Block) -> BlockSynchronize output_values from ReturnOperation.
Uses ReturnOperation.operands as the source of truth for return values, ensuring consistency between the operation stream and block metadata.
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]BitType [source]¶
class BitType(ClassicalTypeMixin, ValueType)Type representing a classical bit.
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
ClassicalSegment [source]¶
class ClassicalSegment(Segment)A segment of pure classical operations.
Contains arithmetic, comparisons, and control flow. Will be executed directly in Python.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
kind: SegmentKind
ClassicalStep [source]¶
class ClassicalStepA classical execution step.
Constructor¶
def __init__(self, segment: ClassicalSegment, role: str = 'classical') -> NoneAttributes¶
role: strsegment: ClassicalSegment
ControlFlowVisitor [source]¶
class ControlFlowVisitor(ABC)Base class for visiting operations with control flow handling.
Subclasses override visit_operation to define per-operation behavior.
Control flow recursion is handled automatically by the base class.
Example:
class MeasurementCounter(ControlFlowVisitor):
def __init__(self):
self.count = 0
def visit_operation(self, op: Operation) -> None:
if isinstance(op, MeasureOperation):
self.count += 1Methods¶
visit_operation¶
def visit_operation(self, op: Operation) -> NoneProcess a single operation. Override in subclasses.
visit_operations¶
def visit_operations(self, operations: list[Operation]) -> NoneVisit all operations including nested control flow.
DecodeQFixedOperation [source]¶
class DecodeQFixedOperation(Operation)Decode measured bits to float (classical operation).
This operation converts a sequence of classical bits from qubit measurements into a floating-point number using fixed-point encoding.
The decoding formula:
float_value = Σ bit[i] * 2^(int_bits - 1 - i)
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Example:
bits = [1, 0, 1] with int_bits=0
→ 0.101 (binary) = 0.5 + 0.125 = 0.625operands: [ArrayValue of bits (vec[bit])] results: [Float value]
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
ExpvalOp [source]¶
class ExpvalOp(Operation)Expectation value operation.
This operation computes the expectation value <psi|H|psi> where psi is the quantum state and H is the Hamiltonian observable.
The operation bridges quantum and classical computation:
Input: quantum state (qubits) + Observable reference
Output: classical Float (expectation value)
Example IR:
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
hamiltonian: Value Alias for observable (deprecated, use observable instead).observable: Value The Observable parameter operand.operation_kind: OperationKind ExpvalOp is HYBRID - bridges quantum state to classical value.output: Value The expectation value result.qubits: Value The quantum register operand.signature: Signature
ExpvalSegment [source]¶
class ExpvalSegment(Segment)A segment for expectation value computation.
Represents computing <psi|H|psi> where psi is the quantum state and H is a Hamiltonian observable.
This segment bridges a quantum circuit (state preparation) to a classical expectation value.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
hamiltonian_value: Value | None = None,
qubits_value: Value | None = None,
result_ref: str = '',
) -> NoneAttributes¶
hamiltonian_value: Value | Nonekind: SegmentKindqubits_value: Value | Noneresult_ref: str
ExpvalStep [source]¶
class ExpvalStepAn expectation-value execution step.
Constructor¶
def __init__(self, segment: ExpvalSegment, quantum_step_index: int = 0) -> NoneAttributes¶
quantum_step_index: intsegment: ExpvalSegment
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
HybridBoundary [source]¶
class HybridBoundaryRepresents a measurement or encode operation at quantum/classical boundary.
These operations bridge quantum and classical segments.
Constructor¶
def __init__(
self,
operation: Operation,
source_segment_index: int,
target_segment_index: int,
value_ref: str,
) -> NoneAttributes¶
operation: Operationsource_segment_index: inttarget_segment_index: intvalue_ref: str
MeasureQFixedOperation [source]¶
class MeasureQFixedOperation(Operation)Measure a quantum fixed-point number.
This operation measures all qubits in a QFixed register and produces a Float result. During transpilation, this is lowered to individual MeasureOperations plus a DecodeQFixedOperation.
operands: [QFixed value (contains qubit_values in params)] results: [Float value]
Encoding:
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MultipleQuantumSegmentsError [source]¶
class MultipleQuantumSegmentsError(Exception)Raised when program has multiple quantum segments.
Qamomile enforces a single quantum circuit execution pattern:
[Classical Prep] → Quantum Circuit → [Classical Post/Expval]
Your program has multiple quantum segments, suggesting quantum operations that depend on measurement results (JIT compilation not supported).
NisqSegmentationStrategy [source]¶
class NisqSegmentationStrategy(SegmentationStrategy)Single-quantum-segment planning strategy for current Qamomile runtimes.
Methods¶
create_plan¶
def create_plan(
self,
segments: list[Segment],
block: Block,
boundaries: list[HybridBoundary],
) -> ProgramPlanOperationKind [source]¶
class OperationKind(enum.Enum)Classification of operations for classical/quantum separation.
This enum is used to categorize operations during compilation to determine which parts run on classical hardware vs quantum hardware.
Values:
QUANTUM: Pure quantum operations (gates, qubit allocation) CLASSICAL: Pure classical operations (arithmetic, comparisons) HYBRID: Operations that bridge classical and quantum (measurement, encode/decode) CONTROL: Control flow structures (for, while, if)
Attributes¶
CLASSICALCONTROLHYBRIDQUANTUM
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
ProgramABI [source]¶
class ProgramABIRuntime-visible ABI for a segmented program.
Constructor¶
def __init__(
self,
public_inputs: dict[str, Value] = dict(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
output_refs: list[str]public_inputs: dict[str, Value]
ProgramPlan [source]¶
class ProgramPlanExecution plan for a hybrid quantum/classical program.
Structure:
[Optional] Classical preprocessing (parameter computation, etc.)
Single quantum segment (REQUIRED)
[Optional] Expval segment OR classical postprocessing
This plan enforces Qamomile’s current execution model: all quantum operations must be in a single quantum circuit.
Constructor¶
def __init__(
self,
steps: list[ProgramStep] = list(),
abi: ProgramABI = ProgramABI(),
boundaries: list[HybridBoundary] = list(),
parameters: dict[str, Value] = dict(),
) -> NoneAttributes¶
abi: ProgramABIboundaries: list[HybridBoundary]parameters: dict[str, Value]steps: list[ProgramStep]
QuantumSegment [source]¶
class QuantumSegment(Segment)A segment of pure quantum operations.
Contains quantum gates and qubit allocations. Will be emitted to a quantum circuit.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
qubit_values: list[Value] = list(),
num_qubits: int = 0,
) -> NoneAttributes¶
kind: SegmentKindnum_qubits: intqubit_values: list[Value]
QuantumStep [source]¶
class QuantumStepA quantum execution step.
Constructor¶
def __init__(self, segment: QuantumSegment) -> NoneAttributes¶
segment: QuantumSegment
QubitType [source]¶
class QubitType(QuantumTypeMixin, ValueType)Type representing a quantum bit (qubit).
ReturnOperation [source]¶
class ReturnOperation(Operation)Explicit return operation marking the end of a block with return values.
This operation represents an explicit return statement in the IR. It takes the values to be returned as operands and produces no results (it is a terminal operation that transfers control flow back to the caller).
operands: [Value, ...] - The values to return (may be empty for void returns) results: [] - Always empty (terminal operation)
Example:
A function that returns two values (a UInt and a Float):
ReturnOperation(
operands=[uint_value, float_value],
results=[],
)
The signature would be:
operands=[ParamHint("return_0", UIntType()), ParamHint("return_1", FloatType())]
results=[]Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKind Return CLASSICAL as this is a control flow operation without quantum effects.signature: Signature Return the signature with operands for each return value and no results.
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:
Binary kinds (EQ/NEQ/LT/LE/GT/GE/AND/OR/ADD/SUB/MUL/DIV/FLOORDIV/MOD/POW):
operands = [lhs, rhs].Unary kind (NOT):
operands = [val].Result:
results = [output_value].
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,
) -> NoneAttributes¶
kind: RuntimeOpKind | Noneoperation_kind: OperationKindsignature: Signature
Segment [source]¶
class Segment(ABC)Base class for separated computation segments.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
input_refs: list[str]kind: SegmentKind Return the kind of this segment.operations: list[Operation]output_refs: list[str]
SegmentationPass [source]¶
class SegmentationPass(Pass[Block, ProgramPlan])Segment a block into a strategy-specific executable program plan.
This pass:
Materializes return operations (syncs output_values from ReturnOperation)
Splits the operation list into quantum and classical segments
Builds a ProgramPlan via the configured segmentation strategy
Input: Block (typically ANALYZED or AFFINE) Output: ProgramPlan
Constructor¶
def __init__(self, strategy: SegmentationStrategy | None = None) -> NoneAttributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> ProgramPlanSegment the block into a ProgramPlan.
SegmentationStrategy [source]¶
class SegmentationStrategy(ABC)Execution-model-specific strategy for building a ProgramPlan.
Methods¶
create_plan¶
def create_plan(
self,
segments: list[Segment],
block: Block,
boundaries: list[HybridBoundary],
) -> ProgramPlanBuild a ProgramPlan from segmented operations.
UIntType [source]¶
class UIntType(ClassicalTypeMixin, ValueType)Type representing an unsigned integer.
ValidateWhileContractPass [source]¶
class ValidateWhileContractPass(Pass[Block, Block])Validates that all WhileOperation conditions are measurement-backed.
Builds a producer map (result UUID → producing Operation instance) and checks every WhileOperation operand against it. A valid condition must be:
A
ValuewithBitTypeMeasurement-backed: produced by
MeasureOperationdirectly, or byIfOperation/PhiOpwhere every reachable leaf source is itself measurement-backed.
Both operands[0] (initial condition) and operands[1]
(loop-carried condition) are validated.
Raises ValidationError for any non-measurement while pattern.
Attributes¶
name: str
Methods¶
run¶
def run(self, block: Block) -> BlockValidate all WhileOperations and return block unchanged.
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.slice_borrow_check¶
Post-fold block-wide slice-view borrow check.
Mirrors the slice-view subset of the frontend’s
ArrayBase._borrowed_indices borrow-tracker semantics on the IR
after :class:ConstantFoldingPass has resolved slice bounds to
concrete values. The pass exists to catch bugs the trace-time
checker cannot see on its own — slices whose bounds were UInt
at trace time so their covered slot set was not enumerable until
bindings were applied:
Aliasing between a (now-concrete) slice view and another live view of the same root parent (raised as :class:
SliceBorrowViolationErrorfrom :meth:_register_slice_bulk_borrow_if_new).A view whose newly-concrete coverage hits a slot that was consumed by a destructive view operation earlier in the block (raised as :class:
SliceBorrowViolationErrorfrom :meth:_process_operand_borrows).
Slice views are otherwise treated as affine at the kernel
boundary: a view that goes out of scope without being slice-
assigned back to the parent is no longer flagged here. This
mirrors how element borrows on locally-allocated registers behave
— natural ancilla / scratch-register patterns such as
Deutsch-Jozsa’s ancilla = qs[n] and Simon’s
qs2 = qs[n:2*n] (used by the oracle, then discarded
unmeasured) compile cleanly. The genuine hazards stay covered:
measure(parent)(or any otherparent.consume()site) while a view is live raisesUnreturnedBorrowErrorfrom the frontend’sArrayBase.consume/validate_all_returned.Returning the parent with an outstanding borrow raises
UnreturnedBorrowErrorfromfunc_to_block._validate_returned_arrays.Direct
q[i]access on a slot a view currently owns is caught at the frontend’s element-access path / this pass’s :meth:_process_operand_borrowsfor symbolic-bound views.Overlapping live views and use-after-destroy are caught at registration time (see the two error sites above).
Direct element borrows (q[i]) are intentionally not observed
here. Element access emits no IR operation, so the IR layer has
nothing to track; the frontend trace-time validator
(func_to_block._validate_returned_arrays and
ArrayBase.validate_all_returned) is the source of truth for
direct-element-borrow violations.
State shape: a single dict keyed by a 2-tuple
(root_logical_id, slot_descriptor) where
root_logical_id is the logical_id of the root parent
ArrayValue (after walking the slice_of chain) and
slot_descriptor is f"const:<idx>" for slots covered by
compile-time-constant slices. Symbolic-bound slices (those whose
bounds remain non-constant post-fold) are not enumerated into
per-qubit slots; the pass records only an exact "sym:<descriptor>"
entry so a later SSA-version refresh of the same symbolic slice
descriptor can update the owner without claiming any new concrete
range.
Namespacing by root logical_id is required so that borrow /
consumed state on one register (a) does not block access to
the identically-named slot on another register (b); without
it, measure(a[1::2]) would incorrectly mark b[1] and
b[3] as destroyed.
Values are either an :class:ArrayValue (the slice view that owns
the slot) or a _ConsumedSlotMarker (a slot already destroyed by
a prior destructive view consume). isinstance on the value
dispatches the two violation messages.
Overview¶
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
BinOpKind | |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CastOperation | Type cast operation for creating aliases over the same quantum resources. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
ExpvalOp | Expectation value operation. |
ForOperation | Represents a for loop operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
MeasureOperation | |
MeasureVectorOperation | Measure a vector of qubits. |
Pass | Base class for all compiler passes. |
SliceBorrowCheckPass | Post-fold linearity checker for sliced views and borrow state. |
SliceBorrowViolationError | Aliasing detected between a slice view and a direct parent access. |
UIntType | Type representing an unsigned integer. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
Constants¶
BoundToken:TypeAlias=ConstBoundToken | ValueBoundToken | MinBoundTokenConstBoundToken:TypeAlias=tuple[Literal['const'], int]MinBoundToken:TypeAlias=tuple[Literal['min'], object, object]Owner=ArrayValue | _ConsumedSlotMarkerBorrow-state owner discriminant.ValueBoundToken:TypeAlias=tuple[Literal['value'], str, int]
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
BinOpKind [source]¶
class BinOpKind(enum.Enum)Attributes¶
ADDDIVFLOORDIVMINMODMULPOWSUB
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CastOperation [source]¶
class CastOperation(Operation)Type cast operation for creating aliases over the same quantum resources.
This operation does NOT allocate new qubits. It creates a new Value that references the same underlying quantum resources with a different type.
Use cases:
Vector[Qubit] -> QFixed (after QPE, for phase measurement)
Vector[Qubit] -> QUInt (for quantum arithmetic)
QUInt -> QFixed (reinterpret bits with different encoding)
QFixed -> QUInt (reinterpret bits with different encoding)
operands: [source_value] - The value being cast results: [cast_result] - The new value with target type (same physical qubits)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
source_type: ValueType | None = None,
target_type: ValueType | None = None,
qubit_mapping: list[str] = list(),
) -> NoneAttributes¶
num_qubits: int Number of qubits involved in the cast.operation_kind: OperationKind Cast stays in the same segment as its source (QUANTUM for quantum types).qubit_mapping: list[str]signature: Signature Return the type signature of this cast operation.source_type: ValueType | Nonetarget_type: ValueType | None
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
ExpvalOp [source]¶
class ExpvalOp(Operation)Expectation value operation.
This operation computes the expectation value <psi|H|psi> where psi is the quantum state and H is the Hamiltonian observable.
The operation bridges quantum and classical computation:
Input: quantum state (qubits) + Observable reference
Output: classical Float (expectation value)
Example IR:
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
hamiltonian: Value Alias for observable (deprecated, use observable instead).observable: Value The Observable parameter operand.operation_kind: OperationKind ExpvalOp is HYBRID - bridges quantum state to classical value.output: Value The expectation value result.qubits: Value The quantum register operand.signature: Signature
ForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationHasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationMeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
SliceBorrowCheckPass [source]¶
class SliceBorrowCheckPass(Pass[Block, Block])Post-fold linearity checker for sliced views and borrow state.
Runs after :class:ConstantFoldingPass (so slice bounds are
concrete where possible) and before segmentation / emit. Walks
the operations of the root block in order, maintaining a borrow
state map modelled on the frontend’s
:attr:ArrayBase._borrowed_indices — a single dict whose
values are slice-view ArrayValue owners or the
_ConsumedSlotMarker sentinel. Direct element borrows
(q[i]) emit no IR operation and are left to the trace-time
validator.
The pass does not flag a leftover slice view at block end —
slice views are affine at the kernel boundary, mirroring how
element borrows behave on a locally-allocated register (the
frontend’s _validate_returned_arrays covers the genuine
leak: returning the parent with a live borrow). Anything that
actually clashes with a live view (direct slot access,
destructive parent consume, overlapping views, use-after-
destroy) is rejected at the eager check points listed in the
module docstring.
Constructor¶
def __init__(self) -> NoneInitialize per-run mutable state to safe defaults.
Attributes¶
name: str Return the pass identifier for tracing/logging.
Methods¶
run¶
def run(self, input: Block) -> BlockRun the borrow tracker over input.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block to check. Expected to be in AFFINE or HIERARCHICAL kind — post-fold but pre-segmentation. |
Returns:
Block — The same Block unchanged (pass-through).
Raises:
ValidationError— If called on an unexpected block kind.SliceBorrowViolationError— If a slice view and a direct access collide, two views overlap, or a use-after- destroy is observed.
SliceBorrowViolationError [source]¶
class SliceBorrowViolationError(AffineTypeError)Aliasing detected between a slice view and a direct parent access.
Raised by :class:SliceBorrowCheckPass at transpile time when
a parent array slot is simultaneously held by a VectorView and
accessed directly, or when two overlapping views cover the same
slot. For slices with constant bounds this is normally caught at
trace time; this error covers the post-fold case when slice bounds
were symbolic UInt parameters resolved by bindings.
Example of incorrect code (detected only after bindings resolve
lo/hi to concrete values)::
region = q[lo:hi] # bindings give lo=0, hi=4 → covers {0,1,2,3}
qa = region[0] # borrows parent slot 0 via the view
qb = q[0] # borrows parent slot 0 directly
# SliceBorrowViolationError: slot 0 is held by a slice viewUIntType [source]¶
class UIntType(ClassicalTypeMixin, ValueType)Type representing an unsigned integer.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | Noneqamomile.circuit.transpiler.passes.standard_emit¶
Standard emit pass using GateEmitter protocol.
This module provides StandardEmitPass, a reusable emit pass implementation that uses the GateEmitter protocol for backend-specific gate emission.
The actual emission logic is decomposed into focused modules under
emit_support/. This class serves as the orchestrator with thin
wrappers that delegate to those module functions while preserving
subclass override points (used by QiskitEmitPass, CudaqEmitPass).
Overview¶
| Function | Description |
|---|---|
blockvalue_to_gate | Convert a Block to a backend gate. |
emit_composite_gate | Emit a composite gate operation. |
emit_controlled_fallback | Fallback emission for controlled-U when gate conversion fails. |
emit_controlled_u | Emit a ControlledUOperation. |
emit_for | Emit a for loop. |
emit_for_items | Emit for-items loop (always unrolled). |
emit_gate | Emit a single gate operation. |
emit_if | Emit if/else operation. |
emit_inverse_block | Emit a first-class inverse block operation. |
emit_measure | Emit a single measurement. |
emit_measure_qfixed | Emit QFixed measurement. |
emit_measure_vector | Emit vector measurement. |
emit_pauli_evolve | Emit Pauli evolution: exp(-i * gamma * H). |
emit_while | Emit while loop operation. |
evaluate_binop | Evaluate a BinOp and store the result in bindings. |
evaluate_classical_predicate | Evaluate a CompOp/CondOp/NotOp at emit time and bind its boolean result. |
handle_cast | Handle CastOperation - update qubit_map without emitting gates. |
| Class | Description |
|---|---|
BinOp | Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN). |
CastOperation | Type cast operation for creating aliases over the same quantum resources. |
CompOp | Comparison operation (EQ, NEQ, LT, LE, GT, GE). |
CompositeGateEmitter | Protocol for backend-specific CompositeGate emitters. |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
CondOp | Conditional logical operation (AND, OR). |
ControlledUOperation | Base class for controlled-U operations. |
EmitPass | Base class for backend-specific emission passes. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
GateEmitter | Protocol for backend-specific gate emission. |
GateOperation | Quantum gate operation. |
GateOperationType | |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
InverseBlockOperation | Represent an inverse qkernel/block as a first-class IR operation. |
MeasureOperation | |
MeasureQFixedOperation | Measure a quantum fixed-point number. |
MeasureVectorOperation | Measure a vector of qubits. |
NotOp | |
PauliEvolveOp | Pauli evolution operation: exp(-i * gamma * H). |
QInitOperation | Initialize the qubit |
RuntimeClassicalExpr | A classical expression known to require runtime evaluation. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
WhileOperation | Represents a while loop operation. |
Functions¶
blockvalue_to_gate [source]¶
def blockvalue_to_gate(
emit_pass: 'StandardEmitPass',
block_value: Any,
num_qubits: int,
bindings: dict[str, Any],
input_operands: list[Any] | None = None,
operation_name: str = 'ControlledUOperation',
) -> AnyConvert a Block to a backend gate.
Pre-populates local_qubit_map with one entry per quantum input in
declaration order, then runs the allocator over the block’s body.
For Vector[Qubit] inputs (ArrayValue with a quantum element
type) the entry expands into per-element QubitAddress(uuid, i)
keys — the inner block has no QInitOperation for inputs, so
without these the allocator’s element-resolution assertion fires for
every qs[i] reference in the body.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | The emit pass driving the conversion. Used for its _allocator, _emitter, _resolver, and _emit_operations. |
block_value | Any | The inner block to convert. Expected to expose operations and input_values; anything else returns None (the caller falls back to gate-by-gate decomposition). |
num_qubits | int | Total physical qubits the resulting gate will occupy in the parent circuit. Used as the fallback length for a single Vector[Qubit] input whose shape is symbolic and unresolvable from bindings, and as the sub-circuit width when the block has no qubit-producing operations. |
bindings | dict[str, Any] | Parameter bindings forwarded to the allocator and _emit_operations. Also consulted when resolving Vector[Qubit] input shapes. |
input_operands | list[Any] | None | Optional call-site operands corresponding to block_value.input_values. Quantum operands propagate actual Vector[Qubit] shapes into the nested block before the vector-aware input qubit map is populated; classical operands are resolved into local bindings before the nested block is emitted. Defaults to None. |
operation_name | str | Operation name used in diagnostics when input binding fails. Defaults to "ControlledUOperation". |
Returns:
Any — A backend gate object produced by
emit_pass._emitter.circuit_to_gate, or None when the
conversion is unable to proceed (missing operations,
allocator / emitter exception, etc.) so the caller can fall
back to gate-by-gate emission.
emit_composite_gate [source]¶
def emit_composite_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: CompositeGateOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a composite gate operation.
Resolves each qubit operand through resolve_qubit_index_detailed
so that view-local operands (qft(q[1::2])) walk the slice_of
chain and map to the root parent’s physical qubits. Raises
EmitError if any operand cannot be resolved, rather than
silently dropping it (previously qft(view) emitted zero gates).
Raises:
EmitError— If any control or target qubit operand fails to resolve to a physical qubit index.
emit_controlled_fallback [source]¶
def emit_controlled_fallback(
emit_pass: 'StandardEmitPass',
circuit: Any,
block_value: Any,
num_controls: int,
control_indices: list[int],
target_indices: list[int],
power: int,
bindings: dict[str, Any],
) -> NoneFallback emission for controlled-U when gate conversion fails.
Decomposes the block body gate-by-gate under the full control set.
A block-local qubit map ties the block’s formal quantum inputs to
target_indices, so every inner gate is emitted on the physical
qubit its operand resolves to — multi-target inner blocks are
supported. Nested ControlledUOperations compose their controls
with the outer ones; irreducible multi-controlled single-qubit
gates route through the backend’s
_emit_irreducible_multi_controlled_gate hook. Subclasses may
still override this method to emit controlled blocks natively
(e.g. CUDA-Q’s cudaq.control helper kernels).
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The StandardEmitPass instance. |
circuit | Any | The backend circuit being built. |
block_value | Any | The block value containing operations to control. |
num_controls | int | Number of control qubits. |
control_indices | list[int] | Physical indices of control qubits. |
target_indices | list[int] | Physical indices of target qubits. |
power | int | Number of times to repeat the controlled operation. |
bindings | dict[str, Any] | Parameter bindings. |
Raises:
EmitError— Ifnum_controlsdisagrees withcontrol_indices, the block’s quantum inputs cannot be mapped ontotarget_indices, or an inner operation cannot be lowered under the accumulated controls (e.g. an irreducible multi-controlled gate on a backend without the multi-control hook).
emit_controlled_u [source]¶
def emit_controlled_u(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ControlledUOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a ControlledUOperation.
emit_for [source]¶
def emit_for(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ForOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
force_unroll: bool = False,
) -> NoneEmit a for loop.
emit_for_items [source]¶
def emit_for_items(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: ForItemsOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit for-items loop (always unrolled).
This handles iteration over Dict items, e.g.: for (i, j), Jij in qmc.items(ising): ...
emit_gate [source]¶
def emit_gate(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: GateOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a single gate operation.
emit_if [source]¶
def emit_if(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: IfOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit if/else operation.
Handles two condition types:
Compile-time constant (plain Python
int/boolfrom@qkernelAST transformer closure variables, constant-folded Values, or Values resolvable viabindings): the active branch is emitted unconditionally, the inactive branch is discarded. No backendc_if/if_testis needed.Runtime condition (measurement
Valuethat cannot be resolved at compile time): delegates to the backend’semit_if_start/emit_else_start/emit_if_endprotocol.
emit_inverse_block [source]¶
def emit_inverse_block(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: InverseBlockOperation,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit a first-class inverse block operation.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | StandardEmitPass | Active emit pass. |
circuit | Any | Backend circuit being emitted into. |
op | InverseBlockOperation | Inverse block operation to emit. |
qubit_map | QubitMap | Current quantum value to physical qubit map. |
bindings | dict[str, Any] | Active emit bindings. |
Raises:
EmitError— If an inverse block has missing blocks, unresolved qubit operands, or no available native/fallback emission path.
emit_measure [source]¶
def emit_measure(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any] | None = None,
) -> NoneEmit a single measurement.
Resolves the qubit operand using the full resolver (handles both scalar qubits and array element qubits with composite keys).
Raises:
warnings.warn— If the qubit or clbit cannot be resolved, a warning is emitted instead of silently dropping the measurement.
emit_measure_qfixed [source]¶
def emit_measure_qfixed(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureQFixedOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
) -> NoneEmit QFixed measurement.
emit_measure_vector [source]¶
def emit_measure_vector(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: MeasureVectorOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit vector measurement.
Resolves the qubit operand’s slice_of chain so that measuring a
view (measure(q[1::2])) correctly targets the root parent’s
physical qubits.
Behaviour for unresolvable inputs differs by case:
Unknown vector length (
_resolve_sizereturnsNone) — the function defers silently. This handles transpile-only paths (e.g. unbound parameter-size arrays) where downstream late- binding callers still handle the emit correctly.Resolvable length but a sliced view that resolves to zero physical qubits — raises
EmitError. Previously this produced executions returning[(None, N)], a data-integrity hazard, so the silent path is intentionally narrowed to view-on-empty cases only.Resolvable length but slice bounds are themselves symbolic — raises
EmitErrorfromresolve_slice_chain.
Raises:
EmitError— When a sliced view resolves to zero physical qubits, or when slice bounds remain symbolic at emit time.
emit_pauli_evolve [source]¶
def emit_pauli_evolve(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: PauliEvolveOp,
qubit_map: QubitMap,
bindings: dict[str, Any],
) -> NoneEmit Pauli evolution: exp(-i * gamma * H).
Resolves the Hamiltonian from bindings and decomposes each term using the Pauli gadget technique:
Basis change per qubit (X->H, Y->Sdg*H, Z->identity)
CNOT ladder + RZ
Undo basis change
Subclasses can override this for backend-native implementations (e.g., Qiskit PauliEvolutionGate).
emit_while [source]¶
def emit_while(
emit_pass: 'StandardEmitPass',
circuit: Any,
op: WhileOperation,
qubit_map: QubitMap,
clbit_map: ClbitMap,
bindings: dict[str, Any],
) -> NoneEmit while loop operation.
evaluate_binop [source]¶
def evaluate_binop(emit_pass: 'StandardEmitPass', op: BinOp, bindings: dict[str, Any]) -> NoneEvaluate a BinOp and store the result in bindings.
Tries the shared fold_classical_op first for a clean concrete
fold (which already encapsulates the runtime-parameter guard).
Falls back to creating backend Parameter symbols and doing
symbolic arithmetic when one or both operands are runtime
parameters — that’s the path that lets rx(q, gamma * 2) produce
a circuit with a single Parameter("gamma") * 2 expression rather
than baking in a placeholder.
evaluate_classical_predicate [source]¶
def evaluate_classical_predicate(
emit_pass: 'StandardEmitPass',
op: 'CompOp | CondOp | NotOp',
bindings: dict[str, Any],
) -> NoneEvaluate a CompOp/CondOp/NotOp at emit time and bind its boolean result.
Mirrors the predicate evaluation already done by
compile_time_if_lowering and classical_executor so that an
IfOperation whose condition reaches emit unfolded — typically
because its operands depend on a loop variable bound only at emit time
by emit_for_items / emit_for_unrolled — can still be resolved
via resolve_if_condition.
Delegates the actual fold (including runtime-parameter guard and
strict scalar typing) to fold_classical_op so that all three
callers of the same kind dispatch share one implementation. There
is no symbolic-Parameter fallback for predicates: a runtime classical
expression cannot be expressed as a folded scalar, so the op is left
unbound and downstream emit handles it as a runtime condition.
Parameters:
| Name | Type | Description |
|---|---|---|
emit_pass | 'StandardEmitPass' | The active emit pass (for resolver access). |
op | 'CompOp | CondOp | NotOp' | The predicate op to evaluate. |
bindings | dict[str, Any] | Current parameter/loop-variable bindings; mutated in place on successful evaluation. No-op when operands are unresolvable (e.g. measurement bits) or evaluation raises. |
Returns:
None — None.
handle_cast [source]¶
def handle_cast(emit_pass: 'StandardEmitPass', op: CastOperation, qubit_map: QubitMap) -> NoneHandle CastOperation - update qubit_map without emitting gates.
Classes¶
BinOp [source]¶
class BinOp(BinaryOperationBase)Binary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
kind: BinOpKind | None = None,
) -> NoneAttributes¶
kind: BinOpKind | Noneoperation_kind: OperationKindsignature: Signature
CastOperation [source]¶
class CastOperation(Operation)Type cast operation for creating aliases over the same quantum resources.
This operation does NOT allocate new qubits. It creates a new Value that references the same underlying quantum resources with a different type.
Use cases:
Vector[Qubit] -> QFixed (after QPE, for phase measurement)
Vector[Qubit] -> QUInt (for quantum arithmetic)
QUInt -> QFixed (reinterpret bits with different encoding)
QFixed -> QUInt (reinterpret bits with different encoding)
operands: [source_value] - The value being cast results: [cast_result] - The new value with target type (same physical qubits)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
source_type: ValueType | None = None,
target_type: ValueType | None = None,
qubit_mapping: list[str] = list(),
) -> NoneAttributes¶
num_qubits: int Number of qubits involved in the cast.operation_kind: OperationKind Cast stays in the same segment as its source (QUANTUM for quantum types).qubit_mapping: list[str]signature: Signature Return the type signature of this cast operation.source_type: ValueType | Nonetarget_type: ValueType | None
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,
) -> NoneAttributes¶
kind: CompOpKind | Noneoperation_kind: OperationKindsignature: Signature
CompositeGateEmitter [source]¶
class CompositeGateEmitter(Protocol[C])Protocol for backend-specific CompositeGate emitters.
Each backend can implement emitters for specific composite gate types (QPE, QFT, IQFT, etc.) using native backend libraries.
The emitter pattern allows:
Backends to use native implementations when available (e.g., Qiskit QFT)
Fallback to manual decomposition when native is unavailable
Easy addition of new backends without modifying core code
Example:
class QiskitQFTEmitter:
def can_emit(self, gate_type: CompositeGateType) -> bool:
return gate_type in (CompositeGateType.QFT, CompositeGateType.IQFT)
def emit(self, circuit, op, qubit_indices, bindings) -> bool:
from qiskit.circuit.library import QFTGate
qft_gate = QFTGate(len(qubit_indices))
circuit.append(qft_gate, qubit_indices)
return TrueMethods¶
can_emit¶
def can_emit(self, gate_type: CompositeGateType) -> boolCheck if this emitter can handle the given gate type.
Parameters:
| Name | Type | Description |
|---|---|---|
gate_type | CompositeGateType | The CompositeGateType to check |
Returns:
bool — True if this emitter supports native emission for the gate type
emit¶
def emit(
self,
circuit: C,
op: CompositeGateOperation,
qubit_indices: list[int],
bindings: dict[str, Any],
) -> boolEmit the composite gate to the circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | C | The backend-specific circuit to emit to |
op | CompositeGateOperation | The CompositeGateOperation to emit |
qubit_indices | list[int] | Physical qubit indices for the operation |
bindings | dict[str, Any] | Parameter bindings for the operation |
Returns:
bool — True if emission succeeded, False to fall back to manual decomposition
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
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,
) -> NoneAttributes¶
kind: CondOpKind | Noneoperation_kind: OperationKindsignature: Signature
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Base class for controlled-U operations.
Two concrete subclasses handle distinct operand layouts:
ConcreteControlledU: Fixednum_controls: int, individual qubit operands.SymbolicControlledU: Symbolicnum_controls: Value, vector-based control operands; optionalcontrol_indicesselects a subset of the control vector to act as controls (the rest pass through).
All isinstance(op, ControlledUOperation) checks match every subclass.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
power: int | Value = 1,
block: Block | None = None,
num_controls: int | Value = 1,
) -> NoneAttributes¶
block: Block | Nonecontrol_operands: list[Value] Get the control qubit values.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete.num_controls: int | Valueoperation_kind: OperationKindparam_operands: list[Value] Get parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_operands: list[Value] Get the target qubit values (arguments to U).
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]replace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationEmitPass [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:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Values to bind parameters to. If not provided, parameters must be bound at execution time. |
parameters | list[str] | None | List of parameter names to preserve as backend parameters. |
Attributes¶
bindingsname: strparameters
Methods¶
run¶
def run(self, input: ProgramPlan) -> ExecutableProgram[T]Emit backend code from a program plan.
ForItemsOperation [source]¶
class ForItemsOperation(HasNestedOps, Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
key_vars: list[str] = list(),
value_var: str = '',
key_is_vector: bool = False,
key_var_values: tuple[Value, ...] | None = None,
value_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
key_is_vector: boolkey_var_values: tuple[Value, ...] | Nonekey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: strvalue_var_value: Value | None
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]Include the per-key/value Value fields for cloning/substitution.
Same rationale as ForOperation.all_input_values: keep the IR
identity fields in lockstep with body references so UUID-keyed
lookups stay valid after inline cloning.
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationGateEmitter [source]¶
class GateEmitter(Protocol[T])Protocol for backend-specific gate emission.
Each backend implements this protocol to emit individual gates to their circuit representation.
Type parameter T is the backend’s circuit type (e.g., QuantumCircuit).
Attributes¶
measurement_mode: MeasurementMode Return the measurement mode for this backend.
Methods¶
append_gate¶
def append_gate(self, circuit: T, gate: Any, qubits: list[int]) -> NoneAppend a gate to the circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to append to |
gate | Any | The gate to append (from circuit_to_gate) |
qubits | list[int] | Target qubit indices |
circuit_to_gate¶
def circuit_to_gate(self, circuit: T, name: str = 'U') -> AnyConvert a circuit to a reusable gate.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to convert |
name | str | Label for the gate |
Returns:
Any — Backend-specific gate object, or None if not supported
create_circuit¶
def create_circuit(self, num_qubits: int, num_clbits: int) -> TCreate a new empty circuit.
Parameters:
| Name | Type | Description |
|---|---|---|
num_qubits | int | Number of qubits in the circuit |
num_clbits | int | Number of classical bits in the circuit |
Returns:
T — A new backend-specific circuit object
create_parameter¶
def create_parameter(self, name: str) -> AnyCreate a symbolic parameter for the backend.
Parameters:
| Name | Type | Description |
|---|---|---|
name | str | Parameter name (e.g., “gammas[0]”) |
Returns:
Any — Backend-specific parameter object
emit_barrier¶
def emit_barrier(self, circuit: T, qubits: list[int]) -> NoneEmit barrier on specified qubits.
emit_ch¶
def emit_ch(self, circuit: T, control: int, target: int) -> NoneEmit controlled-Hadamard gate.
emit_cp¶
def emit_cp(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-Phase gate.
emit_crx¶
def emit_crx(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RX gate.
emit_cry¶
def emit_cry(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RY gate.
emit_crz¶
def emit_crz(self, circuit: T, control: int, target: int, angle: float | Any) -> NoneEmit controlled-RZ gate.
emit_cx¶
def emit_cx(self, circuit: T, control: int, target: int) -> NoneEmit CNOT gate.
emit_cy¶
def emit_cy(self, circuit: T, control: int, target: int) -> NoneEmit controlled-Y gate.
emit_cz¶
def emit_cz(self, circuit: T, control: int, target: int) -> NoneEmit CZ gate.
emit_else_start¶
def emit_else_start(self, circuit: T, context: Any) -> NoneStart the else branch.
emit_for_loop_end¶
def emit_for_loop_end(self, circuit: T, context: Any) -> NoneEnd a native for loop context.
emit_for_loop_start¶
def emit_for_loop_start(self, circuit: T, indexset: range) -> AnyStart a native for loop context.
Returns a context manager or loop parameter, depending on backend.
emit_h¶
def emit_h(self, circuit: T, qubit: int) -> NoneEmit Hadamard gate.
emit_if_end¶
def emit_if_end(self, circuit: T, context: Any) -> NoneEnd the if/else block.
emit_if_start¶
def emit_if_start(self, circuit: T, clbit: int, value: int = 1) -> AnyStart a native if context.
Returns context for the if/else block.
emit_measure¶
def emit_measure(self, circuit: T, qubit: int, clbit: int) -> NoneEmit measurement operation.
emit_p¶
def emit_p(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit Phase gate (P(θ) = diag(1, e^(iθ))).
emit_rx¶
def emit_rx(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RX rotation gate.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The circuit to emit to |
qubit | int | Target qubit index |
angle | float | Any | Rotation angle (float or backend parameter) |
emit_ry¶
def emit_ry(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RY rotation gate.
emit_rz¶
def emit_rz(self, circuit: T, qubit: int, angle: float | Any) -> NoneEmit RZ rotation gate.
emit_rzz¶
def emit_rzz(self, circuit: T, qubit1: int, qubit2: int, angle: float | Any) -> NoneEmit RZZ gate (exp(-i * θ/2 * Z⊗Z)).
emit_s¶
def emit_s(self, circuit: T, qubit: int) -> NoneEmit S gate (√Z).
emit_sdg¶
def emit_sdg(self, circuit: T, qubit: int) -> NoneEmit S-dagger gate (inverse of S).
emit_swap¶
def emit_swap(self, circuit: T, qubit1: int, qubit2: int) -> NoneEmit SWAP gate.
emit_t¶
def emit_t(self, circuit: T, qubit: int) -> NoneEmit T gate (√S).
emit_tdg¶
def emit_tdg(self, circuit: T, qubit: int) -> NoneEmit T-dagger gate (inverse of T).
emit_toffoli¶
def emit_toffoli(self, circuit: T, control1: int, control2: int, target: int) -> NoneEmit Toffoli (CCX) gate.
emit_while_end¶
def emit_while_end(self, circuit: T, context: Any) -> NoneEnd the while loop context.
emit_while_start¶
def emit_while_start(self, circuit: T, clbit: int, value: int = 1) -> AnyStart a native while loop context.
emit_x¶
def emit_x(self, circuit: T, qubit: int) -> NoneEmit Pauli-X gate.
emit_y¶
def emit_y(self, circuit: T, qubit: int) -> NoneEmit Pauli-Y gate.
emit_z¶
def emit_z(self, circuit: T, qubit: int) -> NoneEmit Pauli-Z gate.
gate_controlled¶
def gate_controlled(self, gate: Any, num_controls: int) -> AnyCreate controlled version of a gate.
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | The gate to control |
num_controls | int | Number of control qubits |
Returns:
Any — New controlled gate
gate_inverse¶
def gate_inverse(self, gate: Any) -> AnyCreate a backend-native inverse gate when supported.
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | Backend-specific gate object returned by circuit_to_gate. |
Returns:
Any — Backend-specific inverse gate object, or None when the
Any — backend cannot invert reusable gates natively.
gate_power¶
def gate_power(self, gate: Any, power: int) -> AnyCreate gate raised to a power (U^n).
Parameters:
| Name | Type | Description |
|---|---|---|
gate | Any | The gate to raise to a power |
power | int | The power to raise to |
Returns:
Any — New gate representing gate^power
supports_for_loop¶
def supports_for_loop(self) -> boolCheck if backend supports native for loops.
supports_gate_inverse¶
def supports_gate_inverse(self) -> boolReturn whether reusable gates can be inverted natively.
Returns:
bool — True when gate_inverse can return a backend-native
inverse for gates produced by circuit_to_gate. Defaults
to False.
supports_if_else¶
def supports_if_else(self) -> boolCheck if backend supports native if/else.
supports_reusable_gates¶
def supports_reusable_gates(self) -> boolReturn whether circuit_to_gate can produce reusable gates.
Returns:
bool — True when the backend can convert emitted sub-circuits to
reusable gate objects. Defaults to False so emit paths can
avoid building throwaway sub-circuits for backends that only
support inline fallback emission.
supports_while_loop¶
def supports_while_loop(self) -> boolCheck if backend supports native while loops.
GateOperation [source]¶
class GateOperation(Operation)Quantum gate operation.
For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is
stored as the last element of operands. Use the theta
property for typed read access and the rotation / fixed factory
class-methods for type-safe construction.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: GateOperationType | None = None,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindqubit_operands: list[Value] Qubit operands (excluding the theta parameter if present).signature: Signaturetheta: Value | None Angle parameter for rotation gates, orNonefor fixed gates.
Methods¶
fixed¶
@classmethod
def fixed(
cls,
gate_type: GateOperationType,
qubits: list[Value],
results: list[Value],
) -> 'GateOperation'Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.
rotation¶
@classmethod
def rotation(
cls,
gate_type: GateOperationType,
qubits: list[Value],
theta: Value,
results: list[Value],
) -> 'GateOperation'Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.
GateOperationType [source]¶
class GateOperationType(enum.Enum)Attributes¶
CPCXCZHPRXRYRZRZZSSDGSWAPTTDGTOFFOLIXYZ
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationInverseBlockOperation [source]¶
class InverseBlockOperation(Operation)Represent an inverse qkernel/block as a first-class IR operation.
The operation stores both the original forward block and a Qamomile-built
inverse implementation block. Emitters may use source_block with a
backend-native inverse/adjoint primitive, then fall back to
implementation_block when native inversion is unavailable.
Operands are ordered as control qubits, target quantum operands, then
classical/object parameters. Results mirror the quantum operand layout:
control results first, then one target result per target operand. Vector
target operands therefore count as one operand/result while contributing
their scalar width to num_target_qubits.
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
source_block: Block | None = None,
implementation_block: Block | None = None,
) -> NoneAttributes¶
control_qubits: list[‘Value’] Return control quantum operands.custom_name: strimplementation_block: Block | Nonename: str Return a human-readable inverse operation name.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind.parameters: list[‘Value’] Return classical/object parameter operands.signature: Signature Return the operation signature.source_block: Block | Nonetarget_qubits: list[‘Value’] Return target quantum operands.
MeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureQFixedOperation [source]¶
class MeasureQFixedOperation(Operation)Measure a quantum fixed-point number.
This operation measures all qubits in a QFixed register and produces a Float result. During transpilation, this is lowered to individual MeasureOperations plus a DecodeQFixedOperation.
operands: [QFixed value (contains qubit_values in params)] results: [Float value]
Encoding:
For QPE phase (int_bits=0): float_value = 0.b0b1b2... = b00.5 + b10.25 + b2*0.125 + ...
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
num_bits: int = 0,
int_bits: int = 0,
) -> NoneAttributes¶
int_bits: intnum_bits: intoperation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
NotOp [source]¶
class NotOp(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
input: Valueoperation_kind: OperationKindoutput: Valuesignature: Signature
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()) -> NoneAttributes¶
evolved_qubits: Value The evolved quantum register result.gamma: Value The evolution time parameter.observable: Value The Observable parameter operand.operation_kind: OperationKind PauliEvolveOp is QUANTUM - transforms quantum state.qubits: Value The quantum register operand.signature: Signature
QInitOperation [source]¶
class QInitOperation(Operation)Initialize the qubit
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
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:
Binary kinds (EQ/NEQ/LT/LE/GT/GE/AND/OR/ADD/SUB/MUL/DIV/FLOORDIV/MOD/POW):
operands = [lhs, rhs].Unary kind (NOT):
operands = [val].Result:
results = [output_value].
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,
) -> NoneAttributes¶
kind: RuntimeOpKind | Noneoperation_kind: OperationKindsignature: Signature
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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional 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,
)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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.passes.strip_slice_ops¶
Strip SliceArrayOperation / ReleaseSliceViewOperation after the linearity check.
Both ops are purely declarative — the resulting sliced ArrayValue
carries all the emit-time metadata on its own (slice_of /
slice_start / slice_step), and the release marker only exists
so SliceBorrowCheckPass can observe explicit slice-assignment
borrow-returns in program order. ConstantFoldingPass keeps these
ops around when strip_slice_ops=False so the downstream linearity
check can see them. Once the linearity check has run, both ops are
unneeded; segmentation and emission expect a pure quantum-op stream
without classical slice declarations in the middle. This pass removes
them and leaves the block otherwise unchanged.
Overview¶
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
OperationTransformer | Base class for transforming operations with control flow handling. |
Pass | Base class for all compiler passes. |
StripSliceArrayOpsPass | Remove SliceArrayOperation / ReleaseSliceViewOperation nodes. |
Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
ForItemsOperation [source]¶
class ForItemsOperation(HasNestedOps, Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
key_vars: list[str] = list(),
value_var: str = '',
key_is_vector: bool = False,
key_var_values: tuple[Value, ...] | None = None,
value_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
key_is_vector: boolkey_var_values: tuple[Value, ...] | Nonekey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: strvalue_var_value: Value | None
Methods¶
all_input_values¶
def all_input_values(self) -> list[ValueBase]Include the per-key/value Value fields for cloning/substitution.
Same rationale as ForOperation.all_input_values: keep the IR
identity fields in lockstep with body references so UUID-keyed
lookups stay valid after inline cloning.
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationOperationTransformer [source]¶
class OperationTransformer(ABC)Base class for transforming operations with control flow handling.
Subclasses override transform_operation to define per-operation transformation.
Control flow recursion and rebuilding is handled automatically.
Example:
class OperationRenamer(OperationTransformer):
def transform_operation(self, op: Operation) -> Operation:
# Return modified operation
return dataclasses.replace(op, ...)Methods¶
transform_operation¶
def transform_operation(self, op: Operation) -> Operation | NoneTransform a single operation. Return None to remove it.
transform_operations¶
def transform_operations(self, operations: list[Operation]) -> list[Operation]Transform all operations including nested control flow.
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
StripSliceArrayOpsPass [source]¶
class StripSliceArrayOpsPass(Pass[Block, Block])Remove SliceArrayOperation / ReleaseSliceViewOperation nodes.
Both ops are only meaningful to SliceBorrowCheckPass as
view-declaration / release markers; downstream passes (analyze,
plan, emit) neither need nor expect them. Dropping them here
keeps the segmentation quantum-op-only.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockDrop slice marker ops from input.
Walks the operation tree (including nested control flow) and
returns a structurally identical block with every
SliceArrayOperation and ReleaseSliceViewOperation node
removed. The sliced ArrayValue results remain reachable
through later operands’ parent_array chains, so emit-time
resolution is unaffected.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block that has completed SliceBorrowCheckPass. |
Returns:
Block — A new block with all slice marker ops removed.
qamomile.circuit.transpiler.passes.substitution¶
Substitution pass for replacing QKernel subroutines and composite gate strategies.
This pass allows replacing:
CallBlockOperation targets (QKernel subroutines) with alternative implementations
CompositeGateOperation strategies with specified decomposition strategies
Example:
# Replace a custom oracle with an optimized version
config = SubstitutionConfig(
rules=[
SubstitutionRule(source_name="my_oracle", target=optimized_oracle),
SubstitutionRule(source_name="qft", strategy="approximate"),
]
)
pass = SubstitutionPass(config)
new_block = pass.run(block)Overview¶
| Function | Description |
|---|---|
check_signature_compatibility | Check signature compatibility between two Blocks. |
create_substitution_pass | Convenience factory for creating a SubstitutionPass. |
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CallBlockOperation | |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
Pass | Base class for all compiler passes. |
QKernel | Decorator class for Qamomile quantum kernels. |
SignatureCompatibilityError | Error raised when signatures are incompatible during substitution. |
SubstitutionConfig | Configuration for the substitution pass. |
SubstitutionPass | Pass that substitutes CallBlockOperations and CompositeGateOperations. |
SubstitutionRule | A single substitution rule. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Functions¶
check_signature_compatibility [source]¶
def check_signature_compatibility(source: Block, target: Block, strict: bool = True) -> tuple[bool, str | None]Check signature compatibility between two Blocks.
Parameters:
| Name | Type | Description |
|---|---|---|
source | Block | The source Block being replaced |
target | Block | The target Block to replace with |
strict | bool | If True, require exact type matches |
Returns:
bool — Tuple of (is_compatible, error_message).
str | None — If compatible, error_message is None.
create_substitution_pass [source]¶
def create_substitution_pass(
block_replacements: dict[str, 'Block | QKernel'] | None = None,
*,
strategy_overrides: dict[str, str] | None = None,
validate_signatures: bool = True,
) -> SubstitutionPassConvenience factory for creating a SubstitutionPass.
Parameters:
| Name | Type | Description |
|---|---|---|
block_replacements | dict[str, 'Block | QKernel'] | None | Map of block name to replacement |
strategy_overrides | dict[str, str] | None | Map of gate name to strategy name |
validate_signatures | bool | If True, validate signature compatibility when replacing blocks. Default is True. |
Returns:
SubstitutionPass — Configured SubstitutionPass
Example:
pass = create_substitution_pass(
block_replacements={"my_oracle": optimized_oracle},
strategy_overrides={"qft": "approximate", "iqft": "approximate"},
)Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CallBlockOperation [source]¶
class CallBlockOperation(Operation)Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
block: Block | None = None,
) -> NoneAttributes¶
block: Block | Noneoperation_kind: OperationKindsignature: Signature
Methods¶
is_self_reference_to¶
def is_self_reference_to(self, block: Block) -> boolReturn True if this call points to the given block (self-ref).
CompositeGateOperation [source]¶
class CompositeGateOperation(Operation)Represents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure is:
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
gate_type: CompositeGateType = CompositeGateType.CUSTOM,
num_control_qubits: int = 0,
num_target_qubits: int = 0,
custom_name: str = '',
resource_metadata: ResourceMetadata | None = None,
has_implementation: bool = True,
implementation_block: Block | None = None,
composite_gate_instance: Any = None,
strategy_name: str | None = None,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: Block | None Get the implementation block, if any.implementation_block: Block | Nonename: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
QKernel [source]¶
class QKernel(Generic[P, R])Decorator class for Qamomile quantum kernels.
Constructor¶
def __init__(self, func: Callable[P, R]) -> NoneAttributes¶
block: Block Compile the function to a hierarchical Block if not already compiled.funcinput_typesnameoutput_typesraw_funcsignature
Methods¶
build¶
def build(self, parameters: list[str] | None = None, **kwargs: Any = {}) -> BlockBuild a traced Block by tracing this kernel.
Parameters:
| Name | Type | Description |
|---|---|---|
parameters | list[str] | None | List of argument names to keep as unbound parameters. - None (default): Auto-detect parameters (non-Qubit args without value/default) - []: No parameters (all non-Qubit args must have value/default) - [“name”]: Explicit parameter list Only float, int, UInt, and their arrays are allowed as parameters. |
**kwargs | Any | Concrete values for non-parameter arguments. |
Returns:
Block — The traced block ready for transpilation, estimation,
or visualization.
Raises:
TypeError— If a non-parameterizable type is specified as parameter.ValueError— If required arguments are missing.
Example:
@qm.qkernel
def circuit(q: Qubit, theta: float) -> Qubit:
q = qm.rx(q, theta)
return q
# Auto-detect theta as parameter
block = circuit.build()
# Explicit parameter list
block = circuit.build(parameters=["theta"])
# theta bound to concrete value
block = circuit.build(theta=0.5)
# Transpile with binding
transpiler = QiskitTranspiler()
result = transpiler.emit(graph, binding={"theta": 0.5})draw¶
def draw(
self,
inline: bool = False,
fold_loops: bool = True,
expand_composite: bool = False,
inline_depth: int | None = None,
**kwargs: Any = {},
) -> AnyVisualize the circuit using Matplotlib.
This method builds the computation graph and creates a static visualization. Parameters are auto-detected: non-Qubit arguments without concrete values are shown as symbolic parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
inline | bool | If True, expand CallBlockOperation contents (inlining). If False (default), show CallBlockOperation as boxes. |
fold_loops | bool | If True (default), display ForOperation as blocks instead of unrolling. If False, expand loops and show all iterations. |
expand_composite | bool | If True, expand CompositeGateOperation (QFT, IQFT, etc.). If False (default), show as boxes. Independent of inline. |
inline_depth | int | None | Maximum nesting depth for inline expansion. None means unlimited (default). 0 means no inlining, 1 means top-level only, etc. Only affects CallBlock/ControlledU, not CompositeGate. |
**kwargs | Any | Concrete values for arguments. Arguments not provided here (and without defaults) will be shown as symbolic parameters. |
Returns:
Any — matplotlib.figure.Figure object.
Raises:
ImportError— If matplotlib is not installed.
Example:
import qamomile.circuit as qm
@qm.qkernel
def inner(q: qm.Qubit) -> qm.Qubit:
return qm.x(q)
@qm.qkernel
def circuit(q: qm.Qubit, theta: float) -> qm.Qubit:
q = inner(q)
q = qm.h(q)
q = qm.rx(q, theta)
return q
# Draw with auto-detected symbolic parameter (theta)
fig = circuit.draw()
# Draw with bound parameter
fig = circuit.draw(theta=0.5)
# Draw with blocks as boxes (default)
fig = circuit.draw()
# Draw with blocks expanded (inlined)
fig = circuit.draw(inline=True)
# Draw with loops folded (shown as blocks)
fig = circuit.draw(fold_loops=True)
# Draw with composite gates expanded
fig = circuit.draw(expand_composite=True)estimate_resources¶
def estimate_resources(self, *, bindings: dict[str, Any] | None = None) -> ResourceEstimateEstimate all resources for this kernel’s circuit.
Convenience method that delegates to the module-level
estimate_resources function, eliminating the need to
access .block directly.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Optional concrete parameter bindings (scalars and dicts). Dict values trigger |key| cardinality substitution. |
Returns:
ResourceEstimate — ResourceEstimate with qubits, gates, and parameters.
Example:
>>> @qm.qkernel
... def bell() -> qm.Vector[qm.Qubit]:
... q = qm.qubit_array(2)
... q[0] = qm.h(q[0])
... q[0], q[1] = qm.cx(q[0], q[1])
... return q
>>> est = bell.estimate_resources()
>>> print(est.qubits) # 2SignatureCompatibilityError [source]¶
class SignatureCompatibilityError(Exception)Error raised when signatures are incompatible during substitution.
SubstitutionConfig [source]¶
class SubstitutionConfigConfiguration for the substitution pass.
Constructor¶
def __init__(self, rules: list[SubstitutionRule] = list()) -> NoneAttributes¶
rules: list[SubstitutionRule]
Methods¶
get_rule_for_name¶
def get_rule_for_name(self, name: str) -> SubstitutionRule | NoneFind a rule matching the given name.
Parameters:
| Name | Type | Description |
|---|---|---|
name | str | Name to look up |
Returns:
SubstitutionRule | None — Matching SubstitutionRule or None
SubstitutionPass [source]¶
class SubstitutionPass(Pass[Block, Block])Pass that substitutes CallBlockOperations and CompositeGateOperations.
This pass traverses the block and applies substitution rules:
For CallBlockOperation: replaces the block reference with the target
For CompositeGateOperation: sets the strategy_name field
The pass preserves the block structure and only modifies matching operations.
Input: Block (any kind) Output: Block with substitutions applied (same kind as input)
Constructor¶
def __init__(self, config: SubstitutionConfig) -> NoneInitialize the pass with configuration.
Parameters:
| Name | Type | Description |
|---|---|---|
config | SubstitutionConfig | Substitution configuration with rules |
Attributes¶
name: str Return pass name.
Methods¶
run¶
def run(self, input: Block) -> BlockApply substitutions to the block.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block to transform |
Returns:
Block — Block with substitutions applied
SubstitutionRule [source]¶
class SubstitutionRuleA single substitution rule.
Constructor¶
def __init__(
self,
source_name: str,
target: 'Block | QKernel | None' = None,
strategy: str | None = None,
validate_signature: bool = True,
) -> NoneAttributes¶
source_name: strstrategy: str | Nonetarget: ‘Block | QKernel | None’validate_signature: bool
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
qamomile.circuit.transpiler.passes.symbolic_shape_validation¶
Validation pass: reject unresolved parameter shape dims in loop bounds.
Qamomile circuits are fixed-structure at compile time. Any loop whose
bound is a symbolic parameter array shape dimension (e.g.
gamma_dim0) must have that dimension resolved before emit — either
by ParameterShapeResolutionPass folding it from a concrete binding,
or by the user binding the dimension explicitly.
When an unresolved symbolic shape dim reaches a ForOperation operand,
this pass raises a CompileError with an actionable message that
points to the offending parameter and suggests concrete fixes. This is
the user-facing counterpart to the defensive hard fail in
emit_for_unrolled: it runs earlier (after analyze) and can
provide clean diagnostics instead of a cryptic emit-time error.
The library QAOA pattern (p bound to an int, for layer in qmc.range(p), gammas.shape never queried) is unaffected — the
pass only trips when an unresolved symbolic shape dim is actually used
as loop bound / allocation size.
Overview¶
| Class | Description |
|---|---|
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
ForOperation | Represents a for loop operation. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
Pass | Base class for all compiler passes. |
QamomileCompileError | Base class for all Qamomile compilation errors. |
SymbolicShapeValidationPass | Reject unresolved parameter shape dims in compile-time structure ops. |
Value | A typed SSA value in the IR. |
Classes¶
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
ForOperation [source]¶
class ForOperation(HasNestedOps, Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
loop_var_value: Value | None = None,
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: strloop_var_value: Value | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
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]]) -> Operationreplace_values¶
def replace_values(self, mapping: dict[str, ValueBase]) -> OperationHasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
QamomileCompileError [source]¶
class QamomileCompileError(Exception)Base class for all Qamomile compilation errors.
SymbolicShapeValidationPass [source]¶
class SymbolicShapeValidationPass(Pass[Block, Block])Reject unresolved parameter shape dims in compile-time structure ops.
Input: BlockKind.ANALYZED (runs after AnalyzePass).
Output: same block unchanged, or raises QamomileCompileError.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockValue [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
qamomile.circuit.transpiler.passes.validate_while¶
WhileOperation contract validation pass.
Validates that all WhileOperation conditions are measurement-backed
Bit values. A condition is measurement-backed if it originates from
qmc.measure() either directly or through phi-merged branches where
every leaf is itself measurement-backed (e.g. if sel: bit = measure(q1) else: bit = measure(q2)).
All other while patterns (classical variables, constants, comparison
results, non-measurement branch leaves) are rejected with a clear
ValidationError before reaching backend-specific emit passes.
This pass runs after lower_compile_time_ifs and before analyze.
Overview¶
| Class | Description |
|---|---|
BitType | Type representing a classical bit. |
Block | Unified block representation for all pipeline stages. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
IfOperation | Represents an if-else conditional operation. |
MeasureOperation | |
MeasureVectorOperation | Measure a vector of qubits. |
Pass | Base class for all compiler passes. |
PhiOp | SSA Phi function: merge point after conditional branch. |
ValidateWhileContractPass | Validates that all WhileOperation conditions are measurement-backed. |
ValidationError | Error during validation (e.g., non-classical I/O). |
Value | A typed SSA value in the IR. |
WhileOperation | Represents a while loop operation. |
Classes¶
BitType [source]¶
class BitType(ClassicalTypeMixin, ValueType)Type representing a classical bit.
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
HasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
IfOperation [source]¶
class IfOperation(HasNestedOps, Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
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(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationMeasureOperation [source]¶
class MeasureOperation(Operation)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
MeasureVectorOperation [source]¶
class MeasureVectorOperation(Operation)Measure a vector of qubits.
Takes a Vector[Qubit] (ArrayValue) and produces a Vector[Bit] (ArrayValue). This operation measures all qubits in the vector as a single operation.
operands: [ArrayValue of qubits] results: [ArrayValue of bits]
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
Pass [source]¶
class Pass(ABC, Generic[InputT, OutputT])Base class for all compiler passes.
Attributes¶
name: str Human-readable name for this pass.
Methods¶
run¶
def run(self, input: InputT) -> OutputTExecute the pass transformation.
PhiOp [source]¶
class PhiOp(Operation)SSA Phi function: merge point after conditional branch.
This operation selects one of two values based on a condition. Used to merge values from different branches of an if-else statement.
Example:
if condition:
x = x + 1 # true_value
else:
x = x + 2 # false_value
# x is now PhiOp(condition, true_value, false_value)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
condition: Valuefalse_value: Valueoperation_kind: OperationKindoutput: Valuesignature: Signaturetrue_value: Value
ValidateWhileContractPass [source]¶
class ValidateWhileContractPass(Pass[Block, Block])Validates that all WhileOperation conditions are measurement-backed.
Builds a producer map (result UUID → producing Operation instance) and checks every WhileOperation operand against it. A valid condition must be:
A
ValuewithBitTypeMeasurement-backed: produced by
MeasureOperationdirectly, or byIfOperation/PhiOpwhere every reachable leaf source is itself measurement-backed.
Both operands[0] (initial condition) and operands[1]
(loop-carried condition) are validated.
Raises ValidationError for any non-measurement while pattern.
Attributes¶
name: str
Methods¶
run¶
def run(self, block: Block) -> BlockValidate all WhileOperations and return block unchanged.
ValidationError [source]¶
class ValidationError(QamomileCompileError)Error during validation (e.g., non-classical I/O).
Constructor¶
def __init__(self, message: str, value_name: str | None = None)Attributes¶
value_name
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
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,
) -> NoneAttributes¶
max_iterations: int | Noneoperation_kind: OperationKindoperations: list[Operation]signature: Signature
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operationqamomile.circuit.transpiler.passes.value_mapping¶
Value mapping utilities for IR transformations.
Overview¶
| Function | Description |
|---|---|
remap_indexed_identifier | Remap an identifier while preserving a legacy index suffix. |
remap_value_metadata_references | Rewrite UUID and logical-id references inside value metadata. |
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
CastOperation | Type cast operation for creating aliases over the same quantum resources. |
DictValue | A dictionary value stored as stable ordered entries. |
HasNestedOps | Mixin for operations that contain nested operation lists. |
TupleValue | A tuple of IR values for structured data. |
UUIDRemapper | Clones values and operations with fresh UUIDs and logical_ids. |
Value | A typed SSA value in the IR. |
ValueBase | Protocol for IR values with typed metadata. |
ValueMetadata | Typed metadata owned by the compiler/runtime. |
ValueSubstitutor | Substitute IR values in operations using a UUID-keyed mapping. |
Functions¶
remap_indexed_identifier [source]¶
def remap_indexed_identifier(identifier: str, remap_identifier: Callable[[str], str]) -> strRemap an identifier while preserving a legacy index suffix.
Parameters:
| Name | Type | Description |
|---|---|---|
identifier | str | Scalar identifier or legacy "<base>_<index>" carrier key. |
remap_identifier | typing.Callable[[str], str] | Function that remaps scalar identifiers and carrier-key bases. |
Returns:
str — Remapped identifier. Numeric index suffixes are preserved after
remapping the base identifier.
remap_value_metadata_references [source]¶
def remap_value_metadata_references(
metadata: ValueMetadata,
remap_uuid: Callable[[str], str],
remap_logical_id: Callable[[str], str],
) -> ValueMetadataRewrite UUID and logical-id references inside value metadata.
Parameters:
| Name | Type | Description |
|---|---|---|
metadata | ValueMetadata | Metadata bundle whose embedded references should be rewritten. |
remap_uuid | typing.Callable[[str], str] | Function that maps scalar UUID references (and carrier-key bases) to replacement UUIDs. |
remap_logical_id | typing.Callable[[str], str] | Function that maps scalar logical-id references (and carrier-key bases) to replacement logical IDs. |
Returns:
ValueMetadata — Metadata with every embedded UUID / logical-id reference
rewritten. Legacy "<uuid>_<index>" carrier keys keep their
index suffix while remapping the base UUID. The original bundle is
returned unchanged when no reference is rewritten.
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]CastOperation [source]¶
class CastOperation(Operation)Type cast operation for creating aliases over the same quantum resources.
This operation does NOT allocate new qubits. It creates a new Value that references the same underlying quantum resources with a different type.
Use cases:
Vector[Qubit] -> QFixed (after QPE, for phase measurement)
Vector[Qubit] -> QUInt (for quantum arithmetic)
QUInt -> QFixed (reinterpret bits with different encoding)
QFixed -> QUInt (reinterpret bits with different encoding)
operands: [source_value] - The value being cast results: [cast_result] - The new value with target type (same physical qubits)
Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
source_type: ValueType | None = None,
target_type: ValueType | None = None,
qubit_mapping: list[str] = list(),
) -> NoneAttributes¶
num_qubits: int Number of qubits involved in the cast.operation_kind: OperationKind Cast stays in the same segment as its source (QUANTUM for quantum types).qubit_mapping: list[str]signature: Signature Return the type signature of this cast operation.source_type: ValueType | Nonetarget_type: ValueType | None
DictValue [source]¶
class DictValue(_MetadataValueMixin)A dictionary value stored as stable ordered entries.
Constructor¶
def __init__(
self,
name: str,
entries: tuple[tuple[TupleValue | Value, Value], ...] = tuple(),
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
) -> NoneAttributes¶
entries: tuple[tuple[TupleValue | Value, Value], ...]logical_id: strmetadata: ValueMetadataname: strtype: DictTypeuuid: str
Methods¶
is_constant¶
def is_constant(self) -> boolnext_version¶
def next_version(self) -> DictValueHasNestedOps [source]¶
class HasNestedOpsMixin for operations that contain nested operation lists.
Subclasses implement nested_op_lists() and rebuild_nested()
so that generic passes can recurse into control flow without
isinstance chains.
Methods¶
nested_op_lists¶
def nested_op_lists(self) -> list[list[Operation]]Return all nested operation lists in this control flow op.
rebuild_nested¶
def rebuild_nested(self, new_lists: list[list[Operation]]) -> OperationReturn a copy with nested operation lists replaced.
new_lists must have the same length/order as nested_op_lists().
TupleValue [source]¶
class TupleValue(_MetadataValueMixin)A tuple of IR values for structured data.
Constructor¶
def __init__(
self,
name: str,
elements: tuple[Value, ...] = tuple(),
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
) -> NoneAttributes¶
elements: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strtype: ‘TupleType’uuid: str
Methods¶
is_constant¶
def is_constant(self) -> boolnext_version¶
def next_version(self) -> TupleValueUUIDRemapper [source]¶
class UUIDRemapperClones values and operations with fresh UUIDs and logical_ids.
Used during inlining to create unique identities for values when a block is called multiple times.
Constructor¶
def __init__(self)Attributes¶
logical_id_remap: dict[str, str] Get the mapping from old logical_ids to new logical_ids.uuid_remap: dict[str, str] Get the mapping from old UUIDs to new UUIDs.
Methods¶
clone_operation¶
def clone_operation(self, op: Operation) -> OperationClone an operation with fresh UUIDs for all values.
Cloning goes through the Operation.all_input_values() /
Operation.replace_values() protocol so every Value-typed
field — including subclass extras (ControlledUOperation.power,
ForOperation.loop_var_value, ForItemsOperation.key_var_values
etc.) — is cloned consistently with the body references that
point to it. Without this, a subclass field could keep an old
UUID while body operands referencing the same logical Value got
fresh UUIDs, breaking identity-by-UUID lookups at emit time.
Parameters:
| Name | Type | Description |
|---|---|---|
op | Operation | Operation to clone. |
Returns:
Operation — A clone of op with every owned Value (operands,
results, subclass-extra fields) and every nested-body Value
reassigned a fresh UUID / logical_id, and with
CastOperation.qubit_mapping carrier keys remapped.
clone_operations¶
def clone_operations(self, operations: list[Operation]) -> list[Operation]Clone a list of operations with fresh UUIDs.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to clone in order. |
Returns:
list[Operation] — list[Operation]: Cloned operations, each with fresh UUIDs, in the
same order as operations.
clone_value¶
def clone_value(self, value: ValueBase) -> ValueBaseClone any value type with a fresh UUID and logical_id.
Handles Value, ArrayValue, TupleValue, and DictValue through
the unified ValueBase protocol. Nested values (tuple elements, dict
entries, parent_array / element_indices / shape / slice
fields) and embedded metadata references are cloned consistently.
Results are cached by source UUID so a repeated clone returns the
same instance.
Parameters:
| Name | Type | Description |
|---|---|---|
value | ValueBase | The value to clone. |
Returns:
ValueBase — The cloned value of the same concrete type, with a
fresh UUID / logical_id and its nested values and metadata
references remapped through this remapper.
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueBase [source]¶
class ValueBase(Protocol)Protocol for IR values with typed metadata.
Attributes are declared as read-only properties to match frozen dataclass fields in concrete implementations (Value, ArrayValue, etc.).
Attributes¶
logical_id: strmetadata: ValueMetadataname: struuid: str
Methods¶
get_const¶
def get_const(self) -> int | float | bool | Noneis_constant¶
def is_constant(self) -> boolis_parameter¶
def is_parameter(self) -> boolnext_version¶
def next_version(self) -> ValueBaseparameter_name¶
def parameter_name(self) -> str | NoneValueMetadata [source]¶
class ValueMetadataTyped metadata owned by the compiler/runtime.
Constructor¶
def __init__(
self,
scalar: ScalarMetadata | None = None,
cast: CastMetadata | None = None,
qfixed: QFixedMetadata | None = None,
array_runtime: ArrayRuntimeMetadata | None = None,
dict_runtime: DictRuntimeMetadata | None = None,
) -> NoneAttributes¶
array_runtime: ArrayRuntimeMetadata | Nonecast: CastMetadata | Nonedict_runtime: DictRuntimeMetadata | Noneqfixed: QFixedMetadata | Nonescalar: ScalarMetadata | None
ValueSubstitutor [source]¶
class ValueSubstitutorSubstitute IR values in operations using a UUID-keyed mapping.
Parameters:
| Name | Type | Description |
|---|---|---|
value_map | Mapping[str, ValueBase] | Mapping from original value UUIDs to replacement values. |
transitive | bool | Whether substitutions should chase chains such as A -> B -> C to the terminal value. Defaults to False. |
Constructor¶
def __init__(self, value_map: Mapping[str, ValueBase], transitive: bool = False)Initialize the substitutor.
Parameters:
| Name | Type | Description |
|---|---|---|
value_map | Mapping[str, ValueBase] | Mapping from original value UUIDs to replacement values. |
transitive | bool | Whether substitutions should chase chains to their terminal value. Defaults to False. |
Methods¶
substitute_operation¶
def substitute_operation(self, op: Operation) -> OperationSubstitute values in an operation.
Parameters:
| Name | Type | Description |
|---|---|---|
op | Operation | Operation whose operands, results, and subclass-specific value fields should be substituted. |
Returns:
Operation — Operation with all mapped value references replaced.
substitute_value¶
def substitute_value(self, value: ValueBase) -> ValueBaseSubstitute a single value.
Parameters:
| Name | Type | Description |
|---|---|---|
value | ValueBase | Value to replace or rebuild. |
Returns:
ValueBase — Replacement value, rebuilt value with substituted
ValueBase — metadata, or the original value when nothing maps.
qamomile.circuit.transpiler.program_orchestrator¶
Orchestration logic for compiled quantum-classical programs.
This module is internal. Users interact with ExecutableProgram.sample()/run().
Overview¶
| Class | Description |
|---|---|
ClassicalExecutor | Executes classical segments in Python. |
ClassicalStep | A classical execution step. |
CompiledClassicalSegment | A classical segment ready for Python execution. |
CompiledExpvalSegment | A compiled expectation value segment with concrete Hamiltonian. |
CompiledQuantumSegment | A quantum segment with emitted backend circuit. |
ExecutableProgram | A fully compiled program ready for execution. |
ExecutionContext | Holds global state during program execution. |
ExecutionError | Error during program execution. |
ExpvalJob | Job for expectation value computation. |
ExpvalStep | An expectation-value execution step. |
ParameterMetadata | Metadata for all parameters in a compiled segment. |
ProgramOrchestrator | Orchestrates execution of compiled quantum-classical programs. |
QuantumExecutor | Abstract base class for quantum backend execution. |
QuantumStep | A quantum execution step. |
RunJob | Job for single execution. |
SampleJob | Job for sampling execution (multiple shots). |
Classes¶
ClassicalExecutor [source]¶
class ClassicalExecutorExecutes classical segments in Python.
Methods¶
execute¶
def execute(self, segment: ClassicalSegment, context: ExecutionContext) -> dict[str, Any]Execute classical operations and return outputs.
Interprets the operations list directly using Python.
ClassicalStep [source]¶
class ClassicalStepA classical execution step.
Constructor¶
def __init__(self, segment: ClassicalSegment, role: str = 'classical') -> NoneAttributes¶
role: strsegment: ClassicalSegment
CompiledClassicalSegment [source]¶
class CompiledClassicalSegmentA classical segment ready for Python execution.
Constructor¶
def __init__(self, segment: ClassicalSegment) -> NoneAttributes¶
segment: ClassicalSegment
CompiledExpvalSegment [source]¶
class CompiledExpvalSegmentA compiled expectation value segment with concrete Hamiltonian.
This segment computes <psi|H|psi> where psi is the quantum state from a quantum circuit and H is a qamomile.observable.Hamiltonian.
Constructor¶
def __init__(
self,
segment: ExpvalSegment,
hamiltonian: 'qm_o.Hamiltonian',
quantum_segment_index: int = 0,
result_ref: str = '',
qubit_map: dict[int, int] = dict(),
) -> NoneAttributes¶
hamiltonian: ‘qm_o.Hamiltonian’quantum_segment_index: intqubit_map: dict[int, int]result_ref: strsegment: ExpvalSegment
CompiledQuantumSegment [source]¶
class CompiledQuantumSegment(Generic[T])A quantum segment with emitted backend circuit.
Constructor¶
def __init__(
self,
segment: QuantumSegment,
circuit: T,
qubit_map: QubitMap = dict(),
clbit_map: ClbitMap = dict(),
measurement_qubit_map: dict[int, int] = dict(),
parameter_metadata: ParameterMetadata = ParameterMetadata(),
) -> NoneAttributes¶
circuit: Tclbit_map: ClbitMapmeasurement_qubit_map: dict[int, int]parameter_metadata: ParameterMetadataqubit_map: QubitMapsegment: QuantumSegment
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 typeConstructor¶
def __init__(
self,
plan: ProgramPlan | None = None,
compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
compiled_classical: list[CompiledClassicalSegment] = list(),
compiled_expval: list[CompiledExpvalSegment] = list(),
output_refs: list[str] = list(),
num_output_bits: int = 0,
) -> NoneAttributes¶
compiled_classical: list[CompiledClassicalSegment]compiled_expval: list[CompiledExpvalSegment]compiled_quantum: list[CompiledQuantumSegment[T]]has_parameters: bool Check if this program has unbound parameters.num_output_bits: intoutput_refs: list[str]parameter_names: list[str] Get list of parameter names that need binding.plan: ProgramPlan | Nonequantum_circuit: T Get the single quantum circuit.
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 | NoneGet the first quantum circuit, or None if no quantum segments.
run¶
def run(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None = None,
) -> RunJob[Any] | ExpvalJobExecute once and return single result.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
RunJob[Any] | ExpvalJob — RunJob that resolves to the kernel’s return type, or
RunJob[Any] | ExpvalJob — ExpvalJob if the program contains expectation value computation.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
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]Execute with multiple shots and return counts.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
shots | int | Number of shots to run. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
SampleJob[Any] — SampleJob that resolves to SampleResult with results.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
Example:
job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results) # [(0.25, 500), (0.75, 500)]ExecutionContext [source]¶
class ExecutionContextHolds global state during program execution.
Constructor¶
def __init__(self, initial_bindings: dict[str, Any] | None = None)Methods¶
copy¶
def copy(self) -> 'ExecutionContext'Clone the execution context.
get¶
def get(self, key: str) -> Anyget_many¶
def get_many(self, keys: list[str]) -> dict[str, Any]has¶
def has(self, key: str) -> boolset¶
def set(self, key: str, value: Any) -> Noneupdate¶
def update(self, values: dict[str, Any]) -> NoneExecutionError [source]¶
class ExecutionError(QamomileCompileError)Error during program execution.
ExpvalJob [source]¶
class ExpvalJob(Job[float])Job for expectation value computation.
Returns a single float representing <psi|H|psi>.
Constructor¶
def __init__(self, exp_val: float)Initialize expval job.
Parameters:
| Name | Type | Description |
|---|---|---|
exp_val | float | The computed expectation value |
Methods¶
result¶
def result(self) -> floatReturn the expectation value.
status¶
def status(self) -> JobStatusReturn job status.
ExpvalStep [source]¶
class ExpvalStepAn expectation-value execution step.
Constructor¶
def __init__(self, segment: ExpvalSegment, quantum_step_index: int = 0) -> NoneAttributes¶
quantum_step_index: intsegment: ExpvalSegment
ParameterMetadata [source]¶
class ParameterMetadataMetadata for all parameters in a compiled segment.
Tracks parameter information for runtime binding.
Constructor¶
def __init__(self, parameters: list[ParameterInfo] = list()) -> NoneAttributes¶
parameters: list[ParameterInfo]
Methods¶
get_array_names¶
def get_array_names(self) -> set[str]Get unique array/scalar parameter names.
get_ordered_params¶
def get_ordered_params(self) -> list[Any]Get backend parameter objects in definition order.
Useful for backends that require positional parameter binding (e.g., QURI Parts).
Returns:
list[Any] — List of backend_param objects in the order they were defined.
Example:
# For QURI Parts that uses positional binding:
param_values = [bindings[p.name] for p in metadata.parameters]
bound_circuit = circuit.bind_parameters(param_values)get_param_by_name¶
def get_param_by_name(self, name: str) -> ParameterInfo | NoneGet parameter info by full name.
to_binding_dict¶
def to_binding_dict(self, bindings: dict[str, Any]) -> dict[Any, Any]Convert indexed bindings to backend parameter bindings.
Transforms user-provided bindings (with indexed names like “gammas[0]”) into a dictionary mapping backend parameter objects to values. Useful for backends that use dict-based parameter binding (e.g., Qiskit).
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | Dictionary mapping parameter names to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2, “theta”: 0.5} |
Returns:
dict[Any, Any] — Dictionary mapping backend_param objects to values.
Example:
# For Qiskit that uses dict-based binding:
qiskit_bindings = metadata.to_binding_dict(bindings)
bound_circuit = circuit.assign_parameters(qiskit_bindings)ProgramOrchestrator [source]¶
class ProgramOrchestrator(Generic[T])Orchestrates execution of compiled quantum-classical programs.
This is an internal class that handles the runtime execution logic.
Users should use ExecutableProgram.sample() and
ExecutableProgram.run() instead.
Constructor¶
def __init__(self, program: ExecutableProgram[T]) -> NoneMethods¶
run¶
def run(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None,
) -> RunJob[Any] | ExpvalJobExecute once and return single result.
run_expval¶
def run_expval(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None,
) -> ExpvalJobBackward-compatible helper for pure expval execution.
sample¶
def sample(
self,
executor: QuantumExecutor[T],
shots: int,
bindings: dict[str, Any] | None,
) -> SampleJob[Any]Execute with multiple shots and return counts.
QuantumExecutor [source]¶
class QuantumExecutor(ABC, Generic[T])Abstract base class for quantum backend execution.
To implement a custom executor:
execute() [Required] Execute circuit and return bitstring counts as dict[str, int]. Keys are bitstrings in big-endian format (e.g., “011” means q2=0, q1=1, q0=1).
bind_parameters() [Optional] Bind parameter values to parametric circuits. Override if your executor supports parametric circuits (e.g., QAOA variational circuits). Use ParameterMetadata.to_binding_dict() for easy conversion.
estimate() [Optional] Compute expectation values <psi|H|psi>. Override if your executor supports estimation primitives (e.g., Qiskit Estimator, QURI Parts).
Example (Minimal): class MyExecutor(QuantumExecutor[QuantumCircuit]): def init(self): from qiskit_aer import AerSimulator self.backend = AerSimulator()
def execute(self, circuit, shots):
from qiskit import transpile
if circuit.num_clbits == 0:
circuit = circuit.copy()
circuit.measure_all()
transpiled = transpile(circuit, self.backend)
return self.backend.run(transpiled, shots=shots).result().get_counts()Example (With Parameter Binding): def bind_parameters(self, circuit, bindings, metadata): # metadata.to_binding_dict() converts indexed names to backend params return circuit.assign_parameters(metadata.to_binding_dict(bindings))
Methods¶
bind_parameters¶
def bind_parameters(
self,
circuit: T,
bindings: dict[str, Any],
parameter_metadata: ParameterMetadata,
) -> TBind parameter values to the circuit.
Default implementation returns the circuit unchanged. Override for backends that support parametric circuits.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The parameterized circuit |
bindings | dict[str, Any] | Dict mapping parameter names (indexed format) to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
parameter_metadata | ParameterMetadata | Metadata about circuit parameters |
Returns:
T — New circuit with parameters bound
estimate¶
def estimate(
self,
circuit: T,
hamiltonian: 'qm_o.Hamiltonian',
params: Sequence[float] | None = None,
) -> floatEstimate the expectation value of a Hamiltonian.
This method computes <psi|H|psi> where psi is the quantum state prepared by the circuit and H is the Hamiltonian.
Backends can override this method to provide optimized implementations using their native estimator primitives.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit (state preparation ansatz) |
hamiltonian | 'qm_o.Hamiltonian' | The qamomile.observable.Hamiltonian to measure |
params | Sequence[float] | None | Optional parameter values for parametric circuits |
Returns:
float — The estimated expectation value
Raises:
NotImplementedError— If the executor does not support estimation
execute¶
def execute(self, circuit: T, shots: int) -> dict[str, int]Execute the circuit and return bitstring counts.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit to execute |
shots | int | Number of measurement shots |
Returns:
dict[str, int] — Dictionary mapping bitstrings to counts.
dict[str, int] — {“00”: 512, “11”: 512}
QuantumStep [source]¶
class QuantumStepA quantum execution step.
Constructor¶
def __init__(self, segment: QuantumSegment) -> NoneAttributes¶
segment: QuantumSegment
RunJob [source]¶
class RunJob(Job[T], Generic[T])Job for single execution.
Returns a single result value matching the kernel’s return type.
Constructor¶
def __init__(self, raw_counts: dict[str, int], result_converter: Callable[[str], T])Initialize run job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (should have single entry) |
result_converter | Callable[[str], T] | Function to convert bitstring to typed result |
Methods¶
result¶
def result(self) -> TReturn the single result.
status¶
def status(self) -> JobStatusReturn job status.
SampleJob [source]¶
class SampleJob(Job[SampleResult[T]], Generic[T])Job for sampling execution (multiple shots).
Returns a SampleResult containing counts for each unique result.
Constructor¶
def __init__(
self,
raw_counts: dict[str, int],
result_converter: Callable[[dict[str, int]], list[tuple[T, int]]],
shots: int,
)Initialize sample job.
Parameters:
| Name | Type | Description |
|---|---|---|
raw_counts | dict[str, int] | Bitstring counts from executor (e.g., {“00”: 512, “11”: 512}) |
result_converter | Callable[[dict[str, int]], list[tuple[T, int]]] | Function to convert raw counts to typed results |
shots | int | Number of shots executed |
Methods¶
result¶
def result(self) -> SampleResult[T]Return the sample result.
status¶
def status(self) -> JobStatusReturn job status.
qamomile.circuit.transpiler.quantum_executor¶
Abstract base class for quantum backend execution.
This module provides a simple interface for implementing custom quantum executors. Executors bridge Qamomile’s compiled circuits to various quantum backends including local simulators and cloud quantum devices.
Basic Example (Local Simulator): from qiskit_aer import AerSimulator
class MyExecutor(QuantumExecutor[QuantumCircuit]):
def __init__(self):
self.backend = AerSimulator()
def execute(self, circuit: QuantumCircuit, shots: int) -> dict[str, int]:
from qiskit import transpile
if circuit.num_clbits == 0:
circuit = circuit.copy()
circuit.measure_all()
transpiled = transpile(circuit, self.backend)
job = self.backend.run(transpiled, shots=shots)
return job.result().get_counts()Cloud Backend Example (IBM Quantum): from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
class IBMQuantumExecutor(QuantumExecutor[QuantumCircuit]):
def __init__(self, backend_name: str = "ibm_brisbane"):
self.service = QiskitRuntimeService()
self.backend_name = backend_name
def execute(self, circuit: QuantumCircuit, shots: int) -> dict[str, int]:
from qiskit.transpiler.preset_passmanagers import (
generate_preset_pass_manager,
)
backend = self.service.backend(self.backend_name)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
transpiled = pm.run(circuit)
sampler = SamplerV2(backend)
job = sampler.run([transpiled], shots=shots)
return job.result()[0].data.meas.get_counts()
def bind_parameters(self, circuit, bindings, metadata):
# Use helper method for easy conversion
return circuit.assign_parameters(metadata.to_binding_dict(bindings))Bitstring Format:
The execute() method returns dict[str, int] where keys are bitstrings in big-endian format (leftmost bit = highest qubit index). Example: {“011”: 512, “100”: 488} for 3 qubits
Overview¶
| Class | Description |
|---|---|
ParameterMetadata | Metadata for all parameters in a compiled segment. |
QuantumExecutor | Abstract base class for quantum backend execution. |
Classes¶
ParameterMetadata [source]¶
class ParameterMetadataMetadata for all parameters in a compiled segment.
Tracks parameter information for runtime binding.
Constructor¶
def __init__(self, parameters: list[ParameterInfo] = list()) -> NoneAttributes¶
parameters: list[ParameterInfo]
Methods¶
get_array_names¶
def get_array_names(self) -> set[str]Get unique array/scalar parameter names.
get_ordered_params¶
def get_ordered_params(self) -> list[Any]Get backend parameter objects in definition order.
Useful for backends that require positional parameter binding (e.g., QURI Parts).
Returns:
list[Any] — List of backend_param objects in the order they were defined.
Example:
# For QURI Parts that uses positional binding:
param_values = [bindings[p.name] for p in metadata.parameters]
bound_circuit = circuit.bind_parameters(param_values)get_param_by_name¶
def get_param_by_name(self, name: str) -> ParameterInfo | NoneGet parameter info by full name.
to_binding_dict¶
def to_binding_dict(self, bindings: dict[str, Any]) -> dict[Any, Any]Convert indexed bindings to backend parameter bindings.
Transforms user-provided bindings (with indexed names like “gammas[0]”) into a dictionary mapping backend parameter objects to values. Useful for backends that use dict-based parameter binding (e.g., Qiskit).
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | Dictionary mapping parameter names to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2, “theta”: 0.5} |
Returns:
dict[Any, Any] — Dictionary mapping backend_param objects to values.
Example:
# For Qiskit that uses dict-based binding:
qiskit_bindings = metadata.to_binding_dict(bindings)
bound_circuit = circuit.assign_parameters(qiskit_bindings)QuantumExecutor [source]¶
class QuantumExecutor(ABC, Generic[T])Abstract base class for quantum backend execution.
To implement a custom executor:
execute() [Required] Execute circuit and return bitstring counts as dict[str, int]. Keys are bitstrings in big-endian format (e.g., “011” means q2=0, q1=1, q0=1).
bind_parameters() [Optional] Bind parameter values to parametric circuits. Override if your executor supports parametric circuits (e.g., QAOA variational circuits). Use ParameterMetadata.to_binding_dict() for easy conversion.
estimate() [Optional] Compute expectation values <psi|H|psi>. Override if your executor supports estimation primitives (e.g., Qiskit Estimator, QURI Parts).
Example (Minimal): class MyExecutor(QuantumExecutor[QuantumCircuit]): def init(self): from qiskit_aer import AerSimulator self.backend = AerSimulator()
def execute(self, circuit, shots):
from qiskit import transpile
if circuit.num_clbits == 0:
circuit = circuit.copy()
circuit.measure_all()
transpiled = transpile(circuit, self.backend)
return self.backend.run(transpiled, shots=shots).result().get_counts()Example (With Parameter Binding): def bind_parameters(self, circuit, bindings, metadata): # metadata.to_binding_dict() converts indexed names to backend params return circuit.assign_parameters(metadata.to_binding_dict(bindings))
Methods¶
bind_parameters¶
def bind_parameters(
self,
circuit: T,
bindings: dict[str, Any],
parameter_metadata: ParameterMetadata,
) -> TBind parameter values to the circuit.
Default implementation returns the circuit unchanged. Override for backends that support parametric circuits.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The parameterized circuit |
bindings | dict[str, Any] | Dict mapping parameter names (indexed format) to values. e.g., {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
parameter_metadata | ParameterMetadata | Metadata about circuit parameters |
Returns:
T — New circuit with parameters bound
estimate¶
def estimate(
self,
circuit: T,
hamiltonian: 'qm_o.Hamiltonian',
params: Sequence[float] | None = None,
) -> floatEstimate the expectation value of a Hamiltonian.
This method computes <psi|H|psi> where psi is the quantum state prepared by the circuit and H is the Hamiltonian.
Backends can override this method to provide optimized implementations using their native estimator primitives.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit (state preparation ansatz) |
hamiltonian | 'qm_o.Hamiltonian' | The qamomile.observable.Hamiltonian to measure |
params | Sequence[float] | None | Optional parameter values for parametric circuits |
Returns:
float — The estimated expectation value
Raises:
NotImplementedError— If the executor does not support estimation
execute¶
def execute(self, circuit: T, shots: int) -> dict[str, int]Execute the circuit and return bitstring counts.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | T | The quantum circuit to execute |
shots | int | Number of measurement shots |
Returns:
dict[str, int] — Dictionary mapping bitstrings to counts.
dict[str, int] — {“00”: 512, “11”: 512}
qamomile.circuit.transpiler.result¶
EmitResult data structures for transpiler output.
Overview¶
| Class | Description |
|---|---|
ClassicalMapping | Maps a logical Value to a classical value or measurement result slot. |
EmitResult | Structured result from Transpiler.emit(). |
OutputMapping | Maps Block output position to a physical resource. |
QubitMapping | Maps a logical Value to a physical qubit index. |
Classes¶
ClassicalMapping [source]¶
class ClassicalMappingMaps a logical Value to a classical value or measurement result slot.
Constructor¶
def __init__(
self,
value_uuid: str,
value_name: str,
value: Union[int, float, bool, None],
clbit_index: Union[int, None] = None,
) -> NoneAttributes¶
clbit_index: Union[int, None]value: Union[int, float, bool, None]value_name: strvalue_uuid: str
EmitResult [source]¶
class EmitResult(Generic[T])Structured result from Transpiler.emit().
Contains the backend-specific circuit along with mapping information that tracks the correspondence between logical Values and physical qubit/clbit indices.
Constructor¶
def __init__(
self,
circuit: T,
qubit_mappings: list[QubitMapping],
classical_mappings: list[ClassicalMapping],
output_mappings: list[OutputMapping],
num_qubits: int,
num_clbits: int = 0,
) -> NoneAttributes¶
circuit: Tclassical_mappings: list[ClassicalMapping]num_clbits: intnum_qubits: intoutput_mappings: list[OutputMapping]qubit_mappings: list[QubitMapping]
Methods¶
get_measurement_clbit_indices¶
def get_measurement_clbit_indices(self) -> list[int]Get clbit indices for all measurement outputs in order.
get_output_mapping_by_index¶
def get_output_mapping_by_index(self, index: int) -> Union[OutputMapping, None]Get output mapping by tuple index.
get_output_qubit_indices¶
def get_output_qubit_indices(self) -> list[int]Get qubit indices for all quantum outputs in order.
get_qubit_index_by_name¶
def get_qubit_index_by_name(self, name: str) -> Union[int, None]Look up qubit index by Value name.
OutputMapping [source]¶
class OutputMappingMaps Block output position to a physical resource.
Constructor¶
def __init__(
self,
output_index: int,
value_uuid: str,
value_name: str,
kind: str,
physical_index: Union[int, None],
classical_value: Union[int, float, bool, None] = None,
) -> NoneAttributes¶
classical_value: Union[int, float, bool, None]kind: stroutput_index: intphysical_index: Union[int, None]value_name: strvalue_uuid: str
QubitMapping [source]¶
class QubitMappingMaps a logical Value to a physical qubit index.
Constructor¶
def __init__(self, value_uuid: str, value_name: str, qubit_index: int) -> NoneAttributes¶
qubit_index: intvalue_name: strvalue_uuid: str
qamomile.circuit.transpiler.segments¶
Data structures for segmented quantum/classical execution plans.
Overview¶
| Class | Description |
|---|---|
ClassicalSegment | A segment of pure classical operations. |
ClassicalStep | A classical execution step. |
ExpvalSegment | A segment for expectation value computation. |
ExpvalStep | An expectation-value execution step. |
HybridBoundary | Represents a measurement or encode operation at quantum/classical boundary. |
MultipleQuantumSegmentsError | Raised when program has multiple quantum segments. |
ProgramABI | Runtime-visible ABI for a segmented program. |
ProgramPlan | Execution plan for a hybrid quantum/classical program. |
QuantumSegment | A segment of pure quantum operations. |
QuantumStep | A quantum execution step. |
Segment | Base class for separated computation segments. |
SegmentKind | Type of computation segment. |
Value | A typed SSA value in the IR. |
Constants¶
ProgramStep:TypeAlias=ClassicalStep | QuantumStep | ExpvalStep
Classes¶
ClassicalSegment [source]¶
class ClassicalSegment(Segment)A segment of pure classical operations.
Contains arithmetic, comparisons, and control flow. Will be executed directly in Python.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
kind: SegmentKind
ClassicalStep [source]¶
class ClassicalStepA classical execution step.
Constructor¶
def __init__(self, segment: ClassicalSegment, role: str = 'classical') -> NoneAttributes¶
role: strsegment: ClassicalSegment
ExpvalSegment [source]¶
class ExpvalSegment(Segment)A segment for expectation value computation.
Represents computing <psi|H|psi> where psi is the quantum state and H is a Hamiltonian observable.
This segment bridges a quantum circuit (state preparation) to a classical expectation value.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
hamiltonian_value: Value | None = None,
qubits_value: Value | None = None,
result_ref: str = '',
) -> NoneAttributes¶
hamiltonian_value: Value | Nonekind: SegmentKindqubits_value: Value | Noneresult_ref: str
ExpvalStep [source]¶
class ExpvalStepAn expectation-value execution step.
Constructor¶
def __init__(self, segment: ExpvalSegment, quantum_step_index: int = 0) -> NoneAttributes¶
quantum_step_index: intsegment: ExpvalSegment
HybridBoundary [source]¶
class HybridBoundaryRepresents a measurement or encode operation at quantum/classical boundary.
These operations bridge quantum and classical segments.
Constructor¶
def __init__(
self,
operation: Operation,
source_segment_index: int,
target_segment_index: int,
value_ref: str,
) -> NoneAttributes¶
operation: Operationsource_segment_index: inttarget_segment_index: intvalue_ref: str
MultipleQuantumSegmentsError [source]¶
class MultipleQuantumSegmentsError(Exception)Raised when program has multiple quantum segments.
Qamomile enforces a single quantum circuit execution pattern:
[Classical Prep] → Quantum Circuit → [Classical Post/Expval]
Your program has multiple quantum segments, suggesting quantum operations that depend on measurement results (JIT compilation not supported).
ProgramABI [source]¶
class ProgramABIRuntime-visible ABI for a segmented program.
Constructor¶
def __init__(
self,
public_inputs: dict[str, Value] = dict(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
output_refs: list[str]public_inputs: dict[str, Value]
ProgramPlan [source]¶
class ProgramPlanExecution plan for a hybrid quantum/classical program.
Structure:
[Optional] Classical preprocessing (parameter computation, etc.)
Single quantum segment (REQUIRED)
[Optional] Expval segment OR classical postprocessing
This plan enforces Qamomile’s current execution model: all quantum operations must be in a single quantum circuit.
Constructor¶
def __init__(
self,
steps: list[ProgramStep] = list(),
abi: ProgramABI = ProgramABI(),
boundaries: list[HybridBoundary] = list(),
parameters: dict[str, Value] = dict(),
) -> NoneAttributes¶
abi: ProgramABIboundaries: list[HybridBoundary]parameters: dict[str, Value]steps: list[ProgramStep]
QuantumSegment [source]¶
class QuantumSegment(Segment)A segment of pure quantum operations.
Contains quantum gates and qubit allocations. Will be emitted to a quantum circuit.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
qubit_values: list[Value] = list(),
num_qubits: int = 0,
) -> NoneAttributes¶
kind: SegmentKindnum_qubits: intqubit_values: list[Value]
QuantumStep [source]¶
class QuantumStepA quantum execution step.
Constructor¶
def __init__(self, segment: QuantumSegment) -> NoneAttributes¶
segment: QuantumSegment
Segment [source]¶
class Segment(ABC)Base class for separated computation segments.
Constructor¶
def __init__(
self,
operations: list[Operation] = list(),
input_refs: list[str] = list(),
output_refs: list[str] = list(),
) -> NoneAttributes¶
input_refs: list[str]kind: SegmentKind Return the kind of this segment.operations: list[Operation]output_refs: list[str]
SegmentKind [source]¶
class SegmentKind(Enum)Type of computation segment.
Attributes¶
CLASSICALEXPVALQUANTUM
Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
qamomile.circuit.transpiler.transpiler¶
Base transpiler class for backend-specific compilation.
Overview¶
| Function | Description |
|---|---|
count_call_blocks | Count all CallBlockOperations reachable from an operation list. |
count_unrollable_call_blocks | Count CallBlockOperations the inline/partial-eval loop can still resolve. |
| Class | Description |
|---|---|
AffineValidationPass | Validate affine type semantics at IR level. |
AnalyzePass | Analyze and validate an affine block. |
Block | Unified block representation for all pipeline stages. |
BlockKind | Classification of block structure for pipeline stages. |
CompileTimeIfLoweringPass | Lowers compile-time resolvable IfOperations before separation. |
ConstantFoldingPass | Evaluates constant expressions at compile time. |
DecompositionConfig | Configuration for decomposition strategy selection. |
EmitPass | Base class for backend-specific emission passes. |
EntrypointValidationPass | Validate top-level entrypoint constraints. |
ExecutableProgram | A fully compiled program ready for execution. |
FrontendTransformError | Error during frontend AST-to-builder lowering. |
InlinePass | Inline all CallBlockOperations to create an affine block. |
ParameterShapeResolutionPass | Substitute symbolic parameter array shape dims with concrete constants. |
PartialEvaluationPass | Fold constants and lower compile-time control flow. |
ProgramPlan | Execution plan for a hybrid quantum/classical program. |
QKernel | Decorator class for Qamomile quantum kernels. |
QamomileCompileError | Base class for all Qamomile compilation errors. |
SegmentationPass | Segment a block into a strategy-specific executable program plan. |
SliceBorrowCheckPass | Post-fold linearity checker for sliced views and borrow state. |
SubstitutionConfig | Configuration for the substitution pass. |
SubstitutionPass | Pass that substitutes CallBlockOperations and CompositeGateOperations. |
SubstitutionRule | A single substitution rule. |
SymbolicShapeValidationPass | Reject unresolved parameter shape dims in compile-time structure ops. |
Transpiler | Base class for backend-specific transpilers. |
TranspilerConfig | Configuration for the transpiler pipeline. |
Functions¶
count_call_blocks [source]¶
def count_call_blocks(operations: list[Operation]) -> intCount all CallBlockOperations reachable from an operation list.
Recurses into InverseBlockOperation / ControlledUOperation
nested blocks and into IfOperation / HasNestedOps bodies, so
calls hidden inside control flow or operation-owned blocks are
counted. unroll_recursion uses this as the primary termination
signal (count == 0 means the block is fully inlined).
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to scan. |
Returns:
int — Total number of CallBlockOperations reachable from
operations, including nested ones.
count_unrollable_call_blocks [source]¶
def count_unrollable_call_blocks(operations: list[Operation]) -> intCount CallBlockOperations the inline/partial-eval loop can still resolve.
This mirrors :func:count_call_blocks but does not descend into
a ControlledUOperation.block or an InverseBlockOperation’s
nested blocks. A call trapped inside one of those operation-owned
blocks cannot be resolved by the unroll_recursion fixed-point
loop: partial_eval (ConstantFoldingPass /
CompileTimeIfLoweringPass) only recurses into HasNestedOps
bodies, never into operation-owned blocks, so a self-recursive
kernel’s base-case if is never folded there. Such a call is
therefore not unrollable. Calls at the top level or inside
For / If / While bodies are unrollable and are counted.
The unroll loop uses this to tell two failure modes apart: a non-zero
:func:count_call_blocks with a zero count_unrollable_call_blocks
means every residual call is trapped inside a controlled / inverted
block (i.e. a recursive @qkernel was passed to qmc.control /
qmc.inverse), as opposed to a genuinely non-terminating top-level
recursion.
Parameters:
| Name | Type | Description |
|---|---|---|
operations | list[Operation] | Operations to scan. |
Returns:
int — Number of CallBlockOperations reachable without entering a
ControlledUOperation.block or InverseBlockOperation
nested block.
Classes¶
AffineValidationPass [source]¶
class AffineValidationPass(Pass[Block, Block])Validate affine type semantics at IR level.
This pass serves as a safety net to catch affine type violations that may have bypassed the frontend checks. It verifies:
Each quantum value is used (consumed) at most once
Quantum values are not silently discarded
Input: Block (any kind) Output: Same Block (unchanged, validation only)
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockValidate affine type semantics in the block.
Raises:
ValidationError— If the block kind is not AFFINE.AffineTypeError— If a quantum value is consumed multiple times.
AnalyzePass [source]¶
class AnalyzePass(Pass[Block, Block])Analyze and validate an affine block.
This pass:
Builds a dependency graph between values (used locally for validation)
Validates that quantum ops don’t depend on non-parameter classical results
Checks that block inputs/outputs are classical
Input: Block with BlockKind.AFFINE Output: Block with BlockKind.ANALYZED
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockAnalyze the block and validate dependencies.
Block [source]¶
class BlockUnified block representation for all pipeline stages.
Replaces the older traced and callable IR wrappers with a single structure.
The kind field indicates which pipeline stage this block is at.
Constructor¶
def __init__(
self,
name: str = '',
label_args: list[str] = list(),
input_values: list[Value] = list(),
output_values: list[Value] = list(),
output_names: list[str] = list(),
operations: list['Operation'] = list(),
kind: BlockKind = BlockKind.HIERARCHICAL,
parameters: dict[str, Value] = dict(),
param_slots: tuple[ParamSlot, ...] = tuple(),
) -> NoneAttributes¶
input_values: list[Value]kind: BlockKindlabel_args: list[str]name: stroperations: list[‘Operation’]output_names: list[str]output_values: list[Value]param_slots: tuple[ParamSlot, ...]parameters: dict[str, Value]
Methods¶
call¶
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'Create a CallBlockOperation against this block.
is_affine¶
def is_affine(self) -> boolCheck if block contains no CallBlockOperations.
unbound_parameters¶
def unbound_parameters(self) -> list[str]Return list of unbound parameter names.
BlockKind [source]¶
class BlockKind(Enum)Classification of block structure for pipeline stages.
Attributes¶
AFFINEANALYZEDHIERARCHICALTRACED
CompileTimeIfLoweringPass [source]¶
class CompileTimeIfLoweringPass(Pass[Block, Block])Lowers compile-time resolvable IfOperations before separation.
After constant folding, some IfOperation conditions are statically
known but remain as control-flow nodes. SegmentationPass treats them
as segment boundaries, causing MultipleQuantumSegmentsError for
classical-only compile-time if after quantum init.
This pass:
Evaluates conditions including expression-derived ones (
CompOp,CondOp,NotOpchains).Replaces resolved
IfOperations with selected-branch operations.Substitutes phi output UUIDs with selected-branch values in all subsequent operations and block outputs.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun the compile-time if lowering pass.
ConstantFoldingPass [source]¶
class ConstantFoldingPass(Pass[Block, Block])Evaluates constant expressions at compile time.
This pass folds BinOp operations when all operands are constants or bound parameters, eliminating unnecessary classical operations that would otherwise split quantum segments.
Example:
Before (with bindings={"phase": 0.5}):
BinOp(phase * 2) -> classical segment split
After:
Constant 1.0 -> no segment splitConstructor¶
def __init__(self, bindings: dict[str, Any] | None = None, *, strip_slice_ops: bool = True)Create a constant-folding pass.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Compile-time parameter bindings used when folding BinOps that reference declared parameters. |
strip_slice_ops | bool | When True (default), removes SliceArrayOperation nodes after folding. Set to False when a downstream pass — notably SliceBorrowCheckPass — still needs to observe slice declaration points in program order to decide view liveness. A separate strip pass must then run after the linearity check so segmentation still sees a pure quantum-op stream. |
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockRun constant folding on the block.
DecompositionConfig [source]¶
class DecompositionConfigConfiguration for decomposition strategy selection.
This configuration is passed to the transpiler to control which decomposition strategies are used for composite gates.
Constructor¶
def __init__(
self,
strategy_overrides: dict[str, str] = dict(),
strategy_params: dict[str, dict[str, Any]] = dict(),
default_strategy: str = 'standard',
) -> NoneAttributes¶
default_strategy: strstrategy_overrides: dict[str, str]strategy_params: dict[str, dict[str, Any]]
Methods¶
get_strategy_for_gate¶
def get_strategy_for_gate(self, gate_name: str) -> strGet the strategy name for a specific gate.
Parameters:
| Name | Type | Description |
|---|---|---|
gate_name | str | The gate name (e.g., “qft”, “iqft”) |
Returns:
str — Strategy name to use
get_strategy_params¶
def get_strategy_params(self, strategy_name: str) -> dict[str, Any]Get parameters for a specific strategy.
Parameters:
| Name | Type | Description |
|---|---|---|
strategy_name | str | The strategy name |
Returns:
dict[str, Any] — Dictionary of parameters
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:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Values to bind parameters to. If not provided, parameters must be bound at execution time. |
parameters | list[str] | None | List of parameter names to preserve as backend parameters. |
Attributes¶
bindingsname: strparameters
Methods¶
run¶
def run(self, input: ProgramPlan) -> ExecutableProgram[T]Emit backend code from a program plan.
EntrypointValidationPass [source]¶
class EntrypointValidationPass(Pass[Block, Block])Validate top-level entrypoint constraints.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockExecutableProgram [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 typeConstructor¶
def __init__(
self,
plan: ProgramPlan | None = None,
compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
compiled_classical: list[CompiledClassicalSegment] = list(),
compiled_expval: list[CompiledExpvalSegment] = list(),
output_refs: list[str] = list(),
num_output_bits: int = 0,
) -> NoneAttributes¶
compiled_classical: list[CompiledClassicalSegment]compiled_expval: list[CompiledExpvalSegment]compiled_quantum: list[CompiledQuantumSegment[T]]has_parameters: bool Check if this program has unbound parameters.num_output_bits: intoutput_refs: list[str]parameter_names: list[str] Get list of parameter names that need binding.plan: ProgramPlan | Nonequantum_circuit: T Get the single quantum circuit.
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 | NoneGet the first quantum circuit, or None if no quantum segments.
run¶
def run(
self,
executor: QuantumExecutor[T],
bindings: dict[str, Any] | None = None,
) -> RunJob[Any] | ExpvalJobExecute once and return single result.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
RunJob[Any] | ExpvalJob — RunJob that resolves to the kernel’s return type, or
RunJob[Any] | ExpvalJob — ExpvalJob if the program contains expectation value computation.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
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]Execute with multiple shots and return counts.
Parameters:
| Name | Type | Description |
|---|---|---|
executor | QuantumExecutor[T] | Backend-specific quantum executor. |
shots | int | Number of shots to run. |
bindings | dict[str, Any] | None | Parameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2} |
Returns:
SampleJob[Any] — SampleJob that resolves to SampleResult with results.
Raises:
ExecutionError— If no quantum circuit to executeValueError— If required parameters are missing
Example:
job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results) # [(0.25, 500), (0.75, 500)]FrontendTransformError [source]¶
class FrontendTransformError(QamomileCompileError)Error during frontend AST-to-builder lowering.
InlinePass [source]¶
class InlinePass(Pass[Block, Block])Inline all CallBlockOperations to create an affine block.
This pass recursively inlines function calls while preserving control flow structures (For, If, While).
Input: Block with BlockKind.HIERARCHICAL (may contain CallBlockOperations) Output: Block with BlockKind.AFFINE (no CallBlockOperations)
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockInline all CallBlockOperations.
Self-recursive CallBlockOperations (ones whose .block is the
block currently being expanded) are unrolled one level per
call: the inner self-call is substituted but left intact so
that the outer fixed-point loop (inline ↔ partial_eval in
Transpiler.transpile) can fold the base-case if between
iterations. The output kind is AFFINE when no
CallBlockOperations remain, otherwise HIERARCHICAL.
ParameterShapeResolutionPass [source]¶
class ParameterShapeResolutionPass(Pass[Block, Block])Substitute symbolic parameter array shape dims with concrete constants.
Input: BlockKind.HIERARCHICAL (runs before InlinePass).
Output: same block kind, with matching shape dim Values constant-folded.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None) -> NoneAttributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockPartialEvaluationPass [source]¶
class PartialEvaluationPass(Pass[Block, Block])Fold constants and lower compile-time control flow.
Constructor¶
def __init__(self, bindings: dict[str, Any] | None = None)Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockProgramPlan [source]¶
class ProgramPlanExecution plan for a hybrid quantum/classical program.
Structure:
[Optional] Classical preprocessing (parameter computation, etc.)
Single quantum segment (REQUIRED)
[Optional] Expval segment OR classical postprocessing
This plan enforces Qamomile’s current execution model: all quantum operations must be in a single quantum circuit.
Constructor¶
def __init__(
self,
steps: list[ProgramStep] = list(),
abi: ProgramABI = ProgramABI(),
boundaries: list[HybridBoundary] = list(),
parameters: dict[str, Value] = dict(),
) -> NoneAttributes¶
abi: ProgramABIboundaries: list[HybridBoundary]parameters: dict[str, Value]steps: list[ProgramStep]
QKernel [source]¶
class QKernel(Generic[P, R])Decorator class for Qamomile quantum kernels.
Constructor¶
def __init__(self, func: Callable[P, R]) -> NoneAttributes¶
block: Block Compile the function to a hierarchical Block if not already compiled.funcinput_typesnameoutput_typesraw_funcsignature
Methods¶
build¶
def build(self, parameters: list[str] | None = None, **kwargs: Any = {}) -> BlockBuild a traced Block by tracing this kernel.
Parameters:
| Name | Type | Description |
|---|---|---|
parameters | list[str] | None | List of argument names to keep as unbound parameters. - None (default): Auto-detect parameters (non-Qubit args without value/default) - []: No parameters (all non-Qubit args must have value/default) - [“name”]: Explicit parameter list Only float, int, UInt, and their arrays are allowed as parameters. |
**kwargs | Any | Concrete values for non-parameter arguments. |
Returns:
Block — The traced block ready for transpilation, estimation,
or visualization.
Raises:
TypeError— If a non-parameterizable type is specified as parameter.ValueError— If required arguments are missing.
Example:
@qm.qkernel
def circuit(q: Qubit, theta: float) -> Qubit:
q = qm.rx(q, theta)
return q
# Auto-detect theta as parameter
block = circuit.build()
# Explicit parameter list
block = circuit.build(parameters=["theta"])
# theta bound to concrete value
block = circuit.build(theta=0.5)
# Transpile with binding
transpiler = QiskitTranspiler()
result = transpiler.emit(graph, binding={"theta": 0.5})draw¶
def draw(
self,
inline: bool = False,
fold_loops: bool = True,
expand_composite: bool = False,
inline_depth: int | None = None,
**kwargs: Any = {},
) -> AnyVisualize the circuit using Matplotlib.
This method builds the computation graph and creates a static visualization. Parameters are auto-detected: non-Qubit arguments without concrete values are shown as symbolic parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
inline | bool | If True, expand CallBlockOperation contents (inlining). If False (default), show CallBlockOperation as boxes. |
fold_loops | bool | If True (default), display ForOperation as blocks instead of unrolling. If False, expand loops and show all iterations. |
expand_composite | bool | If True, expand CompositeGateOperation (QFT, IQFT, etc.). If False (default), show as boxes. Independent of inline. |
inline_depth | int | None | Maximum nesting depth for inline expansion. None means unlimited (default). 0 means no inlining, 1 means top-level only, etc. Only affects CallBlock/ControlledU, not CompositeGate. |
**kwargs | Any | Concrete values for arguments. Arguments not provided here (and without defaults) will be shown as symbolic parameters. |
Returns:
Any — matplotlib.figure.Figure object.
Raises:
ImportError— If matplotlib is not installed.
Example:
import qamomile.circuit as qm
@qm.qkernel
def inner(q: qm.Qubit) -> qm.Qubit:
return qm.x(q)
@qm.qkernel
def circuit(q: qm.Qubit, theta: float) -> qm.Qubit:
q = inner(q)
q = qm.h(q)
q = qm.rx(q, theta)
return q
# Draw with auto-detected symbolic parameter (theta)
fig = circuit.draw()
# Draw with bound parameter
fig = circuit.draw(theta=0.5)
# Draw with blocks as boxes (default)
fig = circuit.draw()
# Draw with blocks expanded (inlined)
fig = circuit.draw(inline=True)
# Draw with loops folded (shown as blocks)
fig = circuit.draw(fold_loops=True)
# Draw with composite gates expanded
fig = circuit.draw(expand_composite=True)estimate_resources¶
def estimate_resources(self, *, bindings: dict[str, Any] | None = None) -> ResourceEstimateEstimate all resources for this kernel’s circuit.
Convenience method that delegates to the module-level
estimate_resources function, eliminating the need to
access .block directly.
Parameters:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Optional concrete parameter bindings (scalars and dicts). Dict values trigger |key| cardinality substitution. |
Returns:
ResourceEstimate — ResourceEstimate with qubits, gates, and parameters.
Example:
>>> @qm.qkernel
... def bell() -> qm.Vector[qm.Qubit]:
... q = qm.qubit_array(2)
... q[0] = qm.h(q[0])
... q[0], q[1] = qm.cx(q[0], q[1])
... return q
>>> est = bell.estimate_resources()
>>> print(est.qubits) # 2QamomileCompileError [source]¶
class QamomileCompileError(Exception)Base class for all Qamomile compilation errors.
SegmentationPass [source]¶
class SegmentationPass(Pass[Block, ProgramPlan])Segment a block into a strategy-specific executable program plan.
This pass:
Materializes return operations (syncs output_values from ReturnOperation)
Splits the operation list into quantum and classical segments
Builds a ProgramPlan via the configured segmentation strategy
Input: Block (typically ANALYZED or AFFINE) Output: ProgramPlan
Constructor¶
def __init__(self, strategy: SegmentationStrategy | None = None) -> NoneAttributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> ProgramPlanSegment the block into a ProgramPlan.
SliceBorrowCheckPass [source]¶
class SliceBorrowCheckPass(Pass[Block, Block])Post-fold linearity checker for sliced views and borrow state.
Runs after :class:ConstantFoldingPass (so slice bounds are
concrete where possible) and before segmentation / emit. Walks
the operations of the root block in order, maintaining a borrow
state map modelled on the frontend’s
:attr:ArrayBase._borrowed_indices — a single dict whose
values are slice-view ArrayValue owners or the
_ConsumedSlotMarker sentinel. Direct element borrows
(q[i]) emit no IR operation and are left to the trace-time
validator.
The pass does not flag a leftover slice view at block end —
slice views are affine at the kernel boundary, mirroring how
element borrows behave on a locally-allocated register (the
frontend’s _validate_returned_arrays covers the genuine
leak: returning the parent with a live borrow). Anything that
actually clashes with a live view (direct slot access,
destructive parent consume, overlapping views, use-after-
destroy) is rejected at the eager check points listed in the
module docstring.
Constructor¶
def __init__(self) -> NoneInitialize per-run mutable state to safe defaults.
Attributes¶
name: str Return the pass identifier for tracing/logging.
Methods¶
run¶
def run(self, input: Block) -> BlockRun the borrow tracker over input.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block to check. Expected to be in AFFINE or HIERARCHICAL kind — post-fold but pre-segmentation. |
Returns:
Block — The same Block unchanged (pass-through).
Raises:
ValidationError— If called on an unexpected block kind.SliceBorrowViolationError— If a slice view and a direct access collide, two views overlap, or a use-after- destroy is observed.
SubstitutionConfig [source]¶
class SubstitutionConfigConfiguration for the substitution pass.
Constructor¶
def __init__(self, rules: list[SubstitutionRule] = list()) -> NoneAttributes¶
rules: list[SubstitutionRule]
Methods¶
get_rule_for_name¶
def get_rule_for_name(self, name: str) -> SubstitutionRule | NoneFind a rule matching the given name.
Parameters:
| Name | Type | Description |
|---|---|---|
name | str | Name to look up |
Returns:
SubstitutionRule | None — Matching SubstitutionRule or None
SubstitutionPass [source]¶
class SubstitutionPass(Pass[Block, Block])Pass that substitutes CallBlockOperations and CompositeGateOperations.
This pass traverses the block and applies substitution rules:
For CallBlockOperation: replaces the block reference with the target
For CompositeGateOperation: sets the strategy_name field
The pass preserves the block structure and only modifies matching operations.
Input: Block (any kind) Output: Block with substitutions applied (same kind as input)
Constructor¶
def __init__(self, config: SubstitutionConfig) -> NoneInitialize the pass with configuration.
Parameters:
| Name | Type | Description |
|---|---|---|
config | SubstitutionConfig | Substitution configuration with rules |
Attributes¶
name: str Return pass name.
Methods¶
run¶
def run(self, input: Block) -> BlockApply substitutions to the block.
Parameters:
| Name | Type | Description |
|---|---|---|
input | Block | Block to transform |
Returns:
Block — Block with substitutions applied
SubstitutionRule [source]¶
class SubstitutionRuleA single substitution rule.
Constructor¶
def __init__(
self,
source_name: str,
target: 'Block | QKernel | None' = None,
strategy: str | None = None,
validate_signature: bool = True,
) -> NoneAttributes¶
source_name: strstrategy: str | Nonetarget: ‘Block | QKernel | None’validate_signature: bool
SymbolicShapeValidationPass [source]¶
class SymbolicShapeValidationPass(Pass[Block, Block])Reject unresolved parameter shape dims in compile-time structure ops.
Input: BlockKind.ANALYZED (runs after AnalyzePass).
Output: same block unchanged, or raises QamomileCompileError.
Attributes¶
name: str
Methods¶
run¶
def run(self, input: Block) -> BlockTranspiler [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¶
MAX_UNROLL_DEPTH: intconfig: TranspilerConfig Get the transpiler configuration.
Methods¶
affine_validate¶
def affine_validate(self, block: Block) -> BlockPass 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) -> BlockPass 2: Validate and analyze dependencies.
classical_lowering¶
def classical_lowering(self, block: Block) -> BlockPass 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) -> BlockPass 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:
| Name | Type | Description |
|---|---|---|
separated | ProgramPlan | The separated program to emit |
bindings | dict[str, Any] | None | Parameter values to bind at compile time |
parameters | list[str] | None | Parameter 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) -> BlockPass 1: Inline all CallBlockOperations.
lower_compile_time_ifs¶
def lower_compile_time_ifs(self, block: Block, bindings: dict[str, Any] | None = None) -> BlockPass 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) -> BlockPass 1.75: Fold constants and lower compile-time control flow.
plan¶
def plan(self, block: Block) -> ProgramPlanPass 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) -> BlockPass 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) -> NoneSet the transpiler configuration.
Parameters:
| Name | Type | Description |
|---|---|---|
config | TranspilerConfig | Transpiler configuration to use |
slice_borrow_check¶
def slice_borrow_check(self, block: Block) -> BlockPass 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:
A view whose newly-concrete coverage overlaps another live view of the same root parent.
A view whose newly-concrete coverage hits a slot that was consumed by a destructive view operation earlier in the block.
A view that reaches the end of the block while still recorded as the owner of the parent’s slots (i.e. it was never used or never released).
Direct element borrows (q[i]) emit no IR operation, so the
IR-level pass cannot observe them; the trace-time validation
in :func:func_to_block._validate_returned_arrays covers that
path.
The pass is a pass-through for the IR — it only raises on violations and leaves the block unchanged on success.
strip_slice_ops¶
def strip_slice_ops(self, block: Block) -> BlockPass 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) -> BlockPass 0.5: Apply substitutions (optional).
This pass replaces CallBlockOperation targets and sets strategy names on CompositeGateOperations based on config.
Parameters:
| Name | Type | Description |
|---|---|---|
block | Block | Block 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,
) -> BlockConvert a QKernel to a Block.
Parameters:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to convert |
bindings | dict[str, Any] | None | Concrete values to bind at trace time (resolves array shapes) |
parameters | list[str] | None | Names 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) -> TCompile and extract just the quantum circuit.
This is a convenience method for when you just want the backend circuit without the full executable.
Parameters:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to compile |
bindings | dict[str, Any] | None | Parameter 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:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to compile |
bindings | dict[str, Any] | None | Parameter 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. |
parameters | list[str] | None | Parameter names to preserve as backend parameters |
Returns:
ExecutableProgram[T] — ExecutableProgram ready for execution
Raises:
ValueError— If a name appears in bothbindingsandparameters. A name being in both is ambiguous (placeholder value vs runtime symbol) and used to silently miscompile control-flow predicates that depended on parameter-array elements; rejecting the overlap up front keeps the contract unambiguous.QamomileCompileError— If compilation fails (validation, dependency errors)
Pipeline:
to_block: Convert QKernel to Block
substitute: Apply substitutions (if configured)
resolve_parameter_shapes: Constant-fold symbolic Vector param dims
inline: Inline CallBlockOperations
affine_validate: Validate affine type semantics
partial_eval: Fold constants and lower compile-time control flow
analyze: Validate and analyze dependencies
validate_symbolic_shapes: Reject unresolved parameter shape dims
plan: Build ProgramPlan (segment into C->Q->C steps)
emit: Generate backend-specific code
unroll_recursion¶
def unroll_recursion(self, block: Block, bindings: dict[str, Any] | None = None) -> BlockFixed-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 every residual call
is trapped inside an operation-owned block where partial_eval
cannot fold it (control / inverse of a recursive kernel — raises a
targeted error, see below), or when MAX_UNROLL_DEPTH is reached
(genuinely non-terminating top-level recursion — raises).
Parameters:
| Name | Type | Description |
|---|---|---|
block | Block | The block to unroll. May be HIERARCHICAL (still containing self-referential CallBlockOperations) or already AFFINE (returned unchanged). |
bindings | dict[str, Any] | None | Compile-time bindings used by partial_eval to fold the base-case condition. Defaults to None, meaning no bindings are applied. |
Returns:
Block — The fully unrolled, AFFINE block once no
CallBlockOperation remains. Returned unchanged when the
input already has no calls.
Raises:
FrontendTransformError— If every remainingCallBlockOperationis trapped inside aControlledUOperation.block/InverseBlockOperationblock (a self-recursive kernel was passed toqmc.control/qmc.inverse), or if a genuinely non-terminating top-level recursion does not converge withinMAX_UNROLL_DEPTHiterations. The two cases carry distinct, cause-specific messages.
validate_symbolic_shapes¶
def validate_symbolic_shapes(self, block: Block) -> BlockPass 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.
TranspilerConfig [source]¶
class TranspilerConfigConfiguration for the transpiler pipeline.
This configuration allows customizing the compilation behavior, including decomposition strategies and subroutine substitutions.
Example:
config = TranspilerConfig(
decomposition=DecompositionConfig(
strategy_overrides={"qft": "approximate"},
),
substitutions=SubstitutionConfig(
rules=[
SubstitutionRule("my_oracle", target=optimized_oracle),
],
),
)
transpiler = QiskitTranspiler(config=config)Constructor¶
def __init__(
self,
decomposition: DecompositionConfig = DecompositionConfig(),
substitutions: SubstitutionConfig = SubstitutionConfig(),
) -> NoneAttributes¶
decomposition: DecompositionConfigsubstitutions: SubstitutionConfig
Methods¶
with_strategies¶
@classmethod
def with_strategies(
cls,
strategy_overrides: dict[str, str] | None = None,
**kwargs: Any = {},
) -> 'TranspilerConfig'Create config with strategy overrides.
Parameters:
| Name | Type | Description |
|---|---|---|
strategy_overrides | dict[str, str] | None | Map of gate name to strategy name |
**kwargs | Any | Additional config options |
Returns:
'TranspilerConfig' — TranspilerConfig instance
Example:
config = TranspilerConfig.with_strategies(
strategy_overrides={"qft": "approximate", "iqft": "approximate"}
)qamomile.circuit.transpiler.value_resolver¶
Unified value resolution for transpiler passes.
Several transpiler passes need to resolve an IR Value to a concrete
Python value (int, float, bool). Each pass previously carried its own
copy of the resolution logic with slightly different lookup orders and
naming conventions.
ValueResolver consolidates those into a single class with a
deterministic resolution order:
Context map — caller-supplied
UUID → concrete valuedict (e.g.folded_values,concrete_values).Constant —
value.is_constant() → value.get_const().Compile-time array element —
arr[i]orarr[a:b][i]resolves from the root array’sconst_arraymetadata or binding.Bindings by parameter name —
value.is_parameter() → bindings[param_name].Bindings by value name —
value.name → bindings[name].Returns
Noneif none of the above match.
Overview¶
| Class | Description |
|---|---|
ArrayValue | An array of typed IR values. |
Value | A typed SSA value in the IR. |
ValueResolver | Resolve IR Values to concrete Python values. |
Classes¶
ArrayValue [source]¶
class ArrayValue(Value[T])An array of typed IR values.
When slice_of is set, this array is a strided view over another
array. Element accesses on a sliced ArrayValue resolve to
physical slots on the root parent via the affine map
parent_index = slice_start + slice_step * view_local_index,
applied recursively along slice_of chains. The emit-time
resolver walks this chain to produce the final qubit index; passes
that substitute or clone values must treat slice_of /
slice_start / slice_step as Value references that need to
track through the same mapping as parent_array.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
shape: tuple[Value, ...] = tuple(),
slice_of: 'ArrayValue | None' = None,
slice_start: 'Value | None' = None,
slice_step: 'Value | None' = None,
) -> NoneAttributes¶
logical_id: strmetadata: ValueMetadataname: strshape: tuple[Value, ...]slice_of: ‘ArrayValue | None’slice_start: ‘Value | None’slice_step: ‘Value | None’type: Tuuid: str
Methods¶
is_slice¶
def is_slice(self) -> boolReturn True if this array is a strided view of another array.
Returns:
bool — True iff slice_of is non-None.
next_version¶
def next_version(self) -> ArrayValue[T]Value [source]¶
class Value(_MetadataValueMixin, Generic[T])A typed SSA value in the IR.
The name field is display-only: it labels the value for
visualization and error messages and has no role in identity. Identity
is carried by uuid (per-version) and logical_id (across
versions).
An empty string (name="") is the anonymous marker used by
auto-generated tmp values (arithmetic results, comparison results,
coerced constants). Name-based readers must guard with truthiness
(if value.name and value.name in bindings: ...) so anonymous values
never collide on a shared empty key. User-supplied parameter names and
array names continue to be non-empty.
Constructor¶
def __init__(
self,
type: T,
name: str,
version: int = 0,
metadata: ValueMetadata = ValueMetadata(),
uuid: str = (lambda: str(uuid.uuid4()))(),
logical_id: str = (lambda: str(uuid.uuid4()))(),
parent_array: ArrayValue | None = None,
element_indices: tuple[Value, ...] = (),
) -> NoneAttributes¶
element_indices: tuple[Value, ...]logical_id: strmetadata: ValueMetadataname: strparent_array: ArrayValue | Nonetype: Tuuid: strversion: int
Methods¶
is_array_element¶
def is_array_element(self) -> boolnext_version¶
def next_version(self) -> Value[T]Create a new Value with incremented version and fresh UUID.
Metadata is intentionally preserved across versions so that
parameter bindings and constant annotations remain accessible
after the value is updated (e.g. by a gate application or a
classical operation). The logical_id also stays the same:
it identifies the same logical variable across SSA versions,
independently of backend resource allocation. This applies to
every Value regardless of its type (Qubit, Float,
Bit, ...) -- it is not specific to qubits.
ValueResolver [source]¶
class ValueResolverResolve IR Values to concrete Python values.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already resolved values. The values may be either raw Python scalars or Value objects; if a Value is found its get_const() is extracted automatically. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user at transpile time. |
Constructor¶
def __init__(
self,
context: dict[str, Any] | None = None,
bindings: dict[str, Any] | None = None,
)Create a resolver with optional context and bindings.
Parameters:
| Name | Type | Description |
|---|---|---|
context | dict[str, Any] | None | UUID-keyed map of already-resolved values. Defaults to None. |
bindings | dict[str, Any] | None | Name-keyed parameter bindings supplied by the user. Defaults to None. |
Methods¶
resolve¶
def resolve(self, value: Any) -> Any | NoneResolve a Value-like object to a concrete Python value.
If value is not a Value-like object (no uuid attribute) it
is returned as-is — the caller already has a concrete value.
Parameters:
| Name | Type | Description |
|---|---|---|
value | Any | The Value-like object or already concrete value to resolve. |
Returns:
Any | None — Any | None: The resolved concrete value, the original
concrete value for non-Value inputs, or None when no
resolution rule applies.