Circuit and loss instructions
Circuit syntax
A .stim file contains one instruction per line: NAME(arguments) targets. Arguments and targets depend on the instruction. # introduces a comment; REPEAT N { ... } repeats a block. Qubit targets are zero-based integers. Use rstim circuit stats --in circuit.stim to parse a file and inspect its measurement, detector and observable counts.
| Instruction | Role | Example |
|---|---|---|
R, RX, RY | Prepare a qubit in a Pauli basis; restores a lost atom | R 0 1 |
H, S, CX, CZ | Clifford evolution on available qubits | CX 0 1 |
X_ERROR(p), DEPOLARIZE1(p), DEPOLARIZE2(p) | Stochastic Pauli noise | X_ERROR(0.01) 0 |
M, MX, MY, MR | Measure, optionally reset | M 0 1 |
DETECTOR | Declare a measurement parity relative to the noiseless reference | DETECTOR rec[-1] |
OBSERVABLE_INCLUDE(k) | Add measurement parity to logical observable k | OBSERVABLE_INCLUDE(0) rec[-1] |
TICK, coordinates | Timing and drawing annotations | TICK |
A record target rec[-k] refers to the kth most recent stored bit at that point in execution. It is not a qubit index. Each detector and observable computes a parity; these declarations do not perform another measurement. The Get started circuit explains the example step by step.
RustQEC reads Stim-style syntax, but support differs by execution, analysis and export mode. The support contract scopes compatibility; accepted simulator instructions are not automatically accepted by every decoder. Stim's upstream gate reference is background for overlapping instructions, not a promise of complete compatibility.
Atom-loss extensions
LOSS(p) q... independently removes each still-present target with probability p. Loss persists until reset. Ideal single-qubit gates do nothing to absent atoms; a two-qubit interaction is skipped if either partner is absent. In the current executor, DEPOLARIZE2 also skips an incomplete pair. These execution rules define this simulator's model and do not claim to describe all physical loss mechanisms.
| Instruction | Stored record | Reset |
|---|---|---|
ML / MZL | loss flag, then Z-value bit for each target | No |
MRL / MRZL | loss flag, then Z-value bit for each target | Yes, after readout |
MXL, MYL | loss flag, then X/Y-value bit | No |
MRXL, MRYL | loss flag, then X/Y-value bit | Yes |
Flag 1 means the atom is absent at readout. An uninverted lost measurement stores value 1 as a placeholder, not a physical outcome. Reset restores the atom after recording the flag. The simulator's X/Y loss readouts do not extend the native loss decoder: v1 accepts Z loss readouts only. A decoder's result must not depend on the chosen placeholder.
Blinded logical input marker
TICK[rstim:logical_flip_point] marks the insertion point for a private logical Pauli in a blinded dataset. It must occur exactly once at top level, after ideal preparation and before positive-probability noise. A comment with similar text is not the marker. The training tutorial explains how the labels and masks relate.
Native loss decoder acceptance
The following is rendered from the canonical v1 contract. It defines parser and compiler acceptance, resource limits, bundle validation and failure codes. Acceptance of an external producer is determined by circuit conformance; release support promises additionally have a finite tested scope. See the support boundary.
Status: stable contract (versioned). This document is the public
specification of the circuit subset accepted by rstim decode and produced
by rstim dataset export. It exists so that dataset producers outside this
repository can generate decodable datasets without reading the compiler
source.
The reference implementation is
rstim/src/unified_cli/decode/compiler.rs
(compile_circuit and normalize_supported_circuit). Where this document and
the implementation disagree, the implementation is wrong or this document is
stale; both are pinned together by the test suite, so please file an issue.
1. Scope and versioning
- Subset version: v1.
- The decoder accepts exactly one circuit per dataset, stored as
circuit.stiminside a public dataset bundle (see §7). - Any circuit meeting every requirement in §2–§6 is accepted, regardless of which software generated it. Acceptance is capability-checked per circuit; there is no allow-list of generator programs or code families.
- Widening the subset (new instructions,
REPEAT, additional loss-visible bases) requires a new subset version. Rejections that v1 specifies must stay rejections within v1.
2. File-level requirements
| Requirement | Error code on violation |
|---|---|
Circuit is valid UTF-8 and parses under rstim::validation::parse_and_validate | invalid_dataset / unsupported_circuit |
Circuit is flat: no REPEAT blocks | unsupported_circuit ("outside the flat native Mid-SWAP subset") |
Measurement/detector/observable/sweep-bit counts match manifest.json | invalid_dataset |
| No sweep bits; between 1 and 64 observables | unsupported_circuit |
3. Instruction subset
Each instruction is classified as kept for analysis (present in the DEM extraction circuit), structural (consumed by the loss compiler itself), or rejected.
| Instruction | Class | Notes |
|---|---|---|
LOSS q... | structural | Declares a loss-opportunity site. Not itself analyzed; it opens the window in which a later loss-visible readout may herald a loss. Targets must be plain qubits. |
ML, MZL | structural → M | Loss-visible Z readout. Emits two measurement records: flag then value (see §4). |
MRL, MRZL | structural → MR | Loss-visible Z readout with reset. Same two-record layout; closes the loss window for that wire. |
MXL, MYL, MRXL, MRYL | rejected | Non-Z loss-visible bases are future work. |
H | kept | Also tracked as a basis-change site for envelope compilation. |
CX, CNOT, ZCX | kept (decomposed to H–CZ–H) | Targets must form complete, pairwise-disjoint qubit pairs within one instruction. |
R, RZ | kept | Closes any open loss window for the targeted wires. |
X_ERROR, DEPOLARIZE1, DEPOLARIZE2 | kept | The only noise channels in v1. All probabilities must be finite and < 0.5 at DEM level. |
QUBIT_COORDS, SHIFT_COORDS, TICK, DETECTOR, OBSERVABLE_INCLUDE | kept | Semantically inert annotations for loss-envelope construction; they remain in the analysis circuit so detector coordinates are preserved. |
anything else (incl. Y_ERROR, Z_ERROR, PAULI_CHANNEL_*, CORRELATED_ERROR, MPP, S, SWAP, …) | rejected | unsupported_circuit naming the instruction. |
Loss-visible readouts with inline noise arguments (ML(p) ...) are rejected.
4. Loss-record layout
For every loss-visible readout the measurement record interleaves:
- flag record — 1 iff the atom was heralded lost at this readout;
- value record — the measurement value bit.
The flag occupies the earlier measurement index. During compilation the flag
position is materialized as an MPAD placeholder so record indices stay
stable. Consequences:
DETECTORandOBSERVABLE_INCLUDEmust reference value records, never flag records (unsupported_circuit, "detectors and observables must reference value bits, not loss flags").- Each readout must have at least one
LOSSsite on that wire since the last reset (unsupported_circuit, "no LOSS opportunity since reset"). - A readout without reset (
ML/MZL) is terminal for its wire: no subsequent instruction may target that wire (unsupported_circuit, "ML must be terminal for each measured physical wire").
5. Detector error model requirements
The kept-for-analysis circuit (loss structure removed, noiseless variant used for reference samples) must yield a DEM satisfying:
- every detector carries at least
x, y, tcoordinates; - every error probability is finite and
< 0.5(zero-probability errors are ignored); - after DEM decomposition, every error component touches at most two
detectors (graphlike). Non-graphlike remnants are rejected
(
unsupported_circuit, "non-graphlike Pauli effect"); - observable-only error components are rejected for the matching backend ("observable-only Pauli effects are unsupported by envelope-matching");
- at least one decodable effect and one graph edge exist.
Edges are classified for diagnostics: same (x, y) → time-like, otherwise
space-like, single-detector → boundary.
6. Resource limits
| Limit | Value | Error on exceed |
|---|---|---|
| Envelope-MLE candidates per loss measurement | 100 000 | unsupported_circuit ("exceeds candidate limit") |
| Unique primitive loss probes | 100 000 | unsupported_circuit ("exceeds primitive probe limit") |
| Primitive detector/observable symptom terms | 10 000 000 | unsupported_circuit ("exceeds primitive symptom-term limit") |
| Measurements / detectors | 10 000 000 each | layout error |
| Observables | min(64, 1 000 000) | unsupported_circuit |
| Parity terms in measurement transforms | 100 000 000 | layout error |
| Transform working memory | 512 MiB transform / 256 MiB block | layout error |
Primitive effects are deduplicated by (instruction boundary, qubit, Pauli)
and evaluated in one reverse detector-sensitivity traversal. Envelope-Matching
uses the primitive-to-edge union directly and therefore does not enumerate the
composite Envelope-MLE candidate set. Successful decode stats expose
primitive_probe_count, primitive_symptom_terms, and
loss_envelope_candidate_count so generator growth remains observable.
7. Dataset bundle contract (consumer side)
rstim decode accepts a directory containing exactly:
manifest.json— formatrstim_decoder_datasetschema v1, orqude_decoder_datasetschema v3 (Decoder-Server interchange);circuit.stim— a v1-subset circuit;shots.b8—lsb_firstbit-packed measurement rows, width equal to the circuit's measurement count, zero padding.
SHA-256 hashes of both files, row widths, shot count, file size, and (for the
rstim format) the derived dataset_id are verified before compilation.
Violations report missing_dataset_file, invalid_dataset, or
unsupported_dataset_mode. Decode-time failures report decode_timeout or
decode_infeasible (exit code 3); all other failures exit 2.
8. Relationship to built-in generators
rstim circuit gen --code surface_code --task rotated_memory_z_midswap
emits circuits inside this subset, and the decode regression suite replays
them. Membership in the subset is the contract, not the generator. The
compiler performs no generator identification: any circuit satisfying §2–§6 is
accepted, whether hand-written, generated by this repository, or produced by
third-party tooling. Conformance fixtures that bypass the built-in generators
live under rstim/tests/ and are added together with this
specification's rollout.
9. Error-code summary
| Code | Meaning | Exit |
|---|---|---|
unsupported_circuit | circuit violates §2–§6 | 2 |
invalid_dataset | manifest/hash/layout mismatch | 2 |
missing_dataset_file | bundle file absent or unreadable | 2 |
unsupported_dataset_mode | dataset is not measurements_blinded | 2 |
decode_timeout | per-shot time limit hit | 3 |
decode_infeasible | model infeasible for a shot | 3 |