Decode with atom loss
Run your first loss-aware decoding experiment: one circuit, 64 shots, four steps from sample to score.
The experiment at a glance
Atom loss removes a qubit until reset. A loss flag records whether its measurement is missing; a decoder uses these flags and surviving measurements to predict the logical flip.
- 01Generatecircuit.stim
- 02Samplepublic + private
- 03Decodepublic → predictions
- 04Checkpredictions + answers
Data boundary Only public records enter the decoder. Private answers are used at the final scoring step.
Run the downloaded example
The example ZIP contains run.sh, check.py and a README. Extract it, then run all four steps:
sh run.sh
Decoder support and scope
Envelope matching is Beta unless publication verification succeeds within its declared Mid-SWAP scope. This tutorial exercises one generated case. Decoder choices and exact support limits →
The loss model and stored record
LOSS(p) removes each present target independently with probability p. A lost atom stays absent until reset. Single-qubit gates skip it; a two-qubit gate is skipped when either partner is absent. These are the simulator's explicit model choices.
ML stores two bits per target: loss flag first, then value. A flag of 0 means the value is a measurement outcome. A flag of 1 means the stored value is a placeholder; it must not become ordinary syndrome evidence. MRL reports the same pair and then resets, restoring the atom.
cat > loss-record.stim <<'STIM'
R 0
LOSS(1) 0
ML 0
R 0
ML 0
STIM
rstim circuit sample --in loss-record.stim --shots 1 --seed 7 \
--out-format 01 --out loss-record.01 > /dev/null
cat loss-record.01
1100
The first 11 is a lost flag plus placeholder. After reset, 00 is a present atom measured in |0⟩. This small example demonstrates sampling semantics; it does not meet the native decoder's full circuit contract.
A heralded loss readout identifies an interval in which loss occurred, rather than its exact physical time. Keep flags alongside values and use surviving checks. The instruction reference separates simulator semantics from the native decoder's Z-only, flat-circuit acceptance rules.
What the Mid-SWAP gadget changes
The generator alternates the order of four CX layers. After the first physical layer in each round it exchanges the logical data/check roles of the participating wires; later gates and readout use the updated mapping. Reading and resetting the current check roles helps expose losses that would otherwise remain on a data role.
The model keeps physical loss state attached to its wire until reset; changing a logical role does not itself restore a lost atom. The generated circuit below is the executable definition. Inspect it with rstim render_svg or Shot Lab to see actual gates and paired flag/value records.
1. Generate the circuit
Create a distance-3, two-round Mid-SWAP memory circuit. Mid-SWAP exchanges data/check roles during the checks so readout can reveal loss.
rstim circuit gen \
--code surface_code --task rotated_memory_z_midswap \
--distance 3 --rounds 2 --after-clifford-depolarization 0.002 \
--operation-loss-probability 0.002 \
--measurement-loss-probability 0.003 \
--out circuit.stim
--after-clifford-depolarization sets Pauli noise after Clifford gates. --operation-loss-probability sets loss on gate targets; --measurement-loss-probability sets loss at readout. All four steps use circuit.stim.
2. Sample 64 shots
Export loss-visible measurements and keep the answer key in a separate bundle.
mkdir -p data
rstim dataset export \
--circuit circuit.stim --shots 64 --seed 7 \
--mode measurements_blinded --logical-x-qubits 1,8,15 \
--public-out data/public --private-out data/private
data/public/
Circuit, manifest and measurement rows in shots.b8.
data/private/
Logical-error targets in answers.b8, input masks and a manifest.
Changing the layout? The logical-X support 1,8,15 is specific to this circuit. Recompute it and regenerate both bundles together.
3. Decode public records
Envelope matching builds a graph conditioned on the observed loss pattern, then predicts one logical flip per shot from the public records.
rstim decode --decoder envelope-matching \
--dataset data/public \
--out predictions.b8 --stats-out decode-stats.json
Creates predictions.b8 and decode-stats.json.
What is in the output?
The prediction file contains one byte per shot in this one-observable example. Statistics report shot counts, distinct loss patterns, compilation and decoding time, and failures.
4. Check the predictions
Save check.py ↓ in your working directory (also included in the example ZIP), then run:
python3 check.py
Decoded shots: 64
Loss patterns: 10
Logical errors: 0 / 64
Each disagreement between a prediction and its private answer counts as one logical error.
Or copy the complete check into your terminal
python3 - <<'PY'
import json
from pathlib import Path
public = json.loads(Path('data/public/manifest.json').read_text())
private = json.loads(Path('data/private/manifest.json').read_text())
stats = json.loads(Path('decode-stats.json').read_text())
predictions = Path('predictions.b8').read_bytes()
answers = Path('data/private/answers.b8').read_bytes()
assert public['dataset_id'] == private['dataset_id'], 'Mismatched datasets'
assert public['circuit']['observables'] == 1, 'This check expects one observable'
assert (
len(predictions) == len(answers) == public['shots'] == stats['shot_count']
), 'Incomplete rows'
assert all(bit in (0, 1) for bit in predictions + answers), 'Invalid padding bits'
errors = sum(predicted != answer for predicted, answer in zip(predictions, answers))
print(f"Decoded shots: {stats['shot_count']}")
print(f"Loss patterns: {stats['distinct_loss_patterns']}")
print(f"Logical errors: {errors} / {public['shots']}")
PY
Interpretation Zero errors in 64 shots checks this example. It does not establish a zero logical error rate.
Decoder choices and method sources
envelope-matching is included in the default CLI and uses matching on a loss-conditioned graph. envelope-mle requires the optional ilp build and searches for the most likely fault configuration in the implemented envelope model. It is not a claim of optimal decoding for an arbitrary physical noise model.
These implementations reproduce methods described in Liu et al., Achieving Optimal-Distance Atom-Loss Correction via Pauli Envelope (v2). That pinned version is the reproduction reference; subsequent paper revisions may differ. For delayed loss detection background, see Baranes et al., Leveraging Qubit Loss Detection in Fault Tolerant Quantum Algorithms. Algorithm derivations are left to the original papers.
Envelope matching is Beta unless publication verification succeeds; its release evidence is not published and verified yet. Envelope MLE is Beta unless publication verification succeeds; its release evidence is not published and verified yet.
Matching and MLE have independently verified release evidence and different supported workloads. See the support table and measured accuracy and timing. A decoder accepting a circuit does not establish a Supported claim for every distance, loss rate or batch size.
Troubleshooting & support
The decoder reports unsupported_circuit
The input falls outside the compiler’s acceptance rules. Start with the exact circuit above, then compare your changes with the support contract. A rejection is not a logical prediction.
The output differs from the example
Check the CLI version, seed 7, 64 shots, circuit parameters and decoder choice. Use a fresh directory and rerun all four steps. Do not score a failed or incomplete decoding run.
The check reports mismatched datasets or incomplete rows
Regenerate the public and private bundles together, then rerun decoding. Both manifests must share a dataset_id, and prediction, answer and statistics counts must agree. Do not combine files from different runs.
Should I apply the private input masks again?
No. The physical logical-error targets already account for the hidden logical-input masks. Compare predictions directly with answers.b8.