code wiki / _hdl_build / nx_stem_gate.nx
nx_stem_gate.nx source
↩ module page · 100 lines · 7940 B
1// nx_stem_gate.nx -- KAT for R-UX-2 (nx_stem): FULL Porter (1980) on real search vocabulary + paper vectors. expect_exit: 0
2import "nx_syscalls.nx"
3import "nx_stem.nx"
4import "nx_gate_verdict.nx"
5
6func st_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
7func st_putb(p: *u8, n: i64) -> i64 { if n>0 { sys_write(1,p,n) } return 0 }
8func st_pn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
9func st_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
10func st_wn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
11func st_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
12
13// stem `word` and check the result == `expect` (length + bytes). prints the row. returns 1 pass / 0 fail.
14func st_case(word: *u8, expect: *u8) -> i64 {
15 let buf: *u8=sys_mmap(64)
16 let wl: i64=st_len(word)
17 var i: i64=0; while i<wl { buf[i]=word[i]; i=i+1 }
18 let nl: i64=vr_stem(buf, wl)
19 let el: i64=st_len(expect)
20 var ok: i64=1
21 if nl!=el { ok=0 } else { var j: i64=0; while j<nl { if buf[j]!=expect[j] { ok=0; j=nl } else { j=j+1 } } }
22 st_puts(" " as *u8); st_putb(word, wl); st_puts(" -> " as *u8); st_putb(buf, nl)
23 st_puts(" exp=" as *u8); st_putb(expect, el); st_puts(" " as *u8)
24 if ok==1 { st_puts("PASS\n" as *u8) } else { st_puts("FAIL\n" as *u8) }
25 return ok
26}
27
28func main() -> i64 {
29 st_puts("=== R-UX-2 STEMMING -- FULL Porter (all 5 steps) on real search vocab + paper vectors ===\n" as *u8)
30 var pass: i64=0; var total: i64=0
31 total=total+1; pass=pass + st_case("plans\x00" as *u8, "plan\x00" as *u8) // s
32 total=total+1; pass=pass + st_case("claims\x00" as *u8, "claim\x00" as *u8) // s
33 total=total+1; pass=pass + st_case("contracts\x00" as *u8, "contract\x00" as *u8) // s
34 total=total+1; pass=pass + st_case("trusts\x00" as *u8, "trust\x00" as *u8) // s
35 total=total+1; pass=pass + st_case("businesses\x00" as *u8, "busi\x00" as *u8) // sses->ss
36 total=total+1; pass=pass + st_case("families\x00" as *u8, "famili\x00" as *u8) // ies->i (Porter)
37 total=total+1; pass=pass + st_case("business\x00" as *u8, "busi\x00" as *u8) // ss unchanged
38 total=total+1; pass=pass + st_case("car\x00" as *u8, "car\x00" as *u8) // no-s unchanged
39
40 // ---- PORTER-LITE conflation (2026-07-03 upgrade): -ed/-ing/-ly + derivational + over-stem safety ----
41 st_puts("-- conflation (variants share a stem; distinct words must not) --\n" as *u8)
42 total=total+1; pass=pass + st_case("running\x00" as *u8, "run\x00" as *u8) // ing + de-double
43 total=total+1; pass=pass + st_case("ranked\x00" as *u8, "rank\x00" as *u8) // ed
44 total=total+1; pass=pass + st_case("ranking\x00" as *u8, "rank\x00" as *u8) // ing
45 total=total+1; pass=pass + st_case("indexing\x00" as *u8, "index\x00" as *u8) // ing
46 total=total+1; pass=pass + st_case("crawling\x00" as *u8, "crawl\x00" as *u8) // ing
47 total=total+1; pass=pass + st_case("computing\x00" as *u8, "comput\x00" as *u8) // ing
48 total=total+1; pass=pass + st_case("computed\x00" as *u8, "comput\x00" as *u8) // ed (same stem as computing)
49 // ---- FULL PORTER (2026-08-13 upgrade): steps 2-5, vectors from the Porter paper ----
50 st_puts("-- full Porter steps 2-5 --\n" as *u8)
51 total=total+1; pass=pass + st_case("relational\x00" as *u8, "relat\x00" as *u8)
52 total=total+1; pass=pass + st_case("conditional\x00" as *u8, "condit\x00" as *u8)
53 total=total+1; pass=pass + st_case("rational\x00" as *u8, "ration\x00" as *u8)
54 total=total+1; pass=pass + st_case("vietnamization\x00" as *u8, "vietnam\x00" as *u8)
55 total=total+1; pass=pass + st_case("predication\x00" as *u8, "predic\x00" as *u8)
56 total=total+1; pass=pass + st_case("operator\x00" as *u8, "oper\x00" as *u8)
57 total=total+1; pass=pass + st_case("feudalism\x00" as *u8, "feudal\x00" as *u8)
58 total=total+1; pass=pass + st_case("decisiveness\x00" as *u8, "decis\x00" as *u8)
59 total=total+1; pass=pass + st_case("hopefulness\x00" as *u8, "hope\x00" as *u8)
60 total=total+1; pass=pass + st_case("formaliti\x00" as *u8, "formal\x00" as *u8)
61 total=total+1; pass=pass + st_case("electriciti\x00" as *u8, "electr\x00" as *u8)
62 total=total+1; pass=pass + st_case("electrical\x00" as *u8, "electr\x00" as *u8)
63 total=total+1; pass=pass + st_case("hopeful\x00" as *u8, "hope\x00" as *u8)
64 total=total+1; pass=pass + st_case("goodness\x00" as *u8, "good\x00" as *u8)
65 total=total+1; pass=pass + st_case("replacement\x00" as *u8, "replac\x00" as *u8)
66 total=total+1; pass=pass + st_case("adoption\x00" as *u8, "adopt\x00" as *u8)
67 total=total+1; pass=pass + st_case("triplicate\x00" as *u8, "triplic\x00" as *u8)
68 total=total+1; pass=pass + st_case("formative\x00" as *u8, "form\x00" as *u8)
69 total=total+1; pass=pass + st_case("controll\x00" as *u8, "control\x00" as *u8)
70 total=total+1; pass=pass + st_case("roll\x00" as *u8, "roll\x00" as *u8)
71 total=total+1; pass=pass + st_case("rate\x00" as *u8, "rate\x00" as *u8)
72 total=total+1; pass=pass + st_case("sky\x00" as *u8, "sky\x00" as *u8)
73 total=total+1; pass=pass + st_case("feed\x00" as *u8, "feed\x00" as *u8)
74 total=total+1; pass=pass + st_case("agreed\x00" as *u8, "agre\x00" as *u8)
75 total=total+1; pass=pass + st_case("filing\x00" as *u8, "file\x00" as *u8)
76 total=total+1; pass=pass + st_case("happy\x00" as *u8, "happi\x00" as *u8)
77 total=total+1; pass=pass + st_case("ponies\x00" as *u8, "poni\x00" as *u8)
78 // NEG over-stemming: distinct words must NOT collapse to the same root
79 let sa: *u8=sys_mmap(64); let sb: *u8=sys_mmap(64)
80 var i9: i64=0; while i9<3 { sa[i9]="run\x00"[i9]; i9=i9+1 } let la: i64=vr_stem(sa,3)
81 i9=0; while i9<4 { sb[i9]="rank\x00"[i9]; i9=i9+1 } let lb: i64=vr_stem(sb,4)
82 var diff: i64=1; if la==lb { var j9: i64=0; var eq: i64=1; while j9<la { if sa[j9]!=sb[j9] { eq=0; j9=la } else { j9=j9+1 } } if eq==1 { diff=0 } }
83 total=total+1; pass=pass+diff
84 st_puts(" NEG run != rank distinct: "); if diff==1 { st_puts("PASS\n") } else { st_puts("FAIL\n") }
85
86 st_puts("----\nSTEM gate " as *u8); st_pn(pass); st_puts("/" as *u8); st_pn(total); st_puts(" passed\n" as *u8)
87 st_puts("HONEST: FULL Porter (1980, all 5 steps) as of 2026-08-13 -- no irregulars (children->child needs a lexicon).\n" as *u8)
88 st_puts(" Recall win: query 'plan' reaches docs that say 'plans'; 'operator' now conflates with 'operate'.\n" as *u8)
89 let lg: i64=sys_openat_append("knowledge/status/stem_gate.log" as *u8, 0x1a4)
90 if lg>=0 { st_w(lg, "R-UX-2 stem gate pass=" as *u8); st_wn(lg, pass); st_w(lg, "/" as *u8); st_wn(lg, total); if pass==total { st_w(lg, " GREEN\n" as *u8) } else { st_w(lg, " RED\n" as *u8) } sys_close(lg) }
91 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
92 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
93 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
94 let ctr__dry: *i64 = gv_ctr()
95 ctr__dry[0] = pass
96 ctr__dry[1] = total
97 let rc__dry: i64 = gv_verdict("STEM-GATE" as *u8, ctr__dry, "sovereign FULL-Porter stemming, paper-vector-verified)" as *u8)
98 sys_exit(rc__dry)
99 return rc__dry
100}