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

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

qamomile.qiskit.transpiler

Qiskit backend transpiler implementation.

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

Overview

FunctionDescription
resolve_if_conditionResolve an if-condition to a compile-time boolean.
ClassDescription
EmitErrorError during backend code emission.
EmitPassBase class for backend-specific emission passes.
ForOperationRepresents a for loop operation.
IfOperationRepresents an if-else conditional operation.
QiskitEmitPassQiskit-specific emission pass.
QiskitExecutorQiskit quantum executor using AerSimulator or other backends.
QiskitGateEmitterGateEmitter implementation for Qiskit.
QiskitTranspilerQiskit backend transpiler.
SeparatePassSeparate a block into quantum and classical segments.
StandardEmitPassStandard emit pass implementation using GateEmitter protocol.
TranspilerBase class for backend-specific transpilers.
WhileOperationRepresents a while loop operation.

Functions

resolve_if_condition [source]

def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | None

Resolve an if-condition to a compile-time boolean.

Checks whether the condition can be statically evaluated at emit time. Plain Python values (int/bool captured by @qkernel from closure), constant-folded Values, and Values resolvable via bindings are all treated as compile-time constants.

Parameters:

NameTypeDescription
conditionAnyThe condition from IfOperation (plain value or Value object).
bindingsdict[str, Any]Current variable bindings (uuid → value and/or name → value).

Returns:

bool | NoneTrue/False for compile-time resolvable conditions, bool | NoneNone for runtime conditions that must be dispatched to the bool | None — backend’s conditional branching protocol.

Classes

EmitError [source]

class EmitError(QamomileCompileError)

Error during backend code emission.

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

EmitPass [source]

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

Base class for backend-specific emission passes.

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

Input: SimplifiedProgram (enforces C→Q→C pattern) Output: ExecutableProgram with compiled segments

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

Initialize with optional parameter bindings.

Parameters:

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

Emit backend code from simplified program.


ForOperation [source]

class ForOperation(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 = '',
    operations: list[Operation] = list(),
) -> None
Attributes

IfOperation [source]

class IfOperation(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

QiskitEmitPass [source]

class QiskitEmitPass(StandardEmitPass['QuantumCircuit'])

Qiskit-specific emission pass.

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

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

Initialize the Qiskit emit pass.

Parameters:

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

QiskitExecutor [source]

class QiskitExecutor(QuantumExecutor['QuantumCircuit'])

Qiskit quantum executor using AerSimulator or other backends.

Example:

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

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

Initialize executor with backend and optional estimator.

Parameters:

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

Bind parameter values to the Qiskit circuit.

Parameters:

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

Returns:

'QuantumCircuit' — New circuit with parameters bound

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

Estimate the expectation value of a Hamiltonian.

Parameters:

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

Returns:

float — The estimated expectation value

Raises:

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

Execute circuit and return bitstring counts.

Parameters:

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

Returns:

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


QiskitGateEmitter [source]

class QiskitGateEmitter

GateEmitter implementation for Qiskit.

Emits individual quantum gates to Qiskit QuantumCircuit objects.

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

Append a gate to the circuit.

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

Convert circuit to a reusable gate.

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

Create a new Qiskit QuantumCircuit.

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

Create a Qiskit Parameter object.

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

Handled by context manager.

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

End is handled by context manager exit.

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

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

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

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

Handled by context manager.

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

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

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

Handled by context manager.

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

Start a native while loop.

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

Create controlled version of a gate.

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

Create gate raised to a power.

supports_for_loop
def supports_for_loop(self) -> bool

Qiskit supports native for loops.

supports_if_else
def supports_if_else(self) -> bool

Qiskit supports native if/else.

supports_while_loop
def supports_while_loop(self) -> bool

Qiskit supports native while loops.


QiskitTranspiler [source]

class QiskitTranspiler(Transpiler['QuantumCircuit'])

Qiskit backend transpiler.

Converts Qamomile QKernels into Qiskit QuantumCircuits.

Parameters:

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

Example:

from qamomile.qiskit import QiskitTranspiler
import qamomile as qm

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

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

Initialize the Qiskit transpiler.

Parameters:

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

Create a Qiskit executor.

Parameters:

NameTypeDescription
backend``Qiskit backend (defaults to AerSimulator)

Returns:

QiskitExecutor — QiskitExecutor configured with the backend


SeparatePass [source]

class SeparatePass(Pass[Block, SimplifiedProgram])

Separate a block into quantum and classical segments.

This pass:

  1. Materializes return operations (syncs output_values from ReturnOperation)

  2. Splits the operation list into quantum and classical segments

  3. Validates single quantum segment (enforces C→Q→C pattern)

Input: Block (typically ANALYZED or AFFINE) Output: SimplifiedProgram with single quantum segment and optional prep/post

Attributes
Methods
run
def run(self, input: Block) -> SimplifiedProgram

Separate the block into segments.


StandardEmitPass [source]

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

Standard emit pass implementation using GateEmitter protocol.

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

Parameters:

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

Transpiler [source]

class Transpiler(ABC, Generic[T])

Base class for backend-specific transpilers.

Provides the full compilation pipeline from QKernel to executable program.

Usage:

transpiler = QiskitTranspiler()

Option 1: Full pipeline

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

Option 2: Step-by-step

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

Option 3: Just get the circuit (no execution)

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

With configuration (strategy overrides)

config = TranspilerConfig.with_strategies({“qft”: “approximate”}) transpiler = QiskitTranspiler(config=config)

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

Pass 1.5: Validate affine type semantics.

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

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

Pass 2: Validate and analyze dependencies.

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

Pass 1.5: Fold constant expressions.

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

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

Pass 4: Generate backend-specific code.

Parameters:

NameTypeDescription
separatedSimplifiedProgramThe separated program to emit
bindingsdict[str, Any] | NoneParameter values to bind at compile time
parameterslist[str] | NoneParameter names to preserve as backend parameters
executor
def executor(self, **kwargs: Any = {}) -> QuantumExecutor[T]

Create a quantum executor for this backend.

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

Pass 1: Inline all CallBlockOperations.

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

Pass 1.75: Lower compile-time resolvable IfOperations.

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

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

separate
def separate(self, block: Block) -> SimplifiedProgram

Pass 3: Lower and split into quantum and classical segments.

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

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

Set the transpiler configuration.

Parameters:

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

Pass 0.5: Apply substitutions (optional).

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

Parameters:

NameTypeDescription
blockBlockBlock to transform

Returns:

Block — Block with substitutions applied

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

Convert a QKernel to a Block.

Parameters:

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

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

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

Compile and extract just the quantum circuit.

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

Parameters:

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

Returns:

T — Backend-specific quantum circuit

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

Full compilation pipeline from QKernel to executable.

Parameters:

NameTypeDescription
kernelQKernelThe QKernel to compile
bindingsdict[str, Any] | NoneParameter values to bind (also resolves array shapes)
parameterslist[str] | NoneParameter names to preserve as backend parameters

Returns:

ExecutableProgram[T] — ExecutableProgram ready for execution

Raises:

Pipeline:

  1. to_block: Convert QKernel to Block

  2. substitute: Apply substitutions (if configured)

  3. inline: Inline CallBlockOperations

  4. affine_validate: Validate affine type semantics

  5. constant_fold: Fold constant expressions 5.5. lower_compile_time_ifs: Lower compile-time IfOperations 5.8. validate_while_contract: Validate while conditions are measurement-backed

  6. analyze: Validate and analyze dependencies

  7. separate: Split into quantum/classical segments

  8. emit: Generate backend-specific code

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

Pass 1.8: Validate WhileOperation conditions are measurement-backed.

Rejects while patterns whose condition is not a measurement result (Bit from qmc.measure()). This prevents late ValueError at emit time for unsupported while forms.


WhileOperation [source]

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