Resource estimation module for Qamomile circuits.
This module provides comprehensive resource estimation for quantum circuits, including:
Qubit counting: Algebraic qubit count with SymPy
Gate counting: Breakdown by gate type (single/two-qubit, T gates, Clifford)
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
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
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¶
| Function | Description |
|---|---|
count_gates | Count gates in a quantum circuit. |
estimate_resources | Estimate all resources for a quantum circuit. |
| Class | Description |
|---|---|
ResourceEstimate | Comprehensive resource estimate for a quantum circuit. |
Functions¶
count_gates [source]¶
def count_gates(block: BlockValue | list[Operation]) -> GateCountCount 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:
GateOperation: Single gate counts
ForOperation: Multiplies inner count by iterations
IfOperation: Takes maximum of branches
CallBlockOperation: Recursively counts called blocks
ControlledUOperation: Counts as a single opaque gate
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | 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,
) -> ResourceEstimateEstimate all resources for a quantum circuit.
This is the main entry point for comprehensive resource estimation. Combines qubit counting and gate counting.
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | list[Operation] | BlockValue or list of Operations to analyze |
bindings | dict[str, Any] | None | Optional 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) # 1Example 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 ResourceEstimateComprehensive 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(),
) -> NoneAttributes¶
gates: GateCountparameters: dict[str, sp.Symbol]qubits: sp.Expr
Methods¶
simplify¶
def simplify(self) -> ResourceEstimateSimplify all SymPy expressions.
Returns:
ResourceEstimate — New ResourceEstimate with simplified expressions
substitute¶
def substitute(self, **values: int | float = {}) -> ResourceEstimateSubstitute concrete values for parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
**values | int | float | Parameter 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¶
| Function | Description |
|---|---|
estimate_qaoa | Estimate resources for QAOA circuit. |
estimate_qdrift | Estimate resources for qDRIFT Hamiltonian simulation. |
estimate_qpe | Estimate resources for Quantum Phase Estimation. |
estimate_qsvt | Estimate resources for QSVT-based Hamiltonian simulation. |
estimate_trotter | Estimate 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',
) -> ResourceEstimateEstimate resources for QAOA circuit.
QAOA alternates between cost and mixer unitaries for p layers. For Ising/QUBO problems:
Cost layer: RZZ gates on edges (controlled-Z rotations)
Mixer layer: RX gates on all qubits
Based on standard QAOA formulation (Farhi et al. 2014).
Parameters:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits (problem size) |
p | sp.Expr | int | Number of QAOA layers |
num_edges | sp.Expr | int | Number of edges in problem graph (for cost Hamiltonian) |
mixer_type | str | Type 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) # 195References:
Farhi et al. “A Quantum Approximate Optimization Algorithm” arXiv:1411.4028
Section 20 of arXiv:2310.03011v2 for variational algorithms
estimate_qdrift [source]¶
def estimate_qdrift(
L: sp.Expr | int,
hamiltonian_1norm: sp.Expr | float,
time: sp.Expr | float,
error: sp.Expr | float,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
L | sp.Expr | int | Number of terms in Hamiltonian |
hamiltonian_1norm | sp.Expr | float | ||H||_1 = Σ|coefficients| |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target 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:
Section 11.2 of arXiv:2310.03011v2
Campbell arXiv:1811.08017: qDRIFT algorithm
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',
) -> ResourceEstimateEstimate resources for Quantum Phase Estimation.
QPE estimates the eigenvalue of a unitary operator U = e^(iHt). Two main approaches:
Trotter-based: Approximate e^(iHt) using Trotter formulas
Qubitization: Use block-encoding with quantum walk operator
Parameters:
| Name | Type | Description |
|---|---|---|
n_system | sp.Expr | int | Number of system qubits (qubits in the state being analyzed) |
precision | sp.Expr | int | Number of bits of precision in phase estimate (ε = 2^(-precision)) |
hamiltonian_norm | sp.Expr | float | None | Normalization ||H|| for block-encoding (required for qubitization) |
method | str | “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:
Nielsen & Chuang, Section 5.2: Original QPE
Section 13 of arXiv:2310.03011v2: Modern variants
Low & Chuang arXiv:1610.06546: Qubitization-based QPE
estimate_qsvt [source]¶
def estimate_qsvt(
n: sp.Expr | int,
hamiltonian_norm: sp.Expr | float,
time: sp.Expr | float,
error: sp.Expr | float,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits |
hamiltonian_norm | sp.Expr | float | α where ||H|| ≤ α (block-encoding normalization) |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target 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:
Section 11.4 of arXiv:2310.03011v2
Low & Chuang arXiv:1610.06546: QSVT framework
Gilyen et al. arXiv:1806.01838: QSP/QSVT
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,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits |
L | sp.Expr | int | Number of terms in Hamiltonian decomposition |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target error ε |
order | int | Trotter order (2, 4, 6, ...). Higher order = fewer steps but more complex |
hamiltonian_1norm | sp.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:
Section 11.1 of arXiv:2310.03011v2
Childs et al. arXiv:1912.08854: Improved Trotter bounds
qamomile.circuit.estimator.algorithmic.hamiltonian_simulation¶
Theoretical resource estimates for Hamiltonian simulation.
Provides estimates for multiple simulation methods:
Product formulas (Trotter/Suzuki)
qDRIFT
QSVT/QSP-based methods
Based on Section 11 of arXiv:2310.03011v2.
Overview¶
| Function | Description |
|---|---|
estimate_qdrift | Estimate resources for qDRIFT Hamiltonian simulation. |
estimate_qsvt | Estimate resources for QSVT-based Hamiltonian simulation. |
estimate_trotter | Estimate resources for Trotter/Suzuki formula Hamiltonian simulation. |
| Class | Description |
|---|---|
ResourceEstimate | Comprehensive 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,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
L | sp.Expr | int | Number of terms in Hamiltonian |
hamiltonian_1norm | sp.Expr | float | ||H||_1 = Σ|coefficients| |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target 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:
Section 11.2 of arXiv:2310.03011v2
Campbell arXiv:1811.08017: qDRIFT algorithm
estimate_qsvt [source]¶
def estimate_qsvt(
n: sp.Expr | int,
hamiltonian_norm: sp.Expr | float,
time: sp.Expr | float,
error: sp.Expr | float,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits |
hamiltonian_norm | sp.Expr | float | α where ||H|| ≤ α (block-encoding normalization) |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target 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:
Section 11.4 of arXiv:2310.03011v2
Low & Chuang arXiv:1610.06546: QSVT framework
Gilyen et al. arXiv:1806.01838: QSP/QSVT
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,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits |
L | sp.Expr | int | Number of terms in Hamiltonian decomposition |
time | sp.Expr | float | Evolution time t |
error | sp.Expr | float | Target error ε |
order | int | Trotter order (2, 4, 6, ...). Higher order = fewer steps but more complex |
hamiltonian_1norm | sp.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:
Section 11.1 of arXiv:2310.03011v2
Childs et al. arXiv:1912.08854: Improved Trotter bounds
Classes¶
ResourceEstimate [source]¶
class ResourceEstimateComprehensive 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(),
) -> NoneAttributes¶
gates: GateCountparameters: dict[str, sp.Symbol]qubits: sp.Expr
Methods¶
simplify¶
def simplify(self) -> ResourceEstimateSimplify all SymPy expressions.
Returns:
ResourceEstimate — New ResourceEstimate with simplified expressions
substitute¶
def substitute(self, **values: int | float = {}) -> ResourceEstimateSubstitute concrete values for parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
**values | int | float | Parameter 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¶
| Function | Description |
|---|---|
estimate_qaoa | Estimate resources for QAOA circuit. |
estimate_qaoa_ising | Estimate resources for QAOA on Ising model. |
| Class | Description |
|---|---|
ResourceEstimate | Comprehensive 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',
) -> ResourceEstimateEstimate resources for QAOA circuit.
QAOA alternates between cost and mixer unitaries for p layers. For Ising/QUBO problems:
Cost layer: RZZ gates on edges (controlled-Z rotations)
Mixer layer: RX gates on all qubits
Based on standard QAOA formulation (Farhi et al. 2014).
Parameters:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits (problem size) |
p | sp.Expr | int | Number of QAOA layers |
num_edges | sp.Expr | int | Number of edges in problem graph (for cost Hamiltonian) |
mixer_type | str | Type 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) # 195References:
Farhi et al. “A Quantum Approximate Optimization Algorithm” arXiv:1411.4028
Section 20 of arXiv:2310.03011v2 for variational algorithms
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,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | int | Number of qubits |
p | sp.Expr | int | Number of QAOA layers |
quadratic_terms | sp.Expr | int | Number of J_ij terms (edges in interaction graph) |
linear_terms | sp.Expr | int | None | Number 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/2Classes¶
ResourceEstimate [source]¶
class ResourceEstimateComprehensive 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(),
) -> NoneAttributes¶
gates: GateCountparameters: dict[str, sp.Symbol]qubits: sp.Expr
Methods¶
simplify¶
def simplify(self) -> ResourceEstimateSimplify all SymPy expressions.
Returns:
ResourceEstimate — New ResourceEstimate with simplified expressions
substitute¶
def substitute(self, **values: int | float = {}) -> ResourceEstimateSubstitute concrete values for parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
**values | int | float | Parameter 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¶
| Function | Description |
|---|---|
estimate_eigenvalue_filtering | Estimate resources for eigenstate filtering (QSVT-based). |
estimate_qpe | Estimate resources for Quantum Phase Estimation. |
| Class | Description |
|---|---|
ResourceEstimate | Comprehensive 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,
) -> ResourceEstimateEstimate 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:
| Name | Type | Description |
|---|---|---|
n_system | sp.Expr | int | Number of system qubits |
target_overlap | sp.Expr | float | Desired overlap γ with target eigenstate |
gap | sp.Expr | float | None | Spectral 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:
Lin & Tong arXiv:1910.14596: Eigenstate filtering via QSVT
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',
) -> ResourceEstimateEstimate resources for Quantum Phase Estimation.
QPE estimates the eigenvalue of a unitary operator U = e^(iHt). Two main approaches:
Trotter-based: Approximate e^(iHt) using Trotter formulas
Qubitization: Use block-encoding with quantum walk operator
Parameters:
| Name | Type | Description |
|---|---|---|
n_system | sp.Expr | int | Number of system qubits (qubits in the state being analyzed) |
precision | sp.Expr | int | Number of bits of precision in phase estimate (ε = 2^(-precision)) |
hamiltonian_norm | sp.Expr | float | None | Normalization ||H|| for block-encoding (required for qubitization) |
method | str | “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:
Nielsen & Chuang, Section 5.2: Original QPE
Section 13 of arXiv:2310.03011v2: Modern variants
Low & Chuang arXiv:1610.06546: Qubitization-based QPE
Classes¶
ResourceEstimate [source]¶
class ResourceEstimateComprehensive 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(),
) -> NoneAttributes¶
gates: GateCountparameters: dict[str, sp.Symbol]qubits: sp.Expr
Methods¶
simplify¶
def simplify(self) -> ResourceEstimateSimplify all SymPy expressions.
Returns:
ResourceEstimate — New ResourceEstimate with simplified expressions
substitute¶
def substitute(self, **values: int | float = {}) -> ResourceEstimateSubstitute concrete values for parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
**values | int | float | Parameter 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¶
| Function | Description |
|---|---|
build_for_items_scope | Build child resolver for a ForItemsOperation body. |
build_for_loop_scope | Build child resolver and resolved bounds for a ForOperation. |
build_if_scopes | Build child resolvers for both branches of an IfOperation. |
build_while_scope | Build child resolver and trip-count symbol for a WhileOperation. |
classify_controlled_u | Classify a ControlledUOperation (opaque gate, total=1). |
classify_gate | Classify a single GateOperation into a GateCount. |
count_gates | Count gates in a quantum circuit. |
extract_gate_count_from_metadata | Extract GateCount from ResourceMetadata. |
qft_iqft_gate_count | Gate count for QFT or IQFT on n qubits. |
resolve_composite_gate | Resolve a CompositeGateOperation to its resource source. |
resolve_controlled_u | Resolve a ControlledUOperation to (num_controls, num_targets). |
resolve_for_items_cardinality | Return the symbolic cardinality |dict_name| for a ForItems loop. |
symbolic_iterations | Compute the number of iterations of range(start, stop, step). |
| Class | Description |
|---|---|
BlockValue | Represents a subroutine as a function block. |
CallBlockOperation | |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
ControlledUOperation | Controlled-U operation that applies a unitary block conditionally. |
ExprResolver | Single source of truth for converting IR Values to SymPy expressions. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
GateCount | Gate count breakdown for a quantum circuit. |
GateOperation | |
IfOperation | Represents an if-else conditional operation. |
Operation | |
WhileOperation | Represents a while loop operation. |
Functions¶
build_for_items_scope [source]¶
def build_for_items_scope(op: ForItemsOperation, resolver: ExprResolver) -> ExprResolverBuild child resolver for a ForItemsOperation body.
Parameters:
| Name | Type | Description |
|---|---|---|
op | ForItemsOperation | The for-items loop operation. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | ForOperation | The for-loop operation. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | Any | An IfOperation with true_operations and false_operations attributes. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | Any | A WhileOperation with an operations attribute. |
resolver | ExprResolver | Resolver 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) -> GateCountClassify 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:
| Name | Type | Description |
|---|---|---|
nc | int | sp.Expr | Number of control qubits (concrete or symbolic). |
num_targets | int | Number 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) -> GateCountClassify 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]) -> GateCountCount 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:
GateOperation: Single gate counts
ForOperation: Multiplies inner count by iterations
IfOperation: Takes maximum of branches
CallBlockOperation: Recursively counts called blocks
ControlledUOperation: Counts as a single opaque gate
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | 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) -> GateCountExtract 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:
| Name | Type | Description |
|---|---|---|
meta | ResourceMetadata | Metadata 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) -> GateCountGate count for QFT or IQFT on n qubits.
QFT = n H + n(n-1)/2 CP + n//2 SWAP
Parameters:
| Name | Type | Description |
|---|---|---|
n | sp.Expr | Number 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) -> CompositeGateResolutionResolve a CompositeGateOperation to its resource source.
Priority (deterministic, not fallback):
resource_metadata— always preferred when presentimplementation(has_implementation + BlockValue)Known formula (QFT / IQFT)
Error — no resource info available
Parameters:
| Name | Type | Description |
|---|---|---|
op | CompositeGateOperation | The operation to resolve. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | ControlledUOperation | The operation to resolve. |
resolver | ExprResolver | Resolver 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.ExprReturn the symbolic cardinality |dict_name| for a ForItems loop.
Parameters:
| Name | Type | Description |
|---|---|---|
op | ForItemsOperation | The 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.ExprCompute 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:
| Name | Type | Description |
|---|---|---|
start | sp.Expr | Symbolic start bound. |
stop | sp.Expr | Symbolic stop bound. |
step | sp.Expr | Symbolic step bound. |
Returns:
sp.Expr — sp.Expr: Symbolic iteration count Max(0, ceiling((stop - start) / step)).
Raises:
ValueError— If step is a concrete zero.
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(),
) -> NoneAttributes¶
input_values: list[Value]label_args: list[str]name: stroperations: list[Operation]return_values: list[Value]type: BlockType
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()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
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:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure depends on has_implementation:
If has_implementation=True:
operands[0]: BlockValue (the implementation)
operands[1:1+num_control_qubits]: Control qubits (if any)
operands[1+num_control_qubits:1+num_control_qubits+num_target_qubits]: Target qubits
operands[1+num_control_qubits+num_target_qubits:]: Parameters
If has_implementation=False (stub):
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
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,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: ‘BlockValue | None’ Get the implementation BlockValue, if any.name: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Controlled-U operation that applies a unitary block conditionally.
The operands structure is:
operands[0]: BlockValue (the unitary U to apply)
operands[1:1+num_controls]: Control qubits
operands[1+num_controls:]: Target qubits (arguments to U)
The results structure is:
results[0:num_controls]: Control qubits (returned)
results[num_controls:]: Target qubits (returned from U)
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,
) -> NoneAttributes¶
blockGet the BlockValue (unitary U).control_operandsGet the control qubit values.controlled_indices: list[Value] | Nonehas_index_spec: bool Whether target/control positions are specified via index lists.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete (int).num_controls: int | Valueoperation_kind: OperationKindparam_operandsGet parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_indices: list[Value] | Nonetarget_operandsGet the target qubit values (arguments to U).
ExprResolver [source]¶
class ExprResolverSingle source of truth for converting IR Values to SymPy expressions.
Resolution strategy (deterministic, single path):
Already sp.Basic → return as-is
Not a Value (int, float, bool) → direct conversion
UUID in context (call_context / BinOp) → return mapped expression
Constant value → sp.Integer / sp.Float
Unbound parameter → sp.Symbol (symbolic) or raise (concrete)
Loop variable (name-based) → return mapped symbol
BinOp/CompOp result → trace in block operations
Search parent blocks → trace in ancestors
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:
| Name | Type | Description |
|---|---|---|
block | Any | The current block (BlockValue or _LocalBlock) whose operations are searched for BinOp/CompOp traces. |
context | dict[str, sp.Expr] | None | UUID → resolved expression mapping for values passed across scope boundaries (e.g. call arguments, composite-gate operands). |
loop_var_names | dict[str, sp.Symbol] | None | Value name → SymPy symbol mapping for loop variables in scope. |
parent_blocks | list[Any] | None | Ancestor blocks to search when tracing fails in the current block. |
Attributes¶
block: Any The current block being resolved against.context: dict[str, sp.Expr] Copy of the UUID → expression context mapping.loop_var_names: dict[str, sp.Symbol] Copy of the loop variable name → symbol mapping.
Methods¶
call_child_scope¶
def call_child_scope(self, call_op: Any) -> ExprResolverCreate 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:
| Name | Type | Description |
|---|---|---|
call_op | Any | A 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,
) -> ExprResolverCreate 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:
| Name | Type | Description |
|---|---|---|
inner_block | Any | The block for the child scope. |
extra_context | dict[str, sp.Expr] | None | Additional UUID → expression mappings to merge into the child context. |
extra_loop_vars | dict[str, sp.Symbol] | None | Additional 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.ExprConvert IR Value to SymPy expression (symbolic mode).
Unbound parameters become sp.Symbol. Never raises for valid IR.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Any | IR Value, primitive Python type, or sp.Basic. |
Returns:
sp.Expr — sp.Expr: Resolved SymPy expression.
resolve_concrete¶
def resolve_concrete(self, v: Any) -> intConvert IR Value to concrete int.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Any | IR Value, primitive Python type, or sp.Basic. |
Returns:
int — The resolved concrete integer.
Raises:
UnresolvedValueError— If the value is symbolic.
ForItemsOperation [source]¶
class ForItemsOperation(Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
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(),
) -> NoneAttributes¶
key_is_vector: boolkey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: str
ForOperation [source]¶
class ForOperation(Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: stroperation_kind: OperationKindoperations: list[Operation]signature: Signature
GateCount [source]¶
class GateCountGate 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(),
) -> NoneAttributes¶
clifford_gates: sp.Exprmulti_qubit: sp.Exproracle_calls: dict[str, sp.Expr]oracle_queries: dict[str, sp.Expr]rotation_gates: sp.Exprsingle_qubit: sp.Exprt_gates: sp.Exprtotal: sp.Exprtwo_qubit: sp.Expr
Methods¶
max¶
def max(self, other: GateCount) -> GateCountElement-wise maximum of two gate counts.
Parameters:
| Name | Type | Description |
|---|---|---|
other | GateCount | The 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) -> GateCountSimplify all SymPy expressions.
Returns:
GateCount — New instance with sp.simplify and
_strip_nonneg_max applied to every field.
zero¶
@staticmethod
def zero() -> GateCountReturn 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,
) -> NoneAttributes¶
gate_type: GateOperationType | Noneoperation_kind: OperationKindsignature: Signaturetheta: float | Value | None
IfOperation [source]¶
class IfOperation(Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
true_operations: list[Operation] = list(),
false_operations: list[Operation] = list(),
phi_ops: list[PhiOp] = list(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Operation [source]¶
class Operation(abc.ABC)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operands: list[Value]operation_kind: OperationKind Return the kind of this operation for classical/quantum classification.results: list[Value]signature: Signature
WhileOperation [source]¶
class WhileOperation(Operation)Represents a while loop operation.
Only measurement-backed conditions are supported: the condition must
be a Bit value produced by qmc.measure(). Non-measurement
conditions (classical variables, constants, comparisons) are rejected
by ValidateWhileContractPass before reaching backend emit.
Example::
bit = qmc.measure(q)
while bit:
q = qmc.h(q)
bit = qmc.measure(q)Constructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
operations: list[Operation] = list(),
) -> NoneAttributes¶
operation_kind: OperationKindoperations: list[Operation]signature: Signature
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¶
| Function | Description |
|---|---|
build_for_items_scope | Build child resolver for a ForItemsOperation body. |
build_for_loop_scope | Build child resolver and resolved bounds for a ForOperation. |
build_if_scopes | Build child resolvers for both branches of an IfOperation. |
build_while_scope | Build child resolver and trip-count symbol for a WhileOperation. |
qubits_counter | Count the number of qubits required by a BlockValue. |
resolve_for_items_cardinality | Return the symbolic cardinality |dict_name| for a ForItems loop. |
symbolic_iterations | Compute the number of iterations of range(start, stop, step). |
| Class | Description |
|---|---|
ArrayValue | An array of values with shape information. |
BlockValue | Represents a subroutine as a function block. |
CallBlockOperation | |
CompositeGateOperation | Represents a composite gate (QPE, QFT, etc.) as a single operation. |
ControlledUOperation | Controlled-U operation that applies a unitary block conditionally. |
ExprResolver | Single source of truth for converting IR Values to SymPy expressions. |
ForItemsOperation | Represents iteration over dict/iterable items. |
ForOperation | Represents a for loop operation. |
IfOperation | Represents an if-else conditional operation. |
Operation | |
QInitOperation | Initialize the qubit |
QubitType | Type representing a quantum bit (qubit). |
WhileOperation | Represents a while loop operation. |
Functions¶
build_for_items_scope [source]¶
def build_for_items_scope(op: ForItemsOperation, resolver: ExprResolver) -> ExprResolverBuild child resolver for a ForItemsOperation body.
Parameters:
| Name | Type | Description |
|---|---|---|
op | ForItemsOperation | The for-items loop operation. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | ForOperation | The for-loop operation. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | Any | An IfOperation with true_operations and false_operations attributes. |
resolver | ExprResolver | Resolver 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:
| Name | Type | Description |
|---|---|---|
op | Any | A WhileOperation with an operations attribute. |
resolver | ExprResolver | Resolver 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.ExprCount 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:
QInitOperation: Counts single qubits and qubit arrays
ForOperation/WhileOperation: Counts inner resources (assumes uncomputation)
IfOperation: Takes the maximum of both branches
CallBlockOperation: Recursively counts called blocks
ControlledUOperation: Recursively counts the unitary block
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | 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 nresolve_for_items_cardinality [source]¶
def resolve_for_items_cardinality(op: ForItemsOperation) -> sp.ExprReturn the symbolic cardinality |dict_name| for a ForItems loop.
Parameters:
| Name | Type | Description |
|---|---|---|
op | ForItemsOperation | The 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.ExprCompute 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:
| Name | Type | Description |
|---|---|---|
start | sp.Expr | Symbolic start bound. |
stop | sp.Expr | Symbolic stop bound. |
step | sp.Expr | Symbolic step bound. |
Returns:
sp.Expr — sp.Expr: Symbolic iteration count Max(0, ceiling((stop - start) / step)).
Raises:
ValueError— If step is a concrete zero.
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(),
) -> NoneAttributes¶
logical_id: strname: strparams: dict[str, Any]shape: tuple[Value, ...]type: Tuuid: str
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(),
) -> NoneAttributes¶
input_values: list[Value]label_args: list[str]name: stroperations: list[Operation]return_values: list[Value]type: BlockType
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()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
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:
Resource estimation without full implementation
Backend-native conversion (e.g., Qiskit’s QPE)
User-defined complex gates
The operands structure depends on has_implementation:
If has_implementation=True:
operands[0]: BlockValue (the implementation)
operands[1:1+num_control_qubits]: Control qubits (if any)
operands[1+num_control_qubits:1+num_control_qubits+num_target_qubits]: Target qubits
operands[1+num_control_qubits+num_target_qubits:]: Parameters
If has_implementation=False (stub):
operands[0:num_control_qubits]: Control qubits (if any)
operands[num_control_qubits:num_control_qubits+num_target_qubits]: Target qubits
operands[num_control_qubits+num_target_qubits:]: Parameters
The results structure:
results[0:num_control_qubits]: Control qubits (returned)
results[num_control_qubits:]: Target qubits (returned)
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,
) -> NoneAttributes¶
composite_gate_instance: Anycontrol_qubits: list[‘Value’] Get the control qubit operands.custom_name: strgate_type: CompositeGateTypehas_implementation: boolimplementation: ‘BlockValue | None’ Get the implementation BlockValue, if any.name: str Human-readable name of this composite gate.num_control_qubits: intnum_target_qubits: intoperation_kind: OperationKind Return the operation kind (always QUANTUM).parameters: list[‘Value’] Get the parameter operands (angles, etc.).resource_metadata: ResourceMetadata | Nonesignature: Signature Return the operation signature.strategy_name: str | Nonetarget_qubits: list[‘Value’] Get the target qubit operands.
ControlledUOperation [source]¶
class ControlledUOperation(Operation)Controlled-U operation that applies a unitary block conditionally.
The operands structure is:
operands[0]: BlockValue (the unitary U to apply)
operands[1:1+num_controls]: Control qubits
operands[1+num_controls:]: Target qubits (arguments to U)
The results structure is:
results[0:num_controls]: Control qubits (returned)
results[num_controls:]: Target qubits (returned from U)
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,
) -> NoneAttributes¶
blockGet the BlockValue (unitary U).control_operandsGet the control qubit values.controlled_indices: list[Value] | Nonehas_index_spec: bool Whether target/control positions are specified via index lists.is_symbolic_num_controls: bool Whether num_controls is symbolic (Value) rather than concrete (int).num_controls: int | Valueoperation_kind: OperationKindparam_operandsGet parameter operands (non-qubit, non-block).power: int | Valuesignature: Signaturetarget_indices: list[Value] | Nonetarget_operandsGet the target qubit values (arguments to U).
ExprResolver [source]¶
class ExprResolverSingle source of truth for converting IR Values to SymPy expressions.
Resolution strategy (deterministic, single path):
Already sp.Basic → return as-is
Not a Value (int, float, bool) → direct conversion
UUID in context (call_context / BinOp) → return mapped expression
Constant value → sp.Integer / sp.Float
Unbound parameter → sp.Symbol (symbolic) or raise (concrete)
Loop variable (name-based) → return mapped symbol
BinOp/CompOp result → trace in block operations
Search parent blocks → trace in ancestors
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:
| Name | Type | Description |
|---|---|---|
block | Any | The current block (BlockValue or _LocalBlock) whose operations are searched for BinOp/CompOp traces. |
context | dict[str, sp.Expr] | None | UUID → resolved expression mapping for values passed across scope boundaries (e.g. call arguments, composite-gate operands). |
loop_var_names | dict[str, sp.Symbol] | None | Value name → SymPy symbol mapping for loop variables in scope. |
parent_blocks | list[Any] | None | Ancestor blocks to search when tracing fails in the current block. |
Attributes¶
block: Any The current block being resolved against.context: dict[str, sp.Expr] Copy of the UUID → expression context mapping.loop_var_names: dict[str, sp.Symbol] Copy of the loop variable name → symbol mapping.
Methods¶
call_child_scope¶
def call_child_scope(self, call_op: Any) -> ExprResolverCreate 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:
| Name | Type | Description |
|---|---|---|
call_op | Any | A 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,
) -> ExprResolverCreate 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:
| Name | Type | Description |
|---|---|---|
inner_block | Any | The block for the child scope. |
extra_context | dict[str, sp.Expr] | None | Additional UUID → expression mappings to merge into the child context. |
extra_loop_vars | dict[str, sp.Symbol] | None | Additional 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.ExprConvert IR Value to SymPy expression (symbolic mode).
Unbound parameters become sp.Symbol. Never raises for valid IR.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Any | IR Value, primitive Python type, or sp.Basic. |
Returns:
sp.Expr — sp.Expr: Resolved SymPy expression.
resolve_concrete¶
def resolve_concrete(self, v: Any) -> intConvert IR Value to concrete int.
Parameters:
| Name | Type | Description |
|---|---|---|
v | Any | IR Value, primitive Python type, or sp.Basic. |
Returns:
int — The resolved concrete integer.
Raises:
UnresolvedValueError— If the value is symbolic.
ForItemsOperation [source]¶
class ForItemsOperation(Operation)Represents iteration over dict/iterable items.
Example:
for (i, j), Jij in qmc.items(ising):
bodyConstructor¶
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(),
) -> NoneAttributes¶
key_is_vector: boolkey_vars: list[str]operation_kind: OperationKindoperations: list[Operation]signature: Signaturevalue_var: str
ForOperation [source]¶
class ForOperation(Operation)Represents a for loop operation.
Example:
for i in range(start, stop, step):
bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
loop_var: str = '',
operations: list[Operation] = list(),
) -> NoneAttributes¶
loop_var: stroperation_kind: OperationKindoperations: list[Operation]signature: Signature
IfOperation [source]¶
class IfOperation(Operation)Represents an if-else conditional operation.
Example:
if condition:
true_body
else:
false_bodyConstructor¶
def __init__(
self,
operands: list[Value] = list(),
results: list[Value] = list(),
true_operations: list[Operation] = list(),
false_operations: list[Operation] = list(),
phi_ops: list[PhiOp] = list(),
) -> NoneAttributes¶
condition: Valuefalse_operations: list[Operation]operation_kind: OperationKindphi_ops: list[PhiOp]signature: Signaturetrue_operations: list[Operation]
Operation [source]¶
class Operation(abc.ABC)Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operands: list[Value]operation_kind: OperationKind Return the kind of this operation for classical/quantum classification.results: list[Value]signature: Signature
QInitOperation [source]¶
class QInitOperation(Operation)Initialize the qubit
Constructor¶
def __init__(self, operands: list[Value] = list(), results: list[Value] = list()) -> NoneAttributes¶
operation_kind: OperationKindsignature: Signature
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(),
) -> NoneAttributes¶
operation_kind: OperationKindoperations: list[Operation]signature: Signature
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¶
| Function | Description |
|---|---|
count_gates | Count gates in a quantum circuit. |
estimate_resources | Estimate all resources for a quantum circuit. |
qubits_counter | Count the number of qubits required by a BlockValue. |
| Class | Description |
|---|---|
BlockValue | Represents a subroutine as a function block. |
Operation | |
ResourceEstimate | Comprehensive resource estimate for a quantum circuit. |
Functions¶
count_gates [source]¶
def count_gates(block: BlockValue | list[Operation]) -> GateCountCount 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:
GateOperation: Single gate counts
ForOperation: Multiplies inner count by iterations
IfOperation: Takes maximum of branches
CallBlockOperation: Recursively counts called blocks
ControlledUOperation: Counts as a single opaque gate
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | 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,
) -> ResourceEstimateEstimate all resources for a quantum circuit.
This is the main entry point for comprehensive resource estimation. Combines qubit counting and gate counting.
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | list[Operation] | BlockValue or list of Operations to analyze |
bindings | dict[str, Any] | None | Optional 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) # 1Example 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.ExprCount 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:
QInitOperation: Counts single qubits and qubit arrays
ForOperation/WhileOperation: Counts inner resources (assumes uncomputation)
IfOperation: Takes the maximum of both branches
CallBlockOperation: Recursively counts called blocks
ControlledUOperation: Recursively counts the unitary block
Parameters:
| Name | Type | Description |
|---|---|---|
block | BlockValue | 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 nClasses¶
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(),
) -> NoneAttributes¶
input_values: list[Value]label_args: list[str]name: stroperations: list[Operation]return_values: list[Value]type: BlockType
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()) -> NoneAttributes¶
operands: list[Value]operation_kind: OperationKind Return the kind of this operation for classical/quantum classification.results: list[Value]signature: Signature
ResourceEstimate [source]¶
class ResourceEstimateComprehensive 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(),
) -> NoneAttributes¶
gates: GateCountparameters: dict[str, sp.Symbol]qubits: sp.Expr
Methods¶
simplify¶
def simplify(self) -> ResourceEstimateSimplify all SymPy expressions.
Returns:
ResourceEstimate — New ResourceEstimate with simplified expressions
substitute¶
def substitute(self, **values: int | float = {}) -> ResourceEstimateSubstitute concrete values for parameters.
Parameters:
| Name | Type | Description |
|---|---|---|
**values | int | float | Parameter 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))