code wiki / _hdl_build / nx_gassim_gate.nx

nx_gassim_gate.nx source

↩ module page · 125 lines · 9042 B

1// nx_gassim_gate.nx -- NATIVE verify of the browser kinetic-theory gas sim (base = mmap; SAME code runs in the 2// sovereign WASM). Proves real statistical-mechanics physics: (1) the gas runs and collides, (2) every particle 3// stays contained (no tunnel/escape), (3) total kinetic energy is conserved over a long run (elastic dynamics), 4// (4) an isolated head-on elastic collision conserves total momentum AND kinetic energy EXACTLY, (5) THERMALIZATION 5// -- starting from a single speed the velocity distribution spreads (onset of Maxwell-Boltzmann), (6) raster -> PNG. 6// license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_gassim.nx" 9import "nx_png.nx" 10import "nx_gate_verdict.nx" 11 12func 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 } 13func 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 } 14// ★D001 MIGRATED BY HAND, same as nx_solarsim_gate: this gate counted through a pass[0] pointer 15// against a LITERAL denominator (rows=7), an idiom nx_gate_dry_apply does not recognise. Moving the 16// rows onto the shared base class makes declared == executed BY CONSTRUCTION -- adding the three 17// rows below moves the count by itself, where the literal would have printed 10/7. 18func g_row(id: *u8, ok: i64, ctr: *i64) -> i64 { return gv_check(id, ok, ctr) } 19func iabs(x: i64) -> i64 { if x<0 { return 0-x } return x } 20func isq(N0: i64) -> i64 { if N0<2 { return N0 } var x: i64=N0; var y: i64=(x+1)/2; while y<x { x=y; y=(x + N0/x)/2 } return x } 21 22func main() -> i64 { 23 let pass: *i64 = gv_ctr() 24 g_w("=== NX-GASSIM native verify (kinetic-theory gas; SAME code runs in sovereign wasm) ===\n") 25 let base: i64 = sys_mmap(2*1048576) as i64 26 let PX: *i64=(base+O_PX) as *i64; let PY: *i64=(base+O_PY) as *i64; let VX: *i64=(base+O_VX) as *i64; let VY: *i64=(base+O_VY) as *i64 27 let COL: *i64=(base+O_COL) as *i64 28 29 // ---- main run: thermalization + energy + containment ---- 30 init_impl(base) 31 let e0: i64 = energy(base) 32 var t: i64=0; while t<1000 { step_one_impl(base); t=t+1 } 33 let e1: i64 = energy(base) 34 let drift: i64 = iabs(e1-e0)*1000/e0 // permille 35 let col: i64 = COL[0] 36 // speed spread (start: all 200 -> spread 0) 37 var smin: i64=999999; var smax: i64=0; var i: i64=0 38 while i<N { let sp: i64=isq(VX[i]*VX[i]+VY[i]*VY[i]); if sp<smin { smin=sp } if sp>smax { smax=sp } i=i+1 } 39 let spread: i64 = smax-smin 40 // containment 41 var allin: i64=1; i=0 42 while i<N { if PX[i]<RAD { allin=0 } if PX[i]>BW-RAD { allin=0 } if PY[i]<RAD { allin=0 } if PY[i]>BW-RAD { allin=0 } i=i+1 } 43 44 render_impl(base) 45 write_png((base + O_FB) as *i64, W, H, "knowledge/nx_gassim.png" as *u8) 46 var nb: i64=0; i=0 47 while i<W*H { let b: i64=i*8; let m: *u8=(base+O_FB) as *u8; if (m[b] as i64)!=12 { nb=nb+1 } else { if (m[b+1] as i64)!=12 { nb=nb+1 } else { if (m[b+2] as i64)!=20 { nb=nb+1 } } } i=i+1 } 48 49 // ⚠MEASURED HERE, IMMEDIATELY AFTER THE RENDER, AND NOT LATER. The head-on collision section 50 // below RE-INITS the arena and overwrites PX/PY/VX/VY, so reading particle positions after it 51 // compares the frame that WAS rendered against state that has since been replaced. The first cut 52 // of this tooth did exactly that and reported present=0/20 on a frame carrying 580 non-background 53 // pixels -- it said so out loud rather than passing, which is how the ordering bug surfaced. 54 let fbp: *i64 = (base+O_FB) as *i64 55 let bg1: i64 = fbp[0] 56 let bg2: i64 = fbp[W-1] 57 let seen: *i64 = sys_mmap(N*8) as *i64 58 var present: i64=0; var pchecked: i64=0; var matched: i64=0; var distinct: i64=0 59 var q: i64=0 60 while q<N { 61 let dx: i64=PX[q]*W/BW; let dy: i64=PY[q]*H/BW 62 if dx>=0 { if dx<W { if dy>=0 { if dy<H { 63 pchecked = pchecked + 1 64 let px: i64 = fbp[dy*W+dx] 65 if px != bg1 { present = present + 1 } 66 let spd: i64 = isq(VX[q]*VX[q]+VY[q]*VY[q]) 67 var rr: i64 = spd*255/360; if rr>255 { rr=255 } 68 if px == rgb(rr, 80, 255-rr) { matched = matched + 1 } 69 var d: i64=0; var dup: i64=0 70 while d<distinct { if seen[d]==px { dup=1 } d=d+1 } 71 if dup==0 { seen[distinct]=px; distinct=distinct+1 } 72 } } } } 73 q=q+1 74 } 75 76 // ---- isolated head-on collision: exact momentum + energy ---- 77 init_impl(base) 78 i=0; while i<N { VX[i]=0; VY[i]=0; i=i+1 } // freeze the gas 79 PX[0]=7800; PY[0]=8000; VX[0]=120; VY[0]=0 80 PX[1]=8200; PY[1]=8000; VX[1]=0-120; VY[1]=0 // d=400 < 2R=480, head-on approaching 81 var pbx: i64=0; var pby: i64=0; i=0; while i<N { pbx=pbx+VX[i]; pby=pby+VY[i]; i=i+1 } 82 let eb: i64 = energy(base) 83 step_one_impl(base) 84 var pax: i64=0; var pay: i64=0; i=0; while i<N { pax=pax+VX[i]; pay=pay+VY[i]; i=i+1 } 85 let ea: i64 = energy(base) 86 var mom_ok: i64=0; if pax==pbx { if pay==pby { mom_ok=1 } } 87 let ecol_ok: i64 = (ea==eb) as i64 // head-on equal mass -> exact 88 89 g_w(" run: steps=1000 collisions="); g_n(col); g_w(" energy E0="); g_n(e0); g_w(" E1="); g_n(e1); g_w(" drift(permille)="); g_n(drift); g_w("\n") 90 g_w(" thermalization: speed min="); g_n(smin); g_w(" max="); g_n(smax); g_w(" spread="); g_n(spread); g_w(" (all started at 200)\n") 91 g_w(" head-on: momentum before=("); g_n(pbx); g_w(","); g_n(pby); g_w(") after=("); g_n(pax); g_w(","); g_n(pay); g_w(") E "); g_n(eb); g_w("->"); g_n(ea); g_w(" non-bg-px="); g_n(nb); g_w("\n") 92 93 var ran: i64=0; if col>50 { ran=1 } 94 g_row("RUNS + COLLISIONS: 1000 steps integrated and the gas underwent many elastic collisions (>50)" as *u8, ran, pass) 95 g_row("CONTAINED: every particle stayed inside the box (no escape/tunnelling) -- exact elastic walls" as *u8, allin, pass) 96 g_row("ENERGY CONSERVED: total kinetic energy drift < 3% over 1000 steps (elastic dynamics, integer collisions)" as *u8, (drift < 30) as i64, pass) 97 g_row("COLLISION EXACTNESS: an isolated head-on elastic collision conserves total momentum AND kinetic energy exactly" as *u8, mom_ok*ecol_ok, pass) 98 g_row("THERMALIZATION: from a single speed (200) a velocity DISTRIBUTION emerges (spread > 100) -- onset of Maxwell-Boltzmann" as *u8, (spread > 100) as i64, pass) 99 g_row("RASTER: the frame is non-empty (this row only counts non-background pixels -- see the two below)" as *u8, (nb>100) as i64, pass) 100 101 // ★THE ROW ABOVE USED TO CLAIM "20 particles, speed-coloured" WHILE COUNTING PIXELS. nb>100 is 102 // satisfied by ONE particle, or by twenty flat-coloured ones -- neither the count nor the colour 103 // rule was ever tested. Found 2026-08-14 by nx_vacuity_census; same label-overclaims-the-predicate 104 // class as nx_solarsim_gate's "Sun + planets" row, which tested only the Sun. 105 // The screen mapping is taken from render_impl itself rather than re-derived: 106 // dx = PX[i]*W/BW dy = PY[i]*H/BW colour = rgb(min(255, spd*255/360), 80, 255-rr) 107 // EVERY particle is checked and the count is bound to N, so a scan that examined nothing cannot 108 // read as a pass. Presence is tested as "not the background" rather than "equals its own colour" 109 // because two overlapping discs legitimately overwrite each other's centre -- that would be a 110 // flaky tooth, and a flaky tooth is one everybody learns to ignore. 111 g_w(" particles present="); g_n(present); g_w("/"); g_n(pchecked); g_w(" (of N="); g_n(N) 112 g_w(") distinct centre colours="); g_n(distinct); g_w(" exact-colour-match="); g_n(matched) 113 g_w(" (diagnostic: the gate's isq and the engine's isqrt are separate implementations)\n") 114 var parts_ok: i64=0 115 if pchecked==N { if present==N { parts_ok=1 } } 116 g_row("ALL PARTICLES IN FRAME: every one of the N particles is drawn at the screen position render_impl computes -- counted against N so an empty scan cannot pass" as *u8, parts_ok, pass) 117 g_row("SPEED-COLOURED FOR REAL: the particle centres carry MORE THAN ONE colour, so the speed->hue rule is actually applied; twenty flat discs would give exactly one" as *u8, (distinct > 1) as i64, pass) 118 g_row("neg-control-background-uniform: two far-apart pixels on the top row agree, so the presence row above is measuring particles and not background variation" as *u8, (bg1 == bg2) as i64, pass) 119 var iface: i64=0; if ww()==W { if hh()==H { if fb_off()==O_FB { iface=1 } } } 120 g_row("WASM-READY: init/tick/render/ww/hh/fb_off interface intact -- the exact base-relative code wasm runs" as *u8, iface, pass) 121 122 let rc: i64 = gv_verdict("GASSIM-GATE" as *u8, pass, "real kinetic-theory gas; energy-conserving, thermalizing, and every particle verified PRESENT in the rendered frame with the speed-hue rule proven applied" as *u8) 123 sys_exit(rc) 124 return rc 125}