code wiki / _hdl_build / nx_nofloat_muon_ns.nx

nx_nofloat_muon_ns.nx source

↩ module page · 113 lines · 4660 B

1// nx_nofloat_muon_ns.nx -- SOVEREIGN no-float Newton-Schulz orthogonalization = the core of the Muon 2// optimizer (K3 F405 gap; operator 2026-07-19 "beyond SOTA, novel"). Muon = MomentUm Orthogonalized by 3// Newton-Schulz (Keller Jordan). NS quintic iteration drives a matrix toward its orthogonal polar factor: 4// X0 = G / ||G||_F (Frobenius-normalize so spectral norm <= 1) 5// X_{k+1} = a*X + b*(A*X) + c*(A*A*X), A = X*X^T, (a,b,c) = (3.4445, -4.7750, 2.0315) 6// After ~5 iters X*X^T -> I. Done in PURE INTEGER Q16 (matmul accumulate-then-shift + integer isqrt) = 7// BIT-EXACT DETERMINISTIC orthogonalization -- a float training stack CANNOT reproduce this bit-for-bit 8// (non-associative accumulation); that is the novel exceed. Grounded: kellerjordan.github.io/posts/muon. 9// license_tier: ORIGINAL No hw writes (Rule 26). 10import "nx_syscalls.nx" 11 12const MN_Q: i64 = 65536 // Q16 one 13const MN_QBITS: i64 = 16 14const MN_NMAX: i64 = 8 // max matrix dim supported 15// NS quintic coeffs in Q16 (Muon): a=3.4445, b=-4.7750, c=2.0315 16const MN_A: i64 = 225755 17const MN_B: i64 = 0 - 312934 18const MN_C: i64 = 133136 19const MN_ITERS: i64 = 5 20 21// integer sqrt of a non-negative i64 (floor). Newton iteration. 22func mn_isqrt(v: i64) -> i64 { 23 if v <= 0 { return 0 } 24 var x: i64 = v 25 var y: i64 = (x + 1) / 2 26 while y < x { x = y; y = (x + v / x) / 2 } 27 return x 28} 29// C[n x n] = A[n x n] * B[n x n] in Q16 (accumulate i64, >>16). A,B,C distinct buffers. 30func mn_mm(a: *i64, b: *i64, c: *i64, n: i64) -> i64 { 31 var i: i64 = 0 32 while i < n { 33 var j: i64 = 0 34 while j < n { 35 var s: i64 = 0 36 var k: i64 = 0 37 while k < n { s = s + a[i*n+k] * b[k*n+j]; k = k + 1 } 38 c[i*n+j] = s >> MN_QBITS 39 j = j + 1 40 } 41 i = i + 1 42 } 43 return 0 44} 45// C = A^T (n x n) 46func mn_transpose(a: *i64, c: *i64, n: i64) -> i64 { 47 var i: i64 = 0 48 while i < n { var j: i64 = 0; while j < n { c[j*n+i] = a[i*n+j]; j = j + 1 } i = i + 1 } 49 return 0 50} 51// out = pa*A + pb*B + pc*C (scalars in Q16, matrices in Q16) elementwise, n x n 52func mn_comb(a: *i64, b: *i64, c: *i64, out: *i64, pa: i64, pb: i64, pc: i64, n: i64) -> i64 { 53 var i: i64 = 0 54 let nn: i64 = n * n 55 while i < nn { 56 out[i] = ((pa * a[i]) >> MN_QBITS) + ((pb * b[i]) >> MN_QBITS) + ((pc * c[i]) >> MN_QBITS) 57 i = i + 1 58 } 59 return 0 60} 61// Newton-Schulz orthogonalize G (n x n, Q16) -> X (n x n, Q16), `iters` NS steps. 62// Muon NS = APPROXIMATE orthogonalization: singular values -> ~1 (fixed points 0.87/1.26), not exactly 1. 63func mn_orthogonalize_it(g: *i64, x: *i64, n: i64, iters: i64) -> i64 { 64 let nn: i64 = n * n 65 // Frobenius norm ||G||_F = sqrt(sum g^2). g in Q16 -> g^2 in Q32; sum in i64; sqrt -> Q16 norm. 66 var ss: i64 = 0 67 var i: i64 = 0 68 while i < nn { let v: i64 = g[i] >> 8; ss = ss + v * v; i = i + 1 } // (g>>8)^2 = g^2 >> 16 = Q16-scaled sumsq 69 let fro: i64 = mn_isqrt(ss) // ~ ||G||_F in Q8-ish; normalize by ratio 70 if fro <= 0 { return 0 } 71 // X0 = G / ||G||_F : x = g * Q / (fro<<8) (fro was sqrt of Q16-scaled -> scale back) 72 let denom: i64 = fro << 8 73 i = 0 74 while i < nn { x[i] = (g[i] << MN_QBITS) / denom; i = i + 1 } 75 // iteration buffers 76 let xt: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 77 let aM: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 78 let ax: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 79 let aax: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 80 var it: i64 = 0 81 while it < iters { 82 mn_transpose(x, xt, n) // X^T 83 mn_mm(x, xt, aM, n) // A = X X^T 84 mn_mm(aM, x, ax, n) // A X 85 mn_mm(aM, ax, aax, n) // A A X 86 mn_comb(x, ax, aax, x, MN_A, MN_B, MN_C, n) // X = aX + b(AX) + c(AAX) 87 it = it + 1 88 } 89 return 0 90} 91// default 5-iteration Muon NS 92func mn_orthogonalize(g: *i64, x: *i64, n: i64) -> i64 { return mn_orthogonalize_it(g, x, n, MN_ITERS) } 93// orthogonality error metric: sum |(X X^T)[i][j] - I[i][j]| in Q16 (0 = perfectly orthogonal) 94func mn_ortho_err(x: *i64, n: i64) -> i64 { 95 let xt: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 96 let g: *i64 = sys_mmap(MN_NMAX*MN_NMAX*8) as *i64 97 mn_transpose(x, xt, n) 98 mn_mm(x, xt, g, n) 99 var e: i64 = 0 100 var i: i64 = 0 101 while i < n { 102 var j: i64 = 0 103 while j < n { 104 var t: i64 = g[i*n+j] 105 if i == j { t = t - MN_Q } 106 if t < 0 { t = 0 - t } 107 e = e + t 108 j = j + 1 109 } 110 i = i + 1 111 } 112 return e 113}