code wiki / (root) / nx_mmdev_gate.nx

nx_mmdev_gate.nx source

↩ module page · 118 lines · 6887 B

1// nx_mmdev_gate.nx -- GATE for the millimetre surface-deviation ruler (PG4, procgen.plan, 2026-08-24). 2// 3// A ruler is proven by geometry whose true answer is known BEFORE the ruler runs. The fixtures here are 4// NXMSH2 meshes written through the same nx_nxmesh_lib the ruler reads, so the codec round-trip is under 5// test too, in caller-owned mmap -- never a production plane. 6// 7// KNOWN ANSWERS: a unit square (two triangles, 100 mm on a side) against a copy of itself lifted 5.0 mm 8// along its normal. Every vertex of one sits exactly 5.0 mm from the other's surface, so mean, p95 and 9// max must ALL read 50 in tenths of a millimetre. A wrong point-triangle case (edge or corner region 10// taken instead of the face) would read larger; a wrong sign or a dropped axis would read 0 or ~70. 11// That is the anti-vacuity property: the trivial wrong implementations cannot pass it. 12 13import "nx_syscalls.nx" 14import "nx_gate_verdict.nx" 15import "nx_vecmath.nx" 16import "nx_nxmesh_lib.nx" 17import "nx_mmdev_lib.nx" 18 19// 100 mm square in tenths of a millimetre; lift of exactly 5.0 mm. 20const MG_SIDE: i64 = 1000 21const MG_LIFT: i64 = 50 22const MG_LIFT2: i64 = 2500 23// One tenth of a millimetre of slack for the f32 round trip at 0.1 mm resolution -- the codec rounds to 24// nearest, so the worst case is half a unit per coordinate. Printed beside every measurement. 25const MG_SLACK: i64 = 1 26 27// Two triangles: (0,0,0)(S,0,0)(S,S,0) and (0,0,0)(S,S,0)(0,S,0), lifted by `lift` along +z. 28func mg_square(buf: *u8, lift: i64) -> i64 { 29 nm_put_u32(buf, NM_OFF_NLAYERS, 0) 30 nm_put_u32(buf, NM_OFF_NTRIS, 2) 31 let tb: i64 = nm_tri_base(buf) 32 let p: *i64 = sys_mmap(9 * 8) as *i64 33 p[0]=0; p[1]=0; p[2]=lift; p[3]=MG_SIDE; p[4]=0; p[5]=lift; p[6]=MG_SIDE; p[7]=MG_SIDE; p[8]=lift 34 nm_put_tri(buf, tb, 0, p) 35 p[0]=0; p[1]=0; p[2]=lift; p[3]=MG_SIDE; p[4]=MG_SIDE; p[5]=lift; p[6]=0; p[7]=MG_SIDE; p[8]=lift 36 nm_put_tri(buf, tb, 1, p) 37 return 0 38} 39 40func mg_near(a: i64, b: i64) -> i64 { var d: i64 = a - b; if d < 0 { d = 0 - d } if d <= MG_SLACK { return 1 } return 0 } 41 42func main() -> i64 { 43 let c: *i64 = gv_ctr() 44 gv_head("NX-MMDEV-GATE -- millimetre surface deviation ruler (PG4)" as *u8) 45 46 let bytes: i64 = nm_file_bytes(0, 2) 47 let base: *u8 = sys_mmap(bytes + 16) 48 let lifted: *u8 = sys_mmap(bytes + 16) 49 mg_square(base, 0) 50 mg_square(lifted, MG_LIFT) 51 52 // ---- codec round trip through the shared lib --------------------------------------------------- 53 let tb: i64 = nm_tri_base(base) 54 let rx: i64 = nm_coord(base, tb, 0, 1, 0) 55 let rz: i64 = nm_coord(lifted, tb, 0, 0, 2) 56 gv_puts(" codec S->" as *u8); gv_num(rx); gv_puts(" lift->" as *u8); gv_num(rz); gv_puts("\n" as *u8) 57 gv_check("f32-codec-round-trips-the-fixture-within-slack" as *u8, mg_near(rx, MG_SIDE) == 1 && mg_near(rz, MG_LIFT) == 1, c) 58 59 // ---- point-to-triangle on known cases --------------------------------------------------------- 60 // face interior: point above the centre of the first triangle 61 let dface: i64 = md_dist2_pt_tri(600, 300, MG_LIFT, 0,0,0, MG_SIDE,0,0, MG_SIDE,MG_SIDE,0) 62 // vertex region: point beyond corner A along the outward diagonal, at distance sqrt(2)*100 -> 141 63 let dvert: i64 = md_dist2_pt_tri(0-100, 0-100, 0, 0,0,0, MG_SIDE,0,0, MG_SIDE,MG_SIDE,0) 64 // edge region: point 100 below edge AB at its midpoint 65 let dedge: i64 = md_dist2_pt_tri(500, 0-100, 0, 0,0,0, MG_SIDE,0,0, MG_SIDE,MG_SIDE,0) 66 gv_puts(" pt-tri face d2=" as *u8); gv_num(dface); gv_puts(" (expect " as *u8); gv_num(MG_LIFT2) 67 gv_puts(") vertex d2=" as *u8); gv_num(dvert); gv_puts(" (expect 20000) edge d2=" as *u8); gv_num(dedge) 68 gv_puts(" (expect 10000)\n" as *u8) 69 gv_check("point-triangle-face-region-exact" as *u8, dface == MG_LIFT2, c) 70 gv_check("point-triangle-vertex-region-exact" as *u8, dvert == 20000, c) 71 gv_check("point-triangle-edge-region-exact" as *u8, dedge == 10000, c) 72 73 // ---- the ruler: known 5.0 mm answer, both directions ------------------------------------------ 74 let ab: *i64 = md_res() 75 let rc1: i64 = md_measure(base, lifted, ab) 76 gv_subjects("tri-verts-measured" as *u8, ab[MD_R_VERTS], c) 77 gv_puts(" base->lifted rc=" as *u8); gv_num(rc1) 78 gv_puts(" mean=" as *u8); gv_num(md_mean(ab)); gv_puts(" p95=" as *u8); gv_num(ab[MD_R_P95]) 79 gv_puts(" max=" as *u8); gv_num(ab[MD_R_MAX]); gv_puts(" expect all " as *u8); gv_num(MG_LIFT) 80 gv_puts(" slack=" as *u8); gv_num(MG_SLACK); gv_puts("\n" as *u8) 81 gv_check("known-5mm-lift-reads-5mm-mean-p95-and-max" as *u8, 82 rc1 == 0 && mg_near(md_mean(ab), MG_LIFT) == 1 && mg_near(ab[MD_R_P95], MG_LIFT) == 1 && mg_near(ab[MD_R_MAX], MG_LIFT) == 1, c) 83 84 let ba: *i64 = md_res() 85 let rc2: i64 = md_measure(lifted, base, ba) 86 gv_puts(" lifted->base mean=" as *u8); gv_num(md_mean(ba)); gv_puts("\n" as *u8) 87 gv_check("ruler-is-symmetric-on-a-parallel-offset" as *u8, rc2 == 0 && mg_near(md_mean(ba), md_mean(ab)) == 1, c) 88 89 // ---- self-compare is the non-vacuity proof: a mesh is ZERO from itself ------------------------ 90 let self: *i64 = md_res() 91 let rc3: i64 = md_measure(base, base, self) 92 gv_puts(" self mean=" as *u8); gv_num(md_mean(self)); gv_puts(" max=" as *u8); gv_num(self[MD_R_MAX]); gv_puts("\n" as *u8) 93 gv_check("self-compare-reads-exactly-zero" as *u8, rc3 == 0 && md_mean(self) == 0 && self[MD_R_MAX] == 0, c) 94 95 // ---- neg-controls ------------------------------------------------------------------------------ 96 // A refusal, not garbage: a subject over the derived extent bound. Build one triangle 3 m long. 97 let huge: *u8 = sys_mmap(nm_file_bytes(0, 1) + 16) 98 nm_put_u32(huge, NM_OFF_NLAYERS, 0) 99 nm_put_u32(huge, NM_OFF_NTRIS, 1) 100 let p: *i64 = sys_mmap(9 * 8) as *i64 101 p[0]=0; p[1]=0; p[2]=0; p[3]=30000; p[4]=0; p[5]=0; p[6]=0; p[7]=100; p[8]=0 102 nm_put_tri(huge, nm_tri_base(huge), 0, p) 103 let rr: *i64 = md_res() 104 let rc4: i64 = md_measure(base, huge, rr) 105 gv_puts(" neg-control 3m subject rc=" as *u8); gv_num(rc4); gv_puts(" (1 = REFUSED extent)\n" as *u8) 106 gv_check("neg-control-over-extent-subject-is-refused-by-name-not-measured" as *u8, rc4 == 1, c) 107 108 let empty: *u8 = sys_mmap(NM_HDR + 16) 109 nm_put_u32(empty, NM_OFF_NLAYERS, 0) 110 nm_put_u32(empty, NM_OFF_NTRIS, 0) 111 let re: *i64 = md_res() 112 let rc5: i64 = md_measure(base, empty, re) 113 gv_puts(" neg-control empty reference rc=" as *u8); gv_num(rc5); gv_puts(" (3 = empty)\n" as *u8) 114 gv_check("neg-control-empty-reference-refuses-rather-than-reporting-zero-deviation" as *u8, rc5 == 3, c) 115 116 return gv_verdict("nx_mmdev_gate" as *u8, c, 117 "Deviation in tenths of a millimetre against geometry with a known answer; the codec, the point-triangle regions, both directions, self-zero and two refusals each print their value." as *u8) 118}