anima-python 0.13.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1386 @@
1
+ # ==========================================================================
2
+ # ⛔ ENGINE-INTERNAL / DEPRECATED py-MIRROR — DO NOT RUN OR SCORE DIRECTLY
3
+ # 측정/학습/서빙/직렬화는 cli/ 단일진입만: anima eval | train | serialize
4
+ # (canonical = hexa core/*.hexa 단일 SSOT; py 미러는 2026-06-28 폐기, DIRECTIONAL).
5
+ # 이 파일을 `python3 core/decode.py` 로 직접 실행하거나 side-harness로 import-채점하면
6
+ # = 단일진입 우회(#2603 위반) + terminal verdict 불가. cli/가 import하는 경로만 허용.
7
+ # ==========================================================================
8
+ import sys as _anima_entry_guard
9
+ if __name__ == "__main__":
10
+ _anima_entry_guard.exit("⛔ decode.py 직접 실행 금지 — cli/ 단일진입(anima eval/train/serialize, canonical=hexa) 경유. #2603")
11
+
12
+ """core/decode.py — UNIFIED PY DECODE ENGINE: byte-faithful 1:1 merge of the two
13
+ per-mouth decoder mirrors into ONE module.
14
+
15
+ * CONV (CLM ConvMoE) mouth = the verbatim port of core/clm_decode.hexa
16
+ (formerly core/clm_decode.py)
17
+ * BYTE (ByteGPT transformer) = the verbatim port of core/decode.hexa
18
+ (formerly core/bytegpt_decode.py)
19
+
20
+ Per CLAUDE.md a_engine_native_learning: hexa + py are TWO co-equal production
21
+ engines kept at byte-parity. This module is the numpy mirror of the two decode
22
+ mouths; it exposes the UNION of both modules' public names so a caller can do
23
+ `import decode as clm` OR `import decode as bg` (or `import decode`) with ZERO
24
+ call-site churn (drop-in for clm_decode.py + bytegpt_decode.py).
25
+
26
+ Organization:
27
+ (a) SHARED — imports + the transcendental/PRNG helpers that are BYTE-IDENTICAL
28
+ across both source modules (dt_exp, _MASK, _mix32, _rng_next, _topk_sample).
29
+ (b) CONV (CLM) — the full clm_decode.py public API, verbatim.
30
+ (c) BYTE (ByteGPT) — the full bytegpt_decode.py public API, verbatim, PLUS a
31
+ byte-exact KV-cache fast path that REPLACES the O(gen²) full re-forward
32
+ decode loop (the O(gen²) reference is kept under a `_full` suffix).
33
+ (d) MOUTH DISPATCH — header-sniff (CLM\\x01 magic → conv; 5×u32 → byte),
34
+ mirroring generator.hexa gen_auto_backend.
35
+
36
+ DIVERGENT SAME-NAMED HELPERS — kept under DISTINCT names, never silently merged:
37
+ * clm's `_gn_sqrt` (gn_lib, 40-iter from g0=x) ⊥ bg's `dt_sqrt` (flame_math,
38
+ 24-iter from g0=max(x,1)) — different bodies, both retained (distinct names).
39
+ * clm's `_rd_u32` and bg's `_bg_rd_u32` — IDENTICAL bodies; `_bg_rd_u32` is an
40
+ alias of `_rd_u32` (surface preserved, one definition).
41
+ The PRNG trio (_mix32/_rng_next/_topk_sample) + dt_exp were byte-identical across
42
+ the two source files (bg imported dt_exp FROM clm), so they are deduped to one
43
+ copy in the SHARED section with no behavior change.
44
+
45
+ KV-CACHE (the ByteGPT fast path, new here): the hexa KV-cache is byte-identical
46
+ to its full-forward reference (decode.hexa:919). numpy BLAS GEMM is
47
+ M-dependent at the ~1e-15 ULP level (a single-row projection differs from the
48
+ same row of an M=T batch), so the py KV logits are NOT bit-identical to the py
49
+ full-forward — but the DECODE TOKEN STREAM is identical (argmax/inverse-CDF are
50
+ robust to ~1e-13 logit drift), and the cache is fully RE-SYNCED (rebuilt at M=T)
51
+ whenever the window slides past `block`. Byte-exactness of the token stream is
52
+ gated by state/1815_cls_bytegpt/_decode_selftest.py.
53
+ """
54
+
55
+ import sys
56
+ import math
57
+ import os
58
+ import struct
59
+ import numpy as np
60
+
61
+ # ── H_9200 E1 SLW eval-time controls (process-global; set by cli/evaluate.py) ──
62
+ # The gated-write forward-slot applies by default whenever a .clm carries an
63
+ # "SLW\x01" trailer. These two switches let the pre-registered controls run WITHOUT
64
+ # retraining (frozen-first · no tune-to-green): --slot-off forces γ=0 (bit-exact base
65
+ # trunk = slot-ablation), --slot-shuffle scrambles the WRITE address (shuffle-bind).
66
+ _SLW_GAMMA_OVERRIDE = None # float 0.0 => ablate the slot lane (γ=0 passthrough)
67
+ _SLW_SHUFFLE_SEED = None # int => permute the write address only (reads unpermuted)
68
+
69
+
70
+ def set_slw_controls(gamma_override=None, shuffle_seed=None):
71
+ """Set the SLW eval-time controls (cli/evaluate.py --slot-off / --slot-shuffle)."""
72
+ global _SLW_GAMMA_OVERRIDE, _SLW_SHUFFLE_SEED
73
+ _SLW_GAMMA_OVERRIDE = gamma_override
74
+ _SLW_SHUFFLE_SEED = shuffle_seed
75
+
76
+
77
+ # ════════════════════════════════════════════════════════════════════════
78
+ # (a) SHARED — helpers byte-identical across clm_decode.py + bytegpt_decode.py
79
+ # ════════════════════════════════════════════════════════════════════════
80
+
81
+ def dt_exp(x):
82
+ """flame_math.hexa::dt_exp — halve until |xr|<=0.25, 12-term Taylor (k=1..11),
83
+ then square r times. Vectorized; halving by 2 is exact in fp64, so the
84
+ per-element halve-count r matches the hexa scalar while-loop exactly.
85
+ (SHARED: bg's top-k sampler softmax uses the SAME dt_exp — was `from
86
+ clm_decode import dt_exp` in bytegpt_decode.py.)"""
87
+ x = np.asarray(x, dtype=np.float64)
88
+ scalar = (x.ndim == 0)
89
+ x = np.atleast_1d(x)
90
+ xr = x.copy()
91
+ r = np.zeros(x.shape, dtype=np.int64)
92
+ mask = np.abs(xr) > 0.25
93
+ while mask.any():
94
+ xr = np.where(mask, xr / 2.0, xr)
95
+ r = np.where(mask, r + 1, r)
96
+ mask = np.abs(xr) > 0.25
97
+ term = np.ones_like(xr)
98
+ acc = np.ones_like(xr)
99
+ k = 1
100
+ while k < 12:
101
+ term = term * xr / float(k)
102
+ acc = acc + term
103
+ k = k + 1
104
+ rmax = int(r.max()) if r.size else 0
105
+ s = 0
106
+ while s < rmax:
107
+ m = r > s
108
+ acc = np.where(m, acc * acc, acc)
109
+ s = s + 1
110
+ return float(acc[0]) if scalar else acc
111
+
112
+
113
+ # ── seeded top-k temperature sampler PRNG — BYTE-IDENTICAL across both mouths
114
+ # (clm_decode.hexa _clmd_mix32/_rng_next ≡ decode.hexa _g6_mix32/_rng_next;
115
+ # xorshift32 & 0xFFFFFFFF). Deduped to one copy.
116
+ _MASK = 0xFFFFFFFF
117
+
118
+
119
+ def _mix32(s):
120
+ """_clmd_mix32 / _g6_mix32 — SplitMix32-style finalizer."""
121
+ z = (s + 0x9E3779B9) & _MASK
122
+ z = ((z ^ (z // 65536)) * 0x85EBCA6B) & _MASK
123
+ z = ((z ^ (z // 8192)) * 0xC2B2AE35) & _MASK
124
+ z = (z ^ (z // 65536)) & _MASK
125
+ if z == 0:
126
+ z = 0x9E3779B9
127
+ return z
128
+
129
+
130
+ def _rng_next(s):
131
+ """_clmd_rng_next / _g6_rng_next — xorshift32 step -> (state, u in [0,1))."""
132
+ x = s & _MASK
133
+ if x == 0:
134
+ x = 0x9E3779B9
135
+ x = (x ^ (x * 8192)) & _MASK
136
+ x = (x ^ (x // 131072)) & _MASK
137
+ x = (x ^ (x * 32)) & _MASK
138
+ return x, (float(x) / 4294967296.0)
139
+
140
+
141
+ def _topk_sample(logits, vocab, top_k, temp, rng):
142
+ """_clmd_topk_sample / _g6_topk_sample — top-k by repeated argmax (ties:
143
+ first/strict >), /temp, dt_exp softmax (max-sub), inverse-CDF draw. logits:[V].
144
+ (SHARED: both mouths' samplers had byte-identical bodies.)"""
145
+ kcap = top_k if (top_k > 0 and top_k < vocab) else vocab
146
+ taken = np.zeros(vocab, dtype=np.float64)
147
+ sel_idx = []
148
+ sel_val = []
149
+ picks = 0
150
+ while picks < kcap:
151
+ bi = -1
152
+ bv = 0.0
153
+ for k in range(vocab):
154
+ if taken[k] < 0.5:
155
+ v = logits[k]
156
+ if bi < 0 or v > bv:
157
+ bi = k; bv = v
158
+ if bi < 0:
159
+ picks = kcap
160
+ else:
161
+ taken[bi] = 1.0
162
+ sel_idx.append(bi)
163
+ sel_val.append(bv / temp)
164
+ picks += 1
165
+ nsel = len(sel_idx)
166
+ mx = sel_val[0]
167
+ for i in range(1, nsel):
168
+ if sel_val[i] > mx:
169
+ mx = sel_val[i]
170
+ probs = []
171
+ summ = 0.0
172
+ for j in range(nsel):
173
+ e = float(dt_exp(np.array(sel_val[j] - mx)))
174
+ probs.append(e); summ += e
175
+ s2, u = _rng_next(rng)
176
+ target = u * summ
177
+ acc = 0.0
178
+ pick = sel_idx[nsel - 1]
179
+ for p in range(nsel):
180
+ acc += probs[p]
181
+ if target <= acc:
182
+ pick = sel_idx[p]
183
+ break
184
+ return pick, s2
185
+
186
+
187
+ # ════════════════════════════════════════════════════════════════════════
188
+ # (b) CONV (CLM ConvMoE) — verbatim port of core/clm_decode.hexa
189
+ # (formerly core/clm_decode.py). PRNG/dt_exp reused from SHARED above.
190
+ # ════════════════════════════════════════════════════════════════════════
191
+
192
+ # ── primitive math — ported 1:1 from stdlib/flame/*.hexa ──
193
+
194
+ def dt_ln(x):
195
+ """flame_math.hexa::dt_ln — u=(x-1)/(x+1); 2*Σ_{k=0..23} u^(2k+1)/(2k+1).
196
+ KNOWN-BUGGY for x far from 1 (diverges); reproduced verbatim for parity."""
197
+ x = np.asarray(x, dtype=np.float64)
198
+ scalar = (x.ndim == 0)
199
+ x = np.atleast_1d(x)
200
+ u = (x - 1.0) / (x + 1.0)
201
+ u2 = u * u
202
+ termp = u.copy()
203
+ acc = np.zeros_like(u)
204
+ k = 0
205
+ while k < 24:
206
+ acc = acc + termp / float(2 * k + 1)
207
+ termp = termp * u2
208
+ k = k + 1
209
+ out = 2.0 * acc
210
+ return float(out[0]) if scalar else out
211
+
212
+
213
+ def dt_erf(x):
214
+ """flame_math.hexa::dt_erf — Abramowitz&Stegun 7.1.26, exp via dt_exp."""
215
+ x = np.asarray(x, dtype=np.float64)
216
+ scalar = (x.ndim == 0)
217
+ x = np.atleast_1d(x)
218
+ sign = np.where(x < 0.0, -1.0, 1.0)
219
+ z = np.abs(x)
220
+ t = 1.0 / (1.0 + 0.3275911 * z)
221
+ a1 = 0.254829592
222
+ a2 = -0.284496736
223
+ a3 = 1.421413741
224
+ a4 = -1.453152027
225
+ a5 = 1.061405429
226
+ poly = ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t
227
+ out = sign * (1.0 - poly * dt_exp(0.0 - z * z))
228
+ return float(out[0]) if scalar else out
229
+
230
+
231
+ _INV_SQRT2 = 0.70710678118654752440
232
+ _INV_SQRT2PI = 0.39894228040143267794
233
+
234
+
235
+ def _nn_normal_cdf(x):
236
+ return 0.5 * (1.0 + dt_erf(x * _INV_SQRT2))
237
+
238
+
239
+ def nn_gelu_fwd(g):
240
+ """nn_lib.hexa::nn_gelu_fwd — GELU(x)=x*Phi(x), Phi via dt_erf (EXACT erf)."""
241
+ g = np.asarray(g, dtype=np.float64)
242
+ return g * _nn_normal_cdf(g)
243
+
244
+
245
+ def _moe_exp(x):
246
+ """moe_lib.hexa::_moe_exp — ln2 range-reduce, 14-term Taylor, *2^n.
247
+ DISTINCT from dt_exp (used ONLY in the MoE router softmax)."""
248
+ x = np.asarray(x, dtype=np.float64)
249
+ scalar = (x.ndim == 0)
250
+ x = np.atleast_1d(x)
251
+ ln2 = 0.6931471805599453
252
+ r = x.copy()
253
+ n = np.zeros(x.shape, dtype=np.int64)
254
+ m = r > 0.34657359
255
+ while m.any():
256
+ r = np.where(m, r - ln2, r)
257
+ n = np.where(m, n + 1, n)
258
+ m = r > 0.34657359
259
+ m = r < -0.34657359
260
+ while m.any():
261
+ r = np.where(m, r + ln2, r)
262
+ n = np.where(m, n - 1, n)
263
+ m = r < -0.34657359
264
+ term = np.ones_like(r)
265
+ summ = np.ones_like(r)
266
+ k = 1
267
+ while k < 14:
268
+ term = term * r / float(k)
269
+ summ = summ + term
270
+ k = k + 1
271
+ # *2^n via exact power-of-two scaling (== repeated *2 / /2 in hexa)
272
+ p = summ * np.power(2.0, n.astype(np.float64))
273
+ return float(p[0]) if scalar else p
274
+
275
+
276
+ def _gn_sqrt(x):
277
+ """gn_lib.hexa::_gn_sqrt — Newton-Raphson 40 iters from g0=x. scalar.
278
+ (DIVERGENT twin of bg's dt_sqrt — DO NOT merge; distinct name kept.)"""
279
+ if x <= 0.0:
280
+ return 0.0
281
+ g = x
282
+ i = 0
283
+ while i < 40:
284
+ g = 0.5 * (g + x / g)
285
+ i = i + 1
286
+ return g
287
+
288
+
289
+ def nn_groupnorm_fwd(x, gamma, beta, T, C, G):
290
+ """gn_lib.hexa::nn_groupnorm_fwd — eps=1e-5. x:[T,C]. Returns y:[T,C].
291
+ Here G is always 1 (=> normalize over all C per the whole [T,C] group)."""
292
+ eps = 0.00001
293
+ cg = C // G
294
+ m = float(cg * T)
295
+ x = x.reshape(T, C)
296
+ y = np.empty_like(x)
297
+ for grp in range(G):
298
+ c0 = grp * cg
299
+ sl = x[:, c0:c0 + cg]
300
+ mu = sl.sum() / m
301
+ var = ((sl - mu) * (sl - mu)).sum() / m
302
+ inv = 1.0 / _gn_sqrt(var + eps)
303
+ xh = (sl - mu) * inv
304
+ y[:, c0:c0 + cg] = gamma[c0:c0 + cg] * xh + beta[c0:c0 + cg]
305
+ return y
306
+
307
+
308
+ def nn_moe_softmax(logits, T, E):
309
+ """moe_lib.hexa::nn_moe_softmax — stable softmax over E via _moe_exp. logits:[T,E]."""
310
+ logits = logits.reshape(T, E)
311
+ mx = logits.max(axis=1, keepdims=True)
312
+ ev = _moe_exp(logits - mx)
313
+ s = ev.sum(axis=1, keepdims=True)
314
+ return ev / s
315
+
316
+
317
+ def nn_moe_router_fwd(logits_r, ex_out, T, E, C):
318
+ """moe_lib.hexa::nn_moe_router_fwd — y[t,c]=Σ_e probs[t,e]*ex_out[e,t,c].
319
+ ex_out:[E,T,C]. Returns y:[T,C]."""
320
+ probs = nn_moe_softmax(logits_r, T, E) # [T,E]
321
+ ex = ex_out.reshape(E, T, C)
322
+ # y[t,c] = Σ_e probs[t,e]*ex[e,t,c]
323
+ y = np.einsum('te,etc->tc', probs, ex)
324
+ return y
325
+
326
+
327
+ def nn_ce_loss_allpos(logits, targets, T, V):
328
+ """nn_lib.hexa::nn_ce_loss_allpos — mean over T of -ln(softmax[tgt]).
329
+ Stable softmax via dt_exp, pt_safe floor 1e-6, -ln via dt_ln. logits:[T,V]."""
330
+ logits = logits.reshape(T, V)
331
+ total = 0.0
332
+ for t in range(T):
333
+ row = logits[t]
334
+ mx = row.max()
335
+ tot = float(dt_exp(row - mx).sum())
336
+ tgt = int(targets[t])
337
+ p_t = float(dt_exp(np.array(row[tgt] - mx))) / tot
338
+ pt_safe = p_t if p_t >= 0.000001 else 0.000001
339
+ total = total + (0.0 - float(dt_ln(np.array(pt_safe))))
340
+ return total / float(T)
341
+
342
+
343
+ # ── .clm file parse + int4 dequant — 1:1 from clm_decode.hexa _clmd_load* ──
344
+
345
+ def _rd_u32(rb, off):
346
+ return rb[off] | (rb[off + 1] << 8) | (rb[off + 2] << 16) | (rb[off + 3] << 24)
347
+
348
+
349
+ def clm_decodable(path):
350
+ """clm_decode.hexa::clm_decodable — CLM\\x01 header AND CLMX v0.2 trailer."""
351
+ try:
352
+ rb = open(path, 'rb').read()
353
+ except Exception:
354
+ return False
355
+ if len(rb) < 5:
356
+ return False
357
+ if not (rb[0] == 67 and rb[1] == 76 and rb[2] == 77 and rb[3] == 1):
358
+ return False
359
+ nblk = rb[4]
360
+ off = 5
361
+ b = 0
362
+ while b < nblk:
363
+ if off + 8 > len(rb):
364
+ return False
365
+ cout = _rd_u32(rb, off)
366
+ rest = _rd_u32(rb, off + 4)
367
+ off = off + 8
368
+ n = cout * rest
369
+ off = off + (n + 1) // 2
370
+ off = off + cout * 4
371
+ b = b + 1
372
+ if off + 5 > len(rb):
373
+ return False
374
+ return rb[off] == 67 and rb[off + 1] == 76 and rb[off + 2] == 77 and rb[off + 3] == 88
375
+
376
+
377
+ def clm_config(path):
378
+ """clm_decode.hexa::clm_config — recover (d,K,V,E,L,nblk) from header."""
379
+ if not clm_decodable(path):
380
+ return {"ok": False}
381
+ rb = open(path, 'rb').read()
382
+ nblk = rb[4]
383
+ d = _rd_u32(rb, 5)
384
+ rest0 = _rd_u32(rb, 9)
385
+ K = rest0 // d
386
+ off = 5
387
+ bi = 0
388
+ E = 2
389
+ V = 256
390
+ while bi < nblk:
391
+ c = _rd_u32(rb, off)
392
+ r = _rd_u32(rb, off + 4)
393
+ if bi == nblk - 2:
394
+ E = c
395
+ if bi == nblk - 1:
396
+ V = c
397
+ n = c * r
398
+ off = off + 8 + (n + 1) // 2 + c * 4
399
+ bi = bi + 1
400
+ L = nblk - E - 3
401
+ return {"ok": True, "d": d, "K": K, "V": V, "E": E, "L": L, "nblk": nblk}
402
+
403
+
404
+ def _load_block(rb, off):
405
+ """_clmd_load_block — int4-sym dequant: w = (nibble-8) * per-channel-scale.
406
+ Returns (w_2d[cout,rest], new_off)."""
407
+ cout = _rd_u32(rb, off); off += 4
408
+ rest = _rd_u32(rb, off); off += 4
409
+ n = cout * rest
410
+ nbytes = (n + 1) // 2
411
+ raw = np.frombuffer(rb, dtype=np.uint8, count=nbytes, offset=off).astype(np.int64)
412
+ off += nbytes
413
+ low = (raw & 0xF) - 8
414
+ high = ((raw >> 4) & 0xF) - 8
415
+ codes = np.empty(2 * len(raw), dtype=np.float64)
416
+ codes[0::2] = low
417
+ codes[1::2] = high
418
+ codes = codes[:n]
419
+ scales = np.frombuffer(rb, dtype='<f4', count=cout, offset=off).astype(np.float64)
420
+ off += cout * 4
421
+ w = codes.reshape(cout, rest) * scales[:, None]
422
+ return w, off
423
+
424
+
425
+ def _load_ext(rb, off):
426
+ """_clmd_load_ext — length-prefixed fp32 tensor (n:u32, then n*f32 LE)."""
427
+ n = _rd_u32(rb, off); off += 4
428
+ vals = np.frombuffer(rb, dtype='<f4', count=n, offset=off).astype(np.float64)
429
+ off += n * 4
430
+ return vals, off
431
+
432
+
433
+ def clm_load_weights(path):
434
+ """_clmd_load — full file parse into a weight dict. Conv weights are kept
435
+ pre-transposed as Wt[Kdim,Cout] (the _clmd_scratch_new transpose, applied
436
+ once) since the py forward GEMMs xcol[T,Kdim] @ Wt[Kdim,Cout]."""
437
+ if not clm_decodable(path):
438
+ return {"ok": False}
439
+ rb = open(path, 'rb').read()
440
+ nblk = rb[4]
441
+ d = _rd_u32(rb, 5)
442
+ rest0 = _rd_u32(rb, 9)
443
+ K = rest0 // d
444
+ # walk to find E (block nblk-2 cout), V (block nblk-1 cout)
445
+ off = 5
446
+ bi = 0
447
+ E = 2
448
+ V = 256
449
+ while bi < nblk:
450
+ c = _rd_u32(rb, off)
451
+ r = _rd_u32(rb, off + 4)
452
+ if bi == nblk - 2:
453
+ E = c
454
+ if bi == nblk - 1:
455
+ V = c
456
+ n = c * r
457
+ off = off + 8 + (n + 1) // 2 + c * 4
458
+ bi = bi + 1
459
+ L = nblk - E - 3
460
+
461
+ # ── conv blocks, in order: ec, tc[L], eW[E], rW, roW ──
462
+ off = 5
463
+ ecW, off = _load_block(rb, off) # [d, d*K]
464
+ tcW = []
465
+ for _ in range(L):
466
+ w, off = _load_block(rb, off); tcW.append(w) # [d, d*K]
467
+ eW = []
468
+ for _ in range(E):
469
+ w, off = _load_block(rb, off); eW.append(w) # [d, d*K]
470
+ rW, off = _load_block(rb, off) # [E, d]
471
+ roW, off = _load_block(rb, off) # [V, d]
472
+ off = off + 5 # skip "CLMX" + n_ext byte
473
+
474
+ # ── ext tensors, in order ──
475
+ embed, off = _load_ext(rb, off) # [V*d]
476
+ ecB, off = _load_ext(rb, off) # [d]
477
+ tcB = []
478
+ for _ in range(L):
479
+ v, off = _load_ext(rb, off); tcB.append(v) # [d]
480
+ eB = []
481
+ for _ in range(E):
482
+ v, off = _load_ext(rb, off); eB.append(v) # [d]
483
+ rB, off = _load_ext(rb, off) # [E]
484
+ roB, off = _load_ext(rb, off) # [V]
485
+ tgG = []
486
+ for _ in range(L):
487
+ v, off = _load_ext(rb, off); tgG.append(v) # [d]
488
+ tgB = []
489
+ for _ in range(L):
490
+ v, off = _load_ext(rb, off); tgB.append(v) # [d]
491
+ noG, off = _load_ext(rb, off) # [d]
492
+ noB, off = _load_ext(rb, off) # [d]
493
+
494
+ # pre-transpose conv weights -> Wt[Kdim, Cout] (= w_2d.T)
495
+ W = {
496
+ "ok": True, "d": d, "E": E, "V": V, "K": K, "L": L,
497
+ "ecWt": ecW.T.copy(), "ecB": ecB,
498
+ "tcWt": [w.T.copy() for w in tcW], "tcB": tcB,
499
+ "eWt": [w.T.copy() for w in eW], "eB": eB,
500
+ "rWt": rW.T.copy(), "rB": rB,
501
+ "roWt": roW.T.copy(), "roB": roB,
502
+ "embed": embed.reshape(V, d),
503
+ "tgG": tgG, "tgB": tgB, "noG": noG, "noB": noB,
504
+ "bind_type": 0,
505
+ }
506
+
507
+ # ── optional CLMB bind-readout section (serialize_v3_bind) ──────────────
508
+ # "CLMB" = bytes 67,76,77,66. Present only when the .clm was serialized
509
+ # with a Hadamard/linear bind readout retained in-forward (H_1818).
510
+ # If absent, bind_type=0 and the standard additive _conv1d readout is used.
511
+ # CLMB layout (after CLMX ext arrays):
512
+ # CLMB magic 67,76,77,66
513
+ # bind_type u8 (1=Hadamard u*v, 2=linear u+v)
514
+ # Wa block (k, d) int4-sym conv block
515
+ # Wb block (k, d) int4-sym conv block
516
+ # WaB ext u32 k + k*f32
517
+ # WbB ext u32 k + k*f32
518
+ # In a CLMB file, roW holds Wo (V, k) NOT (V, d); roWt = (k, V).
519
+ if (off + 5 <= len(rb)
520
+ and rb[off] == 67 and rb[off + 1] == 76
521
+ and rb[off + 2] == 77 and rb[off + 3] == 66):
522
+ off += 4 # skip "CLMB"
523
+ bind_type = rb[off]; off += 1
524
+ WaW, off = _load_block(rb, off) # (k, d)
525
+ WbW, off = _load_block(rb, off) # (k, d)
526
+ WaB_ext, off = _load_ext(rb, off) # (k,)
527
+ WbB_ext, off = _load_ext(rb, off) # (k,)
528
+ W["bind_type"] = int(bind_type)
529
+ W["WaWt"] = WaW.T.copy() # (d, k)
530
+ W["WbWt"] = WbW.T.copy() # (d, k)
531
+ W["WaB"] = WaB_ext
532
+ W["WbB"] = WbB_ext
533
+ # roWt is already Wo.T = (k, V); roB is already WoB (V,) — loaded above.
534
+
535
+ # ── optional "SLW\x01" gated-write forward-slot trailer (H_9200 E1) ──────
536
+ # End of the trailer chain (after CLMX ext / CLMB), read at the current `off`.
537
+ # Absent/short => slw=None => forward is byte-identical to today (passthrough).
538
+ # Codec is CORE-owned in core/slw.py (owner directive: core lives in core/).
539
+ from slw import read_slw
540
+ W["slw"], off = read_slw(rb, off)
541
+
542
+ # ── optional "CLML" read-side context-pooling lane trailer (fork A · H_9235) ──
543
+ # Appended after the SLW trailer. Absent/short => clml=None => byte-identical forward
544
+ # (lane_apply passthrough). CORE-owned codec in core/clml.py.
545
+ from clml import read_clml
546
+ W["clml"], off = read_clml(rb, off, W["d"], W["V"])
547
+
548
+ return W
549
+
550
+
551
+ # ── forward — 1:1 from clm_decode.hexa _clmd_conv1d / _clmd_fwd_logits_sc ──
552
+
553
+ def _conv1d(x, Wt, b, T, Cin, Cout, K, dil):
554
+ """_clmd_conv1d_pre (host path) — causal dilated im2col + matmul + bias.
555
+ x:[T,Cin], Wt:[Cin*K, Cout], b:[Cout]. Returns y:[T,Cout].
556
+ im2col layout: xcol[t, ci*K + k] = x[t - dil*(K-1-k), ci] (0 if p<0)."""
557
+ Kdim = Cin * K
558
+ x = x.reshape(T, Cin)
559
+ xcol = np.zeros((T, Cin, K), dtype=np.float64)
560
+ t_idx = np.arange(T)
561
+ for k in range(K):
562
+ offset = dil * (K - 1 - k)
563
+ p = t_idx - offset
564
+ valid = p >= 0
565
+ xcol[valid, :, k] = x[p[valid], :]
566
+ xcol = xcol.reshape(T, Kdim)
567
+ mm = xcol @ Wt # [T, Cout]
568
+ return mm + b[None, :]
569
+
570
+
571
+ def _fwd_trunk(W, tok, T):
572
+ """Trunk forward through the FINAL groupnorm — returns yn:[T, d], the pre-readout,
573
+ PRE-E1-slot penultimate hidden (post-MoE, post final-GN). This is the pure-trunk
574
+ concept representation (E1-slot independent, matching the H_1822 β 303M-trunk-penult
575
+ precedent). Extracted from _fwd_logits so the decode path (slot+readout applied) and
576
+ the read-only hidden tap (clm_forward_hidden, ρ·weave / γ binding-lane probe H_9235)
577
+ share ONE byte-identical trunk forward."""
578
+ d = W["d"]; E = W["E"]; K = W["K"]; L = W["L"]
579
+ # embedding
580
+ ids = tok.astype(np.int64)
581
+ xe = W["embed"][ids] # [T, d]
582
+ # ec conv (K, dil=1)
583
+ xt = _conv1d(xe, W["ecWt"], W["ecB"], T, d, d, K, 1)
584
+ # L trunk layers: xt = xt + gelu(groupnorm(conv(xt)))
585
+ DIL_CAP = 512
586
+ dil = 1
587
+ for li in range(L):
588
+ dil_eff = dil if dil <= DIL_CAP else DIL_CAP
589
+ h = _conv1d(xt, W["tcWt"][li], W["tcB"][li], T, d, d, K, dil_eff)
590
+ hn = nn_groupnorm_fwd(h, W["tgG"][li], W["tgB"][li], T, d, 1)
591
+ hg = nn_gelu_fwd(hn)
592
+ xt = xt + hg.reshape(T, d)
593
+ dil = dil * 2
594
+ # router conv (K=1, Cout=E)
595
+ logits_r = _conv1d(xt, W["rWt"], W["rB"], T, d, E, 1, 1) # [T, E]
596
+ # E experts: gelu(conv(xt))
597
+ ex_out = np.empty((E, T, d), dtype=np.float64)
598
+ for ej in range(E):
599
+ eo = _conv1d(xt, W["eWt"][ej], W["eB"][ej], T, d, d, K, 1)
600
+ ex_out[ej] = nn_gelu_fwd(eo).reshape(T, d)
601
+ # MoE router mix
602
+ y = nn_moe_router_fwd(logits_r, ex_out, T, E, d) # [T, d]
603
+ # final groupnorm
604
+ yn = nn_groupnorm_fwd(y, W["noG"], W["noB"], T, d, 1)
605
+ return yn
606
+
607
+
608
+ def clm_forward_hidden(W, tok, T):
609
+ """Read-only penultimate-hidden tap — the pre-readout, pre-E1-slot yn:[T, d] (post-MoE,
610
+ post final groupnorm) for token ids tok:[T]. Engine-native: the EXACT production trunk
611
+ forward (_fwd_trunk, shared with _fwd_logits), so the dumped representation is
612
+ byte-identical to what the gates decode over. For the ρ·weave held-out-pair
613
+ recombination / γ binding-lane probe (H_9235): dumps the pure-trunk concept
614
+ representation a read-side lane consumes. No decode sampling / readout / perturbation."""
615
+ ta = tok if hasattr(tok, "astype") else np.array(tok, dtype=np.float64)
616
+ return _fwd_trunk(W, ta, T)
617
+
618
+
619
+ def clm_forward_hidden_logits(W, tok, T):
620
+ """Read-only combined tap: (yn_trunk:[T,d], logits:[T,V]) in ONE trunk forward — the pre-slot
621
+ penultimate AND the base (lane-OFF) full-forward logits. Avoids a double _fwd_trunk when a caller
622
+ (the CLML lane trainer, H_9235) needs both the lane input (yn) and the base logits (CE target)."""
623
+ ta = tok if hasattr(tok, "astype") else np.array(tok, dtype=np.float64)
624
+ yn = _fwd_trunk(W, ta, T)
625
+ d = W["d"]; V = W["V"]; x = yn
626
+ if W.get("slw") is not None:
627
+ from slw import slot_apply
628
+ x = slot_apply(x, W["slw"], gamma=_SLW_GAMMA_OVERRIDE,
629
+ shuffle_perm=(None if _SLW_SHUFFLE_SEED is None
630
+ else np.random.RandomState(_SLW_SHUFFLE_SEED).permutation(W["slw"]["n_slot"])))
631
+ if W.get("bind_type", 0) != 0:
632
+ u = x @ W["WaWt"] + W["WaB"]; v = x @ W["WbWt"] + W["WbB"]
633
+ g = u * v if W["bind_type"] == 1 else u + v
634
+ logits = g @ W["roWt"] + W["roB"]
635
+ else:
636
+ logits = _conv1d(x, W["roWt"], W["roB"], T, d, V, 1, 1)
637
+ return yn, logits
638
+
639
+
640
+ def _seed_to_tok(seed, T):
641
+ """T-window right-aligned byte encoding (1:1 with the decode seed→tok in
642
+ clm_decode_topk_sampled_W): utf-8 surrogateescape bytes, right-aligned into a
643
+ length-T window, left-pad = 32.0 (space). Shared by the hidden-dump probe."""
644
+ seed_b = seed.encode('utf-8', 'surrogateescape')
645
+ slen = len(seed_b)
646
+ tok = np.empty(T, dtype=np.float64)
647
+ for p in range(T):
648
+ si = slen - T + p
649
+ tok[p] = float(seed_b[si]) if si >= 0 else 32.0
650
+ return tok
651
+
652
+
653
+ def _fwd_logits(W, tok, T):
654
+ """_clmd_fwd_logits_sc (host path) — full CLMConvMoE forward. tok:[T] ids.
655
+ Returns logits:[T, V]."""
656
+ d = W["d"]; V = W["V"]
657
+ yn = _fwd_trunk(W, tok, T) # [T, d] pre-readout, pre-slot penultimate
658
+ yn_trunk = yn # keep pre-slot trunk penultimate for the CLML read-side lane
659
+ # H_9200 E1 — gated-write forward-slot on the post-norm penultimate (before
660
+ # readout), byte-parity with the torch SLWModule + core/decode.hexa. None =>
661
+ # additive golden path untouched. The eval-time controls are process-global
662
+ # (set by cli/evaluate.py set_slw_controls): _SLW_GAMMA_OVERRIDE (--slot-off γ=0
663
+ # ablation) and _SLW_SHUFFLE_SEED (--slot-shuffle: a fixed permutation of the
664
+ # WRITE address only, reads unpermuted, breaks role→slot correspondence).
665
+ if W.get("slw") is not None:
666
+ from slw import slot_apply
667
+ perm = None
668
+ if _SLW_SHUFFLE_SEED is not None:
669
+ perm = np.random.RandomState(_SLW_SHUFFLE_SEED).permutation(W["slw"]["n_slot"])
670
+ yn = slot_apply(yn, W["slw"], gamma=_SLW_GAMMA_OVERRIDE, shuffle_perm=perm)
671
+ # readout: additive Conv1d (standard) OR Hadamard/linear bind (CLMB)
672
+ if W.get("bind_type", 0) != 0:
673
+ # CLMB bind readout: yn → (Wa,Wb) linear projections → Hadamard/+ → Wo
674
+ # WaWt=(d,k), WbWt=(d,k); roWt=(k,V) holds Wo.T; roB=(V,) holds WoB.
675
+ u = yn @ W["WaWt"] + W["WaB"] # [T, k]
676
+ v = yn @ W["WbWt"] + W["WbB"] # [T, k]
677
+ g = u * v if W["bind_type"] == 1 else u + v # Hadamard(1) or linear(2)
678
+ out_logits = g @ W["roWt"] + W["roB"] # [T, V] roWt=(k,V)
679
+ else:
680
+ out_logits = _conv1d(yn, W["roWt"], W["roB"], T, d, V, 1, 1) # [T, V]
681
+ # fork-A CLML read-side context-pooling lane (H_9235) — reads the pre-slot trunk
682
+ # penultimate, causal-mean-pools the full context, adds a gated tether-clipped logit
683
+ # bias. None/absent => passthrough (byte-identical). DISJOINT (read-only + additive bias).
684
+ if W.get("clml") is not None:
685
+ from clml import lane_apply
686
+ out_logits = lane_apply(yn_trunk, out_logits, W["clml"])
687
+ return out_logits
688
+
689
+
690
+ # ── public CLM decode/CE entries — 1:1 from clm_decode.hexa ──
691
+
692
+ def clm_forward_ce(path, corpus, nwin_max):
693
+ """clm_decode.hexa::clm_forward_ce — mean CE over nwin_max T=24 causal
694
+ windows; uniform_ce = dt_ln(V); green = model_ce < uniform AND < shuffle."""
695
+ if not clm_decodable(path):
696
+ return {"ok": False, "reason": "not v0.2-decodable", "green": False,
697
+ "model_ce": 0.0, "shuffle_ce": 0.0, "uniform_ce": 0.0, "windows": 0}
698
+ W = clm_load_weights(path)
699
+ d = W["d"]; E = W["E"]; V = W["V"]; K = W["K"]
700
+ bytes_arr = np.frombuffer(open(corpus, 'rb').read(), dtype=np.uint8)
701
+ n_bytes = len(bytes_arr)
702
+ T = 24
703
+ stride = (n_bytes - T - 1) // nwin_max
704
+ if stride < 1:
705
+ stride = 1
706
+ sum_model = 0.0; sum_shuf = 0.0; nwin = 0
707
+ for s in range(nwin_max):
708
+ base = s * stride
709
+ if base + T + 1 <= n_bytes:
710
+ tok = bytes_arr[base:base + T].astype(np.float64)
711
+ tgt = bytes_arr[base + 1:base + T + 1].astype(np.float64)
712
+ logits = _fwd_logits(W, tok, T)
713
+ ce = nn_ce_loss_allpos(logits, tgt, T, V)
714
+ sum_model += ce
715
+ tgt_sh = tgt[::-1]
716
+ sum_shuf += nn_ce_loss_allpos(logits, tgt_sh, T, V)
717
+ nwin += 1
718
+ model_ce = sum_model / float(nwin)
719
+ shuf_ce = sum_shuf / float(nwin)
720
+ uniform_ce = float(dt_ln(np.array(float(V))))
721
+ lt_u = model_ce < uniform_ce
722
+ lt_s = model_ce < shuf_ce
723
+ return {"ok": True, "windows": nwin, "d": d, "E": E, "V": V, "K": K, "L": W["L"],
724
+ "model_ce": model_ce, "shuffle_ce": shuf_ce, "uniform_ce": uniform_ce,
725
+ "lt_uniform": lt_u, "lt_shuffle": lt_s, "green": lt_u and lt_s}
726
+
727
+
728
+ def clm_decode_argmax(path, seed, gen):
729
+ """clm_decode.hexa::clm_decode_argmax — greedy continuation. T=24 window,
730
+ right-aligned seed (pad-left byte 32). argmax ties: first (strict >)."""
731
+ if not clm_decodable(path):
732
+ return {"ok": False, "text": ""}
733
+ W = clm_load_weights(path)
734
+ V = W["V"]
735
+ T = 24
736
+ seed_b = seed.encode('utf-8', 'surrogateescape')
737
+ slen = len(seed_b)
738
+ tok = np.empty(T, dtype=np.float64)
739
+ for p in range(T):
740
+ si = slen - T + p
741
+ tok[p] = float(seed_b[si]) if si >= 0 else 32.0
742
+ out = bytearray()
743
+ for _ in range(gen):
744
+ logits = _fwd_logits(W, tok, T)
745
+ row = logits[T - 1]
746
+ besti = 0
747
+ bestv = row[0]
748
+ for k in range(1, V):
749
+ if row[k] > bestv:
750
+ bestv = row[k]; besti = k
751
+ out.append(besti)
752
+ tok[:T - 1] = tok[1:]
753
+ tok[T - 1] = float(besti)
754
+ return {"ok": True, "text": out.decode('utf-8', 'surrogateescape')}
755
+
756
+
757
+ def clm_decode_topk_sampled(path, seed, gen, top_k, temp, seed_rng):
758
+ """clm_decode.hexa::clm_decode_topk_sampled — seeded top-k temperature draw."""
759
+ if not clm_decodable(path):
760
+ return {"ok": False, "text": ""}
761
+ W = clm_load_weights(path)
762
+ return clm_decode_topk_sampled_W(W, seed, gen, top_k, temp, seed_rng)
763
+
764
+
765
+ def clm_decode_topk_sampled_W(W, seed, gen, top_k, temp, seed_rng):
766
+ V = W["V"]
767
+ T = 24
768
+ seed_b = seed.encode('utf-8', 'surrogateescape')
769
+ slen = len(seed_b)
770
+ tok = np.empty(T, dtype=np.float64)
771
+ for p in range(T):
772
+ si = slen - T + p
773
+ tok[p] = float(seed_b[si]) if si >= 0 else 32.0
774
+ out = bytearray()
775
+ rng = _mix32(seed_rng)
776
+ for _ in range(gen):
777
+ logits = _fwd_logits(W, tok, T)
778
+ nb, rng = _topk_sample(logits[T - 1], V, top_k, temp, rng)
779
+ out.append(nb)
780
+ tok[:T - 1] = tok[1:]
781
+ tok[T - 1] = float(nb)
782
+ return {"ok": True, "text": out.decode('utf-8', 'surrogateescape')}
783
+
784
+
785
+ # ════════════════════════════════════════════════════════════════════════
786
+ # (c) BYTE (ByteGPT transformer) — verbatim port of core/decode.hexa
787
+ # (formerly core/bytegpt_decode.py) + byte-exact KV-cache fast path.
788
+ # ════════════════════════════════════════════════════════════════════════
789
+
790
+ # libm erf, vectorized elementwise (object-ufunc -> float64). The hexa GELU calls
791
+ # `extern fn erf` (the C libm scalar erf), so math.erf is the byte-faithful twin.
792
+ _erf_vec = np.frompyfunc(math.erf, 1, 1)
793
+
794
+
795
+ def dt_sqrt(x):
796
+ """flame_math.hexa::dt_sqrt — Newton-Raphson 24 iters from g0=max(x,1).
797
+ Scalar. (DIVERGENT twin of clm's _gn_sqrt: 40 iters from g0=x — kept distinct.)"""
798
+ if x <= 0.0:
799
+ return 0.0
800
+ g = x if x > 1.0 else 1.0
801
+ i = 0
802
+ while i < 24:
803
+ g = 0.5 * (g + x / g)
804
+ i = i + 1
805
+ return g
806
+
807
+
808
+ def _bg_gelu(x):
809
+ """decode.hexa::_bg_gelu — 0.5*x*(1+erf(x*0.7071067811865476)).
810
+ erf via libm (math.erf), NOT the dt_erf twin (ING#23 torch-parity)."""
811
+ x = np.asarray(x, dtype=np.float64)
812
+ e = _erf_vec(x * 0.7071067811865476).astype(np.float64)
813
+ return 0.5 * x * (1.0 + e)
814
+
815
+
816
+ def _bg_layernorm_rows(X, g, b, T, d):
817
+ """decode.hexa::_bg_layernorm — per-row LayerNorm over length d.
818
+ biased variance, eps=1e-5, inv = 1/dt_sqrt(var+eps). X:[T,d]. Returns Y:[T,d].
819
+ dt_sqrt is scalar per row (matching the hexa scalar while-loop)."""
820
+ eps = 0.00001
821
+ X = X.reshape(T, d)
822
+ Y = np.empty_like(X)
823
+ for i in range(T):
824
+ row = X[i]
825
+ mean = row.sum() / float(d)
826
+ dv = row - mean
827
+ var = (dv * dv).sum() / float(d)
828
+ inv = 1.0 / dt_sqrt(var + eps)
829
+ Y[i] = g * (dv * inv) + b
830
+ return Y
831
+
832
+
833
+ # ── .bin header + weight load — 1:1 from decode.hexa _bg_rd_u32 / bg_load ──
834
+
835
+ # _bg_rd_u32 ≡ clm's _rd_u32 (byte-identical). Aliased to the single SHARED def.
836
+ _bg_rd_u32 = _rd_u32
837
+
838
+
839
+ def bg_header(path):
840
+ """parse the 5xu32 header [vocab,d,n_layer,n_head,block]. Returns dict."""
841
+ with open(path, 'rb') as f:
842
+ hdr = f.read(20)
843
+ if len(hdr) < 20:
844
+ return {"ok": False}
845
+ vocab = _bg_rd_u32(hdr, 0)
846
+ d = _bg_rd_u32(hdr, 4)
847
+ nlay = _bg_rd_u32(hdr, 8)
848
+ nh = _bg_rd_u32(hdr, 12)
849
+ block = _bg_rd_u32(hdr, 16)
850
+ return {"ok": True, "vocab": vocab, "d": d, "nlay": nlay, "nh": nh, "block": block}
851
+
852
+
853
+ def bg_is_bytegpt(path):
854
+ """mouth-sniff: NOT CLM\\x01 magic AND a sane 5xu32 ByteGPT header.
855
+ Mirrors generator.hexa gen_auto_ideate dispatch (CLM\\x01 -> clm, else bytegpt)."""
856
+ try:
857
+ with open(path, 'rb') as f:
858
+ hdr = f.read(20)
859
+ except Exception:
860
+ return False
861
+ if len(hdr) < 20:
862
+ return False
863
+ # CLM\x01 magic => ConvMoE, not ByteGPT
864
+ if hdr[0] == 67 and hdr[1] == 76 and hdr[2] == 77 and hdr[3] == 1:
865
+ return False
866
+ vocab = _bg_rd_u32(hdr, 0)
867
+ d = _bg_rd_u32(hdr, 4)
868
+ nlay = _bg_rd_u32(hdr, 8)
869
+ nh = _bg_rd_u32(hdr, 12)
870
+ block = _bg_rd_u32(hdr, 16)
871
+ # sane ranges + d divisible by n_head (GPT invariant)
872
+ if not (1 <= vocab <= 1 << 20 and 1 <= d <= 1 << 16 and 1 <= nlay <= 1024
873
+ and 1 <= nh <= 1024 and 1 <= block <= 1 << 20):
874
+ return False
875
+ if d % nh != 0:
876
+ return False
877
+ return True
878
+
879
+
880
+ def _rd_f32(rb, off, n):
881
+ """read n LE f32 from byte buffer at byte offset off -> float64 array[n]."""
882
+ return np.frombuffer(rb, dtype='<f4', count=n, offset=off).astype(np.float64)
883
+
884
+
885
+ def _bg_read_bind_block(rb, off, d):
886
+ """Read ONE BGB injected-bind block from the flat trailer at byte offset off.
887
+ Layout = a base ByteGPT layer's 12 param tensors in bg_load order (LE f32),
888
+ then one LE f32 scalar `gate`. Returns (block_dict, new_off).
889
+ (Shapes match bg_load's per-layer read exactly — reference-matched, no reorder.)"""
890
+ blk = {}
891
+ blk["ln1w"] = _rd_f32(rb, off, d); off += d * 4
892
+ blk["ln1b"] = _rd_f32(rb, off, d); off += d * 4
893
+ blk["inW"] = _rd_f32(rb, off, 3 * d * d).reshape(3 * d, d); off += 3 * d * d * 4
894
+ blk["inB"] = _rd_f32(rb, off, 3 * d); off += 3 * d * 4
895
+ blk["oW"] = _rd_f32(rb, off, d * d).reshape(d, d); off += d * d * 4
896
+ blk["oB"] = _rd_f32(rb, off, d); off += d * 4
897
+ blk["ln2w"] = _rd_f32(rb, off, d); off += d * 4
898
+ blk["ln2b"] = _rd_f32(rb, off, d); off += d * 4
899
+ blk["m0W"] = _rd_f32(rb, off, 4 * d * d).reshape(4 * d, d); off += 4 * d * d * 4
900
+ blk["m0B"] = _rd_f32(rb, off, 4 * d); off += 4 * d * 4
901
+ blk["m2W"] = _rd_f32(rb, off, d * 4 * d).reshape(d, 4 * d); off += d * 4 * d * 4
902
+ blk["m2B"] = _rd_f32(rb, off, d); off += d * 4
903
+ blk["gate"] = float(_rd_f32(rb, off, 1)[0]); off += 4
904
+ return blk, off
905
+
906
+
907
+ def bg_load(path):
908
+ """decode.hexa::bg_load — parse the flat binary ONCE into a weight dict.
909
+ Weight binary layout (LE f32, decode.hexa:29-36):
910
+ [vocab,d,n_layer,n_head,block] 5xu32
911
+ tok[vocab*d] pos[block*d]
912
+ per layer: ln1.w[d] ln1.b[d] in_proj.w[3d*d] in_proj.b[3d]
913
+ out_proj.w[d*d] out_proj.b[d] ln2.w[d] ln2.b[d]
914
+ mlp0.w[4d*d] mlp0.b[4d] mlp2.w[d*4d] mlp2.b[d]
915
+ ln_f.w[d] ln_f.b[d] head[vocab*d]
916
+ (torch Linear stores W as [out,in] row-major; y = x.Wt + b.)"""
917
+ rb = open(path, 'rb').read()
918
+ vocab = _bg_rd_u32(rb, 0)
919
+ d = _bg_rd_u32(rb, 4)
920
+ nlay = _bg_rd_u32(rb, 8)
921
+ nh = _bg_rd_u32(rb, 12)
922
+ block = _bg_rd_u32(rb, 16)
923
+ off = 20
924
+
925
+ tok = _rd_f32(rb, off, vocab * d).reshape(vocab, d); off += vocab * d * 4
926
+ pos = _rd_f32(rb, off, block * d).reshape(block, d); off += block * d * 4
927
+
928
+ ln1w = []; ln1b = []; inW = []; inB = []
929
+ oW = []; oB = []; ln2w = []; ln2b = []
930
+ m0W = []; m0B = []; m2W = []; m2B = []
931
+ for _ in range(nlay):
932
+ ln1w.append(_rd_f32(rb, off, d)); off += d * 4
933
+ ln1b.append(_rd_f32(rb, off, d)); off += d * 4
934
+ inW.append(_rd_f32(rb, off, 3 * d * d).reshape(3 * d, d)); off += 3 * d * d * 4
935
+ inB.append(_rd_f32(rb, off, 3 * d)); off += 3 * d * 4
936
+ oW.append(_rd_f32(rb, off, d * d).reshape(d, d)); off += d * d * 4
937
+ oB.append(_rd_f32(rb, off, d)); off += d * 4
938
+ ln2w.append(_rd_f32(rb, off, d)); off += d * 4
939
+ ln2b.append(_rd_f32(rb, off, d)); off += d * 4
940
+ m0W.append(_rd_f32(rb, off, 4 * d * d).reshape(4 * d, d)); off += 4 * d * d * 4
941
+ m0B.append(_rd_f32(rb, off, 4 * d)); off += 4 * d * 4
942
+ m2W.append(_rd_f32(rb, off, d * 4 * d).reshape(d, 4 * d)); off += d * 4 * d * 4
943
+ m2B.append(_rd_f32(rb, off, d)); off += d * 4
944
+ lnfw = _rd_f32(rb, off, d); off += d * 4
945
+ lnfb = _rd_f32(rb, off, d); off += d * 4
946
+ head = _rd_f32(rb, off, vocab * d).reshape(vocab, d); off += vocab * d * 4
947
+
948
+ # ── optional BGB injected-bind trailer (serialize_bind, H_9027) ──────
949
+ # "BGB\x01" = bytes 66,71,66,1, appended AFTER `head`. Carries n_bind appended
950
+ # GATED transformer blocks (each = a standard base layer: the SAME 12 param
951
+ # tensors in the SAME order/layout as above, then one LE f32 gate). Applied
952
+ # after the L base blocks and BEFORE ln_f (mirrors the CLM "CLMB" bind-trailer
953
+ # precedent). ABSENT trailer => bind=[] => forward BYTE-IDENTICAL to plain ByteGPT.
954
+ bind = []
955
+ if (off + 8 <= len(rb)
956
+ and rb[off] == 66 and rb[off + 1] == 71
957
+ and rb[off + 2] == 66 and rb[off + 3] == 1):
958
+ off += 4 # skip "BGB\x01"
959
+ n_bind = _bg_rd_u32(rb, off); off += 4
960
+ for _ in range(n_bind):
961
+ blk, off = _bg_read_bind_block(rb, off, d)
962
+ bind.append(blk)
963
+
964
+ return {"ok": True, "vocab": vocab, "d": d, "nlay": nlay, "nh": nh, "block": block,
965
+ "tok": tok, "pos": pos, "ln1w": ln1w, "ln1b": ln1b,
966
+ "inW": inW, "inB": inB, "oW": oW, "oB": oB,
967
+ "ln2w": ln2w, "ln2b": ln2b, "m0W": m0W, "m0B": m0B,
968
+ "m2W": m2W, "m2B": m2B, "lnfw": lnfw, "lnfb": lnfb, "head": head,
969
+ "bind": bind}
970
+
971
+
972
+ # bg_load_ranged — byte-identical W-map to bg_load (hexa builds it via ranged
973
+ # read_bytes_at to dodge the whole-file boxing OOM; the resulting weights are the
974
+ # same, and the py read already mmaps lazily via frombuffer). Aliased for surface
975
+ # parity with the hexa public entries (decode.hexa:782).
976
+ bg_load_ranged = bg_load
977
+
978
+
979
+ # ── forward — 1:1 from decode.hexa _bg_mha / _bg_linear / bg_forward_last_W ──
980
+
981
+ def _bg_mha(H, inW, inB, oW, oB, T, d, nh):
982
+ """decode.hexa::_bg_mha — torch nn.MultiheadAttention semantics.
983
+ H:[T,d] pre-normed. in_proj W[3d,d] rows Q|K|V; out_proj W[d,d]+b.
984
+ scale=1/dt_sqrt(hd), causal, libm exp softmax. Returns Aout:[T,d]."""
985
+ hd = d // nh
986
+ scale = 1.0 / dt_sqrt(float(hd))
987
+ # QKV = H[T,d] @ inW.T[d,3d] + inB -> packed [T,3d]; Q=cols0..d, K=d..2d, V=2d..3d
988
+ QKV = H @ inW.T + inB # [T, 3d]
989
+ Q = QKV[:, 0:d]; K = QKV[:, d:2 * d]; V = QKV[:, 2 * d:3 * d]
990
+ ctx = np.zeros((T, d), dtype=np.float64)
991
+ for hh in range(nh):
992
+ base = hh * hd
993
+ Qh = Q[:, base:base + hd]; Kh = K[:, base:base + hd]; Vh = V[:, base:base + hd]
994
+ for i in range(T):
995
+ L = i + 1
996
+ # scores over keys 0..i, scaled
997
+ sc = (Qh[i] @ Kh[0:L].T) * scale # [L]
998
+ mx = sc.max()
999
+ e = np.exp(sc - mx) # libm-equivalent
1000
+ tot = e.sum()
1001
+ ctx[i, base:base + hd] = (e / tot) @ Vh[0:L] # [hd]
1002
+ # out proj: Aout = ctx @ oW.T + oB
1003
+ return ctx @ oW.T + oB
1004
+
1005
+
1006
+ def _bg_apply_bind(x, bind, T, d, nh):
1007
+ """Apply N appended GATED transformer blocks to the full post-base sequence
1008
+ x:[T,d], AFTER the L base blocks and BEFORE ln_f. Each block is a STANDARD
1009
+ transformer block (reuses _bg_layernorm_rows / _bg_mha / _bg_gelu — the exact
1010
+ base-layer ops) plus a scalar gate:
1011
+ block(x) = x + mha(ln1(x)) + mlp(ln2(x + mha(ln1(x))))
1012
+ x = x + gate * (block(x) - x) # gate=0 => identity (exact)
1013
+ Mirrors BindAttnByteGPT.forward `x = x + gate*(bind(x)-x)`. Returns x:[T,d]."""
1014
+ for blk in bind:
1015
+ nrm = _bg_layernorm_rows(x, blk["ln1w"], blk["ln1b"], T, d)
1016
+ aout = _bg_mha(nrm, blk["inW"], blk["inB"], blk["oW"], blk["oB"], T, d, nh)
1017
+ xa = x + aout # x + mha(ln1(x))
1018
+ nrm2 = _bg_layernorm_rows(xa, blk["ln2w"], blk["ln2b"], T, d)
1019
+ h4 = _bg_gelu(nrm2 @ blk["m0W"].T + blk["m0B"]) # [T, 4d]
1020
+ mlpo = h4 @ blk["m2W"].T + blk["m2B"] # [T, d]
1021
+ blk_out = xa + mlpo # = block(x)
1022
+ x = x + blk["gate"] * (blk_out - x) # gate=0 => x unchanged
1023
+ return x
1024
+
1025
+
1026
+ def bg_forward_last_W(W, ids, T):
1027
+ """decode.hexa::bg_forward_last_W — full forward from a loaded weight
1028
+ dict; returns last-position next-byte logits float64[vocab]. ids:[T] int.
1029
+ When W["bind"] is non-empty the appended gated blocks run after the L base
1030
+ blocks and before ln_f (H_9027); absent/empty => byte-identical to before."""
1031
+ d = W["d"]; nlay = W["nlay"]; nh = W["nh"]; vocab = W["vocab"]
1032
+ ids = np.asarray(ids, dtype=np.int64)
1033
+ # x[T,d] = tok[id] + pos[t]
1034
+ x = W["tok"][ids] + W["pos"][0:T] # [T, d]
1035
+ for Lr in range(nlay):
1036
+ # attn sub-block: x = x + MHA(LN1(x))
1037
+ nrm = _bg_layernorm_rows(x, W["ln1w"][Lr], W["ln1b"][Lr], T, d)
1038
+ aout = _bg_mha(nrm, W["inW"][Lr], W["inB"][Lr], W["oW"][Lr], W["oB"][Lr], T, d, nh)
1039
+ x = x + aout
1040
+ # mlp sub-block: x = x + Wd(GELU(W0(LN2(x))))
1041
+ nrm = _bg_layernorm_rows(x, W["ln2w"][Lr], W["ln2b"][Lr], T, d)
1042
+ h4 = nrm @ W["m0W"][Lr].T + W["m0B"][Lr] # [T, 4d]
1043
+ h4 = _bg_gelu(h4)
1044
+ mlpo = h4 @ W["m2W"][Lr].T + W["m2B"][Lr] # [T, d]
1045
+ x = x + mlpo
1046
+ # appended injected-bind blocks (H_9027) — after base stack, before ln_f
1047
+ if W.get("bind"):
1048
+ x = _bg_apply_bind(x, W["bind"], T, d, nh)
1049
+ # final LayerNorm on the LAST position only, then tied head
1050
+ lastrow = _bg_layernorm_rows(x[T - 1:T], W["lnfw"], W["lnfb"], 1, d)[0] # [d]
1051
+ logits = W["head"] @ lastrow # [vocab]
1052
+ return logits
1053
+
1054
+
1055
+ def bg_forward_last_hidden(W, ids, T):
1056
+ """H_9129 L5 rung-3 — same full forward as bg_forward_last_W but returns the
1057
+ final-LN LAST-position hidden state float64[d] (the pre-head representation),
1058
+ NOT the tied-head logits. The hippocampal associative store (core/hippo_assoc)
1059
+ keys on this hidden, not on logits (design: reps = final-LN hidden). Byte-shares
1060
+ the forward body with bg_forward_last_W; the only difference is the return line
1061
+ (head @ lastrow omitted). ids:[T] int; W["bind"] handled identically (H_9027)."""
1062
+ d = W["d"]; nlay = W["nlay"]; nh = W["nh"]
1063
+ ids = np.asarray(ids, dtype=np.int64)
1064
+ x = W["tok"][ids] + W["pos"][0:T] # [T, d]
1065
+ for Lr in range(nlay):
1066
+ nrm = _bg_layernorm_rows(x, W["ln1w"][Lr], W["ln1b"][Lr], T, d)
1067
+ aout = _bg_mha(nrm, W["inW"][Lr], W["inB"][Lr], W["oW"][Lr], W["oB"][Lr], T, d, nh)
1068
+ x = x + aout
1069
+ nrm = _bg_layernorm_rows(x, W["ln2w"][Lr], W["ln2b"][Lr], T, d)
1070
+ h4 = _bg_gelu(nrm @ W["m0W"][Lr].T + W["m0B"][Lr]) # [T, 4d]
1071
+ mlpo = h4 @ W["m2W"][Lr].T + W["m2B"][Lr] # [T, d]
1072
+ x = x + mlpo
1073
+ if W.get("bind"):
1074
+ x = _bg_apply_bind(x, W["bind"], T, d, nh)
1075
+ lastrow = _bg_layernorm_rows(x[T - 1:T], W["lnfw"], W["lnfb"], 1, d)[0] # [d]
1076
+ return lastrow # final-LN last-pos hidden
1077
+
1078
+
1079
+ def bytegpt_forward_last(path, ids, T):
1080
+ """decode.hexa::bytegpt_forward_last — load + forward (parity probe)."""
1081
+ W = bg_load(path)
1082
+ return bg_forward_last_W(W, ids, T)
1083
+
1084
+
1085
+ def bg_argmax(a):
1086
+ """decode.hexa::bg_argmax — index of max (ties: first, strict >)."""
1087
+ bi = 0
1088
+ bv = a[0]
1089
+ for k in range(1, len(a)):
1090
+ if a[k] > bv:
1091
+ bv = a[k]; bi = k
1092
+ return bi
1093
+
1094
+
1095
+ def _seed_to_ids(seed):
1096
+ """string|bytes|list -> list[int] byte ids."""
1097
+ if isinstance(seed, (list, tuple)):
1098
+ return [int(x) for x in seed]
1099
+ if isinstance(seed, str):
1100
+ seed = seed.encode('utf-8', 'surrogateescape')
1101
+ return list(seed)
1102
+
1103
+
1104
+ # ── KV-cache fast path — NEW (byte-exact TOKEN stream vs full-forward) ───────
1105
+ #
1106
+ # The full-forward loop re-forwards ALL T window tokens every decode step
1107
+ # (O(gen²)). The KV path caches per-layer (K,V) = the in_proj K,V slices from
1108
+ # _bg_mha and, on each new token, forwards ONLY the new position, attending it
1109
+ # against the cached K,V of all layers. This mirrors the hexa KV-cache
1110
+ # (decode.hexa:919, proven byte-identical to full-forward there).
1111
+ #
1112
+ # WINDOW-SLIDE RESYNC: ByteGPT indexes the positional embedding by position
1113
+ # WITHIN the window (pos[0:T]), not by absolute token index. While the window is
1114
+ # still GROWING (n <= block, start=0) every cached position keeps its window
1115
+ # index → K,V stay valid → cheap incremental append. Once the window SLIDES
1116
+ # (n > block, start>0) every token's window position shifts by one → its pos
1117
+ # embedding (hence K,V) changes → the cache is INVALID and is fully REBUILT at
1118
+ # M=T (byte-identical to full-forward for that window). So sliding steps cost a
1119
+ # full forward (correct, not faster); the speedup is the growing-window regime,
1120
+ # which is the entire eval decode path (seed+gen << block=512 for the 303M).
1121
+
1122
+ def _bg_forward_build(W, ids, T):
1123
+ """Full-forward over the window (== bg_forward_last_W) that ALSO captures the
1124
+ per-layer (K,V) in_proj slices for every position. Returns (logits, cache)
1125
+ where cache[Lr] = [K[T,d], V[T,d]]. The last-position logits are byte-
1126
+ identical to bg_forward_last_W (same ops, M=T batched)."""
1127
+ d = W["d"]; nlay = W["nlay"]; nh = W["nh"]
1128
+ ids = np.asarray(ids, dtype=np.int64)
1129
+ x = W["tok"][ids] + W["pos"][0:T] # [T, d]
1130
+ hd = d // nh
1131
+ scale = 1.0 / dt_sqrt(float(hd))
1132
+ cache = []
1133
+ for Lr in range(nlay):
1134
+ nrm = _bg_layernorm_rows(x, W["ln1w"][Lr], W["ln1b"][Lr], T, d)
1135
+ QKV = nrm @ W["inW"][Lr].T + W["inB"][Lr] # [T, 3d]
1136
+ Q = QKV[:, 0:d]; K = QKV[:, d:2 * d]; V = QKV[:, 2 * d:3 * d]
1137
+ ctx = np.zeros((T, d), dtype=np.float64)
1138
+ for hh in range(nh):
1139
+ base = hh * hd
1140
+ Qh = Q[:, base:base + hd]; Kh = K[:, base:base + hd]; Vh = V[:, base:base + hd]
1141
+ for i in range(T):
1142
+ L = i + 1
1143
+ sc = (Qh[i] @ Kh[0:L].T) * scale
1144
+ mx = sc.max()
1145
+ e = np.exp(sc - mx)
1146
+ tot = e.sum()
1147
+ ctx[i, base:base + hd] = (e / tot) @ Vh[0:L]
1148
+ aout = ctx @ W["oW"][Lr].T + W["oB"][Lr]
1149
+ x = x + aout
1150
+ nrm = _bg_layernorm_rows(x, W["ln2w"][Lr], W["ln2b"][Lr], T, d)
1151
+ h4 = nrm @ W["m0W"][Lr].T + W["m0B"][Lr]
1152
+ h4 = _bg_gelu(h4)
1153
+ mlpo = h4 @ W["m2W"][Lr].T + W["m2B"][Lr]
1154
+ x = x + mlpo
1155
+ cache.append([K.copy(), V.copy()])
1156
+ lastrow = _bg_layernorm_rows(x[T - 1:T], W["lnfw"], W["lnfb"], 1, d)[0]
1157
+ logits = W["head"] @ lastrow
1158
+ return logits, cache
1159
+
1160
+
1161
+ def _bg_kv_step(W, cache, id_new, win_pos):
1162
+ """Forward ONLY the new position (window index win_pos, byte id id_new),
1163
+ attending against + appending to the per-layer K,V cache. Returns the new
1164
+ position's next-byte logits. cache[Lr]=[K,V] is grown in place by one row.
1165
+ Reuses the EXACT _bg_mha attention ops (same scale, libm exp softmax, same
1166
+ per-output accumulation order) so the token stream matches full-forward."""
1167
+ d = W["d"]; nlay = W["nlay"]; nh = W["nh"]
1168
+ hd = d // nh
1169
+ scale = 1.0 / dt_sqrt(float(hd))
1170
+ x = (W["tok"][int(id_new)] + W["pos"][win_pos]).astype(np.float64).reshape(1, d)
1171
+ for Lr in range(nlay):
1172
+ nrm = _bg_layernorm_rows(x, W["ln1w"][Lr], W["ln1b"][Lr], 1, d) # [1,d]
1173
+ qkv = nrm @ W["inW"][Lr].T + W["inB"][Lr] # [1,3d]
1174
+ qn = qkv[:, 0:d]; kn = qkv[:, d:2 * d]; vn = qkv[:, 2 * d:3 * d] # [1,d]
1175
+ Kc = np.concatenate([cache[Lr][0], kn], axis=0) # [T,d]
1176
+ Vc = np.concatenate([cache[Lr][1], vn], axis=0)
1177
+ cache[Lr][0] = Kc; cache[Lr][1] = Vc
1178
+ ctx = np.zeros((1, d), dtype=np.float64)
1179
+ for hh in range(nh):
1180
+ base = hh * hd
1181
+ qh = qn[0, base:base + hd] # [hd]
1182
+ Kh = Kc[:, base:base + hd] # [T,hd]
1183
+ Vh = Vc[:, base:base + hd] # [T,hd]
1184
+ sc = (qh @ Kh.T) * scale # [T]
1185
+ mx = sc.max()
1186
+ e = np.exp(sc - mx)
1187
+ tot = e.sum()
1188
+ ctx[0, base:base + hd] = (e / tot) @ Vh
1189
+ aout = ctx @ W["oW"][Lr].T + W["oB"][Lr] # [1,d]
1190
+ x = x + aout
1191
+ nrm = _bg_layernorm_rows(x, W["ln2w"][Lr], W["ln2b"][Lr], 1, d)
1192
+ h4 = nrm @ W["m0W"][Lr].T + W["m0B"][Lr]
1193
+ h4 = _bg_gelu(h4)
1194
+ mlpo = h4 @ W["m2W"][Lr].T + W["m2B"][Lr]
1195
+ x = x + mlpo
1196
+ lastrow = _bg_layernorm_rows(x, W["lnfw"], W["lnfb"], 1, d)[0]
1197
+ logits = W["head"] @ lastrow
1198
+ return logits
1199
+
1200
+
1201
+ def _bg_step_logits(W, toks, st):
1202
+ """One decode step's last-position logits via KV cache. `st` is a mutable
1203
+ dict {'cache','start'} carried across steps. Builds (M=T) on the first step
1204
+ OR whenever the window slides (start changes = pos-embedding re-index); else
1205
+ appends the single new token incrementally."""
1206
+ block = W["block"]
1207
+ n = len(toks)
1208
+ start = n - block if n > block else 0
1209
+ T = n - start
1210
+ # Injected-bind models (H_9027): the appended blocks have their OWN attention
1211
+ # over the full post-base sequence, which the incremental KV step can't supply
1212
+ # from base-layer K,V alone — so decode via the full-sequence forward (byte-
1213
+ # exact vs the torch reference; gate=0 => identical to the base KV stream since
1214
+ # the base forward is unchanged and the bind contribution is exactly zero).
1215
+ if W.get("bind"):
1216
+ return bg_forward_last_W(W, toks[start:start + T], T)
1217
+ if st['cache'] is None or start != st['start']:
1218
+ logits, cache = _bg_forward_build(W, toks[start:start + T], T)
1219
+ st['cache'] = cache; st['start'] = start
1220
+ return logits
1221
+ # incremental: the new token is at window position T-1 (= toks[start+T-1]).
1222
+ return _bg_kv_step(W, st['cache'], toks[start + T - 1], T - 1)
1223
+
1224
+
1225
+ # ── public decode entries — 1:1 from decode.hexa (KV path wired in) ──
1226
+
1227
+ def bytegpt_decode_argmax(path, seed_ids, gen):
1228
+ """decode.hexa::bytegpt_decode_argmax — greedy continuation, weights
1229
+ loaded ONCE, prompt window grown (capped at block). Returns {ok,text,ids}.
1230
+ (Decode loop = byte-exact KV cache; full-forward reference = _decode_argmax_W_full.)"""
1231
+ W = bg_load(path)
1232
+ return _decode_argmax_W(W, seed_ids, gen)
1233
+
1234
+
1235
+ # bytegpt_decode_argmax_ranged — OOM-safe twin (hexa: bg_load_ranged). Same compute.
1236
+ def bytegpt_decode_argmax_ranged(path, seed_ids, gen):
1237
+ W = bg_load_ranged(path)
1238
+ return _decode_argmax_W(W, seed_ids, gen)
1239
+
1240
+
1241
+ def _decode_argmax_W(W, seed_ids, gen):
1242
+ """KV-cache greedy decode from an already-loaded weight dict. Token stream is
1243
+ byte-exact vs _decode_argmax_W_full (the O(gen²) full-forward reference)."""
1244
+ toks = _seed_to_ids(seed_ids)
1245
+ outl = []
1246
+ st = {'cache': None, 'start': None}
1247
+ for _ in range(gen):
1248
+ logits = _bg_step_logits(W, toks, st)
1249
+ nb = bg_argmax(logits)
1250
+ toks.append(nb)
1251
+ outl.append(nb)
1252
+ text = bytes(outl).decode('utf-8', 'surrogateescape')
1253
+ return {"ok": True, "text": text, "ids": outl}
1254
+
1255
+
1256
+ def _decode_argmax_W_full(W, seed_ids, gen):
1257
+ """ORIGINAL O(gen²) full-forward greedy decode (KV-cache OFF). Retained as the
1258
+ byte-exactness reference for the self-test."""
1259
+ vocab = W["vocab"]; block = W["block"]
1260
+ toks = _seed_to_ids(seed_ids)
1261
+ outl = []
1262
+ for _ in range(gen):
1263
+ n = len(toks)
1264
+ start = n - block if n > block else 0
1265
+ T = n - start
1266
+ ids = toks[start:start + T]
1267
+ logits = bg_forward_last_W(W, ids, T)
1268
+ nb = bg_argmax(logits)
1269
+ toks.append(nb)
1270
+ outl.append(nb)
1271
+ text = bytes(outl).decode('utf-8', 'surrogateescape')
1272
+ return {"ok": True, "text": text, "ids": outl}
1273
+
1274
+
1275
+ def bytegpt_decode_topk_sampled(path, seed_ids, gen, top_k, temp, seed_rng):
1276
+ """decode.hexa::bytegpt_decode_topk_sampled — seeded top-k temp draw."""
1277
+ W = bg_load(path)
1278
+ return bytegpt_decode_topk_sampled_W(W, seed_ids, gen, top_k, temp, seed_rng)
1279
+
1280
+
1281
+ # OOM-safe twin (hexa: bytegpt_decode_topk_sampled_ranged via bg_load_ranged).
1282
+ def bytegpt_decode_topk_sampled_ranged(path, seed_ids, gen, top_k, temp, seed_rng):
1283
+ W = bg_load_ranged(path)
1284
+ return bytegpt_decode_topk_sampled_W(W, seed_ids, gen, top_k, temp, seed_rng)
1285
+
1286
+
1287
+ def bytegpt_decode_topk_sampled_W(W, seed_ids, gen, top_k, temp, seed_rng):
1288
+ """KV-cache seeded top-k decode from an already-loaded weight dict (== hexa
1289
+ _bg_gen_from_W KV branch). seed_ids = string|bytes|list of byte ids. Token
1290
+ stream is byte-exact vs bytegpt_decode_topk_sampled_W_full."""
1291
+ vocab = W["vocab"]
1292
+ toks = _seed_to_ids(seed_ids)
1293
+ outl = []
1294
+ rng = _mix32(seed_rng)
1295
+ st = {'cache': None, 'start': None}
1296
+ for _ in range(gen):
1297
+ logits = _bg_step_logits(W, toks, st)
1298
+ nb, rng = _topk_sample(logits, vocab, top_k, temp, rng)
1299
+ toks.append(nb)
1300
+ outl.append(nb)
1301
+ text = bytes(outl).decode('utf-8', 'surrogateescape')
1302
+ return {"ok": True, "text": text, "ids": outl}
1303
+
1304
+
1305
+ def bytegpt_decode_topk_sampled_W_full(W, seed_ids, gen, top_k, temp, seed_rng):
1306
+ """ORIGINAL O(gen²) full-forward seeded top-k decode (KV-cache OFF). Retained
1307
+ as the byte-exactness reference for the self-test."""
1308
+ vocab = W["vocab"]; block = W["block"]
1309
+ toks = _seed_to_ids(seed_ids)
1310
+ outl = []
1311
+ rng = _mix32(seed_rng)
1312
+ for _ in range(gen):
1313
+ n = len(toks)
1314
+ start = n - block if n > block else 0
1315
+ T = n - start
1316
+ ids = toks[start:start + T]
1317
+ logits = bg_forward_last_W(W, ids, T)
1318
+ nb, rng = _topk_sample(logits, vocab, top_k, temp, rng)
1319
+ toks.append(nb)
1320
+ outl.append(nb)
1321
+ text = bytes(outl).decode('utf-8', 'surrogateescape')
1322
+ return {"ok": True, "text": text, "ids": outl}
1323
+
1324
+
1325
+ # ════════════════════════════════════════════════════════════════════════
1326
+ # (d) MOUTH DISPATCH — header-sniff (mirrors generator.hexa gen_auto_backend).
1327
+ # CLM\x01 magic + CLMX trailer => conv (.clm); sane 5xu32 header => byte (.bin).
1328
+ # ════════════════════════════════════════════════════════════════════════
1329
+
1330
+ def decode_mouth_kind(path):
1331
+ """gen_mouth_kind — 'clm' | 'bytegpt' | 'unknown'. clm checked FIRST (its
1332
+ CLM\\x01 magic is what bg_is_bytegpt explicitly rejects)."""
1333
+ if clm_decodable(path):
1334
+ return "clm"
1335
+ if bg_is_bytegpt(path):
1336
+ return "bytegpt"
1337
+ return "unknown"
1338
+
1339
+
1340
+ def decode_load(path):
1341
+ """gen_auto_backend — load the correct weight dict by mouth sniff. Returns
1342
+ (kind, W). kind in {'clm','bytegpt'}; raises for an unknown mouth."""
1343
+ k = decode_mouth_kind(path)
1344
+ if k == "clm":
1345
+ return "clm", clm_load_weights(path)
1346
+ if k == "bytegpt":
1347
+ return "bytegpt", bg_load(path)
1348
+ raise RuntimeError("ckpt not decodable (unknown mouth): " + str(path))
1349
+
1350
+
1351
+ def decode_auto_topk_sampled(path, seed, gen, top_k, temp, seed_rng):
1352
+ """gen_auto_chat — dispatch a seeded top-k decode to the correct mouth by
1353
+ header sniff (conv .clm -> clm_decode_topk_sampled_W; byte .bin ->
1354
+ bytegpt_decode_topk_sampled_W, KV cache). seed = string."""
1355
+ kind, W = decode_load(path)
1356
+ if kind == "clm":
1357
+ return clm_decode_topk_sampled_W(W, seed, gen, top_k, temp, seed_rng)
1358
+ return bytegpt_decode_topk_sampled_W(W, seed, gen, top_k, temp, seed_rng)
1359
+
1360
+
1361
+ def decode_auto_argmax(path, seed, gen):
1362
+ """gen_auto (greedy) — dispatch argmax decode by header sniff. seed = string.
1363
+ (clm uses its T=24 right-aligned window; bytegpt grows the window to block.)"""
1364
+ kind, W = decode_load(path)
1365
+ if kind == "clm":
1366
+ # clm_decode_argmax loads-from-path; re-wrap on the already-loaded W path
1367
+ V = W["V"]; T = 24
1368
+ seed_b = seed.encode('utf-8', 'surrogateescape')
1369
+ slen = len(seed_b)
1370
+ tok = np.empty(T, dtype=np.float64)
1371
+ for p in range(T):
1372
+ si = slen - T + p
1373
+ tok[p] = float(seed_b[si]) if si >= 0 else 32.0
1374
+ out = bytearray()
1375
+ for _ in range(gen):
1376
+ logits = _fwd_logits(W, tok, T)
1377
+ row = logits[T - 1]
1378
+ besti = 0; bestv = row[0]
1379
+ for k in range(1, V):
1380
+ if row[k] > bestv:
1381
+ bestv = row[k]; besti = k
1382
+ out.append(besti)
1383
+ tok[:T - 1] = tok[1:]
1384
+ tok[T - 1] = float(besti)
1385
+ return {"ok": True, "text": out.decode('utf-8', 'surrogateescape')}
1386
+ return _decode_argmax_W(W, seed, gen)