Reed–Solomon DQI decoder

A Reed–Solomon decoder that runs inside decoded quantum interferometry (DQI). The discovered circuit replaces the Euclidean algorithm with the Berlekamp–Massey recurrence, and runs it backward without keeping a record of every step.

In brief

The baseline (Khattar et al., 2025) runs the extended Euclidean algorithm, with every case of every step under control.

Berlekamp–Massey needs far less arithmetic, but each round overwrites values that the reverse round needs. The two cases of a round become one shared update plus a cheap swap. Most overwritten values are read back from the registers that remain. The rare round that leaves no trace gets one reserved slot, and the circuit accepts failure on the very rare input that needs a second.

TQ = 5·10⁸TQ = 10⁹TQ = 2·10⁹TQ = 5·10⁹TQ = 10¹⁰1,5002,0002,5005·10⁵10⁶2·10⁶5·10⁶peak qubits Q →Toffoli count T →Discovered circuitKhattar et al. (2025)Live qubits as Toffolis execute5.1M440k1,938
Syndromes and polynomials hold most qubits in both circuits, so they differ mainly in Toffolis.
1

Registers and the linear phase

init, zlin

The input is the 70 syndromes of a Reed–Solomon code over 𝔽212, one 12-qubit word each, 840 qubits in all. They determine an error word e with at most 35 nonzero symbols. The circuit applies the sign (−1)⟨c,e⟩ for a fixed mask c and returns every ancilla to zero. The error word has 49,140 bits, but the task needs one bit of it.

Few registers persist. The working discrepancy Dw, the signed counter dW, and three scratch qubits stay held. The locator σ, the template bank, and the history stack belong to BM and take wires only when first touched. The evaluator ω gets no register of its own: it will live in the first 35 syndrome words.

The parity of position j is a field trace, ⟨cj, ej⟩ = Tr(μjej). An interpolation polynomial U of degree 70 matches μj at 70 positions, and its share of the phase equals Σi Tr(uiSi), a fixed parity of syndrome bits. Z gates apply it. The residual mask vanishes at 71 positions, so the later scan has 4,024 positions with work to do.

b = Builder()
Start 0 Toffolis · peak 863 qubits
with b.phase("init"): # profile-stage blocks (metadata; emit nothing)
syn = list(declare_registers(b, [(f"s{r:02d}", B) for r in range(N)]).values())
assert all(list(syn[r]) == list(range(B * r, B * r + B)) for r in range(N)), (
"syn ids not contiguous"
) # qubits Br..Br+B-1
ANC = []
def An(n):
qs = b.qubits(n)
ANC.extend(qs)
return qs
Dw = An(B) # fused-Q working discrepancy register
dW = An(DWB) # two's-complement d counter
OMW = [syn[i] for i in range(W)] # omega lives IN PLACE in syn[0..W-1]
# Ownership wire-sets (claim/release bookkeeping; emits no op). Every
# long-lived wire joins exactly one named set with its full id list, so
# the anonymous pool live - sum(owned) is empty from init to cleanup;
# tools/occupancy_profile.py validates the discipline fail-closed.
b.claim("syn", [w for reg in syn for w in reg])
b.claim("dw", Dw)
b.claim("dcount", dW)
# Transient scratch round-trips through the allocator (A.open /
# A.close). Only state that persists between windows (discrepancies,
# stack, controls, counters, the Em pivots) stays held; everything that
# returns to |0> mid-circuit is freed there, so peak_qubits is the
# measured max co-live width and the liveness profile shows the true
# windows. Journal replays (the BM reverse, the Psi route) run
# closures over hard wire ids, so A logs the window ids a journal
# touches and re-materializes exactly that set before its replay
# (A.replay; reclaim fails closed when any id is not free).
A = Alloc(b)
sA = An(1)[0]
b.claim("pivA", [sA])
sB = An(1)[0]
b.claim("pivB", [sB])
sT = An(1)[0]
b.claim("fanT", [sT])
E = Em(b, sA, sB, sT, A)
bm = BM(E, A, syn, Dw, dW)
SIG = bm.SIG
# Width ledger: N * B syn + (B + DWB + 3) held (Dw, dW, pivots) + the
# lazily-materialized wires ((2W+3) B bank + STK_CAP tagged stack slots)
# + the late BM/reverse rounds' window tiling. The peak assert below
# enforces the total.
# ---- 1. zlin: free Z part sum_i Tr(u_i S_i) -----------------------------
Linear phase 0 Toffolis · peak 863 qubits
with b.phase("zlin"):
for i in range(N):
for bb in bitlist(ZMASKI[i], B):
b.z(syn[i][bb])
2

Seventy Berlekamp–Massey rounds

bm

Berlekamp–Massey finds the locator σ, whose roots mark the error positions, by reading one syndrome per round. Each round computes the discrepancy Δ, the amount by which the current σ fails to predict the new syndrome. It then corrects σ with a multiple of an earlier locator τ, the template, shifted by z once per round. bm.run() emits the 70 rounds and records every step in a journal for the later reverse pass.

Each round touches only the coefficients that can already be active. After r syndromes a typical locator has degree near r/2, well below the worst case min(r, 35). Classical simulation over 403 million sampled inputs fixed a coefficient window per round. A rare input crosses a window, at a rate of 3.8 × 10−5, and can then get a wrong phase; the circuit still restores the syndrome.

Berlekamp–Massey rounds 141,071 Toffolis · peak 1,813 qubits
bm.run()
3

One round on one arithmetic path

BM.round

A round first forms Δ over its truncated window. The flag ctl is set when Δ ≠ 0 and d ≥ 0, the case where τ is replaced by σ. The shift of τ by z is a relabeling of the bank and costs nothing.

Compiled directly, the replace and retain cases would be two controlled arithmetic paths, and both would cost Toffolis. Here a replace round first swaps σ with the template. Both cases then run the same multiply–add σk ← σk + mτk. On a replace round the result is a nonzero multiple of the textbook locator, which has the same roots.

No register holds the accepted discrepancy δ. The update keeps σ0δ = 1, so the circuit forms p = Δσ0 and inverts it with the 66-Toffoli tower chain. Twelve Toffolis select m = p on a retain round and m = p−1 on a replace round. Each field product costs 42 Toffolis. Afterwards p erases by measurement through the identity p = Δ(τ0 + σ0) + [replace].

def round_head(self, r, bb_l):
"""Open round r (inside its bm/rNN phase block): journal mark, the
round's cascade stack slots, and the fused-Q bank rotation (a
relabel). Returns the rotated bank.
"""
self.A.round = r
self.A.log = self.pools.setdefault(r, set())
self.JROUND.append(self.J.mark())
# Lazy-materialization invariant: a register touched mid-round may
# only take free-list ids that strictly earlier rounds' windows freed
# (those return before the descending replay reaches them). At the
# bank/ctl touch sites this holds because the round's own freed ids
# are always reconsumed by the windows still open there; the cascade
# runs after every window closed, so its stack depths materialize at
# the round head instead. reclaim fails closed on any breach.
for s in self.STK[: CAPS[r]]:
s.mat()
return [bb_l[W + 1]] + bb_l[: W + 1]
⋯ 1 line
def discrepancy(self, r):
"""Dw <- sum_{i <= IMAXV[r]} sigma_i S_{r-i} (the truncated window)."""
rtD = []
for i in range(IMAXV[r] + 1):
bil_terms(rtD, KT, spec_plain(self.SIG[i]), spec_plain(self.syn[r - i]), self.Dw)
self.E.mac(rtD)
⋯ 2 lines
def quotient(self, ctl, bb_l):
"""Yield the round quotient m without a stored accepted discrepancy.
Invariant (README): sigma_0 * DEL == 1 on every
correct-path round, DEL the accepted discrepancy of the q-form
recursion, so the recursion's m = D'/DEL' is
ctl=0: m = Delta * sigma_0 = p,
ctl=1: m = DEL_old / Delta = 1/(Delta * sigma_0) = inv(p).
Exit erases m (a function of p, inv(p), ctl), the chain and inv(p),
then p. Dw = Delta on every branch there; p = Delta * sigma_0_old,
and sigma_0_old now sits in bb_l[0] (ctl=1) or SIG[0] (ctl=0, where
Delta != 0 forces bb_l[0] == 0); on ctl=1 the update left SIG[0] =
1/Delta, so Delta*(bb_l[0] + SIG[0]) = p + ctl:
p == Dw * (bb_l[0] ^ SIG[0]) ^ ctl*[1] (one KT claim).
"""
E = self.E
with opened(E, "pq", B) as pv:
E.mac(prod_rt(pv, self.Dw, self.SIG[0]))
with opened(E, "dinv", B) as dv, chain_live(E, pv, dv), opened(E, "m", B) as mq:
# m = p ^ ctl*(p ^ inv(p)): B free copies + B CCX
rtM = []
for t_ in range(B):
rtM.append(("L", (pv[t_],), 0, (mq[t_],)))
rtM.append(norm_term((ctl,), 0, tuple(sorted((pv[t_], dv[t_]))), 0, (mq[t_],)))
E.mac(rtM)
yield mq
E.free(rtM)
rtPe = []
bil_terms(
rtPe,
KT,
spec_plain(self.Dw),
[frozenset((bb_l[0][j], self.SIG[0][j])) for j in range(B)],
pv,
)
rtPe.append(("L", (ctl,), 0, (pv[0],)))
E.free(rtPe)
⋯ 1 line
def bank_swaps(self, r, ctl, bb_l):
"""cswap(ctl) of the sigma and B banks over slots 0..KMSV[r]."""
for k2 in range(KMSV[r] + 1):
if r == 1 and k2 == 1:
# provable identity: both branches leave sigma_1 ==
# B_1 entering this swap (2-branch enumeration)
continue
for t_ in range(B):
self.E.cswap(ctl, self.SIG[k2][t_], bb_l[k2][t_])
⋯ 1 line
def update(self, r, k0, mq, bb_l):
"""sigma_k ^= m * B_k over slots k0..KMMV[r] (one KT12 each)."""
for k2 in range(k0, KMMV[r] + 1):
self.E.xor(prod_rt(self.SIG[k2], mq, bb_l[k2]))
⋯ 112 lines
def round(self, r, bb_l):
"""Emit a general round 0 < r < N-1."""
with self.b.phase(f"bm/r{r:02d}"):
bb_l = self.round_head(r, bb_l)
with opened(self.E, "ctl", 1) as (ctl,):
self.discrepancy(r)
# ctl is set iff Dw != 0 and d >= 0
flag_test(self.E, self.Dw, (self.dW[SGN],), ctl)
with self.quotient(ctl, bb_l) as mq:
self.bank_swaps(r, ctl, bb_l)
self.update(r, 0, mq, bb_l)
self.push(r)
self.erase_dw(ctl)
self.close_ctl(r, ctl)
if r < N - 2:
# +1 always -> d = ctl ? -d : d+1 (at r=N-2 the increment is
# dropped: the counter has no later consumer and the complement
# alone arms the erase anchor)
self.inc_d()
return bb_l
4

The evaluator, written over the syndromes

monicize, omega

monicize divides the locator coefficients σ1 to σ35 by σ0. This keeps the roots and leaves the ratio ω/σ′ unchanged. On an approximate path σ0 can be zero; the stage then scales by one, so it stays reversible on every input.

The relation σS = ω mod z70 gives the evaluator. Coefficient i of σS equals Si+1 plus a function of earlier syndromes, so the map is triangular and runs in place. The first 35 words become ω. On every correct decode the last 35 become zero, 420 qubits of workspace for the next stage.

The blocks are middle products. Each evaluates its two operands at fixed field points with CNOTs, multiplies the values, and interpolates only the requested band. Only products of two data-dependent values cost Toffolis.

inputS₁ … S₇₀omegaω₀ … ω₃₄zeroseuclid/Rω₀ … ω₃₄ab+1omega_restoreS₁ … S₇₀0355370word (12 qubits)
The 70 syndrome words (12 qubits each) at four points in the circuit. The evaluator ω overwrites the first 35 words and zeroes the rest, and the cofactors a and b then grow in those zeroed words, so the decoder adds only one extra word.
Normalize 1,583 Toffolis · peak 1,793 qubits
mon_stage(E, SIG, "monicize", range(1, W + 1), True)
# ---- 4. omega70 = sigma_m*S mod z^N, IN PLACE in syn[0..N-1] ------------
# sigma_m is monic: the triangles' diagonals span sigma_1..sigma_{W-1},
# the off-diagonal tail block's sigma_1..sigma_W (omega_rts).
# Rows W..N-1 (the TAIL) end at 0 on every correct decode and host the
# Bezout pair (stage 5).
MACRT = omega_rts(SIG, syn)
Evaluator 15,246 Toffolis · peak 1,758 qubits
omega_pass(E, MACRT, "omega", range(len(MACRT)))
5

A half-degree Euclidean pass for 1/σ′

euclid

Forney's formula recovers an error value as ω(β)/σ′(β) at a root β. A division at every position would dominate the cost. The circuit instead computes, once, a polynomial Ψ with Ψσ′ ≡ 1 mod σ, which equals 1/σ′ at every root.

In characteristic 2 squaring is linear, so σ = E2 + zO2 with Ei = √σ2i and Oi = √σ2i+1. The square roots rewrite the locator words in place, and σ′ = O2. If AE + BO = 1, then Ψ = B2 + zA2. The Euclidean algorithm thus runs on halves of degree 17 that fit in 18 words. A barrel shift by m = ⌊(35 − L)/2⌋ gives every input the same shape; the counter already holds m in bits 2 to 6 after adding two.

The forward pass runs 17 fixed blocks of two eliminations and parks each quotient in the word it clears. The cofactors grow in the zeroed syndrome words: a seed places 1/h for the last pivot h, and build_R replays the forward journal backward while it accumulates the pair. One extra word completes the two 18-word registers. The circuit reaches its peak of 1,837 qubits in these passes.

Half-degree Euclid 44,470 Toffolis · peak 1,837 qubits
with b.phase("euclid/setup"):
ONE = A.open("one", B)
EPS = A.open("zprec", 6) # eps + 5-bit idx
PRE = A.open("pre", 1)[0]
PSI_IDS = set()
JSET, JPAD, JPRE, JF, JSEED = (Journal(), Journal(), Journal(), Journal(), Journal())
with E.using(J=JSET), A.logging(PSI_IDS):
E.x(ONE[0])
for i in range(1, W + 1):
JSET.step(
lambda r=list(SIG[i]): linear_in_place(b, r, SQRT_ROWS),
lambda r=list(SIG[i]): linear_in_place(b, r, SQUARE_ROWS),
)
# dW += 2: a constant increment on bits 1..7 (ladder carries, MBU-erased)
with opened(E, "inc", DWB - 3) as tr:
E.inc1(dW[1:DWB], tr)
EW = [ONE] + [list(SIG[2 * i]) for i in range(1, NH)]
OWD = [list(SIG[2 * i + 1]) for i in range(NH)]
MBITS = dW[2:7] # m = (dW + 2) >> 2
with b.phase("euclid/pad"), E.using(J=JPAD):
pad_barrel(E, MBITS, EW, OWD)
with b.phase("euclid/pre"), E.using(J=JPRE), A.logging(PSI_IDS):
psi_pre(E, EW, OWD, PRE)
with b.phase("euclid/F"), E.using(J=JF), A.logging(PSI_IDS):
F_FIN, _G_FIN, RECS = psi_forward(E, EW, OWD, EPS[0], EPS[1:6])
# ---- seed + R: the Bezout pair (a, b) grows in the TAIL + one EXT word --
# a[(m+1) % 18] <- inv(h) (h = the final F pivot), then R = the journal
# reverse of F interleaved with the cofactor recurrence: on exit EB holds
# (E', O') again and (a, b) = (A, B) with A E' + B O' = z^m, deg <= 17.
with b.phase("euclid/seed"):
TAILW = [list(syn[i]) for i in range(W, N)]
AW = TAILW[:NH]
with E.using(J=JSEED), A.logging(PSI_IDS):
psi_seed(E, F_FIN[NH - 1], MBITS, AW)
with b.phase("euclid/R"):
with A.replay(PSI_IDS, "psipool"):
EXT = A.open("ext", B) # opened under the replay hold: never a PSI_IDS id
BWD = TAILW[NH:] + [EXT]
JR, AFIN, BFIN = build_R(E, JF, RECS, AW, BWD, PRE, PSI_WIN, (EW, OWD))
JR.forward()
A.close("zprec", EPS)
6

The position scan

sweep

The scan visits all 4,095 positions and skips the point body at the 71 positions the linear phase removed. At each of the other 4,024 it tests whether the point is a root of σ and, on a root, applies Tr(ν ωΨ) for a fixed per-position constant ν. A position costs 11 Toffolis for the root test and 12 for the pairing, 23 in all, against 80 with a division at every point.

Position scan 92,552 Toffolis · peak 1,806 qubits
with b.phase("sweep"):
emit_sweep(b, E, A, OMW, EW + OWD, AFIN + BFIN)
7

The point body

sweep_plan, emit_sweep

A Chien search would multiply each stored word by a constant between points. Here the words stay fixed. At point t, each bit of a rotated word is a fixed parity of stored bits, so the plan precomputes membership masks over t for ω, for the locator halves, and for the cofactors. The body is one repeated block, and each CNOT is gated by a table bit for its point.

The XOR of the 36 locator words equals xm√σ(x), which is zero exactly at a root. An eleven-rung AND ladder tests its twelve bits. The XOR of the cofactor words is V with Ψ = V2, so Tr(νωΨ) = Σa ⟨ra, ω(x)⟩Va, a bilinear form of rank 12.

Each of the twelve terms is one Toffoli into a scratch bit. A CZ with the root flag applies the phase, and an X-basis measurement erases the scratch bit. The twelve-bit error value never exists.

def sweep_plan(b, A, omw, ebw, abw):
"""Return the body as [(gate vector over t, emitter(s_))] in emission order,
s_ the body's wire handles; a None vector emits ungated (the tree
window open on allocator A). Mirrors the per-point form: som fan-ins, the root-test
ladder (pivot_pair builds, sorted operands), the rank-12 pairing
(fan_pair), the ladder erase (emit_free, reversed), the som unwind.
"""
m_om = rot_member(list(range(W))) & LIVE # som fan-ins
m_eb = rot_member(LOG_EB) & LIVE # root-test groups
m_v = rot_member(LOG_AB) & LIVE # pairing V groups
prow = np.zeros((B, M), dtype=np.int64) # r_a(lam) masks
for t in range(M):
if LIVE[t]:
prow[:, t] = pair_rows(LAMJ2[(M - t) % M])
single = np.stack([prow == (1 << c) for c in range(B)], axis=1) # [a, c, t]
built = ~single.any(axis=1) & LIVE # [a, t]
m_sa = np.stack([((prow >> c) & 1).astype(bool) & built for c in range(B)], axis=1) # [a, c, t]
# the per-point spelling the body mirrors: every root-test group is
# non-empty (both pivots build), every V group has >= 2 wires (it builds)
assert (m_eb.any(axis=(1, 2)) | ~LIVE).all(), "empty root-test group"
assert (m_v.sum(axis=(1, 2)) >= 2)[:, LIVE].all(), "degenerate V group"
eb_sorted = sorted(
(w, k, j) for k, word in enumerate(ebw) for j, w in enumerate(word)
) # terms sort operands
assert len({w for w, _, _ in eb_sorted}) == len(eb_sorted)
plan = []
def op(vec, fn):
plan.append((vec, fn))
def eb_build(g, s, inverse):
cands = [(w, m_eb[g, k, j]) for w, k, j in eb_sorted]
if inverse:
op(LIVE, lambda s_: b.x(s_[s]))
cands.reverse()
for w, v in cands:
op(v, lambda s_, w=w: b.cx(w, s_[s]))
if not inverse:
op(LIVE, lambda s_: b.x(s_[s]))
def ua(i, s_):
return s_["sA"] if i == 1 else s_["tr"][i - 2]
def rung(i, mid):
"""ladder rung i >= 1: wa = group 0 (i == 1, built in sA) or
tree[i-2] (direct), wb = group i (built in sB).
"""
if i == 1:
eb_build(0, "sA", False)
eb_build(i, "sB", False)
op(LIVE, mid)
eb_build(i, "sB", True)
if i == 1:
eb_build(0, "sA", True)
om = [(bb, k, j) for bb in range(B) for k in range(W) for j in range(B)]
for bb, k, j in om:
op(m_om[bb, k, j], lambda s_, bb=bb, k=k, j=j: b.cx(omw[k][j], s_["som"][bb]))
op(None, lambda s_: s_.__setitem__("tr", A.open("tree", B - 1)))
for i in range(1, B):
rung(i, lambda s_, i=i: b.ccx(ua(i, s_), s_["sB"], s_["tr"][i - 1]))
vw = [(k, j) for k in range(len(abw)) for j in range(B)]
for a_ in range(B):
cases = [(built[a_], lambda s_: s_["sA"])] + [
(single[a_, c] & LIVE, lambda s_, c=c: s_["som"][c]) for c in range(B)
]
for c in range(B):
op(m_sa[a_, c], lambda s_, c=c: b.cx(s_["som"][c], s_["sA"]))
for k, j in vw:
op(m_v[a_, k, j], lambda s_, k=k, j=j: b.cx(abw[k][j], s_["sB"]))
for v, u in cases:
op(v, lambda s_, u=u: b.ccx(u(s_), s_["sB"], s_["sT"]))
op(LIVE, lambda s_: b.cz(s_["tr"][B - 2], s_["sT"]))
op(LIVE, lambda s_: s_.__setitem__("m", b.hmr(s_["sT"])))
for v, u in cases:
op(v, lambda s_, u=u: b.cz(u(s_), s_["sB"], cond=s_["m"]))
for k, j in reversed(vw):
op(m_v[a_, k, j], lambda s_, k=k, j=j: b.cx(abw[k][j], s_["sB"]))
for c in reversed(range(B)):
op(m_sa[a_, c], lambda s_, c=c: b.cx(s_["som"][c], s_["sA"]))
for i in range(B - 1, 0, -1):
op(LIVE, lambda s_, i=i: s_.__setitem__("m", b.hmr(s_["tr"][i - 1])))
rung(i, lambda s_, i=i: b.cz(ua(i, s_), s_["sB"], cond=s_["m"]))
op(LIVE, lambda s_: A.close("tree", s_["tr"]))
for bb, k, j in reversed(om):
op(m_om[bb, k, j], lambda s_, bb=bb, k=k, j=j: b.cx(omw[k][j], s_["som"][bb]))
return plan
⋯ 2 lines
def emit_sweep(b, E, A, omw, ebw, abw):
"""Emit the sweep: one gate-table row of M bits per distinct gate
vector (the forward and unwind passes share rows; row r gates
iteration t on bit r * M + t), then the repeat(M) body over the held
pivots and the som / tree windows of allocator A.
"""
plan = sweep_plan(b, A, omw, ebw, abw)
rows = {}
for vec, _ in plan:
if vec is not None:
rows.setdefault(vec.tobytes(), vec)
rows.setdefault(LIVE.tobytes(), LIVE)
row_of = {key: r for r, key in enumerate(rows)}
table = b.declare_table(np.concatenate(list(rows.values())).astype(np.uint8).tolist())
with b.repeat(M) as it:
def gate(vec):
return b.gated(table, it + row_of[vec.tobytes()] * M)
s_ = {"sA": E.sA, "sB": E.sB, "sT": E.sT, "som": A.open("som", B)}
for vec, fn in plan:
if vec is None:
fn(s_)
else:
with gate(vec):
fn(s_)
with gate(LIVE):
A.close("som", s_["som"])
8

Unwind the Euclidean pass and the evaluator

euclid_inv, omega_restore, unmonicize

euclid_inv is the literal reverse of euclid: it replays each journal backward, last one first, through the setup. The cofactor words return to zero and the locator halves to σ.

Each evaluator block writes targets disjoint from its operands, so emitting the same block again undoes it. omega_restore runs the blocks in reverse order and recovers all 70 syndromes, on every input. unmonicize then restores the scale of σ that the backward rounds expect.

Euclid reversed 44,470 Toffolis · peak 1,837 qubits
with b.phase("euclid_inv/R"):
A.reopen("zprec", EPS)
A.reopen("psipool", PSI_POOL)
JR.reverse()
A.close("ext", EXT)
with b.phase("euclid_inv/seed"):
JSEED.reverse()
with b.phase("euclid_inv/F"):
JF.reverse()
with b.phase("euclid_inv/pre"):
JPRE.reverse()
with b.phase("euclid_inv/pad"):
JPAD.reverse()
with b.phase("euclid_inv/setup"):
JSET.reverse()
A.close("psipool", PSI_POOL)
A.close("pre", [PRE])
A.close("zprec", EPS)
A.close("one", ONE)
# ---- 8. omega_restore: exact reversed block list ------------------------
# each block's targets are disjoint from its operands, so re-emitting the
# same term list un-XORs it; the reversed block order restores S exactly.
Evaluator reversed 15,246 Toffolis · peak 1,758 qubits
omega_pass(E, MACRT, "omega_restore", reversed(range(len(MACRT))))
# ---- 9. unmonicize: SIG[i] <- sigma_0*SIG[i] for i=W..1 -----------------
Normalize reversed 1,583 Toffolis · peak 1,793 qubits
mon_stage(E, SIG, "unmonicize", range(W, 0, -1), False)
9

Rounds reversed

reverse, cleanup

bm.reverse() replays the round journal from the newest round to the oldest. The forward rounds erased their temporaries by measurement at no Toffoli cost, and the reverse pass recomputes only those erased values. It therefore costs 86,176 Toffolis against 141,071 for the forward rounds.

The cleanup releases the held registers. The syndrome is unchanged.

Rounds reversed 86,176 Toffolis · peak 1,813 qubits
bm.reverse()
# ---- 11. cleanup ---------------------------------------------------------
# Release-before-free through the only teardown path: every workspace set
# returns its wires (full id lists, reverse claim order) ahead of the
# frees; the N * B syndrome wires stay owned to the end as the declared
# registers.
Cleanup 0 Toffolis · peak 863 qubits
with b.phase("cleanup"):
b.release("fanT", [sT])
b.release("pivB", [sB])
b.release("pivA", [sA])
b.release("dcount", dW)
b.release("dw", Dw)
b.recycle_all(reversed(ANC))
10

Recovering Δ for the reverse pass

push, erase_dw, close_ctl, reverse

Reversing a round needs its discrepancy Δ. Keeping one word per round would raise the qubit count to 2,677. A round with Δ = 0 leaves σ unchanged. A replace round leaves σ0 = Δ−1, so erase_dw erases Dw against the inverse of σ0 by measurement, and the reverse pass recomputes it from the locator.

A retain round with Δ ≠ 0 leaves σ0 unchanged, so σ0 cannot supply Δ. Every round with d < 0 therefore pushes Δ onto a stack with Fredkin gates, tagged with its round. A stack that never overflows needs 35 entries, 665 qubits. Rounds with d < 0 are rare on DQI inputs, so the circuit keeps one 19-qubit entry. An input that needs a second entry occurs with probability 1.0 × 10−4 and can get a wrong phase; the syndrome is still restored.

The tag also erases the round flag: close_ctl uses ctl = (sign bit of the updated d) AND NOT [top tag = r]. During the replay the Fredkin ladders run backward and pop each entry at its own round.

def push(self, r, ctl=True):
"""Emit the fused-Q push cascade on pqc = dW[SGN] (d<0 forces ctl=0);
ctl=False spells it with plain swaps (the unconditional r=N-1
push, 0 Toffoli, no tag). Extent CAPS[r] = min(DP extent,
STK_CAP): the CLAMPED Fredkin ladder still acts on pairwise-distinct
qubits; on a full stack it rotates STK[STK_CAP-1] into Dw (overflow
drop, the E2 class); on a not-full stack it is the identical
shift as the uncapped ladder. Inter-slot swaps carry all STKW
lanes; the Dw level is value-only.
"""
E, STK = self.E, self.STK
capr = CAPS[r]
if not capr:
return
pqc = self.dW[SGN]
def sw(x, y):
if ctl:
E.cswap(pqc, x, y)
else:
E.swap(x, y)
for i2 in range(capr - 2, -1, -1):
for t_ in range(STKW):
sw(STK[i2][t_], STK[i2 + 1][t_])
for t_ in range(B):
sw(self.Dw[t_], STK[0][t_])
if not ctl:
return
# tag the incoming entry with its round: the vacated slot's tag lanes
# are |0> below overflow, so free CX from the push flag writes r
# exactly (overflow shots are the E2 class)
for bp in bitlist(r, TAGB):
E.cx(pqc, STK[0][B + bp])
⋯ 1 line
def erase_dw(self, ctl):
"""Erase Dw. Post-cascade Dw == ctl * Delta on every branch (d<0:
pushed, Dw = 0; ctl=0, d>=0: Delta = 0), and ctl=1 left sigma_0 =
1/Delta: Dw == ctl * inv(sigma_0), one chain on SIG[0] and a B-term
claim (stack overflow is the E2 class).
"""
E = self.E
with opened(E, "wreg", B) as wr, chain_live(E, self.SIG[0], wr):
E.free([norm_term((ctl,), 0, (wr[t_],), 0, (self.Dw[t_],)) for t_ in range(B)])
⋯ 1 line
def close_ctl(self, r, ctl):
"""d complement if ctl, then erase ctl (the caller closes its
window). Post-complement dW[SGN] = [ctl OR pushed], and a push at
this round iff the top tag reads r,
so ctl == dW[SGN] AND NOT [top tag == r]. Rounds the DP proves
push-free (and r=0) anchor on dW[SGN] alone, for free. On a stack
overflow the rotated-out tag corrupts the compare -- overflow shots
are already the E2 class.
"""
E, dW = self.E, self.dW
for i in range(DWB):
E.cx(ctl, dW[i])
if CAPS_FULL[r] == 0:
E.free([norm_term((dW[SGN],), 0, (), 1, (ctl,))])
else:
tag = self.STK[0][B:] # materialized at round_head
with opened(E, "eqt", TAGB - 1) as eqw:
flips = bitlist(~r & TAGMASK, TAGB)
for bp in flips:
E.x(tag[bp])
eqr = E.ladder([((tag[i],), 0) for i in range(TAGB)], eqw)
E.free([norm_term((dW[SGN],), 0, (eqw[TAGB - 2],), 1, (ctl,))])
E.frees(eqr)
for bp in flips:
E.x(tag[bp])
⋯ 107 lines
def reverse(self):
"""Stage 10, the journaled measurement-based reverse pass. Every BM
step went through J with its conjugate (macs record
release-or-recompute per the emit-time pebbling choice), so
replaying the conjugates in reverse re-materializes each round's
intermediates at the mirrored points and the replayed Fredkin
cascades pop the stack at exactly the right moments. The journal
replays closures over hard wire ids: each round's window pool is
re-materialized with reclaim right before its replay and freed
right after, and every bank slot is freed after the replay of its
first-touch round (its state there equals the forward state before
that round: |0>). The availability lines up by time symmetry -- an
id a bank slot took at forward round f is released before the
replays of rounds < f, exactly when their pools want it back -- and
reclaim fails closed on any gap.
"""
b, A, JR = self.b, self.A, self.JROUND
freed = 0
for k in range(len(JR) - 2, -1, -1):
rr = k - 1 # round -1 = the seed
with b.phase("reverse/seed" if rr < 0 else f"reverse/r{rr:02d}"):
if JR[k + 1] > JR[k]:
with A.replay(self.pools.get(rr, ())):
self.J.reverse(since=JR[k], until=JR[k + 1])
for reg in reversed(A.bank_log.get(rr, [])):
A.close(reg.name, reg.wires)
freed += 1
assert freed == len(self.SIG) + len(self.BB) + len(self.STK), (
"lazy registers leaked past the reverse",
freed,
)
Start (init): 0 Toffolis, peak 863 qubitsLinear phase (zlin): 0 Toffolis, peak 863 qubitsBerlekamp–Massey rounds (bm): 141,071 Toffolis, peak 1,813 qubitsNormalize (monicize): 1,583 Toffolis, peak 1,793 qubitsEvaluator (omega): 15,246 Toffolis, peak 1,758 qubitsHalf-degree Euclid (euclid): 44,470 Toffolis, peak 1,837 qubitsPosition scan (sweep): 92,552 Toffolis, peak 1,806 qubitsEuclid reversed (euclid_inv): 44,470 Toffolis, peak 1,837 qubitsEvaluator reversed (omega_restore): 15,246 Toffolis, peak 1,758 qubitsNormalize reversed (unmonicize): 1,583 Toffolis, peak 1,793 qubitsRounds reversed (reverse): 86,176 Toffolis, peak 1,813 qubitsCleanup (cleanup): 0 Toffolis, peak 863 qubits1,837840peak live qubits per phase, above the 840 I/O qubits4.4 × 10⁵ Toffolis →
def build():
"""Build the circuit and assert its pins. Returns (builder, Toffoli
count); the occupancy/liveness profilers consume its wire_log.
"""
# ---- registers, held scratch, allocators --------------------------------
b = Builder()
Start 0 Toffolis · peak 863 qubits
with b.phase("init"): # profile-stage blocks (metadata; emit nothing)
syn = list(declare_registers(b, [(f"s{r:02d}", B) for r in range(N)]).values())
assert all(list(syn[r]) == list(range(B * r, B * r + B)) for r in range(N)), (
"syn ids not contiguous"
) # qubits Br..Br+B-1
ANC = []
def An(n):
qs = b.qubits(n)
ANC.extend(qs)
return qs
Dw = An(B) # fused-Q working discrepancy register
dW = An(DWB) # two's-complement d counter
OMW = [syn[i] for i in range(W)] # omega lives IN PLACE in syn[0..W-1]
# Ownership wire-sets (claim/release bookkeeping; emits no op). Every
# long-lived wire joins exactly one named set with its full id list, so
# the anonymous pool live - sum(owned) is empty from init to cleanup;
# tools/occupancy_profile.py validates the discipline fail-closed.
b.claim("syn", [w for reg in syn for w in reg])
b.claim("dw", Dw)
b.claim("dcount", dW)
# Transient scratch round-trips through the allocator (A.open /
# A.close). Only state that persists between windows (discrepancies,
# stack, controls, counters, the Em pivots) stays held; everything that
# returns to |0> mid-circuit is freed there, so peak_qubits is the
# measured max co-live width and the liveness profile shows the true
# windows. Journal replays (the BM reverse, the Psi route) run
# closures over hard wire ids, so A logs the window ids a journal
# touches and re-materializes exactly that set before its replay
# (A.replay; reclaim fails closed when any id is not free).
A = Alloc(b)
sA = An(1)[0]
b.claim("pivA", [sA])
sB = An(1)[0]
b.claim("pivB", [sB])
sT = An(1)[0]
b.claim("fanT", [sT])
E = Em(b, sA, sB, sT, A)
bm = BM(E, A, syn, Dw, dW)
SIG = bm.SIG
# Width ledger: N * B syn + (B + DWB + 3) held (Dw, dW, pivots) + the
# lazily-materialized wires ((2W+3) B bank + STK_CAP tagged stack slots)
# + the late BM/reverse rounds' window tiling. The peak assert below
# enforces the total.
# ---- 1. zlin: free Z part sum_i Tr(u_i S_i) -----------------------------
Linear phase 0 Toffolis · peak 863 qubits
with b.phase("zlin"):
for i in range(N):
for bb in bitlist(ZMASKI[i], B):
b.z(syn[i][bb])
# ---- 2. bm: BM forward (q-form conditional-swap, single-chain m) --------
Berlekamp–Massey rounds 141,071 Toffolis · peak 1,813 qubits
bm.run()
# ---- 3. monicize: SIG[i] <- inv(sigma_0)*SIG[i] for i=1..W --------------
Normalize 1,583 Toffolis · peak 1,793 qubits
mon_stage(E, SIG, "monicize", range(1, W + 1), True)
# ---- 4. omega70 = sigma_m*S mod z^N, IN PLACE in syn[0..N-1] ------------
# sigma_m is monic: the triangles' diagonals span sigma_1..sigma_{W-1},
# the off-diagonal tail block's sigma_1..sigma_W (omega_rts).
# Rows W..N-1 (the TAIL) end at 0 on every correct decode and host the
# Bezout pair (stage 5).
MACRT = omega_rts(SIG, syn)
Evaluator 15,246 Toffolis · peak 1,758 qubits
omega_pass(E, MACRT, "omega", range(len(MACRT)))
# ---- 5. euclid: the half-degree Bezout pass (Psi route) -----------------
# sigma_m = E(z)^2 + z O(z)^2 with E_i = sqrt(sigma_2i), O_i =
# sqrt(sigma_2i+1): SIG[1..35] are square-rooted IN PLACE (a free linear
# map) and the Euclid bank EB is E = [ONE, SIG2, .., SIG34], O = [SIG1, ..,
# SIG35] (ONE is a fresh word holding 1 = E_0). m = floor((35 - L)/2) =
# (dW + 2) >> 2 (dW = the BM counter, +2 in place), and the barrel pad
# shifts both halves up by m words so deg E' = 17 on every correct decode.
# JSET journals the setup (ONE, the in-place square roots, dW += 2) so
# stage 7 undoes it with one reverse.
# PSI_IDS logs every scratch id the Psi journals touch; stages R and 7
# hold exactly that set around their replays.
Half-degree Euclid 44,470 Toffolis · peak 1,837 qubits
with b.phase("euclid/setup"):
ONE = A.open("one", B)
EPS = A.open("zprec", 6) # eps + 5-bit idx
PRE = A.open("pre", 1)[0]
PSI_IDS = set()
JSET, JPAD, JPRE, JF, JSEED = (Journal(), Journal(), Journal(), Journal(), Journal())
with E.using(J=JSET), A.logging(PSI_IDS):
E.x(ONE[0])
for i in range(1, W + 1):
JSET.step(
lambda r=list(SIG[i]): linear_in_place(b, r, SQRT_ROWS),
lambda r=list(SIG[i]): linear_in_place(b, r, SQUARE_ROWS),
)
# dW += 2: a constant increment on bits 1..7 (ladder carries, MBU-erased)
with opened(E, "inc", DWB - 3) as tr:
E.inc1(dW[1:DWB], tr)
EW = [ONE] + [list(SIG[2 * i]) for i in range(1, NH)]
OWD = [list(SIG[2 * i + 1]) for i in range(NH)]
MBITS = dW[2:7] # m = (dW + 2) >> 2
with b.phase("euclid/pad"), E.using(J=JPAD):
pad_barrel(E, MBITS, EW, OWD)
with b.phase("euclid/pre"), E.using(J=JPRE), A.logging(PSI_IDS):
psi_pre(E, EW, OWD, PRE)
with b.phase("euclid/F"), E.using(J=JF), A.logging(PSI_IDS):
F_FIN, _G_FIN, RECS = psi_forward(E, EW, OWD, EPS[0], EPS[1:6])
# ---- seed + R: the Bezout pair (a, b) grows in the TAIL + one EXT word --
# a[(m+1) % 18] <- inv(h) (h = the final F pivot), then R = the journal
# reverse of F interleaved with the cofactor recurrence: on exit EB holds
# (E', O') again and (a, b) = (A, B) with A E' + B O' = z^m, deg <= 17.
with b.phase("euclid/seed"):
TAILW = [list(syn[i]) for i in range(W, N)]
AW = TAILW[:NH]
with E.using(J=JSEED), A.logging(PSI_IDS):
psi_seed(E, F_FIN[NH - 1], MBITS, AW)
with b.phase("euclid/R"):
with A.replay(PSI_IDS, "psipool"):
EXT = A.open("ext", B) # opened under the replay hold: never a PSI_IDS id
BWD = TAILW[NH:] + [EXT]
JR, AFIN, BFIN = build_R(E, JF, RECS, AW, BWD, PRE, PSI_WIN, (EW, OWD))
JR.forward()
A.close("zprec", EPS)
# ---- 6. sweep: root flag + rank-12 Psi pairing over the M points --------
Position scan 92,552 Toffolis · peak 1,806 qubits
with b.phase("sweep"):
emit_sweep(b, E, A, OMW, EW + OWD, AFIN + BFIN)
# ---- 7. euclid_inv: R^-1, unseed, F^-1, un-pre, un-pad, un-setup --------
# The zprec and psipool holds span R..setup, so they open and close by
# hand (A.replay's two halves) in the first and last phase.
PSI_POOL = sorted(PSI_IDS)
Euclid reversed 44,470 Toffolis · peak 1,837 qubits
with b.phase("euclid_inv/R"):
A.reopen("zprec", EPS)
A.reopen("psipool", PSI_POOL)
JR.reverse()
A.close("ext", EXT)
with b.phase("euclid_inv/seed"):
JSEED.reverse()
with b.phase("euclid_inv/F"):
JF.reverse()
with b.phase("euclid_inv/pre"):
JPRE.reverse()
with b.phase("euclid_inv/pad"):
JPAD.reverse()
with b.phase("euclid_inv/setup"):
JSET.reverse()
A.close("psipool", PSI_POOL)
A.close("pre", [PRE])
A.close("zprec", EPS)
A.close("one", ONE)
# ---- 8. omega_restore: exact reversed block list ------------------------
# each block's targets are disjoint from its operands, so re-emitting the
# same term list un-XORs it; the reversed block order restores S exactly.
Evaluator reversed 15,246 Toffolis · peak 1,758 qubits
omega_pass(E, MACRT, "omega_restore", reversed(range(len(MACRT))))
# ---- 9. unmonicize: SIG[i] <- sigma_0*SIG[i] for i=W..1 -----------------
Normalize reversed 1,583 Toffolis · peak 1,793 qubits
mon_stage(E, SIG, "unmonicize", range(W, 0, -1), False)
# ---- 10. reverse: the journaled BM reverse pass -------------------------
Rounds reversed 86,176 Toffolis · peak 1,813 qubits
bm.reverse()
# ---- 11. cleanup ---------------------------------------------------------
# Release-before-free through the only teardown path: every workspace set
# returns its wires (full id lists, reverse claim order) ahead of the
# frees; the N * B syndrome wires stay owned to the end as the declared
# registers.
Cleanup 0 Toffolis · peak 863 qubits
with b.phase("cleanup"):
b.release("fanT", [sT])
b.release("pivB", [sB])
b.release("pivA", [sA])
b.release("dcount", dW)
b.release("dw", Dw)
b.recycle_all(reversed(ANC))
# =========================================================================
# Metrics gate, pre-emission: the pins under the measured window
# schedule and STK_CAP = 1.
# =========================================================================
TOF = assert_metrics(b, __file__)
return b, TOF