Qiskit backend transpiler implementation.
This module provides QiskitTranspiler for converting Qamomile QKernels into Qiskit QuantumCircuits.
Overview¶
| Function | Description |
|---|---|
resolve_if_condition | Resolve an if-condition to a compile-time boolean. |
| Class | Description |
|---|---|
EmitError | Error during backend code emission. |
EmitPass | Base class for backend-specific emission passes. |
ForOperation | Represents a for loop operation. |
IfOperation | Represents an if-else conditional operation. |
QiskitEmitPass | Qiskit-specific emission pass. |
QiskitExecutor | Qiskit quantum executor using AerSimulator or other backends. |
QiskitGateEmitter | GateEmitter implementation for Qiskit. |
QiskitTranspiler | Qiskit backend transpiler. |
SeparatePass | Separate a block into quantum and classical segments. |
StandardEmitPass | Standard emit pass implementation using GateEmitter protocol. |
Transpiler | Base class for backend-specific transpilers. |
WhileOperation | Represents a while loop operation. |
Functions¶
resolve_if_condition [source]¶
def resolve_if_condition(condition: Any, bindings: dict[str, Any]) -> bool | NoneResolve 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:
| Name | Type | Description |
|---|---|---|
condition | Any | The condition from IfOperation (plain value or Value object). |
bindings | dict[str, Any] | Current variable bindings (uuid → value and/or name → value). |
Returns:
bool | None — True/False for compile-time resolvable conditions,
bool | None — None 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¶
operation
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:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Values to bind parameters to. If not provided, parameters must be bound at execution time. |
parameters | list[str] | None | List of parameter names to preserve as backend parameters. |
Attributes¶
bindingsname: strparameters
Methods¶
run¶
def run(self, input: 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):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: stroperation_kind: OperationKindoperations: list[Operation]signature: Signature
IfOperation [source]¶
class IfOperation(Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
true_operations: list[Operation] = list(),
false_operations: list[Operation] = list(),
phi_ops: list[PhiOp] = list(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
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:
| Name | Type | Description |
|---|---|---|
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
use_native_composite | bool | If 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:
| Name | Type | Description |
|---|---|---|
backend | `` | Qiskit backend (defaults to AerSimulator if available) |
estimator | `` | Optional QiskitExpectationEstimator for expectation values |
Attributes¶
backend
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:
| Name | Type | Description |
|---|---|---|
circuit | 'QuantumCircuit' | The parameterized circuit |
bindings | dict[str, Any] | Dict mapping parameter names (indexed format) to values |
parameter_metadata | ParameterMetadata | Metadata 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,
) -> floatEstimate the expectation value of a Hamiltonian.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | 'QuantumCircuit' | Qiskit QuantumCircuit (state preparation ansatz) |
hamiltonian | 'qm_o.Hamiltonian' | The qamomile.observable.Hamiltonian to measure |
params | Sequence[float] | None | Optional parameter values for parametric circuits |
Returns:
float — The estimated expectation value
Raises:
RuntimeError— If no estimator is configured
execute¶
def execute(self, circuit: 'QuantumCircuit', shots: int) -> dict[str, int]Execute circuit and return bitstring counts.
Parameters:
| Name | Type | Description |
|---|---|---|
circuit | 'QuantumCircuit' | The quantum circuit to execute |
shots | int | Number of measurement shots |
Returns:
dict[str, int] — Dictionary mapping bitstrings to counts (e.g., {“00”: 512, “11”: 512})
QiskitGateEmitter [source]¶
class QiskitGateEmitterGateEmitter 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]) -> NoneAppend 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) -> AnyCreate a Qiskit Parameter object.
emit_barrier¶
def emit_barrier(self, circuit: 'QuantumCircuit', qubits: list[int]) -> Noneemit_ch¶
def emit_ch(self, circuit: 'QuantumCircuit', control: int, target: int) -> Noneemit_cp¶
def emit_cp(
self,
circuit: 'QuantumCircuit',
control: int,
target: int,
angle: float | Any,
) -> Noneemit_crx¶
def emit_crx(
self,
circuit: 'QuantumCircuit',
control: int,
target: int,
angle: float | Any,
) -> Noneemit_cry¶
def emit_cry(
self,
circuit: 'QuantumCircuit',
control: int,
target: int,
angle: float | Any,
) -> Noneemit_crz¶
def emit_crz(
self,
circuit: 'QuantumCircuit',
control: int,
target: int,
angle: float | Any,
) -> Noneemit_cx¶
def emit_cx(self, circuit: 'QuantumCircuit', control: int, target: int) -> Noneemit_cy¶
def emit_cy(self, circuit: 'QuantumCircuit', control: int, target: int) -> Noneemit_cz¶
def emit_cz(self, circuit: 'QuantumCircuit', control: int, target: int) -> Noneemit_else_start¶
def emit_else_start(self, circuit: 'QuantumCircuit', context: Any) -> NoneHandled by context manager.
emit_for_loop_end¶
def emit_for_loop_end(self, circuit: 'QuantumCircuit', context: Any) -> NoneEnd is handled by context manager exit.
emit_for_loop_start¶
def emit_for_loop_start(self, circuit: 'QuantumCircuit', indexset: range) -> AnyStart 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) -> Noneemit_if_end¶
def emit_if_end(self, circuit: 'QuantumCircuit', context: Any) -> NoneHandled by context manager.
emit_if_start¶
def emit_if_start(self, circuit: 'QuantumCircuit', clbit: int, value: int = 1) -> AnyStart a native if using Qiskit’s if_test context manager.
emit_measure¶
def emit_measure(self, circuit: 'QuantumCircuit', qubit: int, clbit: int) -> Noneemit_p¶
def emit_p(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> Noneemit_rx¶
def emit_rx(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> Noneemit_ry¶
def emit_ry(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> Noneemit_rz¶
def emit_rz(self, circuit: 'QuantumCircuit', qubit: int, angle: float | Any) -> Noneemit_rzz¶
def emit_rzz(
self,
circuit: 'QuantumCircuit',
qubit1: int,
qubit2: int,
angle: float | Any,
) -> Noneemit_s¶
def emit_s(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_sdg¶
def emit_sdg(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_swap¶
def emit_swap(self, circuit: 'QuantumCircuit', qubit1: int, qubit2: int) -> Noneemit_t¶
def emit_t(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_tdg¶
def emit_tdg(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_toffoli¶
def emit_toffoli(
self,
circuit: 'QuantumCircuit',
control1: int,
control2: int,
target: int,
) -> Noneemit_while_end¶
def emit_while_end(self, circuit: 'QuantumCircuit', context: Any) -> NoneHandled by context manager.
emit_while_start¶
def emit_while_start(self, circuit: 'QuantumCircuit', clbit: int, value: int = 1) -> AnyStart a native while loop.
emit_x¶
def emit_x(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_y¶
def emit_y(self, circuit: 'QuantumCircuit', qubit: int) -> Noneemit_z¶
def emit_z(self, circuit: 'QuantumCircuit', qubit: int) -> Nonegate_controlled¶
def gate_controlled(self, gate: Any, num_controls: int) -> AnyCreate controlled version of a gate.
gate_power¶
def gate_power(self, gate: Any, power: int) -> AnyCreate gate raised to a power.
supports_for_loop¶
def supports_for_loop(self) -> boolQiskit supports native for loops.
supports_if_else¶
def supports_if_else(self) -> boolQiskit supports native if/else.
supports_while_loop¶
def supports_while_loop(self) -> boolQiskit supports native while loops.
QiskitTranspiler [source]¶
class QiskitTranspiler(Transpiler['QuantumCircuit'])Qiskit backend transpiler.
Converts Qamomile QKernels into Qiskit QuantumCircuits.
Parameters:
| Name | Type | Description |
|---|---|---|
use_native_composite | bool | If 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:
| Name | Type | Description |
|---|---|---|
use_native_composite | bool | If True, use native Qiskit implementations for QFT/IQFT. If False, use manual decomposition. |
Methods¶
executor¶
def executor(self, backend = None) -> QiskitExecutorCreate a Qiskit executor.
Parameters:
| Name | Type | Description |
|---|---|---|
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:
Materializes return operations (syncs output_values from ReturnOperation)
Splits the operation list into quantum and classical segments
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¶
name: str
Methods¶
run¶
def run(self, input: Block) -> SimplifiedProgramSeparate 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:
| Name | Type | Description |
|---|---|---|
gate_emitter | GateEmitter[T] | Backend-specific gate emitter |
bindings | dict[str, Any] | None | Parameter bindings for the circuit |
parameters | list[str] | None | List of parameter names to preserve as backend parameters |
composite_emitters | list[CompositeGateEmitter[T]] | None | Optional list of CompositeGateEmitter for native implementations |
Constructor¶
def __init__(
self,
gate_emitter: GateEmitter[T],
bindings: dict[str, Any] | None = None,
parameters: list[str] | None = None,
composite_emitters: list[CompositeGateEmitter[T]] | None = None,
)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¶
config: TranspilerConfig Get the transpiler configuration.
Methods¶
affine_validate¶
def affine_validate(self, block: Block) -> BlockPass 1.5: Validate affine type semantics.
This is a safety net to catch affine type violations that may have bypassed frontend checks. Validates that quantum values are used at most once.
analyze¶
def analyze(self, block: Block) -> BlockPass 2: Validate and analyze dependencies.
constant_fold¶
def constant_fold(self, block: Block, bindings: dict[str, Any] | None = None) -> BlockPass 1.5: Fold constant expressions.
Evaluates BinOp operations when all operands are constants
or bound parameters. This prevents quantum segment splitting
from parametric expressions like phase * 2.
emit¶
def emit(
self,
separated: SimplifiedProgram,
bindings: dict[str, Any] | None = None,
parameters: list[str] | None = None,
) -> ExecutableProgram[T]Pass 4: Generate backend-specific code.
Parameters:
| Name | Type | Description |
|---|---|---|
separated | SimplifiedProgram | The separated program to emit |
bindings | dict[str, Any] | None | Parameter values to bind at compile time |
parameters | list[str] | None | Parameter names to preserve as backend parameters |
executor¶
def executor(self, **kwargs: Any = {}) -> QuantumExecutor[T]Create a quantum executor for this backend.
inline¶
def inline(self, block: Block) -> BlockPass 1: Inline all CallBlockOperations.
lower_compile_time_ifs¶
def lower_compile_time_ifs(self, block: Block, bindings: dict[str, Any] | None = None) -> BlockPass 1.75: Lower compile-time resolvable IfOperations.
Evaluates IfOperation conditions (including expression-derived conditions via CompOp/CondOp/NotOp) and replaces resolved ones with selected-branch operations. Phi outputs are substituted with selected-branch values throughout the block.
This prevents SeparatePass from seeing classical-only compile-time IfOperations that would otherwise split quantum segments.
separate¶
def separate(self, block: Block) -> SimplifiedProgramPass 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) -> NoneSet the transpiler configuration.
Parameters:
| Name | Type | Description |
|---|---|---|
config | TranspilerConfig | Transpiler configuration to use |
substitute¶
def substitute(self, block: Block) -> BlockPass 0.5: Apply substitutions (optional).
This pass replaces CallBlockOperation targets and sets strategy names on CompositeGateOperations based on config.
Parameters:
| Name | Type | Description |
|---|---|---|
block | Block | Block to transform |
Returns:
Block — Block with substitutions applied
to_block¶
def to_block(
self,
kernel: QKernel,
bindings: dict[str, Any] | None = None,
parameters: list[str] | None = None,
) -> BlockConvert a QKernel to a Block.
Parameters:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to convert |
bindings | dict[str, Any] | None | Concrete values to bind at trace time (resolves array shapes) |
parameters | list[str] | None | Names to keep as unbound parameters |
When bindings or parameters are provided, uses kernel.build() to properly resolve array shapes from the bound data. Otherwise uses the cached block_value for efficiency.
to_circuit¶
def to_circuit(self, kernel: QKernel, bindings: dict[str, Any] | None = None) -> TCompile and extract just the quantum circuit.
This is a convenience method for when you just want the backend circuit without the full executable.
Parameters:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to compile |
bindings | dict[str, Any] | None | Parameter values to bind |
Returns:
T — Backend-specific quantum circuit
transpile¶
def transpile(
self,
kernel: QKernel,
bindings: dict[str, Any] | None = None,
parameters: list[str] | None = None,
) -> ExecutableProgram[T]Full compilation pipeline from QKernel to executable.
Parameters:
| Name | Type | Description |
|---|---|---|
kernel | QKernel | The QKernel to compile |
bindings | dict[str, Any] | None | Parameter values to bind (also resolves array shapes) |
parameters | list[str] | None | Parameter names to preserve as backend parameters |
Returns:
ExecutableProgram[T] — ExecutableProgram ready for execution
Raises:
QamomileCompileError— If compilation fails (validation, dependency errors)
Pipeline:
to_block: Convert QKernel to Block
substitute: Apply substitutions (if configured)
inline: Inline CallBlockOperations
affine_validate: Validate affine type semantics
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
analyze: Validate and analyze dependencies
separate: Split into quantum/classical segments
emit: Generate backend-specific code
validate_while_contract¶
def validate_while_contract(self, block: Block) -> BlockPass 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(),
) -> NoneAttributes¶
operation_kind: OperationKindoperations: list[Operation]signature: Signature