Skip to content

Neutral-atom FT compiler demo

This page walks the strongest current end-to-end path in Quon: a typed surface-code source program is compiled into a verified neutral-atom schedule artifact, a QEC experiment JSON with a sibling Stim circuit, and an analytic resource report — from one compiler invocation.

A fresh reviewer with the repo cloned and Devbox installed can reproduce every artifact on this page with a single command:

Terminal window
devbox run -- cargo run -p quonc -- examples/na_qec/surface_d3_cx.qn \
--target targets/neutral_atom/generic_rna_v0.json \
--emit-na-schedule /tmp/na-ft-demo.schedule.json \
--emit-resource-report /tmp/na-ft-demo.report.md \
--emit-qec-experiment /tmp/na-ft-demo.qec.json

That one compile emits four files:

File What it is Evidence kind
/tmp/na-ft-demo.schedule.json Neutral-atom schedule view envelope (na_schedule_view) analytic
/tmp/na-ft-demo.report.md Compiler resource report analytic
/tmp/na-ft-demo.qec.json QEC experiment IR (dual-emit, ADR-0018) structure
/tmp/na-ft-demo.stim Sibling structure Stim circuit (noiseless) structure

The schedule is verified in-compiler: the run prints quantum.na verification passed (QEC auto) (ADR-0021 auto-verifies the quantum.na schedule for QEC-backed programs).

The input is the executable examples/na_qec/surface_d3_cx.qn fixture. It allocates two distance-3 surface-code patches, runs a memory round on each, applies a logical CX, and measures both in the logical Z basis:

-- Surface-code distance-3 logical CX via fixed-layout three-patch lattice
-- surgery (L-shaped: control|ancilla over target). Compiles on the NA/QEC
-- hybrid path (#250 / ADR-0019).

fn surface_d3_cx(): Q<Bit> = run {
        a <- surface_code<3>()
        b <- surface_code<3>()
        a <- memory_round(a)
        b <- memory_round(b)
        (a, b) <- logical_cx(a, b)
        _ <- measure_logical_z(a)
        measure_logical_z(b)
}

The linear typechecker threads each QecBlock<Surface, 3> value through the memory rounds, logical_cx, and measurements — the same static resource discipline the fixed gate-model path uses, applied to logical patches.

The neutral-atom schedule view (--emit-na-schedule) is a large document — 272 cycle layers of trap transfers, rearrangement, Rydberg entangling stages, and measurement rounds. Its meta + metrics envelope is the compact summary (canonical schedule IR is quantum.na, available via --emit-na-mlir). The metrics object below is a hand-picked subset — the real report also carries timing keys (rearrangement_time_us, transfer_time_us, total_time_us, …), reset_rounds, evidence_disclaimer, and a nested error_budget (see §3), all elided here with ...:

{
"schema_version": 1,
"kind": "na_schedule_view",
"meta": {
"target_id": "generic_reconfigurable_neutral_atom_v0",
"na_backend": "zoned",
"na_placer": "routing_agnostic"
},
"metrics": {
"evidence_kind": "analytic",
"rydberg_stages": 24,
"rearrangement_steps": 72,
"trap_transfers": 240,
"entangle2_count": 72,
"measurement_rounds": 9,
"estimated_cycles": 272,
"bottleneck": "rearrangement",
"logical_qubits": 3,
"physical_atoms": 57,
"atoms_per_logical": 17,
"code_family": "surface_code_like",
"distance": 3,
"memory_rounds": 2
// ... timing (*_time_us), reset_rounds, evidence_disclaimer, error_budget
}
// ... "zones", "layout", and 272 "layers" elided
}

The sibling structure Stim circuit encodes the lattice-surgery CX as Horsman-style logical-operator MPP merges (ADR-0019). The header states the model plainly, and byproduct Pauli-frame updates land as OBSERVABLE_INCLUDE records rather than bare detectors:

# Quon QEC experiment — lattice-surgery CX structure (no noise; ADR-0019/0024)
# family=surface distance=3 blocks=3 (L-shaped: control|ancilla / target)
# Merge/ancilla outcomes → OBSERVABLE_INCLUDE via frame; not bare DETECTORs.
# Stim merges use logical MPP (Horsman); NA schedules geometric seam CXs.
# Note: simplified merge/split model; not Stim FT-distance claim.
...
MPP Z0*Z1*Z2*Z34*Z35*Z36
...
MZ 0 1 2 3 4 5 6 7 8
OBSERVABLE_INCLUDE(0) rec[-9] rec[-8] rec[-7]
MZ 17 18 19 20 21 22 23 24 25
OBSERVABLE_INCLUDE(1) rec[-9] rec[-8] rec[-7] rec[-21] rec[-19]
# frame_z source=smooth_merge rec[-20]
# frame_z source=ancilla_mz rec[-19]

--emit-resource-report writes the compiler’s analytic neutral-atom resource report. These are schedule-derived estimates and analytic error-budget contributions (rate × schedule count) — not sampled results:

# Neutral-atom analytic resource report
## Qubit resources
| Metric | Value |
| --- | ---: |
| Logical qubits | 3 |
| Physical atoms | 57 |
| Atoms per logical | 17 |
| Code family | surface_code_like |
| Distance | 3 |
| Memory rounds | 2 |
## Schedule metrics
| Metric | Value |
| --- | ---: |
| Estimated cycles | 272 |
| Bottleneck | rearrangement |
| Rydberg stages | 24 |
| Total time (µs) | 15545 |
## Physical error budget
| Category | Contribution (rate × count) |
| --- | ---: |
| Rydberg | 0.048 |
| Measurement | 0.027 |
| Reset | 0.024 |
| Transfer | 0.168 |
| Movement | 0.036 |
| Idle | 1.6e-8 |

--emit-qec-experiment writes the QEC experiment IR (schema_version: 1, #[serde(deny_unknown_fields)] DTO) plus the sibling .stim. The document records the code family, distance, rounds, logical observables, the NA schedule cross-references (na_refs), and the target error model:

{
"schema_version": 1,
"kind": "qec_experiment",
"family": "surface",
"code_family": "surface_code_like",
"distance": 3,
"rounds": 2,
"logical_ids": [0, 1, 2],
// ... "check_graph", "measurement_schedule", "atom_site_map" elided
"logical_observables": [
{"id": 0, "logical_id": 0, "basis": "z", "atoms": [0, 1, 2]}
// ... one more observable for logical_id 1 (target patch)
],
"error_model": {
"rydberg": 0.002,
"measurement": 0.003,
"reset": 0.004,
"movement": 0.0005,
"transfer": 0.0007,
"idle_per_us": 2e-09
},
"na_refs": [ /* schedule cross-references, excerpted in the next block */ ],
"stim_file": "na-ft-demo.stim"
}

The na_refs array ties each experiment phase back to the neutral-atom schedule, including the lattice-surgery merge/split rounds with their barrier_cycle:

[
{"round_index": 0, "kind": "construct", "logical_id": 0},
// ... round_index 1 elided (non-contiguous excerpt)
{"round_index": 2, "kind": "memory_round", "logical_id": 0, "barrier_cycle": 84},
{"round_index": 3, "kind": "memory_round", "logical_id": 1, "barrier_cycle": 166}
// ... merge/split/frame_update and measure_logical refs elided
]

Quon keeps these two kinds of evidence in separate artifacts and never fuses them into a single claim (ADR-0020):

  • Analytic (compiler). The resource report and schedule-view metrics above. These are derived from the schedule structure and the target error model — atom counts, cycle estimates, timing, and rate × count error-budget contributions. No decoder runs.

  • Sampled / decoder (Python + Stim/Sinter). The structure .stim is noiseless; sampled logical failure rates come from a separate harness that injects noise and decodes. Run it on the emitted experiment:

    Terminal window
    devbox run -- .venv/bin/python python/quon_qec_sinter.py /tmp/na-ft-demo.qec.json \
    --shots 10000 --seed 7 --csv /tmp/na-ft-demo.sinter.csv

    (Requires devbox run -- just setup-python once to install Stim/Sinter into .venv.)

Analytic estimates and sampled logical failure rates are different kinds of evidence, and neither is a threshold claim. Readers may place the files side by side, or use the fused --emit-qec-validation report walked through next, which does this automatically with provenance.

5. Fused QEC validation report (--emit-qec-validation)

Section titled “5. Fused QEC validation report (--emit-qec-validation)”

Everything above (--emit-na-schedule, --emit-resource-report, --emit-qec-experiment) is zero-dependency — no Python required. Quon also has a stronger, optional end-to-end artifact that fuses the compiler’s analytic estimates with sampled Stim/Sinter evidence into one report, with a provenance fingerprint tying the two together (ADR-0020 amendment #280; full reference: docs/neutral_atom/qec_validation_report.md).

This needs the Python/Sinter stack (devbox run -- just setup-python once) — --emit-qec-validation shells out to python/quon_qec_sinter.py to sample logical failures. Run it against the distance-3 surface-code memory example (a smaller program than the CX walkthrough above, chosen to keep the excerpt short):

Terminal window
devbox run -- cargo run -p quonc -- examples/na_qec/surface_d3_memory.qn \
--target targets/neutral_atom/generic_rna_v0.json \
--emit-qec-validation /tmp/na-ft-demo.validation.json \
--validation-shots 2000 --validation-seed 7 --validation-decoder pymatching

That one command compiles, dual-emits the QEC experiment, builds the analytic ResourceReport, samples 2000 shots through Stim/Sinter, and fuses both into /tmp/na-ft-demo.validation.json (+ a sibling .md rendering) — while still writing the underlying primaries (*.qec.json, .stim, *.resource_report.json, *.sampled.json) as separate sibling files, per ADR-0020. The .md rendering below is captured verbatim from a real run — analytic and sampled evidence in clearly labeled sections, tied together by a provenance fingerprint:

## Provenance
| Field | Value |
| --- | --- |
| Source | `examples/na_qec/surface_d3_memory.qn` |
| Distance | 3 |
| Rounds | 2 |
| Experiment SHA-256 | `4dbcec439c3474c7e5401c6e3dab302d782c71948d8f45fa419eb7910d390242` |
## Analytic evidence
*evidence_kind: `analytic`*
| Metric | Value |
| --- | ---: |
| Logical qubits | 1 |
| Physical atoms | 17 |
| Estimated cycles | 165 |
| Rydberg stages | 16 |
## Sampled evidence
*evidence_kind: `sampled`*
- Decoder: `pymatching` · Seed: 7 · Confidence level: 0.95
| Shots | Logical failures | Failure rate | 95% CI (Wilson) |
| ---: | ---: | ---: | :--- |
| 2000 | 6 | 0.003 | [0.0014, 0.0065] |

provenance.experiment_sha256 ties the sampled row back to the exact compiled *.qec.json bytes; fusion refuses (or, with --allow-sampled-mismatch, warns) if attached sampled data doesn’t match the compiled artifact. As always: 6 failures out of 2000 shots at one seeded noise-model working point is validation evidence, not a threshold claim.

This demo is deliberately scoped. What it does not do:

  • No threshold claim. Neither the analytic report nor any sampled Sinter run on this page asserts an error-correction threshold.
  • Scoped lattice surgery. The logical CX is a simplified Horsman-style three-patch gadget at d = 3 (ADR-0019), lowered through a scoped patch-operation planner with fixed L-shaped geometry. There is no general patch router or arbitrary patch placement, and the geometric seam schedule alone is not a Stim-equivalent FT-distance claim.
  • Scoped surface-code schedule. The end-to-end path is validated for the distance-3 surface code; other odd distances are expected to extend but are not part of this verified slice.
  • No proprietary hardware model. The target is the generic reconfigurable neutral-atom descriptor generic_rna_v0.json, not any vendor’s calibrated device model.
  • Non-Clifford logical operations are a resource-accounting model, not yet compiler-reachable from source. Magic-state-consuming logical T, T†, and CCZ exist at the QEC-workload layer (issue #283): a WorkloadBuilder API, expansion into magic-state rounds, resource-report fields (t_count, tdag_count, ccz_count, magic_state_demand), and QEC experiment / Stim-comment emission. This is strictly consumption — magic states are assumed already available and are never produced. There is no distillation factory, and T/CCZ are recorded as metadata rather than expanded to physical gates. The frontend typechecker does not yet bind logical_t / logical_tdag / logical_ccz as source identifiers, so quonc cannot compile a .qn program that uses them end-to-end yet (tracked in #311). The logical operation demonstrated on this page (logical_cx) remains Clifford.