Skip to content

Resource estimates

Count the qubits, gates, depth, measurements and memory of a planned computation before running it, and read each count with its label. The Estimate resources guide explains the counting rules, and Estimate fault-tolerant resources covers compiled Clifford+T counts and physical projections.

import nwqlib
from nwqlib.resources import ResourceContext

nwqlib.estimate(plan) returns a WorkloadEstimate with one quantity per metric and location. Read one with quantity:

import nwqlib
from nwqlib import Eigenproblem
from nwqlib.algorithms import Lanczos
from nwqlib.resources import ResourceContext

problem = Eigenproblem(A=[[1.5, -1], [-1, 0.5]])
method = Lanczos(initial_state=[1, 0], krylov_dimension=2)
selected = nwqlib.plan(problem, method=method, seed=7)
workload = nwqlib.estimate(selected, context=ResourceContext(basis="cx"))

cx = workload.quantity("cx")
width = workload.quantity("logical_width", location="logical_device")
operations = workload.quantity("operations")
print(cx.interpretation, cx.fact.value.numerator, cx.fact.unit.symbol)
print(width.interpretation, width.fact.value.numerator)
print(operations.interpretation)
upper_bound 3 count
exact 2
unavailable

The Plan uses at most 3 CX gates and exactly 2 qubits. No rule of its circuit blocks gives a total operation count in this basis, so that count is unavailable rather than zero, and operations.fact.reason says why. print(workload) lists every quantity with its label and conditions. Each quantity also keeps its evidence, the kind of basis of the cost rules it came from, for example a proof, a numerical estimate, an observation or an assertion.

An estimate describes the planned logical circuit. It is not a count of compiled gates, which Prepared.inspect_resources gives for a prepared circuit, and it includes no routing, error correction or provider billing.

Estimate a plan

estimate

estimate(construction: SelectedConstruction, *, context: ResourceContext | None = None, memo: dict | None = None) -> WorkloadEstimate

Estimate the resources of a planned circuit description without building or running it.

Most callers use nwqlib.estimate(plan), which calls this function on plan.construction. The estimate walks the circuit description once per distinct context and keeps symbolic costs in a compact expression table. It reads no numerical input data, synthesizes no gates and does not unroll repeated parts. Its work is limited in proportion to the size checks of the circuit description (engineering constants).

The result depends only on the construction and the context. A caller that estimates several points of one Plan can pass one memo dictionary for the duration of its operation, and an equal pair of construction and context then returns the estimate already computed. The memo dictionary belongs to that caller, and there is no process-wide cache.

Parameters:

  • construction (SelectedConstruction) –

    The planned circuit description, plan.construction.

  • context (ResourceContext | None, default: None ) –

    Gate basis, rotation precision, synthesis, resident data and batch schedule. None, the default, means ResourceContext(): the "selected_logical" basis, no resident data and an unspecified schedule.

  • memo (dict | None, default: None ) –

    Optional dictionary owned by the caller, mapping (construction.content_id, context.content_id) to the estimate already computed for that pair.

Returns:

  • workload ( WorkloadEstimate ) –

    One quantity per metric and location. Every quantity is "planned" and keeps its label, location and original evidence. A metric without an applicable cost rule is present as unavailable, not as zero.

WorkloadEstimate

Bases: Record

Resource estimate of a planned computation: one quantity per metric and location.

nwqlib.estimate(plan) returns it when no device profile is given, and so does estimate. Read one metric with quantity(metric), or a width or byte peak with quantity(metric, location=...), and list everything with quantities or print(workload). A metric without a cost rule is present and labeled unavailable, never zero. The estimate is of the logical circuit description, before compilation, routing or error correction.

exact_evaluations counts grouped exact-statistic requests, not returned labels, bins or simulator trajectories. A circuit with no terminal measurement batch declares no measurements, so zero shots and settings there do not mean that running it is free. The fields below are read-only.

Attributes:

  • construction_id (ContentID) –

    Content hash of the planned circuit description that was estimated.

  • context (ResourceContext) –

    The ResourceContext that fixed basis, precision, synthesis and schedule.

  • quantities (tuple[ResourceQuantity, ...]) –

    One ResourceQuantity per (metric, location), including unavailable ones.

  • expressions (tuple[Expression, ...]) –

    Symbolic cost expressions that symbolic quantities name. Repeats and shared parts are not expanded.

  • parameters (tuple[Parameter, ...]) –

    Circuit parameters those expressions may use.

  • sources (tuple[Evidence, ...]) –

    The original evidence records of the cost rules. The arithmetic of the estimate does not make them verified.

  • defined_selections (tuple[ContentID, ...]) –

    Content hashes of the circuit blocks and classical kernels the run may reach, not a record of built circuits.

  • work_units (NonnegativeInt) –

    Bookkeeping work of the estimate, not run time, at most 24 * limits.max_steps.

  • evaluated_contexts (NonnegativeInt) –

    Distinct node and call contexts evaluated.

  • limits (AdmissionLimits) –

    The size limits of the planned circuit description.

  • assumptions (tuple[Text, ...]) –

    Conditions of the whole estimate, such as "logical dependency schedule; no physical QEC/routing/factory projection".

Examples:

A two-dimensional Lanczos Plan, estimated in the CX basis, has an exact width of two qubits and an upper bound of three CX gates. No rule gives its total operation count:

>>> import nwqlib
>>> from nwqlib import Eigenproblem
>>> from nwqlib.algorithms import Lanczos
>>> from nwqlib.resources import ResourceContext
>>> problem = Eigenproblem(A=[[1.5, -1], [-1, 0.5]])
>>> method = Lanczos(initial_state=[1, 0], krylov_dimension=2)
>>> selected = nwqlib.plan(problem, method=method, seed=7)
>>> context = ResourceContext(basis="cx")
>>> workload = nwqlib.estimate(selected, context=context)
>>> cx = workload.quantity("cx")
>>> cx.interpretation, cx.fact.value.numerator
('upper_bound', 3)
>>> width = workload.quantity("logical_width", location="logical_device")
>>> width.interpretation, width.fact.value.numerator
('exact', 2)
>>> workload.quantity("operations").interpretation
'unavailable'

quantity

quantity(metric: str, *, location: str | None = None) -> ResourceQuantity

Return the quantity of one metric at one location, without recomputing anything.

Parameters:

  • metric (str) –

    Metric name, such as "cx" or "logical_width".

  • location (str | None, default: None ) –

    Location of a width or byte peak, for example "logical_device" or "host". None, the default, selects a total.

Returns:

Raises:

  • ValueError –

    If no quantity has this metric and location. The message lists up to eight locations of the metric.

ResourceContext

Bases: Record

Settings that fix how a resource estimate counts: gate basis, rotation precision, synthesis, resident data and schedule.

Build it with keyword arguments, for example ResourceContext(basis="cx"), and pass it as context= to nwqlib.estimate or estimate. Every argument is optional, and ResourceContext() counts in the "selected_logical" basis.

Attributes:

  • basis (MetricBasis) –

    Default "selected_logical". Basis in which gate metrics are counted: "selected_logical", "cx", "clifford_t" or "toffoli". Counts in different bases answer different questions and are never converted into or added to each other.

  • precision (Float64 | None) –

    Default None. Positive rotation synthesis precision. An arbitrary rotation gets a T count only when the precision and the synthesis are known.

  • synthesis (Source | None) –

    Default None. Source naming the synthesis method. A block's ResourceLaw applies only under the same choice.

  • resident (tuple[Workspace, ...]) –

    Default (). Workspace entries that stay in memory for the whole workload and are added to every memory peak.

  • capacities (tuple[Limit, ...]) –

    Default (). Device capacities as Limit records, kept for a later device assessment. The estimate itself allocates nothing and queries no device.

  • batch_schedule (Literal['unspecified', 'serial']) –

    Default "unspecified". "serial" declares that independent circuit batches run one at a time, so a batch memory peak holds without condition. With "unspecified" such a peak is labeled conditional. The required schedule stays recorded for the execution to follow.

Raises:

  • ValueError –

    If precision is not positive.

Read a quantity

Each ResourceQuantity holds its value in fact.value: an exact Rational (read numerator and denominator) or a Float64 (read value). Its interpretation says how to read that value:

interpretation Meaning
exact The exact count
upper_bound The count is at most this value, for example a CX bound before gate cancellation and routing, or the maximum over the arms of a branch
estimate Derived from observed, empirically predicted or numerically estimated evidence
conditional Holds only under a stated condition, such as a memory peak that needs independent circuit batches to run one at a time (required_schedule)
unavailable No applicable rule. fact.reason says why, and the value is never read as zero

An exact count or upper bound is only as strong as its evidence, fact.evidence.kind, so a count derived from an asserted rule stays an assertion. The conditions of a value are in fact.assumptions.

Totals over the whole run have location=None. Widths and memory are peaks at a location, so read them with quantity(metric, location=...):

Metrics Value Unit
Gates: operations, single_qubit, two_qubit, controlled, global_phases, clifford, t, toffoli, ccz, arbitrary_rotations, cx Whole run count
Depths: logical_depth, t_depth, non_clifford_depth Whole run count
Calls and measurement: calls, measurements, resets, settings, shots, exact_evaluations, unique_settings, root_setting_declarations, root_repetitions, adaptive_rounds, expected_operations Whole run count
Work: classical_work, construction_work, preparation_components Whole run count
Qubits: logical_width, system, clean_ancilla, dirty_ancilla at a register's location Peak count
Classical registers: classical_registers, classical_bits at "host" Peak count
Memory: memory, known_memory, input_bytes, analysis_bytes, io_bytes, materialization_bytes, stored_bytes at a workspace's location Peak byte

The Estimate resources guide defines what shots, settings, exact_evaluations and the other measurement counts include.

ResourceQuantity

Bases: Record

One count or peak of a resource estimate, with its value, label and sources.

WorkloadEstimate.quantity returns it. The value is fact.value, an exact Rational (read numerator and denominator) or a Float64, in the unit fact.unit: count, or byte for byte metrics. A symbolic value is fact.symbol, and an unavailable one has fact.reason and no value. interpretation says how to read the value (see Read a quantity). print(quantity) shows the value, label and conditions. The fields below are read-only.

Attributes:

  • metric (Metric) –

    Name of the quantity, such as cx, shots or logical_width.

  • fact (Fact) –

    The value, or the reason it is unavailable, with its unit, scope, conditions (fact.assumptions) and the weakest evidence kind among the sources that determined it.

  • population (Text) –

    What is counted, for example "dynamic workload" for a total over the whole run or "simultaneous live footprint" for a peak.

  • lifecycle (Literal['planned', 'prepared', 'submitted', 'observed']) –

    Workflow stage of the quantity: "planned", "prepared", "submitted" or "observed". A planning estimate gives only "planned".

  • basis (Text) –

    Gate basis of the estimate.

  • interpretation (Interpretation) –

    "exact", "upper_bound", "estimate", "conditional" or "unavailable".

  • location (Text | None) –

    Location of a width or byte peak, None for a total.

  • sources (tuple[ContentID, ...]) –

    Content hashes of all evidence attached to the value, including evidence used only to check a gate recipe against a declared rule.

  • derivation_sources (tuple[ContentID, ...]) –

    Content hashes of the evidence that determined the value, a subset of sources.

  • required_schedule (Literal['serial_acquisitions'] | None) –

    "serial_acquisitions" when this peak holds only if independent circuit batches run one at a time, otherwise None. Follow it before comparing the peak with a device capacity.

Raises:

  • ValueError –

    When a record is loaded whose label disagrees with its availability, whose value is negative, not real or, when exact, not an integer (expected_operations may be fractional), whose unit does not match the metric, or whose derivation sources are not among its sources.

Declare costs and memory

A circuit block declares its own costs and memory with these records. The estimate reads them and creates no allocation.

ResourceLaw

Bases: Record

The cost of one call of a circuit block in one metric, as the block declares it.

A circuit block of a Plan can declare cost rules for its metrics. The estimate uses a rule only for a call whose control and adjoint flags, cost parameters and call arguments, basis, precision and synthesis all match. The value is a number per call, not a formula, so the estimate can check it against a known gate recipe and keep its source without running caller code. Rules in different bases are alternatives, not additions. Build it with keyword arguments when you write a block (see Compose blocks). metric, basis, value, interpretation and evidence are required.

Attributes:

  • metric (Metric) –

    Required. The count metric the rule supplies.

  • basis (MetricBasis) –

    Required. Basis the value is counted in.

  • value (NonnegativeInt | Float64) –

    Required. Nonnegative per-call value, an integer when interpretation is "exact".

  • interpretation (Literal['exact', 'upper_bound', 'estimate']) –

    Required. "exact", "upper_bound" or "estimate".

  • evidence (Evidence) –

    Required. Where the value comes from. Observed, empirically predicted or numerically estimated evidence makes every quantity derived from it an estimate.

  • bindings (tuple[Binding, ...]) –

    Default (). Cost parameters and call arguments that must match exactly for the rule to apply.

  • unbound_parameters (tuple[Text, ...]) –

    Default (). Formal parameters whose whole accepted range the rule covers instead of one value. Empty means exact matching only.

  • controlled (StrictBool) –

    Default False. Whether the rule is for the controlled block.

  • adjoint (StrictBool) –

    Default False. Whether the rule is for the adjoint block.

  • precision (Float64 | None) –

    Default None. Rotation precision the rule assumes.

  • synthesis (Source | None) –

    Default None. Synthesis method the rule assumes.

  • assumptions (tuple[Text, ...]) –

    Default (). Conditions carried into every quantity derived from the rule.

Raises:

  • ValueError –

    If the value is negative, an exact value is not an integer, a binding is repeated, or a parameter is both bound and listed in unbound_parameters.

Workspace

Bases: Record

Bytes needed at the same time at one location, as declared by a block or the caller.

A block's workspace lasts for each call. Entries in ResourceContext.resident last for the whole workload. Sizes are declarations, not observed allocations, and quantum widths are counted separately. Build it with keyword arguments. All four fields are required.

Attributes:

  • location (Text) –

    Where the bytes live, for example "host".

  • purpose (Literal['input', 'preparation', 'analysis', 'io', 'materialization', 'stored', 'workspace']) –

    "input", "preparation", "analysis", "io", "materialization", "stored" or "workspace".

  • bytes (NonnegativeInt | None) –

    Nonnegative byte count, or None when unknown. An unknown size makes the memory peak at that location unavailable, never zero.

  • source (Source) –

    Source of the declaration.