code wiki / _hdl_build / nx_stem_bound_gate.nx
nx_stem_bound_gate.nx source
↩ module page · 136 lines · 7904 B
1// nx_stem_bound_gate.nx -- THE STEM RUN BOUND, PROVEN OVER EVERY TERM OF THE LIVE DICTIONARY (search prep cut, 2026-09-14).
2//
3// WHY. dss_stem_expand (nx_docportal_search_seg.nx) finds every dictionary term whose stem equals the query
4// term's stem by walking the sorted run of terms sharing the stem's first 3 bytes and stemming each one. The
5// phase timers in /api/search named that walk as 0.33-0.40 s of every cold query, CPU in nx_stem per run entry
6// (a prefetch pass over the same run measured no gain). Widening the run key from 3 bytes to qsn-1 bytes makes
7// the walk a SUBSET of the old run, and it is exact ONLY IF: for every dictionary term w, w and stem(w) share
8// at least len(stem(w))-1 leading bytes. Porter rewrites suffixes only, and the rewrites that can change a byte
9// inside the stem's span (y to i, biliti to ble) touch at most its LAST byte -- but that is an argument about
10// the textbook, and the estate's stemmer is nx_stem. So this gate does not argue: it walks EVERY term of EVERY
11// live segment (no sample), stems each with the same nx_stem the scorer calls, and counts the terms that violate
12// the bound. One violation is RED and the cut does not ship; the violators are printed as the worklist.
13//
14// The predicate is a pure function so KAT and neg-control teeth pin its arithmetic before the census runs. The
15// shard path probes the manifest to survive the buildroot cwd anchor (nx_livemap_fast_gate's lesson); argv[1]
16// overrides the prefix. license_tier: ORIGINAL No hw writes (Rule 26).
17import "nx_seg_store.nx"
18import "nx_stem.nx"
19import "nx_gate_verdict.nx"
20
21const SB_TOKBUF: i64 = 4096
22const SB_MAXTERM: i64 = 40 // the expansion walk stems only terms shorter than this (dss_stem_expand)
23const SB_NARROW: i64 = 5 // stems of this length or more get a wider key than the old 3 bytes
24const SB_SHOW: i64 = 12 // violators printed; the COUNT is always the whole population
25
26// 1 iff term[0..tl) and stem[0..sl) agree on their first sl-1 bytes and the term is long enough to hold them.
27func sb_shares(term: *u8, tl: i64, stem: *u8, sl: i64) -> i64 {
28 if sl <= 1 { return 1 }
29 let need: i64 = sl - 1
30 if tl < need { return 0 }
31 var k: i64 = 0
32 while k < need {
33 if (term[k] as i64) != (stem[k] as i64) { return 0 }
34 k = k + 1
35 }
36 return 1
37}
38
39func main(argc: i64, argv: *i64) -> i64 {
40 let ctr: *i64 = gv_ctr()
41 gv_head("nx_stem_bound_gate -- every live dictionary term shares its stem's first len(stem)-1 bytes, the run bound the prep cut stands on" as *u8)
42
43 // the predicate, pinned on known pairs before it judges millions
44 gv_check("T1 KAT happy shares 4 of stem happi (y to i differs only in the last byte)" as *u8, sb_shares("happy" as *u8, 5, "happi" as *u8, 5), ctr)
45 gv_check("T1b KAT sensibility shares 6 of stem sensibl (biliti to ble differs only in the last byte)" as *u8, sb_shares("sensibility" as *u8, 11, "sensibl" as *u8, 7), ctr)
46 gv_check("T1c KAT sky shares 2 of stem ski (the short class the old 3-byte key already treats this way)" as *u8, sb_shares("sky" as *u8, 3, "ski" as *u8, 3), ctr)
47 gv_check("T1d KAT hopping shares all of stem hop (a stem shorter than the term)" as *u8, sb_shares("hopping" as *u8, 7, "hop" as *u8, 3), ctr)
48 gv_check("T1e KAT a stem of one byte binds nothing" as *u8, sb_shares("a" as *u8, 1, "x" as *u8, 1), ctr)
49 gv_check("T1f neg-control-abc-against-xyz is a violation" as *u8, (sb_shares("abc" as *u8, 3, "xyz" as *u8, 3) == 0) as i64, ctr)
50 gv_check("T1g neg-control-term-shorter-than-the-bound is a violation (ab against abcd)" as *u8, (sb_shares("ab" as *u8, 2, "abcd" as *u8, 4) == 0) as i64, ctr)
51 gv_check("T1h neg-control-mismatch-inside-the-bound is a violation (photograph against phonograph)" as *u8, (sb_shares("photograph" as *u8, 10, "phonograph" as *u8, 10) == 0) as i64, ctr)
52 gv_check("T1i a difference exactly at the stem's last byte is tolerated (abcde against abcdX)" as *u8, sb_shares("abcde" as *u8, 5, "abcdX" as *u8, 5), ctr)
53
54 // the live shard, from either cwd
55 var prefix: *u8 = "knowledge/store/dp-web-pub-" as *u8
56 let anch: i64 = sys_openat_rd("../knowledge/store/dp-web-pub-manifest.txt" as *u8)
57 if anch >= 0 { sys_close(anch); prefix = "../knowledge/store/dp-web-pub-" as *u8 }
58 if argc >= 2 { prefix = argv[1] as *u8 }
59 gv_puts(" shard prefix=" as *u8); gv_puts(prefix); gv_puts("\n" as *u8)
60 let h: *i64 = ss_open2(prefix, 1)
61 var t2: i64 = 0
62 if (h as i64) != 0 { t2 = 1 }
63 gv_check("T2 the shard opens (nothing below means anything if it does not)" as *u8, t2, ctr)
64 if t2 == 0 {
65 let rcx: i64 = gv_verdict("STEMBOUND" as *u8, ctr, "the run bound over the live dictionary" as *u8)
66 sys_exit(rcx)
67 return rcx
68 }
69 let ns: i64 = h[0]
70 gv_check("T3 the shard has MULTIPLE segments so every dictionary generation is covered" as *u8, (ns > 1) as i64, ctr)
71
72 let stemc: *u8 = sys_mmap(SB_TOKBUF)
73 let cbuf: *u8 = sys_mmap(SB_TOKBUF)
74 let tpb: *i64 = sys_mmap(64) as *i64
75 let tlb: *i64 = sys_mmap(64) as *i64
76 let dcb: *i64 = sys_mmap(64) as *i64
77 var total: i64 = 0
78 var checked: i64 = 0
79 var skipped: i64 = 0
80 var viol: i64 = 0
81 var narrowed: i64 = 0
82 var maxtl: i64 = 0
83 var maxsl: i64 = 0
84 var longer: i64 = 0
85 var shown: i64 = 0
86 var s: i64 = 0
87 while s < ns {
88 let tc: i64 = ss_term_count(h, s)
89 total = total + tc
90 var e: i64 = 0
91 while e < tc {
92 if ss_term_at(h, s, e, tpb, tlb, dcb) == 1 {
93 let tl: i64 = tlb[0]
94 if tl > maxtl { maxtl = tl }
95 if tl < SB_MAXTERM {
96 let dtp: *u8 = tpb[0] as *u8
97 var ci: i64 = 0
98 while ci < tl { cbuf[ci] = dtp[ci]; ci = ci + 1 }
99 cbuf[tl] = 0 as u8
100 let csn: i64 = nx_stem(cbuf, tl, stemc)
101 checked = checked + 1
102 if csn > maxsl { maxsl = csn }
103 if csn > tl { longer = longer + 1 }
104 if csn >= SB_NARROW { narrowed = narrowed + 1 }
105 if sb_shares(cbuf, tl, stemc, csn) == 0 {
106 viol = viol + 1
107 if shown < SB_SHOW {
108 shown = shown + 1
109 gv_puts(" VIOLATION seg=" as *u8); gv_num(s); gv_puts(" term=" as *u8); sys_write(1, cbuf, tl)
110 gv_puts(" stem=" as *u8); sys_write(1, stemc, csn); gv_puts("\n" as *u8)
111 }
112 }
113 } else { skipped = skipped + 1 }
114 }
115 e = e + 1
116 }
117 s = s + 1
118 }
119 gv_kv("segments" as *u8, ns)
120 gv_kv("terms_total" as *u8, total)
121 gv_kv("terms_checked" as *u8, checked)
122 gv_kv("terms_skipped_long" as *u8, skipped)
123 gv_kv("terms_narrowed_class" as *u8, narrowed)
124 gv_kv("stem_longer_than_term" as *u8, longer)
125 gv_kv("violations" as *u8, viol)
126 gv_kv("max_term_len" as *u8, maxtl)
127 gv_kv("max_stem_len" as *u8, maxsl)
128 gv_check("T4 fixture-reached-condition: at least one dictionary term was stemmed" as *u8, (checked > 0) as i64, ctr)
129 gv_check("T5 partition: checked plus skipped-long equals the dictionary total" as *u8, (checked + skipped == total) as i64, ctr)
130 gv_check("T6 the narrowed class is populated (stems of 5 or more bytes exist, so the wider key is exercised)" as *u8, (narrowed > 0) as i64, ctr)
131 gv_check("T7 nx_stem never returns a stem longer than its term" as *u8, (longer == 0) as i64, ctr)
132 gv_check("T8 THE BOUND: zero live terms violate share-first-len(stem)-minus-1-bytes" as *u8, (viol == 0) as i64, ctr)
133 let rc: i64 = gv_verdict("STEMBOUND" as *u8, ctr, "the run bound holds over the whole live dictionary" as *u8)
134 sys_exit(rc)
135 return rc
136}