code wiki / _hdl_build / nx_kinetics_gate.nx
nx_kinetics_gate.nx source
↩ module page · 66 lines · 4768 B
1// nx_kinetics_gate.nx -- NATIVE verify of the browser reaction-kinetics sim (base = mmap; SAME code runs in
2// sovereign WASM). Validates real chemical-kinetics laws: (a) FIRST-ORDER decay has a CONSTANT half-life --
3// successive halvings (1e6->5e5->2.5e5->1.25e5) take EQUAL step counts (the exponential signature, e.g. carbon
4// dating), (b) mass is conserved ([A]+[B]=A0), (c) a reversible reaction A<=>B settles to equilibrium [B]/[A]=kf/kr.
5// Liar-kill: ZERO-order decay (constant rate) has a SHRINKING half-life (each halving takes ~half the time) -- so
6// the equal-interval test distinguishes reaction orders, exactly as a chemist does. license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_kinetics.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
16// step until [A] <= threshold; return steps taken (assumes [A] starts above threshold)
17func steps_to(base: i64, threshold: i64) -> i64 {
18 let A: *i64=(base+O_A) as *i64; var s: i64=0
19 while s<2000000 { step_one_impl(base); s=s+1; if A[0]<=threshold { return s } }
20 return s
21}
22
23func main() -> i64 {
24 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0
25 g_w("=== NX-KINETICS native verify (chemical reaction kinetics; SAME code runs in sovereign wasm) ===\n")
26 let base: i64 = sys_mmap(2*1048576) as i64
27 let A: *i64=(base+O_A) as *i64; let B: *i64=(base+O_B) as *i64; let M: *i64=(base+O_MODE) as *i64
28 let KN: *i64=(base+O_KNUM) as *i64; let KD: *i64=(base+O_KDEN) as *i64; let KR: *i64=(base+O_KRNUM) as *i64
29
30 // FIRST-ORDER: successive half-lives
31 init_impl(base); M[0]=0
32 let h1: i64=steps_to(base, 500000); let h2: i64=steps_to(base, 250000); let h3: i64=steps_to(base, 125000)
33 let mass_ok: i64 = ((A[0]+B[0])==A0) as i64
34
35 // ZERO-ORDER control (liar-kill): half-life shrinks
36 init_impl(base); M[0]=2
37 let z1: i64=steps_to(base, 500000); let z2: i64=steps_to(base, 250000)
38
39 // REVERSIBLE: equilibrium [B]/[A] = kf/kr (kf=3/1000, kr=1/1000 -> 3.0)
40 init_impl(base); M[0]=1; KN[0]=3; KD[0]=1000; KR[0]=1
41 var s: i64=0; while s<20000 { step_one_impl(base); s=s+1 }
42 let eqr: i64 = B[0]*1000/A[0] // x1000, expect ~3000
43
44 g_w(" first-order half-lives(steps): h1="); g_n(h1); g_w(" h2="); g_n(h2); g_w(" h3="); g_n(h3); g_w(" mass[A]+[B]="); g_n(A0); g_w("\n")
45 g_w(" zero-order: z1="); g_n(z1); g_w(" z2="); g_n(z2); g_w(" (shrinks) reversible eq [B]/[A]x1000="); g_n(eqr); g_w(" (kf/kr=3000)\n")
46
47 init_impl(base); var t: i64=0; while t<120 { tick_impl(base, 0); t=t+1 }
48 render_impl(base)
49 write_png((base + O_FB) as *i64, W, H, "knowledge/nx_kinetics.png" as *u8)
50 let m: *u8=(base+O_FB) as *u8; var nb: i64=0; var i: i64=0
51 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)!=14 { nb=nb+1 } else { if (m[b+2] as i64)!=22 { nb=nb+1 } } } i=i+1 }
52
53 var ran: i64=0; if h1>0 { if h3>0 { ran=1 } }
54 g_row("RUNS: the decay integrated and successive half-times were measured" as *u8, ran, pass)
55 g_row("CONSTANT HALF-LIFE: first-order halvings take EQUAL steps (h2,h3 within 3% of h1) -- the exponential law" as *u8, ((iabs(h2-h1)*100/h1 < 3) as i64)*((iabs(h3-h1)*100/h1 < 3) as i64), pass)
56 g_row("MASS CONSERVED: [A]+[B] = A0 exactly at all times (no atoms created or destroyed)" as *u8, mass_ok, pass)
57 g_row("EQUILIBRIUM: reversible A<=>B settles to [B]/[A] = kf/kr = 3.0 within 3%" as *u8, (iabs(eqr-3000) < 90) as i64, pass)
58 g_row("LIAR-KILL: ZERO-order decay's half-life SHRINKS (z2 < 0.7*z1) -- the equal-interval test detects reaction order" as *u8, (z2 < z1*70/100) as i64, pass)
59 g_row("RASTER: framebuffer drawn (decay curve + [A]/[B] bars) -> knowledge/nx_kinetics.png" as *u8, (nb>100) as i64, pass)
60 var iface: i64=0; if ww()==W { if hh()==H { if fb_off()==O_FB { iface=1 } } }
61 g_row("WASM-READY: init/tick/render/ww/hh/fb_off interface intact" as *u8, iface, pass)
62
63 g_w("NX-KINETICS-GATE rows=7 pass="); g_n(pass[0])
64 if pass[0]==7 { g_w(" verdict=GREEN (real reaction kinetics; constant half-life + equilibrium + mass conservation, browser-ready)\n"); sys_exit(0); return 0 }
65 g_w(" verdict=RED\n"); sys_exit(1); return 1
66}