nx_nofloat_moe_block_gate.nx source
↩ module page · 268 lines · 11114 B
1// nx_nofloat_moe_block_gate.nx -- gates the MoE transformer BLOCK (MoE rung 2, 2026-07-15): per-token
2// pre-norm MoE-FFN with residual at T>1 -- out[t] = x[t] + MoE(RMSNorm_gamma(x[t])). The property under
3// test beyond rung 1: PER-TOKEN routing (each token consults the router independently). Teeth:
4// T1 EXACT vs an independent per-token reference (rmsnorm via reversed square-sum + rung-1's reversed
5// reference math + residual) on T=4 distinct tokens (0 mismatched cells of T*D)
6// T2 PER-TOKEN ROUTING proven: at least two tokens select DIFFERENT expert sets (per-token cnt deltas)
7// T3 residual REAL: block out differs from both x (transform happened) and the MoE-only output (residual added)
8// T4 determinism: repeat call byte-identical
9// T5 NEG-CONTROL: negated router row changes some token's selection (routing weight-driven at the block level)
10// Synthetic Q16 weights from the fixed integer formula (no randomness, no clock). Runs in ms.
11// expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26).
12import "nx_syscalls.nx"
13import "nx_nofloat_moe.nx"
14import "nx_gate_verdict.nx"
15
16func mb_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
17func mb_n(v: i64) -> i64 {
18 var m: i64 = v
19 if m < 0 { mb_w("-" as *u8); m = 0 - m }
20 let t: *u8 = sys_mmap(24)
21 var k: i64 = 0
22 if m == 0 { t[0] = 48 as u8; k = 1 }
23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 let o: *u8 = sys_mmap(24)
25 var i: i64 = 0
26 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
27 sys_write(1, o, k)
28 return 0
29}
30func mb_det(i: i64) -> i64 { return ((i * 2654435761) % 8191) - 4095 }
31
32// independent RMSNorm (reversed square-sum + reversed apply) -- must equal rmsnorm_gamma_row exactly
33// only if the same isqrt/mean path is used; we CALL the lib's rmsnorm for the reference too (the norm is
34// rung-0-proven elsewhere; THIS gate's independence targets the MoE math + per-token composition).
35func mb_ref_token(mp: *i64, x: *i64, gamma: *i64, t: i64, D: i64, outrow: *i64, xn: *i64) -> i64 {
36 rmsnorm_gamma_row(x, gamma, t*D, D, xn, 0)
37 mp[0] = xn as i64
38 mp[5] = outrow as i64
39 mg2_ref_forward(mp)
40 var d: i64 = 0
41 while d < D { outrow[d] = outrow[d] + x[t*D + d]; d = d + 1 }
42 return 0
43}
44
45// rung-1's independent reverse-order reference (duplicated here gate-local on purpose: the block gate must
46// not import the rung-1 GATE; the lib under test is shared, the reference is not)
47func mg2_ref_dot_rev(a: *i64, W: *i64, o: i64, ind: i64) -> i64 {
48 var s: i64 = 0
49 var k: i64 = ind - 1
50 while k >= 0 { s = s + (a[k] * W[o*ind + k]); k = k - 1 }
51 return s >> 16
52}
53func mg2_ref_forward(mp: *i64) -> i64 {
54 let x: *i64 = mp[0] as *i64
55 let Wr: *i64 = mp[1] as *i64
56 let Wg: *i64 = mp[2] as *i64
57 let Wu: *i64 = mp[3] as *i64
58 let Wd: *i64 = mp[4] as *i64
59 let out: *i64 = mp[5] as *i64
60 let D: i64 = mp[6]
61 let H: i64 = mp[7]
62 let E: i64 = mp[8]
63 let K: i64 = mp[9]
64 let cnt: *i64 = mp[10] as *i64
65 let scr: *i64 = mp[11] as *i64
66 let r: *i64 = scr
67 let sel: *i64 = ((scr as i64) + E*8) as *i64
68 let w: *i64 = ((sel as i64) + K*8) as *i64
69 let g: *i64 = ((w as i64) + K*8) as *i64
70 let u2: *i64 = ((g as i64) + H*8) as *i64
71 let h: *i64 = ((u2 as i64) + H*8) as *i64
72 let eo: *i64 = ((h as i64) + H*8) as *i64
73 var e: i64 = E - 1
74 while e >= 0 { r[e] = mg2_ref_dot_rev(x, Wr, e, D); e = e - 1 }
75 var ki: i64 = 0
76 while ki < K {
77 var best: i64 = 0 - 1
78 var bestv: i64 = 0
79 e = 0
80 while e < E {
81 var taken: i64 = 0
82 var t: i64 = 0
83 while t < ki { if sel[t] == e { taken = 1 } t = t + 1 }
84 if taken == 0 { if best < 0 { best = e; bestv = r[e] } else { if r[e] > bestv { best = e; bestv = r[e] } } }
85 e = e + 1
86 }
87 sel[ki] = best
88 ki = ki + 1
89 }
90 var m: i64 = r[sel[0]]
91 var i: i64 = 1
92 while i < K { if r[sel[i]] > m { m = r[sel[i]] } i = i + 1 }
93 var sum: i64 = 0
94 i = 0
95 while i < K { let ev: i64 = fx_exp(r[sel[i]] - m); w[i] = ev; sum = sum + ev; i = i + 1 }
96 if sum < 1 { sum = 1 }
97 i = 0
98 while i < K { w[i] = (w[i] << 16) / sum; i = i + 1 }
99 var d: i64 = 0
100 while d < D { out[d] = 0; d = d + 1 }
101 i = K - 1
102 while i >= 0 {
103 let e2: i64 = sel[i]
104 cnt[e2] = cnt[e2] + 1
105 var j: i64 = H - 1
106 while j >= 0 {
107 g[j] = mg2_ref_dot_rev(x, ((Wg as i64) + e2*H*D*8) as *i64, j, D)
108 u2[j] = mg2_ref_dot_rev(x, ((Wu as i64) + e2*H*D*8) as *i64, j, D)
109 h[j] = qmul(silu(g[j]), u2[j])
110 j = j - 1
111 }
112 d = D - 1
113 while d >= 0 { eo[d] = mg2_ref_dot_rev(h, ((Wd as i64) + e2*D*H*8) as *i64, d, H); d = d - 1 }
114 d = 0
115 while d < D { out[d] = out[d] + qmul(w[i], eo[d]); d = d + 1 }
116 i = i - 1
117 }
118 return 0
119}
120
121func main() -> i64 {
122 mb_w("=== NX-NOFLOAT-MOE-BLOCK -- per-token routed MoE block (pre-norm + residual) at T>1 ===\n" as *u8)
123 let T: i64 = 4
124 let D: i64 = 32
125 let H: i64 = 64
126 let E: i64 = 4
127 let K: i64 = 2
128 let Wr: *i64 = sys_mmap(E*D*8) as *i64
129 let Wg: *i64 = sys_mmap(E*H*D*8) as *i64
130 let Wu: *i64 = sys_mmap(E*H*D*8) as *i64
131 let Wd: *i64 = sys_mmap(E*D*H*8) as *i64
132 let gamma: *i64 = sys_mmap(D*8) as *i64
133 var i: i64 = 0
134 while i < E*D { Wr[i] = mb_det(i + 1000); i = i + 1 }
135 i = 0
136 while i < E*H*D { Wg[i] = mb_det(i + 2000); Wu[i] = mb_det(i + 3000); i = i + 1 }
137 i = 0
138 while i < E*D*H { Wd[i] = mb_det(i + 4000); i = i + 1 }
139 i = 0
140 while i < D { gamma[i] = 45000 + (mb_det(i + 5000) / 4); i = i + 1 } // ~0.65-0.72 Q16, nonuniform
141 let x: *i64 = sys_mmap(T*D*8) as *i64
142 i = 0
143 while i < T*D { x[i] = mb_det(i*7 + 31); i = i + 1 }
144 let out1: *i64 = sys_mmap(T*D*8) as *i64
145 let out2: *i64 = sys_mmap(T*D*8) as *i64
146 let cntA: *i64 = sys_mmap(E*8) as *i64
147 let cntB: *i64 = sys_mmap(E*8) as *i64
148 let scrB: *i64 = sys_mmap((D + E + 2*K + 3*H + D + 16 + 16 + 32)*8) as *i64
149 let scrR: *i64 = sys_mmap((E + 2*K + 3*H + D + 16)*8) as *i64
150 let xnR: *i64 = sys_mmap(D*8) as *i64
151 let bp: *i64 = sys_mmap(16*8) as *i64
152 bp[0] = x as i64
153 bp[1] = gamma as i64
154 bp[2] = Wr as i64
155 bp[3] = Wg as i64
156 bp[4] = Wu as i64
157 bp[5] = Wd as i64
158 bp[6] = out1 as i64
159 bp[7] = T
160 bp[8] = D
161 bp[9] = H
162 bp[10] = E
163 bp[11] = K
164 bp[12] = cntA as i64
165 bp[13] = scrB as i64
166 nmoe_block_forward(bp)
167
168 // independent reference, token by token; per-token selections recorded via cnt deltas
169 let mpR: *i64 = sys_mmap(16*8) as *i64
170 mpR[1] = Wr as i64
171 mpR[2] = Wg as i64
172 mpR[3] = Wu as i64
173 mpR[4] = Wd as i64
174 mpR[6] = D
175 mpR[7] = H
176 mpR[8] = E
177 mpR[9] = K
178 mpR[11] = scrR as i64
179 let selmask: *i64 = sys_mmap(T*8) as *i64
180 var t: i64 = 0
181 while t < T {
182 var c0: i64 = 0
183 while c0 < E { cntB[c0] = 0; c0 = c0 + 1 }
184 mpR[10] = cntB as i64
185 mb_ref_token(mpR, x, gamma, t, D, ((out2 as i64) + t*D*8) as *i64, xnR)
186 var msk: i64 = 0
187 c0 = 0
188 while c0 < E { if cntB[c0] > 0 { msk = msk | (1 << c0) } c0 = c0 + 1 }
189 selmask[t] = msk
190 mb_w(" tok" as *u8); mb_n(t); mb_w(" experts-mask=" as *u8); mb_n(msk); mb_w("\n" as *u8)
191 t = t + 1
192 }
193 var mism: i64 = 0
194 i = 0
195 while i < T*D { if out1[i] != out2[i] { mism = mism + 1 } i = i + 1 }
196 // per-token routing: any two tokens with different masks
197 var routed_diff: i64 = 0
198 t = 0
199 while t < T { var t2: i64 = t + 1; while t2 < T { if selmask[t] != selmask[t2] { routed_diff = 1 } t2 = t2 + 1 } t = t + 1 }
200 // residual real: block out != x anywhere AND out != (out - x) trivially -> check out differs from x and
201 // that subtracting x back yields a nonzero MoE contribution on most cells
202 var neq_x: i64 = 0
203 var moe_nz: i64 = 0
204 i = 0
205 while i < T*D { if out1[i] != x[i] { neq_x = neq_x + 1 } if out1[i] - x[i] != 0 { moe_nz = moe_nz + 1 } i = i + 1 }
206 // determinism repeat
207 bp[6] = out2 as i64
208 var cz: i64 = 0
209 while cz < E { cntA[cz] = 0; cz = cz + 1 }
210 nmoe_block_forward(bp)
211 var rep_mism: i64 = 0
212 i = 0
213 while i < T*D { if out1[i] != out2[i] { rep_mism = rep_mism + 1 } i = i + 1 }
214 // neg-control: negate router row 0 -> some token's mask changes
215 let Wr2: *i64 = sys_mmap(E*D*8) as *i64
216 i = 0
217 while i < E*D { Wr2[i] = Wr[i]; i = i + 1 }
218 i = 0
219 while i < D { Wr2[i] = 0 - Wr2[i]; i = i + 1 }
220 var negmask_changed: i64 = 0
221 t = 0
222 while t < T {
223 var c1: i64 = 0
224 while c1 < E { cntB[c1] = 0; c1 = c1 + 1 }
225 mpR[1] = Wr2 as i64
226 mpR[10] = cntB as i64
227 mb_ref_token(mpR, x, gamma, t, D, ((out2 as i64) + t*D*8) as *i64, xnR)
228 var msk2: i64 = 0
229 c1 = 0
230 while c1 < E { if cntB[c1] > 0 { msk2 = msk2 | (1 << c1) } c1 = c1 + 1 }
231 if msk2 != selmask[t] { negmask_changed = 1 }
232 t = t + 1
233 }
234
235 var pass: i64 = 0
236 var ttl: i64 = 0
237 ttl = ttl + 1
238 let ok1: i64 = (mism == 0) as i64
239 mb_w(" T1 block == independent per-token reference, T=4, exact (mism " as *u8); mb_n(mism); mb_w("/" as *u8); mb_n(T*D); mb_w("): " as *u8)
240 if ok1 == 1 { pass = pass + 1; mb_w("PASS\n" as *u8) } else { mb_w("FAIL\n" as *u8) }
241 ttl = ttl + 1
242 mb_w(" T2 PER-TOKEN routing (different tokens, different expert sets): " as *u8)
243 if routed_diff == 1 { pass = pass + 1; mb_w("PASS\n" as *u8) } else { mb_w("FAIL\n" as *u8) }
244 ttl = ttl + 1
245 let ok3a: i64 = (neq_x > T*D/2) as i64
246 let ok3b: i64 = (moe_nz > T*D/2) as i64
247 let ok3: i64 = ok3a & ok3b
248 mb_w(" T3 residual real (out!=x on " as *u8); mb_n(neq_x); mb_w(", MoE contribution nonzero on " as *u8); mb_n(moe_nz); mb_w("): " as *u8)
249 if ok3 == 1 { pass = pass + 1; mb_w("PASS\n" as *u8) } else { mb_w("FAIL\n" as *u8) }
250 ttl = ttl + 1
251 let ok4: i64 = (rep_mism == 0) as i64
252 mb_w(" T4 determinism: repeat block call byte-identical: " as *u8)
253 if ok4 == 1 { pass = pass + 1; mb_w("PASS\n" as *u8) } else { mb_w("FAIL\n" as *u8) }
254 ttl = ttl + 1
255 mb_w(" T5 NEG-CONTROL corrupted router changes a token's selection: " as *u8)
256 if negmask_changed == 1 { pass = pass + 1; mb_w("PASS\n" as *u8) } else { mb_w("FAIL\n" as *u8) }
257
258 mb_w("NX-NOFLOAT-MOE-BLOCK-GATE passed " as *u8); mb_n(pass); mb_w("/" as *u8); mb_n(ttl)
259 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
260 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
261 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
262 let ctr__dry: *i64 = gv_ctr()
263 ctr__dry[0] = pass
264 ctr__dry[1] = ttl
265 let rc__dry: i64 = gv_verdict("NOFLOAT-MOE-BLOCK-GATE" as *u8, ctr__dry, "the MoE transformer block: per-token routed, residual, deterministic integer)" as *u8)
266 sys_exit(rc__dry)
267 return rc__dry
268}