Hermitian DQI decoder

The same DQI phase, on a code built from the Hermitian curve. The discovered circuit turns decoding into linear algebra on a matrix it never writes down.

In brief

No reversible decoder for this code exists in the literature. The baseline is a direct translation of the Feng–Rao decoder (Sakata et al., 1995). It keeps every intermediate state until it runs backward, which drives its peak to 194,053 qubits. The paper reports it for scale only.

The discovered circuit finds the error locator as a null vector of a matrix built from the syndromes, but never stores the matrix. Each product with it is two fixed linear maps, which cost no Toffolis, around 123 small multiplications. A Lanczos walk finds the vector while holding only two vectors at a time.

TQ = 10¹⁰TQ = 10¹¹TQ = 10¹²TQ = 10¹³10⁴10⁵10⁶10⁷10⁸peak qubits Q →Toffoli count T →Discovered circuitFeng–Rao decoder, Sakata et al. (1995)Live qubits as Toffolis execute100M194,053
1

Registers

alloc_state

The input is the syndrome: 123 symbols of 𝔽64, 738 qubits. The error word lives on the 512 points of the Hermitian curve y8 = x9 + y and affects at most 47 of them. The circuit searches for the error locator among combinations of the first 48 monomials, so every vector of the walk has 48 symbols, or 288 qubits.

Two such vectors stay live for the whole run: the head WA and the mate WB, the current and the previous Lanczos vector. A third, X, is the locator register; it collects the null vector during the walk. The walk also keeps a six-bit freeze record and one journal bit per round.

The strips U and V2 hold Aw and, in repair rounds, A2w. They and the per-round scalars are parked outside their working window: their wires are |0⟩ and their ids return to the free list, so they count toward the peak only while in use.

def alloc_state(b):
"""Walk-state allocation in residency order: the syndrome register
(the io floor) first, then the resident walk core -- the wires live
from init to teardown -- and every episodically-held register above
it, so parked spans read as reusable ids, never as resident file.
"""
st = {}
sregs = b.qubits(738)
for r in range(123):
b.qubit_register(sregs[6 * r : 6 * r + 6])
st["s"] = sregs
# resident core (live init..teardown): the vector swap pair, the
# recurrence scalars, the freeze record, and the survival flags
for nm in ("WA", "WB"):
st[nm] = b.qubits(288)
for nm in _W_CORE:
st[nm] = b.qubits(6)
st["FZT"] = b.qubits(6)
for nm in ("exh", "capk1", "capk2"):
st[nm] = b.qubit()
# episodic registers, in window order: the x-carrier (init..seam),
# the swap journal (bit j: slot j..mirror slot j), the per-slot
# word file and flags, and the U/V2 strips
st["X"] = b.qubits(288)
st["SWJ"] = b.qubits(NSLOTS)
for nm in _K48_W + _W_AUX:
st[nm] = b.qubits(6)
st["scr"] = b.qubits(2)
st["zt"] = b.qubits(6)
for nm in _F_BASE + _F_SVC + _F_V3:
st[nm] = b.qubit()
for nm in ("U", "V2"):
st[nm] = b.qubits(288)
st["fix"] = []
# wire-set claims (metadata; emit nothing): the ownership names the
# meta.json viz roles anchor to. Mid-build frees of claimed wires
# (the _inv_p park, the sandwich hosts, the episodic parks) release
# first and re-claim after re-allocation.
b.claim("s", sregs)
for nm in ("WA", "WB", "U", "V2", "X"):
b.claim(nm, st[nm])
b.claim("scal", [q for nm in _SCAL for q in st[nm]])
b.claim("jrn", list(st["FZT"]) + list(st["SWJ"]))
b.claim("flag", list(st["scr"]) + list(st["zt"]) + [st[nm] for nm in _FLAGS])
# contiguous 48-id block (SG..Ca) that is |0> at the seam: hosts
# the sandwich's 48-bit sketch register K
st["K48"] = [q for nm in _K48_W for q in st[nm]]
assert st["K48"] == list(range(st["K48"][0], st["K48"][0] + 48))
# initial parks: every episodic register is |0> before slot 0
# (freshly allocated wires are |0>, so the parks emit nothing)
_park(b, st, ("V2", "U"))
_park(b, st, tuple(n for t in _TIERS for n in t[0] + t[1]), owner="scal")
_park(b, st, tuple(n for t in _TIERS for n in t[2]), owner="flag")
_park(b, st, ("SWJ",), owner="jrn")
return st
2

Seed the walk and run 52 rounds

init, P1

build_tables declares the fixed tables that the products with A read. _y0_init writes a fixed seed y0 into the head with X gates, at no Toffoli cost. The seed's symbols do not sum to zero, so no input can need a repair in the first round.

The forward walk runs 52 rounds: one per dimension of the 48-symbol space, plus four extension rounds in which delayed inputs can finish. Each round costs 5,400 Toffolis, or 11,964 and 16,557 when it carries depth-two and depth-three repair machinery. The first round costs 5,364, because it carries none.

T = build_tables(b)
st = alloc_state(b)
Start 0 Toffolis · peak 2,386 qubits
with b.phase("init"):
_y0_init(b, st)
Forward Lanczos walk 433,689 Toffolis · peak 2,395 qubits
for j in range(nsteps):
emit_slot(b, st, T, j)
3

Applying A without storing it

_matvec_core

The locator coefficients σ lie in the null space of the symmetric 48 × 48 matrix Akk′ = S(ψkψk′), whose entries are sums of one or two syndromes. The circuit never writes A down. It factors a product as Au = ΦT diag(η) Φu: Φ evaluates u at 123 fixed curve points, the weights ηp are linear in the syndromes, and ΦT maps the products back.

The loop visits the 123 points p. In each pass it gathers a parity of syndrome bits and a parity of vector bits onto two scratch qubits, with masks read from the tables. Fifteen passes AND the two parities and scatter the result into the 288 output bits. Together they form one 15-Toffoli multiplication in 𝔽64, so one product costs 123 · 15 = 1,845 Toffolis. Φ, η and ΦT appear only as gather and scatter masks, which cost CNOTs.

To clear a product, emit_matvec_mbu_loop measures the output in the X basis and replays the same gathers with outcome-conditioned CZ gates. This costs no Toffolis.

def _matvec_core(b, s_base, v_base, scr, LT, middle):
ua, vb = scr[0], scr[1]
with b.repeat(NPT) as p, b.repeat(NT16) as t:
with b.repeat(738) as pos, b.gated(LT["SB"], p * (NT16 * 738) + t * 738 + pos):
b.cx(s_base + pos, ua)
with b.repeat(288) as pos, b.gated(LT["VB"], p * (NT16 * 288) + t * 288 + pos):
b.cx(v_base + pos, vb)
middle(p, t, ua, vb)
⋯ 2 lines
def emit_matvec_proj_loop(b, s_base, v_base, out_base, scr, LT):
def middle(p, t, ua, vb):
with b.gated(LT["T15"], t):
tq = b.and_compute(ua, vb)
with b.repeat(288) as pos, b.gated(LT["TG"], p * (NT16 * 288) + t * 288 + pos):
b.cx(tq, out_base + pos)
with b.gated(LT["T15"], t):
b.and_release(tq, ua, vb)
_matvec_core(b, s_base, v_base, scr, LT, middle)
⋯ 2 lines
def emit_matvec_mbu_loop(b, s_base, v_base, out_base, scr, LT):
ms = [b.hmr(out_base + j) for j in range(288)]
def middle(p, t, ua, vb):
e0 = p * (NT16 * 288) + t * 288
for j in range(288):
with b.gated(LT["TG"], e0 + j):
b.cz(ua, vb, cond=ms[j])
_matvec_core(b, s_base, v_base, scr, LT, middle)
⋯ 504 lines
K, V3K, MEXT = 3, 6, 4
NSLOTS = NSTEPS + MEXT
# Slot 0 carries no service machinery: sigma(y0) != 0 on every lane
# (asserted by the emitter layer), so no lane can trigger -- let alone
# be serviced -- at slot 0. The schedule is unchanged (a slot-0
# service could never fire); only the dead machinery is elided.
SERVICE = frozenset(
{s for s in range(NSTEPS) if s % K == 0 and s} | {NSTEPS + i for i in range(MEXT) if i % 2 == 0}
)
V3CAP = frozenset(
{s for s in range(NSTEPS) if s % V3K == 0 and s}
| {NSTEPS + i for i in range(MEXT) if i % 2 == 0}
)
assert V3CAP <= SERVICE
⋯ 345 lines
def emit_slot(b, st, T, j, phase="P1"): # noqa: C901 - straight-line circuit emitter
"""Forward walk slot (mirrorable)."""
LT, MT = T["LT"], T["MT"]
service = j in SERVICE
v3cap = j in V3CAP
sb = flat_base([st["s"]])
hb, mb_ = flat_base([st["WA"]]), flat_base([st["WB"]])
Ub, Vb = flat_base([st["U"]]), flat_base([st["V2"]])
Xb = flat_base([st["X"]])
scr, zt = st["scr"], st["zt"]
swj = st["SWJ"][j]
with b.phase(f"{phase}/s{j:02d}"):
_slot_open(b, st, j, service, v3cap)
# B01 natives
emit_matvec_proj_loop(b, sb, hb, Ub, scr, LT)
emit_sigma_tap(b, hb, st["SG"])
_qscan1(b, T, sb, hb, st["QF"], scr)
emit_sigma_tap(b, Ub, st["DLT"])
# B02 trigger
emit_ztest(b, list(st["SG"]), st["trig"], zt)
_capf_tree(b, st, zt)
# B03 freeze
_freeze_fwd(b, st, j)
# B04 service natives
if service:
_unpark(b, st, ("V2",))
emit_matvec_proj_loop(b, sb, Ub, Vb, scr, LT)
_qscan1(b, T, sb, Ub, st["QU"], scr)
emit_ztest(b, list(st["QF"]), st["zqf"], zt)
if v3cap:
_qscan1(b, T, sb, Vb, st["QV"], scr)
emit_sigma_tap(b, Vb, st["SV"])
emit_ztest(b, list(st["DLT"]), st["zdd"], zt)
# B05 held gates + ptap routes
d2a = d3a = t_qz = None
t_nrm = b.and_compute(st["exh"], st["trig"], pol=(False, False))
if service:
t_tl = b.and_compute(st["exh"], st["trig"], pol=(False, True))
d2a = b.and_compute(t_tl, st["zqf"], pol=(True, False))
if v3cap:
t_qz = b.and_compute(t_tl, st["zqf"])
d3a = b.and_compute(t_qz, st["zdd"], pol=(True, False))
for q in range(6):
b.cswap(d2a, st["SG"][q], st["QF"][q])
if v3cap:
b.cswap(d3a, st["SG"][q], st["DLT"][q])
# B06 swap journal: SWJ[j] = t_nrm ^ d2a ^ d3a
b.cx(t_nrm, swj)
if service:
b.cx(d2a, swj)
if v3cap:
b.cx(d3a, swj)
# B07 engine + entering rotation
_inv_p(b, st, st["SG"], st["t6c"], scr)
if j == 0:
for q in range(6):
b.cx(st["SG"][q], st["KP"][q])
else:
emit_mac6(b, st["Cu"], st["t6c"], st["Z6"], scr)
for q in range(6):
b.cswap(swj, st["Cu"][q], st["Z6"][q])
emit_mac6(b, st["Cu"], st["SG"], st["Z6"], scr)
# B08 normal path
emit_mac6_gated(b, t_nrm, st["KP"], st["t6c"], st["XC"], scr)
emit_macv48(b, MT, st["XC"], hb, Xb, scr)
emit_mac6_gated(b, t_nrm, st["KP"], st["t6c"], st["XC"], scr)
emit_mac6_gated(b, t_nrm, st["QF"], st["t6c"], st["alpha"], scr)
emit_mac6(b, st["Cu"], st["alpha"], st["Ca"], scr)
emit_mac6(b, st["Ca"], st["KP"], st["KM"], scr)
for q in range(6):
b.cswap(t_nrm, st["KP"][q], st["KM"][q])
_G8.mw_xor(b, t_nrm, st["Cu"], st["t6b"])
emit_macv48(b, MT, st["t6b"], Ub, mb_, scr)
_G8.mw_xor(b, t_nrm, st["Cu"], st["t6b"])
emit_macv48(b, MT, st["Ca"], hb, mb_, scr)
# B09 service block
if service:
_coeffs(b, st, d2a, d3a)
_xmacs(b, st, T, d2a, d3a)
_kappa_block(b, st, d2a, d3a)
_assembly(b, st, T, d2a, d3a)
emit_mac6(b, st["Cu"], st["BA0"], st["BFC"], scr) # BFC clear
_coeffs(b, st, d2a, d3a, rev=True)
if v3cap:
_G8.mw_xor(b, d3a, st["Cu"], st["XC"]) # CV3 stage
# B10 clears + leaving rotation
emit_mac6_mbu(b, st["Cu"], st["alpha"], st["Ca"], scr)
emit_mac6_gated_mbu(b, t_nrm, st["QF"], st["t6c"], st["alpha"], scr)
emit_mac6(b, st["Cu"], st["SG"], st["Z6"], scr)
for q in range(6):
b.cswap(swj, st["Cu"][q], st["Z6"][q])
emit_mac6(b, st["Cu"], st["t6c"], st["Z6"], scr)
_inv_p(b, st, st["SG"], st["t6c"], scr)
if service:
for q in range(6):
if v3cap:
b.cswap(d3a, st["SG"][q], st["DLT"][q])
b.cswap(d2a, st["SG"][q], st["QF"][q])
# B11 capf underive
_capf_conj(b, st, j, zt)
# B12 held-gate releases (zqf/zdd/trig/exh live)
if service:
if v3cap:
b.and_release(d3a, t_qz, st["zdd"], pol=(True, False))
b.and_release(t_qz, t_tl, st["zqf"])
b.and_release(d2a, t_tl, st["zqf"], pol=(True, False))
b.and_release(t_tl, st["exh"], st["trig"], pol=(False, True))
b.and_release(t_nrm, st["exh"], st["trig"], pol=(False, False))
# B13 zqf/zdd underives (QF/DLT live)
if service:
emit_ztest(b, list(st["QF"]), st["zqf"], zt)
if v3cap:
emit_ztest(b, list(st["DLT"]), st["zdd"], zt)
# B14 trig underive (SG live)
emit_ztest(b, list(st["SG"]), st["trig"], zt)
# B15 tap clears (strip sources live)
if service:
_qscan1_mbu(b, T, sb, Ub, st["QU"], scr)
if v3cap:
_qscan1_mbu(b, T, sb, Vb, st["QV"], scr)
emit_sigma_tap(b, Vb, st["SV"])
_qscan1_mbu(b, T, sb, hb, st["QF"], scr)
emit_sigma_tap(b, Ub, st["DLT"])
emit_sigma_tap(b, hb, st["SG"])
# B16 dances + disposals
if service:
emit_matvec_mbu_loop(b, sb, hb, Ub, scr, LT) # U clear #1
if v3cap:
emit_matvec_proj_loop(b, sb, Vb, Ub, scr, LT) # U = v3
emit_macv48(b, MT, st["XC"], Ub, mb_, scr) # Cu*v3
st["fix"].append(("cv3", j, [b.hmr(st["XC"][q]) for q in range(6)]))
emit_matvec_mbu_loop(b, sb, Vb, Ub, scr, LT) # U clear
st["fix"].append(("v2d", j, [b.hmr(st["V2"][q]) for q in range(288)]))
_park(b, st, ("V2",))
else:
emit_matvec_mbu_loop(b, sb, hb, Ub, scr, LT)
# B17 role swap on the journal bit
_cswap288(b, swj, hb, mb_)
_slot_close(b, st, j, service, v3cap)
4

One round: update, freeze, or repair

emit_slot

A round first forms U = Aw for the head w and three scalars gk = wTAkw. In characteristic 2, g0 is the square of the sum of the symbols of w, so emit_sigma_tap forms it with CNOTs; g2 comes the same way from U, and _qscan1 forms g1. Zero tests of these scalars detect the end of the walk, g0 = g1 = g2 = 0. _freeze_fwd then writes the round into the freeze record.

The ordinary update acts under t_nrm: the walk has not ended and g0 ≠ 0. The round inverts g0, adds a multiple of w into X, and forms the projection coefficient. It then adds multiples of Aw and w into the mate, which held the previous vector. Symmetry of A makes this three-term recurrence enough. A journal bit records whether the round advanced, and the round ends by exchanging head and mate under it.

Over 𝔽64 a nonzero vector can have g0 = 0. On such an input no update gate acts, and the walk stays frozen until a scheduled repair round. Rounds in SERVICE (every third, and two extension rounds) can repair at depth two, and those in V3CAP (every sixth, and the same extension rounds) at depth three. Together they make 17 of the 52 rounds. They compute A2w, select depth two when g1 ≠ 0 and depth three when only g2 ≠ 0, and advance the walk past the whole block. A deeper block fails.

The round clears its scratch in reverse order, mostly by measurement. A repair round measures V2 and records the outcomes; the reverse walk repairs their phase.

def _matvec_core(b, s_base, v_base, scr, LT, middle):
ua, vb = scr[0], scr[1]
with b.repeat(NPT) as p, b.repeat(NT16) as t:
with b.repeat(738) as pos, b.gated(LT["SB"], p * (NT16 * 738) + t * 738 + pos):
b.cx(s_base + pos, ua)
with b.repeat(288) as pos, b.gated(LT["VB"], p * (NT16 * 288) + t * 288 + pos):
b.cx(v_base + pos, vb)
middle(p, t, ua, vb)
⋯ 2 lines
def emit_matvec_proj_loop(b, s_base, v_base, out_base, scr, LT):
def middle(p, t, ua, vb):
with b.gated(LT["T15"], t):
tq = b.and_compute(ua, vb)
with b.repeat(288) as pos, b.gated(LT["TG"], p * (NT16 * 288) + t * 288 + pos):
b.cx(tq, out_base + pos)
with b.gated(LT["T15"], t):
b.and_release(tq, ua, vb)
_matvec_core(b, s_base, v_base, scr, LT, middle)
⋯ 2 lines
def emit_matvec_mbu_loop(b, s_base, v_base, out_base, scr, LT):
ms = [b.hmr(out_base + j) for j in range(288)]
def middle(p, t, ua, vb):
e0 = p * (NT16 * 288) + t * 288
for j in range(288):
with b.gated(LT["TG"], e0 + j):
b.cz(ua, vb, cond=ms[j])
_matvec_core(b, s_base, v_base, scr, LT, middle)
⋯ 504 lines
K, V3K, MEXT = 3, 6, 4
NSLOTS = NSTEPS + MEXT
# Slot 0 carries no service machinery: sigma(y0) != 0 on every lane
# (asserted by the emitter layer), so no lane can trigger -- let alone
# be serviced -- at slot 0. The schedule is unchanged (a slot-0
# service could never fire); only the dead machinery is elided.
SERVICE = frozenset(
{s for s in range(NSTEPS) if s % K == 0 and s} | {NSTEPS + i for i in range(MEXT) if i % 2 == 0}
)
V3CAP = frozenset(
{s for s in range(NSTEPS) if s % V3K == 0 and s}
| {NSTEPS + i for i in range(MEXT) if i % 2 == 0}
)
assert V3CAP <= SERVICE
⋯ 345 lines
def emit_slot(b, st, T, j, phase="P1"): # noqa: C901 - straight-line circuit emitter
"""Forward walk slot (mirrorable)."""
LT, MT = T["LT"], T["MT"]
service = j in SERVICE
v3cap = j in V3CAP
sb = flat_base([st["s"]])
hb, mb_ = flat_base([st["WA"]]), flat_base([st["WB"]])
Ub, Vb = flat_base([st["U"]]), flat_base([st["V2"]])
Xb = flat_base([st["X"]])
scr, zt = st["scr"], st["zt"]
swj = st["SWJ"][j]
with b.phase(f"{phase}/s{j:02d}"):
_slot_open(b, st, j, service, v3cap)
# B01 natives
emit_matvec_proj_loop(b, sb, hb, Ub, scr, LT)
emit_sigma_tap(b, hb, st["SG"])
_qscan1(b, T, sb, hb, st["QF"], scr)
emit_sigma_tap(b, Ub, st["DLT"])
# B02 trigger
emit_ztest(b, list(st["SG"]), st["trig"], zt)
_capf_tree(b, st, zt)
# B03 freeze
_freeze_fwd(b, st, j)
# B04 service natives
if service:
_unpark(b, st, ("V2",))
emit_matvec_proj_loop(b, sb, Ub, Vb, scr, LT)
_qscan1(b, T, sb, Ub, st["QU"], scr)
emit_ztest(b, list(st["QF"]), st["zqf"], zt)
if v3cap:
_qscan1(b, T, sb, Vb, st["QV"], scr)
emit_sigma_tap(b, Vb, st["SV"])
emit_ztest(b, list(st["DLT"]), st["zdd"], zt)
# B05 held gates + ptap routes
d2a = d3a = t_qz = None
t_nrm = b.and_compute(st["exh"], st["trig"], pol=(False, False))
if service:
t_tl = b.and_compute(st["exh"], st["trig"], pol=(False, True))
d2a = b.and_compute(t_tl, st["zqf"], pol=(True, False))
if v3cap:
t_qz = b.and_compute(t_tl, st["zqf"])
d3a = b.and_compute(t_qz, st["zdd"], pol=(True, False))
for q in range(6):
b.cswap(d2a, st["SG"][q], st["QF"][q])
if v3cap:
b.cswap(d3a, st["SG"][q], st["DLT"][q])
# B06 swap journal: SWJ[j] = t_nrm ^ d2a ^ d3a
b.cx(t_nrm, swj)
if service:
b.cx(d2a, swj)
if v3cap:
b.cx(d3a, swj)
# B07 engine + entering rotation
_inv_p(b, st, st["SG"], st["t6c"], scr)
if j == 0:
for q in range(6):
b.cx(st["SG"][q], st["KP"][q])
else:
emit_mac6(b, st["Cu"], st["t6c"], st["Z6"], scr)
for q in range(6):
b.cswap(swj, st["Cu"][q], st["Z6"][q])
emit_mac6(b, st["Cu"], st["SG"], st["Z6"], scr)
# B08 normal path
emit_mac6_gated(b, t_nrm, st["KP"], st["t6c"], st["XC"], scr)
emit_macv48(b, MT, st["XC"], hb, Xb, scr)
emit_mac6_gated(b, t_nrm, st["KP"], st["t6c"], st["XC"], scr)
emit_mac6_gated(b, t_nrm, st["QF"], st["t6c"], st["alpha"], scr)
emit_mac6(b, st["Cu"], st["alpha"], st["Ca"], scr)
emit_mac6(b, st["Ca"], st["KP"], st["KM"], scr)
for q in range(6):
b.cswap(t_nrm, st["KP"][q], st["KM"][q])
_G8.mw_xor(b, t_nrm, st["Cu"], st["t6b"])
emit_macv48(b, MT, st["t6b"], Ub, mb_, scr)
_G8.mw_xor(b, t_nrm, st["Cu"], st["t6b"])
emit_macv48(b, MT, st["Ca"], hb, mb_, scr)
# B09 service block
if service:
_coeffs(b, st, d2a, d3a)
_xmacs(b, st, T, d2a, d3a)
_kappa_block(b, st, d2a, d3a)
_assembly(b, st, T, d2a, d3a)
emit_mac6(b, st["Cu"], st["BA0"], st["BFC"], scr) # BFC clear
_coeffs(b, st, d2a, d3a, rev=True)
if v3cap:
_G8.mw_xor(b, d3a, st["Cu"], st["XC"]) # CV3 stage
# B10 clears + leaving rotation
emit_mac6_mbu(b, st["Cu"], st["alpha"], st["Ca"], scr)
emit_mac6_gated_mbu(b, t_nrm, st["QF"], st["t6c"], st["alpha"], scr)
emit_mac6(b, st["Cu"], st["SG"], st["Z6"], scr)
for q in range(6):
b.cswap(swj, st["Cu"][q], st["Z6"][q])
emit_mac6(b, st["Cu"], st["t6c"], st["Z6"], scr)
_inv_p(b, st, st["SG"], st["t6c"], scr)
if service:
for q in range(6):
if v3cap:
b.cswap(d3a, st["SG"][q], st["DLT"][q])
b.cswap(d2a, st["SG"][q], st["QF"][q])
# B11 capf underive
_capf_conj(b, st, j, zt)
# B12 held-gate releases (zqf/zdd/trig/exh live)
if service:
if v3cap:
b.and_release(d3a, t_qz, st["zdd"], pol=(True, False))
b.and_release(t_qz, t_tl, st["zqf"])
b.and_release(d2a, t_tl, st["zqf"], pol=(True, False))
b.and_release(t_tl, st["exh"], st["trig"], pol=(False, True))
b.and_release(t_nrm, st["exh"], st["trig"], pol=(False, False))
# B13 zqf/zdd underives (QF/DLT live)
if service:
emit_ztest(b, list(st["QF"]), st["zqf"], zt)
if v3cap:
emit_ztest(b, list(st["DLT"]), st["zdd"], zt)
# B14 trig underive (SG live)
emit_ztest(b, list(st["SG"]), st["trig"], zt)
# B15 tap clears (strip sources live)
if service:
_qscan1_mbu(b, T, sb, Ub, st["QU"], scr)
if v3cap:
_qscan1_mbu(b, T, sb, Vb, st["QV"], scr)
emit_sigma_tap(b, Vb, st["SV"])
_qscan1_mbu(b, T, sb, hb, st["QF"], scr)
emit_sigma_tap(b, Ub, st["DLT"])
emit_sigma_tap(b, hb, st["SG"])
# B16 dances + disposals
if service:
emit_matvec_mbu_loop(b, sb, hb, Ub, scr, LT) # U clear #1
if v3cap:
emit_matvec_proj_loop(b, sb, Vb, Ub, scr, LT) # U = v3
emit_macv48(b, MT, st["XC"], Ub, mb_, scr) # Cu*v3
st["fix"].append(("cv3", j, [b.hmr(st["XC"][q]) for q in range(6)]))
emit_matvec_mbu_loop(b, sb, Vb, Ub, scr, LT) # U clear
st["fix"].append(("v2d", j, [b.hmr(st["V2"][q]) for q in range(288)]))
_park(b, st, ("V2",))
else:
emit_matvec_mbu_loop(b, sb, hb, Ub, scr, LT)
# B17 role swap on the journal bit
_cswap288(b, swj, hb, mb_)
_slot_close(b, st, j, service, v3cap)
5

Route the null vector

mux

After the last round, emit_sandwich decides which vector is the null vector. If w = 0, the Krylov vectors have become dependent and X already holds it. If w ≠ 0 and Aw = 0, w is the null vector; if Aw ≠ 0 and A2w = 0, Aw is. An input in none of the three cases fails.

The circuit tests w ≠ 0, stages U = Aw, and sets capk1 for the second case. Each exact test is one 288-leaf AND tree, 287 Toffolis, whose nodes live on the idle V2 wires. For the third case it does not test the 288 bits of A2w. It forms a fixed 48-bit linear sketch and tests that. A zero vector always gives a zero sketch; a nonzero one gives a zero sketch with probability 2−48.

Two controlled swaps move Aw or w into X.

if not rev:
_unpark(b, st, ("U",))
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
b.x(pnz) # pnz = [WA != 0]
emit_matvec_proj_loop(b, sb, hb, Ub, scr, LT) # U = B*WA
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
t = b.and_compute(pnz, z1)
b.cx(t, st["capk1"])
b.and_release(t, pnz, z1)
b.x(z1)
tP = b.and_compute(pnz, z1) # held across the sketch
emit_sketch_proj(b, sb, Ub, st["K48"][0], scr, LT)
_ktree_flat(b, st, tP)
emit_sketch_mbu(b, sb, Ub, list(st["K48"]), scr, LT)
b.and_release(tP, pnz, z1)
b.x(z1)
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
b.x(pnz)
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
_cswap288(b, st["capk2"], xb, Ub)
_cswap288(b, st["capk1"], xb, hb)
6

The striped phase scan

tail

The locator gives the possible error points, and the phase also needs the error values, e = ω/σ′ at a simple zero. Holding the evaluator ω through the whole scan would occupy more than 100 field symbols. Holding the decoded error word would occupy 3,072 qubits.

emit_tail_stripe instead scans the curve points in stripes of 16. It reads the locator from X. Every register that is |0⟩ here is already parked, so the scan takes its workspace from the free list.

if with_tail:
# Every |0>-at-seam word is already parked by the slot and
# sandwich closes (NOT U: the k2 staging; NOT the resident
# core), so the tail allocates its pools straight from the
# free-list.
Striped phase scan 102,192 Toffolis · peak 2,385 qubits
with b.phase("tail"):
emit_tail_stripe(b, st, st["X"], k=16)
7

One stripe: fill, sweep, erase

tail/fill, tail/sweep, tail/unfill

Part of the phase is linear in the syndromes; Z gates on syndrome bits apply it. The remaining constant vanishes at 128 of the 512 points, which leaves 384 points to scan: 24 stripes of 16.

The fill computes the 48 local coefficients of ω that the stripe needs, three per point, by evaluation–interpolation. A fixed fraction h = n/q, with a numerator linear in the syndromes, stands in for the syndrome series. All products σh lie in a fixed 206-dimensional space, so the fill evaluates both factors at 206 points and multiplies them pointwise, 206 · 15 = 3,090 Toffolis per stripe. A fixed linear fold maps the products into the stripe's bank.

The sweep visits each point. CNOTs gather the local coefficients of σ, which are linear in X. Three zero flags test the first three of them: fr marks a zero of σ, and z1 and z2 mark that the next two also vanish, which signals a repeated zero of multiplicity up to three. The flags select which coefficients enter the quotient. The tower core forms the phase bit Tr(μ̃ω/σ′) with an inverse in 𝔽8, at 33 ANDs per point, and applies it only where σ vanishes. Measurements then clear the per-point values.

The erase measures the bank and corrects the phase with CZ gates, at no Toffoli cost. The 24 stripes cost 102,192 Toffolis; neither an evaluator nor a decoded error word is ever live.

def emit_bank_stripe(b, BQ, si, TT, lam, s, rev, acc6): # noqa: C901 - straight-line circuit emitter
"""Fill (rev=False) / release (rev=True) a stripe bank: one
repeat(206) whose body carries the dense gather/fold meshes,
gated on the LEVT/GEVT/fold bit tables (TT) at t-affine indices
(the MUL64 bit meshes of the evaluation pairs, scanned in
(row, r, j) order). Fill: gated LT/GT gathers, one 15-Tof MAC
into vq, gated fold vq -> bank words, MBU vq on in-body recycled
outcomes. Release is the unomq pattern: hmr the bank, then per
product -- gated gathers, gated OXOR accumulation of the product
mask mu_t onto the six zero-valued acc6 handles, the mesh walk
vs acc6, gated OXOR un-accumulation restoring acc6 to zero (the
OXOR lane work is free and unscored, and the six shared handles
keep the outcome-id space small). acc6 is minted zero once, at
the first release stripe, through the public algebra (fresh
combine, then XOR both sources back out).
"""
W = len(BQ) // 6
FST = 206 * W * 36
LT6 = b.qubits(6)
GT6 = b.qubits(6)
def _lt(t):
for l in range(48):
for r in range(6):
for j in range(6):
with b.gated(TT["LT"], t * 1728 + l * 36 + r * 6 + j):
b.cx(lam[6 * l + j], LT6[r])
def _gt(t):
for kx in range(123):
for r in range(6):
for j in range(6):
with b.gated(TT["GT"], t * 4428 + kx * 36 + r * 6 + j):
b.cx(s[6 * kx + j], GT6[r])
def _fbit(t, Wi, r, j):
return si * FST + t * (W * 36) + Wi * 36 + r * 6 + j
if not rev:
vq = b.qubits(6)
with b.repeat(206) as t:
_lt(t)
_gt(t)
emit_mac_g(b, (LT6, 0), I6M, (GT6, 0), I6M, macc=(vq, 0))
for Wi in range(W):
for r in range(6):
for j in range(6):
with b.gated(TT["FOLD"], _fbit(t, Wi, r, j)):
b.cx(vq[j], BQ[6 * Wi + r])
ms = [b.hmr(vq[j]) for j in range(6)]
def mid(_mi, om, ta, tb):
for j in range(6):
if (om >> j) & 1:
b.cz(ta, tb, cond=ms[j])
_walk_g(b, (LT6, 0), I6M, (GT6, 0), I6M, mid)
for m_ in ms:
b.retire(m_)
_gt(t)
_lt(t)
else:
mW = [[b.hmr(BQ[6 * Wi + r]) for r in range(6)] for Wi in range(W)]
if not acc6:
for _ in range(6):
a = mW[0][0] ^ mW[0][1]
a ^= mW[0][0]
a ^= mW[0][1]
acc6.append(a)
def _mus(t):
# mu_t accumulation onto acc6: dense (j, Wi, r) scan of
# the fold table's column for product t
for j in range(6):
for Wi in range(W):
for r in range(6):
with b.gated(TT["FOLD"], _fbit(t, Wi, r, j)):
acc6[j] ^= mW[Wi][r]
with b.repeat(206) as t:
_lt(t)
_gt(t)
_mus(t)
def mid(_mi, om, ta, tb):
for j in range(6):
if (om >> j) & 1:
b.cz(ta, tb, cond=acc6[j])
_walk_g(b, (LT6, 0), I6M, (GT6, 0), I6M, mid)
_mus(t)
_gt(t)
_lt(t)
for row in mW:
for m_ in row:
b.retire(m_)
if not rev:
b.recycle_all(list(reversed(list(vq))))
b.recycle_all(list(reversed(list(GT6))))
b.recycle_all(list(reversed(list(LT6))))
⋯ 2 lines
# -- the bit-collapsed tower-core sweep
# The sweep's per-point pay Tr2(mu * w / c) collapses to the tower
# form Tr8_2( inv8(N(c)) * Tr64_8(mu * w * c^8) ), N(c) = c^9 in the
# S8 subfield (exhaustively asserted below): 9 + 3 + 18 + 3 = 33 ANDs
# per point, against about 52 for a 3-product inversion ladder plus a
# masked pay walk. inv8(0) = 0 pays 0 at c = 0.
⋯ 306 lines
for r, j in SW_SYNZ:
b.z(s[6 * r + j])
for si in range(NL // k):
with b.phase("tail/fill"):
emit_bank_stripe(b, BQ, si, TT, lam, s, rev=False, acc6=acc6)
with b.phase("tail/sweep"):
l_any = lam_bits[:, :, k * si : k * (si + 1)].any(axis=2)
with b.repeat(k) as ip:
def gathers():
for lvl in range(4):
for sl in range(48):
cell = l_any[lvl, sl]
base = si * k * LSTRIDE + (lvl * 48 + sl) * 36
for r in range(6):
for j in range(6):
if cell[r, j]:
with b.gated(TBL, ip * LSTRIDE + base + r * 6 + j):
b.cx(lam[6 * sl + j], Lh[6 * lvl + r])
for w in range(3 * k):
for r in range(6):
with b.gated(TSEL, ip * (3 * k) + w):
b.cx(BQ[6 * w + r], Wh[6 * (w % 3) + r])
gathers()
_fc_copies(False)
ch_fr = _flag(0)
ch_z1 = _flag(6)
ch_z2 = _flag(12)
fr, z1, z2 = ch_fr[-1], ch_z1[-1], ch_z2[-1]
t12 = b.and_compute(z1, z2)
_dq_diffs()
for src, so, da, db, co in MUX:
for j in range(6):
b.cx(src[so + j], cw[co + j])
b.ccx(z1, DQ[da + j], cw[co + j])
b.ccx(t12, DQ[db + j], cw[co + j])
# ---- tower core: N(c), inv8, b'(mu; w, c), pay ----
for bi in range(3):
_gfix(TC["ndec"][bi], [cw[q] for q in range(6)], NB[bi], mbu=False)
for bi in range(3):
_gfix(TC["idec"][bi], list(NB), MB[bi], mbu=False)
pbase = si * k * 18
for t in range(18):
with b.repeat(6) as jq:
with b.gated(TWM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[6 + jq], ua)
with b.gated(TCM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[jq], vb)
tq = b.and_compute(ua, vb)
with b.repeat(3) as jq, b.gated(TOM, ip * 18 * 3 + pbase * 3 + t * 3 + jq):
b.cx(tq, BB[jq])
b.and_release(tq, ua, vb)
with b.repeat(6) as jq:
with b.gated(TCM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[jq], vb)
with b.gated(TWM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[6 + jq], ua)
for u, v in TC["fdec"]:
for kk in range(3):
if u[kk]:
b.cx(BB[kk], ua)
if v[kk]:
b.cx(MB[kk], vb)
tq = b.and_compute(ua, vb)
b.cz(fr, tq)
b.and_release(tq, ua, vb)
for kk in range(3):
if v[kk]:
b.cx(MB[kk], vb)
if u[kk]:
b.cx(BB[kk], ua)
# ---- tower-core uncompute: b' mesh, inv8, N ----
msb = [b.hmr(BB[jq]) for jq in range(3)]
for t in range(18):
with b.repeat(6) as jq:
with b.gated(TWM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[6 + jq], ua)
with b.gated(TCM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[jq], vb)
for jq in range(3):
with b.gated(TOM, ip * 18 * 3 + pbase * 3 + t * 3 + jq):
b.cz(ua, vb, cond=msb[jq])
with b.repeat(6) as jq:
with b.gated(TCM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[jq], vb)
with b.gated(TWM, ip * 18 * 6 + pbase * 6 + t * 6 + jq):
b.cx(cw[6 + jq], ua)
for m_ in msb:
b.retire(m_)
for bi in (2, 1, 0):
_gfix(TC["idec"][bi], list(NB), MB[bi], mbu=True)
for bi in (2, 1, 0):
_gfix(TC["ndec"][bi], [cw[q] for q in range(6)], NB[bi], mbu=True)
# ---- MUX unwind ----
for src, so, da, db, co in MUX:
for j in range(6):
m = b.hmr(cw[co + j])
b.z(src[so + j], cond=m)
b.cz(z1, DQ[da + j], cond=m)
b.cz(t12, DQ[db + j], cond=m)
b.retire(m)
_dq_diffs()
b.and_release(t12, z1, z2)
for chain, base in ((ch_z2, 12), (ch_z1, 6), (ch_fr, 0)):
_unflag(chain, base)
_fc_copies(True)
gathers()
with b.phase("tail/unfill"):
emit_bank_stripe(b, BQ, si, TT, lam, s, rev=True, acc6=acc6)
8

Reverse the routing, measure the locator

unmux, xseam

The same emitter in reverse swaps the routed vector back, reruns the tests to clear their flags, and clears U by measurement.

The circuit then measures all 288 qubits of X in the X basis and parks the register. The outcomes sx fix the phase that the reverse walk must correct.

Choice reversed 3,619 Toffolis · peak 2,311 qubits
with b.phase("unmux"):
emit_sandwich(b, st, T, rev=True)
Measure locator 0 Toffolis · peak 1,681 qubits
with b.phase("xseam"):
sx = [b.hmr(st["X"][q]) for q in range(288)]
_park(b, st, ("X",))
9

The reverse walk

P2

emit_slot_mirror retraces the rounds from the last to the first. Each forward addition into X becomes CZ gates conditioned on sx, at no Toffoli cost. The mirror reruns the zero tests while their vectors are live. It reads the journal bit to undo the head–mate exchange, then clears it.

A repair round's measurement of V2 left a phase. The mirror recomputes V2 and corrects that phase from the outcomes in fixmap; every recorded repair is used. The reverse walk uses 51,741 fewer Toffolis than the forward walk. _y0_teardown removes the seed, and only the syndrome remains.

fixmap = {(tag, jj): ids for (tag, jj, ids) in st["fix"]}
Reverse walk 381,948 Toffolis · peak 2,107 qubits
for j in range(nsteps - 1, -1, -1):
emit_slot_mirror(b, st, T, j, sx, fixmap)
assert not fixmap, f"unconsumed fixups: {sorted(fixmap)}"
for o in sx:
b.retire(o)
with b.phase("P2/init"):
_y0_teardown(b, st)
Start (init): 0 Toffolis, peak 2,386 qubitsForward Lanczos walk (P1): 433,689 Toffolis, peak 2,395 qubitsChoose null vector (mux): 5,464 Toffolis, peak 2,311 qubitsStriped phase scan (tail): 102,192 Toffolis, peak 2,385 qubitsChoice reversed (unmux): 3,619 Toffolis, peak 2,311 qubitsMeasure locator (xseam): 0 Toffolis, peak 1,681 qubitsReverse walk (P2): 381,948 Toffolis, peak 2,107 qubits2,395738peak live qubits per phase, above the 738 I/O qubits9.3 × 10⁵ Toffolis →
def alloc_state(b):
"""Walk-state allocation in residency order: the syndrome register
(the io floor) first, then the resident walk core -- the wires live
from init to teardown -- and every episodically-held register above
it, so parked spans read as reusable ids, never as resident file.
"""
st = {}
sregs = b.qubits(738)
for r in range(123):
b.qubit_register(sregs[6 * r : 6 * r + 6])
st["s"] = sregs
# resident core (live init..teardown): the vector swap pair, the
# recurrence scalars, the freeze record, and the survival flags
for nm in ("WA", "WB"):
st[nm] = b.qubits(288)
for nm in _W_CORE:
st[nm] = b.qubits(6)
st["FZT"] = b.qubits(6)
for nm in ("exh", "capk1", "capk2"):
st[nm] = b.qubit()
# episodic registers, in window order: the x-carrier (init..seam),
# the swap journal (bit j: slot j..mirror slot j), the per-slot
# word file and flags, and the U/V2 strips
st["X"] = b.qubits(288)
st["SWJ"] = b.qubits(NSLOTS)
for nm in _K48_W + _W_AUX:
st[nm] = b.qubits(6)
st["scr"] = b.qubits(2)
st["zt"] = b.qubits(6)
for nm in _F_BASE + _F_SVC + _F_V3:
st[nm] = b.qubit()
for nm in ("U", "V2"):
st[nm] = b.qubits(288)
st["fix"] = []
# wire-set claims (metadata; emit nothing): the ownership names the
# meta.json viz roles anchor to. Mid-build frees of claimed wires
# (the _inv_p park, the sandwich hosts, the episodic parks) release
# first and re-claim after re-allocation.
b.claim("s", sregs)
for nm in ("WA", "WB", "U", "V2", "X"):
b.claim(nm, st[nm])
b.claim("scal", [q for nm in _SCAL for q in st[nm]])
b.claim("jrn", list(st["FZT"]) + list(st["SWJ"]))
b.claim("flag", list(st["scr"]) + list(st["zt"]) + [st[nm] for nm in _FLAGS])
# contiguous 48-id block (SG..Ca) that is |0> at the seam: hosts
# the sandwich's 48-bit sketch register K
st["K48"] = [q for nm in _K48_W for q in st[nm]]
assert st["K48"] == list(range(st["K48"][0], st["K48"][0] + 48))
# initial parks: every episodic register is |0> before slot 0
# (freshly allocated wires are |0>, so the parks emit nothing)
_park(b, st, ("V2", "U"))
_park(b, st, tuple(n for t in _TIERS for n in t[0] + t[1]), owner="scal")
_park(b, st, tuple(n for t in _TIERS for n in t[2]), owner="flag")
_park(b, st, ("SWJ",), owner="jrn")
return st
⋯ 606 lines
def emit_sandwich(b, st, T, rev=False):
"""Fused kind tests + k2 lam staging. capk1 ^= [WA != 0] &
[B*WA == 0]; capk2 ^= [WA != 0] & [B*WA != 0] & [K == 0], with
K = R.(B*U) the one-sided 48-bit sketch of B^2*WA. The staged
U = B*WA is the k2 lam park (U is NOT poolable through the tail).
Test trees host in V2's dead ids; K hosts on the coefficient
words -- both provably |0> here (the battery gates it).
"""
LT = T["LT"]
sb = flat_base([st["s"]])
hb, Ub = flat_base([st["WA"]]), flat_base([st["U"]])
xb = flat_base([st["X"]])
scr = st["scr"]
pnz, z1 = st["zqf"], st["zdd"]
borrow = ("scr", "zqf", "zdd") # scr + the wires pnz/z1 borrow
host = list(st["V2"])
# V2 is the host pool for the strip ztest trees and the K tree in
# this span: re-materialized from its park, ownership released for
# hosting, re-claimed and re-parked at exit. The sketch hosts and
# the borrowed test flags re-materialize alongside it.
_unpark(b, st, ("V2",))
_unpark(b, st, _K48_W, owner="scal")
_unpark(b, st, borrow, owner="flag")
b.release("V2", host)
if not rev:
_unpark(b, st, ("U",))
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
b.x(pnz) # pnz = [WA != 0]
emit_matvec_proj_loop(b, sb, hb, Ub, scr, LT) # U = B*WA
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
t = b.and_compute(pnz, z1)
b.cx(t, st["capk1"])
b.and_release(t, pnz, z1)
b.x(z1)
tP = b.and_compute(pnz, z1) # held across the sketch
emit_sketch_proj(b, sb, Ub, st["K48"][0], scr, LT)
_ktree_flat(b, st, tP)
emit_sketch_mbu(b, sb, Ub, list(st["K48"]), scr, LT)
b.and_release(tP, pnz, z1)
b.x(z1)
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
b.x(pnz)
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
_cswap288(b, st["capk2"], xb, Ub)
_cswap288(b, st["capk1"], xb, hb)
else:
_cswap288(b, st["capk1"], xb, hb)
_cswap288(b, st["capk2"], xb, Ub)
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
b.x(pnz)
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
b.x(z1)
tP = b.and_compute(pnz, z1)
emit_sketch_proj(b, sb, Ub, st["K48"][0], scr, LT)
_ktree_flat(b, st, tP)
emit_sketch_mbu(b, sb, Ub, list(st["K48"]), scr, LT)
b.and_release(tP, pnz, z1)
b.x(z1)
t = b.and_compute(pnz, z1)
b.cx(t, st["capk1"])
b.and_release(t, pnz, z1)
emit_ztest_strip_flat(b, list(st["U"]), z1, host)
emit_matvec_mbu_loop(b, sb, hb, Ub, scr, LT) # U -> 0, free
b.x(pnz)
emit_ztest_strip_flat(b, list(st["WA"]), pnz, host)
b.claim("V2", host)
_park(b, st, _K48_W, owner="scal")
_park(b, st, borrow, owner="flag", recorded=False)
_park(b, st, ("V2",))
if rev:
_park(b, st, ("U",))
⋯ 556 lines
def build_full(nsteps=NSLOTS, with_tail=True):
"""Init + P1 + mux + tail + unmux + xseam + P2 + teardown."""
from uncompute import Builder
b = Builder(recycle_outcomes=True)
T = build_tables(b)
st = alloc_state(b)
Start 0 Toffolis · peak 2,386 qubits
with b.phase("init"):
_y0_init(b, st)
Forward Lanczos walk 433,689 Toffolis · peak 2,395 qubits
for j in range(nsteps):
emit_slot(b, st, T, j)
Choose null vector 5,464 Toffolis · peak 2,311 qubits
with b.phase("mux"):
emit_sandwich(b, st, T)
if with_tail:
# Every |0>-at-seam word is already parked by the slot and
# sandwich closes (NOT U: the k2 staging; NOT the resident
# core), so the tail allocates its pools straight from the
# free-list.
Striped phase scan 102,192 Toffolis · peak 2,385 qubits
with b.phase("tail"):
emit_tail_stripe(b, st, st["X"], k=16)
Choice reversed 3,619 Toffolis · peak 2,311 qubits
with b.phase("unmux"):
emit_sandwich(b, st, T, rev=True)
Measure locator 0 Toffolis · peak 1,681 qubits
with b.phase("xseam"):
sx = [b.hmr(st["X"][q]) for q in range(288)]
_park(b, st, ("X",))
fixmap = {(tag, jj): ids for (tag, jj, ids) in st["fix"]}
Reverse walk 381,948 Toffolis · peak 2,107 qubits
for j in range(nsteps - 1, -1, -1):
emit_slot_mirror(b, st, T, j, sx, fixmap)
assert not fixmap, f"unconsumed fixups: {sorted(fixmap)}"
for o in sx:
b.retire(o)
with b.phase("P2/init"):
_y0_teardown(b, st)
return b, st