code wiki / (root) / nx_modelfacts.nx

nx_modelfacts.nx source

↩ module page · 259 lines · 11011 B

1// nx_modelfacts.nx -- CLI for 3D model fact extraction into the refcorpus measured-facts plane. 2// 3// nx_modelfacts probe <file> 4// nx_modelfacts sweep <listfile> <source> <provenance> <license> [put] 5// 6// The nx_mediafacts pattern applied to the model classes (GLB/STL/OBJ/PLY): bounded window read 7// + a DRAIN pass so the true file size is known (binary STL detection and truncation honesty 8// both need it), closed fact vocabulary, distribution rows through rc_put_row in-process so the 9// k-anonymity floor physically gates what reaches the journal. 10// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 11import "nx_syscalls.nx" 12import "nx_modelfacts_lib.nx" 13import "nx_mediafacts_lib.nx" // mf_median (sorts in place -- min/max only valid AFTER the call) 14import "nx_refcorpus.nx" 15const MDLC_MAGIC_65536: i64 = 65536 16 17const MDLC_WINDOW: i64 = 4194304 18const MDLC_MAX_FILES: i64 = 4096 19const MDLC_PATH_MAX: i64 = 384 20 21func mdlc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 22func mdlc_w(s: *u8) -> i64 { sys_write(1, s, mdlc_slen(s)); return 0 } 23func mdlc_e(s: *u8) -> i64 { sys_write(2, s, mdlc_slen(s)); return 0 } 24func mdlc_num(v: i64) -> i64 { 25 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 26 var m: i64 = v 27 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 28 let t: *u8 = sys_mmap(32) 29 var k: i64 = 0 30 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 31 let o: *u8 = sys_mmap(32) 32 var i: i64 = 0 33 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 34 sys_write(1, o, k) 35 return 0 36} 37func mdlc_itoa(v: i64, out: *u8) -> i64 { 38 var m: i64 = v 39 var p: i64 = 0 40 if m < 0 { out[p] = 45 as u8; p = p + 1; m = 0 - m } 41 if m == 0 { out[p] = 48 as u8; out[p+1] = 0 as u8; return p + 1 } 42 let t: *u8 = sys_mmap(32) 43 var k: i64 = 0 44 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 45 var i: i64 = 0 46 while i < k { out[p] = t[k - 1 - i]; p = p + 1; i = i + 1 } 47 out[p] = 0 as u8 48 return p 49} 50func mdlc_fmtname(f: i64) -> *u8 { 51 if f == MDL_FMT_GLB { return "glb" as *u8 } 52 if f == MDL_FMT_STL { return "stl" as *u8 } 53 if f == MDL_FMT_OBJ { return "obj" as *u8 } 54 if f == MDL_FMT_PLY { return "ply" as *u8 } 55 return "unknown" as *u8 56} 57 58// window read + DRAIN: buf gets the first MDLC_WINDOW bytes, sizebox[0] the TRUE size (the drain 59// counts the tail without storing it). Returns bytes in buf, or -1 on open failure. 60func mdlc_read(path: *u8, buf: *u8, sizebox: *i64) -> i64 { 61 let fd: i64 = sys_openat_rd(path) 62 if fd < 0 { return 0 - 1 } 63 var got: i64 = 0 64 var stop: i64 = 0 65 while stop == 0 { 66 if got >= MDLC_WINDOW { stop = 1 } else { 67 let k: i64 = sys_read(fd, ((buf as i64) + got) as *u8, MDLC_WINDOW - got) 68 if k <= 0 { stop = 1 } else { got = got + k } 69 } 70 } 71 var total: i64 = got 72 if got >= MDLC_WINDOW { 73 let scratch: *u8 = sys_mmap(MDLC_MAGIC_65536) 74 var d: i64 = 1 75 while d > 0 { d = sys_read(fd, scratch, MDLC_MAGIC_65536); if d > 0 { total = total + d } } 76 } 77 sys_close(fd) 78 sizebox[0] = total 79 return got 80} 81 82func mdlc_print_probe(facts: *i64) -> i64 { 83 mdlc_w("MODELFACT format=" as *u8); mdlc_w(mdlc_fmtname(facts[0])) 84 if facts[1] >= 0 { mdlc_w(" tris=" as *u8); mdlc_num(facts[1]) } 85 if facts[2] >= 0 { mdlc_w(" verts=" as *u8); mdlc_num(facts[2]) } 86 if facts[3] >= 0 { mdlc_w(" faces=" as *u8); mdlc_num(facts[3]) } 87 if facts[4] >= 0 { mdlc_w(" uv_present=" as *u8); mdlc_num(facts[4]) } 88 if facts[5] >= 0 { mdlc_w(" glb_json_bytes=" as *u8); mdlc_num(facts[5]) } 89 if facts[6] >= 0 { mdlc_w(" glb_bin_bytes=" as *u8); mdlc_num(facts[6]) } 90 if facts[7] >= 0 { mdlc_w(" glb_accessors=" as *u8); mdlc_num(facts[7]) } 91 if facts[8] >= 0 { mdlc_w(" glb_skinned_prims=" as *u8); mdlc_num(facts[8]) } 92 if facts[9] >= 0 { mdlc_w(" vrm_present=" as *u8); mdlc_num(facts[9]) } 93 mdlc_w("\n" as *u8) 94 return 0 95} 96 97func mdlc_row(fmt: i64, metric: *u8, val: i64, unit: *u8, cnt: i64, src: *u8, prov: *u8, lic: *u8, do_put: i64, wrote: *i64) -> i64 { 98 let key: *u8 = sys_mmap(160) 99 var p: i64 = 0 100 let fn: *u8 = mdlc_fmtname(fmt) 101 var i: i64 = 0 102 while fn[i] != (0 as u8) { key[p] = fn[i]; p = p + 1; i = i + 1 } 103 key[p] = 95 as u8; p = p + 1 104 i = 0 105 while metric[i] != (0 as u8) { key[p] = metric[i]; p = p + 1; i = i + 1 } 106 key[p] = 0 as u8 107 mdlc_w("MODELFACT-DIST " as *u8); mdlc_w(key); mdlc_w("=" as *u8); mdlc_num(val) 108 mdlc_w(" unit=" as *u8); mdlc_w(unit); mdlc_w(" n=" as *u8); mdlc_num(cnt); mdlc_w("\n" as *u8) 109 if do_put == 0 { return 0 } 110 let vs: *u8 = sys_mmap(32) 111 mdlc_itoa(val, vs) 112 let r: i64 = rc_put_row(src, key, vs, unit, cnt, prov, lic) 113 if r == 0 { wrote[0] = wrote[0] + 1 } 114 return r 115} 116 117// min/median/max rows for one metric's sample array (mf_median sorts first -- T6 law) 118func mdlc_mmm(fmt: i64, base: *u8, arr: *i64, cnt: i64, unit: *u8, src: *u8, prov: *u8, lic: *u8, do_put: i64, wrote: *i64) -> i64 { 119 if cnt <= 0 { return 0 } 120 let med: i64 = mf_median(arr, cnt) 121 let kmin: *u8 = sys_mmap(96) 122 let kmed: *u8 = sys_mmap(96) 123 let kmax: *u8 = sys_mmap(96) 124 var p: i64 = 0 125 var i: i64 = 0 126 while base[i] != (0 as u8) { kmin[p] = base[i]; kmed[p] = base[i]; kmax[p] = base[i]; p = p + 1; i = i + 1 } 127 let smin: *u8 = "_min" as *u8 128 let smed: *u8 = "_median" as *u8 129 let smax: *u8 = "_max" as *u8 130 i = 0; var q: i64 = p 131 while smin[i] != (0 as u8) { kmin[q] = smin[i]; q = q + 1; i = i + 1 } 132 kmin[q] = 0 as u8 133 i = 0; q = p 134 while smed[i] != (0 as u8) { kmed[q] = smed[i]; q = q + 1; i = i + 1 } 135 kmed[q] = 0 as u8 136 i = 0; q = p 137 while smax[i] != (0 as u8) { kmax[q] = smax[i]; q = q + 1; i = i + 1 } 138 kmax[q] = 0 as u8 139 mdlc_row(fmt, kmin, arr[0], unit, cnt, src, prov, lic, do_put, wrote) 140 mdlc_row(fmt, kmed, med, unit, cnt, src, prov, lic, do_put, wrote) 141 mdlc_row(fmt, kmax, arr[cnt-1], unit, cnt, src, prov, lic, do_put, wrote) 142 return 0 143} 144 145func main(argc: i64, argv: *i64) -> i64 { 146 if argc < 3 { 147 mdlc_e("usage: nx_modelfacts probe <file>\n" as *u8) 148 mdlc_e(" nx_modelfacts sweep <listfile> <source> <provenance> <license> [put]\n" as *u8) 149 sys_exit(2) 150 return 2 151 } 152 let verb: *u8 = argv[1] as *u8 153 let buf: *u8 = sys_mmap(MDLC_WINDOW) 154 let sizebox: *i64 = sys_mmap(16) as *i64 155 156 if verb[0] == (112 as u8) { // probe 157 let n: i64 = mdlc_read(argv[2] as *u8, buf, sizebox) 158 if n < 0 { mdlc_e("ERROR: cannot open file\n" as *u8); sys_exit(1); return 1 } 159 let facts: *i64 = sys_mmap(MDL_N_SLOTS * 8) as *i64 160 mdl_probe(buf, n, sizebox[0], facts) 161 mdlc_print_probe(facts) 162 sys_exit(0) 163 return 0 164 } 165 166 if argc < 6 { mdlc_e("sweep needs <listfile> <source> <provenance> <license> [put]\n" as *u8); sys_exit(2); return 2 } 167 let src: *u8 = argv[3] as *u8 168 let prov: *u8 = argv[4] as *u8 169 let lic: *u8 = argv[5] as *u8 170 var do_put: i64 = 0 171 if argc >= 7 { let pv: *u8 = argv[6] as *u8; if pv[0] == (112 as u8) { do_put = 1 } } 172 173 let lp: *i64 = sys_mmap(16) as *i64 174 let lst: *u8 = sys_read_file(argv[2] as *u8, lp) 175 if (lst as i64) == 0 { mdlc_e("ERROR: cannot read listfile\n" as *u8); sys_exit(1); return 1 } 176 let ln: i64 = lp[0] 177 178 // per-format primary-metric samples: glb=accessors, stl=tris, obj/ply=verts 179 let samp: *i64 = sys_mmap(5 * MDLC_MAX_FILES * 8) as *i64 180 let cnt: *i64 = sys_mmap(5 * 8) as *i64 181 var ci: i64 = 0 182 while ci < 5 { cnt[ci] = 0; ci = ci + 1 } 183 var glb_skinned: i64 = 0 184 var glb_vrm: i64 = 0 185 var glb_uv: i64 = 0 186 var glb_total: i64 = 0 187 188 let path: *u8 = sys_mmap(MDLC_PATH_MAX + 8) 189 let facts: *i64 = sys_mmap(MDL_N_SLOTS * 8) as *i64 190 var pos: i64 = 0 191 var files: i64 = 0 192 var skipped: i64 = 0 193 while pos < ln { 194 var pl: i64 = 0 195 var eol: i64 = 0 196 while eol == 0 { 197 if pos >= ln { eol = 1 } else { 198 let c: i64 = lst[pos] as i64 & 0xff 199 pos = pos + 1 200 if c == 10 { eol = 1 } else { 201 if c != 13 { if pl < MDLC_PATH_MAX { path[pl] = c as u8; pl = pl + 1 } } 202 } 203 } 204 } 205 path[pl] = 0 as u8 206 if pl > 0 { if files < MDLC_MAX_FILES { 207 let n2: i64 = mdlc_read(path, buf, sizebox) 208 if n2 <= 0 { skipped = skipped + 1 } else { 209 mdl_probe(buf, n2, sizebox[0], facts) 210 let f: i64 = facts[0] 211 files = files + 1 212 if f != MDL_FMT_UNKNOWN { 213 if f == MDL_FMT_GLB { glb_total = glb_total + 1 214 if facts[8] > 0 { glb_skinned = glb_skinned + 1 } 215 if facts[9] > 0 { glb_vrm = glb_vrm + 1 } 216 if facts[4] > 0 { glb_uv = glb_uv + 1 } } 217 var metric: i64 = 0 - 1 218 if f == MDL_FMT_GLB { metric = facts[7] } 219 if f == MDL_FMT_STL { metric = facts[1] } 220 if f == MDL_FMT_OBJ { metric = facts[2] } 221 if f == MDL_FMT_PLY { metric = facts[2] } 222 if metric >= 0 { let k: i64 = cnt[f] 223 if k < MDLC_MAX_FILES { samp[f * MDLC_MAX_FILES + k] = metric; cnt[f] = k + 1 } } 224 } 225 } 226 } } 227 } 228 229 mdlc_w("MODELFACTS-SWEEP files=" as *u8); mdlc_num(files) 230 mdlc_w(" unreadable=" as *u8); mdlc_num(skipped); mdlc_w("\n" as *u8) 231 232 let wrote: *i64 = sys_mmap(16) as *i64 233 wrote[0] = 0 234 var fmt: i64 = 1 235 while fmt <= 4 { 236 let c2: i64 = cnt[fmt] 237 if c2 > 0 { 238 mdlc_row(fmt, "files_measured" as *u8, c2, "files" as *u8, c2, src, prov, lic, do_put, wrote) 239 var mname: *u8 = "verts" as *u8 240 var munit: *u8 = "verts" as *u8 241 if fmt == MDL_FMT_GLB { mname = "accessors" as *u8; munit = "accessors" as *u8 } 242 if fmt == MDL_FMT_STL { mname = "tris" as *u8; munit = "tris" as *u8 } 243 mdlc_mmm(fmt, mname, ((samp as i64) + fmt * MDLC_MAX_FILES * 8) as *i64, c2, munit, src, prov, lic, do_put, wrote) 244 } 245 fmt = fmt + 1 246 } 247 if glb_total > 0 { 248 mdlc_row(MDL_FMT_GLB, "skinned_files" as *u8, glb_skinned, "files" as *u8, glb_total, src, prov, lic, do_put, wrote) 249 mdlc_row(MDL_FMT_GLB, "vrm_files" as *u8, glb_vrm, "files" as *u8, glb_total, src, prov, lic, do_put, wrote) 250 mdlc_row(MDL_FMT_GLB, "uv_files" as *u8, glb_uv, "files" as *u8, glb_total, src, prov, lic, do_put, wrote) 251 } 252 253 if do_put == 1 { 254 mdlc_w("MODELFACTS-PUT rows_admitted=" as *u8); mdlc_num(wrote[0]); mdlc_w("\n" as *u8) 255 if wrote[0] == 0 { mdlc_e("MODELFACTS-REFUSED-ALL nothing met the admission walls (bucket under the k=8 floor?)\n" as *u8); sys_exit(3); return 3 } 256 } 257 sys_exit(0) 258 return 0 259}