b = Builder()
_r = declare_registers(b, [("x", N_X), ("k", KW)])
XQ, KQ = _r["x"], _r["k"]
b.claim("x", XQ)
b.claim("k", KQ)
# ------------------------------------------------------------ wiring
Dq = XQ[0:25]
Uq = XQ[25 - M : 25]
addr_msb = [XQ[34 - i] for i in range(10)]
low_msb = [XQ[28], XQ[27], XQ[26], XQ[25]]
hi_msb = [XQ[34], XQ[33], XQ[32], XQ[31], XQ[30], XQ[29]]
# ---- fold: sign-fold x, pool the certified-zero spares, allocate words
Fold 0 Toffolis · peak 78 qubits
with b.phase("fold/sign"):
for i in range(38):
b.cx(XQ[38], XQ[i])
wp = WirePool(b, SPARES)
b.release("x", SPARES) # the spares leave x while lent to the pool
with b.phase("fold/words"):
# The pool bank empties into the slope immediately: qFw[0..2] bind
# the spares here (pooled allocs emit no op; the wires are the
# persistent certified-zero x bits). Every other packed-word wire
# materializes at the first leaf that sets its bit, and a bit no
# address ever sets fails the post-walk coverage assert instead of
# riding as a dead wire.
TW = FW + EWID + A0BITS
T = [None] * TW
for _j in range(3):
T[_j] = wp.qubit()
assert set(T[:3]) == set(SPARES) # the pool bank empties into the slope
b.claim("slope", T[:3])
def _matT(j):
if T[j] is None:
T[j] = wp.qubit()
b.claim("slope" if j < FW else "correction" if j < FW + EWID else "constant", [T[j]])
return T[j]
# ---- lookup: content-pruned QROM walk writes the packed word --------
CUM = [0] * (NADDR + 1)
for a in range(NADDR):
CUM[a + 1] = CUM[a] + (1 if WORDS[a] else 0)
def nz_main(lo, span):
return CUM[lo + span] - CUM[lo] > 0
def unif_main(lo, span):
w = WORDS[lo]
if w == 0:
return False
for a in range(lo + 1, lo + span):
if WORDS[a] != w:
return False
return True
def leaf_main(a, wire):
w = WORDS[a]
j = 0
while w:
if w & 1:
if wire is None:
b.x(_matT(j))
else:
b.cx(wire, _matT(j))
w >>= 1
j += 1
def lmark(lo, span):
if span == 128:
b.set_phase(f"lookup/b{lo // 128}")
# descend = the walk levels above the first 128-address subtree; each
# b<n> mark then owns that subtree's leaves plus the pops back to the
# next one
Lookup 495 Toffolis · peak 139 qubits
with b.phase("lookup/descend"):
pruned_walk(
b, addr_msb, 0, NADDR, leaf_main, nz_main, uniform=unif_main, mark=lmark, pool=wp
)
⋯ 8 lines
Add constant 53 Toffolis · peak 139 qubits
with b.phase("a0add/add"):
add(b, KQ[A0SH:], qA0w, gl=GL0, pool=wp)
with b.phase("a0add/meas"):
sbA0 = []
for q in qA0w:
sbA0.append(b.hmr(q))
b.release("constant", qA0w) # demolished: ownership ends before the frees
for q in reversed(qA0w):
wp.recycle(q)
⋯ 96 lines
for t in range(NT):
Slope update 198 Toffolis · peak 137 qubits
with b.phase(f"mid_mul/t{t}"):
⋯ 44 lines
Product into k 589 Toffolis · peak 139 qubits
with b.phase("final_rows/neg"):
for q in KQ:
b.x(q)
for i in range(I0, 11):
with b.phase(f"final_rows/i{i}"):
drop = max(RB, (2 * i + 5) - CAPW)
with b.phase("final_rows/unneg"):
for q in KQ:
b.x(q)
# ---- mid_unmul: exact reverse of mid_mul returns F to B1 ------------
for t in reversed(range(NT)):
Slope restored 198 Toffolis · peak 137 qubits
with b.phase(f"mid_unmul/t{t}"):
⋯ 110 lines
fixup(qFw + qEw, sbA0, WORDS, low_msb, hi_msb,
16)
assert len(wp._free) == 3 and set(wp._free) == set(SPARES), "spares in flight"
b.claim("x", SPARES) # the certified-zero spares re-join x
# ---- unfold ---------------------------------------------------------
Unfold 0 Toffolis · peak 78 qubits
with b.phase("unfold"):
for i in range(38):
b.cx(XQ[38], XQ[i])
def acc_row(m1, partner, flip, cols, wrap, T, colneg=None):
for u, v in flip:
b.cx(u, v)
b.x(m1)
m2 = wp.and_compute(m1, partner)
b.x(m1)
for u, v in flip:
b.cx(u, v)
ts, reps = booth_columns(b, m1, m2, cols, neg=colneg, pool=wp)
A, akw, unwrap = wrap(m2, ts)
add(b, T, A, pool=wp, **akw)
unwrap()
booth_columns_release(b, ts, reps, neg=colneg, pool=wp)
for u, v in flip:
b.cx(u, v)
b.x(m1)
wp.and_release(m2, m1, partner)
b.x(m1)
for u, v in flip:
b.cx(u, v)
⋯ 6 lines
def mid_row(t, invert):
j0, j1, j2 = 2 * t - 1, 2 * t, 2 * t + 1
SH1 = M + 4 - 2 * t
qlo = max(FLOW, EQ - SH1 + 1)
alloc_m1 = j0 >= 0
if alloc_m1:
m1 = wp.qubit()
b.cx(Uq[j1], m1)
b.cx(Uq[j0], m1)
else:
m1 = Uq[j1]
z = wp.qubit()
b.claim("recode", ([m1] if alloc_m1 else []) + [z])
if j2 < M:
b.cx(Uq[j2], z)
b.cx(Uq[j1], z)
neg = Uq[j2] if j2 < M else None
q2top = EQ + EWID - SH1
cols = [(qEw[q + SH1 - EQ], qEw[q + SH1 - EQ - 1]) for q in range(qlo, q2top)]
def wrap(m2, ts):
# sign wire (covers columns q2top .. FW-1)
b.cx(m1, m2)
sw = wp.and_compute(m2, qEw[EWID - 1])
b.cx(m1, m2)
ext = FW - (q2top - FLOW)
ext = max(ext, 0)
for qq in qFw:
if invert:
b.x(qq)
if neg is not None:
b.cx(neg, qq)
def unwrap():
for qq in qFw:
if neg is not None:
b.cx(neg, qq)
if invert:
b.x(qq)
cbit = b.hmr(sw)
b.cx(m1, m2)
b.cz(m2, qEw[EWID - 1], cond=cbit)
b.cx(m1, m2)
wp.recycle(sw)
return ts + [sw] * ext, {"shared": sw}, unwrap
acc_row(m1, z, [], cols, wrap, qFw[qlo - FLOW :])
if j2 < M:
b.cx(Uq[j2], z)
b.cx(Uq[j1], z)
b.release("recode", [z])
wp.recycle(z)
if alloc_m1:
b.cx(Uq[j1], m1)
b.cx(Uq[j0], m1)
b.release("recode", [m1])
wp.recycle(m1)
⋯ 8 lines
def booth_row(i, drop):
sh = FBITS - 2 * i
f1w = qFw[2 * i - FLOW]
have2 = 2 * i + 1 < FBITS
f2w = qFw[2 * i + 1 - FLOW] if have2 else None
Aw = qFw[2 * i - 1 - FLOW]
b.cx(f1w, Aw)
neg = f2w if have2 else None
cols = [
(Dq[sh + q] if sh + q <= 24 else None, Dq[sh + q - 1]) for q in range(drop, 2 * i + 5)
]
m = len(cols) + 1
# [GID]-prefix length: the largest that keeps this row's runway
# moment (row wires + carries + remaining headroom term) under
# CAPRAW
gl = max(0, min(m - 1, CAPRAW - ROWBASE - m - (33 - 2 * i)))
def wrap(g, ts):
b.cx(Aw, g)
if neg is not None:
b.cx(neg, g)
def unwrap():
if neg is not None:
b.cx(neg, g)
b.cx(Aw, g)
return [g] + ts, {"neg": neg, "gl": gl}, unwrap
acc_row(
Aw,
f2w if have2 else f1w,
[(f1w, f2w)] if have2 else [],
cols,
wrap,
KQ[drop - 1 :],
colneg=neg,
)
b.cx(f1w, Aw)
def build_onehot(bits_msb):
hb = bits_msb[0]
w1 = wp.qubit()
b.cx(hb, w1)
w0 = wp.qubit()
b.x(w0)
b.cx(hb, w0)
b.claim("onehot", [w0, w1])
cur = [w0, w1]
levs = []
for bit in bits_msb[1:]:
lev = []
new = []
for w in cur:
hi = wp.and_compute(w, bit)
lo = wp.qubit()
b.cx(w, lo)
b.cx(hi, lo)
new.extend([lo, hi])
lev.append((w, bit, lo, hi))
b.claim("onehot", new)
levs.append(lev)
cur = new
return cur, ((hb, w0, w1), levs)
⋯ 1 line
def un_onehot(meta):
(hb, w0, w1), levs = meta
for lev in reversed(levs):
b.release("onehot", [q for (_w, _bit, lo, hi) in lev for q in (lo, hi)])
for w, bit, lo, hi in reversed(lev):
b.cx(hi, lo)
b.cx(w, lo)
wp.recycle(lo)
wp.and_release(hi, w, bit)
b.release("onehot", [w0, w1])
b.cx(hb, w0)
b.x(w0)
wp.recycle(w0)
b.cx(hb, w1)
wp.recycle(w1)
⋯ 15 lines
def fixup(qubits, pre_sb, wbits, low_msb, hi_msb, lam):
# The parameters are coupled to the closure: the demolition order
# must match the slope + correction releases, and lam must be the
# rail size the leaf indexes.
assert qubits == qFw + qEw and lam == 1 << len(low_msb)
Lookup erased 50 Toffolis · peak 110 qubits
with b.phase("unlook/meas"):
sb = []
for q in qubits:
sb.append(b.hmr(q))
b.release("slope", qFw) # demolished: ownership ends
b.release("correction", qEw) # before the frees
for q in reversed(qubits):
wp.recycle(q)
sb = sb + list(pre_sb)
with b.phase("unlook/onehot"):
oh, meta = build_onehot(low_msb)
assert len(oh) == lam
def nzf(lo, span):
a0 = lo * lam
a1 = min((lo + span) * lam, NADDR)
for a in range(a0, a1):
if wbits[a]:
return True
return False
def leaf(h, wire):
for l in range(lam):
a = h * lam + l
if a >= NADDR:
break
w = wbits[a]
j = 0
while w:
if w & 1:
b.cz(wire, oh[l], cond=sb[j])
w >>= 1
j += 1
def wmark(lo, span):
if span == 8:
b.set_phase(f"unlook/w{lo}")
pruned_walk(b, hi_msb, 0, 1 << len(hi_msb), leaf, nzf, mark=wmark, pool=wp)
with b.phase("unlook/unhot"):
un_onehot(meta)