nx_ontology.nx source
↩ module page · 239 lines · 7662 B
1// nx_ontology.nx -- substrate-native ontology over RDF-style triples.
2//
3// Per user directive 2026-05-14: "ontology needs to be recognized as a
4// part of what we are doing as we build this math layer" (Wikipedia:
5// Ontology (information science)).
6//
7// Reads nxc2/specs/nx_ontology.txt (TSV: subject, predicate, object,
8// optional notes) and exposes count + lookup queries. Predicates are
9// free-form strings; consumers compare directly.
10//
11// Composes with patent_check, provenance, emit_journal: substrate now
12// has a typed knowledge graph linking algorithm -> category -> source
13// -> license -> patent_status.
14//
15// genealogy_id: substrate_ontology_2026_05_14
16// lineage_id: substrate_self_description
17
18// nx_safety_envelope:
19// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
20// sil_target: SIL1
21// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
22// verdict: NOT_YET_EVALUATED
23
24import "nx_syscalls.nx"
25import "nx_runtime.nx"
26import "nx_tier.nx"
27import "nx_str.nx"
28
29const NX_ONT_MAX_TRIPLES: nx_int = 4096
30const NX_ONT_FIELD_CAP: nx_size = 96
31
32// ===== struct =======================================================
33
34struct NxOntologyTriple {
35 subject: *u8,
36 predicate: *u8,
37 object: *u8,
38}
39
40const NX_ONT_TRIPLE_BYTES: nx_size = 24
41
42struct NxOntology {
43 triples: *NxOntologyTriple,
44 n: nx_int,
45 capacity: nx_int,
46}
47
48// ===== parse one TSV row ============================================
49
50// Returns 1 on success, 0 on skip (blank/comment/malformed).
51func nx_ont_parse_line(buf: *u8, lo: nx_int, hi: nx_int,
52 s_buf: *u8, p_buf: *u8, o_buf: *u8,
53 out: *NxOntologyTriple) -> nx_int {
54 // Skip leading whitespace
55 var p: nx_int = lo
56 var ws_done: nx_int = 0
57 while ws_done == 0 {
58 if p >= hi { ws_done = 1 }
59 if ws_done == 0 {
60 let c: nx_int = buf[p] as nx_int
61 if c == 32 { p = p + 1 }
62 if c != 32 {
63 if c == 9 { p = p + 1 }
64 if c != 9 { ws_done = 1 }
65 }
66 }
67 }
68 if p >= hi { return 0 }
69 if buf[p] == 35 { return 0 } // '#' comment
70 if buf[p] == 10 { return 0 } // blank
71
72 // Field 1: subject
73 var e1: nx_int = p
74 var d1: nx_int = 0
75 while d1 == 0 {
76 if e1 >= hi { d1 = 1 }
77 if d1 == 0 {
78 let c: nx_int = buf[e1] as nx_int
79 if c == 9 { d1 = 1 }
80 if c == 10 { d1 = 1 }
81 if d1 == 0 { e1 = e1 + 1 }
82 }
83 }
84 if e1 >= hi { return 0 }
85 if buf[e1] == 10 { return 0 }
86 let s_len: nx_int = e1 - p
87 if s_len == 0 { return 0 }
88 if s_len >= (NX_ONT_FIELD_CAP as nx_int) { return 0 }
89 var i: nx_int = 0
90 while i < s_len { s_buf[i] = buf[p + i]; i = i + 1 }
91 s_buf[s_len] = 0
92
93 // Field 2: predicate
94 p = e1 + 1
95 var e2: nx_int = p
96 var d2: nx_int = 0
97 while d2 == 0 {
98 if e2 >= hi { d2 = 1 }
99 if d2 == 0 {
100 let c: nx_int = buf[e2] as nx_int
101 if c == 9 { d2 = 1 }
102 if c == 10 { d2 = 1 }
103 if d2 == 0 { e2 = e2 + 1 }
104 }
105 }
106 if e2 >= hi { return 0 }
107 if buf[e2] == 10 { return 0 }
108 let p_len: nx_int = e2 - p
109 if p_len == 0 { return 0 }
110 if p_len >= (NX_ONT_FIELD_CAP as nx_int) { return 0 }
111 i = 0
112 while i < p_len { p_buf[i] = buf[p + i]; i = i + 1 }
113 p_buf[p_len] = 0
114
115 // Field 3: object (up to TAB or NL -- TAB allowed for trailing notes)
116 p = e2 + 1
117 var e3: nx_int = p
118 var d3: nx_int = 0
119 while d3 == 0 {
120 if e3 >= hi { d3 = 1 }
121 if d3 == 0 {
122 let c: nx_int = buf[e3] as nx_int
123 if c == 9 { d3 = 1 }
124 if c == 10 { d3 = 1 }
125 if d3 == 0 { e3 = e3 + 1 }
126 }
127 }
128 let o_len: nx_int = e3 - p
129 if o_len == 0 { return 0 }
130 if o_len >= (NX_ONT_FIELD_CAP as nx_int) { return 0 }
131 i = 0
132 while i < o_len { o_buf[i] = buf[p + i]; i = i + 1 }
133 o_buf[o_len] = 0
134
135 // Own copies
136 let s_owned: *u8 = sys_mmap((s_len + 1) as nx_size)
137 nx_str_cpy(s_owned, s_buf)
138 let p_owned: *u8 = sys_mmap((p_len + 1) as nx_size)
139 nx_str_cpy(p_owned, p_buf)
140 let o_owned: *u8 = sys_mmap((o_len + 1) as nx_size)
141 nx_str_cpy(o_owned, o_buf)
142 out.subject = s_owned
143 out.predicate = p_owned
144 out.object = o_owned
145 return 1
146}
147
148// ===== load + queries ===============================================
149
150func nx_ontology_load(path: *u8) -> *NxOntology {
151 let raw: *u8 = sys_mmap(24)
152 let o: *NxOntology = raw as *NxOntology
153 o.triples = (sys_mmap((NX_ONT_MAX_TRIPLES as nx_size) * NX_ONT_TRIPLE_BYTES)) as *NxOntologyTriple
154 o.n = 0
155 o.capacity = NX_ONT_MAX_TRIPLES
156
157 let len_p: *nx_size = (sys_mmap(NX_SIZEOF_NX_SIZE)) as *nx_size
158 len_p[0] = 0
159 let buf: *u8 = sys_read_file(path, len_p)
160 if (buf as nx_size) == 0 { return o }
161 let n: nx_int = len_p[0] as nx_int
162
163 let s_buf: *u8 = sys_mmap(NX_ONT_FIELD_CAP)
164 let p_buf: *u8 = sys_mmap(NX_ONT_FIELD_CAP)
165 let o_buf: *u8 = sys_mmap(NX_ONT_FIELD_CAP)
166
167 var p: nx_int = 0
168 while p < n {
169 var eol: nx_int = p
170 var de: nx_int = 0
171 while de == 0 {
172 if eol >= n { de = 1 }
173 if de == 0 {
174 if buf[eol] == 10 { de = 1 }
175 if de == 0 { eol = eol + 1 }
176 }
177 }
178 if o.n < o.capacity {
179 let raw_t: *u8 = ((o.triples as nx_size) + (o.n as nx_size) * NX_ONT_TRIPLE_BYTES) as *u8
180 let t: *NxOntologyTriple = raw_t as *NxOntologyTriple
181 let parsed: nx_int = nx_ont_parse_line(buf, p, eol, s_buf, p_buf, o_buf, t)
182 if parsed == 1 { o.n = o.n + 1 }
183 }
184 p = eol + 1
185 }
186 return o
187}
188
189func nx_ontology_n_triples(o: *NxOntology) -> nx_int { return o.n }
190
191// Count triples with given predicate.
192func nx_ontology_count_by_predicate(o: *NxOntology, pred: *u8) -> nx_int {
193 var c: nx_int = 0
194 var i: nx_int = 0
195 while i < o.n {
196 let raw_t: *u8 = ((o.triples as nx_size) + (i as nx_size) * NX_ONT_TRIPLE_BYTES) as *u8
197 let t: *NxOntologyTriple = raw_t as *NxOntologyTriple
198 if nx_str_eq(t.predicate, pred) == 1 { c = c + 1 }
199 i = i + 1
200 }
201 return c
202}
203
204// Count triples with given (predicate, object) -- e.g.
205// nx_ontology_count_with_po(o, "in_domain", "competitive_programming")
206func nx_ontology_count_with_po(o: *NxOntology, pred: *u8, obj: *u8) -> nx_int {
207 var c: nx_int = 0
208 var i: nx_int = 0
209 while i < o.n {
210 let raw_t: *u8 = ((o.triples as nx_size) + (i as nx_size) * NX_ONT_TRIPLE_BYTES) as *u8
211 let t: *NxOntologyTriple = raw_t as *NxOntologyTriple
212 if nx_str_eq(t.predicate, pred) == 1 {
213 if nx_str_eq(t.object, obj) == 1 { c = c + 1 }
214 }
215 i = i + 1
216 }
217 return c
218}
219
220// Exact-match triple lookup.
221func nx_ontology_has_triple(o: *NxOntology, subj: *u8, pred: *u8, obj: *u8) -> nx_int {
222 var i: nx_int = 0
223 while i < o.n {
224 let raw_t: *u8 = ((o.triples as nx_size) + (i as nx_size) * NX_ONT_TRIPLE_BYTES) as *u8
225 let t: *NxOntologyTriple = raw_t as *NxOntologyTriple
226 if nx_str_eq(t.subject, subj) == 1 {
227 if nx_str_eq(t.predicate, pred) == 1 {
228 if nx_str_eq(t.object, obj) == 1 { return 1 }
229 }
230 }
231 i = i + 1
232 }
233 return 0
234}
235
236// "Is this subject in this domain?" -- shortcut for in_domain triple lookup.
237func nx_ontology_in_domain(o: *NxOntology, subj: *u8, domain: *u8) -> nx_int {
238 return nx_ontology_has_triple(o, subj, "in_domain" as *u8, domain)
239}