nx_reader_squad_f32_gate.nx source
↩ module page · 708 lines · 33570 B
1// nx_reader_squad_f32_gate.nx -- R3e of the NEURAL PASSAGE READER arc: TRAIN-ON-F32 (quantize-after comes
2// next). The Q16 lane closed honestly: 6 configurations all entered the uniform-collapse absorbing state at
3// E=24 (see nx_reader_squad_gate). f32 has no quantization floor and no bit-identical-states trap, so the
4// SAME architecture + data + recipe should train. This gate = the Q16 gate ported to the ta_* f32 tensor
5// autograd (transformer ops added 2026-07-09, identities verbatim from the GREEN nfa_* lib).
6// T1 reader held-out span-F1 > question-blind ablation + 100 (liar-kill)
7// T2 reader held-out exact-start > 60 permille (chance ~11)
8// T3 train loss falls > 40% (real learning, no collapse)
9// T4 deterministic re-eval
10// Consumes: reader_rows.bin ('dt'), semppmi_v1.bin (vocab), embed_v1.bin (SGNS Q10 -> f32 RAW magnitude).
11// expect_exit: 0 license_tier: ORIGINAL Sovereign: nx_autograd_tensor (f32) + nx_syscalls.
12import "nx_autograd_tensor.nx"
13import "nx_thread_pool.nx" // RF_PAR: data-parallel batch training across the 16-worker pool
14import "nx_hw.nx"
15import "nx_syscalls.nx"
16
17func rf_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
18func rf_pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var x: i64=v; if x<0{b[0]=45;sys_write(1,b,1);x=0-x} if x==0{b[0]=48;sys_write(1,b,1);return 0} var d: i64=0; var y: i64=x; while y>0{d=d+1;y=y/10} var i: i64=d-1; y=x; while i>=0{b[i]=(48+(y%10)) as u8;y=y/10;i=i-1} sys_write(1,b,d); return 0 }
19func rf_ck(name: *u8, c: i64) -> i64 { if c==1 { rf_puts(" PASS " as *u8) } else { rf_puts(" FAIL " as *u8) } rf_puts(name); rf_puts("\n" as *u8); return c }
20
21const RF_E: i64 = 24
22const RF_F: i64 = 48
23const RF_MAXT: i64 = 96
24const RF_MAXQ: i64 = 20
25const RF_MAXG: i64 = 8
26// RF_XL flips the whole gate between the small (998-row reader_rows.bin) and the XL (4771-row
27// reader_rows_xl.bin) datasets -- ONE flag, no duplication. RF_NROWS sizes the row arena for either.
28const RF_XL: i64 = 1
29// RF_PAR: run the batch of 8 examples DATA-PARALLEL on the thread pool (per-example private arenas; grads
30// reduced in mb-order => BIT-IDENTICAL to serial => same loss curve, verified vs the serial 8353 reference).
31// Proven correct in nx_ta_parallel_grad_gate. ~5x faster to the verdict on the soft-float bottleneck.
32const RF_PAR: i64 = 1
33const RF_BATCH: i64 = 8
34// RF_CAUSAL: attention masking. 0 = BIDIRECTIONAL (BERT-style), 1 = causal (autoregressive, from the nano-LM).
35// THEORY TESTED + REFUTED (2026-07-10): I hypothesized causal masking was the bug behind the +9-over-ablation
36// gap. Retrained bidirectional (RF_CAUSAL=0): F1=79 vs causal F1=81 -- a WASH (noise-level, slightly WORSE).
37// => masking is NOT the bug; at E=24/1-layer/1-head with static hash embeddings, attention can't extract much
38// question signal regardless of masking. The gap is a CAPACITY/PARADIGM wall, not a wiring error. Kept =1
39// (the marginally-better measured baseline). Real fix = pretrained model (sovereign Qwen), not from-scratch tweaks.
40const RF_CAUSAL: i64 = 1
41const RF_NROWS: i64 = 4800
42const RF_MAXV: i64 = 16384
43const RF_MAPN: i64 = 32768
44const FOFF_EMB: i64 = 0
45const FOFF_WQ: i64 = 393216
46const FOFF_WK: i64 = 393792
47const FOFF_WV: i64 = 394368
48const FOFF_WO: i64 = 394944
49const FOFF_WG: i64 = 395520
50const FOFF_WU: i64 = 396672
51const FOFF_WD: i64 = 397824
52const FOFF_US: i64 = 398976
53const FOFF_UE: i64 = 399000
54const RF_NP: i64 = 399024
55
56// dataset path helpers -- RF_XL selects small vs XL; used by main + the checkpoint fns (no arg-threading).
57func rf_rows_path() -> *u8 { if RF_XL == 1 { return "knowledge/index/reader_rows_xl.bin" as *u8 } return "knowledge/index/reader_rows.bin" as *u8 }
58func rf_ck_path() -> *u8 { if RF_XL == 1 { return "knowledge/index/rsqf32xl_ckpt.bin" as *u8 } return "knowledge/index/rsqf32_ckpt.bin" as *u8 }
59func rf_ck_part_path() -> *u8 { if RF_XL == 1 { return "knowledge/index/rsqf32xl_ckpt.bin.part" as *u8 } return "knowledge/index/rsqf32_ckpt.bin.part" as *u8 }
60func rf_persist_path() -> *u8 { if RF_XL == 1 { return "knowledge/index/reader_neural_f32xl.bin" as *u8 } return "knowledge/index/reader_neural_f32.bin" as *u8 }
61
62func rf_ehash(buf: *u8, off: i64, len: i64) -> i64 {
63 var h1: i64 = 5381
64 var h2: i64 = 77245
65 var i: i64 = 0
66 while i < len { let c: i64 = buf[off+i] as i64; h1 = (h1*33 + c) % 1073741789; h2 = (h2*131 + c) % 1073741783; i = i + 1 }
67 return h1 * 1073741783 + h2
68}
69func rf_bsearch(a: *i64, n: i64, v: i64) -> i64 {
70 var lo: i64 = 0
71 var hi: i64 = n - 1
72 while lo <= hi { let mid: i64 = (lo+hi)/2; if a[mid] == v { return mid } if a[mid] < v { lo = mid+1 } else { hi = mid-1 } }
73 return 0-1
74}
75func rf_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c }
76func rf_isal(c: i64) -> i64 { if c >= 97 { if c <= 122 { return 1 } } if c >= 48 { if c <= 57 { return 1 } } return 0 }
77func rf_tok(buf: *u8, n: i64, hout: *i64, cap: i64) -> i64 {
78 let wb: *u8 = sys_mmap(64)
79 var nt: i64 = 0
80 var i: i64 = 0
81 while i < n {
82 let c: i64 = rf_lc(buf[i] as i64)
83 if rf_isal(c) == 1 {
84 var wl: i64 = 0
85 var j: i64 = i
86 var live: i64 = 1
87 while live == 1 {
88 if j >= n { live = 0 } else {
89 let cj: i64 = rf_lc(buf[j] as i64)
90 if rf_isal(cj) == 0 { live = 0 } else { if wl < 48 { wb[wl] = cj as u8; wl = wl + 1 } j = j + 1 }
91 }
92 }
93 if nt < cap { hout[nt] = rf_ehash(wb, 0, wl); nt = nt + 1 }
94 i = j
95 } else { i = i + 1 }
96 }
97 return nt
98}
99func rf_vid(map: *i64, vhash: *i64, vst: *i64, h: i64) -> i64 {
100 var slot: i64 = h & (RF_MAPN - 1)
101 if slot < 0 { slot = 0 - slot }
102 var probe: i64 = 0
103 while probe < RF_MAPN {
104 let e: i64 = map[slot]
105 if e == 0 {
106 if vst[0] >= RF_MAXV - 1 { return 1 }
107 vst[0] = vst[0] + 1
108 let id: i64 = vst[0]
109 vhash[id] = h
110 map[slot] = id
111 return id
112 }
113 if vhash[e] == h { return e }
114 slot = (slot + 1) & (RF_MAPN - 1)
115 probe = probe + 1
116 }
117 return 1
118}
119
120// forward on the ta_ tape (f32). out[0]=loss node, out[1]=Ls, out[2]=Le, out[3]=Xg leaf, out[4..12]=leaves.
121// rtab = precomputed RoPE cos/sin table (nx_f32_sin/cos mmap PER CALL -> table-driven or OOM).
122func rf_fwd(tape: *i64, vals: *i64, st: *i64, W: *i64, Xg: *i64, tgts: *i64, tgte: *i64, T: i64, useattn: i64, out: *i64, rtab: *i64) -> i64 {
123 st[0] = 0
124 st[1] = 0
125 let scale: i64 = nx_f32_div(TA_F32_ONE, nx_f32_sqrt(nx_i32_to_f32(RF_E)))
126 let nXg: i64 = ta_leaf(tape, vals, st, T, RF_E, Xg, 0)
127 let nWq: i64 = ta_leaf(tape, vals, st, RF_E, RF_E, W, FOFF_WQ)
128 let nWk: i64 = ta_leaf(tape, vals, st, RF_E, RF_E, W, FOFF_WK)
129 let nWv: i64 = ta_leaf(tape, vals, st, RF_E, RF_E, W, FOFF_WV)
130 let nWo: i64 = ta_leaf(tape, vals, st, RF_E, RF_E, W, FOFF_WO)
131 let nWg: i64 = ta_leaf(tape, vals, st, RF_E, RF_F, W, FOFF_WG)
132 let nWu: i64 = ta_leaf(tape, vals, st, RF_E, RF_F, W, FOFF_WU)
133 let nWd: i64 = ta_leaf(tape, vals, st, RF_F, RF_E, W, FOFF_WD)
134 let nUs: i64 = ta_leaf(tape, vals, st, 1, RF_E, W, FOFF_US)
135 let nUe: i64 = ta_leaf(tape, vals, st, 1, RF_E, W, FOFF_UE)
136 var nH: i64 = nXg
137 if useattn == 1 {
138 let nXn: i64 = ta_rmsnorm_rows(tape, vals, st, nXg)
139 let nQ: i64 = ta_matmul(tape, vals, st, nXn, nWq)
140 let nK: i64 = ta_matmul(tape, vals, st, nXn, nWk)
141 let nV: i64 = ta_matmul(tape, vals, st, nXn, nWv)
142 let nQr: i64 = ta_rope_tab(tape, vals, st, nQ, rtab)
143 let nKr: i64 = ta_rope_tab(tape, vals, st, nK, rtab)
144 let nS: i64 = ta_matmul_nt(tape, vals, st, nQr, nKr)
145 let nSs: i64 = ta_cmul(tape, vals, st, nS, scale)
146 let nA: i64 = ta_softmax_rows(tape, vals, st, nSs, RF_CAUSAL) // RF_CAUSAL=0 => BIDIRECTIONAL reader
147 let nO: i64 = ta_matmul(tape, vals, st, nA, nV)
148 let nOp: i64 = ta_matmul(tape, vals, st, nO, nWo)
149 nH = ta_vadd(tape, vals, st, nXg, nOp)
150 }
151 let nHn: i64 = ta_rmsnorm_rows(tape, vals, st, nH)
152 let nG: i64 = ta_matmul(tape, vals, st, nHn, nWg)
153 let nU2: i64 = ta_matmul(tape, vals, st, nHn, nWu)
154 let nSg: i64 = ta_silu(tape, vals, st, nG)
155 let nHs: i64 = ta_hadamard(tape, vals, st, nSg, nU2)
156 let nD: i64 = ta_matmul(tape, vals, st, nHs, nWd)
157 let nY: i64 = ta_vadd(tape, vals, st, nH, nD)
158 let nYn: i64 = ta_rmsnorm_rows(tape, vals, st, nY)
159 let nLs: i64 = ta_matmul_nt(tape, vals, st, nUs, nYn)
160 let nLe: i64 = ta_matmul_nt(tape, vals, st, nUe, nYn)
161 let nCs: i64 = ta_softce_rows(tape, vals, st, nLs, tgts)
162 let nCe: i64 = ta_softce_rows(tape, vals, st, nLe, tgte)
163 let nRoot: i64 = ta_vadd(tape, vals, st, nCs, nCe)
164 out[0] = nRoot
165 out[1] = nLs
166 out[2] = nLe
167 out[3] = nXg
168 out[4] = nWq
169 out[5] = nWk
170 out[6] = nWv
171 out[7] = nWo
172 out[8] = nWg
173 out[9] = nWu
174 out[10] = nWd
175 out[11] = nUs
176 out[12] = nUe
177 return 0
178}
179
180// accumulate grads into flat G (f32 adds). Dense weights by layout; embedding rows scattered by token id.
181func rf_grab(tape: *i64, grads: *i64, out: *i64, G: *i64, ids: *i64, T: i64) -> i64 {
182 let nXg: i64 = out[3]
183 let gx: i64 = tape[7*nXg+6]
184 var t: i64 = 0
185 while t < T {
186 let id: i64 = ids[t]
187 var e: i64 = 0
188 while e < RF_E { G[FOFF_EMB + id*RF_E + e] = nx_f32_add(G[FOFF_EMB + id*RF_E + e], grads[gx + t*RF_E + e]); e = e + 1 }
189 t = t + 1
190 }
191 var k: i64 = 0
192 while k < 9 {
193 var sz: i64 = 576
194 var of: i64 = 0
195 if k == 0 { of = FOFF_WQ }
196 if k == 1 { of = FOFF_WK }
197 if k == 2 { of = FOFF_WV }
198 if k == 3 { of = FOFF_WO }
199 if k == 4 { sz = 1152; of = FOFF_WG }
200 if k == 5 { sz = 1152; of = FOFF_WU }
201 if k == 6 { sz = 1152; of = FOFF_WD }
202 if k == 7 { sz = 24; of = FOFF_US }
203 if k == 8 { sz = 24; of = FOFF_UE }
204 let nid: i64 = out[4+k]
205 let goff: i64 = tape[7*nid+6]
206 var i: i64 = 0
207 while i < sz { G[of+i] = nx_f32_add(G[of+i], grads[goff+i]); i = i + 1 }
208 k = k + 1
209 }
210 return 0
211}
212
213// ---- data-parallel batch training (RF_PAR): one example per pool worker, private arenas ----
214struct RfCtx {
215 w_ptr: i64,
216 ids_ptr: i64,
217 tt: i64,
218 tape_ptr: i64,
219 vals_ptr: i64,
220 grads_ptr: i64,
221 st_ptr: i64,
222 xg_ptr: i64,
223 out_ptr: i64,
224 ge_ptr: i64,
225 rtab_ptr: i64,
226 useattn: i64,
227 tg_ptr: i64,
228 te_ptr: i64,
229 loss_ptr: i64,
230}
231const RF_CTX_BYTES: i64 = 120
232
233// pool worker: gather this example's embeddings, forward, backward, grab grads into its PRIVATE Ge, store loss.
234// Reads W + rtab (shared, read-only) and writes only its private arenas -> thread-safe (proven pattern).
235func rf_par_task(ctx_i: i64) -> i64 {
236 let c: *RfCtx = ctx_i as *RfCtx
237 let W: *i64 = c.w_ptr as *i64
238 let ids: *i64 = c.ids_ptr as *i64
239 let T: i64 = c.tt
240 let tape: *i64 = c.tape_ptr as *i64
241 let vals: *i64 = c.vals_ptr as *i64
242 let grads: *i64 = c.grads_ptr as *i64
243 let st: *i64 = c.st_ptr as *i64
244 let Xg: *i64 = c.xg_ptr as *i64
245 let out: *i64 = c.out_ptr as *i64
246 let Ge: *i64 = c.ge_ptr as *i64
247 let rtab: *i64 = c.rtab_ptr as *i64
248 let tgts: *i64 = c.tg_ptr as *i64
249 let tgte: *i64 = c.te_ptr as *i64
250 let loss: *i64 = c.loss_ptr as *i64
251 var t: i64 = 0
252 while t < T { var e: i64 = 0; while e < RF_E { Xg[t*RF_E+e] = W[FOFF_EMB + ids[t]*RF_E + e]; e = e + 1 } t = t + 1 }
253 rf_fwd(tape, vals, st, W, Xg, tgts, tgte, T, c.useattn, out, rtab)
254 loss[0] = ta_val(tape, vals, out[0], 0)
255 ta_backward(tape, vals, grads, st[0], out[0])
256 var z: i64 = 0
257 while z < RF_NP { Ge[z] = TA_F32_ZERO; z = z + 1 }
258 rf_grab(tape, grads, out, Ge, ids, T)
259 return 0
260}
261
262func rf_init(W: *i64) -> i64 {
263 var i: i64 = 0
264 while i < 576 { W[FOFF_WQ+i] = ta_constf((((i*13)%9)-4), 32); W[FOFF_WK+i] = ta_constf((((i*17)%9)-4), 32); W[FOFF_WV+i] = ta_constf((((i*19)%9)-4), 32); W[FOFF_WO+i] = ta_constf((((i*23)%9)-4), 32); i = i + 1 }
265 i = 0
266 while i < 1152 { W[FOFF_WG+i] = ta_constf((((i*29)%9)-4), 40); W[FOFF_WU+i] = ta_constf((((i*31)%9)-4), 40); W[FOFF_WD+i] = ta_constf((((i*37)%9)-4), 40); i = i + 1 }
267 i = 0
268 while i < 24 { W[FOFF_US+i] = ta_constf((((i*5+1)%7)-3), 8); W[FOFF_UE+i] = ta_constf((((i*11+2)%7)-3), 8); i = i + 1 }
269 return 0
270}
271
272func rf_span_f1(ids: *i64, a: i64, b: i64, gs: i64, ge: i64) -> i64 {
273 let pl: i64 = b - a + 1
274 let gl: i64 = ge - gs + 1
275 if pl <= 0 { return 0 }
276 if gl <= 0 { return 0 }
277 var common: i64 = 0
278 let used: *i64 = sys_mmap(RF_MAXG*8) as *i64
279 var u: i64 = 0
280 while u < gl { used[u] = 0; u = u + 1 }
281 var p: i64 = a
282 while p <= b {
283 var q2: i64 = 0
284 var got: i64 = 0
285 while q2 < gl {
286 if got == 0 { if used[q2] == 0 { if ids[gs+q2] == ids[p] { used[q2] = 1; common = common + 1; got = 1 } } }
287 q2 = q2 + 1
288 }
289 p = p + 1
290 }
291 if common == 0 { return 0 }
292 return (2*common*1000)/(pl+gl)
293}
294
295func rf_eval(tape: *i64, vals: *i64, st: *i64, W: *i64, dat: *i64, meta: *i64, r0: i64, r1: i64, useattn: i64, res: *i64, rtab: *i64) -> i64 {
296 let out: *i64 = sys_mmap(16*8) as *i64
297 let Xg: *i64 = sys_mmap(RF_MAXT*RF_E*8) as *i64
298 let tgts: *i64 = sys_mmap(8) as *i64
299 let tgte: *i64 = sys_mmap(8) as *i64
300 var f1sum: i64 = 0
301 var exact: i64 = 0
302 var n: i64 = 0
303 var r: i64 = r0
304 while r < r1 {
305 let T: i64 = meta[r*4+0]
306 let qn: i64 = meta[r*4+1]
307 let gs: i64 = meta[r*4+2]
308 let ge: i64 = meta[r*4+3]
309 let ids: *i64 = (dat as i64 + r*RF_MAXT*8) as *i64
310 var t: i64 = 0
311 while t < T { var e: i64 = 0; while e < RF_E { Xg[t*RF_E+e] = W[FOFF_EMB + ids[t]*RF_E + e]; e = e + 1 } t = t + 1 }
312 tgts[0] = gs
313 tgte[0] = ge
314 rf_fwd(tape, vals, st, W, Xg, tgts, tgte, T, useattn, out, rtab)
315 let nLs: i64 = out[1]
316 let nLe: i64 = out[2]
317 var s: i64 = qn + 1
318 var bv: i64 = ta_val(tape, vals, nLs, qn+1)
319 var j: i64 = qn + 2
320 while j < T { let v: i64 = ta_val(tape, vals, nLs, j); if nx_f32_gt(v, bv) == 1 { bv = v; s = j } j = j + 1 }
321 var en: i64 = s
322 var ev: i64 = ta_val(tape, vals, nLe, s)
323 var lim: i64 = s + RF_MAXG
324 if lim > T { lim = T }
325 j = s + 1
326 while j < lim { let v2: i64 = ta_val(tape, vals, nLe, j); if nx_f32_gt(v2, ev) == 1 { ev = v2; en = j } j = j + 1 }
327 f1sum = f1sum + rf_span_f1(ids, s, en, gs, ge)
328 if s == gs { exact = exact + 1 }
329 n = n + 1
330 r = r + 1
331 }
332 if n == 0 { res[0] = 0; res[1] = 0; return 0 }
333 res[0] = f1sum / n
334 res[1] = exact * 1000 / n
335 return 0
336}
337
338// ---- CRASH-TOLERANT CHECKPOINTING (the box gets VM-restarted by sibling sessions; per-epoch checkpoints make
339// any interruption cost <=1 epoch and progress accumulate monotonically). Layout (i64 cells):
340// ck[0]=magic (20262), ck[1]=reader epochs done, ck[2]=ablation epochs done, ck[3]=nw,
341// ck[4]=reader FIRST-epoch loss milli, ck[5]=reader LAST-epoch loss milli (T3 survives resume),
342// ck[6..6+NP) = W (reader), ck[6+NP..6+2NP) = W2 (ablation). W/W2 point INTO ck -> flush = one write. ----
343const RF_CKMAGIC: i64 = 20262
344const RF_CKCELLS: i64 = 6 + RF_NP + RF_NP
345
346func rf_ck_flush(ck: *i64) -> i64 {
347 // ATOMIC checkpoint: write .part, then rename over the live file. A VM kill mid-write (the box gets
348 // sibling-restarted ~15min) must never leave a TORN checkpoint -- a torn one resumes into garbage weights
349 // and trains on silently. rename on the same fs is atomic => the live ckpt is always old-complete or
350 // new-complete, never partial.
351 let fd: i64 = sys_openat_wr(rf_ck_part_path(), 0x1a4)
352 if fd < 0 { return 0 }
353 let nb: i64 = RF_CKCELLS * 8
354 var w: i64 = 0
355 while w < nb { let x: i64 = sys_write(fd, (ck as i64 + w) as *u8, nb - w); if x <= 0 { w = nb } else { w = w + x } }
356 sys_close(fd)
357 if w < nb { return 0 }
358 sys_renameat(rf_ck_part_path(), rf_ck_path())
359 return 1
360}
361
362func rf_ck_load(ck: *i64, nw: i64) -> i64 {
363 let fd: i64 = sys_openat_rd(rf_ck_path())
364 if fd < 0 { return 0 }
365 let nb: i64 = RF_CKCELLS * 8
366 var got: i64 = 0
367 var r: i64 = 1
368 while r > 0 { if got >= nb { r = 0 } else { r = sys_read(fd, (ck as i64 + got) as *u8, nb - got); if r > 0 { got = got + r } } }
369 sys_close(fd)
370 if got < nb { return 0 }
371 if ck[0] != RF_CKMAGIC { return 0 }
372 if ck[3] != nw { return 0 }
373 return 1
374}
375
376// train from start-epoch ep0 (checkpoint-resume); saves the checkpoint after EVERY epoch (ckslot 1=reader,
377// 2=ablation). res0[0]=final-epoch mean loss milli, res0[1]=first-SEEN-epoch mean (for the fall test).
378func rf_train(tape: *i64, vals: *i64, grads: *i64, st: *i64, W: *i64, dat: *i64, meta: *i64, ntrain: i64, useattn: i64, EP: i64, res0: *i64, ck: *i64, ckslot: i64, ep0: i64, rtab: *i64) -> i64 {
379 let out: *i64 = sys_mmap(16*8) as *i64
380 let Xg: *i64 = sys_mmap(RF_MAXT*RF_E*8) as *i64
381 let tgts: *i64 = sys_mmap(8) as *i64
382 let tgte: *i64 = sys_mmap(8) as *i64
383 let G: *i64 = sys_mmap(RF_NP*8) as *i64
384 let lr0: i64 = ta_constf(1, 32) // 0.03125 = R3a's proven rate
385 let clip: i64 = nx_i32_to_f32(4)
386 let nclip: i64 = nx_f32_neg(clip)
387 let inv8: i64 = ta_constf(1, 8)
388 // RF_PAR: pool + RF_BATCH private per-example arena sets (allocated ONCE, reused across epochs/batches)
389 var pool: *NxThreadPool = 0 as *NxThreadPool
390 let ptapes: *i64 = sys_mmap(RF_BATCH*4096*7*8) as *i64
391 let pvals: *i64 = sys_mmap(RF_BATCH*262144*8) as *i64
392 let pgrads: *i64 = sys_mmap(RF_BATCH*262144*8) as *i64
393 let psts: *i64 = sys_mmap(RF_BATCH*2*8) as *i64
394 let pxgs: *i64 = sys_mmap(RF_BATCH*RF_MAXT*RF_E*8) as *i64
395 let pouts: *i64 = sys_mmap(RF_BATCH*16*8) as *i64
396 let pges: *i64 = sys_mmap(RF_BATCH*RF_NP*8) as *i64
397 let plosses: *i64 = sys_mmap(RF_BATCH*8) as *i64
398 let ptg: *i64 = sys_mmap(RF_BATCH*2*8) as *i64
399 let pctxs: *u8 = sys_mmap(RF_BATCH*RF_CTX_BYTES)
400 if RF_PAR == 1 { pool = nx_pool_new(0, 0) }
401 var first: i64 = 1
402 var ep: i64 = ep0
403 while ep < EP {
404 var lsum: i64 = TA_F32_ZERO
405 var nb: i64 = 0
406 var r: i64 = 0
407 while r + 8 <= ntrain {
408 var z: i64 = 0
409 while z < RF_NP { G[z] = TA_F32_ZERO; z = z + 1 }
410 if RF_PAR == 1 {
411 // ---- PARALLEL: submit RF_BATCH examples to the pool, each on private arenas ----
412 let db: i64 = nx_pool_n_completed(pool)
413 var mb: i64 = 0
414 while mb < RF_BATCH {
415 let rr: i64 = r + mb
416 ptg[mb*2] = meta[rr*4+2]
417 ptg[mb*2+1] = meta[rr*4+3]
418 let cx: *RfCtx = ((pctxs as i64) + mb*RF_CTX_BYTES) as *RfCtx
419 cx.w_ptr = W as i64
420 cx.ids_ptr = (dat as i64 + rr*RF_MAXT*8)
421 cx.tt = meta[rr*4+0]
422 cx.tape_ptr = (ptapes as i64 + mb*4096*7*8)
423 cx.vals_ptr = (pvals as i64 + mb*262144*8)
424 cx.grads_ptr = (pgrads as i64 + mb*262144*8)
425 cx.st_ptr = (psts as i64 + mb*2*8)
426 cx.xg_ptr = (pxgs as i64 + mb*RF_MAXT*RF_E*8)
427 cx.out_ptr = (pouts as i64 + mb*16*8)
428 cx.ge_ptr = (pges as i64 + mb*RF_NP*8)
429 cx.rtab_ptr = rtab as i64
430 cx.useattn = useattn
431 cx.tg_ptr = (ptg as i64 + mb*2*8)
432 cx.te_ptr = (ptg as i64 + (mb*2+1)*8)
433 cx.loss_ptr = (plosses as i64 + mb*8)
434 nx_pool_submit(pool, rf_par_task, cx as i64)
435 mb = mb + 1
436 }
437 nx_pool_wait(pool, db + RF_BATCH)
438 // reduce per-example grads (mb order = bit-identical to serial) + sum losses
439 mb = 0
440 while mb < RF_BATCH {
441 let Ge: *i64 = (pges as i64 + mb*RF_NP*8) as *i64
442 var zz: i64 = 0
443 while zz < RF_NP { G[zz] = nx_f32_add(G[zz], Ge[zz]); zz = zz + 1 }
444 lsum = nx_f32_add(lsum, plosses[mb])
445 mb = mb + 1
446 }
447 } else {
448 var mb: i64 = 0
449 while mb < RF_BATCH {
450 let rr: i64 = r + mb
451 let T: i64 = meta[rr*4+0]
452 let gs: i64 = meta[rr*4+2]
453 let ge: i64 = meta[rr*4+3]
454 let ids: *i64 = (dat as i64 + rr*RF_MAXT*8) as *i64
455 var t: i64 = 0
456 while t < T { var e: i64 = 0; while e < RF_E { Xg[t*RF_E+e] = W[FOFF_EMB + ids[t]*RF_E + e]; e = e + 1 } t = t + 1 }
457 tgts[0] = gs
458 tgte[0] = ge
459 rf_fwd(tape, vals, st, W, Xg, tgts, tgte, T, useattn, out, rtab)
460 let nRoot: i64 = out[0]
461 lsum = nx_f32_add(lsum, ta_val(tape, vals, nRoot, 0))
462 ta_backward(tape, vals, grads, st[0], nRoot)
463 rf_grab(tape, grads, out, G, ids, T)
464 mb = mb + 1
465 }
466 }
467 // decay: small=24/40 (48-ep schedule); XL=8/12 (16-ep, 7x more data/epoch converges faster)
468 var d1: i64 = 24
469 var d2: i64 = 40
470 if RF_XL == 1 { d1 = 8; d2 = 12 }
471 var elr: i64 = lr0
472 if ep >= d1 { elr = nx_f32_mul(lr0, ta_constf(1, 2)) }
473 if ep >= d2 { elr = nx_f32_mul(lr0, ta_constf(1, 4)) }
474 var w: i64 = 0
475 while w < RF_NP {
476 var gv: i64 = nx_f32_mul(G[w], inv8)
477 if nx_f32_gt(gv, clip) == 1 { gv = clip }
478 if nx_f32_lt(gv, nclip) == 1 { gv = nclip }
479 W[w] = nx_f32_sub(W[w], nx_f32_mul(elr, gv))
480 w = w + 1
481 }
482 nb = nb + 1
483 r = r + 8
484 }
485 let mean: i64 = nx_f32_div(lsum, nx_i32_to_f32(nb*8))
486 let mm: i64 = ta_f32_to_milli(mean)
487 if first == 1 { res0[1] = mm; first = 0 }
488 res0[0] = mm
489 rf_puts(" epoch "); rf_pn(ep); rf_puts(" mean_loss_milli="); rf_pn(mm); rf_puts("\n" as *u8)
490 if ckslot == 1 { if ep == 0 { ck[4] = mm } ck[5] = mm }
491 ck[ckslot] = ep + 1
492 rf_ck_flush(ck)
493 ep = ep + 1
494 }
495 return 0
496}
497
498func main() -> i64 {
499 rf_puts("nx_reader_squad_f32_gate (R3e: TRAIN-ON-F32 -- same reader, ta_* tensor autograd; Q16 collapse trap does not exist here)\n" as *u8)
500 var pass: i64 = 0
501 var total: i64 = 0
502
503 let fd: i64 = sys_openat_rd(rf_rows_path())
504 if fd < 0 { rf_puts("RED -- reader rows file missing (run: nx_qabench dt / dx)\n" as *u8); return 1 }
505 let cap: i64 = 16777216
506 let raw: *u8 = sys_mmap(cap)
507 var got: i64 = 0
508 var rr2: i64 = 1
509 while rr2 > 0 { rr2 = sys_read(fd, (raw as i64 + got) as *u8, cap - got); if rr2 > 0 { got = got + rr2 } }
510 sys_close(fd)
511 if got < 16 { rf_puts("RED -- reader_rows.bin empty\n" as *u8); return 1 }
512
513 let pfd: i64 = sys_openat_rd("knowledge/index/semppmi_v1.bin" as *u8)
514 if pfd < 0 { rf_puts("RED -- semppmi_v1.bin missing\n" as *u8); return 1 }
515 let pcap: i64 = 2097152
516 let pblob: *u8 = sys_mmap(pcap)
517 var pgot: i64 = 0
518 var pr: i64 = 1
519 while pr > 0 { if pgot >= pcap { pr = 0 } else { pr = sys_read(pfd, (pblob as i64 + pgot) as *u8, pcap - pgot); if pr > 0 { pgot = pgot + pr } } }
520 sys_close(pfd)
521 let phi: *i64 = (pblob as i64 + 8) as *i64
522 let nv: i64 = phi[0]
523 if pgot < 32 + nv*8 { rf_puts("RED -- semppmi vh truncated\n" as *u8); return 1 }
524 let vh: *i64 = (pblob as i64 + 32) as *i64
525 let efd: i64 = sys_openat_rd("knowledge/index/embed_v1.bin" as *u8)
526 if efd < 0 { rf_puts("RED -- embed_v1.bin missing\n" as *u8); return 1 }
527 let ecap: i64 = 67108864
528 let eblob: *u8 = sys_mmap(ecap)
529 var egot: i64 = 0
530 var er: i64 = 1
531 while er > 0 { if egot >= ecap { er = 0 } else { er = sys_read(efd, (eblob as i64 + egot) as *u8, ecap - egot); if er > 0 { egot = egot + er } } }
532 sys_close(efd)
533 let ehi: *i64 = (eblob as i64 + 8) as *i64
534 let env: i64 = ehi[0]
535 let edim: i64 = ehi[1]
536 if edim != RF_E { rf_puts("RED -- embed dim mismatch\n" as *u8); return 1 }
537 if env != nv { rf_puts("RED -- embed/vocab nv mismatch\n" as *u8); return 1 }
538 let EQ: *i64 = (eblob as i64 + 24) as *i64
539 rf_puts(" SGNS loaded: vocab nv="); rf_pn(nv); rf_puts(" dim="); rf_pn(edim); rf_puts("\n" as *u8)
540
541 let dat: *i64 = sys_mmap(RF_NROWS*RF_MAXT*8) as *i64
542 let meta: *i64 = sys_mmap(RF_NROWS*4*8) as *i64
543 let qh: *i64 = sys_mmap(64*8) as *i64
544 let ch: *i64 = sys_mmap(4096*8) as *i64
545 let gh: *i64 = sys_mmap(64*8) as *i64
546 let vhash: *i64 = sys_mmap(RF_MAXV*8) as *i64
547 let vmap: *i64 = sys_mmap(RF_MAPN*8) as *i64
548 let vst: *i64 = sys_mmap(8) as *i64
549 vst[0] = 0
550 var nrows: i64 = 0
551 var off: i64 = 8
552 var scanned: i64 = 0
553 while off + 24 < got {
554 if nrows >= RF_NROWS { off = got } else {
555 let hp: *i64 = (raw as i64 + off) as *i64
556 let qlen: i64 = hp[0]
557 if qlen < 0 { off = got } else { if qlen > 4000 { off = got } else {
558 let qp: *u8 = (raw as i64 + off + 8) as *u8
559 let hp2: *i64 = (raw as i64 + off + 8 + qlen) as *i64
560 let clen: i64 = hp2[0]
561 let cp: *u8 = (raw as i64 + off + 16 + qlen) as *u8
562 let hp3: *i64 = (raw as i64 + off + 16 + qlen + clen) as *i64
563 let alen: i64 = hp3[0]
564 let ap: *u8 = (raw as i64 + off + 24 + qlen + clen) as *u8
565 off = off + 24 + qlen + clen + alen
566 scanned = scanned + 1
567 var qn: i64 = rf_tok(qp, qlen, qh, RF_MAXQ)
568 let cn0: i64 = rf_tok(cp, clen, ch, 4096)
569 let gn: i64 = rf_tok(ap, alen, gh, RF_MAXG)
570 var cn: i64 = RF_MAXT - qn - 1
571 if cn > cn0 { cn = cn0 }
572 if qn >= 3 { if gn >= 1 { if cn >= 8 {
573 var gs: i64 = 0-1
574 var c: i64 = 0
575 while c + gn <= cn {
576 if gs < 0 {
577 var m: i64 = 1
578 var k: i64 = 0
579 while k < gn { if ch[c+k] != gh[k] { m = 0; k = gn } else { k = k + 1 } }
580 if m == 1 { gs = c }
581 }
582 c = c + 1
583 }
584 if gs >= 0 {
585 let T: i64 = qn + 1 + cn
586 let ids: *i64 = (dat as i64 + nrows*RF_MAXT*8) as *i64
587 var t: i64 = 0
588 while t < qn { let lid: i64 = rf_vid(vmap, vhash, vst, qh[t]); ids[t] = lid; t = t + 1 }
589 ids[qn] = 0
590 t = 0
591 while t < cn { let lid2: i64 = rf_vid(vmap, vhash, vst, ch[t]); ids[qn+1+t] = lid2; t = t + 1 }
592 meta[nrows*4+0] = T
593 meta[nrows*4+1] = qn
594 meta[nrows*4+2] = qn + 1 + gs
595 meta[nrows*4+3] = qn + 1 + gs + gn - 1
596 nrows = nrows + 1
597 }
598 } } }
599 } }
600 }
601 }
602 let nw: i64 = vst[0]
603 rf_puts(" scanned="); rf_pn(scanned); rf_puts(" usable="); rf_pn(nrows); rf_puts(" vocab nw="); rf_pn(nw); rf_puts("\n" as *u8)
604 if nrows < 200 { rf_puts("RED -- too few usable rows\n" as *u8); return 1 }
605 var ntrain: i64 = (nrows * 4) / 5
606 rf_puts(" train="); rf_pn(ntrain); rf_puts(" held-out="); rf_pn(nrows - ntrain); rf_puts("\n" as *u8)
607
608 // ---- checkpoint buffer: W/W2 live INSIDE it; resume if a valid checkpoint exists ----
609 let ck: *i64 = sys_mmap(RF_CKCELLS*8) as *i64
610 let W: *i64 = (ck as i64 + 6*8) as *i64
611 let W2: *i64 = (ck as i64 + (6 + RF_NP)*8) as *i64
612 let resumed: i64 = rf_ck_load(ck, nw)
613 if resumed == 1 {
614 rf_puts(" CHECKPOINT RESUMED: reader epochs done="); rf_pn(ck[1]); rf_puts(" ablation done="); rf_pn(ck[2]); rf_puts("\n" as *u8)
615 } else {
616 ck[0] = RF_CKMAGIC
617 ck[1] = 0
618 ck[2] = 0
619 ck[3] = nw
620 ck[4] = 0
621 ck[5] = 0
622 // embeddings: SGNS Q10 -> f32 RAW magnitude (f32 has no absorbing trap; true init)
623 let q10: i64 = nx_i32_to_f32(1024)
624 var hits: i64 = 0
625 var wv: i64 = 1
626 while wv <= nw {
627 let r3: i64 = rf_bsearch(vh, nv, vhash[wv])
628 if r3 >= 0 {
629 var e2: i64 = 0
630 while e2 < RF_E { W[FOFF_EMB + wv*RF_E + e2] = nx_f32_div(nx_i32_to_f32(EQ[r3*RF_E + e2]), q10); e2 = e2 + 1 }
631 hits = hits + 1
632 } else {
633 var e3: i64 = 0
634 while e3 < RF_E { W[FOFF_EMB + wv*RF_E + e3] = ta_constf((((wv*7+e3*3)%11)-5), 16); e3 = e3 + 1 }
635 }
636 wv = wv + 1
637 }
638 var e4: i64 = 0
639 while e4 < RF_E { W[FOFF_EMB + e4] = ta_constf((((e4*5+2)%9)-4), 12); e4 = e4 + 1 }
640 rf_puts(" SGNS coverage: "); rf_pn(hits); rf_puts("/"); rf_pn(nw); rf_puts("\n" as *u8)
641 rf_init(W)
642 var cw: i64 = 0
643 while cw < RF_NP { W2[cw] = W[cw]; cw = cw + 1 }
644 rf_init(W2)
645 rf_ck_flush(ck)
646 }
647
648 let tape: *i64 = sys_mmap(4096*7*8) as *i64
649 let vals: *i64 = sys_mmap(262144*8) as *i64
650 let grads: *i64 = sys_mmap(262144*8) as *i64
651 let st: *i64 = sys_mmap(2*8) as *i64
652 var EP: i64 = 48 // small: 48-ep (664 rows undertrained at 12). XL: 16-ep (4771 rows, 7x more
653 if RF_XL == 1 { EP = 16 } // examples/epoch -> converges in fewer epochs; checkpoint lets us stop early.
654 // RoPE table: ONE build (sin/cos mmap per call; 96*12*2 calls once = fine, per-element in the loop = OOM)
655 let rtab: *i64 = sys_mmap((2 + 2*RF_MAXT*(RF_E/2))*8) as *i64
656 ta_rope_build_tab(rtab, RF_MAXT, RF_E/2)
657 rf_puts(" RoPE table built ("); rf_pn(RF_MAXT); rf_puts("x"); rf_pn(RF_E/2); rf_puts(")\n" as *u8)
658
659 rf_puts(" training READER (f32, SGNS init, R3a recipe; checkpointed per epoch)...\n" as *u8)
660 let resL: *i64 = sys_mmap(2*8) as *i64
661 resL[1] = 0
662 if ck[1] < EP { rf_train(tape, vals, grads, st, W, dat, meta, ntrain, 1, EP, resL, ck, 1, ck[1], rtab) }
663 let resA: *i64 = sys_mmap(2*8) as *i64
664 rf_eval(tape, vals, st, W, dat, meta, ntrain, nrows, 1, resA, rtab)
665 rf_puts(" READER held-out: span-F1="); rf_pn(resA[0]); rf_puts(" exact-start="); rf_pn(resA[1]); rf_puts(" permille\n" as *u8)
666
667 rf_puts(" training ABLATION (question-blind, same everything; checkpointed)...\n" as *u8)
668 let resL2: *i64 = sys_mmap(2*8) as *i64
669 if ck[2] < EP { rf_train(tape, vals, grads, st, W2, dat, meta, ntrain, 0, EP, resL2, ck, 2, ck[2], rtab) }
670 let resB: *i64 = sys_mmap(2*8) as *i64
671 rf_eval(tape, vals, st, W2, dat, meta, ntrain, nrows, 0, resB, rtab)
672 rf_puts(" ABLATION held-out: span-F1="); rf_pn(resB[0]); rf_puts(" exact-start="); rf_pn(resB[1]); rf_puts(" permille\n" as *u8)
673
674 total = total + 1
675 if resA[0] > resB[0] + 100 { pass = pass + 1; rf_ck("T1 reader beats question-blind ablation by >100 F1 (liar-kill)" as *u8, 1) } else { rf_ck("T1 reader beats question-blind ablation by >100 F1 (liar-kill)" as *u8, 0) }
676 total = total + 1
677 if resA[1] > 60 { pass = pass + 1; rf_ck("T2 reader exact-start > 60 permille" as *u8, 1) } else { rf_ck("T2 reader exact-start > 60 permille" as *u8, 0) }
678 total = total + 1
679 var t3: i64 = 0
680 if ck[4] > 0 { if ck[5]*10 < ck[4]*6 { t3 = 1 } } // first vs last reader-epoch loss FROM THE CHECKPOINT (resume-safe)
681 if t3 == 1 { pass = pass + 1; rf_ck("T3 train loss falls >40% (no collapse)" as *u8, 1) } else { rf_ck("T3 train loss falls >40% (no collapse)" as *u8, 0) }
682
683 let resC: *i64 = sys_mmap(2*8) as *i64
684 rf_eval(tape, vals, st, W, dat, meta, ntrain, nrows, 1, resC, rtab)
685 total = total + 1
686 var t4: i64 = 0
687 if resC[0] == resA[0] { if resC[1] == resA[1] { t4 = 1 } }
688 if t4 == 1 { pass = pass + 1; rf_ck("T4 deterministic re-eval" as *u8, 1) } else { rf_ck("T4 deterministic re-eval" as *u8, 0) }
689
690 let pf: i64 = sys_openat_wr(rf_persist_path(), 0x1a4)
691 if pf >= 0 {
692 let mg: *i64 = sys_mmap(32) as *i64
693 let mgb: *u8 = mg as *u8
694 mgb[0]=78 as u8; mgb[1]=88 as u8; mgb[2]=78 as u8; mgb[3]=82 as u8; mgb[4]=51 as u8; mgb[5]=0 as u8; mgb[6]=0 as u8; mgb[7]=0 as u8
695 mg[1] = nw
696 mg[2] = RF_E
697 mg[3] = RF_F
698 sys_write(pf, mg as *u8, 32)
699 sys_write(pf, W as *u8, RF_NP*8)
700 sys_close(pf)
701 rf_puts(" persisted trained f32 reader -> knowledge/index/reader_neural_f32.bin (NXNR3)\n" as *u8)
702 }
703
704 rf_puts("---- nx_reader_squad_f32_gate: passed "); rf_pn(pass); rf_puts(" / "); rf_pn(total); rf_puts("\n" as *u8)
705 if pass == total { rf_puts("READER R3e GREEN -- the f32-trained attention reader LEARNS + GENERALIZES on real SQuAD where the question-blind reader cannot; quantize-after is next.\n" as *u8); return 0 }
706 rf_puts("RED -- R3e not fully passed (see numbers)\n" as *u8)
707 return 1
708}