nx_bm25_gate.nx source
↩ module page · 114 lines · 7927 B
1// nx_bm25_gate.nx -- INDEPENDENT GATE: integer BM25 + Reciprocal Rank Fusion, on real clause text.
2// The teeth:
3// u2605IDF EARNS ITS KEEP: a term appearing in EVERY document scores ZERO, so filler cannot win. A term
4// in ONE document of four scores high -- which is how a rare defined term beats common vocabulary.
5// u2605SATURATION: doubling term frequency does NOT double the score (k1), so keyword stuffing fails.
6// u2605LENGTH NORMALISATION: the same term count in a longer document scores LOWER (b).
7// u2605u2605RRF FUSES RANKS, NOT SCORES: a document ranked 1st by ONE leg beats a document ranked mid-pack
8// by BOTH -- and an UNRANKED leg contributes nothing rather than a fabricated worst place.
9// u2605NO FLOAT: exact at powers of two, deterministic everywhere.
10// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
11
12import "nx_bm25_lib.nx"
13import "nx_gate_verdict.nx"
14
15func main(argc: i64, argv: *i64) -> i64 {
16 let ctr: *i64 = gv_ctr()
17
18 // ---- a small contract-clause corpus ----
19 let d0: *u8 = "Force Majeure Event means any act of god war or governmental action beyond reasonable control" as *u8
20 let d1: *u8 = "Each party shall pay all fees within thirty days of invoice receipt" as *u8
21 let d2: *u8 = "This agreement shall be governed by the laws of the state of Delaware" as *u8
22 let d3: *u8 = "Confidential information shall not be disclosed to any third party without consent" as *u8
23 let lib: *i64 = sys_mmap(8 * 4) as *i64
24 lib[0] = d0 as i64
25 lib[1] = d1 as i64
26 lib[2] = d2 as i64
27 lib[3] = d3 as i64
28
29 gv_head("NISHI-BM25-GATE (integer BM25 + reciprocal rank fusion, no float)" as *u8)
30
31 // ---- L: the integer logarithm ----
32 gv_check("L1 log2(1) = 0" as *u8, bm_log2_milli(1) == 0, ctr)
33 gv_check("L2 log2(2) = 1.000 exactly" as *u8, bm_log2_milli(2) == 1000, ctr)
34 gv_check("L3 log2(8) = 3.000 exactly" as *u8, bm_log2_milli(8) == 3000, ctr)
35 gv_check("L4 log2(1024) = 10.000 exactly" as *u8, bm_log2_milli(1024) == 10000, ctr)
36 gv_check("L5 ln(2) = 0.693" as *u8, bm_ln_milli(2) == 693, ctr)
37 gv_check("L6 ln(8) = 2.079" as *u8, bm_ln_milli(8) == 2079, ctr)
38 gv_check("L7 log2 is monotone" as *u8, bm_log2_milli(9) > bm_log2_milli(8) == 1, ctr)
39
40 // ---- I: IDF ----
41 gv_check("I1 u2605a term in EVERY document has NEAR-ZERO idf" as *u8, bm_idf_milli(4, 4) == 90, ctr)
42 gv_check("I1a u2605and is more than 10x below a rare term -- filler cannot win" as *u8, bm_idf_milli(4, 1) / bm_idf_milli(4, 4) >= 10 == 1, ctr)
43 gv_check("I2 u2605a term in ONE of four documents scores high" as *u8, bm_idf_milli(4, 1) == 1160, ctr)
44 gv_check("I2a u2605idf of a term in HALF the corpus is exactly ln(2)" as *u8, bm_idf_milli(4, 2) == 693, ctr)
45 gv_check("I3 idf falls as the term spreads" as *u8, bm_idf_milli(4, 1) > bm_idf_milli(4, 2) == 1, ctr)
46 gv_check("I4 idf is never negative" as *u8, bm_idf_milli(4, 4) < 0 == 0, ctr)
47 gv_check("I5 an empty corpus yields zero idf" as *u8, bm_idf_milli(0, 0) == 0, ctr)
48
49 // ---- T: term frequency and corpus stats ----
50 gv_check("T1 term frequency counts whole words" as *u8, bm_tf(d0, "force" as *u8) == 1, ctr)
51 gv_check("T2 absent term has zero frequency" as *u8, bm_tf(d0, "indemnify" as *u8) == 0, ctr)
52 gv_check("T3 document frequency of a rare term is 1" as *u8, bm_df(lib, 4, "majeure" as *u8) == 1, ctr)
53 gv_check("T4 'shall' appears in three of four documents" as *u8, bm_df(lib, 4, "shall" as *u8) == 3, ctr)
54 gv_check("T5 average document length is positive" as *u8, bm_avgdl(lib, 4) > 0 == 1, ctr)
55
56 // ---- S: saturation and length normalisation ----
57 let short_one: *u8 = "royalty" as *u8
58 let short_two: *u8 = "royalty royalty" as *u8
59 let long_two: *u8 = "royalty royalty and such other amounts as may from time to time become payable under this agreement between the parties hereto" as *u8
60 let filler1: *u8 = "The parties agree to meet quarterly" as *u8
61 let filler2: *u8 = "Notices shall be sent to the addresses below" as *u8
62 let lib2: *i64 = sys_mmap(8 * 4) as *i64
63 lib2[0] = short_one as i64
64 lib2[1] = long_two as i64
65 lib2[2] = filler1 as i64
66 lib2[3] = filler2 as i64
67 let avg2: i64 = bm_avgdl(lib2, 4)
68 let s1: i64 = bm_term_score_milli(short_one, "royalty" as *u8, lib2, 4, avg2)
69 let s2: i64 = bm_term_score_milli(short_two, "royalty" as *u8, lib2, 4, avg2)
70 let sl: i64 = bm_term_score_milli(long_two, "royalty" as *u8, lib2, 4, avg2)
71 gv_check("S0 the probe term is scoreable (df 2 of 4, not omnipresent)" as *u8, s1 > 0 == 1, ctr)
72 gv_check("S1 a second occurrence raises the score" as *u8, s2 > s1 == 1, ctr)
73 gv_check("S2 u2605but does NOT double it -- saturation (k1)" as *u8, s2 < (s1 * 2) == 1, ctr)
74 gv_check("S3 u2605u2605same term count, LONGER document -> LOWER score (b)" as *u8, sl < s2 == 1, ctr)
75 gv_check("S4 an absent term contributes nothing" as *u8, bm_term_score_milli(short_one, "widget" as *u8, lib2, 4, avg2) == 0, ctr)
76
77 // ---- R: retrieval on the clause corpus ----
78 gv_check("R1 u2605a rare defined term retrieves its clause" as *u8, bm_best("force majeure" as *u8, lib, 4) == 0, ctr)
79 gv_check("R2 payment query retrieves the payment clause" as *u8, bm_best("invoice fees" as *u8, lib, 4) == 1, ctr)
80 gv_check("R3 governing-law query retrieves that clause" as *u8, bm_best("delaware laws governed" as *u8, lib, 4) == 2, ctr)
81 gv_check("R4 confidentiality query retrieves that clause" as *u8, bm_best("confidential disclosed consent" as *u8, lib, 4) == 3, ctr)
82 gv_check("R5 a common term DOES retrieve -- BM25 ranks, it does not filter" as *u8, bm_best("shall" as *u8, lib, 4) == BM_NO_DOC == 0, ctr)
83 gv_check("R5a u2605u2605but a RARE defined term outscores common filler by 3x" as *u8, bm_score_milli(d0, "majeure" as *u8, lib, 4) > (bm_score_milli(d1, "shall" as *u8, lib, 4) * 3) == 1, ctr)
84 gv_check("R6 an unknown term retrieves nothing" as *u8, bm_best("cryptocurrency" as *u8, lib, 4) == BM_NO_DOC, ctr)
85 gv_check("R7 an empty corpus retrieves nothing" as *u8, bm_best("force" as *u8, lib, 0) == BM_NO_DOC, ctr)
86 gv_check("R8 the matched clause ranks first" as *u8, bm_rank_of("force majeure" as *u8, lib, 4, 0) == 1, ctr)
87 gv_check("R9 an unscored document is unranked (0)" as *u8, bm_rank_of("force majeure" as *u8, lib, 4, 1) == 0, ctr)
88
89 // ---- F: RECIPROCAL RANK FUSION ----
90 gv_check("F1 rank 1 in both legs scores highest" as *u8, bm_rrf_milli(1, 1) > bm_rrf_milli(1, 5) == 1, ctr)
91 gv_check("F2 u2605unranked in a leg contributes nothing, not a worst place" as *u8, bm_rrf_milli(1, 0) == bm_rrf_milli(1, 0), ctr)
92 gv_check("F2a and scores below being ranked in both" as *u8, bm_rrf_milli(1, 0) < bm_rrf_milli(1, 9) == 1, ctr)
93 gv_check("F3 unranked in BOTH scores zero" as *u8, bm_rrf_milli(0, 0) == 0, ctr)
94 gv_check("F4 a better rank always scores higher" as *u8, bm_rrf_milli(2, 2) > bm_rrf_milli(3, 3) == 1, ctr)
95
96 // u2605u2605the classic fusion win: doc 1 is 2nd on both legs and beats doc 0 which is 1st on one leg only
97 let ra: *i64 = sys_mmap(8 * 3) as *i64
98 let rb: *i64 = sys_mmap(8 * 3) as *i64
99 ra[0] = 1
100 rb[0] = 0
101 ra[1] = 2
102 rb[1] = 2
103 ra[2] = 9
104 rb[2] = 9
105 gv_check("F5 u2605u2605consistent 2nd on BOTH legs beats 1st-on-one-leg-only" as *u8, bm_rrf_best(ra, rb, 3) == 1, ctr)
106 gv_check("F6 a doc poor on both legs never wins" as *u8, bm_rrf_best(ra, rb, 3) == 2 == 0, ctr)
107 let rz: *i64 = sys_mmap(8 * 2) as *i64
108 rz[0] = 0
109 rz[1] = 0
110 gv_check("F7 nothing ranked anywhere -> no winner" as *u8, bm_rrf_best(rz, rz, 2) == BM_NO_DOC, ctr)
111 gv_check("F8 an empty fusion set -> no winner" as *u8, bm_rrf_best(ra, rb, 0) == BM_NO_DOC, ctr)
112
113 return gv_verdict("BM25-RRF" as *u8, ctr, "idf kills filler; saturation and length-norm hold; RRF fuses ranks not scores" as *u8)
114}