code wiki / _hdl_build / nx_research_strassen4_gate.nx

nx_research_strassen4_gate.nx source

↩ module page · 133 lines · 8274 B

1// nx_research_strassen4_gate.nx -- from REPRODUCTION toward DISCOVERY: show WHY finding low-multiplication 2// schemes matters. Strassen's 2x2 saving (7 mults instead of 8) COMPOUNDS recursively: a 4x4 product done by 3// block-Strassen (2x2 blocks of 2x2 blocks) costs 7x7 = 49 scalar multiplications instead of the naive 4^3 = 64. 4// The TESTING-TEAM runs both, proves block-Strassen == naive bit-exact (independent KAT A*I=A and I*B=B, plus 5// random matrices), COUNTS the multiplications (49 vs 64 = the compounding payoff), and the VERIFIER liar-kill 6// rejects a deliberately-broken recursive scheme. This is the substrate an alphatensor-class search rides on: 7// a candidate scheme is only "discovered" once this exact-comparison gate certifies it. Exact integer, no float, 8// deterministic. GREEN iff 6/6. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10 11func g_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func g_n(v: i64) -> i64 { var m: i64=v; if m<0{g_w("-");m=0-m} let t:*u8=sys_mmap(24); var k:i64=0; if m==0{t[0]=48 as u8;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i:i64=0; let o:*u8=sys_mmap(24); while i<k{o[i]=t[k-1-i];i=i+1}; sys_write(1,o,k); return 0 } 13func g_row(id: *u8, ok: i64, pass: *i64) -> i64 { g_w(" "); g_w(id); g_w(": "); if ok==1 { g_w("OK\n"); pass[0]=pass[0]+1 } else { g_w("FAIL\n") } return 0 } 14 15func rs_mul(cnt: *i64, a: i64, b: i64) -> i64 { cnt[0] = cnt[0] + 1; return a * b } 16func rs_rng(state: *i64) -> i64 { var x: i64 = state[0]; x = x ^ (x << 13); x = x ^ (x >> 7); x = x ^ (x << 17); state[0] = x; return x } 17 18// ---- 2x2 block primitives (blocks are [00,01,10,11]) ---- 19func bl_add(x: *i64, y: *i64, o: *i64) -> i64 { o[0]=x[0]+y[0]; o[1]=x[1]+y[1]; o[2]=x[2]+y[2]; o[3]=x[3]+y[3]; return 0 } 20func bl_sub(x: *i64, y: *i64, o: *i64) -> i64 { o[0]=x[0]-y[0]; o[1]=x[1]-y[1]; o[2]=x[2]-y[2]; o[3]=x[3]-y[3]; return 0 } 21// 2x2 Strassen multiply: 7 scalar multiplications (counted). 22func bl_strassen(x: *i64, y: *i64, o: *i64, cnt: *i64) -> i64 { 23 let m1: i64 = rs_mul(cnt, x[0]+x[3], y[0]+y[3]) 24 let m2: i64 = rs_mul(cnt, x[2]+x[3], y[0]) 25 let m3: i64 = rs_mul(cnt, x[0], y[1]-y[3]) 26 let m4: i64 = rs_mul(cnt, x[3], y[2]-y[0]) 27 let m5: i64 = rs_mul(cnt, x[0]+x[1], y[3]) 28 let m6: i64 = rs_mul(cnt, x[2]-x[0], y[0]+y[1]) 29 let m7: i64 = rs_mul(cnt, x[1]-x[3], y[2]+y[3]) 30 o[0] = m1 + m4 - m5 + m7; o[1] = m3 + m5; o[2] = m2 + m4; o[3] = m1 - m2 + m3 + m6 31 return 0 32} 33 34// a slice of the scratch arena: the i-th 2x2 block (4 i64 = 32 bytes). 35func blk(sc: *i64, i: i64) -> *i64 { return ((sc as i64) + i*32) as *i64 } 36// extract / write a 2x2 block (br,bc in {0,1}) of a row-major 4x4 (16 i64). 37func get_block(m16: *i64, br: i64, bc: i64, out: *i64) -> i64 { 38 let r0: i64 = br*2; let c0: i64 = bc*2 39 out[0]=m16[r0*4+c0]; out[1]=m16[r0*4+c0+1]; out[2]=m16[(r0+1)*4+c0]; out[3]=m16[(r0+1)*4+c0+1]; return 0 40} 41func set_block(m16: *i64, br: i64, bc: i64, b: *i64) -> i64 { 42 let r0: i64 = br*2; let c0: i64 = bc*2 43 m16[r0*4+c0]=b[0]; m16[r0*4+c0+1]=b[1]; m16[(r0+1)*4+c0]=b[2]; m16[(r0+1)*4+c0+1]=b[3]; return 0 44} 45 46// naive 4x4 matmul: 4^3 = 64 scalar multiplications. 47func mm4_naive(a: *i64, b: *i64, c: *i64, cnt: *i64) -> i64 { 48 var i: i64=0 49 while i<4 { var j: i64=0; while j<4 { var s: i64=0; var k: i64=0; while k<4 { s = s + rs_mul(cnt, a[i*4+k], b[k*4+j]); k=k+1 } c[i*4+j]=s; j=j+1 } i=i+1 } 50 return 0 51} 52// block-Strassen 4x4 matmul: 7 block-multiplies x 7 = 49 scalar multiplications. `bad`=1 corrupts C11 (liar-kill). 53func mm4_strassen(a: *i64, b: *i64, c: *i64, cnt: *i64, sc: *i64, bad: i64) -> i64 { 54 let A00: *i64=blk(sc,0); let A01: *i64=blk(sc,1); let A10: *i64=blk(sc,2); let A11: *i64=blk(sc,3) 55 let B00: *i64=blk(sc,4); let B01: *i64=blk(sc,5); let B10: *i64=blk(sc,6); let B11: *i64=blk(sc,7) 56 get_block(a,0,0,A00); get_block(a,0,1,A01); get_block(a,1,0,A10); get_block(a,1,1,A11) 57 get_block(b,0,0,B00); get_block(b,0,1,B01); get_block(b,1,0,B10); get_block(b,1,1,B11) 58 let M1: *i64=blk(sc,8); let M2: *i64=blk(sc,9); let M3: *i64=blk(sc,10); let M4: *i64=blk(sc,11) 59 let M5: *i64=blk(sc,12); let M6: *i64=blk(sc,13); let M7: *i64=blk(sc,14) 60 let t1: *i64=blk(sc,15); let t2: *i64=blk(sc,16); let tt: *i64=blk(sc,17) 61 bl_add(A00,A11,t1); bl_add(B00,B11,t2); bl_strassen(t1,t2,M1,cnt) 62 bl_add(A10,A11,t1); bl_strassen(t1,B00,M2,cnt) 63 bl_sub(B01,B11,t2); bl_strassen(A00,t2,M3,cnt) 64 bl_sub(B10,B00,t2); bl_strassen(A11,t2,M4,cnt) 65 bl_add(A00,A01,t1); bl_strassen(t1,B11,M5,cnt) 66 bl_sub(A10,A00,t1); bl_add(B00,B01,t2); bl_strassen(t1,t2,M6,cnt) 67 bl_sub(A01,A11,t1); bl_add(B10,B11,t2); bl_strassen(t1,t2,M7,cnt) 68 let C00: *i64=blk(sc,18); let C01: *i64=blk(sc,19); let C10: *i64=blk(sc,20); let C11: *i64=blk(sc,21) 69 bl_add(M1,M4,tt); bl_sub(tt,M5,tt); bl_add(tt,M7,C00) 70 bl_add(M3,M5,C01) 71 bl_add(M2,M4,C10) 72 if bad==1 { bl_add(M1,M2,tt) } else { bl_sub(M1,M2,tt) } // bad: +M2 instead of -M2 73 bl_add(tt,M3,tt); bl_add(tt,M6,C11) 74 set_block(c,0,0,C00); set_block(c,0,1,C01); set_block(c,1,0,C10); set_block(c,1,1,C11) 75 return 0 76} 77func eq16(x: *i64, y: *i64) -> i64 { var i: i64=0; while i<16 { if x[i]!=y[i]{return 0} i=i+1 } return 1 } 78 79func main() -> i64 { 80 let pass: *i64 = sys_mmap(8) as *i64; pass[0] = 0 81 g_w("=== NX-RESEARCH-STRASSEN4 GATE (recursive Strassen: 4x4 in 49 mults vs naive 64) ===\n") 82 let sc: *i64 = sys_mmap(4096) as *i64 83 let dump: *i64 = sys_mmap(8) as *i64 84 85 // KAT 1: A * I = A (A = [1..16], I = 4x4 identity) 86 let A: *i64 = sys_mmap(256) as *i64; var i: i64=0; while i<16 { A[i]=i+1; i=i+1 } 87 let I: *i64 = sys_mmap(256) as *i64; i=0; while i<16 { I[i]=0; i=i+1 } I[0]=1; I[5]=1; I[10]=1; I[15]=1 88 let R: *i64 = sys_mmap(256) as *i64 89 dump[0]=0; mm4_strassen(A, I, R, dump, sc, 0) 90 let kat1: i64 = eq16(R, A) 91 // KAT 2: I * B = B 92 let B: *i64 = sys_mmap(256) as *i64; i=0; while i<16 { B[i]=(i*3+1); i=i+1 } 93 dump[0]=0; mm4_strassen(I, B, R, dump, sc, 0) 94 let kat2: i64 = eq16(R, B) 95 96 // reproducibility: block-Strassen == naive over N random 4x4 97 let st: *i64 = sys_mmap(8) as *i64; st[0] = 0x9E3779B97F4A7C15 98 let ra: *i64 = sys_mmap(256) as *i64; let rb: *i64 = sys_mmap(256) as *i64 99 let r1: *i64 = sys_mmap(256) as *i64; let r2: *i64 = sys_mmap(256) as *i64 100 var iter: i64=0; var mism: i64=0; let N: i64=200 101 while iter<N { 102 i=0; while i<16 { ra[i]=(rs_rng(st) & 0xf) - 8; i=i+1 } 103 i=0; while i<16 { rb[i]=(rs_rng(st) & 0xf) - 8; i=i+1 } 104 dump[0]=0; mm4_naive(ra, rb, r1, dump) 105 dump[0]=0; mm4_strassen(ra, rb, r2, dump, sc, 0) 106 if eq16(r1, r2)==0 { mism=mism+1 } 107 iter=iter+1 108 } 109 110 // counts 111 let cn: *i64 = sys_mmap(8) as *i64; cn[0]=0; mm4_naive(A, B, R, cn); let mulsN: i64=cn[0] 112 let cs: *i64 = sys_mmap(8) as *i64; cs[0]=0; mm4_strassen(A, B, R, cs, sc, 0); let mulsS: i64=cs[0] 113 114 // liar-kill: broken recursive scheme != naive 115 dump[0]=0; mm4_naive(A, B, r1, dump) 116 dump[0]=0; mm4_strassen(A, B, r2, dump, sc, 1) 117 let broken_caught: i64 = (eq16(r1, r2)==0) as i64 118 119 g_w(" KAT A*I==A="); g_n(kat1); g_w(" I*B==B="); g_n(kat2); g_w("\n") 120 g_w(" reproducibility: "); g_n(N); g_w(" random 4x4, block-Strassen!=naive mismatches="); g_n(mism); g_w("\n") 121 g_w(" multiplications: naive="); g_n(mulsN); g_w(" recursive-Strassen="); g_n(mulsS); g_w(" (7x7 vs 4^3)\n") 122 123 g_row("KAT: block-Strassen reproduces A*I = A (independent known answer)" as *u8, kat1, pass) 124 g_row("KAT: block-Strassen reproduces I*B = B" as *u8, kat2, pass) 125 g_row("REPRODUCIBILITY: block-Strassen == naive over 200 random 4x4 (0 mismatch)" as *u8, (mism==0) as i64, pass) 126 g_row("EFFICIENCY: naive 4x4 uses 64 scalar multiplications (counted)" as *u8, (mulsN==64) as i64, pass) 127 g_row("COMPOUNDING: recursive Strassen uses 49 = 7^2 (the 7-for-8 saving compounds)" as *u8, (mulsS==49) as i64, pass) 128 g_row("LIAR-KILL: a broken recursive scheme is REJECTED by exact comparison" as *u8, broken_caught, pass) 129 130 g_w("STRASSEN4-GATE rows=6 pass="); g_n(pass[0]) 131 if pass[0] == 6 { g_w(" verdict=GREEN\n"); sys_exit(0); return 0 } 132 g_w(" verdict=RED\n"); sys_exit(1); return 1 133}