Skip to content

Backends, profiles and export

This page covers the backends that run a Plan's circuits, the device profiles that forecast time and memory before a run, and the functions that export circuits as OpenQASM.

from nwqlib.backends import AerBackend, Allocation, DeviceProfile, assess
from nwqlib.io import export_qasm, write_qasm3_file

Pass a backend as backend= to solve or prepare. Without one, a quantum Plan runs on AerBackend(). The expectation of Z in the state |0> is exactly 1:

from nwqlib import Expectation, solve
from nwqlib.algorithms import ExpectationMethod
from nwqlib.backends import AerBackend

problem = Expectation(state=[1.0, 0.0], observable=[[1.0, 0.0], [0.0, -1.0]])
result = solve(problem, method=ExpectationMethod(), backend=AerBackend(),
               seed=7)
print(result.value)  # 1.0

Choose a backend

Backend Class Readouts Needs Guide
Qiskit Aer, local AerBackend Counts, and exact Pauli expectations, probabilities and amplitudes nwqlib[aer] Aer
NWQ-Sim, local NWQSimBackend Counts. CPU statevector also gives exact Pauli expectations, probabilities and amplitudes A runner built for one backend and method NWQ-Sim
NWQ-Sim on a Slurm cluster NWQSimSlurmBackend with SlurmProfile As NWQ-Sim A runner built at the site and a Slurm account Slurm
IBM Quantum IBMRuntimeBackend Counts and provider expectation estimates nwqlib[ibm] and a saved IBM account or a token in NWQLIB_IBM_RUNTIME_TOKEN IBM Runtime
IonQ QPU IonQBackend Raw counts nwqlib[ionq] and an API key in NWQLIB_IONQ_API_KEY IonQ
Quantinuum H2 through Nexus NexusBackend Counts nwqlib[nexus] and an existing qnexus login Nexus

Every backend except Aer runs jobs that continue after Python exits. Save the Run to a directory and reopen it with load_run, as Continue an interrupted run describes. The cloud and Slurm backends have offline checks only, and each Run states its qualification once. Choose a backend compares them, and Backend adapter contract states the rules every backend implements.

AerBackend

Bases: Record

Local Qiskit Aer simulator, the default backend of prepare and solve.

Build it with AerBackend() for noiseless simulation, or with AerBackend.from_noise_model(model) for a Qiskit Aer noise model, and pass it as backend= to solve or prepare. It needs the aer extra (pip install "nwqlib[aer]") and no credentials. A noise model acts on sampled counts only. An exact expectation, probability or amplitude would describe neither the noiseless circuit nor the noisy samples, so those readouts reject a noisy backend before any circuit is built.

The backend holds the caller's NoiseModel object without copying or serializing it, so keep that model unchanged while this backend or its prepared circuits are in use. Run.save stores the model as the SDK's dictionary with NumPy array files, and load_run binds the rebuilt model to the reopened Run's own copy of this configuration (run.backend), leaving the backend passed to load_run unchanged. revise keeps the bound model while noise_model_id is unchanged. The Aer guide covers readouts, noise and circuit inspection.

Attributes:

  • noise_model_id (Text | None) –

    Default None, no noise model. from_noise_model sets it to a fresh UUID that identifies the binding, not the model's contents. A configuration rebuilt from JSON with this field set holds no model and raises when used.

from_noise_model

from_noise_model(model)

Return an Aer backend that applies a Qiskit Aer noise model to sampled counts.

The model is held without copying, and qiskit_aer is imported only by this call.

Parameters:

  • model (NoiseModel) –

    The noise model to apply.

Returns:

  • backend ( AerBackend ) –

    A new backend whose noise_model_id is a fresh UUID.

Raises:

  • TypeError –

    If model is not a Qiskit Aer NoiseModel.

NWQSimBackend

Bases: Record

NWQ-Sim simulator run locally as a detached process, with statevector or density-matrix simulation.

Build it with keyword arguments, for example NWQSimBackend(executable=..., spool=..., max_input_bytes=..., max_output_bytes=..., max_buffer_bytes=...), and pass it as backend= to prepare. executable, spool and the three byte limits are required. The executable is a runner built for one backend and method pair with python -m nwqlib.backends.nwqsim (see the NWQ-Sim guide). Construction launches and inspects nothing.

Preparation translates each circuit to Qiskit's U and CX gates. The runner keeps running after the Python process exits, so the computer that runs it must stay on until the job finishes. The guide records the qualified NWQ-Sim revision and the byte formulas behind max_buffer_bytes.

Attributes:

  • backend (Literal['CPU', 'MPI', 'NVGPU', 'AMDGPU', 'NVGPU_MPI']) –

    Default "CPU". "CPU", "MPI", "NVGPU" or "AMDGPU". "NVGPU_MPI" is rejected, because its constructors read an uninitialized GPU memory counter in the inspected NWQ-Sim sources.

  • method (Literal['SV', 'DM']) –

    Default "SV". "SV" (statevector) or "DM" (density matrix). "MPI" supports "SV" only, because its factory silently substitutes SV for DM.

  • ranks (PositiveInt) –

    Default 1. Positive. Number of cooperating MPI processes. Only "MPI" accepts more than one, and it requires a power of two.

  • mpi_launcher (Text) –

    Default "mpirun". Installed launcher for local MPI runs.

  • executable (Text) –

    Required. Absolute path of the built runner.

  • spool (Text) –

    Required. Absolute path of the directory for request and result files. It identifies a detached job after Python exits, so it cannot be relative.

  • max_input_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each request file.

  • max_output_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each result file that NWQLib reads.

  • max_buffer_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the known state, work and sample arrays of each process, including host and device storage on a GPU. It excludes fused gates, SDK workspace and whole-process memory.

  • optimization_level (Count) –

    Default 0. Qiskit transpiler level, 0 to 3, of the translation to U and CX gates. A level other than 0 is recorded as the exclusion "optimization_level" in the preparation record, so the record has no certified state error and its error numbers are a reference, and the operation count describes the compiled circuit. Levels 2 and 3 resynthesize two-qubit blocks with Qiskit's own synthesis. At those levels an exact readout or trajectory is refused when transpilation relabels wires by removing permutations, because the runner reads the output in logical wire order, and a measured circuit can still supply computational-basis probabilities when transpilation reports no layout. Amplitude readouts require level 0 or 1, or a circuit without measurements, because removing terminal diagonal gates can change relative phases.

Raises:

  • ValueError –

    If the backend, method and rank combination is not supported, or if executable or spool is not an absolute path.

NWQSimSlurmBackend

Bases: Record

NWQ-Sim run as a Slurm batch job on a cluster.

Build it with keyword arguments, for example NWQSimSlurmBackend(profile=..., accounting_since=..., accounting_until=..., max_input_bytes=..., max_output_bytes=..., max_buffer_bytes=..., max_response_bytes=..., timeout_seconds=...), and pass it as backend= to prepare. Every argument except optimization_level is required. The profile holds the runner, its build and the pending-job directory (spool). Submission calls sbatch once, and a job whose acknowledgement was lost is found again by its job name in Slurm accounting within the configured time window. Only offline scheduler and protocol checks qualify this backend, and the site allocation, runner and hardware have no live qualification. The Slurm guide shows a complete run.

Attributes:

  • profile (SlurmProfile) –

    Required. The SlurmProfile. Its total rank count and GPU request are checked against its route.

  • accounting_since (Text) –

    Required. Start of the accounting search window, an ISO time without a time zone, read in the site's local time. Choose a window that covers the intended submission period.

  • accounting_until (Text) –

    Required. End of that window, later than accounting_since.

  • max_input_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each request file, as in NWQSimBackend.

  • max_output_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each result file.

  • max_buffer_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the runner's known arrays per process, as in NWQSimBackend.

  • max_response_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the output of each scheduler command. It must cover the sbatch --parsable reply, 12 bytes plus the cluster name's length (22 bytes for perlmutter).

  • timeout_seconds (Real) –

    Required. Positive deadline in seconds for each scheduler command.

  • optimization_level (Count) –

    Default 0. Qiskit transpiler level of the translation to U and CX gates, as in NWQSimBackend, with the same exclusion "optimization_level" at any other level.

Raises:

  • ValueError –

    If the rank or GPU request does not fit the route, the accounting window has a time zone or is not increasing, or timeout_seconds is not positive.

SlurmProfile

Bases: Record

Slurm site settings for an NWQ-Sim runner: allocation, runner, binding and shared pending-job directory.

Build it with keyword arguments, for example SlurmProfile(cluster=..., account=..., walltime="00:05:00", nodes=1, ranks_per_node=1, threads=1, executable=..., build_identity=..., spool=...), and pass it as profile= to NWQSimSlurmBackend. cluster, account, walltime, nodes, ranks_per_node, threads, executable, build_identity and spool are required. Node, rank and thread counts describe the requested resources, not measured use. Every option value must be one literal token, so that it cannot end its #SBATCH line and add another directive. The Slurm guide gives Perlmutter and Frontier profiles.

Attributes:

  • cluster (Text) –

    Required. One cluster name, letters, digits, _ and - only. "all" and comma lists are rejected, because job lookups name exactly one cluster.

  • account (Text) –

    Required. Slurm account to charge.

  • partition (Text | None) –

    Default None. Slurm partition.

  • qos (Text | None) –

    Default None. Slurm quality of service.

  • constraint (Text | None) –

    Default None. Slurm node constraint, such as "gpu".

  • walltime (Text) –

    Required. Positive time limit in Slurm's [days-]hours:minutes:seconds form.

  • nodes (PositiveInt) –

    Required. Positive. Number of nodes.

  • ranks_per_node (PositiveInt) –

    Required. Positive. MPI ranks per node.

  • threads (PositiveInt) –

    Required. Positive. Threads per rank.

  • gpus_per_task (PositiveInt | None) –

    Default None. Positive. GPUs per task, given together with gpu_bind. The "NVGPU" and "AMDGPU" routes require exactly 1, and the CPU and MPI routes require None.

  • gpu_bind (Text | None) –

    Default None. Slurm GPU binding, given together with gpus_per_task.

  • cpu_bind (Text) –

    Default "cores". Slurm CPU binding.

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

    Default (). Environment modules to load before the run.

  • executable (Text) –

    Required. Absolute path of the runner on the compute nodes.

  • build_identity (Text) –

    Required. Source commit of the runner's NWQ-Sim build. It records which build ran and does not qualify a GPU or distributed implementation.

  • spool (Text) –

    Required. Absolute path of a directory shared with the compute nodes.

  • backend (Literal['CPU', 'MPI', 'NVGPU', 'AMDGPU', 'NVGPU_MPI']) –

    Default "CPU". NWQ-Sim route, as in NWQSimBackend.

  • method (Literal['SV', 'DM']) –

    Default "SV". "SV" or "DM", as in NWQSimBackend.

Raises:

  • ValueError –

    If the route is not supported, cluster is not one name, an option value is not one token, walltime is malformed or zero, gpus_per_task and gpu_bind are not given together, or a path is not absolute.

script

script(submission_id, *, max_input_bytes)

Return the Slurm batch script for one submission, without running it.

Use it to inspect what a submission would send to sbatch. Rendering a script does not qualify a site. The job name nwqlib-<submission UUID> is what a lost submission acknowledgement is searched for. --no-requeue keeps Slurm from running the same request a second time after a node failure or preemption, and srun --kill-on-bad-exit stops all ranks when one fails. Batch stdout and stderr go to /dev/null, because only the runner's result file is read.

Parameters:

  • submission_id (str) –

    Submission UUID that names the job and its subdirectory of spool.

  • max_input_bytes (int) –

    Positive limit in bytes on the request file, passed to the runner.

Returns:

  • script ( str ) –

    The script text, ending with a newline.

Raises:

  • ValueError –

    If max_input_bytes is not a positive integer.

  • ValueError –

    If submission_id is not a canonical UUID.

IBMRuntimeBackend

Bases: Record

IBM Quantum Runtime connection for sampled counts and provider expectation estimates.

Build it with keyword arguments, for example IBMRuntimeBackend(device="ibm_example", instance="my-instance", max_input_bytes=65_536), and pass it as backend= to prepare. device, instance and max_input_bytes are required. It needs the ibm extra. Counts use SamplerV2 and a provider estimate uses EstimatorV2. Construction reads no credential and contacts no service. Preparation and retrieval use the saved SDK account named by account_name, or otherwise the token in the environment variable named by token_env, and no credential is stored in the configuration or the Run's files.

Preparation compiles each circuit for the device with the Plan's runtime seed and keeps the logical-to-physical layout. The Estimator's resilience level is zero unless options_json selects another, so no error mitigation runs implicitly, and the Plan sets the precision. The Run bounds serialized buffers and decoded arrays. SDK HTTP buffering, retries, compilation memory, wall time and billing are not bounded. A refresh keeps the results already decoded when a later result fails to decode. A resumed read fetches the whole job payload again, and results already saved skip only the local decoding. Only offline SDK and transport checks qualify this backend, and live accounts, queues and devices are unqualified. The IBM Runtime guide describes jobs, retrieval and cancellation.

Attributes:

  • device (Text) –

    Required. IBM device name.

  • instance (Text) –

    Required. IBM instance. "auto" is rejected, because retrieval and job recovery compare it with the job's own instance.

  • account_name (Text | None) –

    Default None. Name of a saved IBM SDK account. With None, the token is read from the variable token_env names.

  • token_env (Text) –

    Default "NWQLIB_IBM_RUNTIME_TOKEN". Environment variable that holds the API token, read only during preparation or retrieval.

  • mode (Literal['job', 'batch', 'session']) –

    Default "job". "batch" or "session" attaches every job to the existing container container_id.

  • container_id (Text | None) –

    Default None. ID of an existing Batch or Session. Required in batch and session mode, and must be None in job mode.

  • calibration_id (Text | None) –

    Default None. Device calibration ID passed to the IBM SDK when the device is opened.

  • options_json (Text) –

    Default "{}". JSON object of the requested primitive options. It states the requested options, not the server's defaults. Experimental option overrides are rejected, because they can bypass the requested readout and its uncertainty.

  • optimization_level (Count) –

    Default 1. Qiskit preset pass-manager level, 0 to 3. A level other than 1 is recorded as the exclusion "optimization_level" in the preparation record, and the operation count describes the compiled circuit. The IBM target has no derived roundoff constant, so state_error() gives no bound at any level.

  • initial_layout (tuple[Count, ...] | None) –

    Default None. Physical qubit for each logical qubit, without repeats.

  • max_input_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the QPY copy of each prepared circuit, which only a Run saved to a directory writes.

Raises:

  • ValueError –

    If container_id is given in job mode or missing in batch or session mode, if instance is "auto", or if initial_layout repeats a qubit.

IonQBackend

Bases: Record

IonQ connection for raw sampled counts on an IonQ QPU, through the v0.4 REST API.

Build it with keyword arguments, for example IonQBackend(device="qpu.forte-1", max_input_bytes=1_000_000, max_response_bytes=1_000_000), and pass it as backend= to prepare. device, max_input_bytes and max_response_bytes are required. It needs the ionq extra. Construction imports no SDK and contacts no service. The API key is read from the environment variable named by token_env only when a job is submitted or retrieved, and it is never stored.

Each operation is one HTTP request, so no SDK retry can create a second job. IonQ's v0.4 API offers no qualified way to find a job by name, so a lost submission acknowledgement leaves the outcome uncertain, and Run.wait raises RunFailed without submitting a replacement. Only raw histograms are read, because IonQ's probability results are not counts of shots. The Run bounds decoded data and stored observations. Only offline SDK and API checks qualify this backend, and live QPU behavior is unqualified. The IonQ guide gives the API sources, batch limits and histogram decoding.

Attributes:

  • device (Text) –

    Required. A v0.4 QPU name starting with qpu.. The ideal simulator is rejected because it ignores the requested shots.

  • gateset (Literal['qis', 'native']) –

    Default "qis". "qis" translates circuits with Qiskit to Rx, Ry, Rz and CX, with angles in radians. "native" passes IonQ native gates unchanged, with angles in turns.

  • debiasing (StrictBool) –

    Default False, the only supported value. A debiased job returns separate variant populations whose qubit-map direction the v0.4 job schema does not define, so they cannot be read as one set of counts.

  • token_env (Text) –

    Default "NWQLIB_IONQ_API_KEY". Environment variable that holds the API key.

  • max_input_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the serialized request and the optional QPY copy of each prepared circuit.

  • max_response_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each HTTP response body that NWQLib reads. It does not bound network buffers, provider work, billing or process memory.

  • request_timeout_seconds (Real) –

    Default 30.0. Positive. Connect and read timeout of each request in seconds, not a deadline for the whole request.

  • optimization_level (Count) –

    Default 0. Qiskit transpiler level, 0 to 3, of the "qis" translation. The "native" gateset accepts only 0. Levels 2 and 3 resynthesize two-qubit blocks with Qiskit's own synthesis. A level other than 0 is recorded as the exclusion "optimization_level" in the preparation record, and the operation count describes the compiled circuit. The IonQ target has no derived roundoff constant, so state_error() gives no bound at any level.

NexusBackend

Bases: Record

Quantinuum Nexus connection for sampled counts on an H2 device or emulator.

Build it with keyword arguments, for example NexusBackend(project="<project UUID>", device="H2-1", max_input_bytes=1_000_000), and pass it as backend= to prepare. project, device and max_input_bytes are required. It needs the nexus extra. Construction imports no SDK and does not log in. Authentication uses the user's existing qnexus configuration.

Preparation uploads and compiles each circuit as separate remote steps, and execution sends one job per batch. The Run bounds the data it stores, not HTTP buffering, billing or SDK memory. qnexus 0.49 has no public per-request timeout, so a refresh avoids waiting in the provider queue but one HTTP request can still block indefinitely. Only offline SDK and converter checks qualify this backend, and live compilation and execution are unqualified. The Nexus guide gives the preparation boundary, costs and the qnexus dependency conflict.

Attributes:

  • project (Text) –

    Required. UUID of an existing Nexus project.

  • device (Text) –

    Required. An H2 device name, H2-<n>, with suffix E or LE for the emulators. Helios devices take HUGR or QIR programs, a separate route that this backend does not submit.

  • target_region (Literal['us', 'sg']) –

    Default "us". Execution region, "us" or "sg".

  • credential_name (Text | None) –

    Default None. Name of a Nexus-linked credential, never a secret.

  • optimization_level (Count) –

    Default 1. Nexus compile level, 0 to 3. A level other than 1 is recorded as the exclusion "optimization_level" in the preparation record. The H2 target has no derived roundoff constant, so state_error() gives no bound at any level.

  • max_cost_hqc (Nonnegative | None) –

    Default None, no cap. Nonnegative. Cost cap per submitted program, in Hardware Quantum Credits.

  • max_input_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on the JSON encoding of each prepared pytket circuit.

Raises:

  • ValueError –

    If device is not an H2 device name.

Forecast cost and feasibility

A DeviceProfile describes a machine and its time models, and an Allocation the resources granted to a workload. nwqlib.estimate(plan, profile=profile, allocation=allocation) forecasts every point of the Plan and returns a PlanEstimate. assess forecasts one point. Nothing runs, and the numbers below are synthetic, not measurements of a machine. The one-qubit Plan prepares |1> as H, Z, H and reads <Z> exactly, which counts one invocation, one exact evaluation and three logical operations, so the engineering model predicts 0.25 + 0.5 + 3 × 0.125 = 1.125 seconds:

from datetime import datetime, timezone

from nwqlib import Expectation, plan
from nwqlib.algorithms import ExpectationMethod
from nwqlib.backends import (
    AER_STATEVECTOR_TARGET, Allocation, DeviceConfiguration, DeviceProfile,
    ModelDomain, TimeCoefficient, TimeModel, assess,
)
from nwqlib.core import Limit, Source, Unit
from nwqlib.evidence import Evidence
from nwqlib.operators import ingest_pauli
from nwqlib.problems.inputs import ingest_occupation

problem = Expectation(state=ingest_occupation("1", num_qubits=1),
                      observable=ingest_pauli((("Z", 1.0),), num_qubits=1))
selected = plan(problem, method=ExpectationMethod(preparation_choice="hzh"),
                seed=7)

source = Source(name="example profile", version="1",
                domain="synthetic numbers, not a measured machine",
                reference="api/backends.md")
start = datetime(2026, 1, 1, tzinfo=timezone.utc)
end = datetime(2027, 1, 1, tzinfo=timezone.utc)
target = AER_STATEVECTOR_TARGET  # NWQLib's declared Aer statevector target
machine = DeviceConfiguration(
    name="example machine", version="1", target=target, hardware=source,
    runtime=Source(name=target.name, version="1", domain="example runtime",
                   reference="api/backends.md"),
    build=source, compiler=source, precision="complex128",
    representation="statevector")
spec = Evidence(kind="external_specification", source=source)
grant = Allocation(
    name="example grant", configuration_id=machine.content_id,
    locations=("logical_device",), topology="single_device",
    limits=(Limit(stage="execution", metric="memory",
                  unit=Unit(symbol="byte", dimension="bytes"),
                  kind="capacity_stock", value=2**30,
                  scope="logical_device"),),
    recorded_at=start, valid_until=end, evidence=spec)
domain = ModelDomain(
    configuration_id=machine.content_id, allocation_id=grant.content_id,
    basis="selected_logical", batch_schedule="unspecified",
    acquisition="direct_observation", runtime="seed_independent",
    population="unconditional", readouts=("pauli_expectation",),
    selection_ids=(), primitive_gates=("h", "z"),
    min_qubits=1, max_qubits=1, min_operations=0, max_operations=10,
    max_shots=0, max_exact_evaluations=1, max_readout_items=1,
    max_resets=0, max_measurements=0, max_classical_work=0,
    max_adaptive_rounds=0)
model = TimeModel(
    name="example timing", kind="engineering",
    scope="selected_acquisition",
    coefficients=(
        TimeCoefficient(feature="invocations", seconds_per_unit=0.25,
                        unit="s/invocation"),
        TimeCoefficient(feature="exact_evaluations", seconds_per_unit=0.5,
                        unit="s/exact_evaluation"),
        TimeCoefficient(feature="logical_operations", seconds_per_unit=0.125,
                        unit="s/logical_operation")),
    domain=domain, recorded_at=start, valid_until=end,
    evidence=Evidence(kind="numerical_estimate", source=source),
    assumptions=("synthetic coefficients for this example",))
profile = DeviceProfile(configuration=machine, recorded_at=start,
                        valid_until=end, evidence=spec, models=(model,))

forecast = assess(selected, selected.resolve("expectation"),
                  profile=profile, allocation=grant,
                  assessed_at=datetime(2026, 6, 1, tzinfo=timezone.utc))
print(forecast.time.status)                  # conditional
print(forecast.predictions[0].seconds.value)  # 1.125

The machine's target is a BackendTarget, here the built-in AER_STATEVECTOR_TARGET for exact readouts. An engineering model's prediction is conditional on its stated assumptions. The profiles guide defines the five axes, the memory comparison and the time models.

DeviceProfile

Bases: Record

A stored description of one machine: its configuration, advertised limits and named time models.

Build it with keyword arguments, for example DeviceProfile(configuration=..., recorded_at=..., valid_until=..., evidence=..., models=(model,)), and pass it as profile= to nwqlib.estimate, nwqlib.compare or assess. configuration, recorded_at, valid_until and evidence are required. The profile is data the caller supplies. NWQLib never discovers a machine or refreshes a profile. New calibration makes a new profile with a new content hash, so an earlier assessment is never rewritten. The profiles guide explains the assessment, and the example under Forecast cost and feasibility builds a small profile.

Attributes:

  • configuration (DeviceConfiguration) –

    Required. The DeviceConfiguration.

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

    Default (). Advertised limits as Limit records, at most one per stage, metric and scope.

  • recorded_at (Timestamp) –

    Required. Time zone-aware time the profile was recorded, stored in UTC.

  • valid_until (Timestamp) –

    Required. Time zone-aware end of validity, not before recorded_at.

  • evidence (Evidence) –

    Required. The specification the profile rests on, not a record of an execution.

  • models (tuple[TimeModel, ...]) –

    Default (). TimeModel records with distinct names.

Raises:

  • ValueError –

    If valid_until precedes recorded_at, two limits share a stage, metric and scope, or two models share a name.

DeviceConfiguration

Bases: Record

The machine a device profile describes: target, hardware, runtime, build, compiler and numerical precision.

Build it with keyword arguments and pass it as configuration= to DeviceProfile. name, version, target, hardware, runtime and build are required. Its content hash (content_id) is what an Allocation and a ModelDomain name as their configuration_id, so a time model can refer to the machine without referring to the profile that contains it. An optional field left None stays unknown in an assessment.

Attributes:

  • name (Text) –

    Required. Name of the stored specification.

  • version (Text) –

    Required. Version of the stored specification.

  • target (BackendTarget) –

    Required. The backend target the machine supports, the same target record that backend adapters declare.

  • hardware (Source) –

    Required. Source describing the hardware.

  • runtime (Source) –

    Required. Source of the intended runtime. Its name must equal target.name. It describes what preparation is expected to use, not an observed preparation record.

  • build (Source) –

    Required. Source of the implementation and build configuration.

  • compiler (Source | None) –

    Default None. Source of the intended compiler.

  • precision (Literal['complex64', 'complex128', 'float64'] | None) –

    Default None. "complex64", "complex128" or "float64".

  • representation (Literal['statevector', 'density_matrix', 'tensor', 'hardware', 'classical'] | None) –

    Default None. "statevector", "density_matrix", "tensor", "hardware" or "classical".

Raises:

  • ValueError –

    If runtime.name differs from target.name.

BackendTarget

Bases: Record

What a simulator, cloud provider or export target supports, for profile assessment.

Pass it as target= to a DeviceConfiguration. Start from a built-in target such as AER_STATEVECTOR_TARGET and change fields with revise, or build one with keyword arguments, for example BackendTarget(name="my_target", provider="my_provider"). name and provider are required. For each optional collection, None means unknown and an empty tuple means none, so profile assessment can tell an undeclared subset from an unsupported one. A coarse capability never certifies a readout or instruction that the target does not list. The profiles guide shows how these declarations decide the capability check.

Attributes:

  • name (Text) –

    Required. Backend or target name.

  • provider (Text) –

    Required. Provider family, such as "qiskit_aer" or "ionq".

  • capabilities (tuple[BackendCapability, ...] | None) –

    Default None, unknown. Coarse execution capabilities, such as "statevector", "counts" or "noise_model".

  • description (str) –

    Default "". Text for reports.

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

    Default (). Native or preferred basis gates when known, in the given order.

  • max_qubits (Count | None) –

    Default None. Advertised or configured qubit limit.

  • artifacts (tuple[Text, ...] | None) –

    Default None, unknown. Accepted input forms, such as "selected_construction" (a Plan's construction), which profile assessment requires.

  • readouts (tuple[Literal['pauli_expectation', 'counts', 'probabilities', 'host_scalars', 'amplitudes', 'estimated_observable', 'trajectory'], ...] | None) –

    Default None, unknown. Supported observation kinds among "pauli_expectation", "counts", "probabilities", "host_scalars", "amplitudes", "estimated_observable" and "trajectory", declared separately from capabilities. "trajectory" is the exact schedule with several observation points, and each point also needs its own readout kind listed.

  • readout_features (tuple[Literal['multi_position', 'views'], ...] | None) –

    Default None, unknown. Trajectory features the target executes: "multi_position" (several observation points of one coherent state in one execution) and "views" (reversible basis changes before a Pauli or probability point, undone exactly afterwards).

  • reducers (tuple[Text, ...] | Literal['registered'] | None) –

    Default None, unknown. The registered reducers that the target runs at a trajectory point, which turn a saved state into statistics during execution: a tuple of reducer names, or "registered" for every reducer in nwqlib.core.planning.READOUT_REDUCERS.

  • host_dependencies (tuple[Text, ...] | None) –

    Default None, unknown. Packages available to classical routines on this target. Profile assessment requires every dependency that a chosen routine declares to be listed.

  • instructions (tuple[InstructionSupport, ...] | None) –

    Default None, unknown. Exact instruction subset, including controls and adjoints, as InstructionSupport records, each naming one primitive gate or one implementation Source and its width.

  • program_nodes (tuple[Text, ...] | None) –

    Default None, unknown. Supported Program node kinds.

Raises:

  • ValueError –

    If a collection declares a value twice.

AER_STATEVECTOR_TARGET

AER_STATEVECTOR_TARGET = BackendTarget(name='aer_statevector', provider='qiskit_aer', capabilities=capability_set(BackendCapability.STATEVECTOR), description='Qiskit Aer exact statevector simulator.', readouts=('pauli_expectation', 'probabilities', 'amplitudes', 'trajectory'), readout_features=('multi_position', 'views'), reducers='registered')

Built-in target of the Qiskit Aer statevector simulator, for exact readouts.

It declares the statevector capability and the readouts pauli_expectation, probabilities, amplitudes and trajectory, with the trajectory features multi_position and views and every registered reducer. It leaves artifacts, instructions and program_nodes unknown. Use it as DeviceConfiguration(target=...) for exact readouts, and use AER_COUNTS_TARGET for sampled shots. It is a stored declaration that imports no SDK, not a live device inventory.

AER_COUNTS_TARGET

AER_COUNTS_TARGET = BackendTarget(name='aer_counts', provider='qiskit_aer', capabilities=capability_set(BackendCapability.COUNTS, BackendCapability.NOISE_MODEL), description='Qiskit Aer finite-shot measured circuit simulator.', readouts=('counts',))

Built-in target of the Qiskit Aer simulator with measured shots.

It declares the counts and noise_model capabilities and the counts readout. It leaves readout_features, reducers, artifacts, instructions and program_nodes unknown. Use it as DeviceConfiguration(target=...) for a Plan with sampled shots. It is a stored declaration that imports no SDK, not a live device inventory.

TimeModel

Bases: Record

A named linear model of time in seconds, the sum of coefficient times feature count, for one scope.

Build it with keyword arguments and pass it in models= of DeviceProfile. Every field except form, calibration and uncertainty is required. The one supported form, acquisition_linear/1, is

seconds = c_invocation * invocations + c_shot * sampled_shots
        + c_exact * exact_evaluations + c_operation * logical_operations

over the feature counts of the resource estimate, so it is evaluated without running anything (Finite time models). An engineering model states assumed coefficients and gives conditional numbers under its assumptions. A calibrated model keeps its supplied calibration sources and uncertainty unchanged. Neither kind collects calibration data. An expired, future-dated or out-of-domain model gives an unavailable prediction with its reason.

Attributes:

  • form (Literal['acquisition_linear/1']) –

    Default "acquisition_linear/1", the only accepted value. Arbitrary expressions and plugins are rejected.

  • name (Text) –

    Required. Model name, unique within the profile.

  • kind (Literal['engineering', 'calibrated']) –

    Required. "engineering" for assumed coefficients or "calibrated" for coefficients from a supplied calibration.

  • scope (TimeScope) –

    Required. What the seconds cover: "selected_acquisition", "acquisition_overhead" or "native_call_wall". The first two exclude planning, compilation, queue delay, analysis and whole-run cost. "native_call_wall" covers the synchronous backend call, including waiting and result extraction, and excludes preparation and saving. The scopes overlap, so their predictions must not be added, and none covers a whole run.

  • coefficients (tuple[TimeCoefficient, ...]) –

    Required. One to four TimeCoefficient records with distinct features.

  • domain (ModelDomain) –

    Required. The ModelDomain of workloads the model is valid for.

  • recorded_at (Timestamp) –

    Required. Time zone-aware time the model was recorded, stored in UTC.

  • valid_until (Timestamp) –

    Required. Time zone-aware end of validity, not before recorded_at.

  • evidence (Evidence) –

    Required. Evidence of kind "numerical_estimate" for an engineering model or "empirical_prediction" for a calibrated one.

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

    Required. At least one stated assumption.

  • calibration (CalibrationReference | None) –

    Default None. The CalibrationReference, required for a calibrated model and not allowed for an engineering one.

  • uncertainty (ModelUncertainty | None) –

    Default None. The ModelUncertainty, required for a calibrated model.

Raises:

  • ValueError –

    If valid_until precedes recorded_at, a feature repeats, calibration does not match kind, the evidence kind does not match kind, or a calibrated model has no uncertainty.

TimeCoefficient

Bases: Record

One coefficient of a linear time model: seconds per invocation, shot, exact evaluation or logical operation.

Build it with keyword arguments, for example TimeCoefficient(feature="sampled_shots", seconds_per_unit=0.001, unit="s/shot"), and pass it in coefficients= of TimeModel. Every field is required. The unit is kept exactly as supplied and never converted. A zero coefficient states that the feature contributes nothing, which differs from leaving the feature out.

Attributes:

  • feature (TimeFeature) –

    Required. "invocations", "sampled_shots", "exact_evaluations" or "logical_operations".

  • seconds_per_unit (Nonnegative) –

    Required. Nonnegative coefficient in unit.

  • unit (Literal['s/invocation', 's/shot', 's/exact_evaluation', 's/logical_operation']) –

    Required. The one unit of the feature: "s/invocation", "s/shot", "s/exact_evaluation" or "s/logical_operation" respectively.

Raises:

  • ValueError –

    If unit is not the unit of feature.

ModelDomain

Bases: Record

The workloads a time model is valid for: machine, allocation, readout, operation mix and size ranges.

Build it with keyword arguments and pass it as domain= to TimeModel. Every field except rotation_precision, synthesis and bindings is required. An assessment evaluates the model only for a workload inside every range and list here, and reports the prediction as unavailable otherwise. The record selects, fits and extrapolates nothing. An empty list of selections or gates supports none, never any. Size ranges are inclusive, and max_resets, max_measurements, max_classical_work and max_adaptive_rounds each give the inclusive range from 0 to the maximum. A model calibrated without resets, for example, does not apply once resets are added, even when the gate counts match. The time-model section of the profiles guide lists every domain check.

Attributes:

  • configuration_id (ContentID) –

    Required. content_id of the DeviceConfiguration: hardware, runtime, build, precision and target.

  • allocation_id (ContentID) –

    Required. content_id of the Allocation: every granted location, limit and topology.

  • basis (MetricBasis) –

    Required. Gate basis in which logical operations are counted: "selected_logical", "cx", "clifford_t" or "toffoli".

  • rotation_precision (Float64 | None) –

    Default None. Positive rotation-synthesis precision the operation counts assume.

  • synthesis (Source | None) –

    Default None. Source of the synthesis rule the operation counts assume.

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

    Required. "unspecified" or "serial".

  • acquisition (Literal['direct_observation', 'measurement_batch']) –

    Required. "direct_observation" or "measurement_batch".

  • runtime (RuntimeOptions | Literal['seed_independent']) –

    Required. The runtime seed the model was measured with, as RuntimeOptions(seed=...), or "seed_independent". A whole-Plan forecast does not guess future seeds, so only a seed-independent model applies there.

  • population (Literal['unconditional', 'native_conditioned']) –

    Required. Readout population, "unconditional" or "native_conditioned".

  • readouts (tuple[Literal['pauli_expectation', 'counts', 'probabilities', 'host_scalars', 'amplitudes', 'estimated_observable'], ...]) –

    Required. Distinct supported readouts: "pauli_expectation", "counts", "probabilities", "host_scalars", "amplitudes" or "estimated_observable".

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

    Required. Distinct content hashes of the supported block selections.

  • primitive_gates (tuple[Literal['x', 'h', 'z', 'sdg', 'cx', 'mc_z', 'phase'], ...]) –

    Required. Distinct supported primitive gates: "x", "h", "z", "sdg", "cx", "mc_z" or "phase".

  • min_qubits (Count) –

    Required. Smallest supported qubit count.

  • max_qubits (Count) –

    Required. Largest supported qubit count, at least min_qubits.

  • min_operations (Count) –

    Required. Smallest supported logical operation count.

  • max_operations (Count) –

    Required. Largest supported logical operation count, at least min_operations.

  • max_shots (Count) –

    Required. Largest supported shot count.

  • max_exact_evaluations (Count) –

    Required. Largest supported number of exact evaluations.

  • max_readout_items (Count) –

    Required. Largest supported number of returned readout items.

  • max_resets (Count) –

    Required. Largest supported reset count.

  • max_measurements (Count) –

    Required. Largest supported measurement count.

  • max_classical_work (Count) –

    Required. Largest supported classical work.

  • max_adaptive_rounds (Count) –

    Required. Largest supported number of adaptive rounds.

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

    Default (). Parameter values the model is restricted to, at most one per parameter.

Raises:

  • ValueError –

    If a minimum exceeds its maximum, rotation_precision is not positive, or a binding, readout, selection or gate is repeated.

ModelUncertainty

Bases: Record

The supplied uncertainty of a time model, as an additive interval in seconds around its prediction.

Build it with keyword arguments, for example ModelUncertainty(kind="future_run_prediction", lower_residual_seconds=-0.25, upper_residual_seconds=0.5, coverage=0.9, source=...), and pass it as uncertainty= to TimeModel. Every field except coverage is required, and coverage is required for the two statistical kinds. The residuals are added to the central prediction, so the example gives the interval [prediction - 0.25, prediction + 0.5] seconds. The interval keeps the meaning its source states and is never an execution guarantee.

Attributes:

  • kind (Literal['future_run_prediction', 'sample_mean_confidence', 'model_error_envelope']) –

    Required. "future_run_prediction" concerns one future run. "sample_mean_confidence" concerns a mean and does not bound an individual run. "model_error_envelope" states an engineering uncertainty without a probability.

  • lower_residual_seconds (Real) –

    Required. Zero or negative residual in seconds.

  • upper_residual_seconds (Nonnegative) –

    Required. Nonnegative residual in seconds.

  • coverage (Real | None) –

    Default None. Probability in (0, 1] that the interval holds, required for "future_run_prediction" and "sample_mean_confidence" and not allowed for "model_error_envelope", because a coverage would claim more than an engineering uncertainty supports.

  • source (Source) –

    Required. Source of the stated interval.

Raises:

  • ValueError –

    If coverage is missing for a statistical kind or given for "model_error_envelope".

CalibrationReference

Bases: Record

Where a calibrated time model's coefficients came from: training data, validation data and validation errors.

Build it with keyword arguments and pass it as calibration= to TimeModel. Every field is required. Each Source names the exact data or procedure version. NWQLib never opens or fetches a referenced source. A link to a parent record alone does not establish which workloads trained the model.

Attributes:

  • source (Source) –

    Required. Source of the calibration procedure.

  • training (Source) –

    Required. Source of the training workloads.

  • validation (Source) –

    Required. Source of the held-out validation workloads.

  • validation_errors (Source) –

    Required. Source of the held-out error report.

Allocation

Bases: Record

The resources granted to one workload: locations, their placement and their capacity limits.

Build it with keyword arguments, for example Allocation(name=..., configuration_id=configuration.content_id, locations=("logical_device",), topology="single_device", limits=(...), recorded_at=..., valid_until=..., evidence=...), and pass it as allocation= to nwqlib.estimate, nwqlib.compare or assess. Every field is required. The record states a grant that the caller supplies. NWQLib never queries a scheduler or device for it, and it never configures ranks, threads or devices. Capacities are never pooled across locations. For example, two 8-GiB devices cannot hold a 10-GiB peak on one device. The device-domain section of the profiles guide explains how capacities are compared.

Attributes:

  • name (Text) –

    Required. Name of the grant.

  • configuration_id (ContentID) –

    Required. content_id of the DeviceConfiguration the grant is for. An assessment applies the grant's limits only when it matches the profile's configuration.

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

    Required. Distinct names of the granted locations, the names the Program's registers and workspaces use, such as "logical_device".

  • topology (Literal['single_device', 'independent_devices', 'distributed'] | None) –

    Required. "single_device" (exactly one location), "independent_devices", "distributed", or None when the placement is unknown.

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

    Required. Capacity, consumption and deadline limits as Limit records, at most one per stage, metric and scope. A limit of kind "capacity_stock" names exactly one granted location as its scope.

  • recorded_at (Timestamp) –

    Required. Time zone-aware time the grant was recorded, stored in UTC.

  • valid_until (Timestamp) –

    Required. Time zone-aware end of the grant's validity, not before recorded_at.

  • evidence (Evidence) –

    Required. Evidence describing the grant, not its use.

Raises:

  • ValueError –

    If the locations are empty or repeated, "single_device" has more than one location, two limits share a stage, metric and scope, a "capacity_stock" limit names a location outside the grant, or valid_until precedes recorded_at.

assess

assess(plan: Plan, realization: Realization, *, profile: DeviceProfile, allocation: Allocation, context: ResourceContext | None = None, runtime: RuntimeOptions | None = None, assessed_at: datetime | None = None, accuracy: Accuracy | None = None, facts: tuple[FramedFact, ...] = (), reference: TargetReference | None = None, max_assessments=4096) -> ProfileAssessment

Forecast one resolved point of a Plan on a device profile and allocation, without running anything.

nwqlib.estimate(plan, profile=..., allocation=...) assesses every point of the Plan whose parameters are fixed. Call assess for one point, for example the point that plan.resolve(experiment_name) returns. The result reports five independent axes: applicability, capability, capacity, time and accuracy. Each axis has the status "feasible", "infeasible", "conditional" or "unknown", and a failure on one axis, such as memory, does not hide what another supports, such as an error bound. Time predictions rest on the supplied coefficients, so none is an execution guarantee. No pilot run, profile refresh, circuit compilation or replay of the computation takes place. The profiles guide defines the axes, and Forecast cost and feasibility assesses a one-qubit Plan.

Parameters:

  • plan (Plan) –

    The Plan whose point is assessed.

  • realization (Realization) –

    One resolved point of plan, such as plan.resolve(experiment_name).

  • profile (DeviceProfile) –

    The device profile.

  • allocation (Allocation) –

    The resources granted to the workload.

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

    Resource-counting context, such as the gate basis. None uses ResourceContext().

  • runtime (RuntimeOptions | None, default: None ) –

    Backend seed of an already known preparation. With None, only seed-independent models apply. Seeds are never guessed.

  • assessed_at (datetime | None, default: None ) –

    Time zone-aware assessment time, against which the validity of the profile, allocation and models is checked. None records the current UTC time once.

  • accuracy (Accuracy | None, default: None ) –

    Accuracy criterion to assess. None uses the Plan's selection_accuracy, and with neither the accuracy axis is unknown. Another criterion changes only this assessment, never the Plan's shots or selection.

  • facts (tuple[FramedFact, ...], default: () ) –

    Supplied error facts, passed unchanged to the Plan's error model. A fact for one point cannot cover another.

  • reference (TargetReference | None, default: None ) –

    Supplied reference value, passed unchanged to the Plan's error model.

  • max_assessments (int, default: 4096 ) –

    Positive limit on assessment and prediction rows, here one plus the number of time models, checked before any model is evaluated.

Returns:

  • assessment ( ProfileAssessment ) –

    The forecast. Its predictions hold the time forecasts in seconds, its capacity the memory comparison and its error the complete accuracy assessment.

Raises:

  • TypeError –

    If profile is not a DeviceProfile or accuracy is not an Accuracy.

  • ValueError –

    If the rows exceed max_assessments, or the stored records do not match the Plan, profile and allocation.

PlanEstimate

Bases: Record

The resource estimate of a whole Plan with the device forecasts of its resolved points.

nwqlib.estimate(plan, profile=profile, allocation=allocation) returns it. Without a profile and allocation, estimate returns the WorkloadEstimate alone. The fields below are read-only. All assessments share one assessment time. Points that an adaptive method has not chosen yet, and points along a range axis that is not expanded, are listed in unpredicted instead of being guessed. When a Run is prepared with this estimate, each submission looks up the forecast of its own point, and later timings can be compared with it by align_telemetry.

Attributes:

assessment_for

assessment_for(plan, receipt)

Return the stored forecast of a prepared circuit's point, or None, without evaluating anything.

The forecast is checked against the Plan once per estimate, and against the preparation record each time.

Parameters:

  • plan (Plan) –

    The Plan this estimate belongs to.

  • receipt (PreparedArtifact) –

    The preparation record of one prepared circuit.

Returns:

  • assessment ( ProfileAssessment | None ) –

    The forecast of that circuit's point, or None when the estimate has no forecast for it.

Raises:

  • ValueError –

    If the estimate belongs to another Plan, or the forecast does not match the preparation record.

ProfileAssessment

Bases: Record

The forecast of one resolved Plan point on a device profile: five independent axes and the time predictions.

assess returns it, and PlanEstimate.assessments holds one per point. The fields below are read-only. Each axis is an AxisAssessment whose status summarizes its own details only, so a memory failure cannot hide a supported error bound. No conclusion grants permission to run, configures a backend or changes the computation. An excessive sufficient error bound stays INCONCLUSIVE in error rather than proving that the actual error is too large.

Attributes:

  • point (AssessmentPoint) –

    Content hashes of the inputs: problem, Plan, point, base and selected construction, resource estimate and context, profile, allocation, expected runtime and compiler sources, known runtime seed, and the assessment time.

  • realization (Realization) –

    The resolved point, with its parameter bindings.

  • resources (WorkloadEstimate) –

    Resource estimate of this point. Capability, capacity and time read the same counts.

  • applicability (AxisAssessment) –

    Whether a stated assumption of the method holds for this problem. The built-in Methods record no such statement, so this axis is unknown, or conditional when the Plan lists assumptions or requirements.

  • capability (AxisAssessment) –

    Whether the target supports the point's circuit form, Program nodes, readout, instructions, host kernel and control or adjoint use.

  • capacity (AxisAssessment) –

    Whether each granted location holds the point's simultaneous memory and storage peaks and its known lower requirements.

  • time (AxisAssessment) –

    The time-model predictions and the matching time limits.

  • accuracy (AxisAssessment) –

    The Plan's error-model assessment of criterion.

  • criterion (Accuracy | None) –

    The Accuracy criterion assessed, or None.

  • error (ClaimAssessment | None) –

    The complete ClaimAssessment of criterion, or None without a criterion or error model. Before execution it names no observation or result.

  • predictions (tuple[TimePrediction, ...]) –

    One TimePrediction per time model of the profile, in the profile's order.

AxisAssessment

Bases: Record

One axis of a device forecast: its status and every fact behind it.

Read it from the applicability, capability, capacity, time and accuracy fields of a ProfileAssessment. The fields below are read-only. The status summarizes the details of this axis only. A known failure ("infeasible") decides the axis. Otherwise any "conditional" detail makes it conditional, then any "unknown" detail makes it unknown, and it is "feasible" only when every detail is.

Attributes:

  • axis (Axis) –

    "scientific_applicability", "execution_capability", "capacity_materialization", "time_cost" or "accuracy_evidence".

  • status (Outcome) –

    "feasible", "infeasible", "conditional" or "unknown".

  • details (tuple[AssessmentDetail, ...]) –

    The AssessmentDetail records, partial knowledge included.

AssessmentDetail

Bases: Record

One scoped conclusion of a device forecast, with the value and limit it compares.

Read it from AxisAssessment.details. The fields below are read-only. A detail holds either a resource value (fact) or a method statement (statement), never both, because they are different quantities.

Attributes:

  • quantity (Text) –

    The quantity compared, such as a memory peak.

  • scope (Text) –

    Where the quantity applies, such as one granted location.

  • status (Outcome) –

    "feasible", "infeasible", "conditional" or "unknown".

  • reason (Text) –

    Why the detail has its status.

  • fact (Fact | None) –

    The resource value compared, or None.

  • resource_id (ContentID | None) –

    Content hash of the resource quantity in the estimate, or None.

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

    Content hashes of the time predictions this detail summarizes.

  • limit (Limit | None) –

    The supplied Limit it was compared with, unchanged, or None.

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

    Content hashes of the declarations and records used.

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

    Assumptions the conclusion rests on.

  • statement (FramedFact | None) –

    The method's complete stated assumption or claim, or None.

TimePrediction

Bases: Record

The prediction of one time model for one point, in seconds, with its interval and the feature counts it used.

Read it from ProfileAssessment.predictions. The fields below are read-only. The answer is seconds.value, a prediction for the model's scope, not an observed elapsed time and not permission to run. When an input is missing, seconds is None and reasons says why. An interval keeps the kind and coverage of the model's uncertainty, so a confidence interval for a mean never becomes a bound on a single run.

Attributes:

  • model_id (ContentID) –

    Content hash of the time model.

  • point_id (ContentID) –

    Content hash of the assessed point.

  • form (Literal['acquisition_linear/1']) –

    "acquisition_linear/1".

  • scope (TimeScope) –

    The model's time scope, copied from the model.

  • seconds (Float64 | None) –

    Nonnegative predicted seconds, or None when unavailable.

  • unit (Unit) –

    Seconds.

  • lower_seconds (Float64 | None) –

    Lower end of the interval, at least zero, or None.

  • upper_seconds (Float64 | None) –

    Upper end of the interval, or None.

  • uncertainty (ModelUncertainty | None) –

    The model's ModelUncertainty, or None.

  • features (tuple[Fact, ...]) –

    The feature counts the prediction used.

  • evidence (Evidence) –

    Evidence that names the model's source.

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

    Why the prediction is unavailable. Empty when it is available.

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

    Assumptions the prediction rests on.

Compare forecasts with observed timings

After a Run prepared with a PlanEstimate finishes, align_telemetry(run) pairs each attempt's forecast with its observed timing.

align_telemetry

align_telemetry(run_or_result=None, *, trace: ExecutionTrace | None = None, assessments: tuple[ProfileAssessment, ...] = (), receipts: tuple[PreparedArtifact, ...] = (), observations: ObservationView | None = None, timings: tuple[AttemptTiming, ...] = (), result: Record | None = None, max_comparisons: int = 100000) -> PredictionLedger

Pair the forecasts of a Run with its observed timings and return the signed residuals.

Pass a Run or a completed Result, for example align_telemetry(run), to read its execution record, preparation records, observations and the forecast it was prepared with. The returned PredictionLedger keeps every attempt, failures and partial collections included. A residual observed_seconds - predicted_seconds is formed only when the attempt was bound to its forecast before it started, its data collection completed, and an exact timing of the forecast's scope exists. Every other attempt keeps its forecast with the reason it has no residual, so a runtime or compiler mismatch, a missing scope or preparation record, a failed collection or a right-censored timing stays visible. A right-censored timing is a lower bound, never an exact residual. Nothing is executed, assessed again or fitted, no provider is contacted, and no histogram or backend payload is copied into it. A residual makes no coverage claim, and a historical residual does not establish that the device calibration was valid when the job ran. The telemetry section of the profiles guide describes the pairing rules.

Parameters:

  • run_or_result (Run | Result | None, default: None ) –

    The Run or Result to read. With None, pass trace and the other records explicitly.

  • trace (ExecutionTrace | None, default: None ) –

    Execution record, when no Run or Result is given.

  • assessments (tuple[ProfileAssessment, ...], default: () ) –

    Forecasts to pair. Empty uses the forecast the Run was prepared with.

  • receipts (tuple[PreparedArtifact, ...], default: () ) –

    Preparation records, when no Run or Result is given.

  • observations (ObservationView | None, default: None ) –

    Observations, when no Run or Result is given.

  • timings (tuple[AttemptTiming, ...], default: () ) –

    Additional supplied timings. Each must belong to an attempt of this run. Identical timings of one attempt count once, and different attempts stay distinct.

  • result (Record | None, default: None ) –

    The analysis Result whose contributions are recorded, when no Run or Result is given.

  • max_comparisons (int, default: 100000 ) –

    Positive limit on the forecast and timing pairs formed.

Returns:

Raises:

  • TypeError –

    If no execution record or RunData is available.

  • ValueError –

    If a Run or Result is mixed with explicit records, a timing or record belongs to another run, attempt or Plan, identities conflict, or the pairs exceed max_comparisons.

PredictionLedger

Bases: Record

The forecasts of one Run paired with its observed timings, attempt by attempt.

align_telemetry returns it. The fields below are read-only. Each row holds one attempt's execution event, its timings, the observations it collected and its forecast comparisons, where residual_seconds is the signed observed - predicted seconds or None with the reasons. Collected observations and the contributions of the Result stay separate lists. Use revise to record a new version of supplied data. It never fits coefficients or changes the original assessments, model domains, calibration status or coverage. A forecast is valid at its original assessment time, and a historical residual does not establish that calibration was valid when the job ran.

Attributes:

  • trace_id (ContentID) –

    Content hash of the Run's execution record.

  • run_id (Text) –

    ID of the Run.

  • plan_id (ContentID) –

    Content hash of the Plan.

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

    Content hashes of the forecasts used.

  • predictions (tuple[TimePrediction, ...]) –

    The original TimePrediction records.

  • rows (tuple[TelemetryRow, ...]) –

    One row per attempt, failures, partial collections and right-censored timings included.

  • result_id (ContentID | None) –

    Content hash of the analysis Result, or None. It does not imply that the Result is scientifically valid.

validate_context

validate_context(*, trace, assessments)

Check that a saved PredictionLedger still matches its execution record and forecasts, without recomputing anything.

Parameters:

Returns:

Raises:

  • ValueError –

    If the record differs from the execution record, uses a forecast of another Plan or attempt, or changed its predictions.

AttemptTiming

Bases: Record

A timing that the caller measured for one attempt of a Run, to pair with its forecast.

Build it with keyword arguments, for example AttemptTiming(run_id=..., attempt=..., prepared_id=..., timing=...), and pass it in timings= of align_telemetry. Every field is required. The timing is either an exact duration or a right-censored lower bound, with its source. Distinct attempts stay distinct even when their timings agree.

Attributes:

  • run_id (Text) –

    Required. ID of the Run.

  • attempt (Text) –

    Required. ID of the attempt in the Run's execution record.

  • prepared_id (ContentID) –

    Required. Content hash of the preparation record the attempt used.

  • timing (TimingObservation) –

    Required. The TimingObservation: scope, nonnegative seconds, "exact" or "right_censored", and source. A right-censored timing needs the reason for its cutoff.

Export OpenQASM

export_qasm converts any Qiskit circuit to OpenQASM 3 or 2. write_qasm3_file and write_qasm3 write a Plan's circuit (plan.construction) as OpenQASM 3 without a quantum SDK, for the constructions listed in Export OpenQASM, and materialize_qasm3_file imports such a file back into Qiskit after checking its bytes.

export_qasm

export_qasm(circuit: QuantumCircuit, *, format: str = 'qasm3', path: str | Path | None = None, max_text_bytes: int = DEFAULT_MAX_BYTES, max_operations: int = 100000) -> str | Path

Return the OpenQASM 3 or 2 text of a Qiskit circuit, or write it to a file.

Use it for any built Qiskit circuit, for example one from prepared.circuit(0) or lower_qiskit. Without path it returns the text. With path it writes a temporary file in the same directory and replaces the destination only after the export succeeds, so a failed export leaves an earlier file unchanged. It does not transpile or simulate. Qiskit's OpenQASM 3 exporter streams the text but still builds a complete syntax tree, and its OpenQASM 2 exporter builds the whole string first, so for OpenQASM 2 max_text_bytes limits only the returned or written text. Neither limit bounds expanded gate definitions or Qiskit's workspace.

Parameters:

  • circuit (QuantumCircuit) –

    The circuit to export.

  • format (str, default: 'qasm3' ) –

    "qasm3" or "qasm2".

  • path (str | Path | None, default: None ) –

    A file path whose parent directory exists, or None to return the text.

  • max_text_bytes (int, default: DEFAULT_MAX_BYTES ) –

    Default 10 GB (decimal, 10_000_000_000 bytes). Positive limit on the UTF-8 bytes of the exported text.

  • max_operations (int, default: 100000 ) –

    Positive limit on the top-level instructions of circuit, checked before export.

Returns:

  • output ( str | Path ) –

    The OpenQASM text, or the destination path when path is given.

Raises:

  • ValueError –

    If format is not "qasm2" or "qasm3", a limit is not a positive integer, the circuit has more than max_operations instructions, or the text exceeds max_text_bytes.

  • TypeError –

    If circuit is not a Qiskit QuantumCircuit.

Examples:

>>> from qiskit import QuantumCircuit
>>> from nwqlib.io import export_qasm
>>> bell = QuantumCircuit(2)
>>> _ = bell.h(0)
>>> _ = bell.cx(0, 1)
>>> print(export_qasm(bell))
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
h q[0];
cx q[0], q[1];

write_qasm3_file

write_qasm3_file(construction, path, *, budget: QasmWriteBudget, cancel=None) -> QasmWriteReceipt

Write a Program's circuit as an OpenQASM 3 file, replacing the destination only when the write is complete.

It writes the text as write_qasm3 does, into a temporary file in the destination's directory, and replaces the destination only after the text and its QasmWriteReceipt are complete. On failure or cancellation it removes the temporary file and leaves an existing destination unchanged. No fsync or durability across power loss is promised.

Parameters:

  • construction (SelectedConstruction) –

    The Program and its selected definitions, such as plan.construction.

  • path (str | Path) –

    Destination file. Its directory must exist.

  • budget (QasmWriteBudget) –

    The limits.

  • cancel (Callable[[], bool] | None, default: None ) –

    Called between writes, and a true result stops the write.

Returns:

Raises:

  • ValueError –

    If the construction is outside the writer subset or exceeds budget, before any file is created.

  • QasmWriteError –

    If writing fails after it started. Its prefix describes the text already delivered, its temporary names the temporary file if it could not be removed, and secondary holds later cleanup failures. An exception that is not an Exception, such as KeyboardInterrupt, keeps its type, with cleanup failures in its notes.

write_qasm3

write_qasm3(construction, sink, *, budget: QasmWriteBudget, cancel=None) -> QasmWriteReceipt

Write a Program's circuit as OpenQASM 3 text to a binary stream, without any quantum SDK.

The construction must use the writer subset of the OpenQASM guide: exact gate recipes, sequences, bound repeats written as loops, allocation, computational measurement and reset, and at most one batch setting. Other constructions, such as generic state preparation or Pauli SELECT blocks, are rejected before any text is written. The sink's write must return a positive integer no larger than the buffer offered, and a partial write is completed before more text is produced. Cancellation is checked between writes, so a blocking write cannot be interrupted.

Parameters:

  • construction (SelectedConstruction) –

    The Program and its selected definitions, such as plan.construction.

  • sink (BinaryIO) –

    Binary stream with a write method.

  • budget (QasmWriteBudget) –

    The limits.

  • cancel (Callable[[], bool] | None, default: None ) –

    Called between writes, and a true result stops the write.

Returns:

Raises:

  • ValueError –

    If the construction is outside the writer subset or exceeds budget, before any text is written.

  • QasmWriteError –

    If writing fails after it started. Its prefix describes the text already delivered.

QasmWriteBudget

Bases: Record

Limits for writing a Program as OpenQASM 3 text with write_qasm3 or write_qasm3_file.

Build it with keyword arguments, for example QasmWriteBudget(max_metadata_bytes=1_000_000, max_walk_steps=100_000, max_qubits=1, max_clbits=0, max_bytes=4096, max_instructions=100, max_chunk_bytes=256), and pass it as budget=. Every field is required. The graph and metadata checks run before any text is written. The limits do not grow with the count of a Repeat, which the text writes as one loop.

Attributes:

  • max_metadata_bytes (Count) –

    Required. Limit in bytes on a conservative JSON size of the Program graph and of the final QasmWriteReceipt, each checked before it is used.

  • max_walk_steps (Count) –

    Required. Limit on the steps of each walk over the graph and of the counting and writing passes. A Repeat count is not multiplied in.

  • max_qubits (Count) –

    Required. Limit on the total declared qubits.

  • max_clbits (Count) –

    Required. Limit on the total declared classical bits.

  • max_bytes (Count) –

    Required. Limit on the bytes of text written.

  • max_instructions (Count) –

    Required. Limit on the gate, measurement and reset statements in the text, gate definitions included.

  • max_chunk_bytes (PositiveInt) –

    Required. Positive. Limit in bytes on each buffer offered to the sink. It does not bound how long a blocking sink takes.

QasmWriteReceipt

Bases: Record

The record of a completed OpenQASM 3 file or stream: what was written, its layouts, counts and digest.

write_qasm3 and write_qasm3_file return it, and materialize_qasm3_file checks a file against it. The fields below are read-only. The text describes one circuit template. Writing it runs nothing and collects no observation. The counts are syntactic. They count no shots, gate synthesis or SDK memory, and they are not hardware estimates.

Attributes:

  • construction_id (str) –

    Content hash of the written construction.

  • subset (Literal['nwqlib.direct-qasm3.v1']) –

    "nwqlib.direct-qasm3.v1", the supported subset of OpenQASM 3.0 with stdgates.inc.

  • angle_convention (Literal['binary64-repr']) –

    "binary64-repr", meaning that each angle is the shortest decimal that rounds back to the same binary64 value.

  • selected_definitions (tuple[str, ...]) –

    Content hashes of the block recipes reachable from the root.

  • quantum_layout (tuple[tuple[str, str, Count], ...]) –

    (original name, generated name, width) of each quantum register, in declaration order. Qubit index 0 is the least significant bit.

  • classical_layout (tuple[tuple[str, str, Count], ...]) –

    The same for each classical register.

  • batch_repetitions (Count | None) –

    Repetitions of the measurement batch, kept here and not written as a loop, or None.

  • observation_kind (str | None) –

    Observation kind of the batch, or None.

  • setting_label (str | None) –

    Label of the one written setting, or None.

  • bytes_written (Count) –

    Bytes of text written, punctuation included.

  • emitted_instructions (Count) –

    Gate, measurement and reset statements written, counting a definition body once for each time it appears in the text.

  • expanded_operations (Count) –

    Primitive gates plus one per measured or reset bit, after expanding loops and calls.

  • dynamic_visits (Count) –

    Visits to Program nodes, empty calls and loop bodies included.

  • digest (str) –

    sha256: digest of the text.

  • completion (Literal['stream', 'file']) –

    "stream" from write_qasm3 or "file" from write_qasm3_file.

  • native_bytes (None) –

    Always None, because the SDK memory is not known.

  • peak_rss (None) –

    Always None, because peak process memory is not known.

QasmWriteError

QasmWriteError(message, prefix, *, secondary=(), temporary=None)

Bases: RuntimeError

Raised when writing OpenQASM 3 text fails after the limit checks passed.

prefix is the QasmPrefix of the text already delivered, and __cause__ is the original failure. secondary holds the failures of closing or cleaning up, in the order they occurred. temporary names the temporary file of write_qasm3_file that could not be removed, or is None.

QasmPrefix

QasmPrefix(bytes_written: int, emitted_instructions: int, digest: str)

The text that a failed OpenQASM 3 write had already delivered, never a completed file.

Read it from QasmWriteError.prefix. The fields below are read-only.

Attributes:

  • bytes_written (int) –

    Bytes the sink accepted.

  • emitted_instructions (int) –

    Statements the sink accepted completely.

  • digest (str) –

    sha256: digest of exactly the accepted bytes.

materialize_qasm3_file

materialize_qasm3_file(construction, path, receipt: QasmWriteReceipt, *, writer_budget: QasmWriteBudget, budget: QasmMaterializationBudget) -> QasmMaterialization

Import an OpenQASM 3 file written by write_qasm3_file into Qiskit, after checking its bytes against the construction.

The sizes are derived again from the construction and checked against budget before the file is opened. The text is then written again into a digest to rebuild the QasmWriteReceipt, and the file is read once and its bytes and digest compared with receipt, so a QasmWriteReceipt alone cannot vouch for other text. Those same bytes go to Qiskit's OpenQASM 3 importer and the UnrollForLoops pass. Gate definitions stay logical. Z with more than two controls in total is rejected before import, because the installed importer can synthesize such gates eagerly. It needs the qasm extra (pip install "nwqlib[qasm]"). The checked combination is OpenQASM parser 1.0.1, qiskit-qasm3-import 0.6.0 and Qiskit 2.5.2.

Parameters:

  • construction (SelectedConstruction) –

    The construction the file was written from.

  • path (str | Path) –

    The file.

  • receipt (QasmWriteReceipt) –

    The record that write_qasm3_file returned.

  • writer_budget (QasmWriteBudget) –

    The budget the file was written with.

  • budget (QasmMaterializationBudget) –

    The import limits.

Returns:

  • materialization ( QasmMaterialization ) –

    The imported circuit and its verified QasmWriteReceipt.

Raises:

  • ValueError –

    If the construction exceeds budget, budget asks for a memory bound, a Z gate has more than two controls, or the receipt or the file bytes do not match the construction.

QasmMaterializationBudget

Bases: Record

Limits for importing an OpenQASM 3 file back into Qiskit with materialize_qasm3_file.

Build it with keyword arguments, for example QasmMaterializationBudget(max_bytes=4096, max_qubits=1, max_clbits=0, max_dynamic_visits=100, max_operations=100), and pass it as budget=. The first five fields are required. The counts are derived from the construction and checked before the file is opened. No limit here estimates the importer's memory.

Attributes:

  • max_bytes (Count) –

    Required. Limit on the bytes of the file text.

  • max_qubits (Count) –

    Required. Limit on the total declared qubits.

  • max_clbits (Count) –

    Required. Limit on the total declared classical bits.

  • max_dynamic_visits (Count) –

    Required. Limit on Program node visits after expanding loops, empty and identity loops included.

  • max_operations (Count) –

    Required. Limit on primitive gate, measurement and reset applications after expanding loops. Gates that Qiskit synthesizes for controls are not counted.

  • required_max_native_bytes (Count | None) –

    Default None, the only accepted value. Any other value is rejected before import, because this importer cannot bound its memory.

  • required_max_peak_rss (Count | None) –

    Default None, the only accepted value, for the same reason.

QasmMaterialization

QasmMaterialization(circuit: object, source: QasmWriteReceipt, output_nodes: int, native_bytes: None = None, peak_rss: None = None)

A Qiskit circuit imported from a verified OpenQASM 3 file, with its loops unrolled.

materialize_qasm3_file returns it. The fields below are read-only. Gates are not decomposed and nothing is simulated.

Attributes:

  • circuit (object) –

    The imported Qiskit circuit without loops. Gate definitions from the file stay as logical gates.

  • source (QasmWriteReceipt) –

    The verified QasmWriteReceipt.

  • output_nodes (int) –

    Top-level instructions of circuit after unrolling. It can differ from source.expanded_operations.

  • native_bytes (None) –

    Always None, because the allocation size is not known.

  • peak_rss (None) –

    Always None, because peak process memory is not known.