code wiki / _hdl_build / nx_ballistics_gate.nx

nx_ballistics_gate.nx source

↩ module page · 120 lines · 8636 B

1// nx_ballistics_gate.nx -- NATIVE verify of the browser ballistics sim (base = mmap; SAME code runs in sovereign 2// WASM). Integrates projectiles with the sim's own acceleration and validates the real ballistic laws: (a) range 3// R = v^2 sin(2theta)/g is MAXIMUM at 45deg, (b) complementary angles (30/60, 15/75) give EQUAL range, (c) the 4// range curve follows sin(2theta), (d) vacuum flight is parabolic-SYMMETRIC (apex at half the flight time), (e) air 5// DRAG reduces the range. Liar-kill: a horizontal launch (theta=0) lands immediately (range ~ 0) -- vertical launch 6// is essential, the sim isn't returning a constant. license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_ballistics.nx" 9import "nx_png.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 } 14func iabs(x: i64) -> i64 { if x<0 { return 0-x } return x } 15 16func vx0_of(thed: i64) -> i64 { return V0*cos_fixed(thed)/SC } 17func vy0_of(thed: i64) -> i64 { return V0*sin_fixed(thed)/SC } 18 19// integrate one projectile (matching the sim's update order) and return its range (x at landing) 20func range_at(thed: i64, drag: i64) -> i64 { 21 var x: i64=0; var y: i64=0; var vx: i64=vx0_of(thed); var vy: i64=vy0_of(thed); var s: i64=0 22 while s<5000000 { 23 vx = vx + acc_x(vx,vy,drag); vy = vy + acc_y(vx,vy,drag) 24 x = x + vx; y = y + vy 25 if y<=0 { return x } 26 s=s+1 27 } 28 return x 29} 30// apex step and landing step for a vacuum projectile 31func flight(thed: i64, ap: *i64, land: *i64) -> i64 { 32 var x: i64=0; var y: i64=0; var vx: i64=vx0_of(thed); var vy: i64=vy0_of(thed); var s: i64=0; var apex: i64=0 33 while s<5000000 { 34 vx = vx + acc_x(vx,vy,0); vy = vy + acc_y(vx,vy,0); x = x + vx; y = y + vy; s=s+1 35 if apex==0 { if vy<=0 { apex=s } } 36 if y<=0 { ap[0]=apex; land[0]=s; return 0 } 37 } 38 return 0 39} 40 41func main() -> i64 { 42 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 43 g_w("=== NX-BALLISTICS native verify (projectile firing-table physics; SAME code runs in sovereign wasm) ===\n") 44 let base: i64 = sys_mmap(2*1048576) as i64 45 46 let R15: i64=range_at(261799,0); let R30: i64=range_at(523599,0); let R45: i64=range_at(785398,0) 47 let R60: i64=range_at(1047198,0); let R75: i64=range_at(1308997,0) 48 let R0: i64=range_at(0,0) // horizontal -> ~0 49 let Rd45: i64=range_at(785398,1) // 45deg WITH drag 50 let ap: *i64=sys_mmap(8) as *i64; let ld: *i64=sys_mmap(8) as *i64 51 flight(785398, ap, ld) 52 53 g_w(" ranges(vac): R15="); g_n(R15); g_w(" R30="); g_n(R30); g_w(" R45="); g_n(R45); g_w(" R60="); g_n(R60); g_w(" R75="); g_n(R75); g_w("\n") 54 g_w(" R(0deg)="); g_n(R0); g_w(" R45(drag)="); g_n(Rd45); g_w(" flight: apex_step="); g_n(ap[0]); g_w(" land_step="); g_n(ld[0]); g_w("\n") 55 g_w(" ratios x1000: R15/R45="); g_n(R15*1000/R45); g_w(" (sin30=500) R30/R45="); g_n(R30*1000/R45); g_w(" (sin60=866)\n") 56 57 var peak: i64=1; if R45<R15 { peak=0 } if R45<R30 { peak=0 } if R45<R60 { peak=0 } if R45<R75 { peak=0 } 58 var comp: i64=0; if iabs(R30-R60)*1000/R45 < 20 { if iabs(R15-R75)*1000/R45 < 20 { comp=1 } } 59 var shape: i64=0; if iabs(R15*1000/R45 - 500) < 40 { if iabs(R30*1000/R45 - 866) < 40 { shape=1 } } 60 var sym: i64=0; if iabs(ld[0] - 2*ap[0])*1000/ld[0] < 20 { sym=1 } 61 62 // render a frame 63 init_impl(base); var t: i64=0; while t<120 { tick_impl(base, 0); t=t+1 } 64 render_impl(base) 65 write_png((base + O_FB) as *i64, W, H, "knowledge/nx_ballistics.png" as *u8) 66 let m: *u8=(base+O_FB) as *u8; var nb: i64=0; var i: i64=0 67 while i<W*H { let b: i64=i*8; if (m[b] as i64)!=12 { nb=nb+1 } else { if (m[b+1] as i64)!=16 { nb=nb+1 } else { if (m[b+2] as i64)!=26 { nb=nb+1 } } } i=i+1 } 68 69 var ran: i64=0; if R45>0 { if R15>0 { ran=1 } } 70 g_row("RUNS: ranges integrated for every launch angle (vacuum + drag)" as *u8, ran, pass) 71 g_row("MAX RANGE AT 45deg: R(45) is the maximum over 15/30/45/60/75 -- the classic optimal launch angle" as *u8, peak, pass) 72 g_row("COMPLEMENTARY ANGLES: R(30)=R(60) and R(15)=R(75) within 2% -- the real complementary-angle range symmetry" as *u8, comp, pass) 73 g_row("SIN(2theta) LAW: R(15)/R(45)~0.5 and R(30)/R(45)~0.866 within 4% -- range follows v^2 sin(2theta)/g" as *u8, shape, pass) 74 g_row("PARABOLIC SYMMETRY: vacuum flight reaches apex at half the total flight time (within 2%)" as *u8, sym, pass) 75 g_row("DRAG REDUCES RANGE: the 45deg shot with air drag falls >5% short of the vacuum shot" as *u8, (Rd45 < R45*95/100) as i64, pass) 76 g_row("LIAR-KILL: a horizontal launch (theta=0) lands at once (range << R45/20) -- vertical launch is essential" as *u8, (R0 < R45/20) as i64, pass) 77 g_row("RASTER: framebuffer drawn (ground + two trajectories) -> knowledge/nx_ballistics.png" as *u8, (nb>100) as i64, pass) 78 var iface: i64=0; if ww()==W { if hh()==H { if fb_off()==O_FB { iface=1 } } } 79 g_row("WASM-READY: init/tick/render/ww/hh/fb_off interface intact" as *u8, iface, pass) 80 81 // ---- MUTATION-DERIVED TEETH (2026-08-01, debt 1785604588) ---- 82 // nx_gate_mutation_probe scored this pair 1/4 -- the WORST found so far -- with three survivors: 83 // nx_ballistics.nx:44 `if X > HALF { X = PI - X }` the sine ARGUMENT REDUCTION 84 // nx_ballistics.nx:63 the disc() rasterisation bound 85 // nx_ballistics.nx:143 mem_bytes() 86 // Every physics row above (range law, complementary angles, drag, apex symmetry) is computed from 87 // launch angles of 15..75 degrees, which after reduction never enter the X > HALF branch. So the 88 // gate exercised sine only where the mutated line does not run. 89 // LAW: TESTING A FUNCTION THROUGH ONE CALLER TESTS ONLY THE INPUTS THAT CALLER HAPPENS TO PRODUCE. 90 // Nine rows of real physics still left half the sine domain unvisited. 91 // TOOTH 1 -- an ABSOLUTE sine value in the second quadrant, NOT a symmetry. 92 // ⚠ MY FIRST ATTEMPT WAS BLIND BY CONSTRUCTION and is recorded because the failure is the lesson. 93 // I asserted sin(HALF - d) == sin(HALF + d), the very identity line 44 implements. But inverting 94 // `X > HALF` to `X < HALF` SWAPS which side gets reduced: the low argument is folded and the high 95 // one is not, so both operands take on each other's value and the equality still holds. The tooth 96 // measured a property the mutation PRESERVES. 97 // LAW: A SYMMETRY TEST IS BLIND TO A MUTATION THAT PRESERVES THE SYMMETRY -- when the defect swaps 98 // two sides, comparing those two sides cancels it. Symmetry is a strong tooth for a defect that 99 // breaks one side only (it caught the eyeball colour and the FFT imaginary half); it is the WRONG 100 // tooth when the defect exchanges the sides. 101 // A known value is required here, and sin(2 rad) = 0.909297 is a mathematical constant, not an 102 // implementation detail -- the same standing as the FIPS/RFC vectors other gates assert against. 103 // With the branch intact, 2.0 rad folds to PI-2.0 = 1.141593 and the series is accurate; inverted, 104 // the series is evaluated at 2.0 directly, outside its convergent range. 105 let s2: i64 = sin_fixed(2000000) 106 var sin_ok: i64 = 0 107 if s2 > 899297 { if s2 < 919297 { sin_ok = 1 } } // 0.909297 +/- 1% 108 g_row("SINE KAT: sin(2 rad) == 0.9093 +/-1% -- the >PI/2 reduction branch is exercised and correct" as *u8, sin_ok, pass) 109 // TOOTH 2 -- mem_bytes() must cover the LAST structure's end, O_TR + trail bytes. 110 // ⚠ My first floor (trail bytes alone = 5120) was far below O_TR (524400), so a mutation that 111 // subtracts the trail term still cleared it. A floor only tests what it is above. 112 let mb: i64 = mem_bytes() 113 var mem_ok: i64 = 0 114 if mb > (O_TR + N * TRAILN * 2 * 8) { mem_ok = 1 } 115 g_row("MEM FOOTPRINT: mem_bytes() exceeds the trail storage it must hold (a caller sizes from this)" as *u8, mem_ok, pass) 116 117 g_w("NX-BALLISTICS-GATE rows=11 pass="); g_n(pass[0]) 118 if pass[0]==11 { g_w(" verdict=GREEN (real projectile ballistics; sin(2theta) range law + complementary symmetry + drag, browser-ready)\n"); sys_exit(0); return 0 } 119 g_w(" verdict=RED\n"); sys_exit(1); return 1 120}