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

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

qamomile.circuit.frontend


qamomile.circuit.frontend.ast_transform

Overview

FunctionDescription
collect_quantum_rebind_violationsAnalyze func for forbidden quantum rebind patterns.
emit_ifBuilder function for if-else conditional with Phi function merging.
for_itemsBuilder function to create a for-items loop in Qamomile frontend.
for_loopBuilder function to create a for loop in Qamomile frontend.
should_trace_for_loopDecide whether a qmc.range body must be traced.
transform_control_flow
while_loopCreate a while loop whose condition is a measurement result.
ClassDescription
ControlFlowTransformer
QuantumRebindAnalyzerDetects forbidden quantum variable reassignment at the AST level.
RebindSourceKindDiscriminator for the source of a detected rebind violation.
RebindViolationA detected forbidden quantum variable rebinding.
VariableCollectorCollect variables used and mutated within a block.

Functions

collect_quantum_rebind_violations [source]

def collect_quantum_rebind_violations(func: Callable, quantum_param_names: set[str]) -> list[RebindViolation]

Analyze func for forbidden quantum rebind patterns.

Returns a (possibly empty) list of violations. Never raises on analysis failure – returns [] instead.


emit_if [source]

def emit_if(
    cond_func: Callable,
    true_func: Callable,
    false_func: Callable,
    variables: list,
) -> Any

Builder function for if-else conditional with Phi function merging.

This function is called from AST-transformed code. The AST transformer converts: if condition: true_body else: false_body

Into:

def _cond_N(vars): return condition def _body_N(vars): true_body; return vars def _body_N+1(vars): false_body; return vars result = emit_if(_cond_N, _body_N, _body_N+1, [var_list])

Parameters:

NameTypeDescription
cond_functyping.CallableFunction returning the condition (Bit or bool-like Handle)
true_functyping.CallableFunction executing true branch, returns updated variables
false_functyping.CallableFunction executing false branch, returns updated variables
variableslistList of variables used in the branches

Returns:

typing.Any — Merged variable values after conditional execution (using Phi functions)

Example:

@qkernel
def my_kernel(q: Qubit) -> Qubit:
    result = measure(q)
    if result:
        q = z(q)
    return q

for_items [source]

def for_items(
    d: Dict,
    key_var_names: list[str],
    value_var_name: str,
) -> Generator[tuple[Any, Any], None, None]

Builder function to create a for-items loop in Qamomile frontend.

This context manager creates a ForItemsOperation that iterates over dictionary (key, value) pairs. The operation is always unrolled at transpile time since quantum backends cannot natively iterate over classical data structures.

Parameters:

NameTypeDescription
dDictDict handle to iterate over
key_var_nameslist[str]Names of key unpacking variables (e.g., [“i”, “j”] for tuple keys)
value_var_namestrName of value variable (e.g., “Jij”)

Yields:

tuple[typing.Any, typing.Any] — Tuple of (key_handles, value_handle) for use in loop body

Example:

@qkernel
def ising_cost(
    q: Vector[Qubit],
    ising: Dict[Tuple[UInt, UInt], Float],
    gamma: Float,
) -> Vector[Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q

for_loop [source]

def for_loop(
    start,
    stop,
    step = 1,
    var_name: str = '_loop_idx',
) -> Generator[UInt, None, None]

Builder function to create a for loop in Qamomile frontend.

Parameters:

NameTypeDescription
start``Loop start value (can be Handle or int)
stop``Loop stop value (can be Handle or int)
step``Loop step value (default=1)
var_namestrName of the loop variable (default=“_loop_idx”)

Yields:

UInt — The loop iteration variable (can be used as array index)

Example:

@QKernel
def my_kernel(qubits: Array[Qubit, Literal[3]]) -> Array[Qubit, Literal[3]]:
    for i in qm.range(3):
        qubits[i] = h(qubits[i])
    return qubits

@QKernel
def my_kernel2(qubits: Array[Qubit, Literal[5]]) -> Array[Qubit, Literal[5]]:
    for i in qm.range(1, 4):  # i = 1, 2, 3
        qubits[i] = h(qubits[i])
    return qubits

should_trace_for_loop [source]

def should_trace_for_loop(start: Any, stop: Any, step: Any) -> bool

Decide whether a qmc.range body must be traced.

The frontend executes loop bodies once to capture a ForOperation. When all bounds are concrete and Python’s range would execute zero times, tracing the body would incorrectly leak borrow / destructive-consume state into the enclosing scope. Symbolic or invalid bounds stay conservative and trace the body so the normal compiler validation path reports any errors.

Parameters:

NameTypeDescription
starttyping.AnyLoop start bound.
stoptyping.AnyLoop stop bound.
steptyping.AnyLoop step bound.

Returns:

boolFalse only for statically-known zero-trip loops; True bool — otherwise.


transform_control_flow [source]

def transform_control_flow(func: Callable)

while_loop [source]

def while_loop(cond: Callable) -> Generator[WhileLoop, None, None]

Create a while loop whose condition is a measurement result.

The condition must be a Bit produced by qmc.measure(). Non-measurement conditions (classical variables, constants, comparisons) are accepted at build time but will be rejected by ValidateWhileContractPass during transpilation.

Parameters:

NameTypeDescription
condtyping.CallableA callable (lambda) that returns the loop condition. Must return a Bit handle originating from qmc.measure().

Yields:

WhileLoop — A marker object for the while loop context.

Example::

@qm.qkernel
def repeat_until_zero() -> qm.Bit:
    q = qm.qubit("q")
    q = qm.h(q)
    bit = qm.measure(q)
    while bit:
        q = qm.qubit("q2")
        q = qm.h(q)
        bit = qm.measure(q)
    return bit

Classes

ControlFlowTransformer [source]

class ControlFlowTransformer(ast.NodeTransformer)
Constructor
def __init__(
    self,
    global_names: set[str] | None = None,
    param_names: set[str] | None = None,
    namespace: dict[str, Any] | None = None,
) -> None
Attributes
Methods
visit_AnnAssign
def visit_AnnAssign(self, node: ast.AnnAssign) -> Any

Detect annotated assignments such as a: int = 0 and register the type information.

visit_For
def visit_For(self, node: ast.For) -> Any
visit_FunctionDef
def visit_FunctionDef(self, node: ast.FunctionDef) -> ast.FunctionDef

Process the function body with definition tracking.

Collects parameter names as the initial set of defined variables and delegates to _visit_body_with_tracking for sequential statement processing.

visit_If
def visit_If(self, node: ast.If) -> Any
visit_While
def visit_While(self, node: ast.While) -> Any

QuantumRebindAnalyzer [source]

class QuantumRebindAnalyzer(ast.NodeVisitor)

Detects forbidden quantum variable reassignment at the AST level.

Forbidden patterns (target is an existing quantum variable):

Allowed patterns:

The analyzer is a single-pass ast.NodeVisitor and does not model Python control flow precisely. To keep compile-time-if dead-branch rebinds — which the IR’s CompileTimeIfLoweringPass will later resolve by selecting one branch and discarding the other — from being rejected at decoration time, visit_If / visit_For / visit_While route every branch through :meth:_visit_branch_scope, which snapshots quantum_vars before and restores it after each body / orelse, AND truncates any violations recorded inside the branch back to the pre-branch length. Top-level (non-branch-internal) rebinds are flagged as usual; branch-internal rebinds are deliberately not reported at decoration time. The companion gap on the IR side (AffineValidationPass does not detect silent-discard patterns) is tracked in LIMITATIONS.md.

Constructor
def __init__(self, quantum_param_names: set[str]) -> None

Initialize the analyzer with the kernel’s quantum parameter names.

Parameters:

NameTypeDescription
quantum_param_namesset[str]Names of kernel parameters whose annotated type is a quantum handle (Qubit / Vector[Qubit]). Each is seeded into quantum_vars as its own origin.
Attributes
Methods
visit_AnnAssign
def visit_AnnAssign(self, node: ast.AnnAssign) -> None

Dispatch q: qm.Qubit = expr through the single-assign path.

Parameters:

NameTypeDescription
nodeast.AnnAssignThe annotated assignment statement. Annotation-only forms (q: qm.Qubit with no RHS) are ignored — there is nothing to rebind.
visit_Assign
def visit_Assign(self, node: ast.Assign) -> None

Dispatch a = expr / a, b = expr / a = b = expr.

Parameters:

NameTypeDescription
nodeast.AssignThe assignment statement.
visit_Call
def visit_Call(self, node: ast.Call) -> None

Apply consume effects when a classical-returning call is seen.

_check_single_assign / _check_tuple_assign already invoke :meth:_consume_quantum_args when a classical-returning call appears on the RHS of an assignment. This visitor handles the cases where the same call appears outside an assignment: as a bare expression statement (qm.measure(q)), inside an if / while condition, inside a for iterable, or nested inside any other expression visited via generic_visit. Without this hook, those forms would leave q in quantum_vars and trip a false-positive FRESH_ALLOCATION violation on a later rebind of q.

Re-visiting from inside a covered assignment path is benign: _consume_quantum_args is idempotent — by the time visit_Call runs as part of generic_visit after the assignment dispatch, the relevant origins are already gone from quantum_vars and the second call is a no-op.

Parameters:

NameTypeDescription
nodeast.CallThe call expression.
visit_For
def visit_For(self, node: ast.For) -> None

Visit a for loop’s body and else with branch-local scope.

node.iter is walked first (before the branch-scope snapshot) so that any consume effect inside the iterable expression is reflected in the outer analyzer state. The loop target itself is not modeled — Qamomile’s frontend rewrites qmc.range(...) loops via the control-flow transformer, so the iterator variable is a classical index and never quantum.

Parameters:

NameTypeDescription
nodeast.ForThe for statement.
visit_If
def visit_If(self, node: ast.If) -> None

Visit if/else body with branch-local scope.

node.test is walked first (before the branch-scope snapshot) so that any consume effect inside the condition (e.g. if qm.measure(q):) is reflected in the outer analyzer state, not silently rolled back when the branch scope restores. See :meth:_visit_branch_scope for the snapshot-restore protocol applied to body and orelse.

Parameters:

NameTypeDescription
nodeast.IfThe if statement.
visit_While
def visit_While(self, node: ast.While) -> None

Visit a while loop’s body and else with branch-local scope.

Same protocol as :meth:visit_If. node.test is walked before the branch-scope snapshot.

Parameters:

NameTypeDescription
nodeast.WhileThe while statement.

RebindSourceKind [source]

class RebindSourceKind(enum.StrEnum)

Discriminator for the source of a detected rebind violation.

Each value classifies why the analyzer believes an existing quantum binding is being silently discarded, and lets downstream error-message formatting render a domain-appropriate explanation instead of forcing a generic “different quantum variable” sentence onto, e.g., a fresh allocation.

Members:

DIRECT_ALIAS: q = other_q or q = qs[i]. QUANTUM_ARG: q = f(other_q, ...) where other_q has a different origin than q. FRESH_ALLOCATION: q = qm.qubit(...) / qm.qubit_array(...) — the original quantum state is silently discarded in favor of a freshly allocated one. UNKNOWN_CALL: q = some_func(...) where the call references no known quantum variable and is not a recognized quantum constructor; conservatively treated as a rebind because the original q is not threaded through the RHS. CHAINED_ASSIGNMENT: q1 = q2 = expr where at least one target is an existing quantum variable; chained binding semantics are too ambiguous to verify self-update.

Attributes

RebindViolation [source]

class RebindViolation

A detected forbidden quantum variable rebinding.

Constructor
def __init__(
    self,
    target_name: str,
    source_name: str | None,
    source_kind: RebindSourceKind,
    func_name: str | None,
    lineno: int,
    source_expr: str | None = None,
) -> None
Attributes

VariableCollector [source]

class VariableCollector(ast.NodeVisitor)

Collect variables used and mutated within a block.

Excludes:

Constructor
def __init__(self, global_names: set[str] | None = None)
Attributes
Methods
visit_Assign
def visit_Assign(self, node: ast.Assign)

Visit the RHS first to match Python’s evaluation order.

q1 = qm.h(q1) → RHS q1 (Load) is first → first_context is “Load” cond2 = qm.measure(q2) → RHS q2 (Load) first, LHS cond2 (Store) after

visit_Attribute
def visit_Attribute(self, node: ast.Attribute)

Record the base name of an attribute access.

Global names such as module names (qm.h) are excluded as before, while user variables (qs.shape) are treated as Load.

visit_AugAssign
def visit_AugAssign(self, node: ast.AugAssign)

AugAssign (e.g. x += 1) is an implicit Read-before-Write.

Visit the RHS first and record Name targets as both Load and Store. first_context is “Load” (the existing value is read first).

visit_Call
def visit_Call(self, node: ast.Call)

Exclude the function name of a call.

visit_FunctionDef
def visit_FunctionDef(self, node: ast.FunctionDef)

Skip traversal of inner function definitions.

visit_Name
def visit_Name(self, node: ast.Name)

Collect variable names (only those not in the exclude list).


qamomile.circuit.frontend.composite_gate

Frontend interface for composite gates.

Overview

FunctionDescription
composite_gateDecorator to create a CompositeGate from a qkernel function or as a stub.
get_current_tracer
traceContext manager to set the current tracer.
ClassDescription
BlockUnified block representation for all pipeline stages.
BlockKindClassification of block structure for pipeline stages.
CompositeGateBase class for user-facing composite gate definitions.
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGateTypeRegistry of known composite gate types.
DecompositionStrategyProtocol for defining decomposition strategies.
Qubit
ResourceMetadataResource estimation metadata for composite gates.
Tracer
ValueA typed SSA value in the IR.
Vector1-dimensional array type.

Functions

composite_gate [source]

def composite_gate(
    func: Callable | None = None,
    *,
    stub: bool = False,
    name: str = '',
    num_qubits: int | None = None,
    num_controls: int = 0,
    resource_metadata: ResourceMetadata | None = None,
    gate_type: CompositeGateType = CompositeGateType.CUSTOM,
) -> _WrappedCompositeGate | _StubCompositeGate | Callable[[Callable], _WrappedCompositeGate | _StubCompositeGate]

Decorator to create a CompositeGate from a qkernel function or as a stub.

Usage with qkernel (implementation provided): composite_gate [source](name=“my_qft”) qkernel [source] def my_qft(q0: Qubit, q1: Qubit) -> tuple[Qubit, Qubit]: q0 = h(q0) q0, q1 = cp(q0, q1, pi/2) q1 = h(q1) return q0, q1

# Usage:
q0, q1 = my_qft(q0, q1)

Usage as stub (no implementation, for resource estimation): composite_gate [source]( stub=True, name=“oracle”, num_qubits=5, resource_metadata=ResourceMetadata(query_complexity=100, t_gates=10), ) def oracle(): pass

# Usage:
results = oracle(*qubits)
metadata = oracle.get_resource_metadata()

Parameters:

NameTypeDescription
funcCallable | NoneThe qkernel function (when used without arguments)
stubboolIf True, create a stub gate with no implementation
namestrName for the composite gate
num_qubitsint | NoneNumber of target qubits (required for stub)
num_controlsintNumber of control qubits (default: 0)
resource_metadataResourceMetadata | NoneResourceMetadata for resource estimation (stub mode)
gate_typeCompositeGateTypeThe type of composite gate (default: CUSTOM)

Returns:

_WrappedCompositeGate | _StubCompositeGate | Callable[[Callable], _WrappedCompositeGate | _StubCompositeGate] — A CompositeGate instance that can be called like a gate function.


get_current_tracer [source]

def get_current_tracer() -> Tracer

trace [source]

def trace(tracer: Tracer | None = None) -> Generator[Tracer, None, None]

Context manager to set the current tracer.

Classes

Block [source]

class Block

Unified 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(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check 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

CompositeGate [source]

class CompositeGate(abc.ABC)

Base class for user-facing composite gate definitions.

Subclasses can define composite gates in two ways:

  1. Using _decompose() (recommended for users): Define the gate decomposition using frontend syntax (same as qkernel [source]).

    class QFT(CompositeGate):
        def __init__(self, num_qubits: int):
            self._num_qubits = num_qubits
    
        @property
        def num_target_qubits(self) -> int:
            return self._num_qubits
    
        def _decompose(self, qubits: Vector[Qubit]) -> Vector[Qubit]:
            # Use frontend syntax: qm.h(), qm.cp(), qm.range(), etc.
            n = self._num_qubits
            for j in qmc.range(n - 1, -1, -1):
                qubits[j] = qmc.h(qubits[j])
                for k in qmc.range(j - 1, -1, -1):
                    angle = math.pi / (2 ** (j - k))
                    qubits[j], qubits[k] = qmc.cp(qubits[j], qubits[k], angle)
            return qubits
    
        def _resources(self) -> ResourceMetadata:
            return ResourceMetadata(t_gates=0)
  2. Using get_implementation() (advanced): Return a pre-built Block directly.

Example usage:

# Factory function pattern
def qft(qubits: Vector[Qubit]) -> Vector[Qubit]:
    n = _get_size(qubits)
    return QFT(n)(qubits)

# Direct class usage
result = QFT(3)(*qubit_list)
Attributes
Methods
build_decomposition
def build_decomposition(self, *qubits: Qubit = (), **params: Any = {}) -> Block | None

Build the decomposition circuit dynamically.

Override this method to provide a decomposition that depends on runtime arguments (e.g., QPE needs the unitary Block).

This method is called by InlinePass when inlining composite gates that have dynamic implementations.

Parameters:

NameTypeDescription
*qubitsQubitThe qubits passed to the gate
**paramsAnyAdditional parameters (e.g., unitary for QPE)

Returns:

Block | None — Block containing the decomposition, or None if not available.

Example:

class QPE(CompositeGate):
    def build_decomposition(self, *qubits, **params):
        unitary = params.get("unitary")
        # Build QPE circuit using the unitary
        return self._build_qpe_impl(qubits, unitary)
get_implementation
def get_implementation(self) -> Block | None

Get the implementation Block, if any.

Return None for stub gates (used in resource estimation). Override in subclasses to provide implementation.

Note: If _decompose() is defined, it takes precedence over this method.

get_resource_metadata
def get_resource_metadata(self) -> ResourceMetadata | None

Get resource estimation metadata.

Returns _resources() if defined, otherwise None. Override _resources() to provide resource hints.

get_resources_for_strategy
def get_resources_for_strategy(self, strategy_name: str | None = None) -> ResourceMetadata | None

Get resource metadata for a specific strategy.

Parameters:

NameTypeDescription
strategy_namestr | NoneStrategy to query, or None for default

Returns:

ResourceMetadata | None — ResourceMetadata for the strategy, or None if not available

get_strategy
@classmethod
def get_strategy(cls, name: str | None = None) -> 'DecompositionStrategy | None'

Get a registered decomposition strategy.

Parameters:

NameTypeDescription
namestr | NoneStrategy name, or None for default strategy

Returns:

'DecompositionStrategy | None' — DecompositionStrategy instance, or None if not found

list_strategies
@classmethod
def list_strategies(cls) -> list[str]

List all registered strategy names.

Returns:

list[str] — List of strategy names

register_strategy
@classmethod
def register_strategy(cls, name: str, strategy: 'DecompositionStrategy') -> None

Register a decomposition strategy for this gate type.

Parameters:

NameTypeDescription
namestrStrategy identifier (e.g., “standard”, “approximate”)
strategy'DecompositionStrategy'DecompositionStrategy instance

Example:

QFT.register_strategy("approximate", ApproximateQFTStrategy(k=3))
set_default_strategy
@classmethod
def set_default_strategy(cls, name: str) -> None

Set the default decomposition strategy.

Parameters:

NameTypeDescription
namestrStrategy name to use as default

Raises:


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:

The operands structure is:

The results structure:

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,
) -> None
Attributes

CompositeGateType [source]

class CompositeGateType(enum.Enum)

Registry of known composite gate types.

Attributes

DecompositionStrategy [source]

class DecompositionStrategy(Protocol)

Protocol for defining decomposition strategies.

A decomposition strategy provides:

  1. A unique name for identification

  2. A decompose method that performs the actual decomposition

  3. Resource estimation for the decomposition

Strategies allow the same composite gate to have multiple implementations with different trade-offs (e.g., precision vs. gate count).

Attributes
Methods
decompose
def decompose(self, qubits: tuple['Qubit', ...]) -> tuple['Qubit', ...]

Perform the decomposition.

Parameters:

NameTypeDescription
qubitstuple['Qubit', ...]Input qubits to decompose

Returns:

tuple['Qubit', ...] — Output qubits after decomposition

resources
def resources(self, num_qubits: int) -> 'ResourceMetadata'

Return resource estimates for this decomposition.

Parameters:

NameTypeDescription
num_qubitsintNumber of qubits the gate operates on

Returns:

'ResourceMetadata' — ResourceMetadata with gate counts, depth estimates, etc.


Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

ResourceMetadata [source]

class ResourceMetadata

Resource estimation metadata for composite gates.

Gate count fields mirror GateCount categories.

None semantics:

Fields left as None mean “unknown/unspecified”. During extraction, gate_counter treats None as 0, which may undercount resources if the true value is nonzero. To ensure accurate resource estimates, set all relevant fields explicitly.

When total_gates is set but some of single_qubit_gates, two_qubit_gates, or multi_qubit_gates are None, the extractor emits a UserWarning if the known sub-total is less than total_gates, indicating potentially missing gate category data.

Constructor
def __init__(
    self,
    query_complexity: int | None = None,
    t_gates: int | None = None,
    ancilla_qubits: int = 0,
    total_gates: int | None = None,
    single_qubit_gates: int | None = None,
    two_qubit_gates: int | None = None,
    multi_qubit_gates: int | None = None,
    clifford_gates: int | None = None,
    rotation_gates: int | None = None,
    custom_metadata: dict[str, Any] = dict(),
) -> None
Attributes

Tracer [source]

class Tracer
Constructor
def __init__(self, _operations: list[Operation] = list()) -> None
Attributes
Methods
add_operation
def add_operation(self, op) -> 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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

qamomile.circuit.frontend.constructors

Overview

FunctionDescription
bitCreate a Bit handle from a boolean/int literal or declare a named Bit parameter.
float_Create a Float handle from a float literal or declare a named Float parameter.
get_current_tracer
qubitCreate a new qubit and emit a QInitOperation.
qubit_arrayCreate a new qubit array (vector/matrix/tensor) and emit QInitOperations.
uintCreate a UInt handle from an integer literal or a named parameter.
ClassDescription
ArrayValueAn array of typed IR values.
QInitOperationInitialize the qubit
ValueA typed SSA value in the IR.

Functions

bit [source]

def bit(arg: bool | str | int) -> Bit

Create a Bit handle from a boolean/int literal or declare a named Bit parameter.


float_ [source]

def float_(arg: float | str) -> Float

Create a Float handle from a float literal or declare a named Float parameter.


get_current_tracer [source]

def get_current_tracer() -> Tracer

qubit [source]

def qubit(name: str) -> Qubit

Create a new qubit and emit a QInitOperation.


qubit_array [source]

def qubit_array(
    shape: UInt | int | tuple[UInt | int, ...],
    name: str,
) -> Vector[Qubit] | Matrix[Qubit] | Tensor[Qubit]

Create a new qubit array (vector/matrix/tensor) and emit QInitOperations.


uint [source]

def uint(arg: int | str) -> UInt

Create a UInt handle from an integer literal or a named parameter.

Parameters:

NameTypeDescription
argint | strAn integer literal to bake in as a compile-time constant, or a str naming a symbolic UInt parameter. A bool is rejected: True / False are not valid integer values here even though bool subclasses int. (Sign is not validated here -- a negative literal is accepted and baked in as-is.)

Returns:

UInt — A constant-valued handle for an int argument, or a named symbolic handle for a str argument.

Raises:

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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

QInitOperation [source]

class QInitOperation(Operation)

Initialize the qubit

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

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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.decomposition

Decomposition strategy framework for composite gates.

This module provides the infrastructure for defining multiple decomposition patterns for composite gates, enabling flexible gate synthesis strategies.

Example:

class StandardQFTStrategy:
    @property
    def name(self) -> str:
        return "standard"

    def decompose(self, qubits: tuple[Qubit, ...]) -> tuple[Qubit, ...]:
        # Full precision QFT implementation
        ...

    def resources(self, num_qubits: int) -> ResourceMetadata:
        return ResourceMetadata(...)

class ApproximateQFTStrategy:
    def __init__(self, truncation_depth: int = 3):
        self._k = truncation_depth

    @property
    def name(self) -> str:
        return f"approximate_k{self._k}"

    def decompose(self, qubits: tuple[Qubit, ...]) -> tuple[Qubit, ...]:
        # Truncated rotations QFT
        ...

# Register strategies
QFT.register_strategy("standard", StandardQFTStrategy())
QFT.register_strategy("approximate", ApproximateQFTStrategy(truncation_depth=3))

Overview

FunctionDescription
get_global_registryGet the global strategy registry.
get_strategyGet a strategy from the global registry.
register_strategyRegister a strategy in the global registry.
ClassDescription
DecompositionConfigConfiguration for decomposition strategy selection.
DecompositionStrategyProtocol for defining decomposition strategies.
Qubit
ResourceMetadataResource estimation metadata for composite gates.
StrategyRegistryRegistry for managing decomposition strategies.

Functions

get_global_registry [source]

def get_global_registry() -> StrategyRegistry

Get the global strategy registry.

Returns:

StrategyRegistry — The global StrategyRegistry instance


get_strategy [source]

def get_strategy(
    gate_name: str,
    strategy_name: str | None = None,
) -> DecompositionStrategy | None

Get a strategy from the global registry.

Parameters:

NameTypeDescription
gate_namestrThe gate name
strategy_namestr | NoneThe strategy name (uses “standard” if None)

Returns:

DecompositionStrategy | None — The strategy instance, or None if not found


register_strategy [source]

def register_strategy(gate_name: str, strategy_name: str, strategy: DecompositionStrategy) -> None

Register a strategy in the global registry.

Parameters:

NameTypeDescription
gate_namestrThe gate name (e.g., “qft”, “iqft”)
strategy_namestrThe strategy name (e.g., “standard”, “approximate”)
strategyDecompositionStrategyThe strategy instance

Classes

DecompositionConfig [source]

class DecompositionConfig

Configuration 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',
) -> None
Attributes
Methods
get_strategy_for_gate
def get_strategy_for_gate(self, gate_name: str) -> str

Get the strategy name for a specific gate.

Parameters:

NameTypeDescription
gate_namestrThe 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:

NameTypeDescription
strategy_namestrThe strategy name

Returns:

dict[str, Any] — Dictionary of parameters


DecompositionStrategy [source]

class DecompositionStrategy(Protocol)

Protocol for defining decomposition strategies.

A decomposition strategy provides:

  1. A unique name for identification

  2. A decompose method that performs the actual decomposition

  3. Resource estimation for the decomposition

Strategies allow the same composite gate to have multiple implementations with different trade-offs (e.g., precision vs. gate count).

Attributes
Methods
decompose
def decompose(self, qubits: tuple['Qubit', ...]) -> tuple['Qubit', ...]

Perform the decomposition.

Parameters:

NameTypeDescription
qubitstuple['Qubit', ...]Input qubits to decompose

Returns:

tuple['Qubit', ...] — Output qubits after decomposition

resources
def resources(self, num_qubits: int) -> 'ResourceMetadata'

Return resource estimates for this decomposition.

Parameters:

NameTypeDescription
num_qubitsintNumber of qubits the gate operates on

Returns:

'ResourceMetadata' — ResourceMetadata with gate counts, depth estimates, etc.


Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

ResourceMetadata [source]

class ResourceMetadata

Resource estimation metadata for composite gates.

Gate count fields mirror GateCount categories.

None semantics:

Fields left as None mean “unknown/unspecified”. During extraction, gate_counter treats None as 0, which may undercount resources if the true value is nonzero. To ensure accurate resource estimates, set all relevant fields explicitly.

When total_gates is set but some of single_qubit_gates, two_qubit_gates, or multi_qubit_gates are None, the extractor emits a UserWarning if the known sub-total is less than total_gates, indicating potentially missing gate category data.

Constructor
def __init__(
    self,
    query_complexity: int | None = None,
    t_gates: int | None = None,
    ancilla_qubits: int = 0,
    total_gates: int | None = None,
    single_qubit_gates: int | None = None,
    two_qubit_gates: int | None = None,
    multi_qubit_gates: int | None = None,
    clifford_gates: int | None = None,
    rotation_gates: int | None = None,
    custom_metadata: dict[str, Any] = dict(),
) -> None
Attributes

StrategyRegistry [source]

class StrategyRegistry

Registry for managing decomposition strategies.

This class provides a centralized registry for strategies, allowing them to be looked up by name across the transpiler pipeline.

Example:

registry = StrategyRegistry()
registry.register("qft", "standard", StandardQFTStrategy())
registry.register("qft", "approximate", ApproximateQFTStrategy())

strategy = registry.get("qft", "standard")
Constructor
def __init__(self) -> None

Initialize empty registry.

Methods
get
def get(
    self,
    gate_name: str,
    strategy_name: str | None = None,
) -> DecompositionStrategy | None

Get a strategy for a gate.

Parameters:

NameTypeDescription
gate_namestrThe gate name
strategy_namestr | NoneThe strategy name (uses “standard” if None)

Returns:

DecompositionStrategy | None — The strategy instance, or None if not found

list_gates
def list_gates(self) -> list[str]

List all gates with registered strategies.

Returns:

list[str] — List of gate names

list_strategies
def list_strategies(self, gate_name: str) -> list[str]

List available strategies for a gate.

Parameters:

NameTypeDescription
gate_namestrThe gate name

Returns:

list[str] — List of strategy names

register
def register(
    self,
    gate_name: str,
    strategy_name: str,
    strategy: DecompositionStrategy,
) -> None

Register a strategy for a gate.

Parameters:

NameTypeDescription
gate_namestrThe gate name (e.g., “qft”, “iqft”)
strategy_namestrThe strategy name (e.g., “standard”, “approximate”)
strategyDecompositionStrategyThe strategy instance

qamomile.circuit.frontend.func_to_block

Overview

FunctionDescription
build_param_slotsBuild a ParamSlot tuple for the classical arguments of a kernel.
create_dummy_handleCreate a dummy Handle instance based on ValueType.
create_dummy_inputCreate a dummy input based on parameter type annotation.
func_to_blockConvert a function to a hierarchical Block.
get_current_tracer
handle_type_mapMap Handle type to ValueType.
is_array_typeCheck if type is a Vector, Matrix, or Tensor subclass.
is_dict_typeCheck if type is a Dict handle type.
is_tuple_typeCheck if type is a Tuple handle type.
traceContext manager to set the current tracer.
ClassDescription
ArrayValueAn array of typed IR values.
Bit
BitTypeType representing a classical bit.
BlockUnified block representation for all pipeline stages.
BlockKindClassification of block structure for pipeline stages.
DictDict handle for qkernel functions.
DictTypeType representing a dictionary mapping keys to values.
DictValueA dictionary value stored as stable ordered entries.
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
ObservableHandle representing a Hamiltonian observable parameter.
ObservableTypeType representing a Hamiltonian observable parameter.
ParamKindLifecycle classification for a classical kernel argument.
ParamSlotMetadata for a single classical kernel argument.
QInitOperationInitialize the qubit
Qubit
ReturnOperationExplicit return operation marking the end of a block with return values.
Tracer
TupleTuple handle for qkernel functions.
TupleTypeType representing a tuple of values.
TupleValueA tuple of IR values for structured data.
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.
ValueTypeBase class for all value types in the IR.

Constants

Functions

build_param_slots [source]

def build_param_slots(
    signature: inspect.Signature,
    input_types: dict[str, Any],
    *,
    parameters: list[str] | None = None,
    kwargs: dict[str, Any] | None = None,
    qubit_sizes: dict[str, int] | None = None,
    bind_defaults: bool,
) -> tuple[ParamSlot, ...]

Build a ParamSlot tuple for the classical arguments of a kernel.

Mirrors the argument-classification logic in QKernel._create_traced_block so the resulting slot list reflects the same decisions that drive symbolic-vs-bound input creation. Only classical (non-quantum, non-Tuple, non-Dict) arguments are included; pure-quantum arguments live in Block.input_values instead.

Parameters:

NameTypeDescription
signatureinspect.SignatureThe kernel function’s signature.
input_typesdict[str, Any]Resolved frontend type annotations keyed by argument name (typically QKernel.input_types or the equivalent computed in func_to_block).
parameterslist[str] | NoneNames explicitly requested as runtime parameters via parameters=[...]. None is treated as an empty list.
kwargsdict[str, Any] | NoneConcrete values supplied via bindings / direct kwargs. None is treated as an empty dict.
qubit_sizesdict[str, int] | NoneOptional mapping from Vector[Qubit] parameter names to their integer sizes; these are quantum inputs and are not included in the slot list.
bind_defaultsboolWhen True, Python signature defaults are treated as COMPILE_TIME_BOUND with bound_value=default. When False (e.g., the func_to_block path that does not bake in defaults), defaulted arguments stay RUNTIME_PARAMETER and the default appears only in ParamSlot.default.

Returns:

tuple[ParamSlot, ...] — tuple[ParamSlot, ...]: One slot per classical argument, in the order they appear in signature.parameters.


create_dummy_handle [source]

def create_dummy_handle(value_type: ValueType, name: str = 'dummy', emit_init: bool = True) -> Handle

Create a dummy Handle instance based on ValueType.

Parameters:

NameTypeDescription
value_typeValueTypeThe IR type for the value.
namestrName for the value.
emit_initboolIf True, emit QInitOperation for qubit types (requires active tracer).

Used for creating input parameters during tracing.


create_dummy_input [source]

def create_dummy_input(
    param_type: Any,
    name: str = 'param',
    emit_init: bool = True,
    *,
    shape: tuple[int, ...] | None = None,
) -> Handle

Create a dummy input based on parameter type annotation.

Parameters:

NameTypeDescription
param_typeAnyThe type annotation for the parameter.
namestrName for the value.
emit_initboolIf True, emit QInitOperation for qubit arrays (default: True). Set to False when creating a nested Block’s internal dummy inputs, or when the dummy will receive its qubits from a caller’s CallBlockOperation.
shapetuple[int, ...] | NoneOptional concrete shape for array types. When provided, the dummy array’s shape Values carry compile-time constants instead of symbolic placeholders. Used by call-time sub-kernel specialization so that shape-dependent stdlib helpers (qft / iqft / qpe) resolve get_size to a concrete integer and emit the correct gate sequence. Ignored for non-array types. Default: None (symbolic shape).

Returns:

Handle — A frontend Handle wrapping a dummy Value or ArrayValue suitable for use as a function-parameter input during tracing.

Raises:


func_to_block [source]

def func_to_block(func: Callable) -> Block

Convert a function to a hierarchical Block.

Example:

def my_func(a: UInt, b: UInt) -> tuple[UInt]:
    c = a + b
    return (c, )

block = func_to_block(my_func)

get_current_tracer [source]

def get_current_tracer() -> Tracer

handle_type_map [source]

def handle_type_map(handle_type: type[Handle] | type) -> ValueType

Map Handle type to ValueType.


is_array_type [source]

def is_array_type(t: Any) -> bool

Check if type is a Vector, Matrix, or Tensor subclass.


is_dict_type [source]

def is_dict_type(t: Any) -> bool

Check if type is a Dict handle type.


is_tuple_type [source]

def is_tuple_type(t: Any) -> bool

Check if type is a Tuple handle type.


trace [source]

def trace(tracer: Tracer | None = None) -> Generator[Tracer, None, None]

Context manager to set the current tracer.

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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

BitType [source]

class BitType(ClassicalTypeMixin, ValueType)

Type representing a classical bit.


Block [source]

class Block

Unified 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(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check 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

Dict [source]

class Dict(Handle, Generic[K, V])

Dict handle for qkernel functions.

Represents a dictionary mapping keys to values, commonly used for Ising coefficients like {(i, j): Jij}.

Example:

@qmc.qkernel
def ising_cost(
    q: qmc.Vector[qmc.Qubit],
    ising: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q
Constructor
def __init__(
    self,
    value: DictValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _entries: list[tuple[Handle, Handle]] = list(),
    _size: UInt | None = None,
    _key_type: type | None = None,
) -> None
Attributes
Methods
items
def items(self) -> DictItemsIterator[K, V]

Return an iterator over (key, value) pairs.


DictType [source]

class DictType(ValueType)

Type representing a dictionary mapping keys to values.

Unlike simple types, DictType stores the key and value types, so equality and hashing depend on those types. When key_type and value_type are None, represents a generic Dict type.

Quantum/classical classification is derived from key/value types.

Constructor
def __init__(
    self,
    key_type: ValueType | None = None,
    value_type: ValueType | None = None,
) -> None
Attributes
Methods
is_classical
def is_classical(self) -> bool
is_quantum
def is_quantum(self) -> bool
label
def label(self) -> str

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()))(),
) -> None
Attributes
Methods
is_constant
def is_constant(self) -> bool
next_version
def next_version(self) -> DictValue

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


Observable [source]

class Observable(Handle)

Handle representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1) + 0.5 * qm_o.X(0)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    # Use Hamiltonian from bindings
    return qm.expval(q, H)

# Pass via bindings
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None

ObservableType [source]

class ObservableType(ObjectTypeMixin, ValueType)

Type representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example usage:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    return qm.expval(q, H)

# H is passed as binding
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(self) -> None

ParamKind [source]

class ParamKind(enum.Enum)

Lifecycle classification for a classical kernel argument.

Values:

RUNTIME_PARAMETER: The argument is intended to be bound at execution time by the backend (or, more generally, by the outer caller in a hybrid loop). It survives the compilation pipeline as a symbolic parameter. COMPILE_TIME_BOUND: The argument was provided as a binding (or via a Python default) and is folded into the IR by resolve_parameter_shapes / partial_eval. No symbolic counterpart remains in the emitted circuit.

Attributes

ParamSlot [source]

class ParamSlot

Metadata for a single classical kernel argument.

A ParamSlot describes one position in the kernel’s classical parameter contract — its declared type, whether it is a runtime parameter or a compile-time-bound value, the Python default (if any), the actually-bound value (when kind is COMPILE_TIME_BOUND), and any outer-DSL hints. Slots are immutable; pipeline passes that need to update a slot must clone via dataclasses.replace.

The slot is identified by name, which matches the kernel’s Python parameter name and the corresponding entry in Block.label_args. A slot’s name MUST never overlap between RUNTIME_PARAMETER and COMPILE_TIME_BOUND instances within one Block (this mirrors the project-level bindings / parameters disjointness rule).

Constructor
def __init__(
    self,
    name: str,
    type: 'ValueType',
    kind: ParamKind,
    ndim: int = 0,
    default: Any = None,
    bound_value: Any = None,
    differentiable: bool = False,
) -> None
Attributes

QInitOperation [source]

class QInitOperation(Operation)

Initialize the qubit

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

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

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()) -> None
Attributes

Tracer [source]

class Tracer
Constructor
def __init__(self, _operations: list[Operation] = list()) -> None
Attributes
Methods
add_operation
def add_operation(self, op) -> None

Tuple [source]

class Tuple(Handle, Generic[K, V])

Tuple handle for qkernel functions.

Represents a tuple of values, commonly used for multi-index keys like (i, j) in Ising models.

Example:

@qmc.qkernel
def my_kernel(idx: qmc.Tuple[qmc.UInt, qmc.UInt]) -> qmc.UInt:
    i, j = idx
    return i + j
Constructor
def __init__(
    self,
    value: TupleValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _elements: tuple[Handle, ...] = tuple(),
) -> None
Attributes

TupleType [source]

class TupleType(ValueType)

Type representing a tuple of values.

Unlike simple types, TupleType stores the types of its elements, so equality and hashing depend on the element types.

Quantum/classical classification is derived from element types: quantum if any element is quantum, classical if all are classical.

Constructor
def __init__(self, element_types: tuple[ValueType, ...]) -> None
Attributes
Methods
is_classical
def is_classical(self) -> bool
is_quantum
def is_quantum(self) -> bool
label
def label(self) -> str

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()))(),
) -> None
Attributes
Methods
is_constant
def is_constant(self) -> bool
next_version
def next_version(self) -> TupleValue

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


ValueType [source]

class ValueType(abc.ABC)

Base class for all value types in the IR.

Type instances are compared by class - all instances of the same type class are considered equal. This allows using type instances as dictionary keys where all QubitType() instances match.

Methods
is_classical
def is_classical(self) -> bool
is_object
def is_object(self) -> bool
is_quantum
def is_quantum(self) -> bool
label
def label(self) -> str

qamomile.circuit.frontend.handle

Overview

FunctionDescription
get_sizeReturn the size of a Vector handle as a Python integer.
ClassDescription
Bit
DictDict handle for qkernel functions.
FloatFloating-point handle with arithmetic operations.
Handle
Matrix2-dimensional array type.
ObservableHandle representing a Hamiltonian observable parameter.
QFixed
Qubit
TensorN-dimensional array type (3 or more dimensions).
TupleTuple handle for qkernel functions.
UIntUnsigned integer handle with arithmetic operations.
Vector1-dimensional array type.
VectorViewStrided view over a parent Vector, backed by a sliced ArrayValue.

Functions

get_size [source]

def get_size(arr: Vector[_H]) -> int

Return the size of a Vector handle as a Python integer.

Resolves the leading axis of arr.shape through two forms a Vector shape entry can take:

  1. A plain Python int (built-in bound shape; this is what you get from qmc.qubit_array(N, ...) for literal N).

  2. A UInt handle whose underlying Value carries a compile-time constant (set by uint(literal), _create_bound_input, or partial evaluation).

A UInt handle whose underlying Value is not a constant is treated as an unresolved symbolic dimension and raises ValueError even when the handle has the dataclass-default init_value=0. Falling back to init_value for that case would silently turn a runtime-symbolic Vector[Float] parameter into a “size 0” array, hiding programming errors. Callers that need to handle symbolic shapes (e.g., to gracefully no-op when the size is unknown) must catch the ValueError themselves.

Parameters:

NameTypeDescription
arrVector[Handle]Vector handle whose first axis size is requested.

Returns:

int — The first-axis size as a plain Python int.

Raises:

Classes

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

Dict [source]

class Dict(Handle, Generic[K, V])

Dict handle for qkernel functions.

Represents a dictionary mapping keys to values, commonly used for Ising coefficients like {(i, j): Jij}.

Example:

@qmc.qkernel
def ising_cost(
    q: qmc.Vector[qmc.Qubit],
    ising: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q
Constructor
def __init__(
    self,
    value: DictValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _entries: list[tuple[Handle, Handle]] = list(),
    _size: UInt | None = None,
    _key_type: type | None = None,
) -> None
Attributes
Methods
items
def items(self) -> DictItemsIterator[K, V]

Return an iterator over (key, value) pairs.


Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


Matrix [source]

class Matrix(ArrayBase[T])

2-dimensional array type.

Example:

import qamomile as qm

# Create a 3x4 matrix of qubits
matrix: qm.Matrix[qm.Qubit] = qm.Matrix(shape=(3, 4))

# Access elements (always requires 2 indices)
q = matrix[0, 1]
q = qm.h(q)
matrix[0, 1] = q
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, int | UInt] = (0, 0),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

Observable [source]

class Observable(Handle)

Handle representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1) + 0.5 * qm_o.X(0)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    # Use Hamiltonian from bindings
    return qm.expval(q, H)

# Pass via bindings
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None

QFixed [source]

class QFixed(Handle)
Constructor
def __init__(
    self,
    value: Value[QFixedType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

Tensor [source]

class Tensor(ArrayBase[T])

N-dimensional array type (3 or more dimensions).

Example:

import qamomile as qm

# Create a 2x3x4 tensor of qubits
tensor: qm.Tensor[qm.Qubit] = qm.Tensor(shape=(2, 3, 4))

# Access elements (requires all indices)
q = tensor[0, 1, 2]
q = qm.h(q)
tensor[0, 1, 2] = q
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

Tuple [source]

class Tuple(Handle, Generic[K, V])

Tuple handle for qkernel functions.

Represents a tuple of values, commonly used for multi-index keys like (i, j) in Ising models.

Example:

@qmc.qkernel
def my_kernel(idx: qmc.Tuple[qmc.UInt, qmc.UInt]) -> qmc.UInt:
    i, j = idx
    return i + j
Constructor
def __init__(
    self,
    value: TupleValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _elements: tuple[Handle, ...] = tuple(),
) -> None
Attributes

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

VectorView [source]

class VectorView(Vector[T])

Strided view over a parent Vector, backed by a sliced ArrayValue.

A VectorView is produced by slicing a Vector (q[1::2], q[a:b], etc.). It is a thin Vector subclass whose value is a fresh ArrayValue with slice_of / slice_start / slice_step metadata pointing back to the parent’s ArrayValue. Element accesses go through Vector._get_element unchanged — the IR element carries parent_array = sliced_av, and the emit-time resolver walks the slice_of chain to produce the physical qubit index. No affine translation happens in the view itself.

Because the sliced ArrayValue is a first-class IR Value, the view can be passed as an operand of CallBlockOperation to another @qkernel without the inline-trace special-case path that earlier iterations required. Passing views through expval / measure likewise operates on the sliced qubit subset, not the root parent as a whole.

Linearity:

Slicing bulk-borrows the covered parent slots whenever start, step and length are compile-time int constants. While the view is live, accessing the corresponding parent slot directly (q[0] after evens = q[0::2]) raises QubitConsumedError. Under the strict-return policy the view’s ownership is cleared only by two operations:

Every other consume (broadcast gates h(view), pauli_evolve(view, H, gamma), sub-kernel calls f(view), controlled-U index_spec) only transfers ownership to a freshly-wrapped VectorView and that new view still must be returned via slice assignment. A view left bulk-borrowing at the parent’s consume point raises UnreturnedBorrowError.

Symbolic slices (q[lo:hi] with lo/hi UInt) cannot enumerate their covered slots at trace time and therefore skip the bulk-borrow here; SliceBorrowCheckPass picks them up post-fold after bindings resolve the bounds to concrete values.

Example:

@qmc.qkernel
def alternating_h(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]:
    evens = q[0::2]
    for i in qmc.range(evens.shape[0]):
        evens[i] = qmc.h(evens[i])
    q[0::2] = evens  # explicit return before the parent is used
    return q
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the view and release its parent slice-borrows.

Validates that every view-local borrow has been returned, then dispatches on operation_name to keep the parent’s slice-borrow record consistent with the new strict-return semantics:

Operations that produce a fresh sliced ArrayValue (e.g. :func:qamomile.circuit.frontend.operation.pauli_evolve.pauli_evolve, :class:QKernel.__call__ for callees that return a sliced array) cannot simply use the auto-returned new_view because the new view they build wraps a different Value than this consume’s return. Those op implementations call :meth:_transfer_borrow_to after building their result so the parent’s borrow table tracks the right handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this view (used in error messages and for dispatch).

Returns:

typing.Self — A fresh view handle with the same backing state; under typing.Self — transfer the parent’s borrow table now points at this typing.Self — handle, under release / destruction the parent’s record typing.Self — for the covered slots is finalised.

Raises:


qamomile.circuit.frontend.handle.array

Overview

FunctionDescription
get_current_tracer
is_plain_intReturn True if value is a Python int but not a bool.
ClassDescription
AffineTypeErrorBase class for affine type violations.
ArrayBaseBase class for array types (Vector, Matrix, Tensor).
ArrayValueAn array of typed IR values.
BinOpKind
Bit
BitTypeType representing a classical bit.
CInitOperationInitialize the classical values (const, arguments etc)
ConsumeModeClassify how a VectorView.consume call resolves slice borrows.
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
Handle
Matrix2-dimensional array type.
QInitOperationInitialize the qubit
Qubit
QubitBorrowConflictErrorQubit slot inaccessible because another live handle borrows it.
QubitConsumedErrorQubit handle used after being consumed by a previous operation.
QubitTypeType representing a quantum bit (qubit).
ReleaseSliceViewOperationMark a slice view’s borrow as explicitly returned to its parent.
SliceArrayOperationConstruct a strided view of an ArrayValue.
TensorN-dimensional array type (3 or more dimensions).
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
UnreturnedBorrowErrorBorrowed array element not returned before array use.
ValueA typed SSA value in the IR.
Vector1-dimensional array type.
VectorViewStrided view over a parent Vector, backed by a sliced ArrayValue.

Functions

get_current_tracer [source]

def get_current_tracer() -> Tracer

is_plain_int [source]

def is_plain_int(value: object) -> bool

Return True if value is a Python int but not a bool.

bool is a subclass of int in Python, so isinstance(True, int) is True. This helper distinguishes a genuine integer from a boolean, which matters wherever a boolean must be rejected in an integer slot — for example, validating decoded wire data or a register width.

Parameters:

NameTypeDescription
valueobjectThe value to test.

Returns:

boolTrue when value is an int and not a bool.

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

ArrayBase [source]

class ArrayBase(Handle, Generic[T])

Base class for array types (Vector, Matrix, Tensor).

Provides common functionality for array indexing and element access.

Constructor
def __init__(
    self,
    value: ArrayValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the array, enforcing borrow-return contract for quantum arrays.

For quantum arrays, all borrowed elements must be returned before the array can be consumed. This ensures that no unreturned borrows are silently discarded by operations like qkernel calls or controlled gates.

When any slot of the array has already been physically consumed by an earlier destructive view operation (measure(q[1::2]) then measure(q)), this raises QubitConsumedError rather than silently re-consuming those slots.

create
@classmethod
def create(
    cls,
    shape: tuple[int | UInt, ...],
    name: str,
    el_type: Type[T],
) -> 'ArrayBase[T]'

Create an ArrayValue for the given shape and name.

validate_all_returned
def validate_all_returned(self) -> None

Validate all borrowed elements have been returned.

Strict-return policy: an active slice view that is still registered as the owner of any parent slot is treated as an unreturned borrow even if the view itself has no outstanding element borrows. The caller must perform an explicit slice assignment (parent[a:b:c] = view) to release the view’s bulk-borrow before consuming the parent. Destructively consumed views (parked in the dict with view._consumed set and view._consumed_by classified as :attr:ConsumeMode.DESTRUCTIVE) record physically-destroyed slots and are not outstanding borrows; they survive end-of-block so a later whole-array consume can detect and reject the destroyed slots.

Raises:


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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

BinOpKind [source]

class BinOpKind(enum.Enum)
Attributes

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

BitType [source]

class BitType(ClassicalTypeMixin, ValueType)

Type representing a classical bit.


CInitOperation [source]

class CInitOperation(Operation)

Initialize the classical values (const, arguments etc)

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

ConsumeMode [source]

class ConsumeMode(enum.Enum)

Classify how a VectorView.consume call resolves slice borrows.

ArrayBase.consume and VectorView.consume accept a free-form operation_name string used both for error messages and for dispatching how the parent’s bulk-borrow table is updated. The string itself is purely cosmetic; the dispatch logic only cares about which of three resolution modes applies, captured by this enum:

Attributes

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


Matrix [source]

class Matrix(ArrayBase[T])

2-dimensional array type.

Example:

import qamomile as qm

# Create a 3x4 matrix of qubits
matrix: qm.Matrix[qm.Qubit] = qm.Matrix(shape=(3, 4))

# Access elements (always requires 2 indices)
q = matrix[0, 1]
q = qm.h(q)
matrix[0, 1] = q
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, int | UInt] = (0, 0),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

QInitOperation [source]

class QInitOperation(Operation)

Initialize the qubit

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

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

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 safe

Example 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 borrowed

Correct code::

q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0  # return the element first
q1 = qubits[1]  # now safe

QubitConsumedError [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


QubitType [source]

class QubitType(QuantumTypeMixin, ValueType)

Type representing a quantum bit (qubit).


ReleaseSliceViewOperation [source]

class ReleaseSliceViewOperation(Operation)

Mark a slice view’s borrow as explicitly returned to its parent.

Emitted by :meth:Vector.__setitem__ when used with a slice index (qs[a:b] = qmc.h(qs[a:b])). This op tells the post-fold linearity checker (:class:~qamomile.circuit.transpiler.passes.slice_borrow_check.SliceBorrowCheckPass) that the view referenced in operands[0] no longer owns its covered parent slots, mirroring the frontend’s VectorView.consume(operation_name="slice assignment") borrow release.

Like :class:SliceArrayOperation, this op is a declarative classical-side marker that does not survive into the emit stream: :class:~qamomile.circuit.transpiler.passes.strip_slice_ops.StripSliceArrayOpsPass removes both :class:SliceArrayOperation and :class:ReleaseSliceViewOperation after :class:SliceBorrowCheckPass has observed them. Reaching emit is a compiler-internal invariant violation and is rejected with a RuntimeError from :mod:standard_emit.

Within a control-flow body (ForOperation / WhileOperation / IfOperation), this op only releases view borrows that were created within the same body. Releasing a borrow that the enclosing block has registered (an “outer-snapshot” borrow) is rejected by SliceBorrowCheckPass with SliceBorrowViolationError — the loop-merge semantics of the pass cannot propagate entry deletions out of the body, so the only way to keep the static check consistent is to forbid that pattern.

Example:

``qs[1:3] = qmc.h(qs[1:3])`` emits, after the broadcast loop::

    ReleaseSliceViewOperation(
        operands=[qmc_h_result_view],  # slice_of=qs_value
        results=[],
    )
Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes

SliceArrayOperation [source]

class SliceArrayOperation(Operation)

Construct a strided view of an ArrayValue.

The op itself performs no quantum action — it records that the result ArrayValue is a strided view of the operand parent with the given start / step. The result’s slice_of / slice_start / slice_step fields carry the affine map used by the emit-time resolver.

SliceArrayOperation is classified as :attr:OperationKind.CLASSICAL because slicing is pure index selection — no new quantum operation is introduced. The pipeline keeps this op through PartialEvaluationPass (which invokes ConstantFoldingPass(..., strip_slice_ops=False)) so the post-fold :class:~qamomile.circuit.transpiler.passes.slice_borrow_check.SliceBorrowCheckPass can use it as a view-declaration marker; once that check has run, StripSliceArrayOpsPass removes every SliceArrayOperation / ReleaseSliceViewOperation so segmentation (:mod:~qamomile.circuit.transpiler.passes.separate) and the downstream emit stage only see a pure quantum-op stream. By the time :mod:~qamomile.circuit.transpiler.passes.separate runs the op has therefore been stripped — reaching emit is a compiler- internal invariant violation.

Example:

``q[1::2]`` on a ``Vector[Qubit]`` emits::

    SliceArrayOperation(
        operands=[q_value, uint_1, uint_2],
        results=[sliced_value],  # slice_of=q_value, slice_start=uint_1, slice_step=uint_2
    )
Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes

Tensor [source]

class Tensor(ArrayBase[T])

N-dimensional array type (3 or more dimensions).

Example:

import qamomile as qm

# Create a 2x3x4 tensor of qubits
tensor: qm.Tensor[qm.Qubit] = qm.Tensor(shape=(2, 3, 4))

# Access elements (requires all indices)
q = tensor[0, 1, 2]
q = qm.h(q)
tensor[0, 1, 2] = q
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


UnreturnedBorrowError [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


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

VectorView [source]

class VectorView(Vector[T])

Strided view over a parent Vector, backed by a sliced ArrayValue.

A VectorView is produced by slicing a Vector (q[1::2], q[a:b], etc.). It is a thin Vector subclass whose value is a fresh ArrayValue with slice_of / slice_start / slice_step metadata pointing back to the parent’s ArrayValue. Element accesses go through Vector._get_element unchanged — the IR element carries parent_array = sliced_av, and the emit-time resolver walks the slice_of chain to produce the physical qubit index. No affine translation happens in the view itself.

Because the sliced ArrayValue is a first-class IR Value, the view can be passed as an operand of CallBlockOperation to another @qkernel without the inline-trace special-case path that earlier iterations required. Passing views through expval / measure likewise operates on the sliced qubit subset, not the root parent as a whole.

Linearity:

Slicing bulk-borrows the covered parent slots whenever start, step and length are compile-time int constants. While the view is live, accessing the corresponding parent slot directly (q[0] after evens = q[0::2]) raises QubitConsumedError. Under the strict-return policy the view’s ownership is cleared only by two operations:

Every other consume (broadcast gates h(view), pauli_evolve(view, H, gamma), sub-kernel calls f(view), controlled-U index_spec) only transfers ownership to a freshly-wrapped VectorView and that new view still must be returned via slice assignment. A view left bulk-borrowing at the parent’s consume point raises UnreturnedBorrowError.

Symbolic slices (q[lo:hi] with lo/hi UInt) cannot enumerate their covered slots at trace time and therefore skip the bulk-borrow here; SliceBorrowCheckPass picks them up post-fold after bindings resolve the bounds to concrete values.

Example:

@qmc.qkernel
def alternating_h(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]:
    evens = q[0::2]
    for i in qmc.range(evens.shape[0]):
        evens[i] = qmc.h(evens[i])
    q[0::2] = evens  # explicit return before the parent is used
    return q
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the view and release its parent slice-borrows.

Validates that every view-local borrow has been returned, then dispatches on operation_name to keep the parent’s slice-borrow record consistent with the new strict-return semantics:

Operations that produce a fresh sliced ArrayValue (e.g. :func:qamomile.circuit.frontend.operation.pauli_evolve.pauli_evolve, :class:QKernel.__call__ for callees that return a sliced array) cannot simply use the auto-returned new_view because the new view they build wraps a different Value than this consume’s return. Those op implementations call :meth:_transfer_borrow_to after building their result so the parent’s borrow table tracks the right handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this view (used in error messages and for dispatch).

Returns:

typing.Self — A fresh view handle with the same backing state; under typing.Self — transfer the parent’s borrow table now points at this typing.Self — handle, under release / destruction the parent’s record typing.Self — for the covered slots is finalised.

Raises:


qamomile.circuit.frontend.handle.containers

Container types for qkernel: Tuple and Dict handles.

Overview

ClassDescription
DictDict handle for qkernel functions.
DictItemsIteratorIterator for Dict.items() that yields (key, value) pairs.
DictValueA dictionary value stored as stable ordered entries.
Handle
TupleTuple handle for qkernel functions.
TupleValueA tuple of IR values for structured data.
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.

Classes

Dict [source]

class Dict(Handle, Generic[K, V])

Dict handle for qkernel functions.

Represents a dictionary mapping keys to values, commonly used for Ising coefficients like {(i, j): Jij}.

Example:

@qmc.qkernel
def ising_cost(
    q: qmc.Vector[qmc.Qubit],
    ising: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q
Constructor
def __init__(
    self,
    value: DictValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _entries: list[tuple[Handle, Handle]] = list(),
    _size: UInt | None = None,
    _key_type: type | None = None,
) -> None
Attributes
Methods
items
def items(self) -> DictItemsIterator[K, V]

Return an iterator over (key, value) pairs.


DictItemsIterator [source]

class DictItemsIterator(Generic[K, V])

Iterator for Dict.items() that yields (key, value) pairs.

This is used internally for iterating over Dict entries in qkernel.

Constructor
def __init__(self, dict_handle: 'Dict[K, V]', _index: int = 0) -> None
Attributes

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()))(),
) -> None
Attributes
Methods
is_constant
def is_constant(self) -> bool
next_version
def next_version(self) -> DictValue

Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


Tuple [source]

class Tuple(Handle, Generic[K, V])

Tuple handle for qkernel functions.

Represents a tuple of values, commonly used for multi-index keys like (i, j) in Ising models.

Example:

@qmc.qkernel
def my_kernel(idx: qmc.Tuple[qmc.UInt, qmc.UInt]) -> qmc.UInt:
    i, j = idx
    return i + j
Constructor
def __init__(
    self,
    value: TupleValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _elements: tuple[Handle, ...] = tuple(),
) -> None
Attributes

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()))(),
) -> None
Attributes
Methods
is_constant
def is_constant(self) -> bool
next_version
def next_version(self) -> TupleValue

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.handle.hamiltonian

Observable handle for Hamiltonian parameters.

This module provides the Observable handle class that represents a reference to a Hamiltonian observable provided via bindings during transpilation. Unlike HamiltonianExpr in previous versions, this is a pure parameter handle with no arithmetic operations.

Overview

ClassDescription
Handle
ObservableHandle representing a Hamiltonian observable parameter.

Classes

Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


Observable [source]

class Observable(Handle)

Handle representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1) + 0.5 * qm_o.X(0)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    # Use Hamiltonian from bindings
    return qm.expval(q, H)

# Pass via bindings
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None

qamomile.circuit.frontend.handle.handle

Overview

FunctionDescription
evaluate_binop_valuesEvaluate a binary arithmetic operation on two concrete values.
get_current_tracer
ClassDescription
ArithmeticMixinMixin providing arithmetic operations for numeric Handle types.
ArrayBaseBase class for array types (Vector, Matrix, Tensor).
BinOpBinary arithmetic operation (ADD, SUB, MUL, DIV, FLOORDIV, MOD, POW, MIN).
BinOpKind
CompOpComparison operation (EQ, NEQ, LT, LE, GT, GE).
CompOpKind
CondOpConditional logical operation (AND, OR).
CondOpKind
Handle
NotOp
QubitConsumedErrorQubit handle used after being consumed by a previous operation.
UIntUnsigned integer handle with arithmetic operations.
ValueA typed SSA value in the IR.

Functions

evaluate_binop_values [source]

def evaluate_binop_values(
    kind: BinOpKind | None,
    left: float | int,
    right: float | int,
) -> float | int | None

Evaluate a binary arithmetic operation on two concrete values.

Parameters:

NameTypeDescription
kindBinOpKind | NoneThe BinOpKind to apply.
leftfloat | intLeft operand (numeric).
rightfloat | intRight operand (numeric).

Returns:

float | int | None — The result, or None on division by zero, unknown kind, or float | int | None — arithmetic error.


get_current_tracer [source]

def get_current_tracer() -> Tracer

Classes

ArithmeticMixin [source]

class ArithmeticMixin

Mixin providing arithmetic operations for numeric Handle types.

Requires:

Attributes

ArrayBase [source]

class ArrayBase(Handle, Generic[T])

Base class for array types (Vector, Matrix, Tensor).

Provides common functionality for array indexing and element access.

Constructor
def __init__(
    self,
    value: ArrayValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the array, enforcing borrow-return contract for quantum arrays.

For quantum arrays, all borrowed elements must be returned before the array can be consumed. This ensures that no unreturned borrows are silently discarded by operations like qkernel calls or controlled gates.

When any slot of the array has already been physically consumed by an earlier destructive view operation (measure(q[1::2]) then measure(q)), this raises QubitConsumedError rather than silently re-consuming those slots.

create
@classmethod
def create(
    cls,
    shape: tuple[int | UInt, ...],
    name: str,
    el_type: Type[T],
) -> 'ArrayBase[T]'

Create an ArrayValue for the given shape and name.

validate_all_returned
def validate_all_returned(self) -> None

Validate all borrowed elements have been returned.

Strict-return policy: an active slice view that is still registered as the owner of any parent slot is treated as an unreturned borrow even if the view itself has no outstanding element borrows. The caller must perform an explicit slice assignment (parent[a:b:c] = view) to release the view’s bulk-borrow before consuming the parent. Destructively consumed views (parked in the dict with view._consumed set and view._consumed_by classified as :attr:ConsumeMode.DESTRUCTIVE) record physically-destroyed slots and are not outstanding borrows; they survive end-of-block so a later whole-array consume can detect and reject the destroyed slots.

Raises:


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,
) -> None
Attributes

BinOpKind [source]

class BinOpKind(enum.Enum)
Attributes

CompOp [source]

class CompOp(BinaryOperationBase)

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

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

CompOpKind [source]

class CompOpKind(enum.Enum)
Attributes

CondOp [source]

class CondOp(BinaryOperationBase)

Conditional logical operation (AND, OR).

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

CondOpKind [source]

class CondOpKind(enum.Enum)
Attributes

Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


NotOp [source]

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

QubitConsumedError [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


UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.handle.primitives

Overview

ClassDescription
ArithmeticMixinMixin providing arithmetic operations for numeric Handle types.
BinOpKind
Bit
BitTypeType representing a classical bit.
CompOpKind
CondOpKind
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
Handle
QFixed
Qubit
QubitTypeType representing a quantum bit (qubit).
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.

Classes

ArithmeticMixin [source]

class ArithmeticMixin

Mixin providing arithmetic operations for numeric Handle types.

Requires:

Attributes

BinOpKind [source]

class BinOpKind(enum.Enum)
Attributes

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

BitType [source]

class BitType(ClassicalTypeMixin, ValueType)

Type representing a classical bit.


CompOpKind [source]

class CompOpKind(enum.Enum)
Attributes

CondOpKind [source]

class CondOpKind(enum.Enum)
Attributes

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


QFixed [source]

class QFixed(Handle)
Constructor
def __init__(
    self,
    value: Value[QFixedType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

QubitType [source]

class QubitType(QuantumTypeMixin, ValueType)

Type representing a quantum bit (qubit).


UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.handle.utils

Utility helpers for handle types.

Overview

FunctionDescription
get_sizeReturn the size of a Vector handle as a Python integer.
ClassDescription
Handle
Vector1-dimensional array type.

Functions

get_size [source]

def get_size(arr: Vector[_H]) -> int

Return the size of a Vector handle as a Python integer.

Resolves the leading axis of arr.shape through two forms a Vector shape entry can take:

  1. A plain Python int (built-in bound shape; this is what you get from qmc.qubit_array(N, ...) for literal N).

  2. A UInt handle whose underlying Value carries a compile-time constant (set by uint(literal), _create_bound_input, or partial evaluation).

A UInt handle whose underlying Value is not a constant is treated as an unresolved symbolic dimension and raises ValueError even when the handle has the dataclass-default init_value=0. Falling back to init_value for that case would silently turn a runtime-symbolic Vector[Float] parameter into a “size 0” array, hiding programming errors. Callers that need to handle symbolic shapes (e.g., to gracefully no-op when the size is unknown) must catch the ValueError themselves.

Parameters:

NameTypeDescription
arrVector[Handle]Vector handle whose first axis size is requested.

Returns:

int — The first-axis size as a plain Python int.

Raises:

Classes

Handle [source]

class Handle(abc.ABC)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Mark this handle as consumed and return a fresh handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this handle, used for error messages.

Returns:

typing.Self — A new handle pointing to the same underlying value.

Raises:


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

qamomile.circuit.frontend.operation


qamomile.circuit.frontend.operation.cast

Cast operation for type conversions over the same quantum resources.

Overview

FunctionDescription
castCast a quantum value to a different type without allocating new qubits.
get_current_tracer
ClassDescription
CastOperationType cast operation for creating aliases over the same quantum resources.
QFixed
QFixedTypeQuantum fixed-point type.
Qubit
ValueA typed SSA value in the IR.
Vector1-dimensional array type.
VectorViewStrided view over a parent Vector, backed by a sliced ArrayValue.

Functions

cast [source]

def cast(source: Vector[Qubit], target_type: type, *, int_bits: int = 0) -> QFixed

Cast a quantum value to a different type without allocating new qubits.

The cast performs a move: the source handle is consumed and cannot be reused after the cast. The returned handle references the same physical qubits.

Parameters:

NameTypeDescription
sourceVector[Qubit]The value to cast (currently supports Vector[Qubit])
target_typetypeThe target type class (currently supports QFixed)
int_bitsintFor QFixed, number of integer bits (default: 0 = all fractional)

Returns:

QFixed — A new handle of the target type referencing the same qubits.

Example:

@qmc.qkernel
def my_circuit():
    phase_register = qmc.qubit_array(5, name="phase")
    # ... apply some operations ...

    # Cast the qubit array to QFixed for measurement
    phase_qfixed = qmc.cast(phase_register, qmc.QFixed, int_bits=0)
    phase_value = qmc.measure(phase_qfixed)
    return phase_value

Raises:


get_current_tracer [source]

def get_current_tracer() -> Tracer

Classes

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:

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(),
) -> None
Attributes

QFixed [source]

class QFixed(Handle)
Constructor
def __init__(
    self,
    value: Value[QFixedType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

QFixedType [source]

class QFixedType(QuantumTypeMixin, ValueType)

Quantum fixed-point type.

Represents a quantum register encoding a fixed-point number with specified integer and fractional bits.

Constructor
def __init__(
    self,
    integer_bits: int | Value[UIntType] = 0,
    fractional_bits: int | Value[UIntType] = 0,
) -> None
Attributes
Methods
label
def label(self) -> str

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

VectorView [source]

class VectorView(Vector[T])

Strided view over a parent Vector, backed by a sliced ArrayValue.

A VectorView is produced by slicing a Vector (q[1::2], q[a:b], etc.). It is a thin Vector subclass whose value is a fresh ArrayValue with slice_of / slice_start / slice_step metadata pointing back to the parent’s ArrayValue. Element accesses go through Vector._get_element unchanged — the IR element carries parent_array = sliced_av, and the emit-time resolver walks the slice_of chain to produce the physical qubit index. No affine translation happens in the view itself.

Because the sliced ArrayValue is a first-class IR Value, the view can be passed as an operand of CallBlockOperation to another @qkernel without the inline-trace special-case path that earlier iterations required. Passing views through expval / measure likewise operates on the sliced qubit subset, not the root parent as a whole.

Linearity:

Slicing bulk-borrows the covered parent slots whenever start, step and length are compile-time int constants. While the view is live, accessing the corresponding parent slot directly (q[0] after evens = q[0::2]) raises QubitConsumedError. Under the strict-return policy the view’s ownership is cleared only by two operations:

Every other consume (broadcast gates h(view), pauli_evolve(view, H, gamma), sub-kernel calls f(view), controlled-U index_spec) only transfers ownership to a freshly-wrapped VectorView and that new view still must be returned via slice assignment. A view left bulk-borrowing at the parent’s consume point raises UnreturnedBorrowError.

Symbolic slices (q[lo:hi] with lo/hi UInt) cannot enumerate their covered slots at trace time and therefore skip the bulk-borrow here; SliceBorrowCheckPass picks them up post-fold after bindings resolve the bounds to concrete values.

Example:

@qmc.qkernel
def alternating_h(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]:
    evens = q[0::2]
    for i in qmc.range(evens.shape[0]):
        evens[i] = qmc.h(evens[i])
    q[0::2] = evens  # explicit return before the parent is used
    return q
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the view and release its parent slice-borrows.

Validates that every view-local borrow has been returned, then dispatches on operation_name to keep the parent’s slice-borrow record consistent with the new strict-return semantics:

Operations that produce a fresh sliced ArrayValue (e.g. :func:qamomile.circuit.frontend.operation.pauli_evolve.pauli_evolve, :class:QKernel.__call__ for callees that return a sliced array) cannot simply use the auto-returned new_view because the new view they build wraps a different Value than this consume’s return. Those op implementations call :meth:_transfer_borrow_to after building their result so the parent’s borrow table tracks the right handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this view (used in error messages and for dispatch).

Returns:

typing.Self — A fresh view handle with the same backing state; under typing.Self — transfer the parent’s borrow table now points at this typing.Self — handle, under release / destruction the parent’s record typing.Self — for the covered slots is finalised.

Raises:


qamomile.circuit.frontend.operation.control

Controlled gate operations.

Overview

FunctionDescription
controlCreate a controlled version of a quantum gate.
get_current_tracer
ClassDescription
ArrayValueAn array of typed IR values.
ConcreteControlledUControlled-U with concrete (int) number of controls.
ControlledGateWrapper for controlled version of a QKernel.
ControlledUOperationBase class for controlled-U operations.
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
QKernelDecorator class for Qamomile quantum kernels.
Qubit
SymbolicControlledUControlled-U with symbolic (Value) number of controls.
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.

Functions

control [source]

def control(
    qkernel: QKernel | Callable[..., Any],
    num_controls: int | UInt = 1,
) -> ControlledGate

Create a controlled version of a quantum gate.

Accepts a @qmc.qkernel-decorated function, a qkernel-backed CompositeGate created by the function-form decorator, or a plain built-in gate callable (qmc.rx, qmc.h, qmc.cp, ...). When given a plain callable, a thin @qkernel wrapper is synthesized automatically by inspecting the callable’s signature, so users no longer need to write a one-line wrapper just to control a primitive gate.

Parameters:

NameTypeDescription
qkernelQKernel | Callable[..., Any]A QKernel defining the gate to control, a qkernel-backed CompositeGate, or a built-in gate callable whose parameters are annotated with Qubit, Float / float, or UInt / int (possibly inside a Union such as Union[Qubit, Vector[Qubit]]).
num_controlsint | UIntNumber of control qubits (default: 1). Can be int (concrete) or UInt (symbolic).

Returns:

ControlledGate — A ControlledGate that can be called with ControlledGate(*controls, *targets, **params).

Raises:

Example:

Built-in gates can be controlled directly, with no wrapper::

    crx = qmc.control(qmc.rx)
    ctrl_out, tgt_out = crx(ctrl, target, angle=0.5)

    cch = qmc.control(qmc.h, num_controls=2)
    c0, c1, tgt = cch(ctrl0, ctrl1, target)

``@qmc.qkernel`` arguments are still supported for cases that need
custom logic::

    @qmc.qkernel
    def rx_then_h(q: Qubit, theta: float) -> Qubit:
        q = qmc.rx(q, theta)
        q = qmc.h(q)
        return q

    ctrl_out, tgt_out = qmc.control(rx_then_h)(ctrl, target, theta=0.5)

Qkernel-backed composite gates can also be controlled directly::

    controlled_gate = qmc.control(my_composite_gate)
    ctrl_out, tgt0_out, tgt1_out = controlled_gate(ctrl, tgt0, tgt1)

get_current_tracer [source]

def get_current_tracer() -> Tracer

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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

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,
) -> None
Attributes

ControlledGate [source]

class ControlledGate

Wrapper for controlled version of a QKernel.

Created by calling control(qkernel). The resulting object can be called like a gate function.

Example:

@qmc.qkernel
def phase_gate(q: Qubit, theta: float) -> Qubit:
    return qmc.p(q, theta)

controlled_phase = qmc.control(phase_gate)
ctrl_out, tgt_out = controlled_phase(ctrl, target, theta=0.5)

# Double-controlled
cc_phase = qmc.control(phase_gate, num_controls=2)
c0, c1, tgt = cc_phase(ctrl0, ctrl1, target, theta=0.5)
Constructor
def __init__(self, qkernel: 'QKernel', num_controls: int | UInt = 1) -> None

Wrap a QKernel as a controlled operation.

Parameters:

NameTypeDescription
qkernelQKernelThe kernel to control. Built-in gate callables are not accepted directly here -- :func:control synthesizes a wrapper QKernel for them before instantiating ControlledGate -- so by this point qkernel must expose a dict input_types attribute and an inspect.Signature signature attribute.
num_controlsint | UIntNumber of control qubits. A concrete int must be >= 1; a symbolic UInt defers validation to emit time. Defaults to 1. A bool is rejected: it is not a valid control count even though bool subclasses int.

Raises:


ControlledUOperation [source]

class ControlledUOperation(Operation)

Base class for controlled-U operations.

Two concrete subclasses handle distinct operand layouts:

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,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


QKernel [source]

class QKernel(Generic[P, R])

Decorator class for Qamomile quantum kernels.

Constructor
def __init__(self, func: Callable[P, R]) -> None
Attributes
Methods
build
def build(self, parameters: list[str] | None = None, **kwargs: Any = {}) -> Block

Build a traced Block by tracing this kernel.

Parameters:

NameTypeDescription
parameterslist[str] | NoneList 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.
**kwargsAnyConcrete values for non-parameter arguments.

Returns:

Block — The traced block ready for transpilation, estimation, or visualization.

Raises:

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 = {},
) -> Any

Visualize 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:

NameTypeDescription
inlineboolIf True, expand CallBlockOperation contents (inlining). If False (default), show CallBlockOperation as boxes.
fold_loopsboolIf True (default), display ForOperation as blocks instead of unrolling. If False, expand loops and show all iterations.
expand_compositeboolIf True, expand CompositeGateOperation (QFT, IQFT, etc.). If False (default), show as boxes. Independent of inline.
inline_depthint | NoneMaximum 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.
**kwargsAnyConcrete values for arguments. Arguments not provided here (and without defaults) will be shown as symbolic parameters.

Returns:

Any — matplotlib.figure.Figure object.

Raises:

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

Estimate 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:

NameTypeDescription
bindingsdict[str, Any] | NoneOptional 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)  # 2

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

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,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.operation.control_flow

Overview

FunctionDescription
emit_ifBuilder function for if-else conditional with Phi function merging.
for_itemsBuilder function to create a for-items loop in Qamomile frontend.
for_loopBuilder function to create a for loop in Qamomile frontend.
get_current_tracer
is_array_typeCheck if type is a Vector, Matrix, or Tensor subclass.
itemsIterate over dictionary key-value pairs.
rangeSymbolic range for use in qkernel for-loops.
should_trace_for_loopDecide whether a qmc.range body must be traced.
traceContext manager to set the current tracer.
while_loopCreate a while loop whose condition is a measurement result.
ClassDescription
ArrayBaseBase class for array types (Vector, Matrix, Tensor).
ArrayValueAn array of typed IR values.
Bit
BitTypeType representing a classical bit.
DictDict handle for qkernel functions.
DictItemsIteratorIterator for Dict.items() that yields (key, value) pairs.
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
ForItemsOperationRepresents iteration over dict/iterable items.
ForOperationRepresents a for loop operation.
IfOperationRepresents an if-else conditional operation.
ObservableHandle representing a Hamiltonian observable parameter.
PhiOpSSA Phi function: merge point after conditional branch.
QFixed
Qubit
Tracer
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.
Vector1-dimensional array type.
WhileLoop
WhileOperationRepresents a while loop operation.

Functions

emit_if [source]

def emit_if(
    cond_func: Callable,
    true_func: Callable,
    false_func: Callable,
    variables: list,
) -> Any

Builder function for if-else conditional with Phi function merging.

This function is called from AST-transformed code. The AST transformer converts: if condition: true_body else: false_body

Into:

def _cond_N(vars): return condition def _body_N(vars): true_body; return vars def _body_N+1(vars): false_body; return vars result = emit_if(_cond_N, _body_N, _body_N+1, [var_list])

Parameters:

NameTypeDescription
cond_functyping.CallableFunction returning the condition (Bit or bool-like Handle)
true_functyping.CallableFunction executing true branch, returns updated variables
false_functyping.CallableFunction executing false branch, returns updated variables
variableslistList of variables used in the branches

Returns:

typing.Any — Merged variable values after conditional execution (using Phi functions)

Example:

@qkernel
def my_kernel(q: Qubit) -> Qubit:
    result = measure(q)
    if result:
        q = z(q)
    return q

for_items [source]

def for_items(
    d: Dict,
    key_var_names: list[str],
    value_var_name: str,
) -> Generator[tuple[Any, Any], None, None]

Builder function to create a for-items loop in Qamomile frontend.

This context manager creates a ForItemsOperation that iterates over dictionary (key, value) pairs. The operation is always unrolled at transpile time since quantum backends cannot natively iterate over classical data structures.

Parameters:

NameTypeDescription
dDictDict handle to iterate over
key_var_nameslist[str]Names of key unpacking variables (e.g., [“i”, “j”] for tuple keys)
value_var_namestrName of value variable (e.g., “Jij”)

Yields:

tuple[typing.Any, typing.Any] — Tuple of (key_handles, value_handle) for use in loop body

Example:

@qkernel
def ising_cost(
    q: Vector[Qubit],
    ising: Dict[Tuple[UInt, UInt], Float],
    gamma: Float,
) -> Vector[Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q

for_loop [source]

def for_loop(
    start,
    stop,
    step = 1,
    var_name: str = '_loop_idx',
) -> Generator[UInt, None, None]

Builder function to create a for loop in Qamomile frontend.

Parameters:

NameTypeDescription
start``Loop start value (can be Handle or int)
stop``Loop stop value (can be Handle or int)
step``Loop step value (default=1)
var_namestrName of the loop variable (default=“_loop_idx”)

Yields:

UInt — The loop iteration variable (can be used as array index)

Example:

@QKernel
def my_kernel(qubits: Array[Qubit, Literal[3]]) -> Array[Qubit, Literal[3]]:
    for i in qm.range(3):
        qubits[i] = h(qubits[i])
    return qubits

@QKernel
def my_kernel2(qubits: Array[Qubit, Literal[5]]) -> Array[Qubit, Literal[5]]:
    for i in qm.range(1, 4):  # i = 1, 2, 3
        qubits[i] = h(qubits[i])
    return qubits

get_current_tracer [source]

def get_current_tracer() -> Tracer

is_array_type [source]

def is_array_type(t: Any) -> bool

Check if type is a Vector, Matrix, or Tensor subclass.


items [source]

def items(d: Dict) -> DictItemsIterator

Iterate over dictionary key-value pairs.

This function returns an iterator over (key, value) pairs from a Dict. Used for iterating over Ising coefficients and similar data structures.

Example:

for (i, j), Jij in qmc.items(ising):
    q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)

Parameters:

NameTypeDescription
dDictA Dict handle to iterate over

Returns:

DictItemsIterator — DictItemsIterator yielding (key, value) pairs


range [source]

def range(
    stop_or_start: int | UInt,
    stop: int | UInt | None = None,
    step: int | UInt = 1,
) -> Iterator[UInt]

Symbolic range for use in qkernel for-loops.

This function accepts UInt (symbolic) values and is transformed by the AST transformer into for_loop() calls.

Example:

for i in qmc.range(n):          # 0 to n-1
for i in qmc.range(start, stop):  # start to stop-1
for i in qmc.range(start, stop, step):

should_trace_for_loop [source]

def should_trace_for_loop(start: Any, stop: Any, step: Any) -> bool

Decide whether a qmc.range body must be traced.

The frontend executes loop bodies once to capture a ForOperation. When all bounds are concrete and Python’s range would execute zero times, tracing the body would incorrectly leak borrow / destructive-consume state into the enclosing scope. Symbolic or invalid bounds stay conservative and trace the body so the normal compiler validation path reports any errors.

Parameters:

NameTypeDescription
starttyping.AnyLoop start bound.
stoptyping.AnyLoop stop bound.
steptyping.AnyLoop step bound.

Returns:

boolFalse only for statically-known zero-trip loops; True bool — otherwise.


trace [source]

def trace(tracer: Tracer | None = None) -> Generator[Tracer, None, None]

Context manager to set the current tracer.


while_loop [source]

def while_loop(cond: Callable) -> Generator[WhileLoop, None, None]

Create a while loop whose condition is a measurement result.

The condition must be a Bit produced by qmc.measure(). Non-measurement conditions (classical variables, constants, comparisons) are accepted at build time but will be rejected by ValidateWhileContractPass during transpilation.

Parameters:

NameTypeDescription
condtyping.CallableA callable (lambda) that returns the loop condition. Must return a Bit handle originating from qmc.measure().

Yields:

WhileLoop — A marker object for the while loop context.

Example::

@qm.qkernel
def repeat_until_zero() -> qm.Bit:
    q = qm.qubit("q")
    q = qm.h(q)
    bit = qm.measure(q)
    while bit:
        q = qm.qubit("q2")
        q = qm.h(q)
        bit = qm.measure(q)
    return bit

Classes

ArrayBase [source]

class ArrayBase(Handle, Generic[T])

Base class for array types (Vector, Matrix, Tensor).

Provides common functionality for array indexing and element access.

Constructor
def __init__(
    self,
    value: ArrayValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the array, enforcing borrow-return contract for quantum arrays.

For quantum arrays, all borrowed elements must be returned before the array can be consumed. This ensures that no unreturned borrows are silently discarded by operations like qkernel calls or controlled gates.

When any slot of the array has already been physically consumed by an earlier destructive view operation (measure(q[1::2]) then measure(q)), this raises QubitConsumedError rather than silently re-consuming those slots.

create
@classmethod
def create(
    cls,
    shape: tuple[int | UInt, ...],
    name: str,
    el_type: Type[T],
) -> 'ArrayBase[T]'

Create an ArrayValue for the given shape and name.

validate_all_returned
def validate_all_returned(self) -> None

Validate all borrowed elements have been returned.

Strict-return policy: an active slice view that is still registered as the owner of any parent slot is treated as an unreturned borrow even if the view itself has no outstanding element borrows. The caller must perform an explicit slice assignment (parent[a:b:c] = view) to release the view’s bulk-borrow before consuming the parent. Destructively consumed views (parked in the dict with view._consumed set and view._consumed_by classified as :attr:ConsumeMode.DESTRUCTIVE) record physically-destroyed slots and are not outstanding borrows; they survive end-of-block so a later whole-array consume can detect and reject the destroyed slots.

Raises:


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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

BitType [source]

class BitType(ClassicalTypeMixin, ValueType)

Type representing a classical bit.


Dict [source]

class Dict(Handle, Generic[K, V])

Dict handle for qkernel functions.

Represents a dictionary mapping keys to values, commonly used for Ising coefficients like {(i, j): Jij}.

Example:

@qmc.qkernel
def ising_cost(
    q: qmc.Vector[qmc.Qubit],
    ising: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q
Constructor
def __init__(
    self,
    value: DictValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _entries: list[tuple[Handle, Handle]] = list(),
    _size: UInt | None = None,
    _key_type: type | None = None,
) -> None
Attributes
Methods
items
def items(self) -> DictItemsIterator[K, V]

Return an iterator over (key, value) pairs.


DictItemsIterator [source]

class DictItemsIterator(Generic[K, V])

Iterator for Dict.items() that yields (key, value) pairs.

This is used internally for iterating over Dict entries in qkernel.

Constructor
def __init__(self, dict_handle: 'Dict[K, V]', _index: int = 0) -> None
Attributes

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


ForItemsOperation [source]

class ForItemsOperation(HasNestedOps, Operation)

Represents iteration over dict/iterable items.

Example:

for (i, j), Jij in qmc.items(ising):
    body
Constructor
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(),
) -> None
Attributes
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]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

ForOperation [source]

class ForOperation(HasNestedOps, Operation)

Represents a for loop operation.

Example:

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

Include loop_var_value so cloning/substitution stays consistent.

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

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

IfOperation [source]

class IfOperation(HasNestedOps, Operation)

Represents an if-else conditional operation.

Example:

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

Observable [source]

class Observable(Handle)

Handle representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1) + 0.5 * qm_o.X(0)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    # Use Hamiltonian from bindings
    return qm.expval(q, H)

# Pass via bindings
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None

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()) -> None
Attributes

QFixed [source]

class QFixed(Handle)
Constructor
def __init__(
    self,
    value: Value[QFixedType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

Tracer [source]

class Tracer
Constructor
def __init__(self, _operations: list[Operation] = list()) -> None
Attributes
Methods
add_operation
def add_operation(self, op) -> None

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

WhileLoop [source]

class WhileLoop

WhileOperation [source]

class WhileOperation(HasNestedOps, Operation)

Represents a while loop operation.

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

Example::

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

qamomile.circuit.frontend.operation.expval

Expectation value operation for computing <psi|H|psi>.

This module provides the expval() function for computing the expectation value of a Hamiltonian observable with respect to a quantum state.

Overview

FunctionDescription
expvalCompute the expectation value of an observable on a quantum state.
get_current_tracer
resolve_root_qubit_addressResolve an array-element value to its root (array_uuid, index).
ClassDescription
ArrayValueAn array of typed IR values.
ExpvalOpExpectation value operation.
FloatTypeType representing a floating-point number.
ValueA typed SSA value in the IR.

Functions

expval [source]

def expval(
    qubits: Qubit | Vector[Qubit] | tuple[Qubit, ...],
    hamiltonian: Observable,
) -> Float

Compute the expectation value of an observable on a quantum state.

This function computes <psi|H|psi> where psi is the quantum state represented by qubits and H is the Hamiltonian observable.

The quantum state is consumed by this operation: expval classifies as :attr:ConsumeMode.DESTRUCTIVE, the same category as measure / cast. Conceptually an Estimator runs many shots of the state to estimate the expectation, so the qubits cannot be reused afterwards. Any attempt to access the same qubits / view slots after expval is rejected as use-after-destroy, both at trace time and post-fold in the IR.

Parameters:

NameTypeDescription
qubitsQubit | Vector[Qubit] | tuple[Qubit, ...]The quantum register holding the prepared state. A single Qubit handle is accepted for 1-qubit observables. When a Vector is passed all previously-borrowed elements must have been returned (the strict-return policy is enforced by consume here). When a slice view (VectorView) is passed its covered parent slots become consumed-slot markers so the parent cannot reuse them later.
hamiltonianObservableThe Observable parameter representing the Hamiltonian. The actual qamomile.observable.Hamiltonian is provided via transpile(..., bindings={...}).

Returns:

Float — A scalar handle holding the expectation value, suitable for use as the kernel return value or as an operand to further classical operations.

Raises:

Example:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1) + 0.5 * (qm_o.X(0) + qm_o.X(1))

@qm.qkernel
def vqe_step(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    # Ansatz
    q[0] = qm.ry(q[0], theta)
    q[0], q[1] = qm.cx(q[0], q[1])

    # Expectation value -> Float (q is consumed here)
    return qm.expval(q, H)

# Pass Hamiltonian via bindings
executable = transpiler.transpile(vqe_step, bindings={"H": H})

get_current_tracer [source]

def get_current_tracer() -> Tracer

resolve_root_qubit_address [source]

def resolve_root_qubit_address(value: 'Value') -> tuple[str, int] | None

Resolve 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:

NameTypeDescription
valueValueThe 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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

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:

Example IR:

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

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.frontend.operation.inverse

Frontend helpers for applying inverse quantum operations.

Overview

FunctionDescription
get_current_tracer
inverseCreate an inverse operation wrapper.
ClassDescription
ArrayBaseBase class for array types (Vector, Matrix, Tensor).
ArrayValueAn array of typed IR values.
BlockUnified block representation for all pipeline stages.
BlockKindClassification of block structure for pipeline stages.
CallBlockOperation
CompositeGateBase class for user-facing composite gate definitions.
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
CompositeGateTypeRegistry of known composite gate types.
ConcreteControlledUControlled-U with concrete (int) number of controls.
ControlledUOperationBase class for controlled-U operations.
FloatTypeType representing a floating-point number.
ForItemsOperationRepresents iteration over dict/iterable items.
ForOperationRepresents a for loop operation.
GateOperationQuantum gate operation.
GateOperationType
IfOperationRepresents an if-else conditional operation.
InverseBlockOperationRepresent an inverse qkernel/block as a first-class IR operation.
InverseGateCallable wrapper that applies a QKernel’s inverse.
MeasureOperation
MeasureQFixedOperationMeasure a quantum fixed-point number.
MeasureVectorOperationMeasure a vector of qubits.
Operation
OperationKindClassification of operations for classical/quantum separation.
PauliEvolveOpPauli evolution operation: exp(-i * gamma * H).
QInitOperationInitialize the qubit
QKernelDecorator class for Qamomile quantum kernels.
ResourceMetadataResource estimation metadata for composite gates.
ReturnOperationExplicit return operation marking the end of a block with return values.
SymbolicControlledUControlled-U with symbolic (Value) number of controls.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.
ValueBaseProtocol for IR values with typed metadata.
ValueSubstitutorSubstitute IR values in operations using a UUID-keyed mapping.
VectorViewStrided view over a parent Vector, backed by a sliced ArrayValue.
WhileOperationRepresents a while loop operation.

Functions

get_current_tracer [source]

def get_current_tracer() -> Tracer

inverse [source]

def inverse(target: QKernel | Callable[..., Any]) -> Any

Create an inverse operation wrapper.

Native Qamomile gate functions are first synthesized into tiny QKernel objects, then inverted with the same block walker used for user-defined kernels. Known QFT/IQFT functions map directly to their counterpart so backend-native composite emission remains available.

Parameters:

NameTypeDescription
targetQKernel | Callable[..., Any]Native gate function, QKernel, or supported stdlib function to invert.

Returns:

Any — A callable inverse wrapper, or the opposite QFT/IQFT function.

Raises:

Example:

>>> import qamomile.circuit as qmc
>>> @qmc.qkernel
... def layer(q: qmc.Qubit, angle: qmc.Float) -> qmc.Qubit:
...     q = qmc.h(q)
...     q = qmc.rz(q, angle)
...     return q
>>> @qmc.qkernel
... def circuit(angle: qmc.Float) -> qmc.Qubit:
...     q = qmc.qubit("q")
...     q = layer(q, angle)
...     q = qmc.inverse(layer)(q, angle)
...     return q

Classes

ArrayBase [source]

class ArrayBase(Handle, Generic[T])

Base class for array types (Vector, Matrix, Tensor).

Provides common functionality for array indexing and element access.

Constructor
def __init__(
    self,
    value: ArrayValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the array, enforcing borrow-return contract for quantum arrays.

For quantum arrays, all borrowed elements must be returned before the array can be consumed. This ensures that no unreturned borrows are silently discarded by operations like qkernel calls or controlled gates.

When any slot of the array has already been physically consumed by an earlier destructive view operation (measure(q[1::2]) then measure(q)), this raises QubitConsumedError rather than silently re-consuming those slots.

create
@classmethod
def create(
    cls,
    shape: tuple[int | UInt, ...],
    name: str,
    el_type: Type[T],
) -> 'ArrayBase[T]'

Create an ArrayValue for the given shape and name.

validate_all_returned
def validate_all_returned(self) -> None

Validate all borrowed elements have been returned.

Strict-return policy: an active slice view that is still registered as the owner of any parent slot is treated as an unreturned borrow even if the view itself has no outstanding element borrows. The caller must perform an explicit slice assignment (parent[a:b:c] = view) to release the view’s bulk-borrow before consuming the parent. Destructively consumed views (parked in the dict with view._consumed set and view._consumed_by classified as :attr:ConsumeMode.DESTRUCTIVE) record physically-destroyed slots and are not outstanding borrows; they survive end-of-block so a later whole-array consume can detect and reject the destroyed slots.

Raises:


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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

Block [source]

class Block

Unified 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(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check 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

CallBlockOperation [source]

class CallBlockOperation(Operation)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    block: Block | None = None,
) -> None
Attributes
Methods
is_self_reference_to
def is_self_reference_to(self, block: Block) -> bool

Return True if this call points to the given block (self-ref).


CompositeGate [source]

class CompositeGate(abc.ABC)

Base class for user-facing composite gate definitions.

Subclasses can define composite gates in two ways:

  1. Using _decompose() (recommended for users): Define the gate decomposition using frontend syntax (same as qkernel [source]).

    class QFT(CompositeGate):
        def __init__(self, num_qubits: int):
            self._num_qubits = num_qubits
    
        @property
        def num_target_qubits(self) -> int:
            return self._num_qubits
    
        def _decompose(self, qubits: Vector[Qubit]) -> Vector[Qubit]:
            # Use frontend syntax: qm.h(), qm.cp(), qm.range(), etc.
            n = self._num_qubits
            for j in qmc.range(n - 1, -1, -1):
                qubits[j] = qmc.h(qubits[j])
                for k in qmc.range(j - 1, -1, -1):
                    angle = math.pi / (2 ** (j - k))
                    qubits[j], qubits[k] = qmc.cp(qubits[j], qubits[k], angle)
            return qubits
    
        def _resources(self) -> ResourceMetadata:
            return ResourceMetadata(t_gates=0)
  2. Using get_implementation() (advanced): Return a pre-built Block directly.

Example usage:

# Factory function pattern
def qft(qubits: Vector[Qubit]) -> Vector[Qubit]:
    n = _get_size(qubits)
    return QFT(n)(qubits)

# Direct class usage
result = QFT(3)(*qubit_list)
Attributes
Methods
build_decomposition
def build_decomposition(self, *qubits: Qubit = (), **params: Any = {}) -> Block | None

Build the decomposition circuit dynamically.

Override this method to provide a decomposition that depends on runtime arguments (e.g., QPE needs the unitary Block).

This method is called by InlinePass when inlining composite gates that have dynamic implementations.

Parameters:

NameTypeDescription
*qubitsQubitThe qubits passed to the gate
**paramsAnyAdditional parameters (e.g., unitary for QPE)

Returns:

Block | None — Block containing the decomposition, or None if not available.

Example:

class QPE(CompositeGate):
    def build_decomposition(self, *qubits, **params):
        unitary = params.get("unitary")
        # Build QPE circuit using the unitary
        return self._build_qpe_impl(qubits, unitary)
get_implementation
def get_implementation(self) -> Block | None

Get the implementation Block, if any.

Return None for stub gates (used in resource estimation). Override in subclasses to provide implementation.

Note: If _decompose() is defined, it takes precedence over this method.

get_resource_metadata
def get_resource_metadata(self) -> ResourceMetadata | None

Get resource estimation metadata.

Returns _resources() if defined, otherwise None. Override _resources() to provide resource hints.

get_resources_for_strategy
def get_resources_for_strategy(self, strategy_name: str | None = None) -> ResourceMetadata | None

Get resource metadata for a specific strategy.

Parameters:

NameTypeDescription
strategy_namestr | NoneStrategy to query, or None for default

Returns:

ResourceMetadata | None — ResourceMetadata for the strategy, or None if not available

get_strategy
@classmethod
def get_strategy(cls, name: str | None = None) -> 'DecompositionStrategy | None'

Get a registered decomposition strategy.

Parameters:

NameTypeDescription
namestr | NoneStrategy name, or None for default strategy

Returns:

'DecompositionStrategy | None' — DecompositionStrategy instance, or None if not found

list_strategies
@classmethod
def list_strategies(cls) -> list[str]

List all registered strategy names.

Returns:

list[str] — List of strategy names

register_strategy
@classmethod
def register_strategy(cls, name: str, strategy: 'DecompositionStrategy') -> None

Register a decomposition strategy for this gate type.

Parameters:

NameTypeDescription
namestrStrategy identifier (e.g., “standard”, “approximate”)
strategy'DecompositionStrategy'DecompositionStrategy instance

Example:

QFT.register_strategy("approximate", ApproximateQFTStrategy(k=3))
set_default_strategy
@classmethod
def set_default_strategy(cls, name: str) -> None

Set the default decomposition strategy.

Parameters:

NameTypeDescription
namestrStrategy name to use as default

Raises:


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:

The operands structure is:

The results structure:

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,
) -> None
Attributes

CompositeGateType [source]

class CompositeGateType(enum.Enum)

Registry of known composite gate types.

Attributes

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,
) -> None
Attributes

ControlledUOperation [source]

class ControlledUOperation(Operation)

Base class for controlled-U operations.

Two concrete subclasses handle distinct operand layouts:

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,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


ForItemsOperation [source]

class ForItemsOperation(HasNestedOps, Operation)

Represents iteration over dict/iterable items.

Example:

for (i, j), Jij in qmc.items(ising):
    body
Constructor
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(),
) -> None
Attributes
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]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

ForOperation [source]

class ForOperation(HasNestedOps, Operation)

Represents a for loop operation.

Example:

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

Include loop_var_value so cloning/substitution stays consistent.

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

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

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,
) -> None
Attributes
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

IfOperation [source]

class IfOperation(HasNestedOps, Operation)

Represents an if-else conditional operation.

Example:

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

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,
) -> None
Attributes

InverseGate [source]

class InverseGate

Callable wrapper that applies a QKernel’s inverse.

Parameters:

NameTypeDescription
qkernelQKernelKernel whose inverse should be emitted.
Constructor
def __init__(self, qkernel: QKernel) -> None

Initialize the inverse wrapper.

Parameters:

NameTypeDescription
qkernelQKernelKernel whose inverse should be emitted.

MeasureOperation [source]

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

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,
) -> None
Attributes

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()) -> None
Attributes

Operation [source]

class Operation(abc.ABC)
Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Return all input Values including subclass-specific fields.

Generic passes should use this instead of accessing operands directly to ensure no Value is missed. Subclasses override this to include extra Value fields (e.g. ControlledUOperation.power).

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

Return a copy with all Values substituted via mapping.

Handles operands, results, and subclass-specific Value fields. Subclasses override to handle their extra fields.


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

PauliEvolveOp [source]

class PauliEvolveOp(Operation)

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

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

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

QInitOperation [source]

class QInitOperation(Operation)

Initialize the qubit

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

QKernel [source]

class QKernel(Generic[P, R])

Decorator class for Qamomile quantum kernels.

Constructor
def __init__(self, func: Callable[P, R]) -> None
Attributes
Methods
build
def build(self, parameters: list[str] | None = None, **kwargs: Any = {}) -> Block

Build a traced Block by tracing this kernel.

Parameters:

NameTypeDescription
parameterslist[str] | NoneList 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.
**kwargsAnyConcrete values for non-parameter arguments.

Returns:

Block — The traced block ready for transpilation, estimation, or visualization.

Raises:

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 = {},
) -> Any

Visualize 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:

NameTypeDescription
inlineboolIf True, expand CallBlockOperation contents (inlining). If False (default), show CallBlockOperation as boxes.
fold_loopsboolIf True (default), display ForOperation as blocks instead of unrolling. If False, expand loops and show all iterations.
expand_compositeboolIf True, expand CompositeGateOperation (QFT, IQFT, etc.). If False (default), show as boxes. Independent of inline.
inline_depthint | NoneMaximum 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.
**kwargsAnyConcrete values for arguments. Arguments not provided here (and without defaults) will be shown as symbolic parameters.

Returns:

Any — matplotlib.figure.Figure object.

Raises:

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

Estimate 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:

NameTypeDescription
bindingsdict[str, Any] | NoneOptional 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)  # 2

ResourceMetadata [source]

class ResourceMetadata

Resource estimation metadata for composite gates.

Gate count fields mirror GateCount categories.

None semantics:

Fields left as None mean “unknown/unspecified”. During extraction, gate_counter treats None as 0, which may undercount resources if the true value is nonzero. To ensure accurate resource estimates, set all relevant fields explicitly.

When total_gates is set but some of single_qubit_gates, two_qubit_gates, or multi_qubit_gates are None, the extractor emits a UserWarning if the known sub-total is less than total_gates, indicating potentially missing gate category data.

Constructor
def __init__(
    self,
    query_complexity: int | None = None,
    t_gates: int | None = None,
    ancilla_qubits: int = 0,
    total_gates: int | None = None,
    single_qubit_gates: int | None = None,
    two_qubit_gates: int | None = None,
    multi_qubit_gates: int | None = None,
    clifford_gates: int | None = None,
    rotation_gates: int | None = None,
    custom_metadata: dict[str, Any] = dict(),
) -> None
Attributes

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()) -> None
Attributes

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,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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
Methods
get_const
def get_const(self) -> int | float | bool | None
is_constant
def is_constant(self) -> bool
is_parameter
def is_parameter(self) -> bool
next_version
def next_version(self) -> ValueBase
parameter_name
def parameter_name(self) -> str | None

ValueSubstitutor [source]

class ValueSubstitutor

Substitute IR values in operations using a UUID-keyed mapping.

Parameters:

NameTypeDescription
value_mapMapping[str, ValueBase]Mapping from original value UUIDs to replacement values.
transitiveboolWhether 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:

NameTypeDescription
value_mapMapping[str, ValueBase]Mapping from original value UUIDs to replacement values.
transitiveboolWhether substitutions should chase chains to their terminal value. Defaults to False.
Methods
substitute_operation
def substitute_operation(self, op: Operation) -> Operation

Substitute values in an operation.

Parameters:

NameTypeDescription
opOperationOperation 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) -> ValueBase

Substitute a single value.

Parameters:

NameTypeDescription
valueValueBaseValue to replace or rebuild.

Returns:

ValueBase — Replacement value, rebuilt value with substituted ValueBase — metadata, or the original value when nothing maps.


VectorView [source]

class VectorView(Vector[T])

Strided view over a parent Vector, backed by a sliced ArrayValue.

A VectorView is produced by slicing a Vector (q[1::2], q[a:b], etc.). It is a thin Vector subclass whose value is a fresh ArrayValue with slice_of / slice_start / slice_step metadata pointing back to the parent’s ArrayValue. Element accesses go through Vector._get_element unchanged — the IR element carries parent_array = sliced_av, and the emit-time resolver walks the slice_of chain to produce the physical qubit index. No affine translation happens in the view itself.

Because the sliced ArrayValue is a first-class IR Value, the view can be passed as an operand of CallBlockOperation to another @qkernel without the inline-trace special-case path that earlier iterations required. Passing views through expval / measure likewise operates on the sliced qubit subset, not the root parent as a whole.

Linearity:

Slicing bulk-borrows the covered parent slots whenever start, step and length are compile-time int constants. While the view is live, accessing the corresponding parent slot directly (q[0] after evens = q[0::2]) raises QubitConsumedError. Under the strict-return policy the view’s ownership is cleared only by two operations:

Every other consume (broadcast gates h(view), pauli_evolve(view, H, gamma), sub-kernel calls f(view), controlled-U index_spec) only transfers ownership to a freshly-wrapped VectorView and that new view still must be returned via slice assignment. A view left bulk-borrowing at the parent’s consume point raises UnreturnedBorrowError.

Symbolic slices (q[lo:hi] with lo/hi UInt) cannot enumerate their covered slots at trace time and therefore skip the bulk-borrow here; SliceBorrowCheckPass picks them up post-fold after bindings resolve the bounds to concrete values.

Example:

@qmc.qkernel
def alternating_h(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]:
    evens = q[0::2]
    for i in qmc.range(evens.shape[0]):
        evens[i] = qmc.h(evens[i])
    q[0::2] = evens  # explicit return before the parent is used
    return q
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the view and release its parent slice-borrows.

Validates that every view-local borrow has been returned, then dispatches on operation_name to keep the parent’s slice-borrow record consistent with the new strict-return semantics:

Operations that produce a fresh sliced ArrayValue (e.g. :func:qamomile.circuit.frontend.operation.pauli_evolve.pauli_evolve, :class:QKernel.__call__ for callees that return a sliced array) cannot simply use the auto-returned new_view because the new view they build wraps a different Value than this consume’s return. Those op implementations call :meth:_transfer_borrow_to after building their result so the parent’s borrow table tracks the right handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this view (used in error messages and for dispatch).

Returns:

typing.Self — A fresh view handle with the same backing state; under typing.Self — transfer the parent’s borrow table now points at this typing.Self — handle, under release / destruction the parent’s record typing.Self — for the covered slots is finalised.

Raises:


WhileOperation [source]

class WhileOperation(HasNestedOps, Operation)

Represents a while loop operation.

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

Example::

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

qamomile.circuit.frontend.operation.measurement

Measurement operations for quantum circuits.

Overview

FunctionDescription
get_current_tracer
measureMeasure a qubit or QFixed in the computational basis.
ClassDescription
ArrayValueAn array of typed IR values.
IRMeasureOperation
MeasureQFixedOperationMeasure a quantum fixed-point number.
MeasureVectorOperationMeasure a vector of qubits.
UIntTypeType representing an unsigned integer.
ValueA typed SSA value in the IR.
VectorClass1-dimensional array type.

Functions

get_current_tracer [source]

def get_current_tracer() -> Tracer

measure [source]

def measure(target: Union[Qubit, QFixed, Vector[Qubit]]) -> Union[Bit, Float, Vector[Bit]]

Measure a qubit or QFixed in the computational basis.

Performs a projective measurement in the Z-basis. The quantum resource is consumed by this operation and cannot be used afterwards.

Parameters:

NameTypeDescription
targetUnion[Qubit, QFixed, Vector[Qubit]]The quantum resource to measure. - Qubit: Returns a classical Bit - QFixed: Returns a Float (decoded from measured bits)

Returns:

Union[Bit, Float, Vector[Bit]] — Bit for Qubit input, Float for QFixed input.

Example:

@qkernel
def measure_qubit(q: Qubit) -> Bit:
    q = h(q)
    return measure(q)

@qkernel
def measure_qfixed(qf: QFixed) -> Float:
    # After QPE, qf holds phase bits
    return measure(qf)

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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

MeasureOperation [source]

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

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,
) -> None
Attributes

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()) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

qamomile.circuit.frontend.operation.pauli_evolve

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

This module provides the pauli_evolve() function for applying the time evolution operator of a Pauli Hamiltonian to a quantum state.

Overview

FunctionDescription
get_current_tracer
pauli_evolveApply exp(-i * gamma * H) to a qubit register.
ClassDescription
PauliEvolveOpPauli evolution operation: exp(-i * gamma * H).
VectorViewStrided view over a parent Vector, backed by a sliced ArrayValue.

Functions

get_current_tracer [source]

def get_current_tracer() -> Tracer

pauli_evolve [source]

def pauli_evolve(q: Vector[Qubit], hamiltonian: Observable, gamma: Float) -> Vector[Qubit]

Apply exp(-i * gamma * H) to a qubit register.

Implements Hamiltonian time evolution using the Pauli gadget technique. The actual Hamiltonian is provided via bindings at transpile time.

Each backend can use native implementations:

Parameters:

NameTypeDescription
qVector[Qubit]The quantum register to evolve.
hamiltonianObservableObservable parameter referencing the Hamiltonian. The actual qamomile.observable.Hamiltonian is provided via bindings.
gammaFloatEvolution time / variational parameter.

Returns:

Vector[Qubit] — Vector[Qubit]: The evolved qubit register.

Example:

import qamomile.circuit as qmc
import qamomile.observable as qm_o

H = 0.5 * qm_o.X(0) * qm_o.Z(1) + qm_o.Z(0)

@qmc.qkernel
def cost_layer(
    q: qmc.Vector[qmc.Qubit],
    H: qmc.Observable,
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    q = qmc.pauli_evolve(q, H, gamma)
    return q

transpiler = QiskitTranspiler()
exe = transpiler.transpile(cost_layer, bindings={"H": H, "gamma": 0.5})

Classes

PauliEvolveOp [source]

class PauliEvolveOp(Operation)

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

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

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

VectorView [source]

class VectorView(Vector[T])

Strided view over a parent Vector, backed by a sliced ArrayValue.

A VectorView is produced by slicing a Vector (q[1::2], q[a:b], etc.). It is a thin Vector subclass whose value is a fresh ArrayValue with slice_of / slice_start / slice_step metadata pointing back to the parent’s ArrayValue. Element accesses go through Vector._get_element unchanged — the IR element carries parent_array = sliced_av, and the emit-time resolver walks the slice_of chain to produce the physical qubit index. No affine translation happens in the view itself.

Because the sliced ArrayValue is a first-class IR Value, the view can be passed as an operand of CallBlockOperation to another @qkernel without the inline-trace special-case path that earlier iterations required. Passing views through expval / measure likewise operates on the sliced qubit subset, not the root parent as a whole.

Linearity:

Slicing bulk-borrows the covered parent slots whenever start, step and length are compile-time int constants. While the view is live, accessing the corresponding parent slot directly (q[0] after evens = q[0::2]) raises QubitConsumedError. Under the strict-return policy the view’s ownership is cleared only by two operations:

Every other consume (broadcast gates h(view), pauli_evolve(view, H, gamma), sub-kernel calls f(view), controlled-U index_spec) only transfers ownership to a freshly-wrapped VectorView and that new view still must be returned via slice assignment. A view left bulk-borrowing at the parent’s consume point raises UnreturnedBorrowError.

Symbolic slices (q[lo:hi] with lo/hi UInt) cannot enumerate their covered slots at trace time and therefore skip the bulk-borrow here; SliceBorrowCheckPass picks them up post-fold after bindings resolve the bounds to concrete values.

Example:

@qmc.qkernel
def alternating_h(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]:
    evens = q[0::2]
    for i in qmc.range(evens.shape[0]):
        evens[i] = qmc.h(evens[i])
    q[0::2] = evens  # explicit return before the parent is used
    return q
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the view and release its parent slice-borrows.

Validates that every view-local borrow has been returned, then dispatches on operation_name to keep the parent’s slice-borrow record consistent with the new strict-return semantics:

Operations that produce a fresh sliced ArrayValue (e.g. :func:qamomile.circuit.frontend.operation.pauli_evolve.pauli_evolve, :class:QKernel.__call__ for callees that return a sliced array) cannot simply use the auto-returned new_view because the new view they build wraps a different Value than this consume’s return. Those op implementations call :meth:_transfer_borrow_to after building their result so the parent’s borrow table tracks the right handle.

Parameters:

NameTypeDescription
operation_namestrName of the operation consuming this view (used in error messages and for dispatch).

Returns:

typing.Self — A fresh view handle with the same backing state; under typing.Self — transfer the parent’s borrow table now points at this typing.Self — handle, under release / destruction the parent’s record typing.Self — for the covered slots is finalised.

Raises:


qamomile.circuit.frontend.operation.qubit_gates

Overview

FunctionDescription
ccxToffoli (CCX) gate: flips target when both controls are |1>.
cpControlled-Phase gate.
cxCNOT (Controlled-X) gate.
czCZ (Controlled-Z) gate.
get_current_tracer
hHadamard gate.
pPhase gate: P(theta)|1> = e^{i*theta}|1>.
rxRotation around X-axis: RX(angle) = exp(-i * angle/2 * X).
ryRotation around Y-axis: RY(angle) = exp(-i * angle/2 * Y).
rzRotation around Z-axis: RZ(angle) = exp(-i * angle/2 * Z).
rzzRZZ gate: exp(-i * angle/2 * Z ⊗ Z).
sS gate (square root of Z).
sdgS-dagger gate (inverse of S gate).
swapSWAP gate: exchanges two qubits.
tT gate (fourth root of Z).
tdgT-dagger gate (inverse of T gate).
xPauli-X gate (NOT gate).
yPauli-Y gate.
zPauli-Z gate.
ClassDescription
FloatTypeType representing a floating-point number.
GateOperationType
IRGateOperationQuantum gate operation.
QubitAliasErrorSame qubit used multiple times in one operation.
ValueA typed SSA value in the IR.
VectorClass1-dimensional array type.

Functions

ccx [source]

def ccx(control1: Qubit, control2: Qubit, target: Qubit) -> tuple[Qubit, Qubit, Qubit]

Toffoli (CCX) gate: flips target when both controls are |1>.

Parameters:

NameTypeDescription
control1QubitFirst control qubit.
control2QubitSecond control qubit.
targetQubitTarget qubit.

Returns:

tuple[Qubit, Qubit, Qubit] — Tuple of (control1_out, control2_out, target_out) after CCX.


cp [source]

def cp(control: Qubit, target: Qubit, theta: float | Float) -> tuple[Qubit, Qubit]

Controlled-Phase gate.


cx [source]

def cx(control: Qubit, target: Qubit) -> tuple[Qubit, Qubit]

CNOT (Controlled-X) gate.


cz [source]

def cz(control: Qubit, target: Qubit) -> tuple[Qubit, Qubit]

CZ (Controlled-Z) gate.


get_current_tracer [source]

def get_current_tracer() -> Tracer

h [source]

def h(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

Hadamard gate.

Applied to a single Qubit it returns the transformed qubit. Applied to a Vector[Qubit] it broadcasts the gate over every element via a transpile-time loop, equivalent to for i in qmc.range(n): qs[i] = h(qs[i]).

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit] to apply H to.

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


p [source]

def p(
    target: Union[Qubit, Vector[Qubit]],
    theta: float | Float,
) -> Union[Qubit, Vector[Qubit]]

Phase gate: P(theta)|1> = e^{i*theta}|1>.

Broadcasts the same theta over every qubit when called with a Vector[Qubit].

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit] to apply the phase to.
thetafloat | FloatPhase angle in radians.

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


rx [source]

def rx(
    target: Union[Qubit, Vector[Qubit]],
    angle: float | Float,
) -> Union[Qubit, Vector[Qubit]]

Rotation around X-axis: RX(angle) = exp(-i * angle/2 * X).

Broadcasts the same angle over every qubit when called with a Vector[Qubit].

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].
anglefloat | FloatRotation angle in radians.

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


ry [source]

def ry(
    target: Union[Qubit, Vector[Qubit]],
    angle: float | Float,
) -> Union[Qubit, Vector[Qubit]]

Rotation around Y-axis: RY(angle) = exp(-i * angle/2 * Y).

Broadcasts the same angle over every qubit when called with a Vector[Qubit].

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].
anglefloat | FloatRotation angle in radians.

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


rz [source]

def rz(
    target: Union[Qubit, Vector[Qubit]],
    angle: float | Float,
) -> Union[Qubit, Vector[Qubit]]

Rotation around Z-axis: RZ(angle) = exp(-i * angle/2 * Z).

Broadcasts the same angle over every qubit when called with a Vector[Qubit].

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].
anglefloat | FloatRotation angle in radians.

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


rzz [source]

def rzz(qubit_0: Qubit, qubit_1: Qubit, angle: float | Float) -> tuple[Qubit, Qubit]

RZZ gate: exp(-i * angle/2 * Z ⊗ Z).

The RZZ gate applies a rotation around the ZZ axis on two qubits.

Parameters:

NameTypeDescription
qubit_0QubitFirst qubit.
qubit_1QubitSecond qubit.
anglefloat | FloatRotation angle in radians.

Returns:

tuple[Qubit, Qubit] — Tuple of (qubit_0_out, qubit_1_out) after RZZ.


s [source]

def s(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

S gate (square root of Z).

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


sdg [source]

def sdg(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

S-dagger gate (inverse of S gate).

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


swap [source]

def swap(qubit_0: Qubit, qubit_1: Qubit) -> tuple[Qubit, Qubit]

SWAP gate: exchanges two qubits.

The SWAP gate swaps the states of two qubits.

Parameters:

NameTypeDescription
qubit_0QubitFirst qubit.
qubit_1QubitSecond qubit.

Returns:

tuple[Qubit, Qubit] — Tuple of (qubit_0_out, qubit_1_out) after SWAP.


t [source]

def t(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

T gate (fourth root of Z).

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


tdg [source]

def tdg(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

T-dagger gate (inverse of T gate).

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


x [source]

def x(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

Pauli-X gate (NOT gate).

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


y [source]

def y(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

Pauli-Y gate.

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:


z [source]

def z(target: Union[Qubit, Vector[Qubit]]) -> Union[Qubit, Vector[Qubit]]

Pauli-Z gate.

Broadcasts over a Vector[Qubit] when applied to one.

Parameters:

NameTypeDescription
targetUnion[Qubit, Vector[Qubit]]A single Qubit or a Vector[Qubit].

Returns:

Union[Qubit, Vector[Qubit]] — A Qubit for scalar input, a Vector[Qubit] for array input.

Raises:

Classes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


GateOperationType [source]

class GateOperationType(enum.Enum)
Attributes

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,
) -> None
Attributes
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.


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


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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

qamomile.circuit.frontend.param_validation

Validate bound qkernel argument handles against declared parameter types.

These predicates and validators classify a kernel parameter’s declared annotation (scalar Qubit vs. Vector[Qubit], quantum vs. classical) and check that the handle bound to it at a call site matches that declaration. They are shared by the plain qkernel call path (QKernel.__call__ in :mod:qamomile.circuit.frontend.qkernel) and the controlled-gate call path (ControlledGate in :mod:qamomile.circuit.frontend.operation.control). Keeping them in this neutral module means neither of those modules has to import the other just to reach these checks.

Overview

FunctionDescription
is_array_typeCheck if type is a Vector, Matrix, or Tensor subclass.
ClassDescription
Bit
BitTypeType representing a classical bit.
FloatFloating-point handle with arithmetic operations.
FloatTypeType representing a floating-point number.
ObservableTypeType representing a Hamiltonian observable parameter.
Qubit
UIntUnsigned integer handle with arithmetic operations.
UIntTypeType representing an unsigned integer.

Functions

is_array_type [source]

def is_array_type(t: Any) -> bool

Check if type is a Vector, Matrix, or Tensor subclass.

Classes

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

BitType [source]

class BitType(ClassicalTypeMixin, ValueType)

Type representing a classical bit.


Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FloatType [source]

class FloatType(ClassicalTypeMixin, ValueType)

Type representing a floating-point number.


ObservableType [source]

class ObservableType(ObjectTypeMixin, ValueType)

Type representing a Hamiltonian observable parameter.

This is a reference type - the actual qamomile.observable.Hamiltonian is provided via bindings during transpilation. It cannot be constructed or manipulated within qkernels.

Example usage:

import qamomile.circuit as qm
import qamomile.observable as qm_o

# Build Hamiltonian in Python
H = qm_o.Z(0) * qm_o.Z(1)

@qm.qkernel
def vqe(q: qm.Vector[qm.Qubit], H: qm.Observable) -> qm.Float:
    return qm.expval(q, H)

# H is passed as binding
executable = transpiler.transpile(vqe, bindings={"H": H})
Constructor
def __init__(self) -> None

Qubit [source]

class Qubit(Handle)
Constructor
def __init__(
    self,
    value: Value[QubitType],
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
) -> None
Attributes

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

UIntType [source]

class UIntType(ClassicalTypeMixin, ValueType)

Type representing an unsigned integer.


qamomile.circuit.frontend.qkernel

Overview

FunctionDescription
bitCreate a Bit handle from a boolean/int literal or declare a named Bit parameter.
build_param_slotsBuild a ParamSlot tuple for the classical arguments of a kernel.
collect_quantum_rebind_violationsAnalyze func for forbidden quantum rebind patterns.
create_dummy_inputCreate a dummy input based on parameter type annotation.
float_Create a Float handle from a float literal or declare a named Float parameter.
func_to_blockConvert a function to a hierarchical Block.
get_current_tracer
handle_type_mapMap Handle type to ValueType.
is_array_typeCheck if type is a Vector, Matrix, or Tensor subclass.
is_dict_typeCheck if type is a Dict handle type.
is_tuple_typeCheck if type is a Tuple handle type.
qkernelDecorator to define a Qamomile quantum kernel.
qubit_arrayCreate a new qubit array (vector/matrix/tensor) and emit QInitOperations.
traceContext manager to set the current tracer.
transform_control_flow
uintCreate a UInt handle from an integer literal or a named parameter.
ClassDescription
ArrayBaseBase class for array types (Vector, Matrix, Tensor).
ArrayValueAn array of typed IR values.
Bit
BlockUnified block representation for all pipeline stages.
BlockKindClassification of block structure for pipeline stages.
CallBlockOperation
DictDict handle for qkernel functions.
DictValueA dictionary value stored as stable ordered entries.
FloatFloating-point handle with arithmetic operations.
FrontendTransformErrorError during frontend AST-to-builder lowering.
QKernelDecorator class for Qamomile quantum kernels.
QubitRebindErrorQuantum variable reassigned from a different quantum source.
RebindSourceKindDiscriminator for the source of a detected rebind violation.
RebindViolationA detected forbidden quantum variable rebinding.
ResourceEstimateComprehensive resource estimate for a quantum circuit.
ReturnOperationExplicit return operation marking the end of a block with return values.
Tracer
UIntUnsigned integer handle with arithmetic operations.
ValueA typed SSA value in the IR.
Vector1-dimensional array type.

Functions

bit [source]

def bit(arg: bool | str | int) -> Bit

Create a Bit handle from a boolean/int literal or declare a named Bit parameter.


build_param_slots [source]

def build_param_slots(
    signature: inspect.Signature,
    input_types: dict[str, Any],
    *,
    parameters: list[str] | None = None,
    kwargs: dict[str, Any] | None = None,
    qubit_sizes: dict[str, int] | None = None,
    bind_defaults: bool,
) -> tuple[ParamSlot, ...]

Build a ParamSlot tuple for the classical arguments of a kernel.

Mirrors the argument-classification logic in QKernel._create_traced_block so the resulting slot list reflects the same decisions that drive symbolic-vs-bound input creation. Only classical (non-quantum, non-Tuple, non-Dict) arguments are included; pure-quantum arguments live in Block.input_values instead.

Parameters:

NameTypeDescription
signatureinspect.SignatureThe kernel function’s signature.
input_typesdict[str, Any]Resolved frontend type annotations keyed by argument name (typically QKernel.input_types or the equivalent computed in func_to_block).
parameterslist[str] | NoneNames explicitly requested as runtime parameters via parameters=[...]. None is treated as an empty list.
kwargsdict[str, Any] | NoneConcrete values supplied via bindings / direct kwargs. None is treated as an empty dict.
qubit_sizesdict[str, int] | NoneOptional mapping from Vector[Qubit] parameter names to their integer sizes; these are quantum inputs and are not included in the slot list.
bind_defaultsboolWhen True, Python signature defaults are treated as COMPILE_TIME_BOUND with bound_value=default. When False (e.g., the func_to_block path that does not bake in defaults), defaulted arguments stay RUNTIME_PARAMETER and the default appears only in ParamSlot.default.

Returns:

tuple[ParamSlot, ...] — tuple[ParamSlot, ...]: One slot per classical argument, in the order they appear in signature.parameters.


collect_quantum_rebind_violations [source]

def collect_quantum_rebind_violations(func: Callable, quantum_param_names: set[str]) -> list[RebindViolation]

Analyze func for forbidden quantum rebind patterns.

Returns a (possibly empty) list of violations. Never raises on analysis failure – returns [] instead.


create_dummy_input [source]

def create_dummy_input(
    param_type: Any,
    name: str = 'param',
    emit_init: bool = True,
    *,
    shape: tuple[int, ...] | None = None,
) -> Handle

Create a dummy input based on parameter type annotation.

Parameters:

NameTypeDescription
param_typeAnyThe type annotation for the parameter.
namestrName for the value.
emit_initboolIf True, emit QInitOperation for qubit arrays (default: True). Set to False when creating a nested Block’s internal dummy inputs, or when the dummy will receive its qubits from a caller’s CallBlockOperation.
shapetuple[int, ...] | NoneOptional concrete shape for array types. When provided, the dummy array’s shape Values carry compile-time constants instead of symbolic placeholders. Used by call-time sub-kernel specialization so that shape-dependent stdlib helpers (qft / iqft / qpe) resolve get_size to a concrete integer and emit the correct gate sequence. Ignored for non-array types. Default: None (symbolic shape).

Returns:

Handle — A frontend Handle wrapping a dummy Value or ArrayValue suitable for use as a function-parameter input during tracing.

Raises:


float_ [source]

def float_(arg: float | str) -> Float

Create a Float handle from a float literal or declare a named Float parameter.


func_to_block [source]

def func_to_block(func: Callable) -> Block

Convert a function to a hierarchical Block.

Example:

def my_func(a: UInt, b: UInt) -> tuple[UInt]:
    c = a + b
    return (c, )

block = func_to_block(my_func)

get_current_tracer [source]

def get_current_tracer() -> Tracer

handle_type_map [source]

def handle_type_map(handle_type: type[Handle] | type) -> ValueType

Map Handle type to ValueType.


is_array_type [source]

def is_array_type(t: Any) -> bool

Check if type is a Vector, Matrix, or Tensor subclass.


is_dict_type [source]

def is_dict_type(t: Any) -> bool

Check if type is a Dict handle type.


is_tuple_type [source]

def is_tuple_type(t: Any) -> bool

Check if type is a Tuple handle type.


qkernel [source]

def qkernel(func: Callable[P, R]) -> QKernel[P, R]

Decorator to define a Qamomile quantum kernel.

Parameters:

NameTypeDescription
funcCallable[P, R]The function to decorate.

Returns:

QKernel[P, R] — An instance of QKernel wrapping the function.


qubit_array [source]

def qubit_array(
    shape: UInt | int | tuple[UInt | int, ...],
    name: str,
) -> Vector[Qubit] | Matrix[Qubit] | Tensor[Qubit]

Create a new qubit array (vector/matrix/tensor) and emit QInitOperations.


trace [source]

def trace(tracer: Tracer | None = None) -> Generator[Tracer, None, None]

Context manager to set the current tracer.


transform_control_flow [source]

def transform_control_flow(func: Callable)

uint [source]

def uint(arg: int | str) -> UInt

Create a UInt handle from an integer literal or a named parameter.

Parameters:

NameTypeDescription
argint | strAn integer literal to bake in as a compile-time constant, or a str naming a symbolic UInt parameter. A bool is rejected: True / False are not valid integer values here even though bool subclasses int. (Sign is not validated here -- a negative literal is accepted and baked in as-is.)

Returns:

UInt — A constant-valued handle for an int argument, or a named symbolic handle for a str argument.

Raises:

Classes

ArrayBase [source]

class ArrayBase(Handle, Generic[T])

Base class for array types (Vector, Matrix, Tensor).

Provides common functionality for array indexing and element access.

Constructor
def __init__(
    self,
    value: ArrayValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt, ...] = tuple(),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes
Methods
consume
def consume(self, operation_name: str = 'unknown') -> Self

Consume the array, enforcing borrow-return contract for quantum arrays.

For quantum arrays, all borrowed elements must be returned before the array can be consumed. This ensures that no unreturned borrows are silently discarded by operations like qkernel calls or controlled gates.

When any slot of the array has already been physically consumed by an earlier destructive view operation (measure(q[1::2]) then measure(q)), this raises QubitConsumedError rather than silently re-consuming those slots.

create
@classmethod
def create(
    cls,
    shape: tuple[int | UInt, ...],
    name: str,
    el_type: Type[T],
) -> 'ArrayBase[T]'

Create an ArrayValue for the given shape and name.

validate_all_returned
def validate_all_returned(self) -> None

Validate all borrowed elements have been returned.

Strict-return policy: an active slice view that is still registered as the owner of any parent slot is treated as an unreturned borrow even if the view itself has no outstanding element borrows. The caller must perform an explicit slice assignment (parent[a:b:c] = view) to release the view’s bulk-borrow before consuming the parent. Destructively consumed views (parked in the dict with view._consumed set and view._consumed_by classified as :attr:ConsumeMode.DESTRUCTIVE) record physically-destroyed slots and are not outstanding borrows; they survive end-of-block so a later whole-array consume can detect and reject the destroyed slots.

Raises:


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,
) -> None
Attributes
Methods
is_slice
def is_slice(self) -> bool

Return True if this array is a strided view of another array.

Returns:

boolTrue iff slice_of is non-None.

next_version
def next_version(self) -> ArrayValue[T]

Bit [source]

class Bit(Handle)
Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: bool = False,
) -> None
Attributes

Block [source]

class Block

Unified 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(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check 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

CallBlockOperation [source]

class CallBlockOperation(Operation)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    block: Block | None = None,
) -> None
Attributes
Methods
is_self_reference_to
def is_self_reference_to(self, block: Block) -> bool

Return True if this call points to the given block (self-ref).


Dict [source]

class Dict(Handle, Generic[K, V])

Dict handle for qkernel functions.

Represents a dictionary mapping keys to values, commonly used for Ising coefficients like {(i, j): Jij}.

Example:

@qmc.qkernel
def ising_cost(
    q: qmc.Vector[qmc.Qubit],
    ising: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    for (i, j), Jij in qmc.items(ising):
        q[i], q[j] = qmc.rzz(q[i], q[j], gamma * Jij)
    return q
Constructor
def __init__(
    self,
    value: DictValue,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _entries: list[tuple[Handle, Handle]] = list(),
    _size: UInt | None = None,
    _key_type: type | None = None,
) -> None
Attributes
Methods
items
def items(self) -> DictItemsIterator[K, V]

Return an iterator over (key, value) pairs.


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()))(),
) -> None
Attributes
Methods
is_constant
def is_constant(self) -> bool
next_version
def next_version(self) -> DictValue

Float [source]

class Float(ArithmeticMixin, Handle)

Floating-point handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: float = 0.0,
) -> None
Attributes

FrontendTransformError [source]

class FrontendTransformError(QamomileCompileError)

Error during frontend AST-to-builder lowering.


QKernel [source]

class QKernel(Generic[P, R])

Decorator class for Qamomile quantum kernels.

Constructor
def __init__(self, func: Callable[P, R]) -> None
Attributes
Methods
build
def build(self, parameters: list[str] | None = None, **kwargs: Any = {}) -> Block

Build a traced Block by tracing this kernel.

Parameters:

NameTypeDescription
parameterslist[str] | NoneList 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.
**kwargsAnyConcrete values for non-parameter arguments.

Returns:

Block — The traced block ready for transpilation, estimation, or visualization.

Raises:

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 = {},
) -> Any

Visualize 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:

NameTypeDescription
inlineboolIf True, expand CallBlockOperation contents (inlining). If False (default), show CallBlockOperation as boxes.
fold_loopsboolIf True (default), display ForOperation as blocks instead of unrolling. If False, expand loops and show all iterations.
expand_compositeboolIf True, expand CompositeGateOperation (QFT, IQFT, etc.). If False (default), show as boxes. Independent of inline.
inline_depthint | NoneMaximum 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.
**kwargsAnyConcrete values for arguments. Arguments not provided here (and without defaults) will be shown as symbolic parameters.

Returns:

Any — matplotlib.figure.Figure object.

Raises:

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

Estimate 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:

NameTypeDescription
bindingsdict[str, Any] | NoneOptional 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)  # 2

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)


RebindSourceKind [source]

class RebindSourceKind(enum.StrEnum)

Discriminator for the source of a detected rebind violation.

Each value classifies why the analyzer believes an existing quantum binding is being silently discarded, and lets downstream error-message formatting render a domain-appropriate explanation instead of forcing a generic “different quantum variable” sentence onto, e.g., a fresh allocation.

Members:

DIRECT_ALIAS: q = other_q or q = qs[i]. QUANTUM_ARG: q = f(other_q, ...) where other_q has a different origin than q. FRESH_ALLOCATION: q = qm.qubit(...) / qm.qubit_array(...) — the original quantum state is silently discarded in favor of a freshly allocated one. UNKNOWN_CALL: q = some_func(...) where the call references no known quantum variable and is not a recognized quantum constructor; conservatively treated as a rebind because the original q is not threaded through the RHS. CHAINED_ASSIGNMENT: q1 = q2 = expr where at least one target is an existing quantum variable; chained binding semantics are too ambiguous to verify self-update.

Attributes

RebindViolation [source]

class RebindViolation

A detected forbidden quantum variable rebinding.

Constructor
def __init__(
    self,
    target_name: str,
    source_name: str | None,
    source_kind: RebindSourceKind,
    func_name: str | None,
    lineno: int,
    source_expr: str | None = None,
) -> None
Attributes

ResourceEstimate [source]

class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))

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()) -> None
Attributes

Tracer [source]

class Tracer
Constructor
def __init__(self, _operations: list[Operation] = list()) -> None
Attributes
Methods
add_operation
def add_operation(self, op) -> None

UInt [source]

class UInt(ArithmeticMixin, Handle)

Unsigned integer handle with arithmetic operations.

Constructor
def __init__(
    self,
    value: Value,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    init_value: int = 0,
) -> None
Attributes

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, ...] = (),
) -> None
Attributes
Methods
is_array_element
def is_array_element(self) -> bool
next_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.


Vector [source]

class Vector(ArrayBase[T])

1-dimensional array type.

Example:

import qamomile.circuit as qmc

# Create a vector of 3 qubits
qubits: qmc.Vector[qmc.Qubit] = qmc.qubit_array(3, name="qubits")

# Access elements
q0 = qubits[0]
q0 = qmc.h(q0)
qubits[0] = q0

# Apply H gate to all qubits (CORRECT)
n = qubits.shape[0]
for i in qmc.range(n):
    qubits[i] = qmc.h(qubits[i])

# Slicing returns a VectorView over a subset of the parent vector.
# The view shares borrow tracking with the parent; element access
# on the view transparently indexes the parent.
evens = qubits[0::2]
for i in qmc.range(evens.shape[0]):
    evens[i] = qmc.h(evens[i])
Constructor
def __init__(
    self,
    value: ArrayValue = None,
    parent: 'ArrayBase | None' = None,
    indices: tuple['UInt', ...] = (),
    name: str | None = None,
    id: str = (lambda: str(uuid.uuid4()))(),
    _consumed: bool = False,
    _consumed_by: str | None = None,
    _shape: tuple[int | UInt] = (0,),
    _borrowed_indices: dict[tuple[str, ...], 'tuple[UInt, ...] | ArrayBase[T]'] = dict(),
) -> None
Attributes

qamomile.circuit.frontend.tracer

Overview

FunctionDescription
get_current_tracer
traceContext manager to set the current tracer.
ClassDescription
Operation
Tracer

Functions

get_current_tracer [source]

def get_current_tracer() -> Tracer

trace [source]

def trace(tracer: Tracer | None = None) -> Generator[Tracer, None, None]

Context manager to set the current tracer.

Classes

Operation [source]

class Operation(abc.ABC)
Constructor
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Return all input Values including subclass-specific fields.

Generic passes should use this instead of accessing operands directly to ensure no Value is missed. Subclasses override this to include extra Value fields (e.g. ControlledUOperation.power).

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

Return a copy with all Values substituted via mapping.

Handles operands, results, and subclass-specific Value fields. Subclasses override to handle their extra fields.


Tracer [source]

class Tracer
Constructor
def __init__(self, _operations: list[Operation] = list()) -> None
Attributes
Methods
add_operation
def add_operation(self, op) -> None