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.optimization.fqaoa

This module implements the Fermionic QAOA (FQAOA) converter for the Qamomile framework [yoshioka2023fermionic]. FQAOA translates the Hamiltonians into the representation of fermion systems, and the equality constraint is naturally incorporated as a constant number of particles condition.

The parameterized state β,γ|\vec{\beta},\vec{\gamma}\rangle of pp-layer QAOA is defined as:

β,γ=U(β,γ)0n=eiβp1HMeiγp1HPeiβ0HMeiγ0HPUinit0n|\vec{\beta},\vec{\gamma}\rangle = U(\vec{\beta},\vec{\gamma})|0\rangle^{\otimes n} = e^{-i\beta_{p-1} H_M}e^{-i\gamma_{p-1} H_P} \cdots e^{-i\beta_0 H_M}e^{-i\gamma_0 H_P} U_{init}|0\rangle^{\otimes n}

where HPH_P is the cost Hamiltonian, HMH_M is the mixer Hamiltonian and γl\gamma_l and βl\beta_l are the variational parameters. The 2p2p variational parameters are optimized classically to minimize the expectation value β,γHPβ,γ\langle \vec{\beta},\vec{\gamma}|H_P|\vec{\beta},\vec{\gamma}\rangle. UinitU_{init} prepares the initial state using Givens rotation gates [jiang2018quantum].

This module provides functionality to convert optimization problems which written by jijmodeling into FQAOA circuits (U(β,γ)U(\vec{\beta}, \vec{\gamma})), construct cost Hamiltonians (HPH_P), and decode quantum computation results.

The FQAOAConverter class extends the MathematicalProblemConverter base class, specializing in FQAOA-specific operations such as ansatz circuit generation and result decoding.

Key Features:

Overview

FunctionDescription
fqaoa_stateGenerate complete FQAOA state.
is_close_zeroCheck if a given floating-point value is close to zero within a small tolerance.
ClassDescription
ExecutableProgramA fully compiled program ready for execution.
FQAOAConverterFQAOA (Fermionic Quantum Approximate Optimization Algorithm) converter class.
MathematicalProblemConverter
TranspilerBase class for backend-specific transpilers.

Functions

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.


is_close_zero [source]

def is_close_zero(value: float, abs_tol: float = 1e-15) -> bool

Check if a given floating-point value is close to zero within a small tolerance.

Parameters:

NameTypeDescription
valuefloatThe floating-point value to check.
abs_tolfloatAbsolute tolerance passed to :func:math.isclose. Defaults to 1e-15.

Returns:

bool — True if the value is close to zero, False otherwise.

Classes

ExecutableProgram [source]

class ExecutableProgram(Generic[T])

A fully compiled program ready for execution.

Contains compiled quantum, classical, and expectation-value segments. Use sample() for multi-shot execution or run() for single execution.

Example:

executable = transpiler.compile(kernel)

# Sample: multiple shots, returns counts
job = executable.sample(executor, shots=1000)
result = job.result()  # SampleResult with counts

# Run: single shot, returns typed result
job = executable.run(executor)
result = job.result()  # Returns kernel's return type
Constructor
def __init__(
    self,
    plan: ProgramPlan | None = None,
    compiled_quantum: list[CompiledQuantumSegment[T]] = list(),
    compiled_classical: list[CompiledClassicalSegment] = list(),
    compiled_expval: list[CompiledExpvalSegment] = list(),
    output_refs: list[str] = list(),
    num_output_bits: int = 0,
) -> None
Attributes
Methods
get_circuits
def get_circuits(self) -> list[T]

Get all quantum circuits in execution order.

get_first_circuit
def get_first_circuit(self) -> T | None

Get the first quantum circuit, or None if no quantum segments.

run
def run(
    self,
    executor: QuantumExecutor[T],
    bindings: dict[str, Any] | None = None,
) -> RunJob[Any] | ExpvalJob

Execute once and return single result.

Parameters:

NameTypeDescription
executorQuantumExecutor[T]Backend-specific quantum executor.
bindingsdict[str, Any] | NoneParameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2}

Returns:

RunJob[Any] | ExpvalJob — RunJob that resolves to the kernel’s return type, or RunJob[Any] | ExpvalJob — ExpvalJob if the program contains expectation value computation.

Raises:

Example:

job = executable.run(executor, bindings={"gamma": [0.5]})
result = job.result()
print(result)  # 0.25 (for QFixed) or (0, 1) (for bits)
sample
def sample(
    self,
    executor: QuantumExecutor[T],
    shots: int = 1024,
    bindings: dict[str, Any] | None = None,
) -> SampleJob[Any]

Execute with multiple shots and return counts.

Parameters:

NameTypeDescription
executorQuantumExecutor[T]Backend-specific quantum executor.
shotsintNumber of shots to run.
bindingsdict[str, Any] | NoneParameter bindings. Supports two formats: - Vector: {“gammas”: [0.1, 0.2], “betas”: [0.3, 0.4]} - Indexed: {“gammas[0]”: 0.1, “gammas[1]”: 0.2}

Returns:

SampleJob[Any] — SampleJob that resolves to SampleResult with results.

Raises:

Example:

job = executable.sample(executor, shots=1000, bindings={"gamma": [0.5]})
result = job.result()
print(result.results)  # [(0.25, 500), (0.75, 500)]

FQAOAConverter [source]

class FQAOAConverter(MathematicalProblemConverter)

FQAOA (Fermionic Quantum Approximate Optimization Algorithm) converter class.

This class provides methods to convert optimization problems into FQAOA circuits, construct cost Hamiltonians, and decode quantum computation results.

Examples:

from qamomile.optimization.fqaoa import FQAOAConverter

# Initialize with a compiled optimization problem instance
fqaoa_converter = FQAOAConverter(compiled_instance, num_fermions=4)

# Generate cost Hamiltonian and transpile
cost_hamiltonian = fqaoa_converter.get_cost_hamiltonian()
executable = fqaoa_converter.transpile(transpiler, p=2)
Constructor
def __init__(
    self,
    instance: ommx.v1.Instance,
    num_fermions: int,
    normalize_ising: Optional[Literal['abs_max', 'rms']] = None,
)

Initialize the FQAOAConverter.

This method initializes the converter with the compiled instance of the optimization problem.

Parameters:

NameTypeDescription
instanceommx.v1.Instanceommx.v1.Instance.
num_fermionsintNumber of fermions. This means the constraint M=l,dxl,dM = \sum_{l,d} x_{l,d}.
normalize_isingLiteral[abs_max, rms] | NoneThe normalization method for the Ising Hamiltonian. Available options: - “abs_max”: Normalize by absolute maximum value - “rms”: Normalize by root mean square Defaults to None.
Attributes
Methods
cyclic_mapping
def cyclic_mapping(self) -> dict[tuple[int, int], int]

Get variable maps between decision variable indices (l,d)(l,d) and qubit index ii.

Return:

dict[tuple[int, int], int] : A variable map for ring driver.

get_cost_hamiltonian
def get_cost_hamiltonian(self) -> qm_o.Hamiltonian

Construct the Ising cost Hamiltonian from the spin model.

Builds a Pauli-Z Hamiltonian from the spin model’s linear and quadratic terms.

Returns:

qm_o.Hamiltonian — qm_o.Hamiltonian: The cost Hamiltonian.

get_fermi_orbital
def get_fermi_orbital(self) -> np.ndarray

Compute the single-particle wave functions of the occupied spin orbitals.

Return:

numpy.ndarray: A 2D numpy array of shape (num_fermions, num_qubits)

transpile
def transpile(
    self,
    transpiler: Transpiler,
    *,
    p: int,
    hopping: float = 1.0,
) -> ExecutableProgram

Compile FQAOA ansatz into an executable program with measurements.


MathematicalProblemConverter [source]

class MathematicalProblemConverter(abc.ABC)
Constructor
def __init__(self, instance: ommx.v1.Instance | BinaryModel) -> None
Attributes
Methods
decode
def decode(self, samples: SampleResult[list[int]]) -> BinarySampleSet | ommx.v1.SampleSet

Decode quantum measurement results.

The return type tracks the input that built this converter:

Parameters:

NameTypeDescription
samplesSampleResult[list[int]]Raw quantum measurement results from ExecutableProgram.sample(...).result().

Returns:

BinarySampleSet | ommx.v1.SampleSet — BinarySampleSet | ommx.v1.SampleSet: see method description.

See Also:

:meth:decode_to_binary_sampleset: always returns a :class:BinarySampleSet. Use it when you need the QUBO-domain (penalty-included) energy — e.g. to drive a classical optimizer that must penalize infeasibility.

Example:

>>> # OMMX in → OMMX out
>>> converter = QAOAConverter(ommx_instance)
>>> exe = converter.transpile(QiskitTranspiler(), p=2)
>>> result = exe.sample(QiskitTranspiler().executor(),
...                     shots=1024,
...                     bindings={"gammas": gs, "betas": bs}).result()
>>> sample_set = converter.decode(result)
>>> sample_set.best_feasible.objective
decode_to_binary_sampleset
def decode_to_binary_sampleset(self, samples: SampleResult[list[int]]) -> BinarySampleSet

Decode samples into a :class:BinarySampleSet.

Always returns a :class:BinarySampleSet, regardless of whether this converter was constructed with an :class:ommx.v1.Instance or a :class:BinaryModel. Use this when you need:

For most usage — feasibility, original-objective evaluation, per-constraint diagnostics — prefer the polymorphic :meth:decode, which returns an :class:ommx.v1.SampleSet for OMMX-backed converters.

Parameters:

NameTypeDescription
samplesSampleResult[list[int]]Raw quantum measurement results from ExecutableProgram.sample(...).result().

Returns:

BinarySampleSet — keyed by the SPIN model’s original variable BinarySampleSet — indices (the QUBO variable IDs for OMMX-backed converters) BinarySampleSet — in the converter’s original_vartype — BINARY for BinarySampleSet — OMMX-backed converters, the :class:BinaryModel’s declared BinarySampleSet — vartype otherwise.

get_cost_hamiltonian
def get_cost_hamiltonian(self) -> qm_o.Hamiltonian

Construct the cost Hamiltonian.

Subclasses must implement this method to build the appropriate Hamiltonian for their specific algorithm (e.g., Pauli-Z for QAOA, QRAC-encoded for QRAO).

Returns:

qm_o.Hamiltonian — qm_o.Hamiltonian: The cost Hamiltonian.


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) plan = transpiler.plan(analyzed) executable = transpiler.emit(plan, bindings={“theta”: 0.5})

Option 3: Just get the circuit (no execution)

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

With configuration (strategy overrides)

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

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

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

Pass 2.25: Lower measurement-derived classical ops.

Identifies CompOp / CondOp / NotOp / BinOp instances whose operand dataflow traces back to a measurement and rewrites them to RuntimeClassicalExpr. Compile-time-foldable and emit-time-foldable (loop-bound, parameter-bound) classical ops are left unchanged.

Runs after analyze so the measurement-taint analysis has the full dependency graph available, and before validate_symbolic_shapes / plan / emit so downstream passes can rely on the cleaner IR (in particular: future segmentation work can dispatch on RuntimeClassicalExpr type instead of the BitType-only heuristic).

constant_fold
def constant_fold(self, block: Block, bindings: dict[str, Any] | None = None) -> 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: ProgramPlan,
    bindings: dict[str, Any] | None = None,
    parameters: list[str] | None = None,
) -> ExecutableProgram[T]

Pass 4: Generate backend-specific code.

Parameters:

NameTypeDescription
separatedProgramPlanThe 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 SegmentationPass from seeing classical-only compile-time IfOperations that would otherwise split quantum segments.

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

Pass 1.75: Fold constants and lower compile-time control flow.

plan
def plan(self, block: Block) -> ProgramPlan

Pass 3: Lower and split into a program plan.

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

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

Pass 0.75: Resolve symbolic Vector parameter shape dims.

Qamomile circuits are compile-time fixed-structure. Parameter Vector[Float] / Vector[UInt] inputs carry symbolic {name}_dim{i} shape Values so frontend code like arr.shape[0] returns a usable handle. This pass looks at bindings and, for every parameter array that has a concrete binding, substitutes those symbolic dims with constants so that downstream loop-bound resolution sees fixed lengths.

Parameters without a concrete binding are left as-is; their symbolic dims are harmless as long as no compile-time structure decision depends on them (the library QAOA pattern).

set_config
def set_config(self, config: TranspilerConfig) -> 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 hierarchical block 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). Names in bindings and parameters must be disjoint — a name is either compile-time bound or runtime symbolic, never both.
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. resolve_parameter_shapes: Constant-fold symbolic Vector param dims

  4. inline: Inline CallBlockOperations

  5. affine_validate: Validate affine type semantics

  6. partial_eval: Fold constants and lower compile-time control flow

  7. analyze: Validate and analyze dependencies

  8. validate_symbolic_shapes: Reject unresolved parameter shape dims

  9. plan: Build ProgramPlan (segment into C->Q->C steps)

  10. emit: Generate backend-specific code

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

Fixed-point loop of inline ↔ partial_eval for self-recursive kernels.

Each iteration unrolls one layer of self-referential CallBlockOperation and then folds the base-case IfOperation via partial_eval. Terminates when no CallBlockOperation remains (success), when the call count stops decreasing (symbolic driver — self-calls are left in the IR and handled by downstream passes), or when MAX_UNROLL_DEPTH is reached (non-terminating recursion — raises).

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

Pass 2.5: Reject unresolved parameter shape dims in loop bounds.

Runs after analyze so dependency info is complete. Raises QamomileCompileError with an actionable message when a gamma_dim0-style symbolic Value reaches a ForOperation bound without being folded to a constant by ParameterShapeResolutionPass.