Hands-On Examples for the X-Cube Fracton Decoder

Four interactive demos you can poke at — the geometry, the decode pipeline, the scoreboard, and the noise sweep

Companion to the tutorial and to the paper “Structure-Aware Neural Decoding for the X-Cube Fracton Code” (B. Guarraci, Galatheus). The tutorial explains why fracton decoding is hard and what the paper claims; this page lets you see it. Every widget below runs entirely offline with hand-written canvas + JavaScript — no libraries. The geometry in Widget 1 is derived directly from the edge→cube incidence in internal/fracton/xcube_code.py (the offset table is machine-checked against make_xcube for every edge); Widget 2 is a schematic of the decode path described in the tutorial §3.2–3.3; and all numbers in Widgets 3–4 (and the ablation figures in Widget 2) are taken verbatim from the data/ JSON files. Nothing is invented.

The one idea to hold onto In the surface code an error is a string that lights two defects you can pair up. In the X-cube code an error lights four defects at once, arranged as a rigid 2×2 block, and they are immobile — there is no string to follow. That single fact breaks matching decoders and is what the learned line-aware decoder is built to handle. Widget 1 lets you create those four-at-a-time defects yourself.

1. Errors make fractons (and why matching fails)

Cube-syndrome visualizer — one transverse slice of an \(L=4\) lattice

What this teaches: click an edge to place an \(X\) error and watch it light exactly four cube defects in a rigid 2×2 block (a fracton quadruple, immobile, with no string to match). Then click an adjacent parallel edge: the two errors share cube defects, which cancel, exposing the line/membrane structure that the paper's AxisLineonHead exploits.

clickable edge (qubit) X error placed cube center (quiet) lit cube defect (fracton)

Contrast with the surface code A surface-code error string lights two endpoint defects, and a minimum-weight matching pairs them with the cheapest connecting path — the whole algorithm relies on “defects come in pairs joined by a string.” Here a single error gives four defects at the corners of a flat region, none of them connected by a 1D string. There is no pairing to do, so MWPM has nothing to match. This is exactly why the paper turns to a learned decoder.
What the cancellation shows (toggle two adjacent parallel edges) Two parallel edges sitting side by side in the transverse plane share two of their cube checks. Those shared checks see two flips — an even number — so they go quiet, and defects survive only at the two outer ends. Extend a whole row of parallel edges and the interior defects all cancel; a full periodic row leaves zero defects (it is a logical/stabilizer line). That is the long line/membrane structure where the X-cube hides its logical information, and the AxisLineonHead pools along exactly these axes to read it.

2. How the decoder reads the lattice — the AxisLineonHead pipeline

From cube syndrome to recovery, one stage at a time

What this teaches: the decoder is a generic 3D CNN body plus one code-aware head. The head is the whole trick — it pools features along the logical lines where the X-cube hides its information, then reads off one parity per logical sector. Step through the five stages, and toggle the head to see why a generic global-pool head learns nothing (it ties the do-nothing floor exactly).

The coset-classification reframing (why it is a classifier at all) For any syndrome \(s\) you can fix some error \(R(s)\) consistent with it (a “pure error,” pure linear algebra from \(H_Z\)). The true error differs from \(R(s)\) only by which logical coset it lives in — exactly the \(6L-3\) parity bits. So decoding = predict \(6L-3\) bits, then apply \(R(s)\) plus the predicted logical representative. A per-sector error is just one wrong bit — and those bits are precisely the head's per-sector logits.
Why the ablation is the proof (toggle the head above) Swap the line-aggregation head for a global average pool and the network collapses the whole lattice to one vector — it can no longer tell where evidence sits, so it can only emit the global prior. Its block failure is 0.7342, identical to the trivial floor 0.7342: it learns nothing. The AxisLineonHead (and a coordinate-conv variant) instead score 0.303 / 0.302. Same body, same data, same capacity — the only change is whether the head preserves the line structure. That is the inventive step, made falsifiable.

3. Decoder scoreboard

Learned vs. Brown–Williamson vs. BP+OSD-0 vs. trivial — all ten cells

What this teaches: the learned decoder is best in every one of the ten \((L,p)\) cells, on both metrics. Flip to per-sector LER at \(p=0.03\) and step \(L:3\!\to\!4\!\to\!6\!\to\!8\!\to\!10\) to watch the headline: the learned rate improves with code size (\(0.042\!\to\!0.035\!\to\!0.018\!\to\!0.008\!\to\!0.003\)) while every baseline worsens.

Lines: per-sector LER as \(L\) grows. Only the learned decoder slopes downward. At \(p=0.03\) the learned curve falls \(0.042\rightarrow0.035\rightarrow0.018\rightarrow0.008\rightarrow0.003\); Brown–Williamson rises \(0.098\rightarrow0.169\rightarrow0.242\rightarrow0.295\rightarrow0.336\), crossing above the trivial floor by \(L=6\) (BP+OSD-0 too, by \(L=8\)) — so by \(L=10\) the learned decoder is the only one of four that still beats doing nothing on this per-sector metric.

Why per-sector LER is the honest metric Block failure asks for all \(6L-3\) logical sectors correct at once, so it is brutal for every decoder at large \(L\) — one slip ruins the block. Per-sector LER is the per-logical-qubit rate, and it is where the scaling story lives: a fixed-capacity local rule (or a lookup table) cannot improve with size, but the learned decoder does, because it reads non-local line structure.

4. Noise slider

Sweeping \(p\) at \(L=4\) — the learned advantage fades to a tie near threshold

What this teaches: drag the noise slider across \(p\in\{0.03,0.05,0.07,0.09,0.11,0.13\}\). The learned decoder beats trivial cleanly at low noise, the gap narrows, and the two tie by \(p\approx0.11\)–\(0.13\), in the vicinity of the \(\approx7.5\%\) optimal fracton-sector threshold. BP+OSD-0 is dominated throughout. The decoder is not magic at arbitrary noise — a limitation the paper states itself.

Per-sector LER vs. noise \(p\) at \(L=4\). The vertical marker tracks the slider. Learned (green) hugs just under trivial (grey) and converges to it near \(p\approx0.11\); BP+OSD-0 (purple) sits well above both.

Bounded operating range (paper's own limitation) The learned per-sector advantage over trivial decays smoothly: a clear win at \(p=0.05\) (0.110 vs 0.172), narrowing to 0.198 vs 0.227 at \(p=0.07\) and 0.267 vs 0.274 at \(p=0.09\), then closing to a statistical tie by \(p\approx0.11\)–0.13. This puts the useful range up near the \(\approx7.5\%\) optimal threshold — honest, and exactly what the paper reports.

Companion to the tutorial and main.tex. Widget 1 geometry is derived from internal/fracton/xcube_code.py (offset table machine-verified against make_xcube for every edge and axis). Widget 2 is a schematic of the decode pipeline (§3.2–3.3 of the tutorial); its ablation figures (0.7342 / 0.303 / 0.302) come from data/xcube_L346_gen.jsonsections.ablation. Widget 3–4 numbers are taken verbatim from data/xcube_L346_gen.json, data/xcube_L810_gen.json, data/xcube_L4_psweep.json, and data/xcube_bw_baseline.json per REPRODUCIBILITY.md. No results were invented.