code wiki / (root) / nx_primitive_registry.nx

nx_primitive_registry.nx source

↩ module page · 173 lines · 6419 B

1// nx_primitive_registry.nx -- callable-by-name primitive catalog. 2// 3// Per user 2026-05-15: "actually ingest and use all the algorithms 4// known as primitives as callable elements like functions like other 5// systems". 6// 7// THE PATTERN (NumPy / SciPy / Mathematica / MATLAB): 8// - Every primitive has a stable name (string) 9// - The catalog records (name, signature_id, domain, complexity, 10// provenance), enabling discovery and introspection 11// - Lookup-by-name returns a stable IntID; downstream code 12// dispatches by ID for performance 13// - Per-domain query lets the user enumerate "what physics 14// primitives are available?" 15// 16// NOTE: NishiLang doesn't yet have first-class function pointers in 17// the user-source surface, so the registry stores METADATA + a stable 18// dispatch_id. Caller chooses to invoke by direct symbol name (the 19// fast path -- L3 callable) OR via the dispatcher (the slow but 20// uniform path). Adding first-class fn pointers is a named blocker 21// for full Mathematica-style Symbolic[] dispatch and is on the 22// compiler-improvements queue. 23 24// nx_safety_envelope: 25// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 26// sil_target: SIL1 27// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 28// verdict: NOT_YET_EVALUATED 29 30import "nx_kernel_v2.nx" 31 32// ===== Domain enum (sealed) ========================================= 33const NX_DOMAIN_LOGIC: nx_int = 1 // kernel rules + propositional engine 34const NX_DOMAIN_ARITH: nx_int = 2 // nat / int / rat / real Term substrate 35const NX_DOMAIN_LINALG: nx_int = 3 // vec / matrix 36const NX_DOMAIN_CALC: nx_int = 4 // symbolic derivative / integral 37const NX_DOMAIN_PHYSICS: nx_int = 5 // units + dim analysis + dynamics 38const NX_DOMAIN_CHEM: nx_int = 6 // atomic table + stoichiometry 39const NX_DOMAIN_PROB: nx_int = 7 // probability + statistics 40const NX_DOMAIN_PROOF: nx_int = 8 // proof construction (engine + tactics) 41const NX_DOMAIN_RENDER: nx_int = 9 // visual output (CLI + browser) 42const NX_DOMAIN_DATA: nx_int = 10 // sketches / hashes / encodings 43 44// ===== Complexity buckets (Q-format big-O hints) ==================== 45const NX_COMPLEX_O1: nx_int = 1 46const NX_COMPLEX_O_LOG_N: nx_int = 2 47const NX_COMPLEX_O_N: nx_int = 3 48const NX_COMPLEX_O_N_LOG_N: nx_int = 4 49const NX_COMPLEX_O_N2: nx_int = 5 50const NX_COMPLEX_O_N3: nx_int = 6 51const NX_COMPLEX_O_2N: nx_int = 7 52const NX_COMPLEX_NP: nx_int = 8 53 54// ===== Provenance ==================================================== 55// PROVED_NATIVE: implementation lives in NishiLang + has a kernel 56// chain or smoke-verified semantics. PENDING: registered name only, 57// no implementation yet. No third-party-trust status (cardinal). 58const NX_PRIM_PROVED_NATIVE: nx_int = 0 59const NX_PRIM_PENDING: nx_int = 1 60 61// ===== One catalog entry ============================================ 62struct PrimEntry { 63 name: *u8, 64 name_len: nx_int, 65 sig_id: nx_int, // signature schema id (1=Term->Term, 2=Term*Term->Term, etc.) 66 domain: nx_int, 67 complexity: nx_int, 68 status: nx_int, 69 dispatch_id: nx_int, // stable 0-indexed id 70} 71const NX_PRIM_BYTES: nx_int = 56 72 73struct PrimRegistry { 74 entries: *PrimEntry, 75 n: nx_int, 76 cap: nx_int, 77} 78const NX_PRIM_REG_BYTES: nx_int = 24 79 80func nx_prim_registry_new(cap: nx_int) -> *PrimRegistry { 81 let r: *PrimRegistry = (sys_mmap(NX_PRIM_REG_BYTES as i64)) as *PrimRegistry 82 r.entries = (sys_mmap((cap * NX_PRIM_BYTES) as i64)) as *PrimEntry 83 r.n = 0 84 r.cap = cap 85 return r 86} 87 88func nx_prim_at(r: *PrimRegistry, i: nx_int) -> *PrimEntry { 89 return ((r.entries as nx_int) + (i * NX_PRIM_BYTES)) as *PrimEntry 90} 91 92// Register a primitive. Returns dispatch_id (>= 0) or -1 if full. 93func nx_prim_register( 94 r: *PrimRegistry, 95 name: *u8, name_len: nx_int, 96 sig_id: nx_int, domain: nx_int, 97 complexity: nx_int, status: nx_int 98) -> nx_int { 99 if r.n >= r.cap { return 0 - 1 } 100 let e: *PrimEntry = nx_prim_at(r, r.n) 101 e.name = name 102 e.name_len = name_len 103 e.sig_id = sig_id 104 e.domain = domain 105 e.complexity = complexity 106 e.status = status 107 e.dispatch_id = r.n 108 let id: nx_int = r.n 109 r.n = r.n + 1 110 return id 111} 112 113// Lookup: return dispatch_id of named primitive, or -1. 114// Linear scan; fine for catalogs under ~500 entries. For larger 115// catalogs use a hash index (named follow-up). 116func nx_prim_lookup(r: *PrimRegistry, name: *u8, name_len: nx_int) -> nx_int { 117 var i: nx_int = 0 118 while i < r.n { 119 let e: *PrimEntry = nx_prim_at(r, i) 120 if e.name_len == name_len { 121 var same: nx_int = 1 122 var j: nx_int = 0 123 while j < name_len { 124 let a: *u8 = ((name as nx_int) + j) as *u8 125 let b: *u8 = ((e.name as nx_int) + j) as *u8 126 if a[0] != b[0] { same = 0 } 127 j = j + 1 128 } 129 if same == 1 { return e.dispatch_id } 130 } 131 i = i + 1 132 } 133 return 0 - 1 134} 135 136// Count primitives in a given domain. 137func nx_prim_count_by_domain(r: *PrimRegistry, domain: nx_int) -> nx_int { 138 var n: nx_int = 0 139 var i: nx_int = 0 140 while i < r.n { 141 let e: *PrimEntry = nx_prim_at(r, i) 142 if e.domain == domain { n = n + 1 } 143 i = i + 1 144 } 145 return n 146} 147 148// Count by status. 149func nx_prim_count_by_status(r: *PrimRegistry, status: nx_int) -> nx_int { 150 var n: nx_int = 0 151 var i: nx_int = 0 152 while i < r.n { 153 let e: *PrimEntry = nx_prim_at(r, i) 154 if e.status == status { n = n + 1 } 155 i = i + 1 156 } 157 return n 158} 159 160// Domain name pretty-print. 161func nx_prim_domain_name(d: nx_int) -> *u8 { 162 if d == NX_DOMAIN_LOGIC { return "LOGIC " as *u8 } 163 if d == NX_DOMAIN_ARITH { return "ARITH " as *u8 } 164 if d == NX_DOMAIN_LINALG { return "LINALG " as *u8 } 165 if d == NX_DOMAIN_CALC { return "CALC " as *u8 } 166 if d == NX_DOMAIN_PHYSICS { return "PHYSICS " as *u8 } 167 if d == NX_DOMAIN_CHEM { return "CHEM " as *u8 } 168 if d == NX_DOMAIN_PROB { return "PROB " as *u8 } 169 if d == NX_DOMAIN_PROOF { return "PROOF " as *u8 } 170 if d == NX_DOMAIN_RENDER { return "RENDER " as *u8 } 171 if d == NX_DOMAIN_DATA { return "DATA " as *u8 } 172 return "UNKNOWN " as *u8 173}