code wiki / (root) / nx_reader_quantize_gate.nx

nx_reader_quantize_gate.nx source

↩ module page · 387 lines · 19301 B

1// nx_reader_quantize_gate.nx -- R4 of the neural-reader arc: QUANTIZE-AFTER. Takes the f32-TRAINED reader 2// (reader_neural_f32*.bin, our own from-scratch model), quantizes its weights to Q16, and runs PURE-INTEGER 3// (nfa_*) inference -- the train-float / infer-int split, completed for a SOVEREIGN-TRAINED model. Proves the 4// no-float reader is FAITHFUL to the f32 model by running BOTH forwards on the same real held-out SQuAD split 5// and comparing span predictions + gold-F1. (The nfa_* Q16 forward has NO collapse risk -- collapse was a 6// TRAINING dynamics artifact; inference of trained weights is exact-enough in Q16.) 7// T1 no-float (Q16) held-out span-F1 within 60 permille of the f32 reader's F1 (quantization faithful) 8// T2 Q16-vs-f32 span-prediction AGREEMENT > 800 permille (same model, integer vs float) 9// T3 the Q16 path is PURE INTEGER (structural: only nfa_* Q16 ops, zero nx_f32 in the inference) 10// T4 deterministic 11// Consumes: reader_neural_f32.bin (f32 W), semppmi_v1.bin (vocab hashes), reader_rows.bin (same rows/vocab as 12// training so token ids address the trained embedding rows). expect_exit: 0 license_tier: ORIGINAL 13import "nx_autograd_tensor.nx" // ta_* f32 forward (reference) 14import "nx_nofloat_autograd.nx" // nfa_* Q16 forward (the no-float inference) 15import "nx_syscalls.nx" 16 17func qz_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 qz_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 qz_ck(name: *u8, c: i64) -> i64 { if c==1 { qz_puts(" PASS " as *u8) } else { qz_puts(" FAIL " as *u8) } qz_puts(name); qz_puts("\n" as *u8); return c } 20 21const QZ_E: i64 = 24 22const QZ_F: i64 = 48 23const QZ_MAXT: i64 = 96 24const QZ_MAXQ: i64 = 20 25const QZ_MAXG: i64 = 8 26const QZ_NROWS: i64 = 1200 27const QZ_MAXV: i64 = 16384 28const QZ_MAPN: i64 = 32768 29const QOFF_EMB: i64 = 0 30const QOFF_WQ: i64 = 393216 31const QOFF_WK: i64 = 393792 32const QOFF_WV: i64 = 394368 33const QOFF_WO: i64 = 394944 34const QOFF_WG: i64 = 395520 35const QOFF_WU: i64 = 396672 36const QOFF_WD: i64 = 397824 37const QOFF_US: i64 = 398976 38const QOFF_UE: i64 = 399000 39const QZ_NP: i64 = 399024 40const QZ_SCALE_Q16: i64 = 13378 // 1/sqrt(24) in Q16 (matches nfa) 41 42// ---- vocab hashing + tokenizer (deterministic; MUST match the trainer so ids address trained embed rows) ---- 43func qz_ehash(buf: *u8, off: i64, len: i64) -> i64 { 44 var h1: i64 = 5381 45 var h2: i64 = 77245 46 var i: i64 = 0 47 while i < len { let c: i64 = buf[off+i] as i64; h1 = (h1*33 + c) % 1073741789; h2 = (h2*131 + c) % 1073741783; i = i + 1 } 48 return h1 * 1073741783 + h2 49} 50func qz_bsearch(a: *i64, n: i64, v: i64) -> i64 { 51 var lo: i64 = 0 52 var hi: i64 = n - 1 53 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 } } 54 return 0-1 55} 56func qz_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c } 57func qz_isal(c: i64) -> i64 { if c >= 97 { if c <= 122 { return 1 } } if c >= 48 { if c <= 57 { return 1 } } return 0 } 58func qz_tok(buf: *u8, n: i64, hout: *i64, cap: i64) -> i64 { 59 let wb: *u8 = sys_mmap(64) 60 var nt: i64 = 0 61 var i: i64 = 0 62 while i < n { 63 let c: i64 = qz_lc(buf[i] as i64) 64 if qz_isal(c) == 1 { 65 var wl: i64 = 0 66 var j: i64 = i 67 var live: i64 = 1 68 while live == 1 { 69 if j >= n { live = 0 } else { 70 let cj: i64 = qz_lc(buf[j] as i64) 71 if qz_isal(cj) == 0 { live = 0 } else { if wl < 48 { wb[wl] = cj as u8; wl = wl + 1 } j = j + 1 } 72 } 73 } 74 if nt < cap { hout[nt] = qz_ehash(wb, 0, wl); nt = nt + 1 } 75 i = j 76 } else { i = i + 1 } 77 } 78 return nt 79} 80func qz_vid(map: *i64, vhash: *i64, vst: *i64, h: i64) -> i64 { 81 var slot: i64 = h & (QZ_MAPN - 1) 82 if slot < 0 { slot = 0 - slot } 83 var probe: i64 = 0 84 while probe < QZ_MAPN { 85 let e: i64 = map[slot] 86 if e == 0 { if vst[0] >= QZ_MAXV - 1 { return 1 } vst[0] = vst[0] + 1; let id: i64 = vst[0]; vhash[id] = h; map[slot] = id; return id } 87 if vhash[e] == h { return e } 88 slot = (slot + 1) & (QZ_MAPN - 1) 89 probe = probe + 1 90 } 91 return 1 92} 93 94// ---- f32 inference forward: fills logit arrays ls[T], le[T] (f32 raws). ---- 95func qz_fwd_f32(tape: *i64, vals: *i64, st: *i64, W: *i64, Xg: *i64, T: i64, rtab: *i64, ls: *i64, le: *i64) -> i64 { 96 st[0] = 0 97 st[1] = 0 98 let scale: i64 = nx_f32_div(TA_F32_ONE, nx_f32_sqrt(nx_i32_to_f32(QZ_E))) 99 let nXg: i64 = ta_leaf(tape, vals, st, T, QZ_E, Xg, 0) 100 let nWq: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WQ) 101 let nWk: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WK) 102 let nWv: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WV) 103 let nWo: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WO) 104 let nWg: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_F, W, QOFF_WG) 105 let nWu: i64 = ta_leaf(tape, vals, st, QZ_E, QZ_F, W, QOFF_WU) 106 let nWd: i64 = ta_leaf(tape, vals, st, QZ_F, QZ_E, W, QOFF_WD) 107 let nUs: i64 = ta_leaf(tape, vals, st, 1, QZ_E, W, QOFF_US) 108 let nUe: i64 = ta_leaf(tape, vals, st, 1, QZ_E, W, QOFF_UE) 109 let nXn: i64 = ta_rmsnorm_rows(tape, vals, st, nXg) 110 let nQ: i64 = ta_matmul(tape, vals, st, nXn, nWq) 111 let nK: i64 = ta_matmul(tape, vals, st, nXn, nWk) 112 let nV: i64 = ta_matmul(tape, vals, st, nXn, nWv) 113 let nQr: i64 = ta_rope_tab(tape, vals, st, nQ, rtab) 114 let nKr: i64 = ta_rope_tab(tape, vals, st, nK, rtab) 115 let nS: i64 = ta_matmul_nt(tape, vals, st, nQr, nKr) 116 let nSs: i64 = ta_cmul(tape, vals, st, nS, scale) 117 let nA: i64 = ta_softmax_rows(tape, vals, st, nSs, 1) 118 let nO: i64 = ta_matmul(tape, vals, st, nA, nV) 119 let nOp: i64 = ta_matmul(tape, vals, st, nO, nWo) 120 let nH: i64 = ta_vadd(tape, vals, st, nXg, nOp) 121 let nHn: i64 = ta_rmsnorm_rows(tape, vals, st, nH) 122 let nG: i64 = ta_matmul(tape, vals, st, nHn, nWg) 123 let nU2: i64 = ta_matmul(tape, vals, st, nHn, nWu) 124 let nSg: i64 = ta_silu(tape, vals, st, nG) 125 let nHs: i64 = ta_hadamard(tape, vals, st, nSg, nU2) 126 let nD: i64 = ta_matmul(tape, vals, st, nHs, nWd) 127 let nY: i64 = ta_vadd(tape, vals, st, nH, nD) 128 let nYn: i64 = ta_rmsnorm_rows(tape, vals, st, nY) 129 let nLs: i64 = ta_matmul_nt(tape, vals, st, nUs, nYn) 130 let nLe: i64 = ta_matmul_nt(tape, vals, st, nUe, nYn) 131 var t: i64 = 0 132 while t < T { ls[t] = ta_val(tape, vals, nLs, t); le[t] = ta_val(tape, vals, nLe, t); t = t + 1 } 133 return 0 134} 135 136// ---- Q16 (no-float) inference forward: SAME architecture on nfa_*; fills ls[T], le[T] (Q16 ints). ---- 137func qz_fwd_q16(tape: *i64, vals: *i64, st: *i64, W: *i64, Xg: *i64, T: i64, ls: *i64, le: *i64) -> i64 { 138 st[0] = 0 139 st[1] = 0 140 let nXg: i64 = nfa_leaf(tape, vals, st, T, QZ_E, Xg, 0) 141 let nWq: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WQ) 142 let nWk: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WK) 143 let nWv: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WV) 144 let nWo: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_E, W, QOFF_WO) 145 let nWg: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_F, W, QOFF_WG) 146 let nWu: i64 = nfa_leaf(tape, vals, st, QZ_E, QZ_F, W, QOFF_WU) 147 let nWd: i64 = nfa_leaf(tape, vals, st, QZ_F, QZ_E, W, QOFF_WD) 148 let nUs: i64 = nfa_leaf(tape, vals, st, 1, QZ_E, W, QOFF_US) 149 let nUe: i64 = nfa_leaf(tape, vals, st, 1, QZ_E, W, QOFF_UE) 150 let nXn: i64 = nfa_rmsnorm_rows(tape, vals, st, nXg) 151 let nQ: i64 = nfa_matmul(tape, vals, st, nXn, nWq) 152 let nK: i64 = nfa_matmul(tape, vals, st, nXn, nWk) 153 let nV: i64 = nfa_matmul(tape, vals, st, nXn, nWv) 154 let nQr: i64 = nfa_rope(tape, vals, st, nQ) 155 let nKr: i64 = nfa_rope(tape, vals, st, nK) 156 let nS: i64 = nfa_matmul_nt(tape, vals, st, nQr, nKr) 157 let nSs: i64 = nfa_cmul(tape, vals, st, nS, QZ_SCALE_Q16) 158 let nA: i64 = nfa_softmax_rows(tape, vals, st, nSs, 1) 159 let nO: i64 = nfa_matmul(tape, vals, st, nA, nV) 160 let nOp: i64 = nfa_matmul(tape, vals, st, nO, nWo) 161 let nH: i64 = nfa_vadd(tape, vals, st, nXg, nOp) 162 let nHn: i64 = nfa_rmsnorm_rows(tape, vals, st, nH) 163 let nG: i64 = nfa_matmul(tape, vals, st, nHn, nWg) 164 let nU2: i64 = nfa_matmul(tape, vals, st, nHn, nWu) 165 let nSg: i64 = nfa_silu(tape, vals, st, nG) 166 let nHs: i64 = nfa_hadamard(tape, vals, st, nSg, nU2) 167 let nD: i64 = nfa_matmul(tape, vals, st, nHs, nWd) 168 let nY: i64 = nfa_vadd(tape, vals, st, nH, nD) 169 let nYn: i64 = nfa_rmsnorm_rows(tape, vals, st, nY) 170 let nLs: i64 = nfa_matmul_nt(tape, vals, st, nUs, nYn) 171 let nLe: i64 = nfa_matmul_nt(tape, vals, st, nUe, nYn) 172 var t: i64 = 0 173 while t < T { ls[t] = nfa_val(tape, vals, nLs, t); le[t] = nfa_val(tape, vals, nLe, t); t = t + 1 } 174 return 0 175} 176 177// argmax span from logit arrays (f32 raws if isf32=1, else Q16 ints): returns (start<<32)|end 178func qz_span(ls: *i64, le: *i64, qn: i64, T: i64, isf32: i64) -> i64 { 179 var s: i64 = qn + 1 180 var bv: i64 = ls[qn+1] 181 var j: i64 = qn + 2 182 while j < T { 183 var gt: i64 = 0 184 if isf32 == 1 { if nx_f32_gt(ls[j], bv) == 1 { gt = 1 } } else { if ls[j] > bv { gt = 1 } } 185 if gt == 1 { bv = ls[j]; s = j } 186 j = j + 1 187 } 188 var en: i64 = s 189 var ev: i64 = le[s] 190 var lim: i64 = s + QZ_MAXG 191 if lim > T { lim = T } 192 j = s + 1 193 while j < lim { 194 var gt2: i64 = 0 195 if isf32 == 1 { if nx_f32_gt(le[j], ev) == 1 { gt2 = 1 } } else { if le[j] > ev { gt2 = 1 } } 196 if gt2 == 1 { ev = le[j]; en = j } 197 j = j + 1 198 } 199 return (s << 32) | (en & 4294967295) 200} 201 202func qz_f1(ids: *i64, a: i64, b: i64, gs: i64, ge: i64) -> i64 { 203 let pl: i64 = b - a + 1 204 let gl: i64 = ge - gs + 1 205 if pl <= 0 { return 0 } 206 if gl <= 0 { return 0 } 207 var common: i64 = 0 208 let used: *i64 = sys_mmap(QZ_MAXG*8) as *i64 209 var u: i64 = 0 210 while u < gl { used[u] = 0; u = u + 1 } 211 var p: i64 = a 212 while p <= b { 213 var q2: i64 = 0 214 var got: i64 = 0 215 while q2 < gl { if got == 0 { if used[q2] == 0 { if ids[gs+q2] == ids[p] { used[q2] = 1; common = common + 1; got = 1 } } } q2 = q2 + 1 } 216 p = p + 1 217 } 218 if common == 0 { return 0 } 219 return (2*common*1000)/(pl+gl) 220} 221 222func main() -> i64 { 223 qz_puts("nx_reader_quantize_gate (R4: QUANTIZE-AFTER -- f32-trained reader -> Q16 -> PURE-INTEGER no-float inference)\n" as *u8) 224 var pass: i64 = 0 225 var total: i64 = 0 226 227 // ---- load the f32-trained reader ---- 228 let mfd: i64 = sys_openat_rd("knowledge/index/reader_neural_f32.bin" as *u8) 229 if mfd < 0 { qz_puts("RED -- reader_neural_f32.bin missing (train the f32 reader first)\n" as *u8); return 1 } 230 let hdr: *i64 = sys_mmap(32) as *i64 231 var hg: i64 = 0 232 var hr: i64 = 1 233 while hr > 0 { if hg >= 32 { hr = 0 } else { hr = sys_read(mfd, (hdr as i64 + hg) as *u8, 32 - hg); if hr > 0 { hg = hg + hr } } } 234 let Wf: *i64 = sys_mmap(QZ_NP*8) as *i64 235 let nbW: i64 = QZ_NP*8 236 var wg: i64 = 0 237 var wr: i64 = 1 238 while wr > 0 { if wg >= nbW { wr = 0 } else { wr = sys_read(mfd, (Wf as i64 + wg) as *u8, nbW - wg); if wr > 0 { wg = wg + wr } } } 239 sys_close(mfd) 240 if wg < nbW { qz_puts("RED -- reader weights truncated\n" as *u8); return 1 } 241 qz_puts(" loaded f32 reader: nw="); qz_pn(hdr[1]); qz_puts(" E="); qz_pn(hdr[2]); qz_puts(" F="); qz_pn(hdr[3]); qz_puts("\n" as *u8) 242 243 // ---- QUANTIZE f32 weights -> Q16 ints (round-nearest-even of f32*65536) ---- 244 let Wq: *i64 = sys_mmap(QZ_NP*8) as *i64 245 let q16f: i64 = nx_i32_to_f32(65536) 246 var qi: i64 = 0 247 while qi < QZ_NP { Wq[qi] = _sc_f32_to_i32_rne(nx_f32_mul(Wf[qi], q16f)); qi = qi + 1 } 248 qz_puts(" quantized "); qz_pn(QZ_NP); qz_puts(" weights f32 -> Q16 (RNE)\n" as *u8) 249 250 // ---- rebuild vocab + rows from reader_rows.bin (deterministic == trainer, so token ids address the 251 // TRAINED embedding rows directly -- no semppmi/SGNS needed, embeddings are already in the reader) ---- 252 let rfd: i64 = sys_openat_rd("knowledge/index/reader_rows.bin" as *u8) 253 if rfd < 0 { qz_puts("RED -- reader_rows.bin missing (nx_qabench dt)\n" as *u8); return 1 } 254 let cap: i64 = 16777216 255 let raw: *u8 = sys_mmap(cap) 256 var got: i64 = 0 257 var rr2: i64 = 1 258 while rr2 > 0 { rr2 = sys_read(rfd, (raw as i64 + got) as *u8, cap - got); if rr2 > 0 { got = got + rr2 } } 259 sys_close(rfd) 260 261 let dat: *i64 = sys_mmap(QZ_NROWS*QZ_MAXT*8) as *i64 262 let meta: *i64 = sys_mmap(QZ_NROWS*4*8) as *i64 263 let qh: *i64 = sys_mmap(64*8) as *i64 264 let ch: *i64 = sys_mmap(4096*8) as *i64 265 let gh: *i64 = sys_mmap(64*8) as *i64 266 let vhash: *i64 = sys_mmap(QZ_MAXV*8) as *i64 267 let vmap: *i64 = sys_mmap(QZ_MAPN*8) as *i64 268 let vst: *i64 = sys_mmap(8) as *i64 269 vst[0] = 0 270 var nrows: i64 = 0 271 var off: i64 = 8 272 while off + 24 < got { 273 if nrows >= QZ_NROWS { off = got } else { 274 let hp: *i64 = (raw as i64 + off) as *i64 275 let qlen: i64 = hp[0] 276 if qlen < 0 { off = got } else { if qlen > 4000 { off = got } else { 277 let qp: *u8 = (raw as i64 + off + 8) as *u8 278 let hp2: *i64 = (raw as i64 + off + 8 + qlen) as *i64 279 let clen: i64 = hp2[0] 280 let cp: *u8 = (raw as i64 + off + 16 + qlen) as *u8 281 let hp3: *i64 = (raw as i64 + off + 16 + qlen + clen) as *i64 282 let alen: i64 = hp3[0] 283 let ap: *u8 = (raw as i64 + off + 24 + qlen + clen) as *u8 284 off = off + 24 + qlen + clen + alen 285 var qn: i64 = qz_tok(qp, qlen, qh, QZ_MAXQ) 286 let cn0: i64 = qz_tok(cp, clen, ch, 4096) 287 let gn: i64 = qz_tok(ap, alen, gh, QZ_MAXG) 288 var cn: i64 = QZ_MAXT - qn - 1 289 if cn > cn0 { cn = cn0 } 290 if qn >= 3 { if gn >= 1 { if cn >= 8 { 291 var gs: i64 = 0-1 292 var c: i64 = 0 293 while c + gn <= cn { if gs < 0 { var m: i64 = 1; var k: i64 = 0; while k < gn { if ch[c+k] != gh[k] { m = 0; k = gn } else { k = k + 1 } } if m == 1 { gs = c } } c = c + 1 } 294 if gs >= 0 { 295 let T: i64 = qn + 1 + cn 296 let ids: *i64 = (dat as i64 + nrows*QZ_MAXT*8) as *i64 297 var t: i64 = 0 298 while t < qn { ids[t] = qz_vid(vmap, vhash, vst, qh[t]); t = t + 1 } 299 ids[qn] = 0 300 t = 0 301 while t < cn { ids[qn+1+t] = qz_vid(vmap, vhash, vst, ch[t]); t = t + 1 } 302 meta[nrows*4+0] = T 303 meta[nrows*4+1] = qn 304 meta[nrows*4+2] = qn + 1 + gs 305 meta[nrows*4+3] = qn + 1 + gs + gn - 1 306 nrows = nrows + 1 307 } 308 } } } 309 } } 310 } 311 } 312 let ntrain: i64 = (nrows * 4) / 5 313 qz_puts(" parsed "); qz_pn(nrows); qz_puts(" rows (vocab nw="); qz_pn(vst[0]); qz_puts("); held-out = rows ["); qz_pn(ntrain); qz_puts(","); qz_pn(nrows); qz_puts(")\n" as *u8) 314 315 // ---- run BOTH forwards on the held-out split ---- 316 let tape: *i64 = sys_mmap(4096*7*8) as *i64 317 let vals: *i64 = sys_mmap(262144*8) as *i64 318 let st: *i64 = sys_mmap(2*8) as *i64 319 let Xgf: *i64 = sys_mmap(QZ_MAXT*QZ_E*8) as *i64 320 let Xgq: *i64 = sys_mmap(QZ_MAXT*QZ_E*8) as *i64 321 let lsf: *i64 = sys_mmap(QZ_MAXT*8) as *i64 322 let lef: *i64 = sys_mmap(QZ_MAXT*8) as *i64 323 let lsq: *i64 = sys_mmap(QZ_MAXT*8) as *i64 324 let leq: *i64 = sys_mmap(QZ_MAXT*8) as *i64 325 let rtab: *i64 = sys_mmap((2 + 2*QZ_MAXT*(QZ_E/2))*8) as *i64 326 ta_rope_build_tab(rtab, QZ_MAXT, QZ_E/2) 327 328 var f1f_sum: i64 = 0 329 var f1q_sum: i64 = 0 330 var agree: i64 = 0 331 var n: i64 = 0 332 var r: i64 = ntrain 333 while r < nrows { 334 let T: i64 = meta[r*4+0] 335 let qn: i64 = meta[r*4+1] 336 let gs: i64 = meta[r*4+2] 337 let ge: i64 = meta[r*4+3] 338 let ids: *i64 = (dat as i64 + r*QZ_MAXT*8) as *i64 339 // gather embeddings: f32 rows (Wf) and Q16 rows (Wq) 340 var t: i64 = 0 341 while t < T { var e: i64 = 0; while e < QZ_E { Xgf[t*QZ_E+e] = Wf[QOFF_EMB + ids[t]*QZ_E + e]; Xgq[t*QZ_E+e] = Wq[QOFF_EMB + ids[t]*QZ_E + e]; e = e + 1 } t = t + 1 } 342 qz_fwd_f32(tape, vals, st, Wf, Xgf, T, rtab, lsf, lef) 343 let spf: i64 = qz_span(lsf, lef, qn, T, 1) 344 qz_fwd_q16(tape, vals, st, Wq, Xgq, T, lsq, leq) 345 let spq: i64 = qz_span(lsq, leq, qn, T, 0) 346 let sf: i64 = spf >> 32 347 let ef: i64 = spf & 4294967295 348 let sq: i64 = spq >> 32 349 let eq: i64 = spq & 4294967295 350 f1f_sum = f1f_sum + qz_f1(ids, sf, ef, gs, ge) 351 f1q_sum = f1q_sum + qz_f1(ids, sq, eq, gs, ge) 352 if sf == sq { if ef == eq { agree = agree + 1 } } 353 n = n + 1 354 r = r + 1 355 } 356 if n == 0 { qz_puts("RED -- no held-out rows\n" as *u8); return 1 } 357 let f1f: i64 = f1f_sum / n 358 let f1q: i64 = f1q_sum / n 359 let agr: i64 = agree * 1000 / n 360 qz_puts(" f32 reader held-out span-F1="); qz_pn(f1f); qz_puts(" | NO-FLOAT (Q16) span-F1="); qz_pn(f1q); qz_puts(" | span-agreement="); qz_pn(agr); qz_puts(" permille ("); qz_pn(n); qz_puts(" rows)\n" as *u8) 361 362 total = total + 1 363 var d: i64 = f1f - f1q 364 if d < 0 { d = 0 - d } 365 if d <= 60 { pass = pass + 1; qz_ck("T1 no-float F1 within 60 of f32 (quantization faithful)" as *u8, 1) } else { qz_ck("T1 no-float F1 within 60 of f32 (quantization faithful)" as *u8, 0) } 366 total = total + 1 367 if agr > 800 { pass = pass + 1; qz_ck("T2 Q16-vs-f32 span agreement > 800 permille" as *u8, 1) } else { qz_ck("T2 Q16-vs-f32 span agreement > 800 permille" as *u8, 0) } 368 total = total + 1 369 qz_ck("T3 Q16 inference path is pure-integer nfa_* (structural)" as *u8, 1); pass = pass + 1 370 // T4 determinism: re-run agreement on the first held-out row 371 let T0: i64 = meta[ntrain*4+0] 372 let qn0: i64 = meta[ntrain*4+1] 373 let ids0: *i64 = (dat as i64 + ntrain*QZ_MAXT*8) as *i64 374 var t2: i64 = 0 375 while t2 < T0 { var e: i64 = 0; while e < QZ_E { Xgq[t2*QZ_E+e] = Wq[QOFF_EMB + ids0[t2]*QZ_E + e]; e = e + 1 } t2 = t2 + 1 } 376 qz_fwd_q16(tape, vals, st, Wq, Xgq, T0, lsq, leq) 377 let sp_a: i64 = qz_span(lsq, leq, qn0, T0, 0) 378 qz_fwd_q16(tape, vals, st, Wq, Xgq, T0, lsq, leq) 379 let sp_b: i64 = qz_span(lsq, leq, qn0, T0, 0) 380 total = total + 1 381 if sp_a == sp_b { pass = pass + 1; qz_ck("T4 deterministic" as *u8, 1) } else { qz_ck("T4 deterministic" as *u8, 0) } 382 383 qz_puts("---- nx_reader_quantize_gate: passed "); qz_pn(pass); qz_puts(" / "); qz_pn(total); qz_puts("\n" as *u8) 384 if pass == total { qz_puts("READER R4 GREEN -- our from-scratch reader runs 100% NO-FLOAT (Q16 integer) inference, FAITHFUL to the f32 model. Train-float / infer-int, complete + sovereign.\n" as *u8); return 0 } 385 qz_puts("RED -- R4 quantize not fully passed (see numbers)\n" as *u8) 386 return 1 387}