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}