SDK: results, events and circuit records
Reference for qsolve.results, qsolve.events and qsolve.circuit_record: every field of Result, MethodResult, Metrics, Quality, Mitigation, CircuitStats, Provenance, Uncertainty and Estimate, plus emit, capture and the drawable circuit records.
Updated 13 November 2026 View as markdown
On this page
What a run produces. You never build these objects in a workflow (except Estimate); the SDK builds them from what it measured and you read them in qsolve run --out, in tests and on the platform's run page. All are pydantic models: model_dump(mode="json") gives plain JSON and Model.model_validate(data) reads it back. Back to the SDK reference.
qsolve.results
from qsolve import Estimate, Mitigation, Provenance, Quality, Result, Uncertainty # top level
from qsolve.results import CircuitStats, MethodResult, Metrics # module only
Who measures what: the numbers are computed by the SDK; the words (title, what, strength, limit, note) are declared by your manifest. See Reading your results for how a user sees them.
Result
The final, user-facing result of one run (RunOutput.result).
| Field | Type | Default | Meaning |
|---|---|---|---|
answer |
dict[str, Any] |
required | The quantum method's answer(), validated against the output schema. |
objective |
float |
required | The quantum method's objective, recomputed by evaluate when it gave a solution. |
baseline_objective |
float |
required | The reference method's objective. |
baseline_solver |
str |
required | The reference method's manifest title. |
gap |
float |
required | (objective - baseline) / max(abs(baseline), eps); 0 means it matched the baseline; negative means better. |
uncertainty |
Uncertainty |
required | See below. |
summary |
str |
"" |
One sentence, at most 500 characters. |
artifacts |
dict[str, Any] |
{} |
Reserved for extra output; the SDK leaves it empty. |
quality |
Quality | None |
None |
Fidelity and circuit size of the quantum run. |
methods |
list[MethodResult] |
[] |
Every declared method, in manifest order. |
metrics |
Metrics | None |
None |
The headline accuracy. |
Uncertainty
| Field | Type | Default | Meaning |
|---|---|---|---|
kind |
str |
required | "sampling", "exact" or "heuristic". run_workflow writes sampling when the quantum method gave a stderr, otherwise exact. |
stderr |
float | None |
None |
One standard deviation on the quantum value. |
note |
str |
"" |
Text, for example one standard deviation on the quantum value. |
MethodResult
One method, quantum or classical, run on this input.
| Field | Type | Default | Meaning |
|---|---|---|---|
id |
str |
required | The manifest method id. |
role |
str |
required | quantum, reference or classical. |
title, what, strength, limit |
str |
"" except title |
Declared in the manifest. |
value |
float | None |
None |
The objective this method reached (lower is better); None when unavailable. |
stderr |
float | None |
None |
The method's own error bar. |
vs_reference |
float | None |
None |
(value - reference) / max(abs(reference), eps); 0 means the same. |
seconds |
float | None |
None |
Wall-clock seconds for the method. The only field that differs run to run; it is excluded from the reproducibility hash. |
verified |
str |
"reported" |
recomputed when the SDK evaluated the method's solution with your evaluate; reported when it is the workflow's claim with no solution to re-evaluate. |
dispatches |
int |
0 |
Circuits this method sent to the backend (the quantum method must send at least one). |
claimed |
float | None |
None |
What the method itself reported, set only when it disagreed with the recomputed value. A set claimed fails validation. |
unavailable |
str |
"" |
Why the method could not run on this input. |
p_reference |
float | None |
None |
For sampling methods: the share of samples on the reference answer. |
valid_fraction |
float | None |
None |
For sampling methods: the share of samples that are valid answers. |
top_outcomes |
list[dict] |
[] |
The five most probable outcomes: {"outcome": str, "p": float}. |
answer |
dict | None |
None |
This method's answer(), when it succeeded. |
Metrics
The headline numbers, computed by the SDK (headline).
| Field | Type | Default | Meaning |
|---|---|---|---|
kind |
str |
required | relative_gap, relative_error or error_rate (from the manifest). |
accuracy |
float |
required | 0 to 1: how close the quantum result is to the reference. |
accuracy_pm |
float | None |
None |
Its plus or minus (one sigma, or a 95% interval half-width for an error rate). |
note |
str |
"" |
How it was computed, in your words (manifest metric.note). |
tolerance |
float |
0.0 |
The manifest's metric.tolerance. |
matches |
bool |
False |
The platform's verdict: equal to the reference, within a declared tolerance, or statistically indistinguishable from it. |
Quality
| Field | Type | Default | Meaning |
|---|---|---|---|
mitigation |
Mitigation | None |
None |
Fidelity of the quantum run. |
circuit |
CircuitStats | None |
None |
Size of what was sent. |
Mitigation
Fidelity of the quantum run. The raw figure is measured by the SDK; the mitigated figure is what your own post-processing reports, recomputed against the ideal output. See Error mitigation and fidelity and Metering and cost.
| Field | Type | Default | Meaning |
|---|---|---|---|
fidelity_raw |
float |
required | Measured against the ideal distribution, before any mitigation. |
fidelity_mitigated |
float |
required | After the listed methods; equals the raw figure when you reported nothing. |
reported |
bool |
False |
True when the mitigated figure comes from your report. |
fidelity_floor |
float |
required | The best a noise-free device scores at this shot count. |
postselection_rate |
float |
required | Share of shots that pass your checks (1.0 means nothing discarded). |
methods |
list[str] |
[] |
Mitigation methods you named. |
source |
str |
required | hardware, noise_model or ideal_simulator. |
coverage |
float |
1.0 |
Share of the quantum method's shots that could be scored (not circuits over 20 qubits or with mid-circuit measurement). |
details |
dict[str, Any] |
{} |
Holds steps, your fidelity ladder, when reported. |
CircuitStats
Size of what the quantum method actually sent, measured by the SDK.
| Field | Type | Default | Meaning |
|---|---|---|---|
qubits |
int |
required | Width of the widest circuit (active qubits). |
depth |
int |
required | Greatest depth after transpiling to cx, rz, sx, x. |
two_qubit_gates |
int |
required | Greatest cx count after transpiling. |
circuits |
int |
0 |
Circuits sent in total. |
shots |
int |
0 |
Shots over all of them. |
Provenance
Immutable record of how a result was produced (RunOutput.provenance).
| Field | Type | Default | Meaning |
|---|---|---|---|
run_id |
str |
required | A new UUID for each run. |
workflow, version |
str |
required | Manifest name and version. |
commit_sha, image_digest |
str | None |
None |
As passed to run_workflow. |
sdk_version |
str |
required | qsolve.__version__ at run time. |
input_hash |
str |
required | SHA-256 of the input's canonical JSON, floats rounded to 1e-6. |
params |
dict |
required | The resolved parameters. |
seed |
int |
required | The seed. |
target |
str |
required | The backend's target class: sim-cpu, sim-gpu or qpu. |
provider, device |
str |
required | For example aer and aer-cpu; fake and fake_fez@1.6; ibm and ibm_fez. |
calibration_snapshot |
dict |
{} |
The backend's calibration_snapshot(). |
shots |
int |
0 |
Total shots the quantum method sent. |
exec_time_s |
float |
0.0 |
Wall-clock seconds of the whole run. |
started_at, finished_at |
str |
required | ISO 8601 UTC timestamps. |
result_hash |
str |
required | SHA-256 of the result with each method's seconds set to null. The reproducibility gate compares it. |
solver |
dict |
{} |
{"name": <quantum method id>, "details": <Outcome.details as plain JSON>}. Not hashed. |
Estimate
The pre-run resource estimate, and the one result type you construct yourself. Its fields, and how the platform uses it, are in Metering and cost.
qsolve.events
from qsolve.events import Sink, capture, emit
Structured run events. Solvers and workflows call emit; the runner (or the platform) installs a sink that streams them to the run page and log store. With no sink installed emit costs nothing.
| Name | Signature | Meaning |
|---|---|---|
Sink |
Callable[[dict[str, Any]], None] |
The type of an event receiver. |
emit |
emit(type: str, **data: Any) -> None |
Sends {"type": type, "t": time.time(), **data} to the installed sink, if any. Never raises: an exception in the sink is swallowed because observability must never break a run. In a workflow use ctx.emit, which is this function. |
capture |
capture(sink: Sink | None) -> ContextManager[None] |
Installs sink for the duration of a with block (a ContextVar, so it is per thread and per async task) and restores the previous one afterwards. None turns events off. run_workflow(..., on_event=f) is capture(f) around the run. |
from qsolve.events import capture, emit
seen = []
with capture(seen.append):
emit("train_step", step=1, value=-1.2)
print(seen[0]["type"], seen[0]["step"]) # train_step 1
Events the runner emits itself: stage with stage set to build, run (also carrying device and target) and compare. Event payloads must be JSON-serialisable; the sandbox converts non-finite floats to null.
qsolve.circuit_record
from qsolve.circuit_record import DRAWABLE, active_qubits, circuit_ops, circuit_summary, lowered
Circuits as compact, drawable records: what the platform shows on a run page. A viewer can draw or export them without Qiskit.
| Name | Signature | Meaning |
|---|---|---|
DRAWABLE |
set[str] |
Gate names a viewer can draw and OpenQASM 2 can express (h, cx, rz, measure, barrier, ... 38 names), plus non-unitary operations. |
lowered |
lowered(circuit) -> QuantumCircuit |
Expands every operation outside DRAWABLE by decomposing, for at most 8 rounds. Opaque operations without a definition stay as they are and are drawn as labelled boxes. |
circuit_ops |
circuit_ops(circuit, max_ops=20_000) -> dict |
{"qubits": int, "clbits": int, "ops": [[name, [qubit indices], [params], [clbit indices]], ...], "truncated": bool} of the lowered circuit. Parameters are rounded to 6 places; an unbound parameter is its name; delay ops have no params. Qubit indices are positions in the circuit (physical qubits for a transpiled circuit). Stops at max_ops and sets truncated. |
circuit_summary |
circuit_summary(circuit) -> dict |
{"qubits", "clbits", "size", "depth", "two_qubit_gates", "ops": {name: count}} without lowering: cheap enough for every circuit a run sends. Two-qubit gates exclude barriers. |
active_qubits |
active_qubits(circuit) -> list[int] |
Sorted qubit indices that some operation touches (barriers included). Not to be confused with qsolve.metering.active_qubits, which returns a count. |
from qsolve.circuit_record import circuit_ops
rec = circuit_ops(qc)
print(rec["ops"][:3]) # [["h", [0], [], []], ["cx", [0, 1], [], []], ...]