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

Algorithm building blocks for quantum circuits.

Overview

FunctionDescription
cost_layerApply the cost (phase separation) layer.
cx_entangling_layerApply CX entangling layer with linear connectivity.
cz_entangling_layerApply CZ entangling layer with linear connectivity.
fqaoa_layersApply p layers of cost + mixer.
fqaoa_stateGenerate complete FQAOA state.
givens_rotationApply a single Givens rotation between qubits i and j.
givens_rotationsApply a sequence of Givens rotations.
hopping_gateApply the fermionic hopping gate between qubits i and j.
hubo_ising_costApply the full cost layer including higher-order terms.
hubo_qaoa_layersApply p layers of the HUBO QAOA circuit (cost + mixer).
hubo_qaoa_stateGenerate HUBO QAOA state.
initial_occupationsApply X gates to the first num_fermions qubits.
ising_costApply the Ising cost layer for quadratic interactions.
mixer_layerApply the fermionic mixer layer (even-odd-boundary hopping).
qaoa_layersApply p layers of the QAOA circuit (cost + mixer).
qaoa_stateGenerate QAOA State for Ising model.
rx_layerApply RX rotation to each qubit.
ry_layerApply RY rotation to each qubit.
rz_layerApply RZ rotation to each qubit.
superposition_vectorCreate a uniform superposition state by applying Hadamard to all qubits.
trotterized_time_evolutionApply Suzuki-Trotter time evolution exp(-i gamma H) to q.
x_mixerApply the X-mixer layer.

Functions

cost_layer [source]

def cost_layer(
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply the cost (phase separation) layer.


cx_entangling_layer [source]

def cx_entangling_layer(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]

Apply CX entangling layer with linear connectivity.

Applies CX gates between consecutive qubits: (0,1), (1,2), ..., (n-2,n-1).

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Qubit vector after entanglement


cz_entangling_layer [source]

def cz_entangling_layer(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]

Apply CZ entangling layer with linear connectivity.

Applies CZ gates between consecutive qubits: (0,1), (1,2), ..., (n-2,n-1).

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after entanglement


fqaoa_layers [source]

def fqaoa_layers(
    q: qmc.Vector[qmc.Qubit],
    betas: qmc.Vector[qmc.Float],
    gammas: qmc.Vector[qmc.Float],
    p: qmc.UInt,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    hopping: qmc.Float,
    num_qubits: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply p layers of cost + mixer.


fqaoa_state [source]

def fqaoa_state(
    p: qmc.UInt,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    num_qubits: qmc.UInt,
    num_fermions: qmc.UInt,
    givens_ij: qmc.Matrix[qmc.UInt],
    givens_theta: qmc.Vector[qmc.Float],
    hopping: qmc.Float,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate complete FQAOA state.

Parameters:

NameTypeDescription
pqmc.UIntNumber of FQAOA layers.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of Ising model.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of Ising model.
num_qubitsqmc.UIntNumber of qubits.
num_fermionsqmc.UIntNumber of fermions for initial state.
givens_ijqmc.Matrix[qmc.UInt]Matrix of shape (N, 2) with qubit index pairs for Givens rotations.
givens_thetaqmc.Vector[qmc.Float]Vector of length N with Givens rotation angles.
hoppingqmc.FloatHopping integral for the mixer.
gammasqmc.Vector[qmc.Float]Vector of gamma parameters.
betasqmc.Vector[qmc.Float]Vector of beta parameters.

Returns:

qmc.Vector[qmc.Qubit] — FQAOA state vector.


givens_rotation [source]

def givens_rotation(
    q: qmc.Vector[qmc.Qubit],
    i: qmc.UInt,
    j: qmc.UInt,
    theta: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply a single Givens rotation between qubits i and j.

The controlled-RY factory is constructed inside the function rather than at module level so importing fqaoa does not trigger eager wrapper synthesis (compile/exec + tracing) for every install. The synthesized wrapper is cached per-callable inside qmc.controlled, so the only real cost happens on the first Givens rotation; subsequent calls hit the cache.


givens_rotations [source]

def givens_rotations(
    q: qmc.Vector[qmc.Qubit],
    givens_ij: qmc.Matrix[qmc.UInt],
    givens_theta: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply a sequence of Givens rotations.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register.
givens_ijqmc.Matrix[qmc.UInt]Matrix of shape (N, 2) where each row [i, j] contains the qubit indices for one Givens rotation.
givens_thetaqmc.Vector[qmc.Float]Vector of length N with the rotation angles.

hopping_gate [source]

def hopping_gate(
    q: qmc.Vector[qmc.Qubit],
    i: qmc.UInt,
    j: qmc.UInt,
    beta: qmc.Float,
    hopping: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the fermionic hopping gate between qubits i and j.


hubo_ising_cost [source]

def hubo_ising_cost(
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the full cost layer including higher-order terms.

Applies the standard quadratic Ising cost circuit, then decomposes each higher-order term into phase gadgets.

Parameters:

NameTypeDescription
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients J_{ij} of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients h_i of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
qqmc.Vector[qmc.Qubit]Qubit register.
gammaqmc.FloatVariational parameter for the cost layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


hubo_qaoa_layers [source]

def hubo_qaoa_layers(
    p_val: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply p layers of the HUBO QAOA circuit (cost + mixer).

Each layer applies the HUBO cost circuit (quadratic + higher-order terms) followed by the X-mixer circuit.

Parameters:

NameTypeDescription
p_valqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
qqmc.Vector[qmc.Qubit]Qubit register.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register after all layers.


hubo_qaoa_state [source]

def hubo_qaoa_state(
    p_val: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    n: qmc.UInt,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate HUBO QAOA state.

Creates a uniform superposition and applies p layers of the HUBO QAOA circuit.

Parameters:

NameTypeDescription
p_valqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
nqmc.UIntNumber of qubits.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: HUBO QAOA state vector.


initial_occupations [source]

def initial_occupations(q: qmc.Vector[qmc.Qubit], num_fermions: qmc.UInt) -> qmc.Vector[qmc.Qubit]

Apply X gates to the first num_fermions qubits.


ising_cost [source]

def ising_cost(
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the Ising cost layer for quadratic interactions.

Applies RZZ gates for quadratic terms and RZ gates for linear terms, each scaled by the variational parameter gamma.

Parameters:

NameTypeDescription
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients J_{ij} of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients h_i of the Ising model.
qqmc.Vector[qmc.Qubit]Qubit register.
gammaqmc.FloatVariational parameter for the cost layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


mixer_layer [source]

def mixer_layer(
    q: qmc.Vector[qmc.Qubit],
    beta: qmc.Float,
    hopping: qmc.Float,
    num_qubits: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply the fermionic mixer layer (even-odd-boundary hopping).


qaoa_layers [source]

def qaoa_layers(
    p: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply p layers of the QAOA circuit (cost + mixer).

Each layer applies the Ising cost circuit followed by the X-mixer circuit.

Parameters:

NameTypeDescription
pqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
qqmc.Vector[qmc.Qubit]Qubit register.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register after all layers.


qaoa_state [source]

def qaoa_state(
    p: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    n: qmc.UInt,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate QAOA State for Ising model.

Parameters:

NameTypeDescription
pqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
nqmc.UIntNumber of qubits.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: QAOA state vector.


rx_layer [source]

def rx_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RX rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


ry_layer [source]

def ry_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RY rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


rz_layer [source]

def rz_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RZ rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


superposition_vector [source]

def superposition_vector(n: qmc.UInt) -> qmc.Vector[qmc.Qubit]

Create a uniform superposition state by applying Hadamard to all qubits.

Parameters:

NameTypeDescription
nqmc.UIntNumber of qubits.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Qubit register in the |+>^n state.


trotterized_time_evolution [source]

def trotterized_time_evolution(
    q: qmc.Vector[qmc.Qubit],
    hamiltonian: qmc.Vector[qmc.Observable] | Sequence[Hamiltonian],
    order: int | qmc.UInt,
    gamma: float | qmc.Float,
    step: int | qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply Suzuki-Trotter time evolution exp(-i gamma H) to q.

H = sum_k hamiltonian[k]. The evolution is split into step Trotter slices of size dt = gamma / step; each slice applies the order-th Suzuki-Trotter formula via :func:_trotter_evolve.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register handle.
hamiltonianqmc.Vector[qmc.Observable] | Sequence[Hamiltonian]qmc.Vector[qmc.Observable] when called from a @qkernel (the handle type for a vector of Hamiltonians), or a Python list of qamomile.observable.Hamiltonian objects. At least two sub-Hamiltonian terms are required.
orderint | qmc.UIntApproximation order — 1 or a positive even integer (2, 4, 6, …). Must be a compile-time constant.
gammafloat | qmc.FloatTotal evolution time.
stepint | qmc.UIntNumber of Trotter steps.

Returns:

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

Raises:


x_mixer [source]

def x_mixer(q: qmc.Vector[qmc.Qubit], beta: qmc.Float) -> qmc.Vector[qmc.Qubit]

Apply the X-mixer layer.

Applies RX(2*beta) to every qubit in the register.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register.
betaqmc.FloatVariational parameter for the mixer layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


qamomile.circuit.algorithm.basic

Basic building blocks for variational quantum circuits.

This module provides fundamental rotation layers and entanglement layers that can be composed to build variational ansatze.

Overview

FunctionDescription
cx_entangling_layerApply CX entangling layer with linear connectivity.
cz_entangling_layerApply CZ entangling layer with linear connectivity.
phase_gadgetApply exp(-i * angle/2 * Z_{i0} Z_{i1} ... Z_{ik-1}).
rx_layerApply RX rotation to each qubit.
ry_layerApply RY rotation to each qubit.
rz_layerApply RZ rotation to each qubit.
superposition_vectorCreate a uniform superposition state by applying Hadamard to all qubits.

Functions

cx_entangling_layer [source]

def cx_entangling_layer(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]

Apply CX entangling layer with linear connectivity.

Applies CX gates between consecutive qubits: (0,1), (1,2), ..., (n-2,n-1).

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Qubit vector after entanglement


cz_entangling_layer [source]

def cz_entangling_layer(q: qmc.Vector[qmc.Qubit]) -> qmc.Vector[qmc.Qubit]

Apply CZ entangling layer with linear connectivity.

Applies CZ gates between consecutive qubits: (0,1), (1,2), ..., (n-2,n-1).

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after entanglement


phase_gadget [source]

def phase_gadget(
    q: qmc.Vector[qmc.Qubit],
    indices: qmc.Vector[qmc.UInt],
    angle: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply exp(-i * angle/2 * Z_{i0} Z_{i1} ... Z_{ik-1}).

Decomposes a k-body Z-rotation into CX + RZ primitives.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register.
indicesqmc.Vector[qmc.UInt]Qubit indices for the interaction term. Must be non-empty.
angleqmc.FloatRotation angle in radians.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


rx_layer [source]

def rx_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RX rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


ry_layer [source]

def ry_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RY rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


rz_layer [source]

def rz_layer(
    q: qmc.Vector[qmc.Qubit],
    thetas: qmc.Vector[qmc.Float],
    offset: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply RZ rotation to each qubit.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit vector
thetasqmc.Vector[qmc.Float]Parameter vector
offsetqmc.UIntStarting index in thetas (consumes q.shape[0] parameters)

Returns:

qmc.Vector[qmc.Qubit] — Qubit vector after rotations


superposition_vector [source]

def superposition_vector(n: qmc.UInt) -> qmc.Vector[qmc.Qubit]

Create a uniform superposition state by applying Hadamard to all qubits.

Parameters:

NameTypeDescription
nqmc.UIntNumber of qubits.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Qubit register in the |+>^n state.


qamomile.circuit.algorithm.fqaoa

FQAOA (Fermionic QAOA) circuit building blocks.

This module provides the quantum circuit components for the Fermionic Quantum Approximate Optimization Algorithm (FQAOA), including Givens rotations for initial state preparation, hopping gates for the fermionic mixer, and cost layer construction.

All functions are decorated with @qm_c.qkernel and use Handle-typed parameters so they can be composed inside other @qkernel functions.

Overview

FunctionDescription
cost_layerApply the cost (phase separation) layer.
fqaoa_layersApply p layers of cost + mixer.
fqaoa_stateGenerate complete FQAOA state.
givens_rotationApply a single Givens rotation between qubits i and j.
givens_rotationsApply a sequence of Givens rotations.
hopping_gateApply the fermionic hopping gate between qubits i and j.
initial_occupationsApply X gates to the first num_fermions qubits.
mixer_layerApply the fermionic mixer layer (even-odd-boundary hopping).

Functions

cost_layer [source]

def cost_layer(
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply the cost (phase separation) layer.


fqaoa_layers [source]

def fqaoa_layers(
    q: qmc.Vector[qmc.Qubit],
    betas: qmc.Vector[qmc.Float],
    gammas: qmc.Vector[qmc.Float],
    p: qmc.UInt,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    hopping: qmc.Float,
    num_qubits: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply p layers of cost + mixer.


fqaoa_state [source]

def fqaoa_state(
    p: qmc.UInt,
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    num_qubits: qmc.UInt,
    num_fermions: qmc.UInt,
    givens_ij: qmc.Matrix[qmc.UInt],
    givens_theta: qmc.Vector[qmc.Float],
    hopping: qmc.Float,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate complete FQAOA state.

Parameters:

NameTypeDescription
pqmc.UIntNumber of FQAOA layers.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of Ising model.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of Ising model.
num_qubitsqmc.UIntNumber of qubits.
num_fermionsqmc.UIntNumber of fermions for initial state.
givens_ijqmc.Matrix[qmc.UInt]Matrix of shape (N, 2) with qubit index pairs for Givens rotations.
givens_thetaqmc.Vector[qmc.Float]Vector of length N with Givens rotation angles.
hoppingqmc.FloatHopping integral for the mixer.
gammasqmc.Vector[qmc.Float]Vector of gamma parameters.
betasqmc.Vector[qmc.Float]Vector of beta parameters.

Returns:

qmc.Vector[qmc.Qubit] — FQAOA state vector.


givens_rotation [source]

def givens_rotation(
    q: qmc.Vector[qmc.Qubit],
    i: qmc.UInt,
    j: qmc.UInt,
    theta: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply a single Givens rotation between qubits i and j.

The controlled-RY factory is constructed inside the function rather than at module level so importing fqaoa does not trigger eager wrapper synthesis (compile/exec + tracing) for every install. The synthesized wrapper is cached per-callable inside qmc.controlled, so the only real cost happens on the first Givens rotation; subsequent calls hit the cache.


givens_rotations [source]

def givens_rotations(
    q: qmc.Vector[qmc.Qubit],
    givens_ij: qmc.Matrix[qmc.UInt],
    givens_theta: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply a sequence of Givens rotations.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register.
givens_ijqmc.Matrix[qmc.UInt]Matrix of shape (N, 2) where each row [i, j] contains the qubit indices for one Givens rotation.
givens_thetaqmc.Vector[qmc.Float]Vector of length N with the rotation angles.

hopping_gate [source]

def hopping_gate(
    q: qmc.Vector[qmc.Qubit],
    i: qmc.UInt,
    j: qmc.UInt,
    beta: qmc.Float,
    hopping: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the fermionic hopping gate between qubits i and j.


initial_occupations [source]

def initial_occupations(q: qmc.Vector[qmc.Qubit], num_fermions: qmc.UInt) -> qmc.Vector[qmc.Qubit]

Apply X gates to the first num_fermions qubits.


mixer_layer [source]

def mixer_layer(
    q: qmc.Vector[qmc.Qubit],
    beta: qmc.Float,
    hopping: qmc.Float,
    num_qubits: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply the fermionic mixer layer (even-odd-boundary hopping).


qamomile.circuit.algorithm.qaoa

Overview

FunctionDescription
hubo_ising_costApply the full cost layer including higher-order terms.
hubo_qaoa_layersApply p layers of the HUBO QAOA circuit (cost + mixer).
hubo_qaoa_stateGenerate HUBO QAOA state.
ising_costApply the Ising cost layer for quadratic interactions.
qaoa_layersApply p layers of the QAOA circuit (cost + mixer).
qaoa_stateGenerate QAOA State for Ising model.
x_mixerApply the X-mixer layer.

Functions

hubo_ising_cost [source]

def hubo_ising_cost(
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the full cost layer including higher-order terms.

Applies the standard quadratic Ising cost circuit, then decomposes each higher-order term into phase gadgets.

Parameters:

NameTypeDescription
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients J_{ij} of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients h_i of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
qqmc.Vector[qmc.Qubit]Qubit register.
gammaqmc.FloatVariational parameter for the cost layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


hubo_qaoa_layers [source]

def hubo_qaoa_layers(
    p_val: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply p layers of the HUBO QAOA circuit (cost + mixer).

Each layer applies the HUBO cost circuit (quadratic + higher-order terms) followed by the X-mixer circuit.

Parameters:

NameTypeDescription
p_valqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
qqmc.Vector[qmc.Qubit]Qubit register.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register after all layers.


hubo_qaoa_state [source]

def hubo_qaoa_state(
    p_val: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    higher: qmc.Dict[qmc.Vector[qmc.UInt], qmc.Float],
    n: qmc.UInt,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate HUBO QAOA state.

Creates a uniform superposition and applies p layers of the HUBO QAOA circuit.

Parameters:

NameTypeDescription
p_valqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
higherqmc.Dict[qmc.Vector[qmc.UInt], qmc.Float]Higher-order coefficients keyed by index vectors.
nqmc.UIntNumber of qubits.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: HUBO QAOA state vector.


ising_cost [source]

def ising_cost(
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gamma: qmc.Float,
) -> qmc.Vector[qmc.Qubit]

Apply the Ising cost layer for quadratic interactions.

Applies RZZ gates for quadratic terms and RZ gates for linear terms, each scaled by the variational parameter gamma.

Parameters:

NameTypeDescription
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients J_{ij} of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients h_i of the Ising model.
qqmc.Vector[qmc.Qubit]Qubit register.
gammaqmc.FloatVariational parameter for the cost layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


qaoa_layers [source]

def qaoa_layers(
    p: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    q: qmc.Vector[qmc.Qubit],
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Apply p layers of the QAOA circuit (cost + mixer).

Each layer applies the Ising cost circuit followed by the X-mixer circuit.

Parameters:

NameTypeDescription
pqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
qqmc.Vector[qmc.Qubit]Qubit register.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register after all layers.


qaoa_state [source]

def qaoa_state(
    p: qmc.UInt,
    quad: qmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float],
    linear: qmc.Dict[qmc.UInt, qmc.Float],
    n: qmc.UInt,
    gammas: qmc.Vector[qmc.Float],
    betas: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Qubit]

Generate QAOA State for Ising model.

Parameters:

NameTypeDescription
pqmc.UIntNumber of QAOA layers.
quadqmc.Dict[qmc.Tuple[qmc.UInt, qmc.UInt], qmc.Float]Quadratic coefficients of the Ising model.
linearqmc.Dict[qmc.UInt, qmc.Float]Linear coefficients of the Ising model.
nqmc.UIntNumber of qubits.
gammasqmc.Vector[qmc.Float]Cost-layer parameters, one per layer.
betasqmc.Vector[qmc.Float]Mixer-layer parameters, one per layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: QAOA state vector.


x_mixer [source]

def x_mixer(q: qmc.Vector[qmc.Qubit], beta: qmc.Float) -> qmc.Vector[qmc.Qubit]

Apply the X-mixer layer.

Applies RX(2*beta) to every qubit in the register.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register.
betaqmc.FloatVariational parameter for the mixer layer.

Returns:

qmc.Vector[qmc.Qubit] — qmc.Vector[qmc.Qubit]: Updated qubit register.


qamomile.circuit.algorithm.state_preparation

State-preparation building blocks.

Available routines:

The classical Möttönen angle precomputation (compute_mottonen_amplitude_encoding_ry_angles / compute_mottonen_amplitude_encoding_rz_angles) lives in :mod:qamomile.linalg. Import them from there directly when you need to feed pre-computed angles into amplitude_encoding_from_angles::

from qamomile.linalg import (
    compute_mottonen_amplitude_encoding_ry_angles,
    compute_mottonen_amplitude_encoding_rz_angles,
)

Overview

FunctionDescription
amplitude_encodingApply Möttönen amplitude encoding to qubits in place.
amplitude_encoding_from_anglesApply Möttönen amplitude encoding from pre-computed Ry / Rz angles.
ClassDescription
MottonenAmplitudeEncodingMöttönen amplitude encoding for normalised real or complex vectors.

Functions

amplitude_encoding [source]

def amplitude_encoding(
    qubits: Vector[Qubit],
    amplitudes: Sequence[float] | Sequence[complex] | np.ndarray | Vector[Float],
) -> Vector[Qubit]

Apply Möttönen amplitude encoding to qubits in place.

Convenience wrapper around :class:MottonenAmplitudeEncoding that accepts a Vector handle and writes the gated qubits back into the same vector. Real and complex amplitudes are both supported; see the class docstring for the gate-count tradeoff between the two paths.

.. important::

**Pre-condition: ``qubits`` must currently be in the all-zero
state** $|0\rangle^{\otimes n}$.  Möttönen encodes the
unitary that takes $|0\rangle^{\otimes n}$ to the
normalised target; applied to any other state it produces a
different (in general meaningless) output.  In practice call
this immediately after ``qmc.qubit_array(n, ...)`` inside a
kernel.

amplitudes may be supplied as one of three forms:

Parameters:

NameTypeDescription
qubitsVector[Qubit]Vector of n qubit handles, expected to start in 0n|0\rangle^{\otimes n}.
amplitudesSequence[float] | Sequence[complex] | np.ndarray | Vector[Float]Amplitude vector of length 2**n. Concrete sequences and np.ndarray accept both real and complex inputs and are normalised automatically. Vector[Float] is accepted only when (a) its concrete values are available at trace time (i.e., it came from a bindings={...} entry, not from parameters=[...]) and (b) the values are real; complex amplitudes via a kernel parameter must instead go through :func:amplitude_encoding_from_angles.

Returns:

Vector[Qubit] — Vector[Qubit]: The same qubits vector, with each element updated to the post-encoding qubit handle.

Raises:

Example::

# Concrete Python amplitudes
@qmc.qkernel
def prepare() -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding(q, [1.0, 0.0, 0.0, 1.0])
    return qmc.measure(q)

# Bound Vector[Float] kernel parameter
@qmc.qkernel
def prepare(amps: qmc.Vector[qmc.Float]) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding(q, amps)
    return qmc.measure(q)

transpiler.transpile(prepare, bindings={"amps": [1.0, 0.0, 0.0, 1.0]})

amplitude_encoding_from_angles [source]

def amplitude_encoding_from_angles(
    qubits: Vector[Qubit],
    ry_angles: Sequence[float] | np.ndarray | Vector[Float],
    rz_angles: Sequence[float] | np.ndarray | Vector[Float] | None = None,
) -> Vector[Qubit]

Apply Möttönen amplitude encoding from pre-computed Ry / Rz angles.

.. important::

**Pre-condition: ``qubits`` must currently be in the all-zero
state** $|0\rangle^{\otimes n}$.  The Möttönen Gray-walk
emission produced by these angle vectors only encodes the
intended state when starting from $|0\rangle^{\otimes n}$;
applied to any other input it produces ``U |\phi\rangle`` for
the same ``U`` and a different ``|\phi\rangle``, which is in
general not the target amplitude vector.

Companion to :func:amplitude_encoding for the parametric use case: the user pre-computes the Gray-walk Ry (and optionally Rz) angles classically with :func:qamomile.linalg.compute_mottonen_amplitude_encoding_ry_angles and :func:qamomile.linalg.compute_mottonen_amplitude_encoding_rz_angles, then passes them in as either concrete sequences or as Vector[Float] handles obtained from kernel parameters. In the latter case the angles can be left as runtime parameters (transpiler.transpile(kernel, parameters=["ry_angles", ...])) so the same compiled circuit can be re-bound to different amplitude vectors without recompilation — useful inside hybrid optimisation loops.

Unlike :func:amplitude_encoding, this function does NOT wrap the emission in a :class:MottonenAmplitudeEncoding CompositeGate box on the IR side; the Ry / Rz / CNOT Gray-walk gates are emitted directly into the surrounding kernel. Resource estimation / visualization will therefore see the elementary gates rather than a single high-level op.

Parameters:

NameTypeDescription
qubitsVector[Qubit]Vector of n qubit handles, expected to start in 0n|0\rangle^{\otimes n}.
ry_anglesSequence[float] | np.ndarray | Vector[Float]Gray-walk Ry angles for the magnitude stage. Must have length 2**n - 1.
rz_anglesSequence[float] | np.ndarray | Vector[Float] | NoneGray-walk Rz angles for the phase stage. Pass None (default) to skip the Rz stage entirely (real-amplitude path); otherwise must have length 2**n - 1 as well.

Returns:

Vector[Qubit] — Vector[Qubit]: The same qubits vector, with each element updated to the post-encoding qubit handle.

Raises:

Example::

from qamomile.linalg import (
    compute_mottonen_amplitude_encoding_ry_angles,
    compute_mottonen_amplitude_encoding_rz_angles,
)

# Pre-compute classically (outside the kernel)
ry = compute_mottonen_amplitude_encoding_ry_angles(amps)
rz = compute_mottonen_amplitude_encoding_rz_angles(amps)

@qmc.qkernel
def prepare(
    ry_a: qmc.Vector[qmc.Float],
    rz_a: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding_from_angles(q, ry_a, rz_a)
    return qmc.measure(q)

exe = transpiler.transpile(prepare, parameters=["ry_a", "rz_a"])
# Same compiled circuit, re-bound at "runtime":
exe.run(transpiler.executor(),
        bindings={"ry_a": ry.tolist(), "rz_a": rz.tolist()})

Classes

MottonenAmplitudeEncoding [source]

class MottonenAmplitudeEncoding(CompositeGate)

Möttönen amplitude encoding for normalised real or complex vectors.

Prepares the state iaii\sum_i a_i |i\rangle from 0n|0\rangle^{\otimes n} using uniformly controlled Y (and, for genuinely complex inputs, Z) rotations decomposed into RY / RZ and CNOT gates with Gray-code ordering.

.. important::

**Pre-condition: the input qubits must be in the all-zero state**
$|0\rangle^{\otimes n}$.  The gate emits the unitary
that maps $|0\rangle^{\otimes n}$ to the target
$|\psi\rangle$.  Applied to any other input it
produces ``U |\phi\rangle`` for that ``|\phi\rangle`` —
which is *not* the target amplitude vector.  Qamomile does
not track qubit states at runtime, so this is the caller's
responsibility.

Notes:

Example::

# Real amplitudes (signed allowed)
gate = MottonenAmplitudeEncoding([1.0, 0.0, 0.0, 1.0])
q0, q1 = gate(q0, q1)

# Complex amplitudes
gate = MottonenAmplitudeEncoding([1+0j, 1j, -1+0j, -1j])
q0, q1 = gate(q0, q1)
Constructor
def __init__(self, amplitudes: Sequence[float] | Sequence[complex] | np.ndarray)

Initialise the gate with a concrete amplitude vector.

Runs the full normalisation + complex-detection pass eagerly (O(2^n)) so that input errors — wrong shape, length not a power of two, all-zero amplitudes — surface at construction time rather than at the first _resources() / _decompose() call. Angle precomputation (O(n * 2^n)) stays deferred: it runs lazily on the first _decompose() call and is cached afterwards.

This keeps the dominant cost of Möttönen out of kernel-build time when the gate is later only used for resource estimation. In practice the CompositeGate.__call__ framework eagerly invokes _decompose() to build the implementation block when the gate is invoked inside a @qkernel, so the lazy aspect currently bites only for code that constructs MottonenAmplitudeEncoding standalone — but the laziness still matters there, and is the right shape for a future framework refactor that defers _decompose() until emit time.

Parameters:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude vector of length 2**n. Real or complex; it is automatically normalised. Complex inputs with zero imaginary part are coerced to real (single-stage RY path).

Raises:

Attributes

qamomile.circuit.algorithm.state_preparation.mottonen_amplitude_encoding

State preparation via Möttönen’s uniformly-controlled-rotation construction.

Prepares the n-qubit state

ψ=i=02n1aii|\psi\rangle = \sum_{i=0}^{2^n - 1} a_i \,|i\rangle

from 0n|0\rangle^{\otimes n} for a normalised amplitude vector a. The construction follows Möttönen et al., “Transformation of quantum states using uniformly controlled rotations” (arXiv:quant-ph/0407010). Both the RY-only “amplitude distribution” stage and the RZ “phase restoration” stage are supported, so general complex amplitudes work end-to-end.

.. important::

**Pre-condition: the input register must be in the all-zero state**
$|0\rangle^{\otimes n}$.  The Möttönen construction
decomposes the unitary that takes $|0\rangle^{\otimes n}$
to the target $|\psi\rangle$; applying it to any other
initial state yields a *different* output (the same unitary
applied to a different input), not the target amplitude vector.
There is no runtime guard for this — Qamomile does not track
qubit states — so it is the caller's responsibility to ensure the
register has not yet been mutated when ``amplitude_encoding`` /
``amplitude_encoding_from_angles`` is invoked.  In practice, call
these helpers immediately after ``qmc.qubit_array(n, ...)``
inside a kernel.

This module hosts only the gate-emission side of the algorithm: the MottonenAmplitudeEncoding CompositeGate, the function wrappers amplitude_encoding / amplitude_encoding_from_angles, and the Gray-walk emitter _emit_mottonen_gates. The classical angle precomputation lives in :mod:qamomile.linalg.mottonen so that hybrid loops can call compute_mottonen_amplitude_encoding_*_angles outside any kernel and feed the result back through amplitude_encoding_from_angles with parameters=[...].

Pipeline

  1. Validate and normalise the input — see :func:qamomile.linalg.mottonen.validate_and_normalize_amplitudes (length must be a power of two, all-zero rejected).

  2. Determine whether the input is genuinely complex (has a non-zero imaginary part). Real inputs (including complex with zero imag) keep the original signed-RY path — negative real amplitudes flow through the sign of arctan2(a_1, a_0) naturally, with no RZ overhead. Complex inputs use the iterative disentangling construction.

  3. For real inputs, compute the per-level RY rotation angles by splitting each chunk into upper / lower halves and using arctan2 of the two sub-block norms (or signed arctan2 at the leaf). See :func:qamomile.linalg.mottonen.compute_all_ry_angles_per_level.

  4. For complex inputs, iteratively disentangle the target amplitude vector qubit-by-qubit from LSB to MSB. See :func:qamomile.linalg.mottonen.compute_disentangling_angles_per_level.

  5. At each level k >= 1 apply a uniformly controlled rotation over the previously prepared k qubits. We use the standard Gray-code RY / CNOT decomposition for the magnitude stage and the same structure with RZ for the phase stage. The emitted gate order is “all RY layers, then all RZ layers”. Pairwise [U_y^(k), U_z^(k')] does NOT commute in general (including k != k' cases, because earlier RY targets can be controls of later RZ multiplexers), but the FULL sweep product equals the per-level interleaved product (U_z^(0) U_y^(0)) ... (U_z^(n-1) U_y^(n-1)) as unitaries — this is a structural identity verified by :class:tests.circuit.algorithm.state_preparation.test_mottonen_amplitude_encoding.TestRyRzOrdering with arbitrary (non-disentangling) per-level angles. Within each level the order RY-before-RZ is preserved in both schemes.

Lazy angle precomputation

MottonenAmplitudeEncoding.__init__ runs the cheap normalisation pass eagerly (O(2^n)) so input errors — wrong shape, length not a power of two, all-zero amplitudes — surface at construction time. The expensive angle precomputation (O(n * 2^n)) is deferred: it runs lazily on the first _decompose() call and is cached afterwards. _resources() reads is_complex directly from the cached __init__ state and never triggers angle precomputation, so standalone resource estimation on a MottonenAmplitudeEncoding instance pays only the normalisation cost.

In practice the surrounding CompositeGate.__call__ framework eagerly invokes _decompose() when the gate is invoked inside a @qkernel (to populate the operation’s implementation_block), so kernel-side estimate_resources() does still pay the angle cost today. The lazy aspect is the right shape for a future framework refactor that defers _build_decomposition_block until emit time, and is verified standalone by tests.circuit.algorithm.state_preparation.test_mottonen_amplitude_encoding.TestLazyConstruction.

Overview

FunctionDescription
amplitude_encodingApply Möttönen amplitude encoding to qubits in place.
amplitude_encoding_from_anglesApply Möttönen amplitude encoding from pre-computed Ry / Rz angles.
compute_all_ry_angles_per_levelPre-compute every level’s Ry rotation angle vector (magnitude stage).
compute_disentangling_angles_per_levelIteratively disentangle to obtain both Ry and Rz angles per level.
cxCNOT (Controlled-X) gate.
get_sizeReturn the size of a Vector handle as a Python integer.
ryRotation around Y-axis: RY(angle) = exp(-i * angle/2 * Y).
rzRotation around Z-axis: RZ(angle) = exp(-i * angle/2 * Z).
validate_and_normalize_amplitudesValidate an amplitude vector and return its normalised form.
ClassDescription
CompositeGateBase class for user-facing composite gate definitions.
CompositeGateTypeRegistry of known composite gate types.
MottonenAmplitudeEncodingMöttönen amplitude encoding for normalised real or complex vectors.
ResourceMetadataResource estimation metadata for composite gates.

Functions

amplitude_encoding [source]

def amplitude_encoding(
    qubits: Vector[Qubit],
    amplitudes: Sequence[float] | Sequence[complex] | np.ndarray | Vector[Float],
) -> Vector[Qubit]

Apply Möttönen amplitude encoding to qubits in place.

Convenience wrapper around :class:MottonenAmplitudeEncoding that accepts a Vector handle and writes the gated qubits back into the same vector. Real and complex amplitudes are both supported; see the class docstring for the gate-count tradeoff between the two paths.

.. important::

**Pre-condition: ``qubits`` must currently be in the all-zero
state** $|0\rangle^{\otimes n}$.  Möttönen encodes the
unitary that takes $|0\rangle^{\otimes n}$ to the
normalised target; applied to any other state it produces a
different (in general meaningless) output.  In practice call
this immediately after ``qmc.qubit_array(n, ...)`` inside a
kernel.

amplitudes may be supplied as one of three forms:

Parameters:

NameTypeDescription
qubitsVector[Qubit]Vector of n qubit handles, expected to start in 0n|0\rangle^{\otimes n}.
amplitudesSequence[float] | Sequence[complex] | np.ndarray | Vector[Float]Amplitude vector of length 2**n. Concrete sequences and np.ndarray accept both real and complex inputs and are normalised automatically. Vector[Float] is accepted only when (a) its concrete values are available at trace time (i.e., it came from a bindings={...} entry, not from parameters=[...]) and (b) the values are real; complex amplitudes via a kernel parameter must instead go through :func:amplitude_encoding_from_angles.

Returns:

Vector[Qubit] — Vector[Qubit]: The same qubits vector, with each element updated to the post-encoding qubit handle.

Raises:

Example::

# Concrete Python amplitudes
@qmc.qkernel
def prepare() -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding(q, [1.0, 0.0, 0.0, 1.0])
    return qmc.measure(q)

# Bound Vector[Float] kernel parameter
@qmc.qkernel
def prepare(amps: qmc.Vector[qmc.Float]) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding(q, amps)
    return qmc.measure(q)

transpiler.transpile(prepare, bindings={"amps": [1.0, 0.0, 0.0, 1.0]})

amplitude_encoding_from_angles [source]

def amplitude_encoding_from_angles(
    qubits: Vector[Qubit],
    ry_angles: Sequence[float] | np.ndarray | Vector[Float],
    rz_angles: Sequence[float] | np.ndarray | Vector[Float] | None = None,
) -> Vector[Qubit]

Apply Möttönen amplitude encoding from pre-computed Ry / Rz angles.

.. important::

**Pre-condition: ``qubits`` must currently be in the all-zero
state** $|0\rangle^{\otimes n}$.  The Möttönen Gray-walk
emission produced by these angle vectors only encodes the
intended state when starting from $|0\rangle^{\otimes n}$;
applied to any other input it produces ``U |\phi\rangle`` for
the same ``U`` and a different ``|\phi\rangle``, which is in
general not the target amplitude vector.

Companion to :func:amplitude_encoding for the parametric use case: the user pre-computes the Gray-walk Ry (and optionally Rz) angles classically with :func:qamomile.linalg.compute_mottonen_amplitude_encoding_ry_angles and :func:qamomile.linalg.compute_mottonen_amplitude_encoding_rz_angles, then passes them in as either concrete sequences or as Vector[Float] handles obtained from kernel parameters. In the latter case the angles can be left as runtime parameters (transpiler.transpile(kernel, parameters=["ry_angles", ...])) so the same compiled circuit can be re-bound to different amplitude vectors without recompilation — useful inside hybrid optimisation loops.

Unlike :func:amplitude_encoding, this function does NOT wrap the emission in a :class:MottonenAmplitudeEncoding CompositeGate box on the IR side; the Ry / Rz / CNOT Gray-walk gates are emitted directly into the surrounding kernel. Resource estimation / visualization will therefore see the elementary gates rather than a single high-level op.

Parameters:

NameTypeDescription
qubitsVector[Qubit]Vector of n qubit handles, expected to start in 0n|0\rangle^{\otimes n}.
ry_anglesSequence[float] | np.ndarray | Vector[Float]Gray-walk Ry angles for the magnitude stage. Must have length 2**n - 1.
rz_anglesSequence[float] | np.ndarray | Vector[Float] | NoneGray-walk Rz angles for the phase stage. Pass None (default) to skip the Rz stage entirely (real-amplitude path); otherwise must have length 2**n - 1 as well.

Returns:

Vector[Qubit] — Vector[Qubit]: The same qubits vector, with each element updated to the post-encoding qubit handle.

Raises:

Example::

from qamomile.linalg import (
    compute_mottonen_amplitude_encoding_ry_angles,
    compute_mottonen_amplitude_encoding_rz_angles,
)

# Pre-compute classically (outside the kernel)
ry = compute_mottonen_amplitude_encoding_ry_angles(amps)
rz = compute_mottonen_amplitude_encoding_rz_angles(amps)

@qmc.qkernel
def prepare(
    ry_a: qmc.Vector[qmc.Float],
    rz_a: qmc.Vector[qmc.Float],
) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(2, name="q")
    q = amplitude_encoding_from_angles(q, ry_a, rz_a)
    return qmc.measure(q)

exe = transpiler.transpile(prepare, parameters=["ry_a", "rz_a"])
# Same compiled circuit, re-bound at "runtime":
exe.run(transpiler.executor(),
        bindings={"ry_a": ry.tolist(), "rz_a": rz.tolist()})

compute_all_ry_angles_per_level [source]

def compute_all_ry_angles_per_level(amplitudes: np.ndarray, num_qubits: int) -> list[np.ndarray]

Pre-compute every level’s Ry rotation angle vector (magnitude stage).

Implements the recursive magnitude-stage angle formula given in Möttönen et al., arXiv:quant-ph/0407010, Section III, Eq. (8) (with the leaf case matching the unnumbered angle 2 \arcsin(|a_{2j}| / \sqrt{|a_{2j-1}|^2 + |a_{2j}|^2}) just before Eq. (6), equivalent to 2 atan2(|a_1|, |a_0|) on the leaf pair). The pre-condition is the all-zero state 0n|0\rangle^{\otimes n}; the formulas below describe the angles needed to reach a real amplitudes from there.

For each level k (0 <= k < num_qubits) the amplitude vector is split into 2**k equal chunks. Each chunk yields one per-control-state angle α (Eq. (8)):

For k >= 1 the per-control-state angles are then transformed to the Gray-walk basis via :func:_to_gray_walk_basis (paper Eq. (3)).

Parameters:

NameTypeDescription
amplitudesnp.ndarrayUnit-norm real amplitude vector of length 2**num_qubits.
num_qubitsintNumber of qubits in the target register.

Returns:

list[np.ndarray] — list[np.ndarray]: A list of num_qubits arrays; the k-th entry has length 2**k and holds the Gray-walk Ry angles for that level.


compute_disentangling_angles_per_level [source]

def compute_disentangling_angles_per_level(
    amplitudes: np.ndarray,
    num_qubits: int,
) -> tuple[list[np.ndarray], list[np.ndarray]]

Iteratively disentangle to obtain both Ry and Rz angles per level.

Implements the Möttönen disentangling sweep for general (complex) amplitudes from Möttönen et al., arXiv:quant-ph/0407010, Section III, Eqs. (4)-(8): the phase-equalisation rotation Ξ_z (Eq. (4)) followed by the magnitude rotation, applied pair-by-pair from LSB to MSB. Pre-condition is the all-zero state 0n|0\rangle^{\otimes n}; the angles below are those needed to reach the input amplitudes from there (computed via the inverse sweep that disentangles the input).

At each step the amplitude vector is halved by pairing adjacent entries; for the pair (a_0, a_1) we read off

and replace the pair with the single complex amplitude that survives the implicit Rz^{-1} Ry^{-1} disentangling step (paper Eq. (6) zeros out one of the pair entries; the surviving amplitude is

β=a02+a12exp ⁣(iarga0+arga12),\beta = \sqrt{|a_0|^2 + |a_1|^2} \, \exp\!\left(i\,\frac{\arg a_0 + \arg a_1}{2}\right),

which carries the averaged phase needed by the next outer step of the sweep — the paper does not write β in this exact closed form but the relation falls out of combining Eqs. (5)-(7)). The full sweep is paper Eq. (7).

Zero-magnitude halves are handled gracefully by leaving the corresponding angle at 0 (the underlying state has no support there so the angle is immaterial). The returned per-level arrays are already bit-reversed and gray-walk-transformed (paper Eq. (3) applied per level via :func:_to_gray_walk_basis), ready for the Möttönen Gray-walk emission.

Parameters:

NameTypeDescription
amplitudesnp.ndarrayUnit-norm complex amplitude vector of length 2**num_qubits.
num_qubitsintNumber of qubits in the target register.

Returns:

tuple[list[np.ndarray], list[np.ndarray]] — tuple[list[np.ndarray], list[np.ndarray]]: (ry_angles_per_level, rz_angles_per_level) in Gray-walk ordering. Each list has num_qubits entries; the k-th entry holds 2**k angles for level k of the forward emission.


cx [source]

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

CNOT (Controlled-X) gate.


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:


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:


validate_and_normalize_amplitudes [source]

def validate_and_normalize_amplitudes(
    amplitudes: Sequence[float] | Sequence[complex] | np.ndarray,
) -> tuple[np.ndarray, int, bool]

Validate an amplitude vector and return its normalised form.

The Möttönen construction (arXiv:quant-ph/0407010, Section III) works on a unit-norm amplitude vector indexed by computational basis states; this helper enforces that pre-condition so the downstream angle computation can assume a well-formed input.

Inputs may be real or complex. A complex input whose imaginary part is identically zero (within np.allclose tolerance) is coerced to a real array; this preserves the cheaper signed-RY fast path for vectors that happen to arrive boxed as complex.

Parameters:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude vector. Must be a 1-D sequence whose length is a power of two and at least 2, with at least one non-zero entry.

Returns:

tuple[np.ndarray, int, bool] — tuple[np.ndarray, int, bool]: (normalized, num_qubits, is_complex) where normalized is a unit-norm np.ndarray, num_qubits is log2(len(amplitudes)), and is_complex is True iff the input has a non-zero imaginary component (and therefore needs the phase-restoration stage downstream). When is_complex is False, normalized.dtype is float; otherwise it is complex.

Raises:

Classes

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:


CompositeGateType [source]

class CompositeGateType(enum.Enum)

Registry of known composite gate types.

Attributes

MottonenAmplitudeEncoding [source]

class MottonenAmplitudeEncoding(CompositeGate)

Möttönen amplitude encoding for normalised real or complex vectors.

Prepares the state iaii\sum_i a_i |i\rangle from 0n|0\rangle^{\otimes n} using uniformly controlled Y (and, for genuinely complex inputs, Z) rotations decomposed into RY / RZ and CNOT gates with Gray-code ordering.

.. important::

**Pre-condition: the input qubits must be in the all-zero state**
$|0\rangle^{\otimes n}$.  The gate emits the unitary
that maps $|0\rangle^{\otimes n}$ to the target
$|\psi\rangle$.  Applied to any other input it
produces ``U |\phi\rangle`` for that ``|\phi\rangle`` —
which is *not* the target amplitude vector.  Qamomile does
not track qubit states at runtime, so this is the caller's
responsibility.

Notes:

Example::

# Real amplitudes (signed allowed)
gate = MottonenAmplitudeEncoding([1.0, 0.0, 0.0, 1.0])
q0, q1 = gate(q0, q1)

# Complex amplitudes
gate = MottonenAmplitudeEncoding([1+0j, 1j, -1+0j, -1j])
q0, q1 = gate(q0, q1)
Constructor
def __init__(self, amplitudes: Sequence[float] | Sequence[complex] | np.ndarray)

Initialise the gate with a concrete amplitude vector.

Runs the full normalisation + complex-detection pass eagerly (O(2^n)) so that input errors — wrong shape, length not a power of two, all-zero amplitudes — surface at construction time rather than at the first _resources() / _decompose() call. Angle precomputation (O(n * 2^n)) stays deferred: it runs lazily on the first _decompose() call and is cached afterwards.

This keeps the dominant cost of Möttönen out of kernel-build time when the gate is later only used for resource estimation. In practice the CompositeGate.__call__ framework eagerly invokes _decompose() to build the implementation block when the gate is invoked inside a @qkernel, so the lazy aspect currently bites only for code that constructs MottonenAmplitudeEncoding standalone — but the laziness still matters there, and is the right shape for a future framework refactor that defers _decompose() until emit time.

Parameters:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude vector of length 2**n. Real or complex; it is automatically normalised. Complex inputs with zero imaginary part are coerced to real (single-stage RY path).

Raises:

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

qamomile.circuit.algorithm.trotter

Suzuki-Trotter time evolution as a self-recursive @qkernel.

The public :func:trotterized_time_evolution wrapper validates the hamiltonian length and order and then delegates to the @qkernel :func:_trotter_evolve, which slices the evolution into step Trotter steps and applies a single-step operator from :func:_suzuki_trotter_step. That step kernel branches on order:

order must be bound to a compile-time constant at transpile time — without it the base-case if never folds and the unroll loop has nothing to terminate on. Only order == 1 or even orders 2, 4, 6, ... are accepted; other values raise ValueError at the call site. hamiltonian must contain at least two terms.

Example::

import qamomile.circuit as qmc
import qamomile.observable as qm_o
from qamomile.circuit.algorithm.trotter import (
    trotterized_time_evolution,
)

@qmc.qkernel
def my_circuit(
    Hs: qmc.Vector[qmc.Observable],
    gamma: qmc.Float,
    order: qmc.UInt,
    step: qmc.UInt,
) -> qmc.Vector[qmc.Qubit]:
    q = qmc.qubit_array(1, name="q")
    q = trotterized_time_evolution(q, Hs, order, gamma, step)
    return q

Hs = [qm_o.Z(0), qm_o.X(0)]  # list of qamomile.observable.Hamiltonian

Overview

FunctionDescription
trotterized_time_evolutionApply Suzuki-Trotter time evolution exp(-i gamma H) to q.

Functions

trotterized_time_evolution [source]

def trotterized_time_evolution(
    q: qmc.Vector[qmc.Qubit],
    hamiltonian: qmc.Vector[qmc.Observable] | Sequence[Hamiltonian],
    order: int | qmc.UInt,
    gamma: float | qmc.Float,
    step: int | qmc.UInt,
) -> qmc.Vector[qmc.Qubit]

Apply Suzuki-Trotter time evolution exp(-i gamma H) to q.

H = sum_k hamiltonian[k]. The evolution is split into step Trotter slices of size dt = gamma / step; each slice applies the order-th Suzuki-Trotter formula via :func:_trotter_evolve.

Parameters:

NameTypeDescription
qqmc.Vector[qmc.Qubit]Qubit register handle.
hamiltonianqmc.Vector[qmc.Observable] | Sequence[Hamiltonian]qmc.Vector[qmc.Observable] when called from a @qkernel (the handle type for a vector of Hamiltonians), or a Python list of qamomile.observable.Hamiltonian objects. At least two sub-Hamiltonian terms are required.
orderint | qmc.UIntApproximation order — 1 or a positive even integer (2, 4, 6, …). Must be a compile-time constant.
gammafloat | qmc.FloatTotal evolution time.
stepint | qmc.UIntNumber of Trotter steps.

Returns:

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

Raises: