code wiki / _hdl_build / nx_nofloat_muon_gate.nx
nx_nofloat_muon_gate.nx source
↩ module page · 151 lines · 7476 B
1// nx_nofloat_muon_gate.nx -- gate: the FULL Per-Head Muon optimizer loop (momentum + NS-orthogonalize +
2// apply), deterministic, per-head. Honest scope: proves the OPTIMIZER STEP mechanics + the novel exceed
3// (bit-exact), NOT a full training convergence run (that rides the GPU seat F101).
4// T1 MOMENTUM heavy-ball: repeated aligned grads grow the buffer beyond a single grad (geometric sum)
5// T2 ORTHOGONALIZED update: U = NS(momentum) has far lower orthogonality error than the raw momentum
6// T3 UPDATE APPLIED EXACTLY: W_after == W_before - lr*U elementwise (mechanical correctness)
7// T4 DETERMINISTIC: two identical per-head runs -> bit-identical weights (the exceed: float Muon drifts)
8// T5 PER-HEAD INDEPENDENCE: perturbing head-0's grad changes head-0's W but NOT head-1's W
9// T6 STABLE: 12 steps stay bounded (no blowup)
10// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
11import "nx_nofloat_muon.nx"
12import "nx_nofloat_muon_ns.nx"
13import "nx_gate_verdict.nx"
14import "nx_syscalls.nx"
15
16const UG_Q: i64 = 65536
17const UG_MU: i64 = 58982 // 0.9 momentum
18const UG_LR: i64 = 6553 // 0.1 learning rate
19
20func ug_abs(x: i64) -> i64 { if x < 0 { return 0 - x } return x }
21func ug_copy(src: *i64, dst: *i64, nn: i64) -> i64 { var i: i64 = 0; while i < nn { dst[i] = src[i]; i = i + 1 } return 0 }
22// |X|_1 sum of abs
23func ug_l1(x: *i64, nn: i64) -> i64 { var s: i64 = 0; var i: i64 = 0; while i < nn { s = s + ug_abs(x[i]); i = i + 1 } return s }
24
25func main() -> i64 {
26 let ctr: *i64 = gv_ctr()
27 gv_head("nx_nofloat_muon gate -- full Per-Head Muon optimizer loop (momentum + NS + apply), deterministic" as *u8)
28 let n: i64 = 4
29 let nn: i64 = n * n
30
31 // a well-conditioned-ish gradient matrix (Q16)
32 let grad: *i64 = sys_mmap(64*8) as *i64
33 var i: i64 = 0
34 while i < nn { grad[i] = (((i % 4) + 1) * (UG_Q / 5)) - (UG_Q/3); i = i + 1 }
35 let u: *i64 = sys_mmap(64*8) as *i64
36
37 // ---- T1: momentum heavy-ball accumulation ----
38 let buf1: *i64 = sys_mmap(64*8) as *i64
39 ug_copy(grad, buf1, nn) // buf = grad (first step, no prior momentum) -- start from grad-sized
40 i = 0
41 while i < nn { buf1[i] = 0; i = i + 1 }
42 mu_momentum(buf1, grad, UG_MU, nn); let l1a: i64 = ug_l1(buf1, nn) // after 1
43 mu_momentum(buf1, grad, UG_MU, nn); mu_momentum(buf1, grad, UG_MU, nn); let l1c: i64 = ug_l1(buf1, nn) // after 3
44 var t1: i64 = 0
45 if l1c > (l1a + (l1a/2)) { t1 = 1 } // 3-step momentum > 1.5x single-step (geometric growth)
46 gv_check("T1 MOMENTUM heavy-ball: 3 aligned grads accumulate > 1.5x a single grad" as *u8, t1, ctr)
47
48 // ---- T2: NS-orthogonalized update vs raw momentum ----
49 let bufo: *i64 = sys_mmap(64*8) as *i64
50 ug_copy(grad, bufo, nn)
51 mu_momentum(bufo, grad, UG_MU, nn) // some momentum matrix
52 let errbuf: i64 = mn_ortho_err(bufo, n) // orthogonality error of the RAW momentum
53 mn_orthogonalize(bufo, u, n) // U = NS(momentum)
54 let erru: i64 = mn_ortho_err(u, n) // error of the orthogonalized update
55 var t2: i64 = 0
56 if erru < errbuf { if erru < (nn * UG_Q) { t2 = 1 } } // NS improved + U approx-orthogonal (avg<1/entry)
57 gv_check("T2 ORTHOGONALIZED update: NS(momentum) far lower ortho-error than raw momentum" as *u8, t2, ctr)
58
59 // ---- T3: update applied exactly (W == W - lr*U) ----
60 let w: *i64 = sys_mmap(64*8) as *i64
61 let buf: *i64 = sys_mmap(64*8) as *i64
62 let wsave: *i64 = sys_mmap(64*8) as *i64
63 i = 0
64 while i < nn { w[i] = ((i*7) % 11) * (UG_Q/9); buf[i] = 0; i = i + 1 }
65 ug_copy(w, wsave, nn)
66 // expected: replicate momentum->NS->apply on copies
67 let bufe: *i64 = sys_mmap(64*8) as *i64
68 let ue: *i64 = sys_mmap(64*8) as *i64
69 let we: *i64 = sys_mmap(64*8) as *i64
70 ug_copy(w, we, nn); ug_copy(buf, bufe, nn)
71 mu_momentum(bufe, grad, UG_MU, nn)
72 mn_orthogonalize(bufe, ue, n)
73 i = 0
74 while i < nn { we[i] = we[i] - ((UG_LR * ue[i]) >> 16); i = i + 1 }
75 // actual step
76 mu_step(w, buf, grad, UG_MU, UG_LR, n, u)
77 var t3: i64 = 1
78 i = 0
79 while i < nn { if w[i] != we[i] { t3 = 0 } i = i + 1 }
80 // also confirm it actually moved
81 var moved: i64 = 0
82 i = 0
83 while i < nn { if w[i] != wsave[i] { moved = 1 } i = i + 1 }
84 if moved == 0 { t3 = 0 }
85 gv_check("T3 UPDATE APPLIED EXACTLY: W_after == W_before - lr*NS(momentum), and W moved" as *u8, t3, ctr)
86
87 // ---- T4: deterministic per-head step ----
88 let nh: i64 = 2
89 let hd: i64 = 4
90 let phn: i64 = nh*hd*hd
91 let wA: *i64 = sys_mmap(128*8) as *i64
92 let bA: *i64 = sys_mmap(128*8) as *i64
93 let gA: *i64 = sys_mmap(128*8) as *i64
94 let wB: *i64 = sys_mmap(128*8) as *i64
95 let bB: *i64 = sys_mmap(128*8) as *i64
96 let gB: *i64 = sys_mmap(128*8) as *i64
97 i = 0
98 while i < phn { let gv: i64 = (((i%5)+1)*(UG_Q/6)) - (UG_Q/4); wA[i]=(i%9)*(UG_Q/10); bA[i]=0; gA[i]=gv; wB[i]=(i%9)*(UG_Q/10); bB[i]=0; gB[i]=gv; i=i+1 }
99 mu_perhead_step(wA, bA, gA, UG_MU, UG_LR, nh, hd, u)
100 mu_perhead_step(wB, bB, gB, UG_MU, UG_LR, nh, hd, u)
101 var t4: i64 = 1
102 i = 0
103 while i < phn { if wA[i] != wB[i] { t4 = 0 } i = i + 1 }
104 gv_check("T4 DETERMINISTIC per-head step: two runs bit-identical (float Muon drifts)" as *u8, t4, ctr)
105
106 // ---- T5: per-head independence ----
107 let wC: *i64 = sys_mmap(128*8) as *i64
108 let bC: *i64 = sys_mmap(128*8) as *i64
109 let gC: *i64 = sys_mmap(128*8) as *i64
110 i = 0
111 while i < phn { wC[i]=(i%9)*(UG_Q/10); bC[i]=0; gC[i]=gA[i]; i=i+1 } // gA already consumed bA; rebuild grads
112 i = 0
113 while i < phn { let gv: i64 = (((i%5)+1)*(UG_Q/6)) - (UG_Q/4); gC[i]=gv; i=i+1 }
114 gC[0] = gC[0] + (UG_Q/2) // perturb ONLY head-0 (block 0 = indices 0..hd*hd)
115 // fresh baseline for compare
116 let wD: *i64 = sys_mmap(128*8) as *i64
117 let bD: *i64 = sys_mmap(128*8) as *i64
118 let gD: *i64 = sys_mmap(128*8) as *i64
119 i = 0
120 while i < phn { wD[i]=(i%9)*(UG_Q/10); bD[i]=0; let gv: i64 = (((i%5)+1)*(UG_Q/6)) - (UG_Q/4); gD[i]=gv; i=i+1 }
121 i = 0
122 while i < phn { wC[i]=(i%9)*(UG_Q/10); bC[i]=0; i=i+1 }
123 mu_perhead_step(wC, bC, gC, UG_MU, UG_LR, nh, hd, u) // perturbed head-0
124 mu_perhead_step(wD, bD, gD, UG_MU, UG_LR, nh, hd, u) // baseline
125 let blk: i64 = hd*hd
126 var head0_changed: i64 = 0
127 var head1_same: i64 = 1
128 i = 0
129 while i < blk { if wC[i] != wD[i] { head0_changed = 1 } i = i + 1 }
130 i = blk
131 while i < 2*blk { if wC[i] != wD[i] { head1_same = 0 } i = i + 1 }
132 var t5: i64 = 0
133 if head0_changed == 1 { if head1_same == 1 { t5 = 1 } }
134 gv_check("T5 PER-HEAD INDEPENDENCE: perturbing head-0 grad moves head-0 W only, head-1 untouched" as *u8, t5, ctr)
135
136 // ---- T6: stable over 12 steps ----
137 let wS: *i64 = sys_mmap(64*8) as *i64
138 let bS: *i64 = sys_mmap(64*8) as *i64
139 i = 0
140 while i < nn { wS[i]=(i%7)*(UG_Q/8); bS[i]=0; i=i+1 }
141 var step: i64 = 0
142 while step < 12 { mu_step(wS, bS, grad, UG_MU, UG_LR, n, u); step = step + 1 }
143 var t6: i64 = 1
144 i = 0
145 while i < nn { if ug_abs(wS[i]) > 1000000000 { t6 = 0 } i = i + 1 }
146 gv_check("T6 STABLE over 12 optimizer steps (bounded, no blowup)" as *u8, t6, ctr)
147
148 let rc: i64 = gv_verdict("NOFLOAT-MUON-GATE" as *u8, ctr, "full Per-Head Muon optimizer: momentum + NS-orthogonalized update, applied exactly, per-head independent, bit-exact deterministic no-float" as *u8)
149 sys_exit(rc)
150 return rc
151}