code wiki / _hdl_build / nx_nofloat_block_gate.nx
nx_nofloat_block_gate.nx source
↩ module page · 303 lines · 17778 B
1// nx_nofloat_block_gate.nx -- HARD-EVIDENCE gate for a COMPLETE pre-norm TRANSFORMER BLOCK backprop + train,
2// in PURE INTEGER Q16 (CAP-NF-BLOCK). The block (single-head) is the real Qwen-style shape:
3// H = X + Wo * Attn( RoPE, scaled, causal-softmax )( rmsnorm_rows(X) ) [attention sublayer + residual]
4// Y = H + SwiGLU-FFN( rmsnorm_rows(H) ) [FFN sublayer + residual]
5// SwiGLU-FFN(z) = Wd * ( silu(Wg*z) (*) (Wu*z) )
6// Composed ENTIRELY from gradcheck-verified ops (rmsnorm_rows, matmul, matmul_nt, rope, cmul, softmax_rows,
7// silu, hadamard, vadd, mse). No new backward math -- this proves the COMPOSITION trains.
8//
9// A1 hadamard gradcheck : loss=mse(a(*)b,t); dL/da == finite diff.
10// A2 rmsnorm_rows gradcheck: per-token norm; dL/dx == finite diff.
11// A3 FULL-BLOCK gradcheck wrt Wd (down-proj, short path): dL/dWd == finite diff.
12// A4 FULL-BLOCK gradcheck wrt Wq (the LONGEST chain: through FFN, residual, attention, RoPE, softmax): measured.
13// B the BLOCK TRAINS : with all weights fixed except the down-proj Wd, Y is LINEAR in Wd (convex MSE) ->
14// train Wd from zero to a realizable teacher target; assert loss collapses + Wd converges. A weight DEEP in
15// a full transformer block is driven by the block's own end-to-end backward.
16// C bit-exact ; D neg-control teeth.
17//
18// Evidence -> knowledge/status/nofloat_block.log. Sovereign: nx_nofloat_autograd + nx_syscalls (pure integer).
19// HONEST scope: single-head; multi-head/GQA + multi-block stack are the remaining COMPOSITION. expect_exit: 0
20import "nx_nofloat_autograd.nx"
21import "nx_syscalls.nx"
22import "nx_gate_emit_lib.nx"
23import "nx_gate_verdict.nx"
24
25const BLOG: *u8 = "knowledge/status/nofloat_block.log"
26const Q16: i64 = 65536
27
28
29func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
30func b_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 }
31func b_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 }
32
33// ---- generic single-input-op gradcheck (op 13=hadamard handled separately; here 14=rmsnorm_rows) ----
34func one_loss(tape: *i64, vals: *i64, st: *i64, op: i64, Xs: *i64, Bs: *i64, Ts: *i64, r: i64, c: i64, leaves: *i64) -> i64 {
35 st[0]=0; st[1]=0
36 let nX: i64 = nfa_leaf(tape,vals,st,r,c,Xs,0)
37 var ny: i64 = nX
38 if op == 13 { let nB: i64 = nfa_leaf(tape,vals,st,r,c,Bs,0); ny = nfa_hadamard(tape,vals,st,nX,nB) }
39 if op == 14 { ny = nfa_rmsnorm_rows(tape,vals,st,nX) }
40 let nt: i64 = nfa_leaf(tape,vals,st,r,c,Ts,0)
41 let loss: i64 = nfa_mse(tape,vals,st,ny,nt)
42 leaves[0]=nX
43 return loss
44}
45func one_lossval(tape: *i64, vals: *i64, st: *i64, op: i64, Xs: *i64, Bs: *i64, Ts: *i64, r: i64, c: i64) -> i64 {
46 let lv: *i64 = sys_mmap(8) as *i64
47 let loss: i64 = one_loss(tape,vals,st,op,Xs,Bs,Ts,r,c,lv)
48 return nfa_val(tape,vals,loss,0)
49}
50func one_gradcheck(tape: *i64, vals: *i64, grads: *i64, st: *i64, op: i64, Xs: *i64, Bs: *i64, Ts: *i64, r: i64, c: i64, h: i64, tol_q: i64, floor_q: i64, worst: *i64) -> i64 {
51 let lv: *i64 = sys_mmap(8) as *i64
52 let loss: i64 = one_loss(tape,vals,st,op,Xs,Bs,Ts,r,c,lv)
53 nfa_backward(tape,vals,grads,st[0],loss)
54 let nX: i64 = lv[0]
55 var ok: i64=1; worst[0]=0
56 var i: i64=0
57 while i<r*c {
58 let ana: i64 = nfa_grad(tape,grads,nX,i)
59 let xp: *i64 = sys_mmap(r*c*8) as *i64
60 let xm: *i64 = sys_mmap(r*c*8) as *i64
61 var z: i64=0
62 while z<r*c { xp[z]=Xs[z]; xm[z]=Xs[z]; z=z+1 }
63 xp[i]=Xs[i]+h; xm[i]=Xs[i]-h
64 let lp: i64 = one_lossval(tape,vals,st,op,xp,Bs,Ts,r,c)
65 let lm: i64 = one_lossval(tape,vals,st,op,xm,Bs,Ts,r,c)
66 let fd: i64 = ((lp-lm)*Q16)/(2*h)
67 let num: i64 = g_abs(fd-ana)
68 var den: i64 = g_abs(ana); if den<floor_q { den=floor_q }
69 if num >= ((tol_q*den)>>16) { ok=0 }
70 let rel: i64 = (num*1000)/den
71 if rel>worst[0] { worst[0]=rel }
72 i=i+1
73 }
74 return ok
75}
76
77// ---- the full pre-norm transformer block; leaves[0]=nWq, leaves[1]=nWd; returns nY ----
78func blk_fwd(tape: *i64, vals: *i64, st: *i64, X: *i64, Wq: *i64, Wk: *i64, Wv: *i64, Wo: *i64, Wg: *i64, Wu: *i64, Wd: *i64, T: i64, dm: i64, ffn: i64, scale: i64, leaves: *i64) -> i64 {
79 st[0]=0; st[1]=0
80 let nX: i64 = nfa_leaf(tape,vals,st,T,dm,X,0)
81 let nWq: i64 = nfa_leaf(tape,vals,st,dm,dm,Wq,0)
82 let nWk: i64 = nfa_leaf(tape,vals,st,dm,dm,Wk,0)
83 let nWv: i64 = nfa_leaf(tape,vals,st,dm,dm,Wv,0)
84 let nWo: i64 = nfa_leaf(tape,vals,st,dm,dm,Wo,0)
85 let nWg: i64 = nfa_leaf(tape,vals,st,dm,ffn,Wg,0)
86 let nWu: i64 = nfa_leaf(tape,vals,st,dm,ffn,Wu,0)
87 let nWd: i64 = nfa_leaf(tape,vals,st,ffn,dm,Wd,0)
88 let nXn: i64 = nfa_rmsnorm_rows(tape,vals,st,nX)
89 let nQ: i64 = nfa_matmul(tape,vals,st,nXn,nWq)
90 let nK: i64 = nfa_matmul(tape,vals,st,nXn,nWk)
91 let nV: i64 = nfa_matmul(tape,vals,st,nXn,nWv)
92 let nQr: i64 = nfa_rope(tape,vals,st,nQ)
93 let nKr: i64 = nfa_rope(tape,vals,st,nK)
94 let nS: i64 = nfa_matmul_nt(tape,vals,st,nQr,nKr)
95 let nSs: i64 = nfa_cmul(tape,vals,st,nS,scale)
96 let nA: i64 = nfa_softmax_rows(tape,vals,st,nSs,1)
97 let nO: i64 = nfa_matmul(tape,vals,st,nA,nV)
98 let nOp: i64 = nfa_matmul(tape,vals,st,nO,nWo)
99 let nH: i64 = nfa_vadd(tape,vals,st,nX,nOp)
100 let nHn: i64 = nfa_rmsnorm_rows(tape,vals,st,nH)
101 let nG: i64 = nfa_matmul(tape,vals,st,nHn,nWg)
102 let nU: i64 = nfa_matmul(tape,vals,st,nHn,nWu)
103 let nSg: i64 = nfa_silu(tape,vals,st,nG)
104 let nHs: i64 = nfa_hadamard(tape,vals,st,nSg,nU)
105 let nD: i64 = nfa_matmul(tape,vals,st,nHs,nWd)
106 let nY: i64 = nfa_vadd(tape,vals,st,nH,nD)
107 leaves[0]=nWq; leaves[1]=nWd
108 return nY
109}
110func blk_loss(tape: *i64, vals: *i64, st: *i64, X: *i64, Wq: *i64, Wk: *i64, Wv: *i64, Wo: *i64, Wg: *i64, Wu: *i64, Wd: *i64, Ts: *i64, T: i64, dm: i64, ffn: i64, scale: i64, leaves: *i64) -> i64 {
111 let nY: i64 = blk_fwd(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,T,dm,ffn,scale,leaves)
112 let nt: i64 = nfa_leaf(tape,vals,st,T,dm,Ts,0)
113 return nfa_mse(tape,vals,st,nY,nt)
114}
115func blk_lossval(tape: *i64, vals: *i64, st: *i64, X: *i64, Wq: *i64, Wk: *i64, Wv: *i64, Wo: *i64, Wg: *i64, Wu: *i64, Wd: *i64, Ts: *i64, T: i64, dm: i64, ffn: i64, scale: i64) -> i64 {
116 let lv: *i64 = sys_mmap(2*8) as *i64
117 let loss: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,Ts,T,dm,ffn,scale,lv)
118 return nfa_val(tape,vals,loss,0)
119}
120func blk_out(tape: *i64, vals: *i64, st: *i64, X: *i64, Wq: *i64, Wk: *i64, Wv: *i64, Wo: *i64, Wg: *i64, Wu: *i64, Wd: *i64, T: i64, dm: i64, ffn: i64, scale: i64, outY: *i64) -> i64 {
121 let lv: *i64 = sys_mmap(2*8) as *i64
122 let nY: i64 = blk_fwd(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,T,dm,ffn,scale,lv)
123 var i: i64=0
124 while i<T*dm { outY[i] = nfa_val(tape,vals,nY,i); i=i+1 }
125 return 0
126}
127
128func main() -> i64 {
129 g_puts("nx_nofloat_block gate (a full pre-norm TRANSFORMER BLOCK backprops + trains in PURE INTEGER Q16)\n" as *u8)
130 var pass: i64=0; var total: i64=0
131 let tape: *i64 = sys_mmap(1024*7*8) as *i64
132 let vals: *i64 = sys_mmap(16384*8) as *i64
133 let grads: *i64 = sys_mmap(16384*8) as *i64
134 let st: *i64 = sys_mmap(2*8) as *i64
135 let h: i64 = 512; let floor_q: i64 = 4096
136 let worst: *i64 = sys_mmap(8) as *i64
137
138 // ---- A1 hadamard gradcheck (2x2) ----
139 let ha: *i64 = sys_mmap(4*8) as *i64; ha[0]=32768; ha[1]=0-16384; ha[2]=49152; ha[3]=65536
140 let hb: *i64 = sys_mmap(4*8) as *i64; hb[0]=49152; hb[1]=32768; hb[2]=0-32768; hb[3]=16384
141 let ht: *i64 = sys_mmap(4*8) as *i64; ht[0]=13107; ht[1]=0-6554; ht[2]=19661; ht[3]=6554
142 let ha_ok: i64 = one_gradcheck(tape,vals,grads,st,13,ha,hb,ht,2,2,h,4096,floor_q,worst)
143 g_puts(" [measure] hadamard worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62)\n" as *u8)
144 pass=pass+g_check("A1: hadamard gradcheck -- elementwise mul backward == finite differences" as *u8, ha_ok); total=total+1
145
146 // ---- A2 rmsnorm_rows gradcheck (2 rows x 3 cols) ----
147 let ra: *i64 = sys_mmap(6*8) as *i64; ra[0]=32768; ra[1]=65536; ra[2]=0-32768; ra[3]=16384; ra[4]=0-49152; ra[5]=24576
148 let rt: *i64 = sys_mmap(6*8) as *i64; rt[0]=13107; rt[1]=52429; rt[2]=0-39322; rt[3]=6554; rt[4]=0-26214; rt[5]=32768
149 let ra_ok: i64 = one_gradcheck(tape,vals,grads,st,14,ra,ra,rt,2,3,h,4096,floor_q,worst)
150 g_puts(" [measure] rmsnorm_rows worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62)\n" as *u8)
151 pass=pass+g_check("A2: rmsnorm_rows gradcheck -- per-token normalization backward == finite differences" as *u8, ra_ok); total=total+1
152
153 // ---- block dims + weights ----
154 let T: i64 = 2; let dm: i64 = 2; let ffn: i64 = 4; let scale: i64 = 46341
155 let X: *i64 = sys_mmap(T*dm*8) as *i64; X[0]=32768; X[1]=0-16384; X[2]=49152; X[3]=24576
156 let Wq: *i64 = sys_mmap(dm*dm*8) as *i64; Wq[0]=49152; Wq[1]=0-16384; Wq[2]=32768; Wq[3]=65536
157 let Wk: *i64 = sys_mmap(dm*dm*8) as *i64; Wk[0]=16384; Wk[1]=32768; Wk[2]=0-32768; Wk[3]=49152
158 let Wv: *i64 = sys_mmap(dm*dm*8) as *i64; Wv[0]=65536; Wv[1]=0-32768; Wv[2]=16384; Wv[3]=49152
159 let Wo: *i64 = sys_mmap(dm*dm*8) as *i64; Wo[0]=32768; Wo[1]=16384; Wo[2]=0-16384; Wo[3]=49152
160 let Wg: *i64 = sys_mmap(dm*ffn*8) as *i64; Wg[0]=32768; Wg[1]=0-16384; Wg[2]=49152; Wg[3]=16384; Wg[4]=0-32768; Wg[5]=65536; Wg[6]=24576; Wg[7]=0-8192
161 let Wu: *i64 = sys_mmap(dm*ffn*8) as *i64; Wu[0]=16384; Wu[1]=49152; Wu[2]=0-32768; Wu[3]=32768; Wu[4]=65536; Wu[5]=0-16384; Wu[6]=8192; Wu[7]=40960
162 let Wd: *i64 = sys_mmap(ffn*dm*8) as *i64; Wd[0]=32768; Wd[1]=0-16384; Wd[2]=16384; Wd[3]=49152; Wd[4]=0-32768; Wd[5]=24576; Wd[6]=40960; Wd[7]=0-8192
163 let Tg: *i64 = sys_mmap(T*dm*8) as *i64; Tg[0]=13107; Tg[1]=0-6554; Tg[2]=19661; Tg[3]=6554
164 let lv: *i64 = sys_mmap(2*8) as *i64
165
166 // ---- A3 full-block gradcheck wrt Wd (short path) ----
167 let loss3: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,Tg,T,dm,ffn,scale,lv)
168 nfa_backward(tape,vals,grads,st[0],loss3)
169 let nWd: i64 = lv[1]
170 var a3_ok: i64=1; var a3_worst: i64=0
171 var di: i64=0
172 while di < ffn*dm {
173 let ana: i64 = nfa_grad(tape,grads,nWd,di)
174 let wp: *i64 = sys_mmap(ffn*dm*8) as *i64
175 let wm: *i64 = sys_mmap(ffn*dm*8) as *i64
176 var z: i64=0
177 while z<ffn*dm { wp[z]=Wd[z]; wm[z]=Wd[z]; z=z+1 }
178 wp[di]=Wd[di]+h; wm[di]=Wd[di]-h
179 let lp: i64 = blk_lossval(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,wp,Tg,T,dm,ffn,scale)
180 let lm: i64 = blk_lossval(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,wm,Tg,T,dm,ffn,scale)
181 let fd: i64 = ((lp-lm)*Q16)/(2*h)
182 let num: i64 = g_abs(fd-ana)
183 var den: i64 = g_abs(ana); if den<floor_q { den=floor_q }
184 if num >= ((8192*den)>>16) { a3_ok=0 }
185 let rel: i64 = (num*1000)/den
186 if rel>a3_worst { a3_worst=rel }
187 di=di+1
188 }
189 g_puts(" [measure] block dL/dWd worst rel grad err = " as *u8); g_pn(a3_worst); g_puts(" /1000 (tol=125)\n" as *u8)
190 pass=pass+g_check("A3: FULL-BLOCK gradcheck wrt Wd (FFN down-proj) == finite differences" as *u8, a3_ok); total=total+1
191
192 // ---- A4 full-block gradcheck wrt Wq (the LONGEST chain: FFN<-residual<-attention<-RoPE<-softmax) ----
193 let loss4: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,Tg,T,dm,ffn,scale,lv)
194 nfa_backward(tape,vals,grads,st[0],loss4)
195 let nWq: i64 = lv[0]
196 var a4_ok: i64=1; var a4_worst: i64=0
197 var qi: i64=0
198 while qi < dm*dm {
199 let ana: i64 = nfa_grad(tape,grads,nWq,qi)
200 let wp: *i64 = sys_mmap(dm*dm*8) as *i64
201 let wm: *i64 = sys_mmap(dm*dm*8) as *i64
202 var z: i64=0
203 while z<dm*dm { wp[z]=Wq[z]; wm[z]=Wq[z]; z=z+1 }
204 wp[qi]=Wq[qi]+h; wm[qi]=Wq[qi]-h
205 let lp: i64 = blk_lossval(tape,vals,st,X,wp,Wk,Wv,Wo,Wg,Wu,Wd,Tg,T,dm,ffn,scale)
206 let lm: i64 = blk_lossval(tape,vals,st,X,wm,Wk,Wv,Wo,Wg,Wu,Wd,Tg,T,dm,ffn,scale)
207 let fd: i64 = ((lp-lm)*Q16)/(2*h)
208 let num: i64 = g_abs(fd-ana)
209 var den: i64 = g_abs(ana); if den<floor_q { den=floor_q }
210 if num >= ((16384*den)>>16) { a4_ok=0 } // tol 1/4 (longest fixed-point chain in the block)
211 let rel: i64 = (num*1000)/den
212 if rel>a4_worst { a4_worst=rel }
213 qi=qi+1
214 }
215 g_puts(" [measure] block dL/dWq (full chain) worst rel grad err = " as *u8); g_pn(a4_worst); g_puts(" /1000 (tol=250)\n" as *u8)
216 pass=pass+g_check("A4: FULL-BLOCK gradcheck wrt Wq through FFN+residual+attention+RoPE+softmax == finite diff" as *u8, a4_ok); total=total+1
217
218 // ---- D neg-control teeth (block Wd grad) ----
219 let lossd: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wd,Tg,T,dm,ffn,scale,lv)
220 nfa_backward(tape,vals,grads,st[0],lossd)
221 let dana: i64 = nfa_grad(tape,grads,lv[1],0)
222 let wp0: *i64 = sys_mmap(ffn*dm*8) as *i64
223 let wm0: *i64 = sys_mmap(ffn*dm*8) as *i64
224 var z0: i64=0
225 while z0<ffn*dm { wp0[z0]=Wd[z0]; wm0[z0]=Wd[z0]; z0=z0+1 }
226 wp0[0]=Wd[0]+h; wm0[0]=Wd[0]-h
227 let dfd: i64 = ((blk_lossval(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,wp0,Tg,T,dm,ffn,scale) - blk_lossval(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,wm0,Tg,T,dm,ffn,scale))*Q16)/(2*h)
228 let dbad: i64 = 0 - dana
229 var dden: i64 = g_abs(dana); if dden<floor_q { dden=floor_q }
230 var caught: i64 = 1
231 if g_abs(dfd-dbad) < ((8192*dden)>>16) { caught=0 }
232 pass=pass+g_check("D: neg-control -- a WRONG block gradient is rejected (teeth)" as *u8, caught); total=total+1
233
234 // ---- B the block TRAINS: fix all weights except Wd (Y linear in Wd -> convex); realizable teacher target ----
235 let Wdt: *i64 = sys_mmap(ffn*dm*8) as *i64; Wdt[0]=49152; Wdt[1]=0-32768; Wdt[2]=16384; Wdt[3]=65536; Wdt[4]=0-16384; Wdt[5]=32768; Wdt[6]=24576; Wdt[7]=0-49152
236 let tgt: *i64 = sys_mmap(T*dm*8) as *i64
237 blk_out(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wdt,T,dm,ffn,scale,tgt) // target = block output with Wd*
238 let Wdp: *i64 = sys_mmap(ffn*dm*8) as *i64
239 var zz: i64=0
240 while zz<ffn*dm { Wdp[zz]=0; zz=zz+1 } // learn Wd from zero
241 let gW: *i64 = sys_mmap(ffn*dm*8) as *i64
242 let lvb: *i64 = sys_mmap(2*8) as *i64
243 var lf: i64=0; var ll: i64=0
244 var ep: i64=0
245 while ep < 8000 {
246 let lossb: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wdp,tgt,T,dm,ffn,scale,lvb)
247 nfa_backward(tape,vals,grads,st[0],lossb)
248 if ep==0 { lf = nfa_val(tape,vals,lossb,0) }
249 ll = nfa_val(tape,vals,lossb,0)
250 var z: i64=0
251 while z<ffn*dm { gW[z]=nfa_grad(tape,grads,lvb[1],z); z=z+1 }
252 nfa_sgd(Wdp, gW, ffn*dm, 1024)
253 ep=ep+1
254 }
255 g_puts(" [measure] block train (Wd) loss: start=" as *u8); g_pn(lf); g_puts(" end=" as *u8); g_pn(ll); g_puts("\n" as *u8)
256 // (T=2,ffn=4 -> Wd is under-determined, so GD reaches a valid minimizer with loss->0, NOT necessarily Wd*;
257 // the honest evidence that the block TRAINS is the loss collapse driven by the end-to-end backward.)
258 var learns: i64 = 1
259 if ll*20 > lf { learns=0 } // >= 95% loss reduction (loss collapses to ~0)
260 if lf <= 100 { learns=0 } // started genuinely untrained
261 pass=pass+g_check("B: the BLOCK TRAINS -- the FFN down-proj is driven by the block's end-to-end backward; loss collapses to ~0" as *u8, learns); total=total+1
262
263 // ---- C bit-exact ----
264 let Wdp2: *i64 = sys_mmap(ffn*dm*8) as *i64
265 var z2: i64=0
266 while z2<ffn*dm { Wdp2[z2]=0; z2=z2+1 }
267 let gW2: *i64 = sys_mmap(ffn*dm*8) as *i64
268 let lvc: *i64 = sys_mmap(2*8) as *i64
269 var ep2: i64=0
270 while ep2 < 8000 {
271 let lossc: i64 = blk_loss(tape,vals,st,X,Wq,Wk,Wv,Wo,Wg,Wu,Wdp2,tgt,T,dm,ffn,scale,lvc)
272 nfa_backward(tape,vals,grads,st[0],lossc)
273 var z: i64=0
274 while z<ffn*dm { gW2[z]=nfa_grad(tape,grads,lvc[1],z); z=z+1 }
275 nfa_sgd(Wdp2, gW2, ffn*dm, 1024)
276 ep2=ep2+1
277 }
278 var bitexact: i64 = 1
279 var zc: i64=0
280 while zc<ffn*dm { if Wdp2[zc]!=Wdp[zc] { bitexact=0 } zc=zc+1 }
281 pass=pass+g_check("C: bit-exact -- training the block twice gives IDENTICAL integer Wd (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(BLOG, 420)
286 if logf >= 0 {
287 b_ws(logf,"NOFLOATBLOCK pre-norm single-head A1_had=" as *u8); b_wn(logf,ha_ok); b_ws(logf," A2_rmsrows=" as *u8); b_wn(logf,ra_ok)
288 b_ws(logf," A3_Wd=" as *u8); b_wn(logf,a3_ok); b_ws(logf," A4_Wq_fullchain=" as *u8); b_wn(logf,a4_ok); b_ws(logf," D=" as *u8); b_wn(logf,caught)
289 b_ws(logf," B_trains=" as *u8); b_wn(logf,learns); b_ws(logf," C_bitexact=" as *u8); b_wn(logf,bitexact)
290 if okall==1 { b_ws(logf," verdict=GREEN\n" as *u8) } else { b_ws(logf," verdict=RED\n" as *u8) }
291 sys_close(logf)
292 }
293 g_puts("---- nofloat_block 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-BLOCK-GATE" as *u8, ctr__dry, "a full pre-norm transformer block backprops + trains in pure integer Q16)" as *u8)
301 sys_exit(rc__dry)
302 return rc__dry
303}