code wiki / _hdl_build / nx_interp_gate.nx
nx_interp_gate.nx source
↩ module page · 119 lines · 6339 B
1// nx_interp_gate.nx -- proves + MEASURES the sovereign snapshot interpolation buffer (nx_interp):
2// under packet LOSS + REORDERING, render-in-the-past interpolation reconstructs the peer's true path
3// (loss becomes invisible) while naive snap-to-latest (zero-order hold) staircases. This is what keeps
4// the bad-mobile-network player smooth.
5// 1) reorder-safe + correct: out-of-order pushes -> time-sorted history; interp ~= truth (loss invisible)
6// 2) EXCEED vs naive (neg-control = zero-order hold): interp max error << naive max error (measured)
7// 3) SMOOTHNESS: interp max per-step jump < naive max per-step jump (measured)
8// 4) yaw shortest-arc: 350deg -> 10deg interpolates through 0 (not the long way)
9// 5) no-data (neg): empty history -> sample returns 0 (no fabricated pose)
10// 6) clamp: before-first -> status 2, at/after-last -> status 3 (hold; extrapolate = NET-R2)
11// Built nx_cc_sovereign -> nxasm_x86 (no gcc, no .sh). license_tier: ORIGINAL
12import "nx_syscalls.nx"
13import "nx_gate_emit_lib.nx"
14import "nx_interp.nx"
15import "nx_gate_verdict.nx"
16
17func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
18// build a snapshot with x=val (other fields fixed) for the path proof
19func mkf(f: *i64, x: i64) -> i64 { var i: i64=0; while i<10 { f[i]=0; i=i+1 } f[0]=x; return 0 }
20// naive zero-order hold: value of the newest RECEIVED sample with time <= rt; val(t)=t/2
21func naive_x(times: *i64, nr: i64, rt: i64) -> i64 {
22 var best: i64 = times[0]
23 var i: i64 = 0
24 while i < nr { if times[i] <= rt { best = times[i] } i = i + 1 }
25 return best / 2
26}
27
28func main() -> i64 {
29 g_puts("nx_interp gate (sovereign snapshot interpolation: smooth under loss+jitter+reorder)\n" as *u8)
30 var pass: i64 = 0; var total: i64 = 0
31
32 let K: i64 = 16
33 let hist: *i64 = sys_mmap((1 + K*IP_STRIDE) * 8) as *i64
34 ip_init(hist)
35 let f: *i64 = sys_mmap(10*8) as *i64
36 let out: *i64 = sys_mmap(10*8) as *i64
37
38 // ground truth path val(t)=t/2 sampled at 0,100,...,1000; DROP 300/600/900 (loss); push 500 BEFORE 400 (reorder)
39 let times: *i64 = sys_mmap(8*8) as *i64
40 times[0]=0; times[1]=100; times[2]=200; times[3]=400; times[4]=500; times[5]=700; times[6]=800; times[7]=1000
41 // push in a deliberately out-of-order sequence
42 mkf(f, 0); ip_push(hist, K, 0, f)
43 mkf(f, 50); ip_push(hist, K, 100, f)
44 mkf(f, 100); ip_push(hist, K, 200, f)
45 mkf(f, 250); ip_push(hist, K, 500, f) // 500 pushed BEFORE 400 (reorder)
46 mkf(f, 200); ip_push(hist, K, 400, f)
47 mkf(f, 350); ip_push(hist, K, 700, f)
48 mkf(f, 400); ip_push(hist, K, 800, f)
49 mkf(f, 500); ip_push(hist, K, 1000, f)
50
51 // 1) reorder-safe (sorted) + correct (interp ~= truth despite the 3 drops)
52 var sorted: i64 = 1
53 var i: i64 = 1
54 while i < ip_count(hist) { if ip_time(hist, i-1) > ip_time(hist, i) { sorted = 0 } i = i + 1 }
55 var ei_max: i64 = 0; var en_max: i64 = 0
56 var si_max: i64 = 0; var sn_max: i64 = 0
57 var prev_i: i64 = 0 - 1; var prev_n: i64 = 0 - 1
58 var rt: i64 = 150
59 while rt <= 850 {
60 ip_sample(hist, rt, out)
61 let ix: i64 = out[0]
62 let truev: i64 = rt / 2
63 let ei: i64 = g_abs(ix - truev); if ei > ei_max { ei_max = ei }
64 let nxv: i64 = naive_x(times, 8, rt)
65 let en: i64 = g_abs(nxv - truev); if en > en_max { en_max = en }
66 if prev_i >= 0 { let s: i64 = g_abs(ix - prev_i); if s > si_max { si_max = s } }
67 if prev_n >= 0 { let s: i64 = g_abs(nxv - prev_n); if s > sn_max { sn_max = s } }
68 prev_i = ix; prev_n = nxv
69 rt = rt + 50
70 }
71 g_puts(" [measure] over a lossy(3 drops)+reordered stream: interp_max_err=" as *u8); g_pn(ei_max)
72 g_puts(" naive_max_err=" as *u8); g_pn(en_max); g_puts("\n" as *u8)
73 g_puts(" [measure] per-step jump: interp_max=" as *u8); g_pn(si_max); g_puts(" naive_max=" as *u8); g_pn(sn_max); g_puts("\n" as *u8)
74 var r1: i64 = 1
75 if sorted != 1 { r1 = 0 }
76 if ei_max > 2 { r1 = 0 } // interp reconstructs truth within 2 voxels (loss invisible)
77 pass = pass + g_check("reorder-safe + interp reconstructs truth under loss" as *u8, r1); total=total+1
78
79 // 2) EXCEED vs naive ZOH (measured)
80 pass = pass + g_check("interp_max_err < naive_max_err (smoother than snap-to-latest)" as *u8, ei_max < en_max); total=total+1
81
82 // 3) SMOOTHNESS (measured): interp never jumps as hard as naive
83 pass = pass + g_check("interp per-step jump < naive per-step jump" as *u8, si_max < sn_max); total=total+1
84
85 // 4) yaw shortest-arc
86 let hy: *i64 = sys_mmap((1 + 4*IP_STRIDE) * 8) as *i64
87 ip_init(hy)
88 mkf(f, 0); f[3] = 350; ip_push(hy, 4, 0, f)
89 mkf(f, 0); f[3] = 10; ip_push(hy, 4, 100, f)
90 ip_sample(hy, 50, out)
91 let yv: i64 = out[3]
92 var r4: i64 = 0
93 if yv <= 5 { r4 = 1 }
94 if yv >= 355 { r4 = 1 } // ~0deg (== 360) the short way, NOT ~180
95 g_puts(" [measure] yaw lerp 350->10 at half = " as *u8); g_pn(yv); g_puts(" deg (expect ~0/360, not ~180)\n" as *u8)
96 pass = pass + g_check("yaw interpolates shortest-arc through 0" as *u8, r4); total=total+1
97
98 // 5) no-data neg-control
99 let he: *i64 = sys_mmap((1 + 4*IP_STRIDE) * 8) as *i64
100 ip_init(he)
101 let st0: i64 = ip_sample(he, 500, out)
102 pass = pass + g_check("empty history -> no fabricated pose (status 0)" as *u8, st0 == 0); total=total+1
103
104 // 6) clamp before-first / at-after-last
105 let sbefore: i64 = ip_sample(hist, 0 - 50, out)
106 let safter: i64 = ip_sample(hist, 5000, out)
107 pass = pass + g_check("clamp: before-first=2, after-last=3" as *u8, (sbefore == 2) & (safter == 3)); total=total+1
108
109 g_puts("---- interp gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
110 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
111 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
112 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
113 let ctr__dry: *i64 = gv_ctr()
114 ctr__dry[0] = pass
115 ctr__dry[1] = total
116 let rc__dry: i64 = gv_verdict("INTERP-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
117 sys_exit(rc__dry)
118 return rc__dry
119}