code wiki / _hdl_build / nx_intfp_rope_gate.nx

nx_intfp_rope_gate.nx source

↩ module page · 83 lines · 5184 B

1// nx_intfp_rope_gate.nx -- RoPE (Rotary Position Embedding, universal in 2026) in Q20 INTEGER, no float. Adds 2// integer sin/cos (range-reduced Taylor) to the transcendental set. RoPE rotates each (2i,2i+1) dim-pair of Q,K by 3// angle pos*freq_i. Verifies the DEFINING property: <RoPE(q,m),RoPE(k,n)> depends ONLY on (m-n) (relative pos), 4// and norm preservation, and gradchecks the rotation. Closes the "RoPE integer-native pending" note. license_tier: ORIGINAL 5import "nx_syscalls.nx" 6 7func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 8func wsi(v: i64) -> i64 { if v<0 { sys_write(1,"-" as *u8,1); v=0-v } var m: i64=v; if m==0 { sys_write(1,"0" as *u8,1); return 0 } let t: *u8=sys_mmap(24); var k: i64=0; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let o: *u8=sys_mmap(24); var q: i64=k-1; var i: i64=0; while q>=0{o[i]=t[q];i=i+1;q=q-1} sys_write(1,o,i); return 0 } 9func iabs(v: i64) -> i64 { if v<0 { return 0-v } return v } 10 11const S: i64 = 1048576 12const PI: i64 = 3294199 // pi in Q20 13const PI2: i64 = 1647099 // pi/2 14const TAU: i64 = 6588397 // 2pi 15const DM: i64 = 4 // head dim (even) 16 17// integer sin: reduce x mod 2pi to [-pi,pi], then to [-pi/2,pi/2], Taylor x - x^3/6 + x^5/120 - x^7/5040 18func fp_sin(xin: i64) -> i64 { 19 var x: i64=xin 20 while x>PI { x=x-TAU } while x<=0-PI { x=x+TAU } 21 if x>PI2 { x=PI-x } if x<0-PI2 { x=0-PI-x } // fold to [-pi/2,pi/2] (sin unchanged) 22 let x2: i64=(x*x)/S 23 // Horner: x*(1 - x2/6*(1 - x2/20*(1 - x2/42))) 24 var p: i64=S-(x2/42) 25 p=S-((x2*p)/S)/20 26 p=S-((x2*p)/S)/6 27 return (x*p)/S 28} 29func fp_cos(x: i64) -> i64 { return fp_sin(PI2-x) } 30 31// RoPE rotate the (2i,2i+1) pairs of a DM-vector q by pos*freq_i, into out 32func rope(q: *i64, pos: i64, freq: *i64, out: *i64) -> i64 { 33 var i: i64=0 34 while i<DM/2 { 35 let th: i64=(pos*freq[i])/S // angle = pos*freq_i (Q20) 36 let c: i64=fp_cos(th); let sn: i64=fp_sin(th) 37 let a: i64=q[2*i]; let b: i64=q[2*i+1] 38 out[2*i]=(a*c)/S-(b*sn)/S 39 out[2*i+1]=(a*sn)/S+(b*c)/S 40 i=i+1 41 } 42 return 0 43} 44func dot(a: *i64, b: *i64) -> i64 { var d: i64=0; var i: i64=0; while i<DM { d=d+(a[i]*b[i])/S; i=i+1 } return d } 45 46func main() -> i64 { 47 w("=== nx_intfp_rope: RoPE (rotary pos-emb, universal 2026) in Q20 INTEGER + integer sin/cos, no float ===\n\n" as *u8) 48 // verify sin/cos 49 w(" sin(0)=" as *u8); wsi((fp_sin(0)*1000)/S); w("m sin(pi/2)=" as *u8); wsi((fp_sin(PI2)*1000)/S); w("m(want 1000) sin(pi)=" as *u8); wsi((fp_sin(PI)*1000)/S); w("m cos(0)=" as *u8); wsi((fp_cos(0)*1000)/S); w("m(1000) cos(pi/2)=" as *u8); wsi((fp_cos(PI2)*1000)/S); w("m\n\n" as *u8) 50 let freq: *i64=sys_mmap((DM/2)*8) as *i64; freq[0]=S; freq[1]=S/100 // freq = [1.0, 0.01] 51 let q: *i64=sys_mmap(DM*8) as *i64; let kk: *i64=sys_mmap(DM*8) as *i64 52 var i: i64=0; while i<DM { q[i]=((((i*7+3)%11)-5)*S)/8; kk[i]=((((i*5+1)%11)-5)*S)/8; i=i+1 } 53 let qm: *i64=sys_mmap(DM*8) as *i64; let kn: *i64=sys_mmap(DM*8) as *i64; let q0: *i64=sys_mmap(DM*8) as *i64; let kd: *i64=sys_mmap(DM*8) as *i64 54 // norm preservation: |RoPE(q,3)| == |q| 55 rope(q, 3, freq, qm) 56 let nq: i64=dot(q,q); let nqm: i64=dot(qm,qm) 57 w(" norm: |q|^2=" as *u8); wsi(nq); w(" |RoPE(q,3)|^2=" as *u8); wsi(nqm); w(" (rotation preserves norm)\n" as *u8) 58 // RELATIVE-POSITION property: <RoPE(q,m),RoPE(k,n)> == <RoPE(q,0),RoPE(k,n-m)> 59 let m: i64=5; let n: i64=8 60 rope(q, m, freq, qm); rope(kk, n, freq, kn) 61 let lhs: i64=dot(qm, kn) 62 rope(q, 0, freq, q0); rope(kk, n-m, freq, kd) 63 let rhs: i64=dot(q0, kd) 64 w(" relative-pos: <RoPE(q," as *u8); wsi(m); w("),RoPE(k," as *u8); wsi(n); w(")>=" as *u8); wsi(lhs); w(" == <RoPE(q,0),RoPE(k," as *u8); wsi(n-m); w(")>=" as *u8); wsi(rhs); w("\n" as *u8) 65 let reld: i64=(iabs(lhs-rhs)*1000)/(iabs(lhs)+100) 66 // gradcheck: L=sum RoPE(q,pos)^2 wrt q (rotation is linear; grad = rotate by -theta) 67 // dL/dq[j] via finite diff vs analytic (RoPE is orthonormal so dL/dq = 2q since |RoPE(q)|=|q| => L=|q|^2, dL/dq=2q) 68 var gcok: i64=1; let DELTA: i64=2097; let tmp: i64=0 69 i=0 70 while i<DM { 71 let sv: i64=q[i] 72 q[i]=sv+DELTA; rope(q,3,freq,qm); let Lp: i64=dot(qm,qm) 73 q[i]=sv-DELTA; rope(q,3,freq,qm); let Lm: i64=dot(qm,qm) 74 q[i]=sv; let num: i64=((Lp-Lm)*S)/(2*DELTA); let ana: i64=2*q[i] // L=|q|^2 (norm preserved) => dL/dq=2q 75 let r: i64=(iabs(num-ana)*1000)/(iabs(ana)+100); if r>60 { gcok=0 } 76 i=i+1 77 } 78 w("\n gradcheck (L=|RoPE(q,3)|^2, dL/dq=2q since norm-preserving): " as *u8); if gcok==1 { w("PASS" as *u8) } else { w("FAIL" as *u8) } w("\n" as *u8) 79 w("NX-INTFP-ROPE verdict=" as *u8) 80 if reld<=30 { if gcok==1 { w("GREEN -- integer RoPE PROVEN: relative-position property holds (rel diff " as *u8); wsi(reld); w("permil), norm-preserving, gradchecks. Integer sin/cos added. RoPE integer-native DONE.\n" as *u8) } else { w("YELLOW rel-pos ok but gradcheck off\n" as *u8) } } 81 else { w("RED rel-pos property broken (" as *u8); wsi(reld); w("permil) -- sin/cos or rotation bug\n" as *u8) } 82 return 0 83}