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: Block | list[Operation],
    bindings: dict[str, Any] | None = None,
) -> 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
blockBlock | list[Operation]Block or list of Operations to analyze
bindingsdict[str, Any] | NoneOptional parameter bindings. Required for PauliEvolveOp gate counting (must contain the Hamiltonian).

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: Block | 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
blockBlock | list[Operation]Block 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.
classify_pauli_evolveGate count for PauliEvolve decomposition (Pauli gadget method).
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
BlockUnified block representation for all pipeline stages.
CallBlockOperation
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
ControlledUOperationBase class for controlled-U operations.
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.
GateOperationQuantum gate operation.
HasNestedOpsMixin for operations that contain nested operation lists.
IfOperationRepresents an if-else conditional operation.
Operation
PauliEvolveOpPauli evolution operation: exp(-i * gamma * H).
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.


classify_pauli_evolve [source]
def classify_pauli_evolve(hamiltonian: Any) -> GateCount

Gate count for PauliEvolve decomposition (Pauli gadget method).

For each Hamiltonian term with k qubits (x_count X, y_count Y):

Parameters:

NameTypeDescription
hamiltonianAnyA concrete Hamiltonian with known terms.

Returns:

GateCount — Total gate counts for the full Pauli evolution.


count_gates [source]
def count_gates(
    block: Block | list[Operation],
    bindings: dict[str, Any] | None = None,
) -> 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
blockBlock | list[Operation]Block or list of Operations to analyze
bindingsdict[str, Any] | NoneOptional parameter bindings. Required for PauliEvolveOp gate counting (must contain the Hamiltonian).

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 + Block)

  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

Block [source]
class Block

Unified block representation for all pipeline stages.

Replaces the older traced and callable IR wrappers with a single structure. The kind field indicates which pipeline stage this block is at.

Constructor
def __init__(
    self,
    name: str = '',
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    output_values: list[Value] = list(),
    output_names: list[str] = list(),
    operations: list['Operation'] = list(),
    kind: BlockKind = BlockKind.HIERARCHICAL,
    parameters: dict[str, Value] = dict(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check if block contains no CallBlockOperations.

unbound_parameters
def unbound_parameters(self) -> list[str]

Return list of unbound parameter names.


CallBlockOperation [source]
class CallBlockOperation(Operation)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    block: Block | None = None,
) -> None
Attributes
Methods
is_self_reference_to
def is_self_reference_to(self, block: Block) -> bool

Return True if this call points to the given block (self-ref).


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 is:

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,
    implementation_block: Block | None = None,
    composite_gate_instance: Any = None,
    strategy_name: str | None = None,
) -> None
Attributes

ControlledUOperation [source]
class ControlledUOperation(Operation)

Base class for controlled-U operations.

Three concrete subclasses handle distinct operand layouts:

All isinstance(op, ControlledUOperation) checks match every subclass.

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    power: int | Value = 1,
    block: Block | None = None,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

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 (Block 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 block field is the called Block and operands 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(HasNestedOps, 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,
    key_var_values: tuple[Value, ...] | None = None,
    value_var_value: Value | None = None,
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Include the per-key/value Value fields for cloning/substitution.

Same rationale as ForOperation.all_input_values: keep the IR identity fields in lockstep with body references so UUID-keyed lookups stay valid after inline cloning.

nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

ForOperation [source]
class ForOperation(HasNestedOps, 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 = '',
    loop_var_value: Value | None = None,
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Include loop_var_value so cloning/substitution stays consistent.

Without this override, UUIDRemapper would clone every body reference to the loop variable to a fresh UUID, but leave loop_var_value pointing at the un-cloned original — emit-time UUID-keyed lookups for the loop variable would then miss.

nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

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)

Quantum gate operation.

For rotation gates (RX, RY, RZ, P, CP, RZZ), the angle parameter is stored as the last element of operands. Use the theta property for typed read access and the rotation / fixed factory class-methods for type-safe construction.

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    gate_type: GateOperationType | None = None,
) -> None
Attributes
Methods
fixed
@classmethod
def fixed(
    cls,
    gate_type: GateOperationType,
    qubits: list[Value],
    results: list[Value],
) -> 'GateOperation'

Create a fixed gate (H, X, CX, SWAP, …) with no angle parameter.

rotation
@classmethod
def rotation(
    cls,
    gate_type: GateOperationType,
    qubits: list[Value],
    theta: Value,
    results: list[Value],
) -> 'GateOperation'

Create a rotation gate (RX, RY, RZ, P, CP, RZZ) with an angle.


HasNestedOps [source]
class HasNestedOps

Mixin for operations that contain nested operation lists.

Subclasses implement nested_op_lists() and rebuild_nested() so that generic passes can recurse into control flow without isinstance chains.

Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]

Return all nested operation lists in this control flow op.

rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

Return a copy with nested operation lists replaced.

new_lists must have the same length/order as nested_op_lists().


IfOperation [source]
class IfOperation(HasNestedOps, 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
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

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

Return all input Values including subclass-specific fields.

Generic passes should use this instead of accessing operands directly to ensure no Value is missed. Subclasses override this to include extra Value fields (e.g. ControlledUOperation.power).

replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

Return a copy with all Values substituted via mapping.

Handles operands, results, and subclass-specific Value fields. Subclasses override to handle their extra fields.


PauliEvolveOp [source]
class PauliEvolveOp(Operation)

Pauli evolution operation: exp(-i * gamma * H).

This operation applies the time evolution of a Pauli Hamiltonian to a quantum register.

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

WhileOperation [source]
class WhileOperation(HasNestedOps, 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(),
    max_iterations: int | None = None,
) -> None
Attributes
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

qamomile.circuit.estimator.qubits_counter

Qubit resource counting for Block.

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 Block.
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 typed IR values.
BlockUnified block representation for all pipeline stages.
CallBlockOperation
CompositeGateOperationRepresents a composite gate (QPE, QFT, etc.) as a single operation.
ControlledUOperationBase class for controlled-U operations.
ExprResolverSingle source of truth for converting IR Values to SymPy expressions.
ForItemsOperationRepresents iteration over dict/iterable items.
ForOperationRepresents a for loop operation.
HasNestedOpsMixin for operations that contain nested operation lists.
IfOperationRepresents an if-else conditional operation.
Operation
PauliEvolveOpPauli evolution operation: exp(-i * gamma * H).
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: Block | list[Operation]) -> sp.Expr

Count the number of qubits required by a Block.

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

Parameters:

NameTypeDescription
blockBlock | list[Operation]The Block 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 import Block
>>> block = some_block()
>>> 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 typed IR values.

Constructor
def __init__(
    self,
    type: T,
    name: str,
    version: int = 0,
    metadata: ValueMetadata = ValueMetadata(),
    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]

Block [source]
class Block

Unified block representation for all pipeline stages.

Replaces the older traced and callable IR wrappers with a single structure. The kind field indicates which pipeline stage this block is at.

Constructor
def __init__(
    self,
    name: str = '',
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    output_values: list[Value] = list(),
    output_names: list[str] = list(),
    operations: list['Operation'] = list(),
    kind: BlockKind = BlockKind.HIERARCHICAL,
    parameters: dict[str, Value] = dict(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check if block contains no CallBlockOperations.

unbound_parameters
def unbound_parameters(self) -> list[str]

Return list of unbound parameter names.


CallBlockOperation [source]
class CallBlockOperation(Operation)
Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    block: Block | None = None,
) -> None
Attributes
Methods
is_self_reference_to
def is_self_reference_to(self, block: Block) -> bool

Return True if this call points to the given block (self-ref).


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 is:

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,
    implementation_block: Block | None = None,
    composite_gate_instance: Any = None,
    strategy_name: str | None = None,
) -> None
Attributes

ControlledUOperation [source]
class ControlledUOperation(Operation)

Base class for controlled-U operations.

Three concrete subclasses handle distinct operand layouts:

All isinstance(op, ControlledUOperation) checks match every subclass.

Constructor
def __init__(
    self,
    operands: list[Value] = list(),
    results: list[Value] = list(),
    power: int | Value = 1,
    block: Block | None = None,
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

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 (Block 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 block field is the called Block and operands 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(HasNestedOps, 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,
    key_var_values: tuple[Value, ...] | None = None,
    value_var_value: Value | None = None,
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Include the per-key/value Value fields for cloning/substitution.

Same rationale as ForOperation.all_input_values: keep the IR identity fields in lockstep with body references so UUID-keyed lookups stay valid after inline cloning.

nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

ForOperation [source]
class ForOperation(HasNestedOps, 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 = '',
    loop_var_value: Value | None = None,
    operations: list[Operation] = list(),
) -> None
Attributes
Methods
all_input_values
def all_input_values(self) -> list[ValueBase]

Include loop_var_value so cloning/substitution stays consistent.

Without this override, UUIDRemapper would clone every body reference to the loop variable to a fresh UUID, but leave loop_var_value pointing at the un-cloned original — emit-time UUID-keyed lookups for the loop variable would then miss.

nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation
replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

HasNestedOps [source]
class HasNestedOps

Mixin for operations that contain nested operation lists.

Subclasses implement nested_op_lists() and rebuild_nested() so that generic passes can recurse into control flow without isinstance chains.

Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]

Return all nested operation lists in this control flow op.

rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

Return a copy with nested operation lists replaced.

new_lists must have the same length/order as nested_op_lists().


IfOperation [source]
class IfOperation(HasNestedOps, 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
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

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

Return all input Values including subclass-specific fields.

Generic passes should use this instead of accessing operands directly to ensure no Value is missed. Subclasses override this to include extra Value fields (e.g. ControlledUOperation.power).

replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

Return a copy with all Values substituted via mapping.

Handles operands, results, and subclass-specific Value fields. Subclasses override to handle their extra fields.


PauliEvolveOp [source]
class PauliEvolveOp(Operation)

Pauli evolution operation: exp(-i * gamma * H).

This operation applies the time evolution of a Pauli Hamiltonian to a quantum register.

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(HasNestedOps, 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(),
    max_iterations: int | None = None,
) -> None
Attributes
Methods
nested_op_lists
def nested_op_lists(self) -> list[list[Operation]]
rebuild_nested
def rebuild_nested(self, new_lists: list[list[Operation]]) -> Operation

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 Block.
ClassDescription
BlockUnified block representation for all pipeline stages.
Operation
ResourceEstimateComprehensive resource estimate for a quantum circuit.

Functions

count_gates [source]
def count_gates(
    block: Block | list[Operation],
    bindings: dict[str, Any] | None = None,
) -> 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
blockBlock | list[Operation]Block or list of Operations to analyze
bindingsdict[str, Any] | NoneOptional parameter bindings. Required for PauliEvolveOp gate counting (must contain the Hamiltonian).

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: Block | 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
blockBlock | list[Operation]Block 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: Block | list[Operation]) -> sp.Expr

Count the number of qubits required by a Block.

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

Parameters:

NameTypeDescription
blockBlock | list[Operation]The Block 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 import Block
>>> block = some_block()
>>> count = qubits_counter(block)
>>> print(count)  # e.g., "n + 3" for parametric n

Classes

Block [source]
class Block

Unified block representation for all pipeline stages.

Replaces the older traced and callable IR wrappers with a single structure. The kind field indicates which pipeline stage this block is at.

Constructor
def __init__(
    self,
    name: str = '',
    label_args: list[str] = list(),
    input_values: list[Value] = list(),
    output_values: list[Value] = list(),
    output_names: list[str] = list(),
    operations: list['Operation'] = list(),
    kind: BlockKind = BlockKind.HIERARCHICAL,
    parameters: dict[str, Value] = dict(),
) -> None
Attributes
Methods
call
def call(self, **kwargs: Value = {}) -> 'CallBlockOperation'

Create a CallBlockOperation against this block.

is_affine
def is_affine(self) -> bool

Check if block contains no CallBlockOperations.

unbound_parameters
def unbound_parameters(self) -> list[str]

Return list of unbound parameter names.


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

Return all input Values including subclass-specific fields.

Generic passes should use this instead of accessing operands directly to ensure no Value is missed. Subclasses override this to include extra Value fields (e.g. ControlledUOperation.power).

replace_values
def replace_values(self, mapping: dict[str, ValueBase]) -> Operation

Return a copy with all Values substituted via mapping.

Handles operands, results, and subclass-specific Value fields. Subclasses override to handle their extra fields.


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))