code wiki / _hdl_build / nx_research_relation.nx

nx_research_relation.nx source

↩ module page · 116 lines · 4319 B

1// nx_research_relation.nx -- Researcher EXTRACT, rung 1 of the GROWN-ORGAN 2// semantic pipeline (permanent intelligence = sovereign Nishi organs, hardware 3// rung up; NO trained weights -- those are benchmark/initial only). 4// 5// The number-only extractor (nx_research_extract) pulls "53" out of "53 percent" 6// -- but misses QUALITATIVE claims (concepts, tradeoffs, architecture), which is 7// the real depth gap vs deep-research. This organ extracts (subject, relation, 8// object) triples by an INSPECTABLE, data-driven cue table -- every decision is 9// visible (which cue matched, the exact spans), the opposite of a black box. 10// 11// API: nx_rel_extract(text, n, subj_out, obj_out) -> relation index (>=0) | -1 12// rel_name(i) -> the relation type string for index i. 13// Reuses re_find / re_strlen from nx_research_extract (DRY). license_tier: ORIGINAL. 14 15import "nx_syscalls.nx" 16import "nx_research_extract.nx" 17 18// ---- relation cue table (DATA: cue phrase -> relation type). Extensible. ---- 19func rel_n_cues() -> i64 { return 10 } 20 21func rel_cue(i: i64) -> *u8 { 22 if i == 0 { return " is a " as *u8 } 23 if i == 1 { return " is the " as *u8 } 24 if i == 2 { return " is an " as *u8 } 25 if i == 3 { return " uses " as *u8 } 26 if i == 4 { return " requires " as *u8 } 27 if i == 5 { return " enables " as *u8 } 28 if i == 6 { return " provides " as *u8 } 29 if i == 7 { return " supports " as *u8 } 30 if i == 8 { return " consists of " as *u8 } 31 if i == 9 { return " is based on " as *u8 } 32 return 0 as *u8 33} 34 35func rel_name(i: i64) -> *u8 { 36 if i == 0 { return "IS_A" as *u8 } 37 if i == 1 { return "IS_THE" as *u8 } 38 if i == 2 { return "IS_A" as *u8 } 39 if i == 3 { return "USES" as *u8 } 40 if i == 4 { return "REQUIRES" as *u8 } 41 if i == 5 { return "ENABLES" as *u8 } 42 if i == 6 { return "PROVIDES" as *u8 } 43 if i == 7 { return "SUPPORTS" as *u8 } 44 if i == 8 { return "CONSISTS_OF" as *u8 } 45 if i == 9 { return "BASED_ON" as *u8 } 46 return "NONE" as *u8 47} 48 49// earliest cue in text[0..n): returns cue index | -1; sets *cpos=start, *clen=len. 50func rel_find_cue(text: *u8, n: i64, cpos: *i64, clen: *i64) -> i64 { 51 var best: i64 = 0 - 1 52 var bestpos: i64 = n 53 var bestlen: i64 = 0 54 var i: i64 = 0 55 while i < rel_n_cues() { 56 let cue: *u8 = rel_cue(i) 57 let p: i64 = re_find(text, n, cue) 58 if p >= 0 { 59 if p < bestpos { bestpos = p; best = i; bestlen = re_strlen(cue) } 60 } 61 i = i + 1 62 } 63 if best < 0 { return 0 - 1 } 64 cpos[0] = bestpos 65 clen[0] = bestlen 66 return best 67} 68 69// is byte a clause/sentence stop? ('.' ',' ';' newline) 70func rel_is_stop(c: u8) -> i64 { 71 if c == (46 as u8) { return 1 } 72 if c == (44 as u8) { return 1 } 73 if c == (59 as u8) { return 1 } 74 if c == (10 as u8) { return 1 } 75 return 0 76} 77 78// copy text[a..b) into out, trimming leading/trailing spaces, NUL-terminate; len. 79func rel_slice(text: *u8, a0: i64, b0: i64, out: *u8) -> i64 { 80 var a: i64 = a0 81 var b: i64 = b0 82 while a < b { if text[a] == (32 as u8) { a = a + 1 } else { break } } 83 while b > a { if text[b - 1] == (32 as u8) { b = b - 1 } else { break } } 84 var k: i64 = 0 85 var i: i64 = a 86 while i < b { out[k] = text[i]; k = k + 1; i = i + 1 } 87 out[k] = 0 as u8 88 return k 89} 90 91// Extract ONE (subject, relation, object) claim from a sentence text[0..n). 92// subject = phrase from the last clause-stop before the cue to the cue; 93// object = phrase from the cue end to the next clause-stop (or end). 94func nx_rel_extract(text: *u8, n: i64, subj: *u8, obj: *u8) -> i64 { 95 let cpos: *i64 = (sys_mmap(8)) as *i64 96 let clen: *i64 = (sys_mmap(8)) as *i64 97 let ri: i64 = rel_find_cue(text, n, cpos, clen) 98 if ri < 0 { return 0 - 1 } 99 // subject: walk back from cue start to the last stop (or sentence start) 100 var ss: i64 = cpos[0] - 1 101 while ss > 0 { 102 if rel_is_stop(text[ss]) == 1 { ss = ss + 1; break } 103 ss = ss - 1 104 } 105 if ss < 0 { ss = 0 } 106 rel_slice(text, ss, cpos[0], subj) 107 // object: from cue end forward to the next stop (or n) 108 let oe0: i64 = cpos[0] + clen[0] 109 var oe: i64 = oe0 110 while oe < n { 111 if rel_is_stop(text[oe]) == 1 { break } 112 oe = oe + 1 113 } 114 rel_slice(text, oe0, oe, obj) 115 return ri 116}