Repository navigation
QPU Digital Twins
Build a calibration-conditioned model of a mapped quantum processor, predict measurement distributions, and compare frozen predictions with traceable hardware results.
Scope: FlagQuantum 0.3.1, checked on October 20, 2026. Five complete offline examples below were executed with Python 3.12.14, PyTorch 2.13.0, and macOS ARM64. All calibration values and count fixtures in those examples are synthetic. The account-dependent Quafu script had its CLI checked and its native Bell circuit verified locally; no provider calibration was fetched and no real hardware task was submitted for this page.
Use Noise and Open-System Simulation, Cloud and Quantum Hardware Execution, and Qubit Ordering and Result Conventions alongside this guide.
Formula/code review — October 20, 2026: The equations are paired with code excerpts, and the local CPU examples were re-run with Python 3.12.14 and PyTorch 2.13.0. See the review record for executed commands, distributed checks, and untested hardware/provider paths. Earlier environment and output records are retained.
A QPUDigitalTwin combines a frozen calibration snapshot, an explicit logical-to-physical qubit mapping, and a provider-neutral noise model. predict(circuit) returns both ideal and model-conditioned full computational-basis output distributions.
A useful workflow is:
- Obtain calibration, units, timestamp, physical topology, and any measured readout matrices.
- Select an ordered physical mapping and construct a noise model for those logical wires.
- Freeze and save the twin before inspecting the hardware outcomes used for validation.
- Predict and freeze a circuit/measurement experiment.
- Submit the exact mapped experiment, retain its receipt, and validate the returned result against it.
- Compare distributions with finite-shot uncertainty and repeated hardware runs.
- Track calibration drift and revalidate the scope that matters to the application.
The model is a prediction under explicit assumptions. Creating it, fitting it to existing counts, or labeling a dictionary “hardware” does not establish hardware agreement or prospective validation.
| Object / operation | Purpose |
|---|---|
fq.twin.from_noise_model |
Construct offline from a NoiseModel containing a DeviceNoiseProfile. |
fq.twin.from_quafu_chip_info |
Convert a supplied native Quafu calibration dictionary locally. Fetching that dictionary is a separate provider operation. |
twin.snapshot |
Identify provider, backend, timestamp, ordered physical mapping, calibration, and noise model. |
twin.predict |
Compute ideal and noisy/readout-conditioned probabilities for one circuit. |
prediction.compare_counts |
Compare a count dictionary arithmetically; it does not establish task provenance. |
TwinExperiment / TwinSubmission
|
Freeze the prediction/program and bind a submitted Quafu task to that experiment. |
| Validation series and evidence reports | Summarize bound results, repeated measurements, finite-shot bounds, and the supported scope. |
Create a supported core environment using Installation and Compatibility:
python -m pip install "flagquantum==0.3.1" numpy
python -m pip checkCore requirements are Python 3.10–3.12 and PyTorch >=2.10,<2.15. The offline examples require no provider SDK, credentials, or hardware. Save all scripts in the same directory, since examples 2, 3, and 5 import the model helper from example 1.
The demonstrated prediction path uses an exact dense density matrix on CPU. It requires an fq.Circuit matching the mapping width and one circuit batch; it is not a distributed, MPS, GPU, or differentiable twin-training interface. Dense density storage grows as 4**n, with additional intermediate/output memory.
Save as twin_model.py:
import flagquantum as fq
from flagquantum.noise import (
DeviceNoiseProfile, GateDuration, NoiseModel, QubitNoiseCalibration,
ReadoutError, two_qubit_depolarizing_channel,
)
# Synthetic calibration for documentation; no real device is characterized.
def build_twin(*, t1_scale=1.0, captured_at='2026-10-20T00:00:00+00:00'):
profile = DeviceNoiseProfile(
qubits=(
QubitNoiseCalibration(0, t1=50.0*t1_scale, t2=70.0,
readout_error=ReadoutError(((0.98, 0.02), (0.05, 0.95)))),
QubitNoiseCalibration(1, t1=48.0*t1_scale, t2=65.0,
readout_error=ReadoutError(((0.97, 0.03), (0.04, 0.96)))),
),
gate_durations=(GateDuration('h', 0.035), GateDuration('cx', 0.280)),
source='wiki-synthetic-calibration', captured_at=captured_at, time_unit='us',
)
noise = NoiseModel.from_device_profile(profile)
noise.add('cx', two_qubit_depolarizing_channel(0.03))
return fq.twin.from_noise_model(noise, target='example:synthetic-qpu', qubits=(12, 13))
def bell_circuit():
return fq.Circuit(2).h(0).cx(0, 1)
if __name__ == '__main__':
twin = build_twin()
circuit = bell_circuit()
prediction = twin.predict(circuit)
assert abs(sum(prediction.twin_probabilities) - 1) < 1e-6
assert prediction.total_variation_from_ideal > 0
report = twin.evidence_report(circuit)
assert report.status == 'unverified'
print('Logical-to-physical mapping:', twin.snapshot.physical_qubits)
print('Ideal probabilities:', [round(p, 6) for p in prediction.ideal_probabilities])
print('Twin probabilities:', [round(p, 6) for p in prediction.twin_probabilities])
print(f'Twin versus ideal TVD: {prediction.total_variation_from_ideal:.6f}')
print('Evidence status:', report.status)Run python twin_model.py. Expected output:
Logical-to-physical mapping: (12, 13)
Ideal probabilities: [0.5, 0.0, 0.0, 0.5]
Twin probabilities: [0.469947, 0.04788, 0.037984, 0.444189]
Twin versus ideal TVD: 0.085864
Evidence status: unverified
The profile's wires are logical indices 0 and 1. The ordered mapping (12, 13) says logical qubit 0 is physical 12 and logical qubit 1 is physical 13; reversing that tuple changes the experiment. The illustrative target example:synthetic-qpu identifies no real provider.
T1, T2, and gate durations share the declared microsecond unit. The model combines timing-derived relaxation, an explicit two-qubit depolarizing rule, and readout confusion. Readout rows are true states and columns are observed states. predict applies the configured readout transformation to the evolved distribution; do not apply it again when comparing these returned probabilities.
Use floating-point calibration times and durations consistently for serialization in 0.3.1, as discussed in Noise and Open-System Simulation. Gate durations and applicable calibrations must cover the instructions being simulated. The snapshot does not infer missing gate durations, physical connectivity, routing, or an accurate noise model merely from a target name.
from_noise_model freezes a serialized copy of the input. The contained noise model still has mutable Python/tensor internals; changing it afterward invalidates the frozen identity and can be rejected at prediction time. Build a new twin for a changed model.
Save as twin_quafu_fixture.py:
import flagquantum as fq
# Synthetic payload in the adapter's expected chip_info schema.
chip_info = {
'calibration_time': '2026-10-20T00:00:00+00:00',
'basis_gates': ['h', 'cz'],
'qubits_info': {
'Q12': {'T1': 50.0, 'T2': 70.0, 'length': 35e-9, 'fidelity': 0.999},
'Q13': {'T1': 48.0, 'T2': 65.0, 'length': 35e-9, 'fidelity': 0.998},
},
'couplers_info': {
'C12_13': {'qubits_index': [12, 13], 'length': 280e-9, 'fidelity': 0.98},
},
}
twin = fq.twin.from_quafu_chip_info(
chip_info, target='quafu:synthetic-fixture', qubits=(12, 13),
readout_confusion_matrices=(
((0.98, 0.02), (0.05, 0.95)),
((0.97, 0.03), (0.04, 0.96)),
),
)
# Use an explicit CZ spelling so the calibrated CZ noise rule is exercised.
circuit = fq.Circuit(2).h(0).h(1).cz(0, 1).h(1)
prediction = twin.predict(circuit)
assert abs(sum(prediction.twin_probabilities) - 1) < 1e-6
assert twin.noise_model.device_profile.time_unit == 's'
print('Input: synthetic Quafu-format payload; no provider contacted.')
print('Converted time unit:', twin.noise_model.device_profile.time_unit)
print('Logical qubit 0 T1 in seconds:', f'{twin.noise_model.device_profile.qubits[0].t1:.8f}')
print('Twin probabilities:', [round(p, 6) for p in prediction.twin_probabilities])
print('Evidence status:', twin.evidence_report(circuit).status)Run python twin_quafu_fixture.py. Expected output:
Input: synthetic Quafu-format payload; no provider contacted.
Converted time unit: s
Logical qubit 0 T1 in seconds: 0.00005000
Twin probabilities: [0.468324, 0.049841, 0.037326, 0.444509]
Evidence status: unverified
This tests the schema conversion, not Quafu's current calibration or device availability. In the release adapter, Quafu T1/T2 values are interpreted as microseconds and gate lengths as seconds, then converted to one seconds-based profile. One-qubit average fidelities are mapped to total Pauli-depolarizing probabilities with p=3/2*(1-F); two-qubit CZ fidelities use p=5/4*(1-F), subject to the factory's bounds.
These are model assumptions. Average gate fidelity does not uniquely determine a noise channel, and combining fidelity-derived and relaxation terms requires care about which physical error sources the calibration already includes.
The example explicitly uses CZ so that the calibrated CZ noise rule is exercised. In this release, the native adapter supplies CX timing from the same coupler but attaches the two-qubit fidelity-derived depolarizing rule to CZ. A logical CX circuit therefore must not be assumed to have the identical modeled error placement as its provider-compiled CZ decomposition. Inspect the gate spelling and lowered noise rules used by the actual comparison.
Measured independent or correlated readout confusion matrices can be supplied, with the factory accepting one form at a time. Missing or placeholder readout calibration must not be interpreted as measured perfect readout. Omitting those matrices leaves that readout contribution unmodeled.
The corresponding live pattern is QuafuProvider().fetch_chip_info(backend) followed by from_quafu_chip_info(...). Fetching contacts the provider; construction from an already saved dictionary is local. Confirm the chosen qubits and coupler in the current calibration, preserve its timestamp, and record any independently measured readout matrices.
A sparse public snapshot may omit the durations or usable calibration required by this model. Missing/invalid T1/T2, durations, fidelities, or gate/coupler coverage can cause rejection. Do not invent missing timing or readout values to make construction pass. A connected pair alone does not certify a predictive model.
For two distributions, total variation distance is
| Formula / mathematical operation | Corresponding code excerpt | Check / interpretation |
|---|---|---|
report = prediction.compare_counts(counts) |
twin_compare.py uses synthetic counts and reports their normalized probabilities. | |
0.5 * sum(abs(p - q) for p, q in zip(prediction.twin_probabilities, report.hardware_probabilities)) |
Independently recomputed below and checked against the reported twin-versus-counts TVD. | |
report.ideal_hardware_total_variation - report.twin_hardware_total_variation |
A positive improvement is a closer classical distribution for this fixture; it is not proof of QPU predictive validity. |
It lies between 0 and 1; smaller means closer output distributions. When an agreement score is presented as 1-TVD, it describes this classical distribution comparison, not quantum-state fidelity or the probability that an individual shot is correct.
Save as twin_compare.py:
from twin_model import build_twin, bell_circuit
prediction = build_twin().predict(bell_circuit())
# Synthetic, deliberately chosen counts. These are not hardware measurements.
counts = {'00': 500, '01': 35, '10': 35, '11': 454}
report = prediction.compare_counts(counts)
assert report.shots == 1024
# Independently evaluate the TVD equation with the same basis ordering.
tvd_reference = 0.5 * sum(abs(p - q) for p, q in zip(
prediction.twin_probabilities, report.hardware_probabilities))
assert abs(report.twin_hardware_total_variation - tvd_reference) < 1e-12
assert abs(sum(report.hardware_probabilities) - 1) < 1e-12
assert abs(report.total_variation_improvement - (
report.ideal_hardware_total_variation - report.twin_hardware_total_variation)) < 1e-12
print('Input: synthetic count fixture; not QPU evidence.')
print('Shots:', report.shots)
print(f'Ideal-versus-fixture TVD: {report.ideal_hardware_total_variation:.6f}')
print(f'Twin-versus-fixture TVD: {report.twin_hardware_total_variation:.6f}')
print(f'TVD improvement over ideal: {report.total_variation_improvement:.6f}')
print('Arithmetic comparison passed; no hardware identity was established.')Run python twin_compare.py. Expected output:
Input: synthetic count fixture; not QPU evidence.
Shots: 1024
Ideal-versus-fixture TVD: 0.068359
Twin-versus-fixture TVD: 0.018334
TVD improvement over ideal: 0.050025
Arithmetic comparison passed; no hardware identity was established.
The report field is named hardware_probabilities, but this example deliberately supplies synthetic data. The API cannot turn a user-provided dictionary into a genuine hardware observation. compare_counts computes distances; it does not validate target, mapping, task identity, calibration age, executed program, or finite-shot confidence.
total_variation_improvement equals ideal-versus-counts TVD minus twin-versus-counts TVD. A positive value only says the model is closer to this supplied histogram than the ideal baseline. It does not establish statistical significance, predictive improvement on held-out circuits, or accuracy at another calibration time.
Counts must use fixed-width computational-basis strings in the mapped logical order, with qubit 0 on the left. Set reverse_bits=True only for a known external convention that requires it; do not reverse already normalized FlagQuantum results again.
Save as twin_persistence_drift.py:
from pathlib import Path
from tempfile import TemporaryDirectory
import flagquantum as fq
from twin_model import build_twin, bell_circuit
reference = build_twin()
current = build_twin(t1_scale=1.1, captured_at='2026-10-20T01:00:00+00:00')
with TemporaryDirectory() as directory:
path = Path(directory) / 'twin.json'
fq.twin.dump_twin(reference, path)
restored = fq.twin.load_twin(path)
assert restored.snapshot.identity == reference.snapshot.identity
assert restored.predict(bell_circuit()) == reference.predict(bell_circuit())
print('Saved/restored snapshot and prediction match: True')
drift = fq.twin.compare_calibrations(reference, current)
assert abs(drift.maximum_relative_t1_change - 0.1) < 1e-12
assert drift.maximum_relative_t2_change == 0
assert drift.maximum_readout_tv_distance == 0
history = fq.twin.build_calibration_history([reference, current])
assert len(history.captured_at) == 2
print(f'Maximum relative T1 change: {drift.maximum_relative_t1_change:.6f}')
print(f'Maximum relative T2 change: {drift.maximum_relative_t2_change:.6f}')
print(f'Maximum readout TV drift: {drift.maximum_readout_tv_distance:.6f}')
print('History snapshots:', len(history.captured_at))
print('Calibration drift is not a hardware-accuracy measurement.')Run python twin_persistence_drift.py. Expected output:
Saved/restored snapshot and prediction match: True
Maximum relative T1 change: 0.100000
Maximum relative T2 change: 0.000000
Maximum readout TV drift: 0.000000
History snapshots: 2
Calibration drift is not a hardware-accuracy measurement.
The temporary directory keeps this example repeatable and removes its file afterward. For a persistent artifact, use fq.twin.dump_twin(twin, "my-twin.json") and reload it with load_twin. Loading is offline and reproduces the stored model, not the provider's latest calibration.
The persistence contract uses canonical, private JSON artifacts and refuses replacement with different/invalid content. Retain frozen snapshots and choose a new path for a deliberately changed model. An identity digest provides consistency checking, not hardware attestation.
Calibration drift compares like-for-like target, physical mapping, logical calibration structure, and gate scopes, normalizing timing units. Per-item changes can be signed; the maximum summaries report absolute magnitudes. Readout drift is TVD between conditional readout rows. Histories require increasing timestamps and distinct snapshots.
A 10% T1 change is a change in represented calibration, not a measurement of a 10% prediction error. Drift comparison does not refresh the model, set an expiry threshold, or establish that a previously validated bound still holds. Validate accuracy on appropriately timed hardware data separately.
Save as twin_freeze.py:
import hashlib
import flagquantum as fq
from twin_model import build_twin, bell_circuit
twin = build_twin()
circuit = bell_circuit()
experiment = fq.twin.TwinExperiment.prepare(twin, circuit, name='offline-frozen-bell', shots=1024)
assert experiment.snapshot_identity == twin.snapshot.identity
assert experiment.prediction.circuit_identity == circuit.to_ir().content_hash
assert experiment.submitted_qasm_identity == hashlib.sha256(experiment.submitted_qasm.encode()).hexdigest()
assert experiment.target_qubits == (12, 13)
assert twin.evidence_report(circuit).status == 'unverified'
print('Frozen physical mapping:', experiment.target_qubits)
print('Frozen shots:', experiment.shots)
print('Frozen program format:', experiment.submitted_qasm.splitlines()[0])
print('Snapshot, circuit, and submitted-QASM identities checked: True')
print('Evidence status after preparation:', twin.evidence_report(circuit).status)
print('No hardware task submitted.')Run python twin_freeze.py. Expected output:
Frozen physical mapping: (12, 13)
Frozen shots: 1024
Frozen program format: OPENQASM 2.0;
Snapshot, circuit, and submitted-QASM identities checked: True
Evidence status after preparation: unverified
No hardware task submitted.
Preparation freezes the snapshot/prediction, IR circuit identity, canonical OpenQASM 2 program, backend, ordered physical mapping, and shots. It does not contact the provider or establish a hardware bound. The current TwinExperiment hardware workflow is Quafu-specific and requires positive multiples of 1024 shots; actual device/protocol admission limits still apply.
For prospective evidence, freeze the circuit and model before the hardware data used to evaluate them. Retrospectively selecting a noise model or matching a program hash after inspecting results does not supply that prospective identity binding.
Save the account-dependent script as twin_quafu_live.py:
import argparse
import json
import math
from pathlib import Path
import flagquantum as fq
from flagquantum.remote.qpu import QuafuProvider
parser = argparse.ArgumentParser(description='Capture Quafu calibration, submit one frozen twin experiment, or inspect its saved result.')
parser.add_argument('action', choices=('capture', 'submit', 'status', 'result'))
parser.add_argument('--model', type=Path, default=Path('quafu-twin.json'))
parser.add_argument('--submission', type=Path, default=Path('quafu-twin-submission.json'))
parser.add_argument('--backend')
parser.add_argument('--qubits', help='Ordered connected physical pair, for example 12,13')
parser.add_argument('--readout-json', type=Path, help='Optional measured independent confusion matrices in logical order')
parser.add_argument('--evidence', type=Path, help='On result: attempt strict evidence conversion and save here')
args = parser.parse_args()
def native_bell():
return (fq.Circuit(2).u3(0, math.pi/2, 0.0, math.pi)
.u3(1, math.pi/2, 0.0, math.pi).cz(0, 1)
.u3(1, math.pi/2, 0.0, math.pi))
provider = QuafuProvider()
if args.action == 'capture':
if not args.backend or not args.qubits:
parser.error('capture requires --backend and --qubits from current calibration/topology')
qubits = tuple(int(q) for q in args.qubits.split(','))
if len(qubits) != 2 or len(set(qubits)) != 2:
parser.error('This example requires two distinct connected physical qubits')
chip_info = provider.fetch_chip_info(args.backend)
matrices = None if args.readout_json is None else json.loads(args.readout_json.read_text())
twin = fq.twin.from_quafu_chip_info(
chip_info, target='quafu:' + args.backend, qubits=qubits,
readout_confusion_matrices=matrices,
)
prediction = twin.predict(native_bell())
fq.twin.dump_twin(twin, args.model)
print('Saved model:', args.model)
print('Snapshot identity:', twin.snapshot.identity)
print('Twin probabilities:', [round(p, 6) for p in prediction.twin_probabilities])
elif args.action == 'submit':
if args.submission.exists():
parser.error('Submission file already exists; use status/result for that task')
twin = fq.twin.load_twin(args.model)
if twin.snapshot.provider != 'quafu':
parser.error('This live workflow requires a Quafu twin')
experiment = fq.twin.TwinExperiment.prepare(twin, native_bell(), name='wiki-twin-native-bell', shots=1024)
receipt = experiment.submit(provider)
print('Submitted task:', receipt.task_id, flush=True)
submission = fq.twin.TwinSubmission.from_receipt(experiment, receipt)
fq.twin.dump_submission(submission, args.submission)
print('Saved submission:', args.submission)
else:
submission = fq.twin.load_submission(args.submission)
status = provider.query_status(submission.receipt)
print('Provider status:', status)
if args.action == 'result':
if status not in ('Finished', 'Completed', 'Done'):
raise SystemExit('No terminal success yet; inspect the same task later')
result = provider.fetch_result(submission.receipt)
report = submission.validate_result(result)
print('Counts:', dict(report.counts))
print(f'Ideal-QPU TVD: {report.validation.ideal_hardware_total_variation:.6f}')
print(f'Twin-QPU TVD: {report.validation.twin_hardware_total_variation:.6f}')
print('Validation scope:', report.validation_scope)
print('Executed program equals submission:', report.executed_program_matches_submission)
if args.evidence is not None:
evidence = submission.experiment.evidence_from_report(report, circuit=native_bell(), confidence_level=0.95)
fq.twin.dump_evidence(evidence, args.evidence)
print('Saved evidence:', args.evidence)python twin_quafu_live.py --help is offline. The other actions perform provider operations and require valid access. The script's CLI and ideal native-Bell circuit were checked locally; its calibration fetch, hardware submission, result retrieval, and evidence conversion were not executed against Quafu for this page.
Follow Cloud and Quantum Hardware Execution. This exact-mapping Quafu/SQC path uses a legacy token, distinct from the current task API key:
export QUAFU_API_TOKEN="YOUR_LEGACY_SQC_TOKEN"Choose an accessible backend and a connected physical pair from authoritative current metadata. The following names are placeholders to replace, not a claim that a particular pair is available:
python twin_quafu_live.py capture --backend YOUR_BACKEND --qubits PHYSICAL_Q0,PHYSICAL_Q1 --model quafu-twin.jsonThe capture command fetches calibration, constructs the model, verifies prediction, and saves it; it does not schedule a QPU task. Optionally add --readout-json measured-readout.json, where the JSON contains two measured 2-by-2 true-to-observed matrices in logical order. Without it the script does not claim to include measured readout confusion.
The native circuit spells H using u3(pi/2, 0, pi) and uses CZ explicitly so the adapter's U3 timings and calibrated CZ rule are applicable. Its ideal distribution is [0.5, 0.0, 0.0, 0.5]. A provider's executed gate sequence can still differ; that difference must be assessed rather than inferred from source-level equivalence.
After reviewing the saved model and prediction:
python twin_quafu_live.py submit --model quafu-twin.json --submission quafu-twin-submission.json
python twin_quafu_live.py status --submission quafu-twin-submission.json
python twin_quafu_live.py result --submission quafu-twin-submission.jsonsubmit creates one real 1024-shot task and consumes the provider's applicable quota. The output has this format, not fixed values measured here:
Submitted task: <provider task id>
Saved submission: quafu-twin-submission.json
status queries once. result checks terminal success, retrieves that same task, validates its receipt binding, and prints:
Provider status: <terminal success state>
Counts: <hardware count dictionary>
Ideal-QPU TVD: <measured value>
Twin-QPU TVD: <measured value>
Validation scope: retrospective_diagnostic
Executed program equals submission: <True or False>
There is no guaranteed histogram or guaranteed improvement. Counts vary with shots, hardware, time, and noise. If the task is queued/running, inspect the same saved submission later. This script does not automatically poll or resubmit.
TwinSubmission is a twin-specific artifact, distinct from the general fq.submit(receipt=...) job receipt. Load it with fq.twin.load_submission, not fq.restore_job. Its validated fields retain the experiment, submitted QASM identity, ordered physical mapping, and provider task receipt. Loading is offline and does not submit, cancel, or query anything.
The example refuses an existing submission filename, but it does not provide provider-side exactly-once submission. If submission succeeds remotely and its response or file save fails, reconcile the printed ID/provider records before retrying. A missing local file does not prove that no task was created. Keep the private artifact in persistent personal storage and supply current credentials again after restart.
To attempt converting that bound report into exact-circuit evidence:
python twin_quafu_live.py result --submission quafu-twin-submission.json --evidence twin-evidence.jsonThis additionally requires the original circuit/canonical submitted program and authoritative executed-program information to satisfy the release's binding rules. If the provider reports a transformed program, only the documented mapping-preserving binding checks can qualify it. Missing authoritative executed-program evidence can leave a useful diagnostic report while strict evidence conversion fails. Do not fabricate metadata or relabel a diagnostic as verified evidence to bypass that refusal.
A saved receipt establishes local identity context; it is not cryptographic attestation of what a QPU executed.
Repeatability needs distinct hardware tasks from the same frozen experiment. The release pattern is:
series = experiment.validation_series(
[first_hardware_report, second_hardware_report],
circuit=circuit,
confidence_level=0.95,
)
print(series.mean_twin_qpu_agreement)
print(series.mean_ideal_qpu_agreement)
print(series.mean_qpu_repeatability)
print(series.simultaneous_finite_shot_tv_radius)
evidence = series.to_evidence()This is a continuation recipe requiring previously collected bound reports, not a standalone offline example. The release hardware-evidence example demonstrates the full repeated workflow; running it submits two real tasks. Configure its backend, mapping, and gate/model assumptions for your experiment before use.
Pairwise QPU repeatability is a reference for hardware variability; comparing twin-to-QPU TVD alone cannot separate shot noise, device drift, compiler differences, and model misspecification. Record shot counts and finite-shot confidence radii. More shots reduce sampling uncertainty under the statistical assumptions, but do not eliminate unmodeled systematic error or time drift. High-dimensional output distributions can yield loose bounds at practical shot counts.
| Evidence status | Meaning |
|---|---|
unverified |
A model prediction exists without an applicable empirical bound. |
exact_circuit_verified |
The exact circuit has an applicable bound established from later hardware under the required binding workflow. It does not mean zero error. |
within_evidence_envelope |
A circuit lies inside declared structural scope with a separately established estimate bound; it is not itself an exact-circuit hardware verification. |
out_of_scope |
Snapshot, mapping, or circuit requirements lie outside the supplied evidence. |
Constructing an evidence record by hand does not create the underlying measurements. Use evidence produced by the owning validation workflow and retain the source reports.
TwinCircuitSupport can further restrict directed couplers and maximum logical dependency depth. Connected-region composition, regional models, fixed suites, prospective holdouts, candidate comparisons, and release assessments provide additional scoped workflows. Combining support cells does not prove arbitrary regional accuracy; composing a runnable regional model is also distinct from validating it. Follow the release guide before making claims about unseen circuits or a changed calibration.
| Problem or assumption | Check or limitation |
|---|---|
| A noise model cannot become a twin | It must contain a DeviceNoiseProfile; logical profile wires must match 0..len(mapping)-1. |
| Predictions disagree after remapping | The physical mapping is ordered and part of identity. Match circuit width, qubit order, couplers, and readout ordering. |
| Calibration conversion fails | Verify units, time zones, T1/T2 physical constraints, durations, fidelities, and gate/coupler coverage. Do not fill unknown values with guesses. |
| A logical CX and native CZ experiment differ | Timing and fidelity-derived channel placement are gate-specific. Check modeled versus provider-executed operations. |
| Twin probabilities already contain readout effects | Do not apply the same confusion matrix a second time. |
| Model prediction fits one histogram | This does not prove held-out accuracy, task provenance, or statistical significance. |
| A saved model is old | Loading freezes reproducibility; it does not refresh calibration or extend its validation window. |
| A hardware comparison cannot become evidence | Inspect prospective identities, executed-program information, physical mapping, and strict validation reasons. |
| Prediction runs out of memory | This path is exact dense simulation for one circuit; do not infer MPS/GPU/distributed capacity from other FlagQuantum features. |
The modeled mechanisms inherit the noise model's Markovian assumptions and supported channel/timing/readout representation. General pulse overlap, leakage, crosstalk, non-Markovian effects, arbitrary correlated dynamics, and automatic calibration learning are not established by these examples. A supplied correlated classical readout matrix is not a general correlated quantum-noise model.
Computational-basis agreement does not establish agreement of amplitudes, phases, arbitrary observables, full process fidelity, or an arbitrary quantum state. The current public prediction method returns detached distribution facts, not a supported gradient-based hardware-twin training loop.
No automatic service refresh, hardware submission, trust threshold, model expiry policy, or arbitrary-circuit guarantee follows from a saved snapshot or evidence envelope. Track calibration and validation separately, predeclare comparison circuits and acceptance criteria, and record versions, physical mapping, source calibration, timestamps, executed-program evidence, shots, uncertainty, and applicable scope.
Technical sources below are pinned to v0.3.1:
- QPU digital twin guide: snapshots, experiments, evidence, and regional workflows
- Twin domain overview · Experiment binding and validation scope
- Construction factories · Quafu calibration conversion
- Prediction and frozen model · Counts comparison
- Hardware experiment validation · Repeated validation statistics
- Complete repeated-hardware example · Capability catalog
- Noise and Open-System Simulation · Cloud and Quantum Hardware Execution · Troubleshooting and FAQ
- Installation and Compatibility
- Quick Start
- Install and Run
- Qubit Ordering and Result Conventions
- Runnable Examples
- Building and Simulating Circuits
- Training Parameterized Circuits
- Hybrid Classical-Quantum Models
- Core Concepts
- From Papers and Equations to FlagQuantum Code
- Reproducing Molecular Hydrogen VQE
- Fundamentals
- Tutorials
- Choosing a Simulation Method
- Accelerator Setup
- Distributed Simulation and Training
- Execution
- Circuit Compilation and Interoperability
- Noise and Open-System Simulation
- Quantum Error Correction Experiments
- Cloud and Quantum Hardware Execution
- QPU Digital Twins
- Advanced Topics
- Support and Contribution
All 21 guides are linked in the navigation sections. The Wiki Directory lists published guides and current repository resources.
- Troubleshooting and FAQ
- Reproducibility and Benchmarks
- Development and Contribution Guide
- Documentation Guide
Documentation, capability, and contribution links in this section follow current main; the guides above target 0.3.1.