@hviana/sema 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/example/demo.d.ts +1 -0
  2. package/dist/example/demo.js +39 -0
  3. package/dist/example/train_base.d.ts +87 -0
  4. package/dist/example/train_base.js +2216 -0
  5. package/dist/src/alphabet.d.ts +7 -0
  6. package/dist/src/alphabet.js +33 -0
  7. package/dist/src/alu/src/alu.d.ts +185 -0
  8. package/dist/src/alu/src/alu.js +440 -0
  9. package/dist/src/alu/src/expr.d.ts +61 -0
  10. package/dist/src/alu/src/expr.js +318 -0
  11. package/dist/src/alu/src/index.d.ts +11 -0
  12. package/dist/src/alu/src/index.js +19 -0
  13. package/dist/src/alu/src/kernel-arith.d.ts +16 -0
  14. package/dist/src/alu/src/kernel-arith.js +264 -0
  15. package/dist/src/alu/src/kernel-bits.d.ts +19 -0
  16. package/dist/src/alu/src/kernel-bits.js +152 -0
  17. package/dist/src/alu/src/kernel-logic.d.ts +4 -0
  18. package/dist/src/alu/src/kernel-logic.js +60 -0
  19. package/dist/src/alu/src/kernel-nd.d.ts +3 -0
  20. package/dist/src/alu/src/kernel-nd.js +208 -0
  21. package/dist/src/alu/src/kernel-numeric.d.ts +54 -0
  22. package/dist/src/alu/src/kernel-numeric.js +366 -0
  23. package/dist/src/alu/src/operation.d.ts +168 -0
  24. package/dist/src/alu/src/operation.js +189 -0
  25. package/dist/src/alu/src/parser.d.ts +212 -0
  26. package/dist/src/alu/src/parser.js +469 -0
  27. package/dist/src/alu/src/resonance.d.ts +55 -0
  28. package/dist/src/alu/src/resonance.js +126 -0
  29. package/dist/src/alu/src/text.d.ts +31 -0
  30. package/dist/src/alu/src/text.js +73 -0
  31. package/dist/src/alu/src/value.d.ts +109 -0
  32. package/dist/src/alu/src/value.js +300 -0
  33. package/dist/src/alu/test/alu.test.d.ts +1 -0
  34. package/dist/src/alu/test/alu.test.js +764 -0
  35. package/dist/src/bytes.d.ts +14 -0
  36. package/dist/src/bytes.js +59 -0
  37. package/dist/src/config.d.ts +114 -0
  38. package/dist/src/config.js +96 -0
  39. package/dist/src/derive/src/deduction.d.ts +125 -0
  40. package/dist/src/derive/src/deduction.js +155 -0
  41. package/dist/src/derive/src/index.d.ts +7 -0
  42. package/dist/src/derive/src/index.js +11 -0
  43. package/dist/src/derive/src/priority-queue.d.ts +20 -0
  44. package/dist/src/derive/src/priority-queue.js +73 -0
  45. package/dist/src/derive/src/rewrite.d.ts +56 -0
  46. package/dist/src/derive/src/rewrite.js +100 -0
  47. package/dist/src/derive/src/trie.d.ts +90 -0
  48. package/dist/src/derive/src/trie.js +217 -0
  49. package/dist/src/derive/test/derive.test.d.ts +1 -0
  50. package/dist/src/derive/test/derive.test.js +122 -0
  51. package/dist/src/extension.d.ts +37 -0
  52. package/dist/src/extension.js +7 -0
  53. package/dist/src/geometry.d.ts +137 -0
  54. package/dist/src/geometry.js +430 -0
  55. package/dist/src/index.d.ts +15 -0
  56. package/dist/src/index.js +21 -0
  57. package/dist/src/ingest-cache.d.ts +41 -0
  58. package/dist/src/ingest-cache.js +161 -0
  59. package/dist/src/mind/articulation.d.ts +6 -0
  60. package/dist/src/mind/articulation.js +99 -0
  61. package/dist/src/mind/attention.d.ts +72 -0
  62. package/dist/src/mind/attention.js +894 -0
  63. package/dist/src/mind/canonical.d.ts +29 -0
  64. package/dist/src/mind/canonical.js +88 -0
  65. package/dist/src/mind/graph-search.d.ts +270 -0
  66. package/dist/src/mind/graph-search.js +847 -0
  67. package/dist/src/mind/index.d.ts +5 -0
  68. package/dist/src/mind/index.js +5 -0
  69. package/dist/src/mind/junction.d.ts +95 -0
  70. package/dist/src/mind/junction.js +262 -0
  71. package/dist/src/mind/learning.d.ts +47 -0
  72. package/dist/src/mind/learning.js +201 -0
  73. package/dist/src/mind/match.d.ts +111 -0
  74. package/dist/src/mind/match.js +422 -0
  75. package/dist/src/mind/mechanisms/alu.d.ts +4 -0
  76. package/dist/src/mind/mechanisms/alu.js +29 -0
  77. package/dist/src/mind/mechanisms/cast.d.ts +35 -0
  78. package/dist/src/mind/mechanisms/cast.js +447 -0
  79. package/dist/src/mind/mechanisms/confluence.d.ts +24 -0
  80. package/dist/src/mind/mechanisms/confluence.js +213 -0
  81. package/dist/src/mind/mechanisms/cover.d.ts +6 -0
  82. package/dist/src/mind/mechanisms/cover.js +179 -0
  83. package/dist/src/mind/mechanisms/extraction.d.ts +67 -0
  84. package/dist/src/mind/mechanisms/extraction.js +342 -0
  85. package/dist/src/mind/mechanisms/recall.d.ts +13 -0
  86. package/dist/src/mind/mechanisms/recall.js +151 -0
  87. package/dist/src/mind/mind.d.ts +147 -0
  88. package/dist/src/mind/mind.js +300 -0
  89. package/dist/src/mind/pipeline-mechanism.d.ts +142 -0
  90. package/dist/src/mind/pipeline-mechanism.js +213 -0
  91. package/dist/src/mind/pipeline.d.ts +20 -0
  92. package/dist/src/mind/pipeline.js +185 -0
  93. package/dist/src/mind/primitives.d.ts +43 -0
  94. package/dist/src/mind/primitives.js +162 -0
  95. package/dist/src/mind/rationale.d.ts +134 -0
  96. package/dist/src/mind/rationale.js +162 -0
  97. package/dist/src/mind/reasoning.d.ts +15 -0
  98. package/dist/src/mind/reasoning.js +162 -0
  99. package/dist/src/mind/recognition.d.ts +20 -0
  100. package/dist/src/mind/recognition.js +223 -0
  101. package/dist/src/mind/resonance.d.ts +23 -0
  102. package/dist/src/mind/resonance.js +0 -0
  103. package/dist/src/mind/trace.d.ts +15 -0
  104. package/dist/src/mind/trace.js +73 -0
  105. package/dist/src/mind/traverse.d.ts +100 -0
  106. package/dist/src/mind/traverse.js +447 -0
  107. package/dist/src/mind/types.d.ts +174 -0
  108. package/dist/src/mind/types.js +84 -0
  109. package/dist/src/rabitq-hnsw/src/database.d.ts +200 -0
  110. package/dist/src/rabitq-hnsw/src/database.js +388 -0
  111. package/dist/src/rabitq-hnsw/src/heap.d.ts +22 -0
  112. package/dist/src/rabitq-hnsw/src/heap.js +89 -0
  113. package/dist/src/rabitq-hnsw/src/hnsw.d.ts +125 -0
  114. package/dist/src/rabitq-hnsw/src/hnsw.js +474 -0
  115. package/dist/src/rabitq-hnsw/src/index.d.ts +10 -0
  116. package/dist/src/rabitq-hnsw/src/index.js +6 -0
  117. package/dist/src/rabitq-hnsw/src/prng.d.ts +19 -0
  118. package/dist/src/rabitq-hnsw/src/prng.js +36 -0
  119. package/dist/src/rabitq-hnsw/src/rabitq.d.ts +95 -0
  120. package/dist/src/rabitq-hnsw/src/rabitq.js +283 -0
  121. package/dist/src/rabitq-hnsw/src/store.d.ts +162 -0
  122. package/dist/src/rabitq-hnsw/src/store.js +825 -0
  123. package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +1 -0
  124. package/dist/src/rabitq-hnsw/test/hnsw.test.js +948 -0
  125. package/dist/src/store-sqlite.d.ts +149 -0
  126. package/dist/src/store-sqlite.js +702 -0
  127. package/dist/src/store.d.ts +638 -0
  128. package/dist/src/store.js +1618 -0
  129. package/dist/src/vec.d.ts +31 -0
  130. package/dist/src/vec.js +109 -0
  131. package/package.json +1 -1
@@ -0,0 +1,168 @@
1
+ import { type Value } from "./value.js";
2
+ /** Arity: a fixed operand count, or "variadic" for a fold (and/or of many,
3
+ * dot, min/max, polynomial evaluation). */
4
+ export type Arity = number | "variadic";
5
+ /** Synchronous resonance an op callback may consult, pre-resolved by the host.
6
+ * This is the only path by which a computation reads MEANING from a symbol's
7
+ * opaque bytes; numbers never touch it. */
8
+ export interface ResonanceSync {
9
+ /** The resonant opposite of a symbol's bytes — its antonym / inverse in the
10
+ * resonance space, of whatever modality — or null if none is known. Found
11
+ * by the host's halo resonance and handed in pre-resolved (see
12
+ * resonance.ts). */
13
+ opposite(bytes: Uint8Array): Uint8Array | null;
14
+ /** The canonical operation a symbol's bytes MEAN, found by resonance over the
15
+ * operation concepts — the GENERIC, modality-agnostic recognition path, the
16
+ * same one the host uses to recognise an operator a query does not literally
17
+ * spell. Pre-resolved by the host; null when nothing resonates. This is how
18
+ * the FUNCTION ARGUMENT of a higher-order nd op (the "+" of a reduce, the
19
+ * predicate of a filter) is resolved when it is not a literal surface form —
20
+ * see {@link OpContext.resolveOp}. */
21
+ recogniseOp(bytes: Uint8Array): string | null;
22
+ }
23
+ /** Runtime knobs the numerical kernel reads (the limit layer's tolerance and
24
+ * iteration ceiling). Carried on the context so a derived op never closes
25
+ * over global state. */
26
+ export interface OpRuntime {
27
+ /** Convergence tolerance ε: a refinement stops when successive results agree
28
+ * within this. */
29
+ tol: number;
30
+ /** Hard iteration ceiling, so a non-converging step still terminates. */
31
+ maxIter: number;
32
+ }
33
+ /** Evaluate a symbolic EXPRESSION at a binding of its free variable, returning a
34
+ * plain number, or null when the expression cannot be evaluated (unparseable,
35
+ * or no evaluator wired in). This is the bridge that lets a NUMERICAL op act
36
+ * on a function: an integral, a derivative, a limit (or any refinement) needs
37
+ * to sample its integrand/argument at many points, and the integrand is itself
38
+ * a sub-expression with a free variable — evaluating it is a RECURSIVE
39
+ * application of the same ALU. Injected by the host (the {@link
40
+ * "./alu.js".Alu} facade); absent in a bare registry, where expression-ops
41
+ * simply decline. */
42
+ export type EvalExpr = (bytes: Uint8Array, variable: string, at: number) => number | null;
43
+ /** The context a callback runs in: the means to call sibling ops by name, the
44
+ * runtime knobs, pre-resolved resonance, and (when wired) an expression
45
+ * evaluator. This is what makes derivations compose without import cycles
46
+ * between kernel files. */
47
+ export interface OpContext {
48
+ /** Apply another registered op by canonical name. */
49
+ apply(name: string, args: Value[]): Value;
50
+ /** Whether an op is registered (lets a derivation pick a fast path when an
51
+ * optional sibling exists). */
52
+ has(name: string): boolean;
53
+ /** Resolve an operation-denoting VALUE to a canonical op name — the
54
+ * intelligent callback resolution the higher-order nd ops (map/reduce/filter/
55
+ * find) use for their FUNCTION ARGUMENT. An operation is named the SAME way
56
+ * any operation is recognised anywhere in the kernel, reusing the existing
57
+ * machinery rather than a bespoke table:
58
+ *
59
+ * 1. a literal SURFACE FORM — the op-value's bytes are a registered spelling
60
+ * ("+", "plus", "add", "*", "max", …) → the registry's own form index;
61
+ * 2. else its MEANING — {@link ResonanceSync.recogniseOp} over the same
62
+ * operation concepts, so a synonym or a multimodal gesture the bytes do
63
+ * not literally spell still resolves (pre-resolved by the host);
64
+ * 3. else a bare canonical NAME already (a symbol whose bytes equal an op
65
+ * name), or an int/bit treated as its decimal name — last resort.
66
+ *
67
+ * `arity` (when given) disambiguates a surface a unary and a binary op share
68
+ * (e.g. "-" is both negate and subtract): the claimant of that arity wins.
69
+ * Returns null when nothing resolves, so a higher-order op declines. */
70
+ resolveOp(op: Value, arity?: number): string | null;
71
+ /** The numerical runtime knobs. */
72
+ rt: OpRuntime;
73
+ /** Pre-resolved resonance for the polymorphic inverse and op recognition. */
74
+ resonance: ResonanceSync;
75
+ /** Evaluate a symbolic expression at a variable binding (see {@link
76
+ * EvalExpr}); undefined in a bare registry with no host evaluator. */
77
+ evalExpr?: EvalExpr;
78
+ }
79
+ /** The callback that executes an operation on resolved operands. */
80
+ export type OpFn = (args: Value[], ctx: OpContext) => Value;
81
+ /** How tightly an INFIX operation binds, and to which side — declared at
82
+ * registration, next to the op it describes, so the expression grammar is
83
+ * read off the registry rather than hardcoded in any parser. Higher
84
+ * `precedence` binds tighter. */
85
+ export interface InfixSyntax {
86
+ precedence: number;
87
+ rightAssoc?: boolean;
88
+ }
89
+ /** Optional syntactic/structure traits of an operation, declared where the op
90
+ * is registered. Every parser-facing distinction the ALU makes is one of
91
+ * these traits — there is no side table of names anywhere. */
92
+ export interface OpTraits {
93
+ /** Consumes an n-dimensional value WHOLE (exempt from broadcast). */
94
+ structural?: boolean;
95
+ /** Usable as an infix operator, with the given binding. */
96
+ infix?: InfixSyntax;
97
+ /** The FIRST operand is an EXPRESSION (a function's bytes) rather than a
98
+ * value; the remaining `arity − 1` operands are its points/bounds. The
99
+ * numerical layer's diff/integrate/solve/limit/optimize declare this. */
100
+ expression?: boolean;
101
+ }
102
+ /** An operation — primitive or derived, indistinguishable by type. */
103
+ export interface Operation extends OpTraits {
104
+ /** Canonical id, e.g. "add", "nand", "converge", "sin". */
105
+ name: string;
106
+ /** Operand count (fixed) or "variadic". */
107
+ arity: Arity;
108
+ /** True only for the kernel's irreducible roots. */
109
+ primitive: boolean;
110
+ /** Surface forms this op answers to — the spellings resonance maps to it,
111
+ * e.g. add ← ["+", "plus", "sum", "add"]. May be empty for an internal op
112
+ * that has no user-facing surface. */
113
+ forms: string[];
114
+ /** The callback. */
115
+ fn: OpFn;
116
+ }
117
+ /** A resonance that knows nothing — the default when no host is wired in, so
118
+ * the pure kernel and its tests run with zero coupling. Op recognition then
119
+ * falls back to literal surface forms / canonical names only. */
120
+ export declare const NO_RESONANCE: ResonanceSync;
121
+ /** The collection of operations, indexed by canonical name and by surface form.
122
+ * Building a kernel is a sequence of {@link prim}/{@link derive} calls; the
123
+ * registry then resolves names at apply time, so registration order need only
124
+ * respect the dependency DAG loosely (a derived op may reference an op
125
+ * registered later, since resolution is lazy). */
126
+ export declare class OperationRegistry {
127
+ private readonly ops;
128
+ /** Surface form → the canonical names that claim it. A form may be shared
129
+ * (e.g. "-" is both subtract and negate); the caller disambiguates by arity
130
+ * and position, so the index keeps every claimant. */
131
+ private readonly formIndex;
132
+ /** Register an operation record directly. */
133
+ register(op: Operation): void;
134
+ /** Register a PRIMITIVE op (hand-written callback), with optional {@link
135
+ * OpTraits} — structural (consumes an nd whole, exempt from broadcast),
136
+ * infix binding, expression-operand — declared here, next to the op. */
137
+ prim(name: string, arity: Arity, forms: string[], fn: OpFn, traits?: OpTraits): void;
138
+ /** Register a DERIVED op (callback composes other ops via ctx). `traits`
139
+ * as in {@link prim}. */
140
+ derive(name: string, arity: Arity, forms: string[], fn: OpFn, traits?: OpTraits): void;
141
+ /** The op with this canonical name, or undefined. */
142
+ get(name: string): Operation | undefined;
143
+ has(name: string): boolean;
144
+ /** The canonical names a surface form maps to (empty if none). Several ops
145
+ * can share one surface (unary vs binary "-"), so this returns all. */
146
+ lookupForm(form: string): readonly string[];
147
+ /** Every (surface form → canonical name) pair — the host enumerates these to
148
+ * seed its operator recogniser. */
149
+ formEntries(): Iterable<{
150
+ form: string;
151
+ name: string;
152
+ }>;
153
+ /** Every registered canonical name. */
154
+ names(): Iterable<string>;
155
+ /** Build a context bound to a resonance and runtime — the object derived
156
+ * callbacks call back into. `apply` validates arity-vs-presence and surfaces
157
+ * a clear error rather than letting an undefined op silently produce NaN.
158
+ * An optional expression evaluator lets the numerical layer act on functions
159
+ * (see {@link EvalExpr}). */
160
+ context(resonance: ResonanceSync, rt: OpRuntime, evalExpr?: EvalExpr): OpContext;
161
+ /** Resolve an operation-denoting value to a canonical op name — the shared
162
+ * machinery behind {@link OpContext.resolveOp}. Tries, in order: a literal
163
+ * surface form (the registry's own index, arity-disambiguated), the meaning
164
+ * via `resonance.recogniseOp`, then a bare canonical name / decimal reading.
165
+ * Returns null when nothing resolves. Static-shaped (takes the resonance
166
+ * explicitly) so both the context closure and callers can use it. */
167
+ resolveOp(op: Value, resonance: ResonanceSync, arity?: number): string | null;
168
+ }
@@ -0,0 +1,189 @@
1
+ // operation.ts — the Operation record and the registry it lives in.
2
+ //
3
+ // An Operation is the irreducible unit of the ALU. A PRIMITIVE op has a
4
+ // hand-written callback (the kernel's irreducible roots: nand, the real
5
+ // arithmetic primitives, converge); a DERIVED op's callback only calls OTHER ops
6
+ // by canonical name through the {@link OpContext}. The two are the SAME type —
7
+ // a caller cannot tell a primitive from a derivation — which is the whole point:
8
+ // "subtract = add ∘ negate" is registered exactly like a primitive and competes
9
+ // in the search exactly like one. Because a derived callback's body is a
10
+ // sequence of `ctx.apply("…", …)` calls, the derivation DAG is literal,
11
+ // inspectable source: you can read off, from nand, how every gate is built, and
12
+ // from add/multiply/converge how every number-theoretic and numerical op is.
13
+ //
14
+ // The module is pure. The one window onto meaning a callback may need — the
15
+ // resonant opposite of a symbol, for the polymorphic inverse — arrives through
16
+ // {@link ResonanceSync}, which the host pre-resolves (SEMA's async resonance is
17
+ // hoisted out of the synchronous search, exactly as concept hops and connectors
18
+ // are). ALU never queries resonance itself.
19
+ import { isNd, nd } from "./value.js";
20
+ /** A resonance that knows nothing — the default when no host is wired in, so
21
+ * the pure kernel and its tests run with zero coupling. Op recognition then
22
+ * falls back to literal surface forms / canonical names only. */
23
+ export const NO_RESONANCE = {
24
+ opposite: () => null,
25
+ recogniseOp: () => null,
26
+ };
27
+ /** The collection of operations, indexed by canonical name and by surface form.
28
+ * Building a kernel is a sequence of {@link prim}/{@link derive} calls; the
29
+ * registry then resolves names at apply time, so registration order need only
30
+ * respect the dependency DAG loosely (a derived op may reference an op
31
+ * registered later, since resolution is lazy). */
32
+ export class OperationRegistry {
33
+ ops = new Map();
34
+ /** Surface form → the canonical names that claim it. A form may be shared
35
+ * (e.g. "-" is both subtract and negate); the caller disambiguates by arity
36
+ * and position, so the index keeps every claimant. */
37
+ formIndex = new Map();
38
+ /** Register an operation record directly. */
39
+ register(op) {
40
+ this.ops.set(op.name, op);
41
+ for (const f of op.forms) {
42
+ const a = this.formIndex.get(f);
43
+ if (a) {
44
+ if (!a.includes(op.name))
45
+ a.push(op.name);
46
+ }
47
+ else
48
+ this.formIndex.set(f, [op.name]);
49
+ }
50
+ }
51
+ /** Register a PRIMITIVE op (hand-written callback), with optional {@link
52
+ * OpTraits} — structural (consumes an nd whole, exempt from broadcast),
53
+ * infix binding, expression-operand — declared here, next to the op. */
54
+ prim(name, arity, forms, fn, traits = {}) {
55
+ this.register({ name, arity, primitive: true, forms, fn, ...traits });
56
+ }
57
+ /** Register a DERIVED op (callback composes other ops via ctx). `traits`
58
+ * as in {@link prim}. */
59
+ derive(name, arity, forms, fn, traits = {}) {
60
+ this.register({ name, arity, primitive: false, forms, fn, ...traits });
61
+ }
62
+ /** The op with this canonical name, or undefined. */
63
+ get(name) {
64
+ return this.ops.get(name);
65
+ }
66
+ has(name) {
67
+ return this.ops.has(name);
68
+ }
69
+ /** The canonical names a surface form maps to (empty if none). Several ops
70
+ * can share one surface (unary vs binary "-"), so this returns all. */
71
+ lookupForm(form) {
72
+ return this.formIndex.get(form) ?? [];
73
+ }
74
+ /** Every (surface form → canonical name) pair — the host enumerates these to
75
+ * seed its operator recogniser. */
76
+ *formEntries() {
77
+ for (const [form, names] of this.formIndex) {
78
+ for (const name of names)
79
+ yield { form, name };
80
+ }
81
+ }
82
+ /** Every registered canonical name. */
83
+ names() {
84
+ return this.ops.keys();
85
+ }
86
+ /** Build a context bound to a resonance and runtime — the object derived
87
+ * callbacks call back into. `apply` validates arity-vs-presence and surfaces
88
+ * a clear error rather than letting an undefined op silently produce NaN.
89
+ * An optional expression evaluator lets the numerical layer act on functions
90
+ * (see {@link EvalExpr}). */
91
+ context(resonance, rt, evalExpr) {
92
+ const self = this;
93
+ const ctx = {
94
+ rt,
95
+ resonance,
96
+ evalExpr,
97
+ has: (name) => self.ops.has(name),
98
+ resolveOp: (op, arity) => self.resolveOp(op, resonance, arity),
99
+ apply(name, args) {
100
+ const op = self.ops.get(name);
101
+ if (!op)
102
+ throw new Error(`ALU: unknown operation "${name}"`);
103
+ // ── ELEMENT-WISE BROADCAST ────────────────────────────────────────
104
+ // A SCALAR op (non-structural) applied to an n-dimensional argument
105
+ // lifts over it: the op runs on each element and the results re-pack
106
+ // into an nd of the same shape. This is the ONE place "every operation
107
+ // supports nd" is implemented — add, sin, nand, the polymorphic inverse
108
+ // all broadcast for free, and because each element re-enters `apply`,
109
+ // NESTING recurses (an nd of nd lifts twice) with no extra code.
110
+ //
111
+ // • several nd args ZIP position-wise (their top-level lengths must
112
+ // agree); a scalar arg is held constant against the list — so
113
+ // add([1,2,3],[4,5,6]) = [5,7,9] and add([1,2,3], 10) = [11,12,13].
114
+ // • a structural op is exempt: it wants the whole list (a reduce
115
+ // cannot be lifted across the very elements it folds).
116
+ if (!op.structural && args.some(isNd)) {
117
+ let len = -1;
118
+ for (const a of args) {
119
+ if (!isNd(a))
120
+ continue;
121
+ if (len === -1)
122
+ len = a.items.length;
123
+ else if (a.items.length !== len) {
124
+ throw new Error(`ALU: cannot broadcast "${name}" over lists of unequal length ` +
125
+ `(${len} vs ${a.items.length})`);
126
+ }
127
+ }
128
+ const out = [];
129
+ for (let i = 0; i < len; i++) {
130
+ out.push(ctx.apply(name, args.map((a) => isNd(a) ? a.items[i] : a)));
131
+ }
132
+ return nd(out);
133
+ }
134
+ if (op.arity !== "variadic" && args.length !== op.arity) {
135
+ throw new Error(`ALU: "${name}" expects ${op.arity} operand(s), got ${args.length}`);
136
+ }
137
+ return op.fn(args, ctx);
138
+ },
139
+ };
140
+ return ctx;
141
+ }
142
+ /** Resolve an operation-denoting value to a canonical op name — the shared
143
+ * machinery behind {@link OpContext.resolveOp}. Tries, in order: a literal
144
+ * surface form (the registry's own index, arity-disambiguated), the meaning
145
+ * via `resonance.recogniseOp`, then a bare canonical name / decimal reading.
146
+ * Returns null when nothing resolves. Static-shaped (takes the resonance
147
+ * explicitly) so both the context closure and callers can use it. */
148
+ resolveOp(op, resonance, arity) {
149
+ // The op-value's surface text, if it has a byte reading.
150
+ let text = null;
151
+ if (op.domain === "symbol") {
152
+ let s = "";
153
+ for (let i = 0; i < op.bytes.length; i++) {
154
+ s += String.fromCharCode(op.bytes[i]);
155
+ }
156
+ text = s.trim();
157
+ }
158
+ else if (op.domain === "int")
159
+ text = op.n.toString();
160
+ else if (op.domain === "bit")
161
+ text = String(op.b);
162
+ if (text === null || text.length === 0)
163
+ return null;
164
+ // (1) a literal SURFACE FORM, arity-disambiguated when asked.
165
+ const claimants = this.formIndex.get(text);
166
+ if (claimants && claimants.length > 0) {
167
+ if (arity !== undefined) {
168
+ for (const n of claimants) {
169
+ const o = this.ops.get(n);
170
+ const a = o && (o.arity === "variadic" ? 2 : o.arity);
171
+ if (a === arity)
172
+ return n;
173
+ }
174
+ }
175
+ return claimants[0];
176
+ }
177
+ // (2) the MEANING, via pre-resolved resonance (synonym / multimodal gesture
178
+ // the bytes do not literally spell) — only a symbol carries meaning.
179
+ if (op.domain === "symbol") {
180
+ const byMeaning = resonance.recogniseOp(op.bytes);
181
+ if (byMeaning && this.ops.has(byMeaning))
182
+ return byMeaning;
183
+ }
184
+ // (3) a bare canonical NAME already registered.
185
+ if (this.ops.has(text))
186
+ return text;
187
+ return null;
188
+ }
189
+ }
@@ -0,0 +1,212 @@
1
+ import type { Alu } from "./alu.js";
2
+ import { type ConceptAnchor } from "./resonance.js";
3
+ /** A half-open byte range. */
4
+ export interface Span {
5
+ i: number;
6
+ j: number;
7
+ }
8
+ /** A computation the parser recognised and evaluated: the query span [i, j) it
9
+ * is authoritative for, and the canonical result bytes. */
10
+ export interface ComputedSpan extends Span {
11
+ bytes: Uint8Array;
12
+ }
13
+ /** The port through which the parser reaches its host. This interface is the
14
+ * ENTIRE coupling surface between the ALU and any host: the ALU imports
15
+ * nothing from a mind or store, and every member is a GENERIC capability the
16
+ * host already has — nothing here mentions operations, vocabularies, or any
17
+ * ALU notion, so the host holds no ALU-specific logic either.
18
+ *
19
+ * MEANING (resonance):
20
+ * • meaningOf — which of the given labelled forms does a span MEAN? The ALU
21
+ * supplies the anchors (its own concept vocabulary); the host only answers
22
+ * nearness in its meaning space, above its own threshold, or null. This
23
+ * is what recognises an operation the bytes do not literally spell — an
24
+ * "∫" drawn, a "plus" spoken — in any modality.
25
+ * • continuation — the grounded form the host's corpus continues a form to
26
+ * (the same grounding its recall uses), or null. The ALU is the one that
27
+ * READS this as the resonant opposite: it asks for the continuation of an
28
+ * operand under an inverse, and a corpus that learnt "opposite of large →
29
+ * small" grounds exactly that. The host stays neutral — it only ever
30
+ * answers "where does this form lead?".
31
+ *
32
+ * GEOMETRY (perception):
33
+ * • segment — coherent runs by the host's own geometric perception. The
34
+ * parser uses this to ask "is this gap pure separator?" (one segment or
35
+ * none) — never a character class of its own.
36
+ * • reach — how far (in bytes) an operator may look for its operand: the
37
+ * host's own grouping capacity, so adjacency is judged by the same
38
+ * geometry that groups the host's perception. */
39
+ export interface AluHost {
40
+ meaningOf(bytes: Uint8Array, anchors: ReadonlyArray<ConceptAnchor>): Promise<string | null>;
41
+ continuation(bytes: Uint8Array): Promise<Uint8Array | null>;
42
+ segment(bytes: Uint8Array): Span[];
43
+ reach: number;
44
+ }
45
+ /** A host that knows nothing beyond structure: no resonance, whitespace-run
46
+ * segmentation, unbounded reach. This is what "the ALU runs fully decoupled"
47
+ * means — the parser still reads literal notation, and only the meaning-based
48
+ * paths stay silent. */
49
+ export declare const STRUCTURAL_HOST: AluHost;
50
+ export declare class QueryParser {
51
+ private readonly alu;
52
+ private readonly host;
53
+ /** The host's generic capabilities, specialised once into the {@link
54
+ * AluResonance} the prefetch bridges consume — the ONE place the ALU gives
55
+ * the host's neutral answers their computational reading: op recognition is
56
+ * meaningOf over the ALU's own concept anchors, and the polymorphic INVERSE
57
+ * of a symbol is the corpus's grounded continuation of it (a learnt
58
+ * opposition relation leads from a form to its opposite; the host never
59
+ * needs to know that is what it grounded). */
60
+ private readonly resonance;
61
+ /** Session memo of a term's meaning-based op reading, keyed by its bytes.
62
+ * `meaningOf` is a full river fold of the span — measured at ~a third of
63
+ * a plain-English respond's latency, paid per WORD per query — and it is
64
+ * a pure function of the bytes (perception is pure; the concept anchors
65
+ * are fixed for the Alu's lifetime), so the reading never changes.
66
+ * Bounded: cleared wholesale when full (words recur; a rare clear only
67
+ * re-pays folds, never changes a reading). */
68
+ private readonly meaningMemo;
69
+ private static readonly MEANING_MEMO_MAX;
70
+ constructor(alu: Alu, host?: AluHost);
71
+ /** Recognise and evaluate every computation `query` invokes. All async
72
+ * resonance is resolved in here, so the caller receives finished spans it
73
+ * can fold synchronously into its search. Results are deduplicated; a span
74
+ * that fails to compute is simply absent (the "rule does not fire"
75
+ * contract).
76
+ *
77
+ * The pipeline is one composition ladder, iterated to a FIXPOINT:
78
+ *
79
+ * 1. infix arithmetic RUNS are found and evaluated through the
80
+ * registry-derived grammar;
81
+ * 2. every computed span — a run, or a fired operation — is COLLAPSED
82
+ * into a single virtual operand, so the next round consumes it as one
83
+ * finished value: "sum 1*3 4" is add(3, 4), and "sqrt sum 9 16" is
84
+ * sqrt(25) — nesting by iteration, exactly as the grammar nests
85
+ * expressions, with no recursion machinery of its own;
86
+ * 3. rounds repeat while operations still fire (each round consumes at
87
+ * least one term, so the ladder is bounded by the term count).
88
+ *
89
+ * One AUTHORITY law then reconciles the readings: a span strictly
90
+ * contained in a larger computed span is that computation's MATERIAL (the
91
+ * "2-4" inside a solve's "x^2-4", the inner sum under a sqrt), not a rival
92
+ * result — the same rule by which the host's search lets a computed span
93
+ * override colliding learned facts. */
94
+ parse(query: Uint8Array): Promise<ComputedSpan[]>;
95
+ /** Apply an ALU operation to operand byte spans, with the host's resonance
96
+ * wired in — the entry point for computation over n-dimensional values.
97
+ *
98
+ * Unlike the in-query arithmetic rule (which hands the facade scalar operand
99
+ * bytes), this recognises each operand's STRUCTURE into a Value first and
100
+ * runs the kernel on the finished Values, with the full resonance snapshot
101
+ * pre-resolved — because an nd computation needs meaning in two places the
102
+ * bare facade cannot reach on its own:
103
+ *
104
+ * • the polymorphic INVERSE inside a broadcast — `inverse [large, 3, tall]`
105
+ * lifts element-wise (operation.ts), and each symbol element's opposite
106
+ * is a resonant lookup, grounded in the host's corpus exactly as a scalar
107
+ * inverse is;
108
+ * • the FUNCTION ARGUMENT of a higher-order op — `reduce(xs, ‹+›)`,
109
+ * `map(xs, ‹negate›)`: the operator value is resolved by
110
+ * {@link "./operation.js".OpContext.resolveOp}, which falls through to
111
+ * resonance when the bytes are not a literal surface form.
112
+ *
113
+ * Both are async, so every SYMBOL span reachable in the operands (recursing
114
+ * through nd nesting, see {@link "./value.js".symbolSpans}) is resolved ONCE
115
+ * up front into a synchronous snapshot, and the synchronous kernel computes
116
+ * against it. Returns null when the op is unknown or the computation
117
+ * declines — the "this rule does not fire" contract.
118
+ *
119
+ * `asSymbol(idx)` keeps an operand opaque (not read as structure or a
120
+ * number) — the numerical-layer convention where operand 0 is an
121
+ * expression's bytes; it defaults to "recognise everything", which is what
122
+ * an nd computation wants. */
123
+ compute(name: string, operandBytes: Uint8Array[], asSymbol?: (idx: number) => boolean): Promise<Uint8Array | null>;
124
+ /** Lex the query ONCE into a single ascending token stream: the facade's
125
+ * scanner claims numeric OPERANDS and symbolic OPERATORS, and every maximal
126
+ * unclaimed run between spacing bytes is a TERM — a word, glyph, or opaque
127
+ * fragment that may name an operation. Terms are deliberately bounded by
128
+ * the spacing floor, not the host's geometric segmentation: perception may
129
+ * cut mid-word (its segments are grouping capacity, not word boundaries),
130
+ * while an operation NAME is a notation-level token. Geometry still
131
+ * governs what happens BETWEEN tokens (gap bridging, operand reach).
132
+ *
133
+ * Tokens are disjoint, ascending, and cover every non-spacing byte — so
134
+ * the gap between consecutive tokens is pure spacing BY CONSTRUCTION, a
135
+ * structural fact the run recogniser leans on. */
136
+ private lex;
137
+ /** The maximal infix-arithmetic runs in the query: an alternation of numeric
138
+ * operands and SYMBOLIC operators (e.g. "2+3*4"), returned as [start, end)
139
+ * ranges that begin and end on an operand.
140
+ *
141
+ * Consecutive tokens may be SEPARATED — "3 + 3" is the same run as "3+3".
142
+ * The gap between two tokens is a bridgeable separator exactly when the
143
+ * host's geometric segmenter reads it as at most one coherent run — the
144
+ * same judgement the perception tree makes about spacing — so no character
145
+ * is privileged as "the" separator. */
146
+ private arithmeticRuns;
147
+ /** Evaluate an infix-arithmetic run to its canonical result bytes, through
148
+ * the kernel's recursive expression evaluator, or null if it does not
149
+ * evaluate. A whole result stays an exact int; otherwise the canonical
150
+ * rounded real — deterministic, so the search's chart memoises identical
151
+ * results identically. */
152
+ private evalRun;
153
+ /** Recognise and apply the operations the query's TERMS name — the generic,
154
+ * multimodal path. A term may name an operation literally (its bytes are a
155
+ * registered surface form — no resonance cost) or by RESONANCE (its gist
156
+ * lands on an operation's concept, any modality).
157
+ *
158
+ * Recognition PROPOSES, application DISPOSES: a surface form may be shared
159
+ * by several operations ("zero" is both the constant and solve's
160
+ * root-finding), so every literal claimant is kept, in registration order,
161
+ * and the first whose application actually fires wins — disambiguation by
162
+ * what the query supplies, not by a precedence table. Recognition runs
163
+ * CONCURRENTLY — each term's reading is independent — and is memoised in
164
+ * `readings` across fixpoint rounds (a surviving term is the same token
165
+ * object), so each term resonates at most once per parse. Application is
166
+ * then ordered and deterministic: an EXPRESSION op takes the function that
167
+ * follows it ({@link applyToExpression}), any other op takes its arity's
168
+ * worth of operands from the stream ({@link applyToStream}). Both read
169
+ * the same composed stream — an expression's TEXT comes from the raw query
170
+ * bytes by position, so composition never disturbs it, while a composed
171
+ * operand serves as a finished point/bound or argument. */
172
+ private operations;
173
+ /** Apply a NUMERICAL-LAYER op — one whose first operand is an EXPRESSION (a
174
+ * function), declared by the op's own `expression` trait. The registry's
175
+ * arity says how many trailing numeric operands are its points/bounds
176
+ * (arity − 1); the bytes between the operator and those points — with
177
+ * non-math filler stripped by {@link cleanExprText} — are the expression,
178
+ * evaluated by a recursive application of the kernel. */
179
+ private applyToExpression;
180
+ /** Apply any other op to the OPERAND STREAM after the operator: the numeric
181
+ * operands and symbol terms that follow it, merged nearest-first, each
182
+ * within the host's reach of the token before it — so "sqrt 144",
183
+ * "gcd 12 18", and "opposite large" are one rule, and the NEAREST token is
184
+ * the operand ("opposite large 5" inverts "large", not the 5).
185
+ *
186
+ * Two structural refinements make this read like notation rather than a
187
+ * special case:
188
+ *
189
+ * • WORD-INFIX — an under-supplied operator borrows the numeric operand
190
+ * immediately BEFORE it (within reach), so "7 minus 2" applies
191
+ * subtract(7, 2) exactly as "7 - 2" would: a synonym is notation too.
192
+ * • GROUNDED-ONLY SYMBOLS — when every operand is a symbol, a result that
193
+ * merely echoes an operand means resonance grounded nothing (an inverse
194
+ * with no learnt opposition), and the rule stays silent rather than
195
+ * invent meaning. Numeric identities ("max 3 7" → "7") are real
196
+ * results and pass.
197
+ *
198
+ * A NULLARY op never fires from a bare term: a computation must consume
199
+ * something, or any prose word that happens to name a constant would be
200
+ * rewritten. Symbol operands get their resonance (the opposite each may
201
+ * need) pre-resolved in one prefetch. */
202
+ private applyToStream;
203
+ /** Strip non-math filler tokens from a raw expression string — keep numbers,
204
+ * operators, parens, names the GRAMMAR resolves (unary functions,
205
+ * registered constants), and single-RUNE identifiers. The rune rule is the
206
+ * mirror of {@link "./alu.js".Alu.conceptAnchors}' compound rule: a compound
207
+ * name carries distributional meaning (it is either a resolvable operation
208
+ * or filler — "of", "at", "the"), while a bare atom carries none and can
209
+ * only be the expression's free variable. Dropping the filler leaves the
210
+ * evaluator clean notation. */
211
+ private cleanExprText;
212
+ }