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

Resource estimation module for Qamomile circuits.

This module provides comprehensive resource estimation for quantum circuits, including:

  1. Qubit counting: Algebraic qubit count with SymPy

  2. Gate counting: Breakdown by gate type (single/two-qubit, T gates, Clifford)

  3. Algorithmic estimates: Theoretical bounds for QAOA, QPE, Hamiltonian simulation

All estimates are expressed as SymPy symbolic expressions, allowing dependency on problem size parameters.

Usage:

Basic circuit analysis (method API — recommended): >>> estimate = my_circuit.estimate_resources() >>> print(estimate.qubits) # e.g., “n + 3” >>> print(estimate.gates.total) # e.g., “2*n”

Function API (also supported): >>> from qamomile.circuit.estimator import estimate_resources >>> estimate = estimate_resources(my_circuit.block) >>> print(estimate.qubits) # e.g., “n + 3” >>> print(estimate.gates.total) # e.g., “2*n”

Algorithmic estimates: >>> from qamomile.circuit.estimator.algorithmic import estimate_qaoa >>> import sympy as sp >>> n, p = sp.symbols(‘n p’, positive=True, integer=True) >>> est = estimate_qaoa(n, p, num_edges=n*(n-1)/2) >>> print(est.gates.total)

References:

Based on “Quantum algorithms: A survey of applications and end-to-end complexities” (arXiv:2310.03011v2)

Overview

FunctionDescription
count_gatesCount gates in a quantum circuit.
estimate_resourcesEstimate all resources for a quantum circuit.
ClassDescription
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

count_gates [source]

def count_gates(block: BlockValue | list[Operation]) -> GateCount

Count gates in a quantum circuit.

This function analyzes operations and returns algebraic gate counts using SymPy expressions. Counts may contain symbols for parametric problem sizes (e.g., loop bounds, array dimensions).

Supports:

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]BlockValue or list of Operations to analyze

Returns:

GateCount — GateCount with total, single_qubit, two_qubit, t_gates, clifford_gates

Example:

>>> from qamomile.circuit.estimator import count_gates
>>> count = count_gates(my_circuit.block)
>>> print(count.total)  # e.g., "2*n + 5"
>>> print(count.t_gates)  # e.g., "n"

estimate_resources [source]

def estimate_resources(
    block: BlockValue | list[Operation],
    *,
    bindings: dict[str, Any] | None = None,
) -> ResourceEstimate

Estimate all resources for a quantum circuit.

This is the main entry point for comprehensive resource estimation. Combines qubit counting and gate counting.

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]BlockValue or list of Operations to analyze
bindingsdict[str, Any] | NoneOptional concrete parameter bindings (scalars and dicts).

Returns:

ResourceEstimate — ResourceEstimate with qubits, gates, and parameters

Example:

>>> import qamomile.circuit as qm
>>> from qamomile.circuit.estimator import estimate_resources
>>>
>>> @qm.qkernel
>>> def bell_state() -> qm.Vector[qm.Qubit]:
...     q = qm.qubit_array(2)
...     q[0] = qm.h(q[0])
...     q[0], q[1] = qm.cx(q[0], q[1])
...     return q
>>>
>>> est = estimate_resources(bell_state.block)
>>> print(est.qubits)  # 2
>>> print(est.gates.total)  # 2
>>> print(est.gates.two_qubit)  # 1

Example with parametric size:

qm.qkernel def ghz_state(n: qm.UInt) -> qm.Vector[qm.Qubit]: ... q = qm.qubit_array(n) ... q[0] = qm.h(q[0]) ... for i in qm.range(n - 1): ... q[i], q[i+1] = qm.cx(q[i], q[i+1]) ... return q

est = estimate_resources(ghz_state.block) print(est.qubits) # n print(est.gates.total) # n print(est.gates.two_qubit) # n - 1

Substitute concrete value

concrete = est.substitute(n=100) print(concrete.qubits) # 100 print(concrete.gates.total) # 100

Classes

ResourceEstimate [source]

class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))

qamomile.circuit.estimator.algorithmic

Algorithmic resource estimators based on theoretical complexity formulas.

These estimators provide resource bounds based on published complexity results from quantum algorithms literature, particularly from:

arXiv:2310.03011v2 - “Quantum algorithms: A survey of applications and end-to-end complexities”

Unlike the circuit-based estimators (gate_counter, qubits_counter), these provide theoretical estimates based on algorithm parameters without needing the actual circuit implementation.

Overview

FunctionDescription
estimate_qaoaEstimate resources for QAOA circuit.
estimate_qdriftEstimate resources for qDRIFT Hamiltonian simulation.
estimate_qpeEstimate resources for Quantum Phase Estimation.
estimate_qsvtEstimate resources for QSVT-based Hamiltonian simulation.
estimate_trotterEstimate resources for Trotter/Suzuki formula Hamiltonian simulation.

Functions

estimate_qaoa [source]
def estimate_qaoa(
    n: sp.Expr | int,
    p: sp.Expr | int,
    num_edges: sp.Expr | int,
    mixer_type: str = 'x',
) -> ResourceEstimate

Estimate resources for QAOA circuit.

QAOA alternates between cost and mixer unitaries for p layers. For Ising/QUBO problems:

Based on standard QAOA formulation (Farhi et al. 2014).

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits (problem size)
psp.Expr | intNumber of QAOA layers
num_edgessp.Expr | intNumber of edges in problem graph (for cost Hamiltonian)
mixer_typestrType of mixer (“x” for standard X-mixer, future: “xy”, “grover”)

Returns:

ResourceEstimate — ResourceEstimate with: qubits: n gates.total: 2pn + pnum_edges (RX + RZZ gates) gates.single_qubit: 2pn (RX gates) gates.two_qubit: pnum_edges (RZZ gates)

Example:

>>> import sympy as sp
>>> n, p = sp.symbols('n p', positive=True, integer=True)
>>> # Complete graph K_n has n*(n-1)/2 edges
>>> edges = n * (n - 1) / 2
>>> est = estimate_qaoa(n, p, edges)
>>> print(est.qubits)  # n
>>> print(est.gates.total)  # n*p*(n + 3)/2
>>>
>>> # MaxCut on K_10 with p=3
>>> concrete = est.substitute(n=10, p=3)
>>> print(concrete.gates.total)  # 195

References:


estimate_qdrift [source]
def estimate_qdrift(
    L: sp.Expr | int,
    hamiltonian_1norm: sp.Expr | float,
    time: sp.Expr | float,
    error: sp.Expr | float,
) -> ResourceEstimate

Estimate resources for qDRIFT Hamiltonian simulation.

qDRIFT is a randomized algorithm that samples Hamiltonian terms proportionally to their coefficients. Simpler than Trotter but requires more samples.

Parameters:

NameTypeDescription
Lsp.Expr | intNumber of terms in Hamiltonian
hamiltonian_1normsp.Expr | float||H||_1 = Σ|coefficients|
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε

Returns:

ResourceEstimate — ResourceEstimate for qDRIFT

Complexity (Section 11.2, arXiv:2310.03011v2): Number of samples: N = O(||H||_1^2 * t^2 / ε)

Note quadratic dependence on time (bad) but linear in error (good). Best for small t or when simplicity is valued over gate count.

Example:

>>> import sympy as sp
>>> L, h1, t, eps = sp.symbols('L h1 t eps', positive=True)
>>>
>>> est = estimate_qdrift(L, h1, t, eps)
>>> print(est.gates.total)  # O(h1^2 * t^2 / ε)
>>>
>>> # Compare to Trotter (order 2): O((h1*t)^1.5 / √ε)
>>> # qDRIFT worse for large t, better for small ε

References:


estimate_qpe [source]
def estimate_qpe(
    n_system: sp.Expr | int,
    precision: sp.Expr | int,
    hamiltonian_norm: sp.Expr | float | None = None,
    method: str = 'qubitization',
) -> ResourceEstimate

Estimate resources for Quantum Phase Estimation.

QPE estimates the eigenvalue of a unitary operator U = e^(iHt). Two main approaches:

  1. Trotter-based: Approximate e^(iHt) using Trotter formulas

  2. Qubitization: Use block-encoding with quantum walk operator

Parameters:

NameTypeDescription
n_systemsp.Expr | intNumber of system qubits (qubits in the state being analyzed)
precisionsp.Expr | intNumber of bits of precision in phase estimate (ε = 2^(-precision))
hamiltonian_normsp.Expr | float | NoneNormalization ||H|| for block-encoding (required for qubitization)
methodstr“qubitization” (recommended) or “trotter”

Returns:

ResourceEstimate — ResourceEstimate with qubit and gate counts

For qubitization method (Section 13, arXiv:2310.03011): qubits: n_system + precision + O(log n_system) ancillas calls to block-encoding: O(||H|| * 2^precision) gates per call: depends on Hamiltonian structure

For Trotter method:

qubits: n_system + precision depth: O(2^precision * Trotter_depth)

Example:

>>> import sympy as sp
>>> n = sp.Symbol('n', positive=True, integer=True)
>>> m = sp.Symbol('m', positive=True, integer=True)  # precision bits
>>> alpha = sp.Symbol('alpha', positive=True)  # ||H||
>>>
>>> est = estimate_qpe(n, m, hamiltonian_norm=alpha)
>>> print(est.qubits)  # n + m + O(log n)
>>> print(est.gates.total)  # O(alpha * 2^m)
>>>
>>> # Concrete example: 100 qubits, 10 bits precision
>>> concrete = est.substitute(n=100, m=10, alpha=50)
>>> print(concrete.qubits)  # ~117 (100 + 10 + log2(100))

References:


estimate_qsvt [source]
def estimate_qsvt(
    n: sp.Expr | int,
    hamiltonian_norm: sp.Expr | float,
    time: sp.Expr | float,
    error: sp.Expr | float,
) -> ResourceEstimate

Estimate resources for QSVT-based Hamiltonian simulation.

Quantum Singular Value Transformation (QSVT) provides near-optimal Hamiltonian simulation with complexity linear in time and logarithmic in error.

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits
hamiltonian_normsp.Expr | floatα where ||H|| ≤ α (block-encoding normalization)
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε

Returns:

ResourceEstimate — ResourceEstimate for QSVT simulation

Complexity (Section 11.4, arXiv:2310.03011v2): Calls to block-encoding: O(α*t + log(1/ε) / log(log(1/ε)))

This is nearly optimal: Ω(α*t + log(1/ε)) lower bound known.

Example:

>>> import sympy as sp
>>> n, alpha, t, eps = sp.symbols('n alpha t eps', positive=True)
>>>
>>> est = estimate_qsvt(n, alpha, t, eps)
>>> print(est.gates.total)  # O(α*t + log(1/ε)/log(log(1/ε)))
>>>
>>> # Much better than Trotter for small error!
>>> trotter = estimate_trotter(n, L=alpha, time=t, error=eps)
>>> # QSVT: O(αt + log 1/ε), Trotter: O(α t^1.5 / √ε)

References:


estimate_trotter [source]
def estimate_trotter(
    n: sp.Expr | int,
    L: sp.Expr | int,
    time: sp.Expr | float,
    error: sp.Expr | float,
    order: int = 2,
    hamiltonian_1norm: sp.Expr | float | None = None,
) -> ResourceEstimate

Estimate resources for Trotter/Suzuki formula Hamiltonian simulation.

Product formula methods approximate e^(iHt) by decomposing H into a sum of L terms and using the formula: e^(iHt) ≈ (e^(iH_1 Δt) ... e^(iH_L Δt))^r

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits
Lsp.Expr | intNumber of terms in Hamiltonian decomposition
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε
orderintTrotter order (2, 4, 6, ...). Higher order = fewer steps but more complex
hamiltonian_1normsp.Expr | float | None||H||_1 = Σ|coefficients| (if None, assumes ||H||_1 ~ L)

Returns:

ResourceEstimate — ResourceEstimate for Trotter simulation

Complexity (pth-order formula, Section 11.1): Number of steps: r = O((||H||_1 * t)^(1+1/p) / ε^(1/p)) Total gates: O(r * L * n) where n is gates per Hamiltonian term

Example:

>>> import sympy as sp
>>> n, L, t, eps = sp.symbols('n L t eps', positive=True)
>>>
>>> # Second-order Trotter
>>> est2 = estimate_trotter(n, L, t, eps, order=2)
>>> print(est2.gates.total)  # O(L * (||H||_1 * t)^1.5 / eps^0.5)
>>>
>>> # Fourth-order Trotter (fewer steps, better scaling)
>>> est4 = estimate_trotter(n, L, t, eps, order=4)
>>> print(est4.gates.total)  # O(L * (||H||_1 * t)^1.25 / eps^0.25)
>>>
>>> # Concrete: 100 qubits, 1000 terms, time=10, error=0.001
>>> concrete = est2.substitute(n=100, L=1000, t=10, eps=0.001)

References:


qamomile.circuit.estimator.algorithmic.hamiltonian_simulation

Theoretical resource estimates for Hamiltonian simulation.

Provides estimates for multiple simulation methods:

Based on Section 11 of arXiv:2310.03011v2.

Overview

FunctionDescription
estimate_qdriftEstimate resources for qDRIFT Hamiltonian simulation.
estimate_qsvtEstimate resources for QSVT-based Hamiltonian simulation.
estimate_trotterEstimate resources for Trotter/Suzuki formula Hamiltonian simulation.
ClassDescription
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

estimate_qdrift [source]
def estimate_qdrift(
    L: sp.Expr | int,
    hamiltonian_1norm: sp.Expr | float,
    time: sp.Expr | float,
    error: sp.Expr | float,
) -> ResourceEstimate

Estimate resources for qDRIFT Hamiltonian simulation.

qDRIFT is a randomized algorithm that samples Hamiltonian terms proportionally to their coefficients. Simpler than Trotter but requires more samples.

Parameters:

NameTypeDescription
Lsp.Expr | intNumber of terms in Hamiltonian
hamiltonian_1normsp.Expr | float||H||_1 = Σ|coefficients|
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε

Returns:

ResourceEstimate — ResourceEstimate for qDRIFT

Complexity (Section 11.2, arXiv:2310.03011v2): Number of samples: N = O(||H||_1^2 * t^2 / ε)

Note quadratic dependence on time (bad) but linear in error (good). Best for small t or when simplicity is valued over gate count.

Example:

>>> import sympy as sp
>>> L, h1, t, eps = sp.symbols('L h1 t eps', positive=True)
>>>
>>> est = estimate_qdrift(L, h1, t, eps)
>>> print(est.gates.total)  # O(h1^2 * t^2 / ε)
>>>
>>> # Compare to Trotter (order 2): O((h1*t)^1.5 / √ε)
>>> # qDRIFT worse for large t, better for small ε

References:


estimate_qsvt [source]
def estimate_qsvt(
    n: sp.Expr | int,
    hamiltonian_norm: sp.Expr | float,
    time: sp.Expr | float,
    error: sp.Expr | float,
) -> ResourceEstimate

Estimate resources for QSVT-based Hamiltonian simulation.

Quantum Singular Value Transformation (QSVT) provides near-optimal Hamiltonian simulation with complexity linear in time and logarithmic in error.

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits
hamiltonian_normsp.Expr | floatα where ||H|| ≤ α (block-encoding normalization)
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε

Returns:

ResourceEstimate — ResourceEstimate for QSVT simulation

Complexity (Section 11.4, arXiv:2310.03011v2): Calls to block-encoding: O(α*t + log(1/ε) / log(log(1/ε)))

This is nearly optimal: Ω(α*t + log(1/ε)) lower bound known.

Example:

>>> import sympy as sp
>>> n, alpha, t, eps = sp.symbols('n alpha t eps', positive=True)
>>>
>>> est = estimate_qsvt(n, alpha, t, eps)
>>> print(est.gates.total)  # O(α*t + log(1/ε)/log(log(1/ε)))
>>>
>>> # Much better than Trotter for small error!
>>> trotter = estimate_trotter(n, L=alpha, time=t, error=eps)
>>> # QSVT: O(αt + log 1/ε), Trotter: O(α t^1.5 / √ε)

References:


estimate_trotter [source]
def estimate_trotter(
    n: sp.Expr | int,
    L: sp.Expr | int,
    time: sp.Expr | float,
    error: sp.Expr | float,
    order: int = 2,
    hamiltonian_1norm: sp.Expr | float | None = None,
) -> ResourceEstimate

Estimate resources for Trotter/Suzuki formula Hamiltonian simulation.

Product formula methods approximate e^(iHt) by decomposing H into a sum of L terms and using the formula: e^(iHt) ≈ (e^(iH_1 Δt) ... e^(iH_L Δt))^r

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits
Lsp.Expr | intNumber of terms in Hamiltonian decomposition
timesp.Expr | floatEvolution time t
errorsp.Expr | floatTarget error ε
orderintTrotter order (2, 4, 6, ...). Higher order = fewer steps but more complex
hamiltonian_1normsp.Expr | float | None||H||_1 = Σ|coefficients| (if None, assumes ||H||_1 ~ L)

Returns:

ResourceEstimate — ResourceEstimate for Trotter simulation

Complexity (pth-order formula, Section 11.1): Number of steps: r = O((||H||_1 * t)^(1+1/p) / ε^(1/p)) Total gates: O(r * L * n) where n is gates per Hamiltonian term

Example:

>>> import sympy as sp
>>> n, L, t, eps = sp.symbols('n L t eps', positive=True)
>>>
>>> # Second-order Trotter
>>> est2 = estimate_trotter(n, L, t, eps, order=2)
>>> print(est2.gates.total)  # O(L * (||H||_1 * t)^1.5 / eps^0.5)
>>>
>>> # Fourth-order Trotter (fewer steps, better scaling)
>>> est4 = estimate_trotter(n, L, t, eps, order=4)
>>> print(est4.gates.total)  # O(L * (||H||_1 * t)^1.25 / eps^0.25)
>>>
>>> # Concrete: 100 qubits, 1000 terms, time=10, error=0.001
>>> concrete = est2.substitute(n=100, L=1000, t=10, eps=0.001)

References:

Classes

ResourceEstimate [source]
class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))

qamomile.circuit.estimator.algorithmic.qaoa

Theoretical resource estimates for QAOA (Quantum Approximate Optimization Algorithm).

Based on Section 4 and Section 20 of arXiv:2310.03011v2.

Overview

FunctionDescription
estimate_qaoaEstimate resources for QAOA circuit.
estimate_qaoa_isingEstimate resources for QAOA on Ising model.
ClassDescription
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

estimate_qaoa [source]
def estimate_qaoa(
    n: sp.Expr | int,
    p: sp.Expr | int,
    num_edges: sp.Expr | int,
    mixer_type: str = 'x',
) -> ResourceEstimate

Estimate resources for QAOA circuit.

QAOA alternates between cost and mixer unitaries for p layers. For Ising/QUBO problems:

Based on standard QAOA formulation (Farhi et al. 2014).

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits (problem size)
psp.Expr | intNumber of QAOA layers
num_edgessp.Expr | intNumber of edges in problem graph (for cost Hamiltonian)
mixer_typestrType of mixer (“x” for standard X-mixer, future: “xy”, “grover”)

Returns:

ResourceEstimate — ResourceEstimate with: qubits: n gates.total: 2pn + pnum_edges (RX + RZZ gates) gates.single_qubit: 2pn (RX gates) gates.two_qubit: pnum_edges (RZZ gates)

Example:

>>> import sympy as sp
>>> n, p = sp.symbols('n p', positive=True, integer=True)
>>> # Complete graph K_n has n*(n-1)/2 edges
>>> edges = n * (n - 1) / 2
>>> est = estimate_qaoa(n, p, edges)
>>> print(est.qubits)  # n
>>> print(est.gates.total)  # n*p*(n + 3)/2
>>>
>>> # MaxCut on K_10 with p=3
>>> concrete = est.substitute(n=10, p=3)
>>> print(concrete.gates.total)  # 195

References:


estimate_qaoa_ising [source]
def estimate_qaoa_ising(
    n: sp.Expr | int,
    p: sp.Expr | int,
    quadratic_terms: sp.Expr | int,
    linear_terms: sp.Expr | int | None = None,
) -> ResourceEstimate

Estimate resources for QAOA on Ising model.

Ising Hamiltonian: H = Σ J_ij Z_i Z_j + Σ h_i Z_i

This is a convenience wrapper around estimate_qaoa() that accepts the number of quadratic and linear terms directly.

Parameters:

NameTypeDescription
nsp.Expr | intNumber of qubits
psp.Expr | intNumber of QAOA layers
quadratic_termssp.Expr | intNumber of J_ij terms (edges in interaction graph)
linear_termssp.Expr | int | NoneNumber of h_i terms (defaults to n if None)

Returns:

ResourceEstimate — ResourceEstimate for QAOA

Example:

>>> # 3-regular graph with n vertices: 3n/2 edges
>>> import sympy as sp
>>> n, p = sp.symbols('n p', positive=True, integer=True)
>>> est = estimate_qaoa_ising(n, p, quadratic_terms=3*n/2)
>>> print(est.gates.total)  # 2*n*p + 3*n*p/2

Classes

ResourceEstimate [source]
class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))

qamomile.circuit.estimator.algorithmic.qpe

Theoretical resource estimates for QPE (Quantum Phase Estimation).

Based on Section 13 of arXiv:2310.03011v2.

Overview

FunctionDescription
estimate_eigenvalue_filteringEstimate resources for eigenstate filtering (QSVT-based).
estimate_qpeEstimate resources for Quantum Phase Estimation.
ClassDescription
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

estimate_eigenvalue_filtering [source]
def estimate_eigenvalue_filtering(
    n_system: sp.Expr | int,
    target_overlap: sp.Expr | float,
    gap: sp.Expr | float | None = None,
) -> ResourceEstimate

Estimate resources for eigenstate filtering (QSVT-based).

Uses quantum singular value transformation to filter eigenstates based on their eigenvalues.

Based on Section 2.1 (Fermi-Hubbard) and general eigenstate preparation methods in arXiv:2310.03011v2.

Parameters:

NameTypeDescription
n_systemsp.Expr | intNumber of system qubits
target_overlapsp.Expr | floatDesired overlap γ with target eigenstate
gapsp.Expr | float | NoneSpectral gap Δ (if known, improves estimates)

Returns:

ResourceEstimate — ResourceEstimate

O(1/γ) calls to block-encoding if no gap known:

O(1/√γΔ) if gap Δ is known

Example:

>>> import sympy as sp
>>> n = sp.Symbol('n', positive=True, integer=True)
>>> gamma = sp.Symbol('gamma', positive=True)  # overlap
>>>
>>> est = estimate_eigenvalue_filtering(n, gamma)
>>> print(est.gates.total)  # O(n/gamma)

References:


estimate_qpe [source]
def estimate_qpe(
    n_system: sp.Expr | int,
    precision: sp.Expr | int,
    hamiltonian_norm: sp.Expr | float | None = None,
    method: str = 'qubitization',
) -> ResourceEstimate

Estimate resources for Quantum Phase Estimation.

QPE estimates the eigenvalue of a unitary operator U = e^(iHt). Two main approaches:

  1. Trotter-based: Approximate e^(iHt) using Trotter formulas

  2. Qubitization: Use block-encoding with quantum walk operator

Parameters:

NameTypeDescription
n_systemsp.Expr | intNumber of system qubits (qubits in the state being analyzed)
precisionsp.Expr | intNumber of bits of precision in phase estimate (ε = 2^(-precision))
hamiltonian_normsp.Expr | float | NoneNormalization ||H|| for block-encoding (required for qubitization)
methodstr“qubitization” (recommended) or “trotter”

Returns:

ResourceEstimate — ResourceEstimate with qubit and gate counts

For qubitization method (Section 13, arXiv:2310.03011): qubits: n_system + precision + O(log n_system) ancillas calls to block-encoding: O(||H|| * 2^precision) gates per call: depends on Hamiltonian structure

For Trotter method:

qubits: n_system + precision depth: O(2^precision * Trotter_depth)

Example:

>>> import sympy as sp
>>> n = sp.Symbol('n', positive=True, integer=True)
>>> m = sp.Symbol('m', positive=True, integer=True)  # precision bits
>>> alpha = sp.Symbol('alpha', positive=True)  # ||H||
>>>
>>> est = estimate_qpe(n, m, hamiltonian_norm=alpha)
>>> print(est.qubits)  # n + m + O(log n)
>>> print(est.gates.total)  # O(alpha * 2^m)
>>>
>>> # Concrete example: 100 qubits, 10 bits precision
>>> concrete = est.substitute(n=100, m=10, alpha=50)
>>> print(concrete.qubits)  # ~117 (100 + 10 + log2(100))

References:

Classes

ResourceEstimate [source]
class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))

qamomile.circuit.estimator.gate_counter

Gate counting for quantum circuits.

This module provides algebraic gate counting using SymPy expressions, allowing resource estimates to depend on problem size parameters.

Overview

FunctionDescription
build_for_items_scopeBuild child resolver for a ForItemsOperation body.
build_for_loop_scopeBuild child resolver and resolved bounds for a ForOperation.
build_if_scopesBuild child resolvers for both branches of an IfOperation.
build_while_scopeBuild child resolver and trip-count symbol for a WhileOperation.
classify_controlled_uClassify a ControlledUOperation (opaque gate, total=1).
classify_gateClassify a single GateOperation into a GateCount.
count_gatesCount gates in a quantum circuit.
extract_gate_count_from_metadataExtract GateCount from ResourceMetadata.
qft_iqft_gate_countGate count for QFT or IQFT on n qubits.
resolve_composite_gateResolve a CompositeGateOperation to its resource source.
resolve_controlled_uResolve a ControlledUOperation to (num_controls, num_targets).
resolve_for_items_cardinalityReturn the symbolic cardinality |dict_name| for a ForItems loop.
symbolic_iterationsCompute the number of iterations of range(start, stop, step).
ClassDescription
BlockValueRepresents a subroutine as a function block.
CallBlockOperation
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
ControlledUOperationControlled-U operation that applies a unitary block conditionally.
ExprResolverSingle source of truth for converting IR Values to SymPy expressions.
ForItemsOperationRepresents iteration over dict/iterable items.
ForOperationRepresents a for loop operation.
GateCountGate count breakdown for a quantum circuit.
GateOperation
IfOperationRepresents an if-else conditional operation.
Operation
WhileOperationRepresents a while loop operation.

Functions

build_for_items_scope [source]
def build_for_items_scope(op: ForItemsOperation, resolver: ExprResolver) -> ExprResolver

Build child resolver for a ForItemsOperation body.

Parameters:

NameTypeDescription
opForItemsOperationThe for-items loop operation.
resolverExprResolverResolver for the enclosing scope.

Returns:

ExprResolver — Child resolver scoped to the loop body.


build_for_loop_scope [source]
def build_for_loop_scope(
    op: ForOperation,
    resolver: ExprResolver,
) -> tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol]

Build child resolver and resolved bounds for a ForOperation.

Parameters:

NameTypeDescription
opForOperationThe for-loop operation.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol] — tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol]: (child_resolver, start, stop, step, loop_symbol). The child resolver has block = local block over op.operations, loop variable mapped to loop_symbol, and parent blocks propagated.


build_if_scopes [source]
def build_if_scopes(op: Any, resolver: ExprResolver) -> tuple[ExprResolver, ExprResolver]

Build child resolvers for both branches of an IfOperation.

Parameters:

NameTypeDescription
opAnyAn IfOperation with true_operations and false_operations attributes.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, ExprResolver] — tuple[ExprResolver, ExprResolver]: (true_resolver, false_resolver).


build_while_scope [source]
def build_while_scope(op: Any, resolver: ExprResolver) -> tuple[ExprResolver, sp.Symbol]

Build child resolver and trip-count symbol for a WhileOperation.

Parameters:

NameTypeDescription
opAnyA WhileOperation with an operations attribute.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, sp.Symbol] — tuple[ExprResolver, sp.Symbol]: (child_resolver, trip_count_symbol) where trip_count_symbol is |while|.


classify_controlled_u [source]
def classify_controlled_u(nc: int | sp.Expr, num_targets: int) -> GateCount

Classify a ControlledUOperation (opaque gate, total=1).

power is NOT multiplied — each ControlledUOperation call counts as exactly one gate regardless of power. Exponential oracle counts arise from loop structure (e.g. for _rep in range(2**k)).

Parameters:

NameTypeDescription
ncint | sp.ExprNumber of control qubits (concrete or symbolic).
num_targetsintNumber of target qubits.

Returns:

GateCount — Gate count with total=1 and two_qubit / multi_qubit flags set based on the total qubit count (nc + num_targets).


classify_gate [source]
def classify_gate(op: GateOperation, num_controls: int | sp.Expr = 0) -> GateCount

Classify a single GateOperation into a GateCount.

Handles both concrete and symbolic num_controls. The result always has total=1.


count_gates [source]
def count_gates(block: BlockValue | list[Operation]) -> GateCount

Count gates in a quantum circuit.

This function analyzes operations and returns algebraic gate counts using SymPy expressions. Counts may contain symbols for parametric problem sizes (e.g., loop bounds, array dimensions).

Supports:

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]BlockValue or list of Operations to analyze

Returns:

GateCount — GateCount with total, single_qubit, two_qubit, t_gates, clifford_gates

Example:

>>> from qamomile.circuit.estimator import count_gates
>>> count = count_gates(my_circuit.block)
>>> print(count.total)  # e.g., "2*n + 5"
>>> print(count.t_gates)  # e.g., "n"

extract_gate_count_from_metadata [source]
def extract_gate_count_from_metadata(meta: ResourceMetadata) -> GateCount

Extract GateCount from ResourceMetadata.

Emits UserWarning when total_gates is set but sub-categories have None gaps and the known sub-total is less than total_gates. This warning behaviour is required by test_metadata_warnings.py.

Parameters:

NameTypeDescription
metaResourceMetadataMetadata to extract gate counts from. Fields left as None are treated as 0.

Returns:

GateCount — Extracted gate counts as sp.Integer values.


qft_iqft_gate_count [source]
def qft_iqft_gate_count(n: sp.Expr) -> GateCount

Gate count for QFT or IQFT on n qubits.

QFT = n H + n(n-1)/2 CP + n//2 SWAP

Parameters:

NameTypeDescription
nsp.ExprNumber of qubits (may be symbolic).

Returns:

GateCount — Symbolic gate counts for the standard QFT decomposition.


resolve_composite_gate [source]
def resolve_composite_gate(op: CompositeGateOperation, resolver: ExprResolver) -> CompositeGateResolution

Resolve a CompositeGateOperation to its resource source.

Priority (deterministic, not fallback):

  1. resource_metadata — always preferred when present

  2. implementation (has_implementation + BlockValue)

  3. Known formula (QFT / IQFT)

  4. Error — no resource info available

Parameters:

NameTypeDescription
opCompositeGateOperationThe operation to resolve.
resolverExprResolverResolver for the current scope.

Returns:

CompositeGateResolution — Exactly one of its four branches is populated.


resolve_controlled_u [source]
def resolve_controlled_u(op: ControlledUOperation, resolver: ExprResolver) -> tuple[int | sp.Expr, int]

Resolve a ControlledUOperation to (num_controls, num_targets).

num_controls may be int or sp.Expr (symbolic). num_targets is always a concrete int.

Parameters:

NameTypeDescription
opControlledUOperationThe operation to resolve.
resolverExprResolverResolver for the current scope.

Returns:

tuple[int | sp.Expr, int] — tuple[int | sp.Expr, int]: (num_controls, num_targets).


resolve_for_items_cardinality [source]
def resolve_for_items_cardinality(op: ForItemsOperation) -> sp.Expr

Return the symbolic cardinality |dict_name| for a ForItems loop.

Parameters:

NameTypeDescription
opForItemsOperationThe for-items loop operation.

Returns:

sp.Expr — sp.Expr: A positive integer symbol |dict_name|.


symbolic_iterations [source]
def symbolic_iterations(start: sp.Expr, stop: sp.Expr, step: sp.Expr) -> sp.Expr

Compute the number of iterations of range(start, stop, step).

Uses the discrete formula Max(0, ceiling((stop - start) / step)) which exactly matches Python range() semantics for any integer step (positive, negative, or symbolic).

Parameters:

NameTypeDescription
startsp.ExprSymbolic start bound.
stopsp.ExprSymbolic stop bound.
stepsp.ExprSymbolic step bound.

Returns:

sp.Expr — sp.Expr: Symbolic iteration count Max(0, ceiling((stop - start) / step)).

Raises:

Classes

BlockValue [source]
class BlockValue(Value[BlockType])

Represents a subroutine as a function block.

def func_block(a: UInt, b: UInt) -> tuple[UInt]: ...

BlockValue( name=“func_block”, inputs_type={“a”: UIntType(), “b”: UIntType()}, outputs_type=(UIntType(), ), operations=[...], )

Function to BlockValue conversion can be done via func_to_block function. Each Values in operations are dummy values. The execution of the BlockValue is corresponding to the BlockOperation.

Constructor
def __init__(
    self,
    type: BlockType = BlockType(),
    name: str = '',
    version: int = 0,
    params: dict[str, Any] = dict(),
    uuid: str = (lambda: str(uuid.uuid4()))(),
    logical_id: str = (lambda: str(uuid.uuid4()))(),
    parent_array: ArrayValue | None = None,
    element_indices: tuple[Value, ...] = (),
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    return_values: list[Value] = list(),
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation to call this BlockValue.

Example:

block_value = BlockValue(
    name="func_block",
    inputs_type={"a": UIntType(), "b": UIntType()},
    outputs_type=(UIntType(), ),
    operations=[...],
)
a = Value(UIntType())
b = Value(UIntType())
call_op = block_value.call(a=a, b=b)

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

CompositeGateOperation [source]
class CompositeGateOperation(Operation)

Represents a composite gate (QPE, QFT, etc.) as a single operation.

CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:

The operands structure depends on has_implementation:

The results structure:

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    gate_type: CompositeGateType = CompositeGateType.CUSTOM,
    num_control_qubits: int = 0,
    num_target_qubits: int = 0,
    custom_name: str = '',
    resource_metadata: ResourceMetadata | None = None,
    has_implementation: bool = True,
    composite_gate_instance: Any = None,
    strategy_name: str | None = None,
) -> None
Attributes

ControlledUOperation [source]
class ControlledUOperation(Operation)

Controlled-U operation that applies a unitary block conditionally.

The operands structure is:

The results structure is:

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    num_controls: int | Value = 1,
    power: int | Value = 1,
    target_indices: list[Value] | None = None,
    controlled_indices: list[Value] | None = None,
) -> None
Attributes

ExprResolver [source]
class ExprResolver

Single source of truth for converting IR Values to SymPy expressions.

Resolution strategy (deterministic, single path):

  1. Already sp.Basic → return as-is

  2. Not a Value (int, float, bool) → direct conversion

  3. UUID in context (call_context / BinOp) → return mapped expression

  4. Constant value → sp.Integer / sp.Float

  5. Unbound parameter → sp.Symbol (symbolic) or raise (concrete)

  6. Loop variable (name-based) → return mapped symbol

  7. BinOp/CompOp result → trace in block operations

  8. Search parent blocks → trace in ancestors

  9. Fallback → sp.Symbol (symbolic) or raise (concrete)

Constructor
def __init__(
    self,
    block: Any = None,
    context: dict[str, sp.Expr] | None = None,
    loop_var_names: dict[str, sp.Symbol] | None = None,
    parent_blocks: list[Any] | None = None,
)

Initialise an ExprResolver.

Parameters:

NameTypeDescription
blockAnyThe current block (BlockValue or _LocalBlock) whose operations are searched for BinOp/CompOp traces.
contextdict[str, sp.Expr] | NoneUUID → resolved expression mapping for values passed across scope boundaries (e.g. call arguments, composite-gate operands).
loop_var_namesdict[str, sp.Symbol] | NoneValue name → SymPy symbol mapping for loop variables in scope.
parent_blockslist[Any] | NoneAncestor blocks to search when tracing fails in the current block.
Attributes
Methods
call_child_scope
def call_child_scope(self, call_op: Any) -> ExprResolver

Create a child resolver for a CallBlockOperation.

Maps formal parameter UUIDs → resolved actual arguments, including array shape dimension UUIDs (critical for resolving e.g. kernel.shape[0] inside the callee).

Parent blocks are intentionally reset — the callee only sees its own scope plus values propagated through call_context.

Parameters:

NameTypeDescription
call_opAnyA CallBlockOperation whose operands[0] is the called BlockValue and operands[1:] are actuals.

Returns:

ExprResolver — A new resolver scoped to the callee block with formal→actual bindings in context and empty parent blocks.

child_scope
def child_scope(
    self,
    inner_block: Any,
    extra_context: dict[str, sp.Expr] | None = None,
    extra_loop_vars: dict[str, sp.Symbol] | None = None,
) -> ExprResolver

Create a child resolver for an inner scope (loop body, branch).

Propagates parent_blocks so values from outer scopes remain traceable. For callee scopes (CallBlockOperation), use :meth:call_child_scope instead — callees get a fresh scope.

Parameters:

NameTypeDescription
inner_blockAnyThe block for the child scope.
extra_contextdict[str, sp.Expr] | NoneAdditional UUID → expression mappings to merge into the child context.
extra_loop_varsdict[str, sp.Symbol] | NoneAdditional loop variable name → symbol mappings.

Returns:

ExprResolver — A new resolver scoped to inner_block with parent blocks propagated from the current resolver.

resolve
def resolve(self, v: Any) -> sp.Expr

Convert IR Value to SymPy expression (symbolic mode).

Unbound parameters become sp.Symbol. Never raises for valid IR.

Parameters:

NameTypeDescription
vAnyIR Value, primitive Python type, or sp.Basic.

Returns:

sp.Expr — sp.Expr: Resolved SymPy expression.

resolve_concrete
def resolve_concrete(self, v: Any) -> int

Convert IR Value to concrete int.

Parameters:

NameTypeDescription
vAnyIR Value, primitive Python type, or sp.Basic.

Returns:

int — The resolved concrete integer.

Raises:


ForItemsOperation [source]
class ForItemsOperation(Operation)

Represents iteration over dict/iterable items.

Example:

for (i, j), Jij in qmc.items(ising):
    body
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    key_vars: list[str] = list(),
    value_var: str = '',
    key_is_vector: bool = False,
    operations: list[Operation] = list(),
) -> None
Attributes

ForOperation [source]
class ForOperation(Operation)

Represents a for loop operation.

Example:

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

GateCount [source]
class GateCount

Gate count breakdown for a quantum circuit.

All counts are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    total: sp.Expr,
    single_qubit: sp.Expr,
    two_qubit: sp.Expr,
    multi_qubit: sp.Expr,
    t_gates: sp.Expr,
    clifford_gates: sp.Expr,
    rotation_gates: sp.Expr,
    oracle_calls: dict[str, sp.Expr] = dict(),
    oracle_queries: dict[str, sp.Expr] = dict(),
) -> None
Attributes
Methods
max
def max(self, other: GateCount) -> GateCount

Element-wise maximum of two gate counts.

Parameters:

NameTypeDescription
otherGateCountThe gate count to compare against.

Returns:

GateCount — New instance where each field is sp.Max(self.field, other.field). Oracle dicts are merged key-wise with sp.Max for common keys.

simplify
def simplify(self) -> GateCount

Simplify all SymPy expressions.

Returns:

GateCount — New instance with sp.simplify and _strip_nonneg_max applied to every field.

zero
@staticmethod
def zero() -> GateCount

Return a zero gate count.

Returns:

GateCount — Instance with all fields set to sp.Integer(0) and empty oracle dicts.


GateOperation [source]
class GateOperation(Operation)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    gate_type: GateOperationType | None = None,
    theta: float | Value | None = None,
) -> None
Attributes

IfOperation [source]
class IfOperation(Operation)

Represents an if-else conditional operation.

Example:

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

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

WhileOperation [source]
class WhileOperation(Operation)

Represents a while loop operation.

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

Example::

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

qamomile.circuit.estimator.qubits_counter

Qubit resource counting for BlockValue.

This module counts the number of qubits required by a quantum circuit, using ExprResolver for value resolution and shared engine helpers for control flow scoping.

Overview

FunctionDescription
build_for_items_scopeBuild child resolver for a ForItemsOperation body.
build_for_loop_scopeBuild child resolver and resolved bounds for a ForOperation.
build_if_scopesBuild child resolvers for both branches of an IfOperation.
build_while_scopeBuild child resolver and trip-count symbol for a WhileOperation.
qubits_counterCount the number of qubits required by a BlockValue.
resolve_for_items_cardinalityReturn the symbolic cardinality |dict_name| for a ForItems loop.
symbolic_iterationsCompute the number of iterations of range(start, stop, step).
ClassDescription
ArrayValueAn array of values with shape information.
BlockValueRepresents a subroutine as a function block.
CallBlockOperation
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
ControlledUOperationControlled-U operation that applies a unitary block conditionally.
ExprResolverSingle source of truth for converting IR Values to SymPy expressions.
ForItemsOperationRepresents iteration over dict/iterable items.
ForOperationRepresents a for loop operation.
IfOperationRepresents an if-else conditional operation.
Operation
QInitOperationInitialize the qubit
QubitTypeType representing a quantum bit (qubit).
WhileOperationRepresents a while loop operation.

Functions

build_for_items_scope [source]
def build_for_items_scope(op: ForItemsOperation, resolver: ExprResolver) -> ExprResolver

Build child resolver for a ForItemsOperation body.

Parameters:

NameTypeDescription
opForItemsOperationThe for-items loop operation.
resolverExprResolverResolver for the enclosing scope.

Returns:

ExprResolver — Child resolver scoped to the loop body.


build_for_loop_scope [source]
def build_for_loop_scope(
    op: ForOperation,
    resolver: ExprResolver,
) -> tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol]

Build child resolver and resolved bounds for a ForOperation.

Parameters:

NameTypeDescription
opForOperationThe for-loop operation.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol] — tuple[ExprResolver, sp.Expr, sp.Expr, sp.Expr, sp.Symbol]: (child_resolver, start, stop, step, loop_symbol). The child resolver has block = local block over op.operations, loop variable mapped to loop_symbol, and parent blocks propagated.


build_if_scopes [source]
def build_if_scopes(op: Any, resolver: ExprResolver) -> tuple[ExprResolver, ExprResolver]

Build child resolvers for both branches of an IfOperation.

Parameters:

NameTypeDescription
opAnyAn IfOperation with true_operations and false_operations attributes.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, ExprResolver] — tuple[ExprResolver, ExprResolver]: (true_resolver, false_resolver).


build_while_scope [source]
def build_while_scope(op: Any, resolver: ExprResolver) -> tuple[ExprResolver, sp.Symbol]

Build child resolver and trip-count symbol for a WhileOperation.

Parameters:

NameTypeDescription
opAnyA WhileOperation with an operations attribute.
resolverExprResolverResolver for the enclosing scope.

Returns:

tuple[ExprResolver, sp.Symbol] — tuple[ExprResolver, sp.Symbol]: (child_resolver, trip_count_symbol) where trip_count_symbol is |while|.


qubits_counter [source]
def qubits_counter(block: BlockValue | list[Operation]) -> sp.Expr

Count the number of qubits required by a BlockValue.

This function analyzes the operations in a BlockValue and counts the total number of qubits that need to be allocated. It handles:

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]The BlockValue to analyze.

Returns:

sp.Expr — The qubit count as a sympy expression. May contain symbols sp.Expr — for parametric dimensions (e.g., if array sizes are parameters).

Example:

>>> from qamomile.circuit.ir.block_value import BlockValue
>>> block = some_block_value()
>>> count = qubits_counter(block)
>>> print(count)  # e.g., "n + 3" for parametric n

resolve_for_items_cardinality [source]
def resolve_for_items_cardinality(op: ForItemsOperation) -> sp.Expr

Return the symbolic cardinality |dict_name| for a ForItems loop.

Parameters:

NameTypeDescription
opForItemsOperationThe for-items loop operation.

Returns:

sp.Expr — sp.Expr: A positive integer symbol |dict_name|.


symbolic_iterations [source]
def symbolic_iterations(start: sp.Expr, stop: sp.Expr, step: sp.Expr) -> sp.Expr

Compute the number of iterations of range(start, stop, step).

Uses the discrete formula Max(0, ceiling((stop - start) / step)) which exactly matches Python range() semantics for any integer step (positive, negative, or symbolic).

Parameters:

NameTypeDescription
startsp.ExprSymbolic start bound.
stopsp.ExprSymbolic stop bound.
stepsp.ExprSymbolic step bound.

Returns:

sp.Expr — sp.Expr: Symbolic iteration count Max(0, ceiling((stop - start) / step)).

Raises:

Classes

ArrayValue [source]
class ArrayValue(Value[T])

An array of values with shape information.

ArrayValue extends Value to represent multi-dimensional arrays of typed values (e.g., qubit registers, parameter vectors).

Constructor
def __init__(
    self,
    type: T,
    name: str,
    version: int = 0,
    params: dict[str, Any] = dict(),
    uuid: str = (lambda: str(uuid.uuid4()))(),
    logical_id: str = (lambda: str(uuid.uuid4()))(),
    parent_array: ArrayValue | None = None,
    element_indices: tuple[Value, ...] = (),
    shape: tuple[Value, ...] = tuple(),
) -> None
Attributes
Methods
next_version
def next_version(self) -> ArrayValue[T]

Create a new ArrayValue with incremented version, preserving shape.


BlockValue [source]
class BlockValue(Value[BlockType])

Represents a subroutine as a function block.

def func_block(a: UInt, b: UInt) -> tuple[UInt]: ...

BlockValue( name=“func_block”, inputs_type={“a”: UIntType(), “b”: UIntType()}, outputs_type=(UIntType(), ), operations=[...], )

Function to BlockValue conversion can be done via func_to_block function. Each Values in operations are dummy values. The execution of the BlockValue is corresponding to the BlockOperation.

Constructor
def __init__(
    self,
    type: BlockType = BlockType(),
    name: str = '',
    version: int = 0,
    params: dict[str, Any] = dict(),
    uuid: str = (lambda: str(uuid.uuid4()))(),
    logical_id: str = (lambda: str(uuid.uuid4()))(),
    parent_array: ArrayValue | None = None,
    element_indices: tuple[Value, ...] = (),
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    return_values: list[Value] = list(),
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation to call this BlockValue.

Example:

block_value = BlockValue(
    name="func_block",
    inputs_type={"a": UIntType(), "b": UIntType()},
    outputs_type=(UIntType(), ),
    operations=[...],
)
a = Value(UIntType())
b = Value(UIntType())
call_op = block_value.call(a=a, b=b)

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

CompositeGateOperation [source]
class CompositeGateOperation(Operation)

Represents a composite gate (QPE, QFT, etc.) as a single operation.

CompositeGate allows representing complex multi-gate operations as a single atomic operation in the IR. This enables:

The operands structure depends on has_implementation:

The results structure:

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    gate_type: CompositeGateType = CompositeGateType.CUSTOM,
    num_control_qubits: int = 0,
    num_target_qubits: int = 0,
    custom_name: str = '',
    resource_metadata: ResourceMetadata | None = None,
    has_implementation: bool = True,
    composite_gate_instance: Any = None,
    strategy_name: str | None = None,
) -> None
Attributes

ControlledUOperation [source]
class ControlledUOperation(Operation)

Controlled-U operation that applies a unitary block conditionally.

The operands structure is:

The results structure is:

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    num_controls: int | Value = 1,
    power: int | Value = 1,
    target_indices: list[Value] | None = None,
    controlled_indices: list[Value] | None = None,
) -> None
Attributes

ExprResolver [source]
class ExprResolver

Single source of truth for converting IR Values to SymPy expressions.

Resolution strategy (deterministic, single path):

  1. Already sp.Basic → return as-is

  2. Not a Value (int, float, bool) → direct conversion

  3. UUID in context (call_context / BinOp) → return mapped expression

  4. Constant value → sp.Integer / sp.Float

  5. Unbound parameter → sp.Symbol (symbolic) or raise (concrete)

  6. Loop variable (name-based) → return mapped symbol

  7. BinOp/CompOp result → trace in block operations

  8. Search parent blocks → trace in ancestors

  9. Fallback → sp.Symbol (symbolic) or raise (concrete)

Constructor
def __init__(
    self,
    block: Any = None,
    context: dict[str, sp.Expr] | None = None,
    loop_var_names: dict[str, sp.Symbol] | None = None,
    parent_blocks: list[Any] | None = None,
)

Initialise an ExprResolver.

Parameters:

NameTypeDescription
blockAnyThe current block (BlockValue or _LocalBlock) whose operations are searched for BinOp/CompOp traces.
contextdict[str, sp.Expr] | NoneUUID → resolved expression mapping for values passed across scope boundaries (e.g. call arguments, composite-gate operands).
loop_var_namesdict[str, sp.Symbol] | NoneValue name → SymPy symbol mapping for loop variables in scope.
parent_blockslist[Any] | NoneAncestor blocks to search when tracing fails in the current block.
Attributes
Methods
call_child_scope
def call_child_scope(self, call_op: Any) -> ExprResolver

Create a child resolver for a CallBlockOperation.

Maps formal parameter UUIDs → resolved actual arguments, including array shape dimension UUIDs (critical for resolving e.g. kernel.shape[0] inside the callee).

Parent blocks are intentionally reset — the callee only sees its own scope plus values propagated through call_context.

Parameters:

NameTypeDescription
call_opAnyA CallBlockOperation whose operands[0] is the called BlockValue and operands[1:] are actuals.

Returns:

ExprResolver — A new resolver scoped to the callee block with formal→actual bindings in context and empty parent blocks.

child_scope
def child_scope(
    self,
    inner_block: Any,
    extra_context: dict[str, sp.Expr] | None = None,
    extra_loop_vars: dict[str, sp.Symbol] | None = None,
) -> ExprResolver

Create a child resolver for an inner scope (loop body, branch).

Propagates parent_blocks so values from outer scopes remain traceable. For callee scopes (CallBlockOperation), use :meth:call_child_scope instead — callees get a fresh scope.

Parameters:

NameTypeDescription
inner_blockAnyThe block for the child scope.
extra_contextdict[str, sp.Expr] | NoneAdditional UUID → expression mappings to merge into the child context.
extra_loop_varsdict[str, sp.Symbol] | NoneAdditional loop variable name → symbol mappings.

Returns:

ExprResolver — A new resolver scoped to inner_block with parent blocks propagated from the current resolver.

resolve
def resolve(self, v: Any) -> sp.Expr

Convert IR Value to SymPy expression (symbolic mode).

Unbound parameters become sp.Symbol. Never raises for valid IR.

Parameters:

NameTypeDescription
vAnyIR Value, primitive Python type, or sp.Basic.

Returns:

sp.Expr — sp.Expr: Resolved SymPy expression.

resolve_concrete
def resolve_concrete(self, v: Any) -> int

Convert IR Value to concrete int.

Parameters:

NameTypeDescription
vAnyIR Value, primitive Python type, or sp.Basic.

Returns:

int — The resolved concrete integer.

Raises:


ForItemsOperation [source]
class ForItemsOperation(Operation)

Represents iteration over dict/iterable items.

Example:

for (i, j), Jij in qmc.items(ising):
    body
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    key_vars: list[str] = list(),
    value_var: str = '',
    key_is_vector: bool = False,
    operations: list[Operation] = list(),
) -> None
Attributes

ForOperation [source]
class ForOperation(Operation)

Represents a for loop operation.

Example:

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

IfOperation [source]
class IfOperation(Operation)

Represents an if-else conditional operation.

Example:

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

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

QInitOperation [source]
class QInitOperation(Operation)

Initialize the qubit

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

QubitType [source]
class QubitType(QuantumTypeMixin, ValueType)

Type representing a quantum bit (qubit).


WhileOperation [source]
class WhileOperation(Operation)

Represents a while loop operation.

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

Example::

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

qamomile.circuit.estimator.resource_estimator

Unified resource estimation interface.

This module combines all resource metrics (qubits, gates) into a single interface for comprehensive circuit analysis.

Overview

FunctionDescription
count_gatesCount gates in a quantum circuit.
estimate_resourcesEstimate all resources for a quantum circuit.
qubits_counterCount the number of qubits required by a BlockValue.
ClassDescription
BlockValueRepresents a subroutine as a function block.
Operation
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

count_gates [source]
def count_gates(block: BlockValue | list[Operation]) -> GateCount

Count gates in a quantum circuit.

This function analyzes operations and returns algebraic gate counts using SymPy expressions. Counts may contain symbols for parametric problem sizes (e.g., loop bounds, array dimensions).

Supports:

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]BlockValue or list of Operations to analyze

Returns:

GateCount — GateCount with total, single_qubit, two_qubit, t_gates, clifford_gates

Example:

>>> from qamomile.circuit.estimator import count_gates
>>> count = count_gates(my_circuit.block)
>>> print(count.total)  # e.g., "2*n + 5"
>>> print(count.t_gates)  # e.g., "n"

estimate_resources [source]
def estimate_resources(
    block: BlockValue | list[Operation],
    *,
    bindings: dict[str, Any] | None = None,
) -> ResourceEstimate

Estimate all resources for a quantum circuit.

This is the main entry point for comprehensive resource estimation. Combines qubit counting and gate counting.

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]BlockValue or list of Operations to analyze
bindingsdict[str, Any] | NoneOptional concrete parameter bindings (scalars and dicts).

Returns:

ResourceEstimate — ResourceEstimate with qubits, gates, and parameters

Example:

>>> import qamomile.circuit as qm
>>> from qamomile.circuit.estimator import estimate_resources
>>>
>>> @qm.qkernel
>>> def bell_state() -> qm.Vector[qm.Qubit]:
...     q = qm.qubit_array(2)
...     q[0] = qm.h(q[0])
...     q[0], q[1] = qm.cx(q[0], q[1])
...     return q
>>>
>>> est = estimate_resources(bell_state.block)
>>> print(est.qubits)  # 2
>>> print(est.gates.total)  # 2
>>> print(est.gates.two_qubit)  # 1

Example with parametric size:

qm.qkernel def ghz_state(n: qm.UInt) -> qm.Vector[qm.Qubit]: ... q = qm.qubit_array(n) ... q[0] = qm.h(q[0]) ... for i in qm.range(n - 1): ... q[i], q[i+1] = qm.cx(q[i], q[i+1]) ... return q

est = estimate_resources(ghz_state.block) print(est.qubits) # n print(est.gates.total) # n print(est.gates.two_qubit) # n - 1

Substitute concrete value

concrete = est.substitute(n=100) print(concrete.qubits) # 100 print(concrete.gates.total) # 100


qubits_counter [source]
def qubits_counter(block: BlockValue | list[Operation]) -> sp.Expr

Count the number of qubits required by a BlockValue.

This function analyzes the operations in a BlockValue and counts the total number of qubits that need to be allocated. It handles:

Parameters:

NameTypeDescription
blockBlockValue | list[Operation]The BlockValue to analyze.

Returns:

sp.Expr — The qubit count as a sympy expression. May contain symbols sp.Expr — for parametric dimensions (e.g., if array sizes are parameters).

Example:

>>> from qamomile.circuit.ir.block_value import BlockValue
>>> block = some_block_value()
>>> count = qubits_counter(block)
>>> print(count)  # e.g., "n + 3" for parametric n

Classes

BlockValue [source]
class BlockValue(Value[BlockType])

Represents a subroutine as a function block.

def func_block(a: UInt, b: UInt) -> tuple[UInt]: ...

BlockValue( name=“func_block”, inputs_type={“a”: UIntType(), “b”: UIntType()}, outputs_type=(UIntType(), ), operations=[...], )

Function to BlockValue conversion can be done via func_to_block function. Each Values in operations are dummy values. The execution of the BlockValue is corresponding to the BlockOperation.

Constructor
def __init__(
    self,
    type: BlockType = BlockType(),
    name: str = '',
    version: int = 0,
    params: dict[str, Any] = dict(),
    uuid: str = (lambda: str(uuid.uuid4()))(),
    logical_id: str = (lambda: str(uuid.uuid4()))(),
    parent_array: ArrayValue | None = None,
    element_indices: tuple[Value, ...] = (),
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    return_values: list[Value] = list(),
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation to call this BlockValue.

Example:

block_value = BlockValue(
    name="func_block",
    inputs_type={"a": UIntType(), "b": UIntType()},
    outputs_type=(UIntType(), ),
    operations=[...],
)
a = Value(UIntType())
b = Value(UIntType())
call_op = block_value.call(a=a, b=b)

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

ResourceEstimate [source]
class ResourceEstimate

Comprehensive resource estimate for a quantum circuit.

All metrics are SymPy expressions that may contain symbols for parametric problem sizes.

Constructor
def __init__(
    self,
    qubits: sp.Expr,
    gates: GateCount,
    parameters: dict[str, sp.Symbol] = dict(),
) -> None
Attributes
Methods
simplify
def simplify(self) -> ResourceEstimate

Simplify all SymPy expressions.

Returns:

ResourceEstimate — New ResourceEstimate with simplified expressions

substitute
def substitute(self, **values: int | float = {}) -> ResourceEstimate

Substitute concrete values for parameters.

Parameters:

NameTypeDescription
**valuesint | floatParameter name -> concrete value mappings

Returns:

ResourceEstimate — New ResourceEstimate with substituted values

Example:

>>> est = estimate_resources(circuit)
>>> concrete = est.substitute(n=100, p=3)
>>> print(concrete.qubits)  # 100 (instead of 'n')
to_dict
def to_dict(self) -> dict[str, Any]

Convert to a dictionary for serialization.

Returns:

dict[str, Any] — Dictionary with all metrics as strings (for JSON/YAML export)

Example:

>>> est = estimate_resources(circuit)
>>> data = est.to_dict()
>>> import json
>>> print(json.dumps(data, indent=2))