code wiki / _hdl_build / nx_bm25f_gate.nx

nx_bm25f_gate.nx source

↩ module page · 129 lines · 8694 B

1// nx_bm25f_gate.nx -- MEASURED proof that BM25F (fielded) beats plain BM25 on the property that matters for 2// onsite search: a query term in the TITLE should win over the same term buried in the BODY. Two docs: 3// doc0 title="estate planning services" body="we help utah families with care and guidance" (estate in TITLE) 4// doc1 title="family law attorney" body="we also handle estate matters for clients today" (estate in BODY) 5// Oracle (all checked from the live scorers, not asserted): 6// R1 BM25F: query 'estate' -> doc0 (TITLE hit ranks #1) 7// R2 plain BM25 body-only: query 'estate' -> doc1 (BODY hit) -- so BM25F FLIPPED the ranking toward the title 8// R3 BM25F: query 'family' -> doc1 (its TITLE) 9// R4 plain BM25 body-only: query 'family' -> -1 (NO body contains it) -- BM25F adds TITLE-FIELD RECALL the 10// body-only ranker misses entirely 11// GREEN iff 4/4. Durable knowledge/status/bm25f_gate.log. license_tier: ORIGINAL 12import "nx_bm25f.nx" // bmf_best + bm_best + bm_token_count (via nx_bm25) 13import "nx_syscalls.nx" 14 15func f_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 16func f_num(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 } 17func f_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 } 18func f_wn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; 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 } 19func f_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 20 21func main() -> i64 { 22 f_puts("=== BM25F GATE (fielded: TITLE hit beats BODY hit; vs plain BM25; MEASURED) ===\n" as *u8) 23 let N: i64 = 2 24 let titles: *i64=sys_mmap(8*N) as *i64 25 let bodies: *i64=sys_mmap(8*N) as *i64 26 titles[0]="estate planning services" as *u8 as i64 27 bodies[0]="we help utah families with care and guidance" as *u8 as i64 28 titles[1]="family law attorney" as *u8 as i64 29 bodies[1]="we also handle estate matters for clients today" as *u8 as i64 30 31 let tlens: *i64=sys_mmap(8*N) as *i64 32 let blens: *i64=sys_mmap(8*N) as *i64 33 let dlt: *i64=sys_mmap(8*N) as *i64 34 let dlb: *i64=sys_mmap(8*N) as *i64 35 var tt: i64=0; var tb: i64=0; var i: i64=0 36 while i<N { 37 tlens[i]=f_strlen(titles[i] as *u8); blens[i]=f_strlen(bodies[i] as *u8) 38 dlt[i]=bm_token_count(titles[i] as *u8, tlens[i]); dlb[i]=bm_token_count(bodies[i] as *u8, blens[i]) 39 tt=tt+dlt[i]; tb=tb+dlb[i]; i=i+1 40 } 41 var avgt: i64=tt/N; if avgt<=0 { avgt=1 } 42 var avgb: i64=tb/N; if avgb<=0 { avgb=1 } 43 44 let q_e: *i64=sys_mmap(8) as *i64; q_e[0]="estate" as *u8 as i64 45 let q_f: *i64=sys_mmap(8) as *i64; q_f[0]="family" as *u8 as i64 46 47 let bmf_e: i64=bmf_best(titles, tlens, dlt, bodies, blens, dlb, N, avgt, avgb, q_e, 1) 48 let bm_e: i64=bm_best(bodies, blens, dlb, N, avgb, q_e, 1) 49 let bmf_f: i64=bmf_best(titles, tlens, dlt, bodies, blens, dlb, N, avgt, avgb, q_f, 1) 50 let bm_f: i64=bm_best(bodies, blens, dlb, N, avgb, q_f, 1) 51 52 var pass: i64=0 53 var rows: i64=4 // var, not let: the mutation-derived teeth below add rows at the end 54 f_puts(" R1 BM25F 'estate' -> doc " as *u8); f_num(bmf_e); f_puts(" (expect 0=TITLE)" as *u8) 55 if bmf_e==0 { pass=pass+1; f_puts(" PASS\n" as *u8) } else { f_puts(" FAIL\n" as *u8) } 56 f_puts(" R2 BM25(body) 'estate' -> doc " as *u8); f_num(bm_e); f_puts(" (expect 1=BODY; BM25F flipped it)" as *u8) 57 if bm_e==1 { pass=pass+1; f_puts(" PASS\n" as *u8) } else { f_puts(" FAIL\n" as *u8) } 58 f_puts(" R3 BM25F 'family' -> doc " as *u8); f_num(bmf_f); f_puts(" (expect 1=TITLE)" as *u8) 59 if bmf_f==1 { pass=pass+1; f_puts(" PASS\n" as *u8) } else { f_puts(" FAIL\n" as *u8) } 60 f_puts(" R4 BM25(body) 'family' -> doc " as *u8); f_num(bm_f); f_puts(" (expect -1=body MISSES it; BM25F adds title recall)" as *u8) 61 if bm_f==(0-1) { pass=pass+1; f_puts(" PASS\n" as *u8) } else { f_puts(" FAIL\n" as *u8) } 62 63 f_puts("----\nBM25F rows=" as *u8); f_num(rows); f_puts(" pass=" as *u8); f_num(pass); f_puts("\n" as *u8) 64 let lg: i64=sys_openat_append("knowledge/status/bm25f_gate.log" as *u8, 0x1a4) 65 if lg>=0 { 66 f_w(lg, "BM25F rows=" as *u8); f_wn(lg, rows); f_w(lg, " pass=" as *u8); f_wn(lg, pass) 67 if pass==rows { f_w(lg, " verdict=GREEN\n" as *u8) } else { f_w(lg, " verdict=RED\n" as *u8) } 68 sys_close(lg) 69 } 70 // ---- MUTATION-DERIVED TEETH (2026-08-01, debt 1785604588) ---- 71 // nx_gate_mutation_probe scored this pair 1/4 with THREE survivors, all inside BM25F's DEFINING 72 // mechanism: nx_bm25f.nx:43 the title half of df counting, :61 the TITLE+BODY field combination, 73 // :72 the title-match bonus that is the whole reason BM25F exists rather than plain BM25. 74 // The four existing rows use ONE corpus in which the two documents differ in many ways at once 75 // (different titles AND different bodies AND different lengths), so a ranking stayed correct for 76 // reasons unrelated to the mutated line. 77 // LAW: A TEST WHOSE TWO CASES DIFFER IN MORE THAN ONE WAY CANNOT ATTRIBUTE THE RESULT TO ANY OF 78 // THEM. To measure the title bonus you need two documents identical in every respect EXCEPT which 79 // field carries the term -- a controlled pair, not a realistic one. 80 let M: i64 = 2 81 let ct: *i64=sys_mmap(8*M) as *i64 82 let cb: *i64=sys_mmap(8*M) as *i64 83 // doc0: term in the TITLE. doc1: the SAME two strings with the fields SWAPPED. Identical token 84 // counts, identical field lengths, identical corpus df -- the ONLY difference is placement. 85 ct[0]="widget" as *u8 as i64; cb[0]="alpha beta" as *u8 as i64 86 ct[1]="alpha beta" as *u8 as i64; cb[1]="widget" as *u8 as i64 87 let ctl: *i64=sys_mmap(8*M) as *i64 88 let cbl: *i64=sys_mmap(8*M) as *i64 89 let cdt: *i64=sys_mmap(8*M) as *i64 90 let cdb: *i64=sys_mmap(8*M) as *i64 91 var ci: i64=0; var st: i64=0; var sb: i64=0 92 while ci<M { 93 ctl[ci]=f_strlen(ct[ci] as *u8); cbl[ci]=f_strlen(cb[ci] as *u8) 94 cdt[ci]=bm_token_count(ct[ci] as *u8, ctl[ci]); cdb[ci]=bm_token_count(cb[ci] as *u8, cbl[ci]) 95 st=st+cdt[ci]; sb=sb+cdb[ci]; ci=ci+1 96 } 97 var cavgt: i64=st/M; if cavgt<=0 { cavgt=1 } 98 var cavgb: i64=sb/M; if cavgb<=0 { cavgb=1 } 99 let q_w: *i64=sys_mmap(8) as *i64; q_w[0]="widget" as *u8 as i64 100 let win: i64 = bmf_best(ct, ctl, cdt, cb, cbl, cdb, M, cavgt, cavgb, q_w, 1) 101 rows = rows + 1 102 if win == 0 { pass = pass + 1; f_puts(" T5 PASS TITLE-OVER-BODY: fields swapped, all else identical -> the TITLE doc wins\n" as *u8) } 103 if win != 0 { f_puts(" T5 FAIL TITLE-OVER-BODY: a title hit did NOT outrank an identical body hit\n" as *u8) } 104 // Both fields must CONTRIBUTE: a doc carrying the term in title AND body must outscore the 105 // title-only doc. Kills a combination that drops or subtracts one field's contribution. 106 let bt: *i64=sys_mmap(8*M) as *i64 107 let bb2: *i64=sys_mmap(8*M) as *i64 108 bt[0]="widget" as *u8 as i64; bb2[0]="widget" as *u8 as i64 // both fields 109 bt[1]="widget" as *u8 as i64; bb2[1]="alpha beta" as *u8 as i64 // title only 110 var bi: i64=0; var bt_s: i64=0; var bb_s: i64=0 111 let btl: *i64=sys_mmap(8*M) as *i64 112 let bbl: *i64=sys_mmap(8*M) as *i64 113 let bdt: *i64=sys_mmap(8*M) as *i64 114 let bdb: *i64=sys_mmap(8*M) as *i64 115 while bi<M { 116 btl[bi]=f_strlen(bt[bi] as *u8); bbl[bi]=f_strlen(bb2[bi] as *u8) 117 bdt[bi]=bm_token_count(bt[bi] as *u8, btl[bi]); bdb[bi]=bm_token_count(bb2[bi] as *u8, bbl[bi]) 118 bt_s=bt_s+bdt[bi]; bb_s=bb_s+bdb[bi]; bi=bi+1 119 } 120 var bavgt: i64=bt_s/M; if bavgt<=0 { bavgt=1 } 121 var bavgb: i64=bb_s/M; if bavgb<=0 { bavgb=1 } 122 let win2: i64 = bmf_best(bt, btl, bdt, bb2, bbl, bdb, M, bavgt, bavgb, q_w, 1) 123 rows = rows + 1 124 if win2 == 0 { pass = pass + 1; f_puts(" T6 PASS BOTH-FIELDS: title+body hit outranks title-only -> both fields contribute\n" as *u8) } 125 if win2 != 0 { f_puts(" T6 FAIL BOTH-FIELDS: the body field contributed nothing (or was subtracted)\n" as *u8) } 126 127 if pass==rows { f_puts("BM25F-GATE GREEN (fielded ranking beats plain BM25 on title relevance)\n" as *u8); sys_exit(0); return 0 } 128 f_puts("BM25F-GATE RED\n" as *u8); sys_exit(1); return 1 129}