nx_q4k_matmul_x4_gate.nx source
↩ module page · 314 lines · 11851 B
1// nx_q4k_matmul_x4_gate.nx -- adversarial gate for the PACKED-SIMD
2// Q4_K matmul paths (nx_f32_q4k_matmul_x4 / _pool_x4) against the
3// scalar serial oracle nx_f32_q4k_matmul.
4//
5// NUMERIC REGIME: the x4 path sums each output cell as left-to-right
6// 4-lane dot chunks -- a different f32 rounding order than scalar.
7// This gate therefore constructs data where EVERY intermediate sum is
8// an integer with |sum| < 2^24, so f32 addition is EXACT regardless
9// of order and bit-exact comparison across ALL paths is legitimate:
10// * weights: dense synthetic Q4_K blocks with d=1.0 (f16 0x3C00),
11// dmin=0, all 6-bit scales=1, mins=0, LCG nibble bytes -> every
12// dequantized value is an exact integer 0..15;
13// * A: exact small-int f32 (nx_i32_to_f32 of LCG ints).
14// k=512 lanes, |A|<=512, w<=15 -> |cell| <= 512*15*512 = 3.9M < 2^24.
15// Big shape k=1024, |A|<=512 -> <= 7.9M < 2^24. Exact.
16// (ULP-divergent real-model fidelity is witnessed separately by the
17// argmax probe -- " Paris" -- after the dispatcher flip.)
18//
19// pool-x4 vs serial-x4 equality holds on ANY data (identical per-cell
20// order; column banding never splits a cell) -- asserted here too.
21//
22// Checks (10):
23// 1 scalar serial oracle OK (m=3, k=512, n=37 -- prime n)
24// 2 serial-x4 == scalar bit-exact
25// 3 pool-x4 (auto pool) == serial-x4 bit-exact
26// 4 pool-x4 (3-worker pool, odd banding) == serial-x4
27// 5 pool reuse: second call, new A, same pool == fresh serial-x4
28// 6 m=1 decode shape: serial-x4 == scalar
29// 7 wide-A (+-512 ints): serial-x4 == scalar (exact-regime bound)
30// 8 n=1 single-column edge via pool (band clamp) == scalar
31// 9 SPEEDUP ladder on decode shape m=1 k=1024 n=4864: serial-scalar
32// vs pool-scalar vs pool-x4 (all bit-exact vs each other in this
33// regime); floor: pool-x4 >= 2.5x serial-scalar (measured printed)
34// 10 all three big-shape outputs bit-identical
35//
36// genealogy_id: nx_f32x4_mt_matmul (5.0x packed lever) + q4k_matmul_mt_gate
37// lineage_id: q4k_matmul_x4_gate_v1
38
39import "nx_f32_q4k_matmul.nx"
40import "nx_fmt.nx"
41import "nx_gate_verdict.nx"
42
43const XG_M: i64 = 3
44const XG_K: i64 = 512
45const XG_N: i64 = 37
46
47const XB_K: i64 = 1024
48const XB_N: i64 = 4864
49const XB_REPS: i64 = 3
50
51const XG_SPEEDUP_FLOOR_X100: i64 = 250
52
53func x_lcg(s: i64) -> i64 {
54 var v: i64 = s * 1103515245 + 12345
55 v = v & 2147483647
56 return v
57}
58
59// Dense exact-regime Q4_K super-block: d=1.0, dmin=0, sc[0..7]=1,
60// m[0..7]=0, LCG nibble bytes -> dequant values = exact ints 0..15.
61func x_block_dense(buf: *u8, off: i64, seed: i64) -> i64 {
62 buf[off + 0] = 0x00 as u8
63 buf[off + 1] = 0x3C as u8 // d = f16 1.0 (LE)
64 buf[off + 2] = 0 as u8
65 buf[off + 3] = 0 as u8 // dmin = 0
66 var i: i64 = 0
67 while i < 4 {
68 buf[off + 4 + i] = 0x01 as u8 // sc0..3 = 1 (high bits 0)
69 buf[off + 8 + i] = 0x00 as u8 // m0..3 = 0 (high bits 0)
70 buf[off + 12 + i] = 0x01 as u8 // sc4..7 = 1 (low nib), m4..7 = 0 (high nib)
71 i = i + 1
72 }
73 var s: i64 = seed
74 var z: i64 = 0
75 while z < 128 {
76 s = x_lcg(s)
77 buf[off + 16 + z] = (s & 255) as u8
78 z = z + 1
79 }
80 return off + 144
81}
82
83// n_rows weight rows, each (k/256) dense blocks.
84func x_fill_weights(buf: *u8, n_rows: i64, k: i64, seed: i64) -> i64 {
85 let bpr: i64 = (k / 256) * 144
86 var s: i64 = seed
87 var r: i64 = 0
88 while r < n_rows {
89 var b: i64 = 0
90 while b < k / 256 {
91 s = x_lcg(s)
92 x_block_dense(buf, r * bpr + b * 144, s)
93 b = b + 1
94 }
95 r = r + 1
96 }
97 return 0
98}
99
100// A fill: exact ints in [-half, half-1] as f32.
101func x_fill_a(p: *i64, count: i64, seed: i64, half: i64) -> i64 {
102 var s: i64 = seed
103 var i: i64 = 0
104 while i < count {
105 s = x_lcg(s)
106 let v: i64 = (s % (half + half)) - half
107 p[i] = nx_i32_to_f32(v)
108 i = i + 1
109 }
110 return 0
111}
112
113func x_poison(p: *i64, count: i64) -> i64 {
114 let pv: i64 = 0 - 777777
115 var i: i64 = 0
116 while i < count {
117 p[i] = pv
118 i = i + 1
119 }
120 return 0
121}
122
123func x_same(a: *i64, b: *i64, count: i64) -> i64 {
124 var i: i64 = 0
125 while i < count {
126 if a[i] != b[i] { return 0 }
127 i = i + 1
128 }
129 return 1
130}
131
132func x_nl() -> i64 {
133 fmt_puts("\n" as *u8)
134 return 0
135}
136
137func main() -> i64 {
138 let a_n: i64 = XG_M * XG_K
139 let b_n: i64 = XG_N * (XG_K / 256) * 144
140 let c_n: i64 = XG_M * XG_N
141 let A: *i64 = sys_mmap(a_n * 8) as *i64
142 let B: *u8 = sys_mmap(b_n)
143 let Cs: *i64 = sys_mmap(c_n * 8) as *i64
144 let Cx: *i64 = sys_mmap(c_n * 8) as *i64
145 let Cp: *i64 = sys_mmap(c_n * 8) as *i64
146 x_fill_a(A, a_n, 20260708, 5)
147 x_fill_weights(B, XG_N, XG_K, 424242)
148
149 var pass: i64 = 0
150
151 // ---- 1: scalar oracle ----
152 let v1: nx_int = nx_f32_q4k_matmul(A, B, 0, Cs, XG_M, XG_K, XG_N)
153 if v1 != NX_FQ4M_OK { fmt_puts("X4G 1 SCALAR FAIL"); x_nl(); return 11 }
154 fmt_puts("X4G 1 SCALAR OK"); x_nl()
155 pass = pass + 1
156
157 // ---- 2: serial-x4 == scalar ----
158 x_poison(Cx, c_n)
159 let v2: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N)
160 var ok2: i64 = 0
161 if v2 == NX_FQ4M_OK { ok2 = x_same(Cx, Cs, c_n) }
162 if ok2 != 1 { fmt_puts("X4G 2 X4-SERIAL FAIL"); x_nl(); return 12 }
163 fmt_puts("X4G 2 X4-SERIAL EXACT OK"); x_nl()
164 pass = pass + 1
165
166 // ---- 3: pool-x4 (auto) == serial-x4 ----
167 let poolA: *NxThreadPool = nx_pool_new(0, 0)
168 x_poison(Cp, c_n)
169 let v3: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, A, B, 0, Cp, XG_M, XG_K, XG_N)
170 var ok3: i64 = 0
171 if v3 == NX_FQ4M_OK { ok3 = x_same(Cp, Cx, c_n) }
172 if ok3 != 1 { fmt_puts("X4G 3 POOL-AUTO FAIL"); x_nl(); return 13 }
173 fmt_puts("X4G 3 POOL-AUTO EXACT OK"); x_nl()
174 pass = pass + 1
175
176 // ---- 4: pool-x4 (3 workers, odd banding over prime n) ----
177 let pool3: *NxThreadPool = nx_pool_new(3, 0)
178 x_poison(Cp, c_n)
179 let v4: nx_int = nx_f32_q4k_matmul_pool_x4(pool3, A, B, 0, Cp, XG_M, XG_K, XG_N)
180 var ok4: i64 = 0
181 if v4 == NX_FQ4M_OK { ok4 = x_same(Cp, Cx, c_n) }
182 if ok4 != 1 { fmt_puts("X4G 4 POOL-3 FAIL"); x_nl(); return 14 }
183 fmt_puts("X4G 4 POOL-3 EXACT OK"); x_nl()
184 pass = pass + 1
185
186 // ---- 5: pool reuse, new A contents, same pools ----
187 x_fill_a(A, a_n, 555008, 5)
188 let v5s: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N)
189 if v5s != NX_FQ4M_OK { return 15 }
190 x_poison(Cp, c_n)
191 let v5: nx_int = nx_f32_q4k_matmul_pool_x4(pool3, A, B, 0, Cp, XG_M, XG_K, XG_N)
192 var ok5: i64 = 0
193 if v5 == NX_FQ4M_OK { ok5 = x_same(Cp, Cx, c_n) }
194 nx_pool_shutdown(pool3)
195 if ok5 != 1 { fmt_puts("X4G 5 POOL-REUSE FAIL"); x_nl(); return 15 }
196 fmt_puts("X4G 5 POOL-REUSE EXACT OK"); x_nl()
197 pass = pass + 1
198
199 // ---- 6: m=1 decode shape ----
200 let c1: *i64 = sys_mmap(XG_N * 8) as *i64
201 let c1x: *i64 = sys_mmap(XG_N * 8) as *i64
202 let v6s: nx_int = nx_f32_q4k_matmul(A, B, 0, c1, 1, XG_K, XG_N)
203 x_poison(c1x, XG_N)
204 let v6x: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, c1x, 1, XG_K, XG_N)
205 var ok6: i64 = 0
206 if v6s == NX_FQ4M_OK { if v6x == NX_FQ4M_OK { ok6 = x_same(c1x, c1, XG_N) } }
207 if ok6 != 1 { fmt_puts("X4G 6 M1 FAIL"); x_nl(); return 16 }
208 fmt_puts("X4G 6 M1 EXACT OK"); x_nl()
209 pass = pass + 1
210
211 // ---- 7: wide-A ints (+-512), still exact regime ----
212 x_fill_a(A, a_n, 909008, 512)
213 let v7s: nx_int = nx_f32_q4k_matmul(A, B, 0, Cs, XG_M, XG_K, XG_N)
214 x_poison(Cx, c_n)
215 let v7x: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N)
216 var ok7: i64 = 0
217 if v7s == NX_FQ4M_OK { if v7x == NX_FQ4M_OK { ok7 = x_same(Cx, Cs, c_n) } }
218 if ok7 != 1 { fmt_puts("X4G 7 WIDE-A FAIL"); x_nl(); return 17 }
219 fmt_puts("X4G 7 WIDE-A EXACT OK"); x_nl()
220 pass = pass + 1
221
222 // ---- 8: n=1 single column via pool (band clamp 16 -> 1) ----
223 let cs1: *i64 = sys_mmap(XG_M * 8) as *i64
224 let cp1: *i64 = sys_mmap(XG_M * 8) as *i64
225 let v8s: nx_int = nx_f32_q4k_matmul(A, B, 0, cs1, XG_M, XG_K, 1)
226 x_poison(cp1, XG_M)
227 let v8p: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, A, B, 0, cp1, XG_M, XG_K, 1)
228 var ok8: i64 = 0
229 if v8s == NX_FQ4M_OK { if v8p == NX_FQ4M_OK { ok8 = x_same(cp1, cs1, XG_M) } }
230 if ok8 != 1 { fmt_puts("X4G 8 N1-CLAMP FAIL"); x_nl(); return 18 }
231 fmt_puts("X4G 8 N1-CLAMP EXACT OK"); x_nl()
232 pass = pass + 1
233
234 // ---- 9+10: speedup ladder on the decode shape ----
235 let ba_n: i64 = XB_K
236 let bb_n: i64 = XB_N * (XB_K / 256) * 144
237 let bc_n: i64 = XB_N
238 let BA: *i64 = sys_mmap(ba_n * 8) as *i64
239 let BB: *u8 = sys_mmap(bb_n)
240 let BC0: *i64 = sys_mmap(bc_n * 8) as *i64
241 let BC1: *i64 = sys_mmap(bc_n * 8) as *i64
242 let BC2: *i64 = sys_mmap(bc_n * 8) as *i64
243 x_fill_a(BA, ba_n, 7788, 512)
244 x_fill_weights(BB, XB_N, XB_K, 313373)
245
246 let t0: i64 = sys_now_us()
247 let vb0: nx_int = nx_f32_q4k_matmul(BA, BB, 0, BC0, 1, XB_K, XB_N)
248 let us_scalar: i64 = sys_now_us() - t0
249 if vb0 != NX_FQ4M_OK { return 21 }
250
251 x_poison(BC1, bc_n)
252 let t1: i64 = sys_now_us()
253 var r1: i64 = 0
254 while r1 < XB_REPS {
255 let vb1: nx_int = nx_f32_q4k_matmul_pool(poolA, BA, BB, 0, BC1, 1, XB_K, XB_N)
256 if vb1 != NX_FQ4M_OK { return 22 }
257 r1 = r1 + 1
258 }
259 let us_ps: i64 = (sys_now_us() - t1) / XB_REPS
260
261 x_poison(BC2, bc_n)
262 let t2: i64 = sys_now_us()
263 var r2: i64 = 0
264 while r2 < XB_REPS {
265 let vb2: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, BA, BB, 0, BC2, 1, XB_K, XB_N)
266 if vb2 != NX_FQ4M_OK { return 23 }
267 r2 = r2 + 1
268 }
269 let us_px: i64 = (sys_now_us() - t2) / XB_REPS
270 nx_pool_shutdown(poolA)
271
272 let macs: i64 = XB_K * XB_N
273 var us_a: i64 = us_scalar
274 if us_a < 1 { us_a = 1 }
275 var us_b: i64 = us_ps
276 if us_b < 1 { us_b = 1 }
277 var us_c: i64 = us_px
278 if us_c < 1 { us_c = 1 }
279 fmt_puts("serial_scalar_us="); fmt_putn(us_a); fmt_puts(" mflops="); fmt_putn(2 * macs / us_a); x_nl()
280 fmt_puts("pool_scalar_us="); fmt_putn(us_b); fmt_puts(" mflops="); fmt_putn(2 * macs / us_b); x_nl()
281 fmt_puts("pool_x4_us="); fmt_putn(us_c); fmt_puts(" mflops="); fmt_putn(2 * macs / us_c); x_nl()
282 let sx100: i64 = us_a * 100 / us_c
283 fmt_puts("x4_vs_scalar_x100="); fmt_putn(sx100); x_nl()
284
285 if sx100 < XG_SPEEDUP_FLOOR_X100 {
286 fmt_puts("X4G 9 SPEEDUP FAIL"); x_nl()
287 return 24
288 }
289 fmt_puts("X4G 9 SPEEDUP OK"); x_nl()
290 pass = pass + 1
291
292 var okb: i64 = x_same(BC1, BC0, bc_n)
293 if okb == 1 { okb = x_same(BC2, BC0, bc_n) }
294 if okb != 1 {
295 fmt_puts("X4G 10 BIG-TRIPLE-EXACT FAIL"); x_nl()
296 return 25
297 }
298 fmt_puts("X4G 10 BIG-TRIPLE-EXACT OK"); x_nl()
299 pass = pass + 1
300
301 fmt_puts("Q4K_MATMUL_X4_GATE "); fmt_putn(pass); fmt_puts("/10 GREEN"); x_nl()
302 // MIGRATED onto nx_gate_verdict (D001, minimal form). Every check row above is UNTOUCHED, so the
303 // PASS/FAIL vector cannot change; only the hand-rolled verdict emission is replaced by the one
304 // shared base class. WHY IT MATTERS BEYOND HYGIENE: all three Q4_K gates rolled their own verdict,
305 // so /api/promote refused all three, so /api/gate_run could never find <name>.elf -- which left the
306 // Q4_K matmul with NO PROMOTABLE ORACLE AT ALL and effectively FROZE the kernel. Not by anyone
307 // deciding it should be frozen, but because a verdict-hygiene rule was never counted against the
308 // gates it disqualifies. Migrating ONE gate restores the ability to verify the whole subsystem.
309 let ctr__dry: *i64 = gv_ctr()
310 ctr__dry[0] = pass
311 ctr__dry[1] = 10
312 let rc__dry: i64 = gv_verdict("Q4K-MATMUL-X4-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto nx_gate_verdict so the evidence plane can read it" as *u8)
313 return rc__dry
314}