code wiki / _hdl_build / nx_phys3d_gate.nx
nx_phys3d_gate.nx source
↩ module page · 236 lines · 10039 B
1// nx_phys3d_gate.nx -- gate for the unified sovereign rigid-body core (the 07-01 census's named gap).
2// The CLASSIC engine proofs, all integer-deterministic:
3// T1 integrator exactness (free fall matches the loop-computed analytic sum EXACTLY)
4// T2 restitution: e=0.5 bounce apex ~1/4 of drop height; e=0 body RESTS on the ground and stays
5// T3 THE STACK: 8 dynamic boxes on a static ground -- 1200 ticks, bounded drift, ALL ASLEEP at the end
6// T4 friction is real: mu=0.78 slider STOPS; mu=0 slider KEEPS SLIDING (same push, same ticks)
7// T5 determinism: two worlds, same script -> all body slots IDENTICAL after 500 ticks
8// T6 elastic head-on equal masses: velocities SWAP integer-exact (e=1)
9// T7 inelastic head-on (e=0): both stop (momentum symmetric)
10// license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_phys3d.nx"
13import "nx_gate_verdict.nx"
14
15func hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
16func pn(v: i64) -> i64 {
17 let b: *u8 = sys_mmap(32) as *u8
18 var x: i64 = v
19 var neg: i64 = 0
20 if x < 0 { neg = 1; x = 0 - x }
21 var i: i64 = 31
22 if x == 0 { b[i] = 48 as u8; i = i - 1 }
23 while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 }
24 if neg == 1 { b[i] = 45 as u8; i = i - 1 }
25 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i)
26 return 0
27}
28func gabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
29// static ground slab: top surface at y=0
30func mk_ground(base: i64) -> i64 { return ph_add(base, 1, 0, 0 - 512, 0, 100000, 512, 100000, 0, 0, 200) }
31
32func main() -> i64 {
33 let c: *i64 = gv_ctr()
34
35 // ---- T1 integrator exactness: free fall, no contacts ----
36 let w1: i64 = sys_mmap(ph_bytes()) as i64
37 ph_init(w1)
38 let s1: i64 = ph_add(w1, 0, 0, 500000, 0, 64, 64, 64, 256, 0, 0)
39 var refy: i64 = 500000
40 var refv: i64 = 0
41 var t: i64 = 0
42 while t < 60 {
43 ph_step(w1)
44 refv = refv - 178
45 refy = refy + refv / 256
46 t = t + 1
47 }
48 let b1: *i64 = ph_body(w1, s1)
49 hw(" T1 y=" as *u8); pn(b1[2]); hw(" ref=" as *u8); pn(refy); hw("\n" as *u8)
50 gv_check("integrator-exact-60-tick-free-fall-matches-the-analytic-sum-bit-for-bit" as *u8, b1[2] == refy, c)
51
52 // ---- T2 restitution: bounce ratio + rest ----
53 let w2: i64 = sys_mmap(ph_bytes()) as i64
54 ph_init(w2)
55 mk_ground(w2)
56 let sb: i64 = ph_add(w2, 0, 0, 512, 0, 64, 64, 64, 256, 128, 0) // drop from 2m (512 fx256), e=0.5
57 let bb: *i64 = ph_body(w2, sb)
58 // apex = max height AFTER the first impact (v goes positive) -- no fragile descent detection: the
59 // bounce tick's y is naturally LOWER than the previous falling tick's y (that false-tripped phase-2)
60 var apex1: i64 = 0
61 var bounced: i64 = 0
62 t = 0
63 while t < 600 {
64 ph_step(w2)
65 if bb[5] > 0 { bounced = 1 }
66 if bounced == 1 { if bb[2] > apex1 { apex1 = bb[2] } }
67 t = t + 1
68 }
69 // apex of the first rebound with e=0.5 should be ~1/4 of the drop (energy ~ e^2): window [1/8, 1/2.5]
70 var t2: i64 = 1
71 if apex1 * 8 < 512 { t2 = 0 }
72 if apex1 * 5 > 512 * 2 { t2 = 0 }
73 // e=0 rest: fresh sphere, must settle to r above ground (64) within slop and STAY
74 let sr: i64 = ph_add(w2, 0, 1000, 512, 0, 64, 64, 64, 256, 0, 0)
75 var t3i: i64 = 0
76 while t3i < 300 { ph_step(w2); t3i = t3i + 1 }
77 let br: *i64 = ph_body(w2, sr)
78 let resty: i64 = br[2]
79 if gabs(resty - 64) > PH_SLOP + 3 { t2 = 0 }
80 var t3j: i64 = 0
81 while t3j < 100 { ph_step(w2); t3j = t3j + 1 }
82 if br[2] != resty { t2 = 0 }
83 hw(" T2 apex=" as *u8); pn(apex1); hw("/512 resty=" as *u8); pn(resty); hw("\n" as *u8)
84 gv_check("restitution-e-half-rebounds-near-quarter-drop-and-e-zero-rests-and-stays" as *u8, t2 == 1, c)
85
86 // ---- T3 THE STACK: 8 boxes, 1200 ticks, bounded drift, all asleep ----
87 let w3: i64 = sys_mmap(ph_bytes()) as i64
88 ph_init(w3)
89 mk_ground(w3)
90 var k: i64 = 0
91 while k < 8 {
92 ph_add(w3, 1, 0, 64 + k * 128, 0, 64, 64, 64, 256, 0, 200)
93 k = k + 1
94 }
95 t = 0
96 while t < 1200 { ph_step(w3); t = t + 1 }
97 var t3: i64 = 1
98 var awake_n: i64 = 0
99 var maxdrift: i64 = 0
100 k = 0
101 while k < 8 {
102 let bk: *i64 = ph_body(w3, 1 + k)
103 let dy: i64 = gabs(bk[2] - (64 + k * 128))
104 let dx: i64 = gabs(bk[1])
105 let dz: i64 = gabs(bk[3])
106 if dy > maxdrift { maxdrift = dy }
107 if dx > maxdrift { maxdrift = dx }
108 if dz > maxdrift { maxdrift = dz }
109 if bk[14] == 1 { awake_n = awake_n + 1 }
110 k = k + 1
111 }
112 // structural asserts (a slop-per-interface sag is physical for a penalty/impulse solver; what must hold:
113 // order preserved, gaps sane, no lateral wander, and the stack goes to SLEEP)
114 var order_ok: i64 = 1
115 var lateral: i64 = 0
116 k = 0
117 while k < 7 {
118 let lo: *i64 = ph_body(w3, 1 + k)
119 let hi: *i64 = ph_body(w3, 2 + k)
120 let gap: i64 = hi[2] - lo[2]
121 // WARM-START LANDED (2026-07-03): the bound tightens back to the honest [100,150] -- accumulated
122 // impulses hold column weight instead of re-fighting it, so interfaces must rest near the true
123 // 128-slop, not quantization-freeze 50 deep. (The parked-rung history lives in the git/memory trail.)
124 if gap < 100 { order_ok = 0 }
125 if gap > 150 { order_ok = 0 }
126 k = k + 1
127 }
128 k = 0
129 while k < 8 {
130 let bk2: *i64 = ph_body(w3, 1 + k)
131 if gabs(bk2[1]) > lateral { lateral = gabs(bk2[1]) }
132 if gabs(bk2[3]) > lateral { lateral = gabs(bk2[3]) }
133 k = k + 1
134 }
135 if order_ok == 0 { t3 = 0 }
136 if lateral > 12 { t3 = 0 }
137 if awake_n != 0 { t3 = 0 }
138 // diagnostics (always printed -- evidence for any future tuning)
139 let d0: *i64 = ph_body(w3, 1)
140 let d7: *i64 = ph_body(w3, 8)
141 hw(" [t3-diag] box0 y=" as *u8); pn(d0[2]); hw(" vy=" as *u8); pn(d0[5]); hw(" awake=" as *u8); pn(d0[14])
142 hw(" | box7 y=" as *u8); pn(d7[2]); hw(" vy=" as *u8); pn(d7[5]); hw(" awake=" as *u8); pn(d7[14])
143 hw(" | ydrift=" as *u8); pn(maxdrift); hw(" lateral=" as *u8); pn(lateral); hw("\n" as *u8)
144 hw(" [t3-gaps]" as *u8)
145 k = 0
146 while k < 7 {
147 let glo: *i64 = ph_body(w3, 1 + k)
148 let ghi: *i64 = ph_body(w3, 2 + k)
149 hw(" " as *u8); pn(ghi[2] - glo[2])
150 k = k + 1
151 }
152 hw("\n" as *u8)
153 gv_check("stack-8-boxes-1200-ticks-order-kept-gaps-sane-no-lateral-wander-all-asleep" as *u8, t3 == 1, c)
154
155 // ---- T4 friction real: mu-slider stops, mu0-slider slides ----
156 let w4: i64 = sys_mmap(ph_bytes()) as i64
157 ph_init(w4)
158 mk_ground(w4)
159 let f1: i64 = ph_add(w4, 1, 0, 64, 0, 64, 64, 64, 256, 0, 200)
160 t = 0
161 ph_set_vel(w4, f1, 4000, 0, 0)
162 let f2: i64 = ph_add(w4, 1, 0, 64, 100000, 64, 64, 64, 256, 0, 0)
163 ph_set_vel(w4, f2, 4000, 0, 0)
164 while t < 400 { ph_step(w4); t = t + 1 }
165 let bf1: *i64 = ph_body(w4, f1)
166 let bf2: *i64 = ph_body(w4, f2)
167 var t4: i64 = 1
168 if gabs(bf1[4]) > 40 { t4 = 0 }
169 if gabs(bf2[4]) < 3000 { t4 = 0 }
170 hw(" T4 v_mu=" as *u8); pn(bf1[4]); hw(" v_0=" as *u8); pn(bf2[4]); hw("\n" as *u8)
171 gv_check("friction-real-mu-slider-stops-and-mu-zero-slider-keeps-sliding" as *u8, t4 == 1, c)
172
173 // ---- T5 determinism: identical worlds -> identical states ----
174 let wa: i64 = sys_mmap(ph_bytes()) as i64
175 let wb: i64 = sys_mmap(ph_bytes()) as i64
176 ph_init(wa); ph_init(wb)
177 mk_ground(wa); mk_ground(wb)
178 k = 0
179 while k < 6 {
180 ph_add(wa, 1, 0, 64 + k * 128, 0, 64, 64, 64, 256, 0, 200)
181 ph_add(wb, 1, 0, 64 + k * 128, 0, 64, 64, 64, 256, 0, 200)
182 k = k + 1
183 }
184 let pa: i64 = ph_add(wa, 0, 0 - 2000, 800, 0, 64, 64, 64, 256, 128, 100)
185 let pb: i64 = ph_add(wb, 0, 0 - 2000, 800, 0, 64, 64, 64, 256, 128, 100)
186 ph_set_vel(wa, pa, 6000, 2000, 300)
187 ph_set_vel(wb, pb, 6000, 2000, 300)
188 t = 0
189 while t < 500 { ph_step(wa); ph_step(wb); t = t + 1 }
190 var diff: i64 = 0
191 var si: i64 = 0
192 while si < 8 * 16 {
193 let va: *i64 = (wa + 64) as *i64
194 let vb: *i64 = (wb + 64) as *i64
195 if va[si] != vb[si] { diff = diff + 1 }
196 si = si + 1
197 }
198 hw(" T5 diff-slots=" as *u8); pn(diff); hw("\n" as *u8)
199 gv_check("determinism-two-worlds-500-ticks-all-body-slots-identical" as *u8, diff == 0, c)
200
201 // ---- T6 elastic swap (e=1, equal masses, head-on) ----
202 let w6: i64 = sys_mmap(ph_bytes()) as i64
203 ph_init(w6)
204 let e1: i64 = ph_add(w6, 0, 0 - 300, 64, 0, 64, 64, 64, 256, 256, 0)
205 let e2: i64 = ph_add(w6, 0, 300, 64, 0, 64, 64, 64, 256, 256, 0)
206 ph_set_vel(w6, e1, 2000, 0, 0)
207 ph_set_vel(w6, e2, 0 - 2000, 0, 0)
208 t = 0
209 while t < 60 { ph_step(w6); t = t + 1 }
210 let be1: *i64 = ph_body(w6, e1)
211 let be2: *i64 = ph_body(w6, e2)
212 var t6: i64 = 1
213 if gabs(be1[4] + 2000) > 64 { t6 = 0 }
214 if gabs(be2[4] - 2000) > 64 { t6 = 0 }
215 hw(" T6 v1=" as *u8); pn(be1[4]); hw(" v2=" as *u8); pn(be2[4]); hw("\n" as *u8)
216 gv_check("elastic-head-on-equal-masses-velocities-swap-within-rounding" as *u8, t6 == 1, c)
217
218 // ---- T7 inelastic head-on: both stop ----
219 let w7: i64 = sys_mmap(ph_bytes()) as i64
220 ph_init(w7)
221 let i1: i64 = ph_add(w7, 0, 0 - 300, 64, 0, 64, 64, 64, 256, 0, 0)
222 let i2: i64 = ph_add(w7, 0, 300, 64, 0, 64, 64, 64, 256, 0, 0)
223 ph_set_vel(w7, i1, 2000, 0, 0)
224 ph_set_vel(w7, i2, 0 - 2000, 0, 0)
225 t = 0
226 while t < 60 { ph_step(w7); t = t + 1 }
227 let bi1: *i64 = ph_body(w7, i1)
228 let bi2: *i64 = ph_body(w7, i2)
229 var t7: i64 = 1
230 if gabs(bi1[4]) > 32 { t7 = 0 }
231 if gabs(bi2[4]) > 32 { t7 = 0 }
232 hw(" T7 v1=" as *u8); pn(bi1[4]); hw(" v2=" as *u8); pn(bi2[4]); hw("\n" as *u8)
233 gv_check("inelastic-head-on-both-stop" as *u8, t7 == 1, c)
234
235 return gv_verdict("nx_phys3d_gate" as *u8, c, "Unified deterministic rigid-body core: integrate, bounce, stack, friction, replay, elastic and inelastic; each tooth prints the values it judged." as *u8)
236}