code wiki / (root) / nx_absa_bench_gate.nx

nx_absa_bench_gate.nx source

↩ module page · 221 lines · 15435 B

1// nx_absa_bench_gate.nx -- GATE for the SemEval-2014 SB1 scorer in nx_absa_lib (intelmine IM17), driven 2// IN-PROCESS on a planted gold set under /tmp/nx_absa_bench_gate. The load-bearing proof is the F1 arithmetic 3// (ab_prf) checked at exact permil values including the ZERO-PREDICTION control the rung's done-rule names; the 4// gold parser is proven to dedupe distinct terms and to survive CRLF; the normaliser is proven case- and 5// whitespace-insensitive; a multi-word gold term is proven UNMATCHABLE by a unigram (the honest weakness); and 6// the full ab_eval pipeline is proven non-vacuous on the planted gold. Every fixture asserts its own condition 7// before any outcome is judged. No network. license_tier: ORIGINAL No hw writes (Rule 26). 8import "nx_syscalls.nx" 9import "nx_gatekit_lib.nx" 10import "nx_reviewmine_lib.nx" 11import "nx_absa_lib.nx" 12import "nx_gate_verdict.nx" 13 14const G_ROOT: *u8 = "/tmp/nx_absa_bench_gate" 15const G_GOLD: *u8 = "/tmp/nx_absa_bench_gate/gold.seg" 16const G_GOLDCRLF: *u8 = "/tmp/nx_absa_bench_gate/goldcrlf.seg" 17const G_I64: i64 = 8 18const G_LINES: i64 = 12 // four three-line records 19const G_NG: i64 = 3 // distinct terms: food, service, hard disk (food appears twice) 20const G_LF: i64 = 10 21const G_CR: i64 = 13 22const G_CRLF_CAP: i64 = 512 23// subtask 2 fixtures: three planted lexicons and a directory with none 24const G_LEXDIR: *u8 = "/tmp/nx_absa_bench_gate/lex/" 25const G_NOLEXDIR: *u8 = "/tmp/nx_absa_bench_gate/nolex/" 26const G_LEX_DEFECT: *u8 = "/tmp/nx_absa_bench_gate/lex/lexicon_defect.conf" 27const G_LEX_NOTMEET: *u8 = "/tmp/nx_absa_bench_gate/lex/lexicon_notmeet.conf" 28const G_LEX_EXCEED: *u8 = "/tmp/nx_absa_bench_gate/lex/lexicon_exceed.conf" 29const G_ABSENT_GOLD: *u8 = "/tmp/nx_absa_bench_gate/absent.seg" 30const G_RECORDS: i64 = 4 31const G_LEX_TERMS: i64 = 5 // slow, noisy (defect) + refund (not met) + great, fast (exceed) 32// n-gram fixtures: the four records plus a fifth that repeats the multi-word term, so "hard disk" is a frequent bigram 33// at support two while "hard" and "disk" never occur on their own (p-support zero: fragments to prune) 34const G_GOLD_NG: *u8 = "/tmp/nx_absa_bench_gate/gold_ng.seg" 35const G_ROWS_NG: *u8 = "The $T$ was great .\nfood\n1\nThe $T$ is slow .\nservice\n-1\nThe $T$ is noisy .\nhard disk\n0\nGreat $T$ here .\nfood\n1\nThe $T$ is loud .\nhard disk\n-1\n" 36const G_NG_LINES: i64 = 15 37const G_NG_RECORDS: i64 = 5 38const G_NG_MINSUP: i64 = 2 // pins support at the bigram's frequency 39const G_NG_MINSUP_ABOVE: i64 = 3 // one above it: the control that must find no frequent bigram 40const G_NG_CANDS: i64 = 3 // hard disk, food, great 41const G_NG_PRUNED: i64 = 2 // hard, disk 42const G_TRAIN: *u8 = "/tmp/nx_absa_bench_gate/train.seg" 43const G_TEST: *u8 = "/tmp/nx_absa_bench_gate/test.seg" 44const G_TRAIN_ROWS: *u8 = "The $T$ was slow .\nfood\n1\nThe $T$ is rude .\nservice\n-1\nThe $T$ is noisy .\nhard disk\n0\nThe $T$ is nice .\nkeyboard\n1\n" 45const G_TEST_ROWS: *u8 = "The $T$ was great .\nfood\n1\nThe $T$ is noisy .\nhard disk\n0\nThe $T$ broke .\nmouse\n-1\nI like the keyboard and $T$ .\nfood\n1\n" 46const G_D_DICT: i64 = 4 47const G_D_RECORDS: i64 = 4 48const G_D_NG: i64 = 3 49const G_D_PRED: i64 = 3 50const G_D_INTER: i64 = 2 51// four records; "food" repeats so the gold set must dedupe it; "hard disk" is a multi-word term a unigram cannot match 52const G_ROWS: *u8 = "The $T$ was great .\nfood\n1\nThe $T$ is slow .\nservice\n-1\nThe $T$ is noisy .\nhard disk\n0\nGreat $T$ here .\nfood\n1\n" 53 54func g_lines(path: *u8) -> i64 { 55 let lp: *i64 = sys_mmap(G_I64) as *i64 56 lp[0] = 0 57 let b: *u8 = sys_read_file(path, lp) 58 if (b as i64) == 0 { return 0 } 59 var n: i64 = 0 60 var i: i64 = 0 61 while i < lp[0] { if b[i] == (G_LF as u8) { n = n + 1 } i = i + 1 } 62 return n 63} 64// write a CRLF twin of a NUL-terminated LF source into out, return its byte length 65func g_crlf(src: *u8, out: *u8) -> i64 { 66 var i: i64 = 0 67 var o: i64 = 0 68 while src[i] != (0 as u8) { 69 if (src[i] as i64) == G_LF { out[o] = G_CR as u8; o = o + 1 } 70 out[o] = src[i]; o = o + 1 71 i = i + 1 72 } 73 out[o] = 0 as u8 74 return o 75} 76 77func main() -> i64 { 78 gv_head("=== nx_absa_bench_gate -- the SemEval-2014 SB1 scorer, in-process on a planted gold set under /tmp ===" as *u8) 79 let c: *i64 = gv_ctr() 80 gk_mkdir(G_ROOT) 81 gk_write(G_GOLD, G_ROWS) 82 let cbuf: *u8 = sys_mmap(G_CRLF_CAP) 83 let clen: i64 = g_crlf(G_ROWS, cbuf) 84 gk_write(G_GOLDCRLF, cbuf) 85 86 // ---- fixtures reached their condition ---- 87 gv_need("fixture-root-created" as *u8, gk_exists(G_ROOT), c) 88 gv_check_eq("fixture-reached-the-condition: gold file has twelve lines" as *u8, g_lines(G_GOLD), G_LINES, c) 89 gv_check("fixture-reached-the-condition: crlf twin is longer than the lf source" as *u8, (gk_size(G_GOLDCRLF) > gk_size(G_GOLD)) as i64, c) 90 91 // ---- F1 arithmetic (the load-bearing proof), from counts, in permil ---- 92 let p: *i64 = sys_mmap(AB_PRF_N * G_I64) as *i64 93 ab_prf(2, 3, 4, p) 94 gv_check_eq("prf-precision 2/3 = 666 permil" as *u8, p[AB_P], 666, c) 95 gv_check_eq("prf-recall 2/4 = 500 permil" as *u8, p[AB_R], 500, c) 96 gv_check_eq("prf-f1 2*2/(3+4) = 571 permil" as *u8, p[AB_F1], 571, c) 97 ab_prf(1, 4, 2, p) 98 gv_check_eq("prf-f1 2*1/(4+2) = 333 permil" as *u8, p[AB_F1], 333, c) 99 ab_prf(4, 4, 4, p) 100 gv_check_eq("prf-perfect-precision" as *u8, p[AB_P], 1000, c) 101 gv_check_eq("prf-perfect-recall" as *u8, p[AB_R], 1000, c) 102 gv_check_eq("prf-perfect-f1" as *u8, p[AB_F1], 1000, c) 103 ab_prf(0, 0, 4, p) 104 gv_check_eq("neg-control-zero-prediction-precision-is-zero-not-a-divide" as *u8, p[AB_P], 0, c) 105 gv_check_eq("neg-control-zero-prediction-recall-is-zero" as *u8, p[AB_R], 0, c) 106 gv_check_eq("neg-control-zero-prediction-f1-is-zero" as *u8, p[AB_F1], 0, c) 107 ab_prf(0, 3, 0, p) 108 gv_check_eq("neg-control-no-gold-f1-is-zero" as *u8, p[AB_F1], 0, c) 109 110 // ---- gold parser: distinct-term dedupe, multi-word term stored, CRLF survived ---- 111 let ng: i64 = ab_gold_load(G_GOLD) 112 gv_check_eq("gold-load-dedupes-to-three-distinct-terms" as *u8, ng, G_NG, c) 113 gv_check("gold-contains-a-single-word-term" as *u8, ab_set_has_raw("food" as *u8, 4), c) 114 gv_check("gold-normaliser-is-case-and-whitespace-insensitive" as *u8, ab_set_has_raw(" HARD DISK " as *u8, 15), c) 115 gv_check("neg-control-a-unigram-never-matches-a-multiword-gold-term" as *u8, (ab_set_has_raw("hard" as *u8, 4) == 0) as i64, c) 116 gv_check("neg-control-absent-term-not-in-gold" as *u8, (ab_set_has_raw("keyboard" as *u8, 8) == 0) as i64, c) 117 let ngc: i64 = ab_gold_load(G_GOLDCRLF) 118 gv_check_eq("gold-load-survives-crlf-and-still-dedupes-to-three" as *u8, ngc, G_NG, c) 119 gv_check("neg-control-crlf-term-has-no-trailing-cr" as *u8, ab_set_has_raw("service" as *u8, 7), c) 120 121 // ---- full pipeline: non-vacuous on the planted gold ---- 122 let out: *i64 = sys_mmap(AB_O_N * G_I64) as *i64 123 ab_eval(G_GOLD, 0, out) 124 gv_check_eq("eval-gold-terms-is-three" as *u8, out[AB_O_NG], G_NG, c) 125 gv_check_eq("eval-k-defaults-to-gold-size" as *u8, out[AB_O_K], G_NG, c) 126 gv_check("eval-predicts-at-least-one-term" as *u8, (out[AB_O_NS] > 0) as i64, c) 127 gv_check("eval-matches-at-least-one-gold-term" as *u8, (out[AB_O_INTER] > 0) as i64, c) 128 gv_check("eval-f1-is-positive-on-a-corpus-that-shares-terms-with-its-gold" as *u8, (out[AB_O_F1] > 0) as i64, c) 129 gv_check("eval-matched-never-exceeds-predicted" as *u8, (out[AB_O_INTER] <= out[AB_O_NS]) as i64, c) 130 gv_check("eval-matched-never-exceeds-gold" as *u8, (out[AB_O_INTER] <= out[AB_O_NG]) as i64, c) 131 132 // ---- subtask 2: polarity accuracy on the same planted gold, lexicons planted under /tmp ---- 133 gk_mkdir(G_LEXDIR) 134 gk_rm(G_ABSENT_GOLD) 135 gk_write(G_LEX_DEFECT, "slow\nnoisy\n" as *u8) 136 gk_write(G_LEX_NOTMEET, "refund\n" as *u8) 137 gk_write(G_LEX_EXCEED, "great\nfast\n" as *u8) 138 gv_check("fixture-reached-the-condition: three lexicons planted" as *u8, gk_exists(G_LEX_DEFECT) * gk_exists(G_LEX_NOTMEET) * gk_exists(G_LEX_EXCEED), c) 139 gv_check("fixture-reached-the-condition: absent gold has no file" as *u8, (gk_exists(G_ABSENT_GOLD) == 0) as i64, c) 140 let pq: *i64 = sys_mmap(AB_Q_N * G_I64) as *i64 141 ab_polarity(G_GOLD, G_LEXDIR, pq) 142 gv_check_eq("sb2-records-four" as *u8, pq[AB_Q_RECORDS], G_RECORDS, c) 143 gv_check_eq("sb2-gold-positive-two" as *u8, pq[AB_Q_POS], 2, c) 144 gv_check_eq("sb2-gold-negative-one" as *u8, pq[AB_Q_NEG], 1, c) 145 gv_check_eq("sb2-gold-neutral-one" as *u8, pq[AB_Q_NEU], 1, c) 146 gv_check_eq("sb2-gold-other-zero" as *u8, pq[AB_Q_OTHER], 0, c) 147 gv_check_eq("sb2-class-partition-sums-to-records" as *u8, pq[AB_Q_POS] + pq[AB_Q_NEG] + pq[AB_Q_NEU] + pq[AB_Q_OTHER], pq[AB_Q_RECORDS], c) 148 gv_check_eq("sb2-majority-class-is-positive" as *u8, pq[AB_Q_MAJ_CLASS], AB_POL_POS, c) 149 gv_check_eq("sb2-majority-accuracy 2/4 = 500 permil" as *u8, pq[AB_Q_MAJ_ACC], 500, c) 150 gv_check_eq("sb2-lexicon-terms-loaded-five" as *u8, pq[AB_Q_LEX_TERMS], G_LEX_TERMS, c) 151 gv_check_eq("sb2-lexicon-accuracy 3/4 = 750 permil (noisy reads the neutral record as negative: the honest miss)" as *u8, pq[AB_Q_LEX_ACC], 750, c) 152 gv_check_eq("sb2-lexicon-predicted-positive-two" as *u8, pq[AB_Q_LEX_PRED_POS], 2, c) 153 gv_check_eq("sb2-lexicon-predicted-negative-two" as *u8, pq[AB_Q_LEX_PRED_NEG], 2, c) 154 gv_check_eq("sb2-lexicon-predicted-neutral-zero" as *u8, pq[AB_Q_LEX_PRED_NEU], 0, c) 155 gv_check_eq("sb2-prediction-partition-sums-to-records" as *u8, pq[AB_Q_LEX_PRED_POS] + pq[AB_Q_LEX_PRED_NEG] + pq[AB_Q_LEX_PRED_NEU], pq[AB_Q_RECORDS], c) 156 ab_polarity(G_GOLD, G_NOLEXDIR, pq) 157 gv_check_eq("neg-control-no-lexicon-loads-zero-terms" as *u8, pq[AB_Q_LEX_TERMS], 0, c) 158 gv_check_eq("neg-control-no-lexicon-predicts-every-record-neutral" as *u8, pq[AB_Q_LEX_PRED_NEU], G_RECORDS, c) 159 gv_check_eq("neg-control-no-lexicon-accuracy-is-the-neutral-share 1/4 = 250" as *u8, pq[AB_Q_LEX_ACC], 250, c) 160 ab_polarity(G_ABSENT_GOLD, G_LEXDIR, pq) 161 gv_check_eq("neg-control-absent-gold-zero-records" as *u8, pq[AB_Q_RECORDS], 0, c) 162 gv_check_eq("neg-control-absent-gold-majority-accuracy-zero-not-a-divide" as *u8, pq[AB_Q_MAJ_ACC], 0, c) 163 gv_check_eq("neg-control-absent-gold-lexicon-accuracy-zero" as *u8, pq[AB_Q_LEX_ACC], 0, c) 164 ab_polarity(G_GOLD, G_LEXDIR, pq) 165 166 // ---- the frequent n-gram arm (Hu and Liu candidates with p-support pruning) on a gold with a repeated bigram ---- 167 gk_write(G_GOLD_NG, G_ROWS_NG) 168 gv_check_eq("fixture-reached-the-condition: n-gram gold has fifteen lines" as *u8, g_lines(G_GOLD_NG), G_NG_LINES, c) 169 let u2: *i64 = sys_mmap(AB_O_N * G_I64) as *i64 170 ab_eval(G_GOLD_NG, 0, u2) 171 let g: *i64 = sys_mmap(AB_G_N * G_I64) as *i64 172 ab_ngram_eval(G_GOLD_NG, 0, G_NG_MINSUP, g) 173 let ngf1: i64 = g[AB_G_F1] 174 gv_check_eq("ngram-records-five" as *u8, g[AB_G_RECORDS], G_NG_RECORDS, c) 175 gv_check_eq("ngram-min-support-pinned-two" as *u8, g[AB_G_MINSUP], G_NG_MINSUP, c) 176 gv_check_eq("ngram-frequent-bigram-hard-disk-found" as *u8, g[AB_G_BIGRAMS], 1, c) 177 gv_check_eq("ngram-psupport-prunes-the-two-fragments-hard-and-disk" as *u8, g[AB_G_PRUNED], G_NG_PRUNED, c) 178 gv_check("ngram-candidates-at-least-two-including-the-frequent-bigram" as *u8, (g[AB_G_CAND] >= 2) as i64, c) 179 gv_check_eq("ngram-predicted-equals-candidates" as *u8, g[AB_G_NS], g[AB_G_CAND], c) 180 gv_check_eq("ngram-multiword-gold-term-now-matched" as *u8, g[AB_G_MATCHED_BIGRAMS], 1, c) 181 gv_check_eq("ngram-matched-food-and-hard-disk-two" as *u8, g[AB_G_INTER], 2, c) 182 gv_check_eq("ngram-f1-recomputed-from-its-own-counts (matched 2, gold 3)" as *u8, g[AB_G_F1], 2 * g[AB_G_INTER] * AB_PERMIL / (g[AB_G_NS] + G_NG), c) 183 gv_check("ngram-arm-beats-the-unigram-arm-on-the-same-multiword-gold" as *u8, (g[AB_G_F1] > u2[AB_O_F1]) as i64, c) 184 ab_ngram_eval(G_GOLD_NG, 0, G_NG_MINSUP_ABOVE, g) 185 gv_check_eq("neg-control-support-above-the-bigram-frequency-finds-no-frequent-bigram" as *u8, g[AB_G_BIGRAMS], 0, c) 186 gv_check_eq("neg-control-nothing-pruned-without-a-frequent-bigram" as *u8, g[AB_G_PRUNED], 0, c) 187 gv_check_eq("neg-control-no-candidate-reaches-support-three-so-nothing-is-predicted" as *u8, g[AB_G_NS], 0, c) 188 gv_check_eq("neg-control-ngram-zero-prediction-f1-zero" as *u8, g[AB_G_F1], 0, c) 189 ab_ngram_eval(G_GOLD_NG, 0, 0, g) 190 gv_check_eq("ngram-derived-support-floors-at-one-on-five-records" as *u8, g[AB_G_MINSUP], AB_NG_MINSUP_FLOOR, c) 191 gv_check("ngram-derived-support-keeps-at-least-one-bigram-as-a-candidate" as *u8, (g[AB_G_BIGRAMS] >= 1) as i64, c) 192 193 // ---- the supervised training-dictionary tagger (rung IM28 first cut) on a planted train and test ---- 194 gk_write(G_TRAIN, G_TRAIN_ROWS) 195 gk_write(G_TEST, G_TEST_ROWS) 196 gv_check("fixture-reached-the-condition: train and test seg planted" as *u8, gk_exists(G_TRAIN) * gk_exists(G_TEST), c) 197 let d: *i64 = sys_mmap(AB_D_N * G_I64) as *i64 198 ab_dict_eval(G_TRAIN, G_TEST, d) 199 let dictf1: i64 = d[AB_D_F1] 200 gv_check_eq("dict-learns-four-training-terms" as *u8, d[AB_D_DICT], G_D_DICT, c) 201 gv_check_eq("dict-test-records-four" as *u8, d[AB_D_RECORDS], G_D_RECORDS, c) 202 gv_check_eq("dict-test-gold-terms-three" as *u8, d[AB_D_NG], G_D_NG, c) 203 gv_check_eq("dict-predicts-three: food, hard disk, keyboard (service unseen in the test corpus is not predicted)" as *u8, d[AB_D_NS], G_D_PRED, c) 204 gv_check_eq("dict-matches-food-and-hard-disk-two (keyboard is a false positive, mouse a miss, so a multi-word bigram matched)" as *u8, d[AB_D_INTER], G_D_INTER, c) 205 gv_check_eq("dict-precision 2/3 = 666 permil (keyboard predicted but not gold)" as *u8, d[AB_D_P], 666, c) 206 gv_check_eq("dict-recall 2/3 = 666 permil (mouse missed: absent from the training dictionary)" as *u8, d[AB_D_R], 666, c) 207 gv_check_eq("dict-f1-recomputed-from-its-own-counts" as *u8, d[AB_D_F1], 2 * d[AB_D_INTER] * AB_PERMIL / (d[AB_D_NS] + d[AB_D_NG]), c) 208 209 gv_values_head() 210 gv_kv("dict_f1_permil" as *u8, dictf1) 211 gv_kv("ngram_f1_permil_at_support_two" as *u8, ngf1) 212 gv_kv("unigram_f1_permil_same_gold" as *u8, u2[AB_O_F1]) 213 gv_kv("sb2_majority_acc_permil" as *u8, pq[AB_Q_MAJ_ACC]) 214 gv_kv("sb2_lexicon_acc_permil" as *u8, pq[AB_Q_LEX_ACC]) 215 gv_kv("gold_terms" as *u8, out[AB_O_NG]) 216 gv_kv("predicted" as *u8, out[AB_O_NS]) 217 gv_kv("matched" as *u8, out[AB_O_INTER]) 218 gv_kv("f1_permil" as *u8, out[AB_O_F1]) 219 gv_kv("vocab" as *u8, out[AB_O_VOCAB]) 220 return gv_verdict("nx_absa_bench_gate" as *u8, c, "the SemEval-2014 SB1 F1 scorer proven in-process on a planted gold set under /tmp: the F1 arithmetic at exact permil values with a zero-prediction and a no-gold control, distinct-term dedupe, CRLF tolerance, a case/whitespace-insensitive normaliser, the unigram-cannot-match-multiword honest weakness, a non-vacuous end-to-end eval, and the subtask-2 polarity arms (majority and lexicon) on planted lexicons with a no-lexicon control, and the frequent n-gram arm with p-support pruning on a gold whose multi-word term repeats, with a support-above-frequency control, and the supervised training-dictionary tagger with a false-positive and a miss planted so precision and recall are each below one; every fixture asserts its own condition first" as *u8) 221}