code wiki / _hdl_build / nx_ocr_recall_lib.nx
nx_ocr_recall_lib.nx source
↩ module page · 104 lines · 3824 B
1// nx_ocr_recall_lib.nx -- the reading-recall SCORING MATH as a shared lib (single-responsibility: the CLI
2// nx_ocr_recall.nx and the gate nx_ocr_recall_gate.nx both call ocr_recall_score, so the gate proves the
3// EXACT code the CLI runs -- no fork/pipe harness to deadlock). Truth-token multiset recall/precision/F1,
4// SQuAD-norm (lowercase, non-alnum->space, articles a/an/the dropped). out[0]=recall out[1]=precision
5// out[2]=f1 out[3]=truth_tokens out[4]=ours_tokens out[5]=matched, all integer permille where a ratio.
6// license_tier: ORIGINAL
7import "nx_syscalls.nx"
8
9const ORL_CAP: i64 = 262144
10const ORL_MAXTOK: i64 = 8192
11
12func orl_norm(src: *u8, n: i64, buf: *u8) -> i64 {
13 var i: i64 = 0
14 while i < n {
15 var c: i64 = (src[i] as i64) & 255
16 if c >= 65 { if c <= 90 { c = c + 32 } }
17 var ok: i64 = 0
18 if c >= 97 { if c <= 122 { ok = 1 } }
19 if c >= 48 { if c <= 57 { ok = 1 } }
20 if ok == 1 { buf[i] = c as u8 } else { buf[i] = 32 as u8 }
21 i = i + 1
22 }
23 return n
24}
25func orl_tok(buf: *u8, n: i64, toff: *i64, tlen: *i64) -> i64 {
26 var cnt: i64 = 0
27 var i: i64 = 0
28 while i < n {
29 var sk: i64 = 1
30 while sk == 1 {
31 if i >= n { sk = 0 }
32 else { if (buf[i] as i64) == 32 { i = i + 1 } else { sk = 0 } }
33 }
34 if i < n {
35 var j: i64 = i
36 var sc: i64 = 1
37 while sc == 1 {
38 if j >= n { sc = 0 }
39 else { if (buf[j] as i64) != 32 { j = j + 1 } else { sc = 0 } }
40 }
41 let L: i64 = j - i
42 var art: i64 = 0
43 if L == 1 { if (buf[i] as i64) == 97 { art = 1 } }
44 if L == 2 { if (buf[i] as i64) == 97 { if (buf[i+1] as i64) == 110 { art = 1 } } }
45 if L == 3 { if (buf[i] as i64) == 116 { if (buf[i+1] as i64) == 104 { if (buf[i+2] as i64) == 101 { art = 1 } } } }
46 if art == 0 { if cnt < ORL_MAXTOK { toff[cnt] = i; tlen[cnt] = L; cnt = cnt + 1 } }
47 i = j
48 }
49 }
50 return cnt
51}
52func orl_eq(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 {
53 if al != bl { return 0 }
54 var k: i64 = 0
55 while k < al { if a[ao+k] != b[bo+k] { return 0 } k = k + 1 }
56 return 1
57}
58// score truth (n bytes) vs ours (m bytes) -> out[0..5]
59func ocr_recall_score(truth: *u8, tn0: i64, ours: *u8, on0: i64, out: *i64) -> i64 {
60 let tb: *u8 = sys_mmap(ORL_CAP)
61 let ob: *u8 = sys_mmap(ORL_CAP)
62 var tn: i64 = tn0
63 if tn > ORL_CAP { tn = ORL_CAP }
64 var on: i64 = on0
65 if on > ORL_CAP { on = ORL_CAP }
66 orl_norm(truth, tn, tb)
67 if on > 0 { orl_norm(ours, on, ob) }
68 let t_off: *i64 = sys_mmap(ORL_MAXTOK*8) as *i64
69 let t_len: *i64 = sys_mmap(ORL_MAXTOK*8) as *i64
70 let o_off: *i64 = sys_mmap(ORL_MAXTOK*8) as *i64
71 let o_len: *i64 = sys_mmap(ORL_MAXTOK*8) as *i64
72 let used: *i64 = sys_mmap(ORL_MAXTOK*8) as *i64
73 let ntt: i64 = orl_tok(tb, tn, t_off, t_len)
74 var not_: i64 = 0
75 if on > 0 { not_ = orl_tok(ob, on, o_off, o_len) }
76 var i: i64 = 0
77 while i < not_ { used[i] = 0; i = i + 1 }
78 var hit: i64 = 0
79 i = 0
80 while i < ntt {
81 var j: i64 = 0
82 var done: i64 = 0
83 while j < not_ {
84 if done == 0 { if used[j] == 0 {
85 if orl_eq(tb, t_off[i], t_len[i], ob, o_off[j], o_len[j]) == 1 { used[j] = 1; hit = hit + 1; done = 1 }
86 } }
87 j = j + 1
88 }
89 i = i + 1
90 }
91 var recall: i64 = 0
92 if ntt > 0 { recall = (hit * 1000) / ntt }
93 var prec: i64 = 0
94 if not_ > 0 { prec = (hit * 1000) / not_ }
95 var f1: i64 = 0
96 if recall + prec > 0 { f1 = (2 * recall * prec) / (recall + prec) }
97 out[0] = recall
98 out[1] = prec
99 out[2] = f1
100 out[3] = ntt
101 out[4] = not_
102 out[5] = hit
103 return 0
104}