code wiki / _hdl_build / nx_kind.nx
nx_kind.nx source
↩ module page · 586 lines · 25392 B
1// nx_kind.nx -- L0 OF THE SEMANTIC LADDER, OMNI EDITION (debts 1785954089 + 1785955711; operator
2// 2026-08-05: "animal, human, humanoid, real, fantasy, natural object, mechanical -- whatever fits the
3// ontological goal"). Successor to nx_bodyparts v1, which COMPILED IN "humanoid" and could therefore
4// only ever recognise one species -- the exact magic-number/spec-as-data violation the estate forbids.
5//
6// A KIND IS A ROW, NOT A FUNCTION. Schemas are predicates over a mesh's structural signature; the
7// organ evaluates a mesh against EVERY registered kind and reports the best match plus WHY each other
8// failed. Adding "quadruped" or "fastener" is an append, never a recompile.
9//
10// SIGNATURE (rig-free, works on any mesh soup): slice along the declared stack axis into bands; in each
11// band build a histogram over the declared cluster axis; count occupied runs (clusters) and the span
12// width. Triangle SPANS are rasterised, not vertices (a coarse box must occupy every band it crosses --
13// a refusal from an empty measurement is not a refusal from a measurement).
14//
15// SCHEMA ROWS (plane knowledge/store/kind-, tab-separated, key-first; last-wins by convention):
16// <kind> stack <axis 0=x 1=y 2=z> <cluster-axis> -- declares the frame
17// <kind> band <lo> <hi> <minclust> <maxclust> <label> -- lo/hi are per-mille of extent
18// <kind> narrow <lo> <hi> <frac-permil-of-max> <label> -- a waist/neck: a width MINIMUM
19// Unknown verbs are IGNORED ADDITIVELY so new predicate kinds (radial-symmetry, periodicity, genus)
20// can be seeded before this organ learns to test them.
21//
22// nx_kind <mesh.nxmesh> [bands] (schemas from the plane)
23// nx_kind schema <file> <mesh.nxmesh> [bands] (schemas from a file -- offline/selftest)
24// nx_kind selftest
25// license_tier: ORIGINAL expect_exit: 0
26import "nx_syscalls.nx"
27import "nx_store_seed_lib.nx"
28const KD_MAGIC_65536: i64 = 65536
29const KD_MAGIC_1600: i64 = 1600
30const KD_MAGIC_262144: i64 = 262144
31const KD_MAGIC_1350: i64 = 1350
32const KD_MAGIC_1300: i64 = 1300
33const KD_MAGIC_1430: i64 = 1430
34const KD_MAGIC_1100: i64 = 1100
35
36const KD_CAP: i64 = 33554432
37const KD_SCAP: i64 = 262144
38const KD_MAXTRI: i64 = 400000
39const KD_MAXBAND: i64 = 256
40const KD_BINS: i64 = 128
41const KD_GAP: i64 = 2
42const KD_MAXTAX: i64 = 32
43const KD_MAXRULE: i64 = 256
44const KD_NAMECAP: i64 = 32
45const KD_M8388607: i64 = 8388607
46const KD_M8388608: i64 = 8388608
47const KD_BIG: i64 = 4611686018427387903
48const KD_TAB: i64 = 9
49const KD_NL: i64 = 10
50
51func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
52func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
53func kd_pr(b: *u8, a: i64, e: i64) -> i64 { if e > a { sys_write(1, ((b as i64)+a) as *u8, e-a) } return 0 }
54func kd_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64) + ((b[o+1] as i64)<<8) + ((b[o+2] as i64)<<16) + ((b[o+3] as i64)<<24) }
55func kd_f32q(w: i64) -> i64 {
56 let sign: i64 = (w >> 31) & 1
57 let expo: i64 = (w >> 23) & 255
58 if expo == 0 { return 0 }
59 var mant: i64 = (w & KD_M8388607) | KD_M8388608
60 let sh: i64 = expo - 127
61 var v: i64 = 0
62 if sh >= 23 { if sh - 23 > 30 { return 0 } }
63 if sh >= 23 { v = mant * 100 * (1 << (sh - 23)) }
64 if sh < 23 { if 23 - sh > 62 { return 0 } }
65 if sh < 23 { v = (mant * 100) >> (23 - sh) }
66 if sign == 1 { return 0 - v }
67 return v
68}
69func kd_refuse(reason: *u8) -> i64 { hw("KIND REFUSED: " as *u8); hw(reason); hw("\n" as *u8); return 0 }
70
71func kd_load(path: *u8, vx: *i64) -> i64 {
72 let fd: i64 = sys_openat_rd(path)
73 if fd < 0 { return 0 - 1 }
74 let b: *u8 = sys_mmap(KD_CAP + 64)
75 var n: i64 = 0
76 var go: i64 = 1
77 while go == 1 {
78 let r: i64 = sys_read(fd, ((b as i64) + n) as *u8, KD_CAP - n)
79 if r <= 0 { go = 0 } else { n = n + r }
80 if n >= KD_CAP { go = 0 }
81 }
82 sys_close(fd)
83 if n < 44 { return 0 - 1 }
84 if b[0] != (78 as u8) { return 0 - 1 }
85 if b[5] != (50 as u8) { return 0 - 1 }
86 let nlay: i64 = kd_u32(b, 8)
87 let nt: i64 = kd_u32(b, 12)
88 if nt <= 0 { return 0 - 1 }
89 if nt > KD_MAXTRI { return 0 - 1 }
90 let hdr: i64 = 16 + nlay*24
91 if hdr + nt*84 > n { return 0 - 1 }
92 var t: i64 = 0
93 while t < nt {
94 var c: i64 = 0
95 while c < 9 { vx[t*9+c] = kd_f32q(kd_u32(b, hdr + t*84 + c*4)); c = c + 1 }
96 t = t + 1
97 }
98 return nt
99}
100func kd_readfile(path: *u8, buf: *u8, cap: i64) -> i64 {
101 let fd: i64 = sys_openat_rd(path)
102 if fd < 0 { return 0 - 1 }
103 var n: i64 = 0
104 var go: i64 = 1
105 while go == 1 {
106 let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n)
107 if r <= 0 { go = 0 } else { n = n + r }
108 if n >= cap { go = 0 }
109 }
110 sys_close(fd)
111 return n
112}
113
114// ---- signature: clusters + width per band, over declared axes ----
115static KD_CL: i64
116static KD_WD: i64
117static KD_NB: i64
118func kd_clusters(occ: *i64) -> i64 {
119 var runs: i64 = 0
120 var inrun: i64 = 0
121 var empty: i64 = 0
122 var i: i64 = 0
123 while i < KD_BINS {
124 if occ[i] > 0 {
125 if inrun == 0 { runs = runs + 1; inrun = 1 }
126 empty = 0
127 } else {
128 empty = empty + 1
129 if empty >= KD_GAP { inrun = 0 }
130 }
131 i = i + 1
132 }
133 return runs
134}
135func kd_width(occ: *i64) -> i64 {
136 var lo: i64 = 0 - 1
137 var hi: i64 = 0 - 1
138 var i: i64 = 0
139 while i < KD_BINS {
140 if occ[i] > 0 { if lo < 0 { lo = i } hi = i }
141 i = i + 1
142 }
143 if lo < 0 { return 0 }
144 return hi - lo + 1
145}
146// ★A PREDICATE OVER A 2-AXIS PROJECTION MEASURES A SHADOW UNLESS IT WINDOWS THE THIRD AXIS
147// (found 2026-08-05 by the quadruped fixture: its barrel spans the same z as the legs beneath it, so
148// legs+barrel merged into ONE cluster and 'four legs' was untestable). wlo/whi are per-mille of the
149// THIRD axis extent (the one that is neither stack nor cluster); 0..1000 = no filter.
150func kd_sig(vx: *i64, nt: i64, nband: i64, sa: i64, ca: i64, wlo: i64, whi: i64) -> i64 {
151 var wa: i64 = 3 - sa - ca
152 var wmn: i64 = KD_BIG
153 var wmx: i64 = 0-KD_BIG
154 var tw: i64 = 0
155 while tw < nt {
156 var cw: i64 = 0
157 while cw < 3 {
158 let wv: i64 = vx[tw*9+cw*3+wa]
159 if wv < wmn { wmn = wv }
160 if wv > wmx { wmx = wv }
161 cw = cw + 1
162 }
163 tw = tw + 1
164 }
165 var wext: i64 = wmx - wmn
166 if wext < 1 { wext = 1 }
167 var smn: i64 = KD_BIG
168 var smx: i64 = 0-KD_BIG
169 var cmn: i64 = KD_BIG
170 var cmx: i64 = 0-KD_BIG
171 var t: i64 = 0
172 while t < nt {
173 var c: i64 = 0
174 while c < 3 {
175 let s: i64 = vx[t*9+c*3+sa]
176 let u: i64 = vx[t*9+c*3+ca]
177 if s < smn { smn = s }
178 if s > smx { smx = s }
179 if u < cmn { cmn = u }
180 if u > cmx { cmx = u }
181 c = c + 1
182 }
183 t = t + 1
184 }
185 var ext: i64 = smx - smn
186 if ext < 1 { return 0 - 1 }
187 var wid: i64 = cmx - cmn
188 if wid < 1 { wid = 1 }
189 let grid: *i64 = sys_mmap(KD_MAXBAND*KD_BINS*8 + 64) as *i64
190 var g: i64 = 0
191 while g < nband*KD_BINS { grid[g] = 0; g = g + 1 }
192 t = 0
193 while t < nt {
194 var slo: i64 = vx[t*9+sa]
195 var shi: i64 = slo
196 var ulo: i64 = vx[t*9+ca]
197 var uhi: i64 = ulo
198 var c2: i64 = 1
199 while c2 < 3 {
200 let ss: i64 = vx[t*9+c2*3+sa]
201 let uu: i64 = vx[t*9+c2*3+ca]
202 if ss < slo { slo = ss }
203 if ss > shi { shi = ss }
204 if uu < ulo { ulo = uu }
205 if uu > uhi { uhi = uu }
206 c2 = c2 + 1
207 }
208 // third-axis window filter (per-mille of that axis' extent)
209 var wc: i64 = (vx[t*9+wa] + vx[t*9+3+wa] + vx[t*9+6+wa])/3
210 var wpm: i64 = (wc - wmn)*1000/wext
211 var keep: i64 = 0
212 if wpm >= wlo { if wpm <= whi { keep = 1 } }
213 var b0: i64 = (slo - smn)*nband/ext
214 var b1: i64 = (shi - smn)*nband/ext
215 if b0 < 0 { b0 = 0 }
216 if b1 >= nband { b1 = nband-1 }
217 var i0: i64 = (ulo - cmn)*KD_BINS/wid
218 var i1: i64 = (uhi - cmn)*KD_BINS/wid
219 if i0 < 0 { i0 = 0 }
220 if i1 >= KD_BINS { i1 = KD_BINS-1 }
221 if keep == 1 {
222 var bb: i64 = b0
223 while bb <= b1 {
224 var ii: i64 = i0
225 while ii <= i1 { grid[bb*KD_BINS + ii] = grid[bb*KD_BINS + ii] + 1; ii = ii + 1 }
226 bb = bb + 1
227 }
228 }
229 t = t + 1
230 }
231 if KD_CL == 0 { KD_CL = sys_mmap(KD_MAXBAND*8) as i64; KD_WD = sys_mmap(KD_MAXBAND*8) as i64 }
232 let cl: *i64 = KD_CL as *i64
233 let wd: *i64 = KD_WD as *i64
234 var b3: i64 = 0
235 while b3 < nband {
236 cl[b3] = kd_clusters(((grid as i64) + b3*KD_BINS*8) as *i64)
237 wd[b3] = kd_width(((grid as i64) + b3*KD_BINS*8) as *i64)
238 b3 = b3 + 1
239 }
240 KD_NB = nband
241 return ext
242}
243
244// ---- schema parsing ----
245func kd_eol(b: *u8, n: i64, i: i64) -> i64 {
246 var e: i64 = i
247 while e < n { if b[e] == (KD_NL as u8) { return e } else { e = e + 1 } }
248 return n
249}
250// fill col[0..2k] with start/end of up to maxc tab-separated fields in [ls,le)
251func kd_cols(b: *u8, ls: i64, le: i64, col: *i64, maxc: i64) -> i64 {
252 var c: i64 = 0
253 var p: i64 = ls
254 while c < maxc {
255 // ★A BREAK-BY-SENTINEL THAT OVERWRITES THE CURSOR DESTROYS THE POSITION IT EXISTS TO REPORT
256 // (banked law, re-broken here 2026-08-05 = 4th occurrence: q=le+le then q-le-le is 0, so every
257 // field parsed EMPTY and all 7 kinds came back nameless). Terminate with a FLAG, never the cursor.
258 var q: i64 = p
259 var fnd: i64 = 0
260 while fnd == 0 {
261 if q >= le { fnd = 1 } else { if b[q] == (KD_TAB as u8) { fnd = 1 } else { q = q + 1 } }
262 }
263 col[c*2] = p
264 col[c*2+1] = q
265 if q >= le { c = c + 1; while c < maxc { col[c*2] = le; col[c*2+1] = le; c = c + 1 } return c }
266 p = q + 1
267 c = c + 1
268 }
269 return c
270}
271func kd_int(b: *u8, a: i64, e: i64) -> i64 {
272 var v: i64 = 0
273 var neg: i64 = 0
274 var i: i64 = a
275 if i < e { if b[i] == (45 as u8) { neg = 1; i = i + 1 } }
276 while i < e {
277 let ch: i64 = b[i] as i64
278 if ch >= 48 { if ch <= 57 { v = v*10 + (ch-48) } }
279 i = i + 1
280 }
281 if neg == 1 { return 0 - v }
282 return v
283}
284func kd_same(b: *u8, a: i64, e: i64, lit: *u8) -> i64 {
285 var l: i64 = 0
286 while lit[l] != (0 as u8) { l = l + 1 }
287 if e - a != l { return 0 }
288 var i: i64 = 0
289 while i < l { if b[a+i] != lit[i] { return 0 } i = i + 1 }
290 return 1
291}
292func kd_streq(b: *u8, a1: i64, e1: i64, a2: i64, e2: i64) -> i64 {
293 if e1-a1 != e2-a2 { return 0 }
294 var i: i64 = 0
295 while i < e1-a1 { if b[a1+i] != b[a2+i] { return 0 } i = i + 1 }
296 return 1
297}
298
299func kd_run(meshp: *u8, sb: *u8, sn: i64, nband: i64) -> i64 {
300 let vx: *i64 = sys_mmap(KD_MAXTRI*9*8 + 64) as *i64
301 let nt: i64 = kd_load(meshp, vx)
302 if nt < 0 { kd_refuse("mesh unreadable or not NXMSH2" as *u8); return 3 }
303 if sn <= 0 { kd_refuse("no kind schemas (plane empty or file unreadable) -- refusing to guess an ontology" as *u8); return 4 }
304 // distinct kind names (first field of each row)
305 let tn0: *i64 = sys_mmap(KD_MAXTAX*8) as *i64
306 let tn1: *i64 = sys_mmap(KD_MAXTAX*8) as *i64
307 var ntax: i64 = 0
308 let col: *i64 = sys_mmap(24*2*8) as *i64
309 var i: i64 = 0
310 while i < sn {
311 let le: i64 = kd_eol(sb, sn, i)
312 if le > i {
313 kd_cols(sb, i, le, col, 10)
314 var seen: i64 = 0
315 var k: i64 = 0
316 while k < ntax { if kd_streq(sb, col[0], col[1], tn0[k], tn1[k]) == 1 { seen = 1; k = ntax } else { k = k + 1 } }
317 if seen == 0 { if ntax < KD_MAXTAX { tn0[ntax] = col[0]; tn1[ntax] = col[1]; ntax = ntax + 1 } }
318 }
319 i = le + 1
320 }
321 hw("{\x22organ\x22:\x22nx_kind\x22,\x22level\x22:\x22L0-kind\x22,\x22tris\x22:" as *u8); pn(nt)
322 hw(",\x22bands\x22:" as *u8); pn(nband)
323 hw(",\x22kinds_registered\x22:" as *u8); pn(ntax)
324 hw(",\x22results\x22:[" as *u8)
325 var best: i64 = 0 - 1
326 var best_rules: i64 = 0
327 var tix: i64 = 0
328 while tix < ntax {
329 // frame: default stack=y(1) cluster=x(0); a stack row overrides
330 var sa: i64 = 1
331 var ca: i64 = 0
332 i = 0
333 while i < sn {
334 let le2: i64 = kd_eol(sb, sn, i)
335 if le2 > i {
336 kd_cols(sb, i, le2, col, 8)
337 if kd_streq(sb, col[0], col[1], tn0[tix], tn1[tix]) == 1 {
338 if kd_same(sb, col[2], col[3], "stack" as *u8) == 1 { sa = kd_int(sb, col[4], col[5]); ca = kd_int(sb, col[6], col[7]) }
339 }
340 }
341 i = le2 + 1
342 }
343 if kd_sig(vx, nt, nband, sa, ca, 0, 1000) < 0 { kd_refuse("degenerate extent on the declared stack axis" as *u8); return 5 }
344 let cl: *i64 = KD_CL as *i64
345 let wd: *i64 = KD_WD as *i64
346 var wmax: i64 = 0
347 var b4: i64 = 0
348 while b4 < nband { if wd[b4] > wmax { wmax = wd[b4] } b4 = b4 + 1 }
349 var rules: i64 = 0
350 var passed: i64 = 0
351 var f0: i64 = 0
352 var f1: i64 = 0
353 i = 0
354 while i < sn {
355 let le3: i64 = kd_eol(sb, sn, i)
356 if le3 > i {
357 kd_cols(sb, i, le3, col, 10)
358 if kd_streq(sb, col[0], col[1], tn0[tix], tn1[tix]) == 1 {
359 if kd_same(sb, col[2], col[3], "band" as *u8) == 1 {
360 rules = rules + 1
361 let lo: i64 = kd_int(sb, col[4], col[5])
362 let hi: i64 = kd_int(sb, col[6], col[7])
363 let mnc: i64 = kd_int(sb, col[8], col[9])
364 let mxc: i64 = kd_int(sb, col[10], col[11])
365 // optional third-axis window in fields 7,8 (per-mille); absent = whole extent
366 var rwlo: i64 = 0
367 var rwhi: i64 = 1000
368 if col[15] > col[14] { rwlo = kd_int(sb, col[14], col[15]); rwhi = kd_int(sb, col[16], col[17]) }
369 if rwhi <= rwlo { rwlo = 0; rwhi = 1000 }
370 kd_sig(vx, nt, nband, sa, ca, rwlo, rwhi)
371 var got: i64 = 0
372 var b5: i64 = 0
373 while b5 < nband {
374 let pm: i64 = b5*1000/nband
375 if pm >= lo { if pm <= hi { if cl[b5] > got { got = cl[b5] } } }
376 b5 = b5 + 1
377 }
378 var ok: i64 = 0
379 if got >= mnc { if got <= mxc { ok = 1 } }
380 if ok == 1 { passed = passed + 1 } else { if f1 == 0 { f0 = col[12]; f1 = col[13] } }
381 kd_sig(vx, nt, nband, sa, ca, 0, 1000)
382 }
383 if kd_same(sb, col[2], col[3], "narrow" as *u8) == 1 {
384 rules = rules + 1
385 let lo2: i64 = kd_int(sb, col[4], col[5])
386 let hi2: i64 = kd_int(sb, col[6], col[7])
387 let frac: i64 = kd_int(sb, col[8], col[9])
388 var wmin: i64 = KD_BIG
389 var b6: i64 = 0
390 while b6 < nband {
391 let pm2: i64 = b6*1000/nband
392 if pm2 >= lo2 { if pm2 <= hi2 { if wd[b6] > 0 { if wd[b6] < wmin { wmin = wd[b6] } } } }
393 b6 = b6 + 1
394 }
395 var ok2: i64 = 0
396 if wmin < KD_BIG { if wmax > 0 { if wmin*1000 <= wmax*frac { ok2 = 1 } } }
397 if ok2 == 1 { passed = passed + 1 } else { if f1 == 0 { f0 = col[10]; f1 = col[11] } }
398 }
399 }
400 }
401 i = le3 + 1
402 }
403 if tix > 0 { hw("," as *u8) }
404 hw("{\x22kind\x22:\x22" as *u8); kd_pr(sb, tn0[tix], tn1[tix])
405 hw("\x22,\x22rules\x22:" as *u8); pn(rules)
406 hw(",\x22passed\x22:" as *u8); pn(passed)
407 if passed == rules { if rules > 0 { hw(",\x22match\x22:1" as *u8) } else { hw(",\x22match\x22:0" as *u8) } } else { hw(",\x22match\x22:0,\x22first_fail\x22:\x22" as *u8); kd_pr(sb, f0, f1); hw("\x22" as *u8) }
408 hw("}" as *u8)
409 if passed == rules { if rules > best_rules { best = tix; best_rules = rules } }
410 tix = tix + 1
411 }
412 hw("]" as *u8)
413 if best >= 0 { hw(",\x22verdict\x22:\x22" as *u8); kd_pr(sb, tn0[best], tn1[best]); hw("\x22,\x22matched_rules\x22:" as *u8); pn(best_rules) } else { hw(",\x22verdict\x22:\x22NO-KIND-MATCH\x22" as *u8) }
414 hw(",\x22note\x22:\x22kinds are DATA (plane rows); unknown verbs ignored additively so radial-symmetry/periodicity/genus can be seeded before they are testable\x22}\n" as *u8)
415 if best >= 0 { return 0 }
416 return 1
417}
418
419// ---- fixtures ----
420func kd_encf(v: i64, scale: i64) -> i64 {
421 if v == 0 { return 0 }
422 var neg: i64 = 0
423 var m: i64 = v
424 if m < 0 { neg = 1; m = 0-m }
425 var e: i64 = 0
426 var num: i64 = m
427 var den: i64 = scale
428 while num >= den*2 { den = den*2; e = e+1 }
429 while num < den { num = num*2; e = e-1 }
430 let frac: i64 = ((num - den)*KD_M8388608)/den
431 var bits: i64 = ((e+127) << 23) | (frac & KD_M8388607)
432 if neg == 1 { bits = bits | (1<<31) }
433 return bits
434}
435func kd_w32(b: *u8, o: i64, v: i64) -> i64 { b[o]=(v&255) as u8; b[o+1]=((v>>8)&255) as u8; b[o+2]=((v>>16)&255) as u8; b[o+3]=((v>>24)&255) as u8; return 0 }
436func kd_tri(b: *u8, off: i64, x0: i64, y0: i64, z0: i64, x1: i64, y1: i64, z1: i64, x2: i64, y2: i64, z2: i64) -> i64 {
437 kd_w32(b, off, kd_encf(x0,1)); kd_w32(b, off+4, kd_encf(y0,1)); kd_w32(b, off+8, kd_encf(z0,1))
438 kd_w32(b, off+12, kd_encf(x1,1)); kd_w32(b, off+16, kd_encf(y1,1)); kd_w32(b, off+20, kd_encf(z1,1))
439 kd_w32(b, off+24, kd_encf(x2,1)); kd_w32(b, off+28, kd_encf(y2,1)); kd_w32(b, off+32, kd_encf(z2,1))
440 var q: i64 = 36
441 while q < 84 { b[off+q] = 0 as u8; q = q + 1 }
442 return 0
443}
444func kd_box(b: *u8, off: i64, xlo: i64, xhi: i64, ylo: i64, yhi: i64, zlo: i64, zhi: i64) -> i64 {
445 var o: i64 = off
446 kd_tri(b, o, xlo,ylo,zlo, xhi,ylo,zlo, xhi,yhi,zlo); o = o + 84
447 kd_tri(b, o, xlo,ylo,zlo, xhi,yhi,zlo, xlo,yhi,zlo); o = o + 84
448 kd_tri(b, o, xlo,ylo,zhi, xhi,ylo,zhi, xhi,yhi,zhi); o = o + 84
449 kd_tri(b, o, xlo,ylo,zhi, xhi,yhi,zhi, xlo,yhi,zhi); o = o + 84
450 kd_tri(b, o, xlo,ylo,zlo, xlo,yhi,zlo, xlo,yhi,zhi); o = o + 84
451 kd_tri(b, o, xlo,ylo,zlo, xlo,yhi,zhi, xlo,ylo,zhi); o = o + 84
452 kd_tri(b, o, xhi,ylo,zlo, xhi,yhi,zlo, xhi,yhi,zhi); o = o + 84
453 kd_tri(b, o, xhi,ylo,zlo, xhi,yhi,zhi, xhi,ylo,zhi); o = o + 84
454 kd_tri(b, o, xlo,ylo,zlo, xhi,ylo,zlo, xhi,ylo,zhi); o = o + 84
455 kd_tri(b, o, xlo,ylo,zlo, xhi,ylo,zhi, xlo,ylo,zhi); o = o + 84
456 kd_tri(b, o, xlo,yhi,zlo, xhi,yhi,zlo, xhi,yhi,zhi); o = o + 84
457 kd_tri(b, o, xlo,yhi,zhi, xhi,yhi,zlo, xlo,yhi,zhi); o = o + 84
458 return 12
459}
460func kd_hdr(b: *u8, ntri: i64) -> i64 {
461 b[0]=78 as u8; b[1]=88 as u8; b[2]=77 as u8; b[3]=83 as u8
462 b[4]=72 as u8; b[5]=50 as u8; b[6]=0 as u8; b[7]=0 as u8
463 kd_w32(b, 8, 1); kd_w32(b, 12, ntri)
464 var q: i64 = 0
465 while q < 16 { b[16+q] = 0 as u8; q = q + 1 }
466 b[16]=115 as u8; b[17]=107 as u8; b[18]=105 as u8; b[19]=110 as u8
467 kd_w32(b, 32, 0); kd_w32(b, 36, ntri)
468 return 40
469}
470func kd_save(path: *u8, b: *u8, ntri: i64) -> i64 {
471 var z: i64 = 0
472 while z < ntri { kd_w32(b, 40 + ntri*84 + z*4, 0); z = z + 1 }
473 let fd: i64 = sys_openat_wr(path, 420)
474 if fd < 0 { return 0 - 1 }
475 sys_write(fd, b, 40 + ntri*84 + ntri*4)
476 sys_close(fd)
477 return 0
478}
479func kd_fix_blob(path: *u8) -> i64 {
480 let b: *u8 = sys_mmap(KD_MAGIC_65536)
481 kd_hdr(b, 12)
482 kd_box(b, 40, 0-150, 150, 0, KD_MAGIC_1600, 0-100, 100)
483 return kd_save(path, b, 12)
484}
485func kd_fix_human(path: *u8) -> i64 {
486 let b: *u8 = sys_mmap(KD_MAGIC_262144)
487 var o: i64 = 40
488 var n: i64 = 0
489 n = n + kd_box(b, o, 0-150, 150, 700, KD_MAGIC_1350, 0-100, 100); o = o + 12*84
490 n = n + kd_box(b, o, 0-450, 0-250, 1000, KD_MAGIC_1300, 0-60, 60); o = o + 12*84
491 n = n + kd_box(b, o, 250, 450, 1000, KD_MAGIC_1300, 0-60, 60); o = o + 12*84
492 n = n + kd_box(b, o, 0-140, 0-40, 60, 700, 0-80, 80); o = o + 12*84
493 n = n + kd_box(b, o, 40, 140, 60, 700, 0-80, 80); o = o + 12*84
494 n = n + kd_box(b, o, 0-60, 60, KD_MAGIC_1350, KD_MAGIC_1430, 0-60, 60); o = o + 12*84
495 n = n + kd_box(b, o, 0-110, 110, KD_MAGIC_1430, KD_MAGIC_1600, 0-110, 110); o = o + 12*84
496 kd_hdr(b, n)
497 return kd_save(path, b, n)
498}
499// a QUADRUPED: long horizontal body (x = long axis) on 4 legs -- proves the schema frame is data
500func kd_fix_quad(path: *u8) -> i64 {
501 let b: *u8 = sys_mmap(KD_MAGIC_262144)
502 var o: i64 = 40
503 var n: i64 = 0
504 n = n + kd_box(b, o, 0-600, 600, 700, 1000, 0-200, 200); o = o + 12*84 // barrel
505 n = n + kd_box(b, o, 0-560, 0-440, 0, 700, 0-180, 0-60); o = o + 12*84 // legs (4, split in z too)
506 n = n + kd_box(b, o, 0-560, 0-440, 0, 700, 60, 180); o = o + 12*84
507 n = n + kd_box(b, o, 440, 560, 0, 700, 0-180, 0-60); o = o + 12*84
508 n = n + kd_box(b, o, 440, 560, 0, 700, 60, 180); o = o + 12*84
509 n = n + kd_box(b, o, 600, 900, 900, KD_MAGIC_1100, 0-120, 120); o = o + 12*84 // head+neck forward
510 kd_hdr(b, n)
511 return kd_save(path, b, n)
512}
513func kd_wr(path: *u8, s: *u8) -> i64 {
514 var n: i64 = 0
515 while s[n] != (0 as u8) { n = n + 1 }
516 let fd: i64 = sys_openat_wr(path, 420)
517 if fd < 0 { return 0 - 1 }
518 sys_write(fd, s, n)
519 sys_close(fd)
520 return 0
521}
522func kd_selftest() -> i64 {
523 var fails: i64 = 0
524 kd_fix_blob("/tmp/kd_blob.nxmesh" as *u8)
525 kd_fix_human("/tmp/kd_human.nxmesh" as *u8)
526 kd_fix_quad("/tmp/kd_quad.nxmesh" as *u8)
527 kd_wr("/tmp/kd_schema.txt" as *u8, "humanoid\tstack\t1\t0\nhumanoid\tband\t550\t800\t3\t9\tarms-clear-of-torso\nhumanoid\tband\t80\t420\t2\t4\tlegs-separated\nhumanoid\tnarrow\t800\t920\t600\tneck-minimum\nquadruped\tstack\t0\t2\nquadruped\tband\t0\t1000\t2\t6\tlegs-along-length\t0\t450\nquadruped\tband\t100\t900\t1\t2\tbarrel-body\t500\t1000\n" as *u8)
528 let sb: *u8 = sys_mmap(KD_SCAP)
529 let sn: i64 = kd_readfile("/tmp/kd_schema.txt" as *u8, sb, KD_SCAP)
530 hw("T0 blob must match NO kind:\n" as *u8)
531 if kd_run("/tmp/kd_blob.nxmesh" as *u8, sb, sn, 64) == 0 { fails = fails + 1; hw("T0 FAIL blob matched a kind\n" as *u8) } else { hw("T0 PASS blob unmatched\n" as *u8) }
532 hw("T1 humanoid fixture must match humanoid:\n" as *u8)
533 if kd_run("/tmp/kd_human.nxmesh" as *u8, sb, sn, 64) != 0 { fails = fails + 1; hw("T1 FAIL humanoid unmatched\n" as *u8) } else { hw("T1 PASS\n" as *u8) }
534 hw("T2 quadruped fixture must match quadruped (proves the FRAME is data, not code):\n" as *u8)
535 if kd_run("/tmp/kd_quad.nxmesh" as *u8, sb, sn, 64) != 0 { fails = fails + 1; hw("T2 FAIL quadruped unmatched\n" as *u8) } else { hw("T2 PASS\n" as *u8) }
536 hw("T3 empty schema must REFUSE (never guess an ontology):\n" as *u8)
537 if kd_run("/tmp/kd_human.nxmesh" as *u8, sb, 0, 64) == 0 { fails = fails + 1; hw("T3 FAIL empty schema accepted\n" as *u8) } else { hw("T3 PASS refused\n" as *u8) }
538 if fails == 0 { hw("KIND-SELFTEST GREEN 4/4\n" as *u8); return 0 }
539 hw("KIND-SELFTEST RED fails=" as *u8); pn(fails); hw("\n" as *u8)
540 return 1
541}
542
543func main(argc: i64, argv: *i64) -> i64 {
544 if argc >= 2 {
545 let a1: *u8 = argv[1] as *u8
546 var m: i64 = 0
547 while a1[m] != (0 as u8) { m = m + 1 }
548 if m == 8 {
549 var ok: i64 = 1
550 let lit: *u8 = "selftest" as *u8
551 var i: i64 = 0
552 while i < 8 { if a1[i] != lit[i] { ok = 0; i = 8 } else { i = i + 1 } }
553 if ok == 1 { let rc: i64 = kd_selftest(); sys_exit(rc); return rc }
554 }
555 if m == 6 {
556 var ok2: i64 = 1
557 let lit2: *u8 = "schema" as *u8
558 var j: i64 = 0
559 while j < 6 { if a1[j] != lit2[j] { ok2 = 0; j = 6 } else { j = j + 1 } }
560 if ok2 == 1 {
561 if argc < 4 { hw("usage: nx_kind schema <file> <mesh.nxmesh> [bands]\n" as *u8); sys_exit(2); return 2 }
562 let sb2: *u8 = sys_mmap(KD_SCAP)
563 let sn2: i64 = kd_readfile(argv[2] as *u8, sb2, KD_SCAP)
564 var nb2: i64 = 64
565 let rc2: i64 = kd_run(argv[3] as *u8, sb2, sn2, nb2)
566 sys_exit(rc2)
567 return rc2
568 }
569 }
570 }
571 if argc < 2 { hw("usage: nx_kind <mesh.nxmesh> [bands] | schema <file> <mesh> | selftest\n" as *u8); sys_exit(2); return 2 }
572 let sb3: *u8 = sys_mmap(KD_SCAP)
573 let sn3: i64 = sts_load("knowledge/store/kind-" as *u8, sb3, KD_SCAP - 16)
574 var nb3: i64 = 64
575 if argc >= 3 {
576 let a2: *u8 = argv[2] as *u8
577 nb3 = 0
578 var q: i64 = 0
579 while a2[q] != (0 as u8) { nb3 = nb3*10 + ((a2[q] as i64) - 48); q = q + 1 }
580 if nb3 < 16 { nb3 = 16 }
581 if nb3 > KD_MAXBAND { nb3 = KD_MAXBAND }
582 }
583 let rc3: i64 = kd_run(argv[1] as *u8, sb3, sn3, nb3)
584 sys_exit(rc3)
585 return rc3
586}