code wiki / _hdl_build / nx_nofloat_lm_gate.nx
nx_nofloat_lm_gate.nx source
↩ module page · 303 lines · 17793 B
1// nx_nofloat_lm_gate.nx -- THE CAPSTONE: a tiny TRANSFORMER LANGUAGE MODEL trains END-TO-END on next-token
2// prediction, in PURE INTEGER Q16 (CAP-NF-LM). Full LM forward:
3// X = embed(E, ids) -> pre-norm transformer block (attn+RoPE+causal-softmax+SwiGLU-FFN+residuals)
4// -> rmsnorm_rows -> logits = H_n . W_lm -> loss = softmax-cross-entropy(logits, next-token ids)
5// Composed ENTIRELY from gradcheck-verified ops + the two new LM-head ops (embed gather/scatter, fused softce).
6//
7// A1 embed gradcheck : dE (gather backward = scatter-add) == finite difference.
8// A2 softce gradcheck : dlogits (fused CE identity softmax-onehot) == finite difference.
9// A3 full-LM gradcheck wrt W_lm : the LM-head gradient through CE == finite diff.
10// A4 full-LM gradcheck wrt E : the LONGEST chain -- E's gradient flows back through head+norm+FFN+attention
11// +RoPE+softmax+embed (the WHOLE model) == finite diff. This proves end-to-end backprop of the LM.
12// D neg-control teeth ; C bit-exact.
13// B THE LM FITS (memorizes a FIXED sequence) : train E + W_lm (through the full forward; gradient traverses the whole block) on a
14// next-token task (ids 0,1,2,3 -> 1,2,3,0); assert CE loss drops substantially from ~ln(V).
15//
16// Evidence -> knowledge/status/nofloat_lm.log. Sovereign: nx_nofloat_autograd + nx_syscalls (pure integer).
17// HONEST scope: single-head, single-block, tiny vocab; multi-head/GQA + deeper stack + scale remain. expect_exit: 0
18import "nx_nofloat_autograd.nx"
19import "nx_syscalls.nx"
20import "nx_gate_emit_lib.nx"
21import "nx_gate_verdict.nx"
22
23const LLOG: *u8 = "knowledge/status/nofloat_lm.log"
24const Q16: i64 = 65536
25
26
27func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
28func l_ws(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
29func l_wn(fd: i64, v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(fd,"-" as *u8,1);m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(fd,b,k); return 0 }
30// deterministic small nonzero init (zero-init = dead-gradient trap): values in ~[-0.25, 0.25] Q16
31func lm_init(arr: *i64, n: i64, seed: i64) -> i64 { var i: i64=0; while i<n { arr[i] = (((i*7 + seed*13 + 1) % 11) - 5) * 3277; i=i+1 } return 0 }
32
33// ---- full LM forward; W = ptr-array of 9 weight arrays [E,Wq,Wk,Wv,Wo,Wg,Wu,Wd,Wlm]; leaves[i]<->W[i], leaves[9]=logits ----
34func lm_fwd(tape: *i64, vals: *i64, st: *i64, W: *i64, ids: *i64, tgt: *i64, T: i64, dm: i64, ffn: i64, V: i64, scale: i64, leaves: *i64) -> i64 {
35 let E: *i64 = W[0] as *i64; let Wq: *i64 = W[1] as *i64; let Wk: *i64 = W[2] as *i64; let Wv: *i64 = W[3] as *i64; let Wo: *i64 = W[4] as *i64
36 let Wg: *i64 = W[5] as *i64; let Wu: *i64 = W[6] as *i64; let Wd: *i64 = W[7] as *i64; let Wlm: *i64 = W[8] as *i64
37 st[0]=0; st[1]=0
38 let nE: i64 = nfa_leaf(tape,vals,st,V,dm,E,0)
39 let nWq: i64 = nfa_leaf(tape,vals,st,dm,dm,Wq,0)
40 let nWk: i64 = nfa_leaf(tape,vals,st,dm,dm,Wk,0)
41 let nWv: i64 = nfa_leaf(tape,vals,st,dm,dm,Wv,0)
42 let nWo: i64 = nfa_leaf(tape,vals,st,dm,dm,Wo,0)
43 let nWg: i64 = nfa_leaf(tape,vals,st,dm,ffn,Wg,0)
44 let nWu: i64 = nfa_leaf(tape,vals,st,dm,ffn,Wu,0)
45 let nWd: i64 = nfa_leaf(tape,vals,st,ffn,dm,Wd,0)
46 let nWlm:i64 = nfa_leaf(tape,vals,st,dm,V,Wlm,0)
47 let nX: i64 = nfa_embed(tape,vals,st,nE,ids,T)
48 let nXn: i64 = nfa_rmsnorm_rows(tape,vals,st,nX)
49 let nQ: i64 = nfa_matmul(tape,vals,st,nXn,nWq)
50 let nK: i64 = nfa_matmul(tape,vals,st,nXn,nWk)
51 let nV: i64 = nfa_matmul(tape,vals,st,nXn,nWv)
52 let nQr: i64 = nfa_rope(tape,vals,st,nQ)
53 let nKr: i64 = nfa_rope(tape,vals,st,nK)
54 let nS: i64 = nfa_matmul_nt(tape,vals,st,nQr,nKr)
55 let nSs: i64 = nfa_cmul(tape,vals,st,nS,scale)
56 let nA: i64 = nfa_softmax_rows(tape,vals,st,nSs,1)
57 let nO: i64 = nfa_matmul(tape,vals,st,nA,nV)
58 let nOp: i64 = nfa_matmul(tape,vals,st,nO,nWo)
59 let nH: i64 = nfa_vadd(tape,vals,st,nX,nOp)
60 let nHn: i64 = nfa_rmsnorm_rows(tape,vals,st,nH)
61 let nG: i64 = nfa_matmul(tape,vals,st,nHn,nWg)
62 let nU: i64 = nfa_matmul(tape,vals,st,nHn,nWu)
63 let nSg: i64 = nfa_silu(tape,vals,st,nG)
64 let nHs: i64 = nfa_hadamard(tape,vals,st,nSg,nU)
65 let nDp: i64 = nfa_matmul(tape,vals,st,nHs,nWd)
66 let nY: i64 = nfa_vadd(tape,vals,st,nH,nDp)
67 let nYn: i64 = nfa_rmsnorm_rows(tape,vals,st,nY)
68 let nLg: i64 = nfa_matmul(tape,vals,st,nYn,nWlm)
69 let nLoss: i64 = nfa_softce_rows(tape,vals,st,nLg,tgt)
70 leaves[0]=nE; leaves[1]=nWq; leaves[2]=nWk; leaves[3]=nWv; leaves[4]=nWo
71 leaves[5]=nWg; leaves[6]=nWu; leaves[7]=nWd; leaves[8]=nWlm; leaves[9]=nLg
72 return nLoss
73}
74func lm_lossval(tape: *i64, vals: *i64, st: *i64, W: *i64, ids: *i64, tgt: *i64, T: i64, dm: i64, ffn: i64, V: i64, scale: i64) -> i64 {
75 let lv: *i64 = sys_mmap(10*8) as *i64
76 let nLoss: i64 = lm_fwd(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale,lv)
77 return nfa_val(tape,vals,nLoss,0)
78}
79// gradcheck wrt weight array widx (leaves[widx]); extract ALL analytic grads first (lm_lossval rebuilds the tape).
80func lm_gc_w(tape: *i64, vals: *i64, grads: *i64, st: *i64, W: *i64, ids: *i64, tgt: *i64, T: i64, dm: i64, ffn: i64, V: i64, scale: i64, leaves: *i64, widx: i64, h: i64, tol_q: i64, floor_q: i64, worst: *i64) -> i64 {
81 let nLoss: i64 = lm_fwd(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale,leaves)
82 nfa_backward(tape,vals,grads,st[0],nLoss)
83 let nnode: i64 = leaves[widx]
84 let cnt: i64 = tape[7*nnode+3]*tape[7*nnode+4]
85 let ana: *i64 = sys_mmap(64*8) as *i64
86 var c: i64=0
87 while c<cnt { ana[c]=nfa_grad(tape,grads,nnode,c); c=c+1 }
88 let arr: *i64 = W[widx] as *i64
89 var ok: i64=1; worst[0]=0
90 var i: i64=0
91 while i<cnt {
92 let old: i64 = arr[i]
93 arr[i]=old+h; let lp: i64 = lm_lossval(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale)
94 arr[i]=old-h; let lm2: i64 = lm_lossval(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale)
95 arr[i]=old
96 let fd: i64 = ((lp-lm2)*Q16)/(2*h)
97 let num: i64 = g_abs(fd-ana[i])
98 var den: i64 = g_abs(ana[i]); if den<floor_q { den=floor_q }
99 if num >= ((tol_q*den)>>16) { ok=0 }
100 let rel: i64 = (num*1000)/den
101 if rel>worst[0] { worst[0]=rel }
102 i=i+1
103 }
104 return ok
105}
106
107// ---- A1 embed standalone: loss = mse(embed(E,ids), tgt) ----
108func emb_loss(tape: *i64, vals: *i64, st: *i64, E: *i64, ids: *i64, Tg: *i64, V: i64, dm: i64, T: i64, leaves: *i64) -> i64 {
109 st[0]=0; st[1]=0
110 let nE: i64 = nfa_leaf(tape,vals,st,V,dm,E,0)
111 let nX: i64 = nfa_embed(tape,vals,st,nE,ids,T)
112 let nt: i64 = nfa_leaf(tape,vals,st,T,dm,Tg,0)
113 let loss: i64 = nfa_mse(tape,vals,st,nX,nt)
114 leaves[0]=nE
115 return loss
116}
117func emb_lossval(tape: *i64, vals: *i64, st: *i64, E: *i64, ids: *i64, Tg: *i64, V: i64, dm: i64, T: i64) -> i64 {
118 let lv: *i64 = sys_mmap(8) as *i64
119 let loss: i64 = emb_loss(tape,vals,st,E,ids,Tg,V,dm,T,lv)
120 return nfa_val(tape,vals,loss,0)
121}
122
123// ---- A2 softce standalone: loss = softce(logits_leaf, tgt) ----
124func ce_loss(tape: *i64, vals: *i64, st: *i64, L: *i64, tgt: *i64, T: i64, V: i64, leaves: *i64) -> i64 {
125 st[0]=0; st[1]=0
126 let nL: i64 = nfa_leaf(tape,vals,st,T,V,L,0)
127 let loss: i64 = nfa_softce_rows(tape,vals,st,nL,tgt)
128 leaves[0]=nL
129 return loss
130}
131func ce_lossval(tape: *i64, vals: *i64, st: *i64, L: *i64, tgt: *i64, T: i64, V: i64) -> i64 {
132 let lv: *i64 = sys_mmap(8) as *i64
133 let loss: i64 = ce_loss(tape,vals,st,L,tgt,T,V,lv)
134 return nfa_val(tape,vals,loss,0)
135}
136
137func main() -> i64 {
138 g_puts("nx_nofloat_lm gate (a tiny TRANSFORMER LM trains end-to-end on next-token, PURE INTEGER Q16)\n" as *u8)
139 var pass: i64=0; var total: i64=0
140 let tape: *i64 = sys_mmap(512*7*8) as *i64
141 let vals: *i64 = sys_mmap(16384*8) as *i64
142 let grads: *i64 = sys_mmap(16384*8) as *i64
143 let st: *i64 = sys_mmap(2*8) as *i64
144 let h: i64 = 512; let floor_q: i64 = 4096
145 let worst: *i64 = sys_mmap(8) as *i64
146
147 // ---- A1: embed gradcheck (V=3,dm=2,T=3; ids gather rows 0,2,1; one repeats nothing here) ----
148 let eE: *i64 = sys_mmap(6*8) as *i64; lm_init(eE,6,1)
149 let eids: *i64 = sys_mmap(3*8) as *i64; eids[0]=0; eids[1]=2; eids[2]=1
150 let eTg: *i64 = sys_mmap(6*8) as *i64; eTg[0]=13107; eTg[1]=0-6554; eTg[2]=19661; eTg[3]=6554; eTg[4]=0-26214; eTg[5]=32768
151 let elv: *i64 = sys_mmap(8) as *i64
152 let el: i64 = emb_loss(tape,vals,st,eE,eids,eTg,3,2,3,elv)
153 nfa_backward(tape,vals,grads,st[0],el)
154 let enode: i64 = elv[0]
155 let eana: *i64 = sys_mmap(8*8) as *i64
156 var ec: i64=0
157 while ec<6 { eana[ec]=nfa_grad(tape,grads,enode,ec); ec=ec+1 }
158 var e_ok: i64=1; var e_worst: i64=0
159 var ei: i64=0
160 while ei<6 {
161 let old: i64=eE[ei]; eE[ei]=old+h; let lp: i64=emb_lossval(tape,vals,st,eE,eids,eTg,3,2,3); eE[ei]=old-h; let lm2: i64=emb_lossval(tape,vals,st,eE,eids,eTg,3,2,3); eE[ei]=old
162 let fd: i64=((lp-lm2)*Q16)/(2*h); let num: i64=g_abs(fd-eana[ei]); var den: i64=g_abs(eana[ei]); if den<floor_q{den=floor_q}
163 if num >= ((4096*den)>>16) { e_ok=0 }
164 let rel: i64=(num*1000)/den; if rel>e_worst{e_worst=rel}
165 ei=ei+1
166 }
167 g_puts(" [measure] embed worst rel grad err = " as *u8); g_pn(e_worst); g_puts(" /1000 (tol=62)\n" as *u8)
168 pass=pass+g_check("A1: embed gradcheck -- gather backward (scatter-add) == finite differences" as *u8, e_ok); total=total+1
169
170 // ---- A2: softce gradcheck (T=2,V=3) ----
171 let cL: *i64 = sys_mmap(6*8) as *i64; cL[0]=32768; cL[1]=0-16384; cL[2]=49152; cL[3]=16384; cL[4]=65536; cL[5]=0-32768
172 let ctg: *i64 = sys_mmap(2*8) as *i64; ctg[0]=1; ctg[1]=2
173 let clv: *i64 = sys_mmap(8) as *i64
174 let cl: i64 = ce_loss(tape,vals,st,cL,ctg,2,3,clv)
175 nfa_backward(tape,vals,grads,st[0],cl)
176 let cnode: i64 = clv[0]
177 let cana: *i64 = sys_mmap(8*8) as *i64
178 var cc: i64=0
179 while cc<6 { cana[cc]=nfa_grad(tape,grads,cnode,cc); cc=cc+1 }
180 var c_ok: i64=1; var c_worst: i64=0
181 var ci: i64=0
182 while ci<6 {
183 let old: i64=cL[ci]; cL[ci]=old+h; let lp: i64=ce_lossval(tape,vals,st,cL,ctg,2,3); cL[ci]=old-h; let lm2: i64=ce_lossval(tape,vals,st,cL,ctg,2,3); cL[ci]=old
184 let fd: i64=((lp-lm2)*Q16)/(2*h); let num: i64=g_abs(fd-cana[ci]); var den: i64=g_abs(cana[ci]); if den<floor_q{den=floor_q}
185 if num >= ((8192*den)>>16) { c_ok=0 } // tol 1/8 (ln/exp fixed-point approximation)
186 let rel: i64=(num*1000)/den; if rel>c_worst{c_worst=rel}
187 ci=ci+1
188 }
189 g_puts(" [measure] softce worst rel grad err = " as *u8); g_pn(c_worst); g_puts(" /1000 (tol=125)\n" as *u8)
190 pass=pass+g_check("A2: softce gradcheck -- fused softmax-CE (softmax-onehot) backward == finite differences" as *u8, c_ok); total=total+1
191
192 // ---- LM dims + weights ----
193 let T: i64=4; let dm: i64=4; let ffn: i64=8; let V: i64=4; let scale: i64=32768 // 1/sqrt(4)=0.5
194 let E: *i64 = sys_mmap(V*dm*8) as *i64; lm_init(E,V*dm,1)
195 let Wq: *i64 = sys_mmap(dm*dm*8) as *i64; lm_init(Wq,dm*dm,2)
196 let Wk: *i64 = sys_mmap(dm*dm*8) as *i64; lm_init(Wk,dm*dm,3)
197 let Wv: *i64 = sys_mmap(dm*dm*8) as *i64; lm_init(Wv,dm*dm,4)
198 let Wo: *i64 = sys_mmap(dm*dm*8) as *i64; lm_init(Wo,dm*dm,5)
199 let Wg: *i64 = sys_mmap(dm*ffn*8) as *i64; lm_init(Wg,dm*ffn,6)
200 let Wu: *i64 = sys_mmap(dm*ffn*8) as *i64; lm_init(Wu,dm*ffn,7)
201 let Wd: *i64 = sys_mmap(ffn*dm*8) as *i64; lm_init(Wd,ffn*dm,8)
202 let Wlm:*i64 = sys_mmap(dm*V*8) as *i64; lm_init(Wlm,dm*V,9)
203 let W: *i64 = sys_mmap(9*8) as *i64
204 W[0]=E as i64; W[1]=Wq as i64; W[2]=Wk as i64; W[3]=Wv as i64; W[4]=Wo as i64; W[5]=Wg as i64; W[6]=Wu as i64; W[7]=Wd as i64; W[8]=Wlm as i64
205 let ids: *i64 = sys_mmap(T*8) as *i64; ids[0]=0; ids[1]=1; ids[2]=2; ids[3]=3
206 let tgt: *i64 = sys_mmap(T*8) as *i64; tgt[0]=1; tgt[1]=2; tgt[2]=3; tgt[3]=0
207 let leaves: *i64 = sys_mmap(10*8) as *i64
208
209 // ---- A3: full-LM gradcheck wrt Wlm (widx 8) ----
210 let a3_ok: i64 = lm_gc_w(tape,vals,grads,st,W,ids,tgt,T,dm,ffn,V,scale,leaves,8,h,8192,floor_q,worst)
211 g_puts(" [measure] full-LM dL/dWlm worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=125)\n" as *u8)
212 pass=pass+g_check("A3: full-LM gradcheck wrt Wlm (LM head through CE) == finite differences" as *u8, a3_ok); total=total+1
213
214 // ---- A4: full-LM gradcheck wrt E (widx 0) -- the LONGEST chain (head+norm+FFN+attn+RoPE+softmax+embed) ----
215 let a4_ok: i64 = lm_gc_w(tape,vals,grads,st,W,ids,tgt,T,dm,ffn,V,scale,leaves,0,h,16384,floor_q,worst)
216 g_puts(" [measure] full-LM dL/dE worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=250)\n" as *u8)
217 pass=pass+g_check("A4: full-LM gradcheck wrt E through the WHOLE model == finite differences (end-to-end backprop)" as *u8, a4_ok); total=total+1
218
219 // ---- D: neg-control teeth (Wlm grad) ----
220 let nLd: i64 = lm_fwd(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale,leaves)
221 nfa_backward(tape,vals,grads,st[0],nLd)
222 let dana: i64 = nfa_grad(tape,grads,leaves[8],0)
223 let old0: i64 = Wlm[0]; Wlm[0]=old0+h; let lpd: i64=lm_lossval(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale); Wlm[0]=old0-h; let lmd: i64=lm_lossval(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale); Wlm[0]=old0
224 let dfd: i64 = ((lpd-lmd)*Q16)/(2*h)
225 let dbad: i64 = 0 - dana
226 var dden: i64 = g_abs(dana); if dden<floor_q { dden=floor_q }
227 var caught: i64 = 1
228 if g_abs(dfd-dbad) < ((8192*dden)>>16) { caught=0 }
229 pass=pass+g_check("D: neg-control -- a WRONG LM gradient is rejected (teeth)" as *u8, caught); total=total+1
230
231 // ---- B: the LM FITS (memorizes a FIXED sequence) next-token (train E + Wlm through the full forward; grad traverses the whole block) ----
232 let gbuf: *i64 = sys_mmap(64*8) as *i64
233 var lf: i64=0; var ll: i64=0
234 var ep: i64=0
235 while ep < 8000 {
236 let nLoss: i64 = lm_fwd(tape,vals,st,W,ids,tgt,T,dm,ffn,V,scale,leaves)
237 nfa_backward(tape,vals,grads,st[0],nLoss)
238 if ep==0 { lf = nfa_val(tape,vals,nLoss,0) }
239 ll = nfa_val(tape,vals,nLoss,0)
240 // update E (widx 0) and Wlm (widx 8)
241 let nE2: i64 = leaves[0]; let cE: i64 = V*dm
242 var z: i64=0
243 while z<cE { gbuf[z]=nfa_grad(tape,grads,nE2,z); z=z+1 }
244 nfa_sgd(E, gbuf, cE, 2048)
245 let nWl: i64 = leaves[8]; let cWl: i64 = dm*V
246 z=0
247 while z<cWl { gbuf[z]=nfa_grad(tape,grads,nWl,z); z=z+1 }
248 nfa_sgd(Wlm, gbuf, cWl, 2048)
249 ep=ep+1
250 }
251 g_puts(" [measure] LM next-token CE loss: start=" as *u8); g_pn(lf); g_puts(" end=" as *u8); g_pn(ll); g_puts(" (ln(V)=ln4 ~ 90852 Q16)\n" as *u8)
252 var fits: i64 = 1
253 if ll*2 > lf { fits=0 } // >= 50% CE reduction = it fit the fixed sequence (memorization, not generalization)
254 if lf <= 0 { fits=0 }
255 pass=pass+g_check("B: the LM FITS (memorizes a FIXED sequence) -- next-token CE loss drops >=50% via end-to-end backprop (E+Wlm trained)" as *u8, fits); total=total+1
256
257 // ---- C: bit-exact ----
258 let E2: *i64 = sys_mmap(V*dm*8) as *i64; lm_init(E2,V*dm,1)
259 let Wlm2:*i64 = sys_mmap(dm*V*8) as *i64; lm_init(Wlm2,dm*V,9)
260 let W2: *i64 = sys_mmap(9*8) as *i64
261 W2[0]=E2 as i64; W2[1]=Wq as i64; W2[2]=Wk as i64; W2[3]=Wv as i64; W2[4]=Wo as i64; W2[5]=Wg as i64; W2[6]=Wu as i64; W2[7]=Wd as i64; W2[8]=Wlm2 as i64
262 let lvc: *i64 = sys_mmap(10*8) as *i64
263 let gbuf2: *i64 = sys_mmap(64*8) as *i64
264 var ep2: i64=0
265 while ep2 < 8000 {
266 let nLoss: i64 = lm_fwd(tape,vals,st,W2,ids,tgt,T,dm,ffn,V,scale,lvc)
267 nfa_backward(tape,vals,grads,st[0],nLoss)
268 let nE2: i64=lvc[0]; var z: i64=0
269 while z<V*dm { gbuf2[z]=nfa_grad(tape,grads,nE2,z); z=z+1 }
270 nfa_sgd(E2, gbuf2, V*dm, 2048)
271 let nWl: i64=lvc[8]; z=0
272 while z<dm*V { gbuf2[z]=nfa_grad(tape,grads,nWl,z); z=z+1 }
273 nfa_sgd(Wlm2, gbuf2, dm*V, 2048)
274 ep2=ep2+1
275 }
276 var bitexact: i64 = 1
277 var zc: i64=0
278 while zc<V*dm { if E2[zc]!=E[zc] { bitexact=0 } zc=zc+1 }
279 zc=0
280 while zc<dm*V { if Wlm2[zc]!=Wlm[zc] { bitexact=0 } zc=zc+1 }
281 pass=pass+g_check("C: bit-exact -- training the LM twice gives IDENTICAL integer weights (determinism)" as *u8, bitexact); total=total+1
282
283 // ---- emit ----
284 var okall: i64=0; if pass==total { okall=1 }
285 let logf: i64 = sys_openat_append(LLOG, 420)
286 if logf >= 0 {
287 l_ws(logf,"NOFLOATLM 1-block 1-head V=4 A1_embed=" as *u8); l_wn(logf,e_ok); l_ws(logf," A2_softce=" as *u8); l_wn(logf,c_ok)
288 l_ws(logf," A3_Wlm=" as *u8); l_wn(logf,a3_ok); l_ws(logf," A4_E_fullchain=" as *u8); l_wn(logf,a4_ok); l_ws(logf," D=" as *u8); l_wn(logf,caught)
289 l_ws(logf," B_fits=" as *u8); l_wn(logf,fits); l_ws(logf," CE_start=" as *u8); l_wn(logf,lf); l_ws(logf," CE_end=" as *u8); l_wn(logf,ll); l_ws(logf," C_bitexact=" as *u8); l_wn(logf,bitexact)
290 if okall==1 { l_ws(logf," verdict=GREEN\n" as *u8) } else { l_ws(logf," verdict=RED\n" as *u8) }
291 sys_close(logf)
292 }
293 g_puts("---- nofloat_lm gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
294 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
295 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
296 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
297 let ctr__dry: *i64 = gv_ctr()
298 ctr__dry[0] = pass
299 ctr__dry[1] = total
300 let rc__dry: i64 = gv_verdict("NOFLOAT-LM-GATE" as *u8, ctr__dry, "a tiny transformer LM trains end-to-end on next-token prediction in pure integer Q16)" as *u8)
301 sys_exit(rc__dry)
302 return rc__dry
303}