@hviana/sema 0.1.7 → 0.1.9

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 (145) hide show
  1. package/example/train_base.ts +29 -4
  2. package/package.json +1 -1
  3. package/src/alu/src/parser.ts +105 -4
  4. package/src/canon.ts +65 -0
  5. package/src/geometry.ts +26 -30
  6. package/src/index.ts +1 -0
  7. package/src/mind/learning.ts +39 -1
  8. package/src/mind/match.ts +29 -6
  9. package/src/mind/mechanisms/cast.ts +33 -13
  10. package/src/mind/mechanisms/confluence.ts +15 -1
  11. package/src/mind/mechanisms/recall.ts +116 -41
  12. package/src/mind/mind.ts +172 -29
  13. package/src/mind/primitives.ts +66 -1
  14. package/src/mind/recognition.ts +10 -0
  15. package/src/mind/types.ts +10 -0
  16. package/src/store-sqlite.ts +68 -0
  17. package/src/store.ts +27 -0
  18. package/test/13-conversation.test.mjs +77 -27
  19. package/test/35-prefix-edge.test.mjs +86 -0
  20. package/dist/example/demo.d.ts +0 -1
  21. package/dist/example/demo.js +0 -39
  22. package/dist/example/train_base.d.ts +0 -87
  23. package/dist/example/train_base.js +0 -2232
  24. package/dist/src/alphabet.d.ts +0 -7
  25. package/dist/src/alphabet.js +0 -33
  26. package/dist/src/alu/src/alu.d.ts +0 -185
  27. package/dist/src/alu/src/alu.js +0 -440
  28. package/dist/src/alu/src/expr.d.ts +0 -61
  29. package/dist/src/alu/src/expr.js +0 -318
  30. package/dist/src/alu/src/index.d.ts +0 -11
  31. package/dist/src/alu/src/index.js +0 -19
  32. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  33. package/dist/src/alu/src/kernel-arith.js +0 -264
  34. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  35. package/dist/src/alu/src/kernel-bits.js +0 -152
  36. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  37. package/dist/src/alu/src/kernel-logic.js +0 -60
  38. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  39. package/dist/src/alu/src/kernel-nd.js +0 -208
  40. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  41. package/dist/src/alu/src/kernel-numeric.js +0 -366
  42. package/dist/src/alu/src/operation.d.ts +0 -168
  43. package/dist/src/alu/src/operation.js +0 -189
  44. package/dist/src/alu/src/parser.d.ts +0 -212
  45. package/dist/src/alu/src/parser.js +0 -469
  46. package/dist/src/alu/src/resonance.d.ts +0 -55
  47. package/dist/src/alu/src/resonance.js +0 -126
  48. package/dist/src/alu/src/text.d.ts +0 -31
  49. package/dist/src/alu/src/text.js +0 -73
  50. package/dist/src/alu/src/value.d.ts +0 -109
  51. package/dist/src/alu/src/value.js +0 -300
  52. package/dist/src/alu/test/alu.test.d.ts +0 -1
  53. package/dist/src/alu/test/alu.test.js +0 -764
  54. package/dist/src/bytes.d.ts +0 -14
  55. package/dist/src/bytes.js +0 -59
  56. package/dist/src/config.d.ts +0 -111
  57. package/dist/src/config.js +0 -91
  58. package/dist/src/derive/src/deduction.d.ts +0 -125
  59. package/dist/src/derive/src/deduction.js +0 -155
  60. package/dist/src/derive/src/index.d.ts +0 -7
  61. package/dist/src/derive/src/index.js +0 -11
  62. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  63. package/dist/src/derive/src/priority-queue.js +0 -73
  64. package/dist/src/derive/src/rewrite.d.ts +0 -56
  65. package/dist/src/derive/src/rewrite.js +0 -100
  66. package/dist/src/derive/src/trie.d.ts +0 -90
  67. package/dist/src/derive/src/trie.js +0 -217
  68. package/dist/src/derive/test/derive.test.d.ts +0 -1
  69. package/dist/src/derive/test/derive.test.js +0 -122
  70. package/dist/src/extension.d.ts +0 -37
  71. package/dist/src/extension.js +0 -7
  72. package/dist/src/geometry.d.ts +0 -148
  73. package/dist/src/geometry.js +0 -517
  74. package/dist/src/index.d.ts +0 -15
  75. package/dist/src/index.js +0 -17
  76. package/dist/src/ingest-cache.d.ts +0 -41
  77. package/dist/src/ingest-cache.js +0 -161
  78. package/dist/src/mind/articulation.d.ts +0 -6
  79. package/dist/src/mind/articulation.js +0 -99
  80. package/dist/src/mind/attention.d.ts +0 -72
  81. package/dist/src/mind/attention.js +0 -898
  82. package/dist/src/mind/canonical.d.ts +0 -29
  83. package/dist/src/mind/canonical.js +0 -88
  84. package/dist/src/mind/graph-search.d.ts +0 -270
  85. package/dist/src/mind/graph-search.js +0 -847
  86. package/dist/src/mind/index.d.ts +0 -5
  87. package/dist/src/mind/index.js +0 -5
  88. package/dist/src/mind/junction.d.ts +0 -95
  89. package/dist/src/mind/junction.js +0 -262
  90. package/dist/src/mind/learning.d.ts +0 -47
  91. package/dist/src/mind/learning.js +0 -201
  92. package/dist/src/mind/match.d.ts +0 -111
  93. package/dist/src/mind/match.js +0 -422
  94. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  95. package/dist/src/mind/mechanisms/alu.js +0 -29
  96. package/dist/src/mind/mechanisms/cast.d.ts +0 -35
  97. package/dist/src/mind/mechanisms/cast.js +0 -447
  98. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  99. package/dist/src/mind/mechanisms/confluence.js +0 -213
  100. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  101. package/dist/src/mind/mechanisms/cover.js +0 -179
  102. package/dist/src/mind/mechanisms/extraction.d.ts +0 -67
  103. package/dist/src/mind/mechanisms/extraction.js +0 -342
  104. package/dist/src/mind/mechanisms/recall.d.ts +0 -13
  105. package/dist/src/mind/mechanisms/recall.js +0 -166
  106. package/dist/src/mind/mind.d.ts +0 -211
  107. package/dist/src/mind/mind.js +0 -433
  108. package/dist/src/mind/pipeline-mechanism.d.ts +0 -142
  109. package/dist/src/mind/pipeline-mechanism.js +0 -213
  110. package/dist/src/mind/pipeline.d.ts +0 -20
  111. package/dist/src/mind/pipeline.js +0 -185
  112. package/dist/src/mind/primitives.d.ts +0 -54
  113. package/dist/src/mind/primitives.js +0 -184
  114. package/dist/src/mind/rationale.d.ts +0 -134
  115. package/dist/src/mind/rationale.js +0 -162
  116. package/dist/src/mind/reasoning.d.ts +0 -15
  117. package/dist/src/mind/reasoning.js +0 -162
  118. package/dist/src/mind/recognition.d.ts +0 -20
  119. package/dist/src/mind/recognition.js +0 -236
  120. package/dist/src/mind/resonance.d.ts +0 -23
  121. package/dist/src/mind/resonance.js +0 -0
  122. package/dist/src/mind/trace.d.ts +0 -15
  123. package/dist/src/mind/trace.js +0 -73
  124. package/dist/src/mind/traverse.d.ts +0 -113
  125. package/dist/src/mind/traverse.js +0 -488
  126. package/dist/src/mind/types.d.ts +0 -176
  127. package/dist/src/mind/types.js +0 -84
  128. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  129. package/dist/src/rabitq-ivf/src/database.js +0 -201
  130. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  131. package/dist/src/rabitq-ivf/src/index.js +0 -4
  132. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  133. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  134. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  135. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  136. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  137. package/dist/src/rabitq-ivf/src/rabitq.js +0 -283
  138. package/dist/src/sema.d.ts +0 -31
  139. package/dist/src/sema.js +0 -63
  140. package/dist/src/store-sqlite.d.ts +0 -176
  141. package/dist/src/store-sqlite.js +0 -890
  142. package/dist/src/store.d.ts +0 -642
  143. package/dist/src/store.js +0 -1612
  144. package/dist/src/vec.d.ts +0 -31
  145. package/dist/src/vec.js +0 -109
@@ -1,469 +0,0 @@
1
- // parser.ts — the ALU's query parser: recognise and evaluate every computation
2
- // a raw byte query invokes.
3
- //
4
- // This is the intelligence layered over the Alu facade, and the ONLY module
5
- // that reaches outside the kernel — through one narrow port, {@link AluHost}.
6
- // The host (SEMA's Mind, or nothing) supplies exactly the two things bytes
7
- // alone cannot answer:
8
- //
9
- // • MEANING (resonance) — which operation an opaque span names, and what the
10
- // resonant opposite of a symbol is. Both are async (they hit the host's
11
- // gist/halo index) and both are pre-resolved here, before any synchronous
12
- // computation — the same hoisting discipline the host's search applies to
13
- // concept hops and connectors.
14
- // • GEOMETRY (segmentation) — where coherent runs begin and end. The parser
15
- // never decides for itself whether the bytes between two tokens are "just a
16
- // separator": it asks the host's geometric segmenter (the same one the
17
- // perception tree uses), so what counts as spacing is a property of the
18
- // learnt alphabet space, not a hardcoded character class. `reach` bounds
19
- // how far an operator may look for its operand — the host's own grouping
20
- // capacity, so "not … 4" across prose stays silent while "not 4" fires.
21
- //
22
- // Everything else — what a numeral is, which symbols are operators, how infix
23
- // binds, which ops act on expressions — is read off the operation registry via
24
- // the facade. The parser therefore has NO vocabulary of its own: extend the
25
- // registry and the parser understands the new notation; teach the host's
26
- // resonance space and it understands new spellings of the old one.
27
- //
28
- // The parser LEXES the query once into a single ascending TOKEN stream —
29
- // numeric OPERANDS and symbolic OPERATORS from the facade's scanner, and the
30
- // unclaimed runs between them as TERMS — and every recogniser reads that one
31
- // stream. Tokens are disjoint and cover every non-spacing byte, so the gap
32
- // between two consecutive tokens is pure spacing by construction. What it finds (independent of any
33
- // content-defined chunking, so a number a chunker would split is read whole):
34
- //
35
- // 1. INFIX ARITHMETIC RUNS — maximal alternations of numeric operands and
36
- // symbolic operators ("2+3*4", "3 + 3"), evaluated wholesale through the
37
- // registry-derived expression grammar, so chaining and precedence are a
38
- // recursive application of the same kernel.
39
- // 2. OPERATIONS NAMED BY MEANING — a term (word, glyph, image/audio fragment)
40
- // that names an operation literally or by resonance, applied to a
41
- // following operand ("opposite large" → "small"), or, for the numerical
42
- // layer, to a following EXPRESSION ("derivative of x^2 at 3").
43
- import { prefetchOpposites, prefetchResonance, } from "./resonance.js";
44
- import { NO_RESONANCE } from "./operation.js";
45
- import { int, real, symbol, symbolSpans } from "./value.js";
46
- import { nonSpaceRuns } from "./text.js";
47
- import { bytesEqual, latin1 } from "../../bytes.js";
48
- /** A host that knows nothing beyond structure: no resonance, whitespace-run
49
- * segmentation, unbounded reach. This is what "the ALU runs fully decoupled"
50
- * means — the parser still reads literal notation, and only the meaning-based
51
- * paths stay silent. */
52
- export const STRUCTURAL_HOST = {
53
- meaningOf: async () => null,
54
- continuation: async () => null,
55
- segment: (bytes) => nonSpaceRuns(bytes),
56
- reach: Number.POSITIVE_INFINITY,
57
- };
58
- export class QueryParser {
59
- alu;
60
- host;
61
- /** The host's generic capabilities, specialised once into the {@link
62
- * AluResonance} the prefetch bridges consume — the ONE place the ALU gives
63
- * the host's neutral answers their computational reading: op recognition is
64
- * meaningOf over the ALU's own concept anchors, and the polymorphic INVERSE
65
- * of a symbol is the corpus's grounded continuation of it (a learnt
66
- * opposition relation leads from a form to its opposite; the host never
67
- * needs to know that is what it grounded). */
68
- resonance;
69
- /** Session memo of a term's meaning-based op reading, keyed by its bytes.
70
- * `meaningOf` is a full river fold of the span — measured at ~a third of
71
- * a plain-English respond's latency, paid per WORD per query — and it is
72
- * a pure function of the bytes (perception is pure; the concept anchors
73
- * are fixed for the Alu's lifetime), so the reading never changes.
74
- * Bounded: cleared wholesale when full (words recur; a rare clear only
75
- * re-pays folds, never changes a reading). */
76
- meaningMemo = new Map();
77
- static MEANING_MEMO_MAX = 4096;
78
- constructor(alu, host = STRUCTURAL_HOST) {
79
- this.alu = alu;
80
- this.host = host;
81
- this.resonance = {
82
- recogniseOp: (bytes) => host.meaningOf(bytes, alu.conceptAnchors()),
83
- opposite: (bytes) => host.continuation(bytes),
84
- };
85
- }
86
- /** Recognise and evaluate every computation `query` invokes. All async
87
- * resonance is resolved in here, so the caller receives finished spans it
88
- * can fold synchronously into its search. Results are deduplicated; a span
89
- * that fails to compute is simply absent (the "rule does not fire"
90
- * contract).
91
- *
92
- * The pipeline is one composition ladder, iterated to a FIXPOINT:
93
- *
94
- * 1. infix arithmetic RUNS are found and evaluated through the
95
- * registry-derived grammar;
96
- * 2. every computed span — a run, or a fired operation — is COLLAPSED
97
- * into a single virtual operand, so the next round consumes it as one
98
- * finished value: "sum 1*3 4" is add(3, 4), and "sqrt sum 9 16" is
99
- * sqrt(25) — nesting by iteration, exactly as the grammar nests
100
- * expressions, with no recursion machinery of its own;
101
- * 3. rounds repeat while operations still fire (each round consumes at
102
- * least one term, so the ladder is bounded by the term count).
103
- *
104
- * One AUTHORITY law then reconciles the readings: a span strictly
105
- * contained in a larger computed span is that computation's MATERIAL (the
106
- * "2-4" inside a solve's "x^2-4", the inner sum under a sqrt), not a rival
107
- * result — the same rule by which the host's search lets a computed span
108
- * override colliding learned facts. */
109
- async parse(query) {
110
- const tokens = this.lex(query);
111
- const runs = this.arithmeticRuns(query, tokens).map(([i, j]) => ({
112
- i,
113
- j,
114
- bytes: this.evalRun(query.subarray(i, j)),
115
- }));
116
- const spans = runs.filter((r) => r.bytes !== null);
117
- let stream = compose(tokens, runs);
118
- const readings = new Map();
119
- for (;;) {
120
- const fired = await this.operations(query, stream, readings);
121
- if (fired.length === 0)
122
- break;
123
- spans.push(...fired);
124
- stream = compose(stream, fired);
125
- }
126
- return authoritative(dedup(spans));
127
- }
128
- /** Apply an ALU operation to operand byte spans, with the host's resonance
129
- * wired in — the entry point for computation over n-dimensional values.
130
- *
131
- * Unlike the in-query arithmetic rule (which hands the facade scalar operand
132
- * bytes), this recognises each operand's STRUCTURE into a Value first and
133
- * runs the kernel on the finished Values, with the full resonance snapshot
134
- * pre-resolved — because an nd computation needs meaning in two places the
135
- * bare facade cannot reach on its own:
136
- *
137
- * • the polymorphic INVERSE inside a broadcast — `inverse [large, 3, tall]`
138
- * lifts element-wise (operation.ts), and each symbol element's opposite
139
- * is a resonant lookup, grounded in the host's corpus exactly as a scalar
140
- * inverse is;
141
- * • the FUNCTION ARGUMENT of a higher-order op — `reduce(xs, ‹+›)`,
142
- * `map(xs, ‹negate›)`: the operator value is resolved by
143
- * {@link "./operation.js".OpContext.resolveOp}, which falls through to
144
- * resonance when the bytes are not a literal surface form.
145
- *
146
- * Both are async, so every SYMBOL span reachable in the operands (recursing
147
- * through nd nesting, see {@link "./value.js".symbolSpans}) is resolved ONCE
148
- * up front into a synchronous snapshot, and the synchronous kernel computes
149
- * against it. Returns null when the op is unknown or the computation
150
- * declines — the "this rule does not fire" contract.
151
- *
152
- * `asSymbol(idx)` keeps an operand opaque (not read as structure or a
153
- * number) — the numerical-layer convention where operand 0 is an
154
- * expression's bytes; it defaults to "recognise everything", which is what
155
- * an nd computation wants. */
156
- async compute(name, operandBytes, asSymbol = () => false) {
157
- const operands = [];
158
- const spans = [];
159
- for (let i = 0; i < operandBytes.length; i++) {
160
- const v = asSymbol(i)
161
- ? symbol(operandBytes[i])
162
- : this.alu.recogniseValue(operandBytes[i]);
163
- operands.push(v);
164
- symbolSpans(v, spans);
165
- }
166
- const resonance = await prefetchResonance(this.resonance, spans);
167
- return this.alu.applyValues(name, operands, resonance);
168
- }
169
- // ── the lex: one reading of the query every recogniser shares ────────────
170
- /** Lex the query ONCE into a single ascending token stream: the facade's
171
- * scanner claims numeric OPERANDS and symbolic OPERATORS, and every maximal
172
- * unclaimed run between spacing bytes is a TERM — a word, glyph, or opaque
173
- * fragment that may name an operation. Terms are deliberately bounded by
174
- * the spacing floor, not the host's geometric segmentation: perception may
175
- * cut mid-word (its segments are grouping capacity, not word boundaries),
176
- * while an operation NAME is a notation-level token. Geometry still
177
- * governs what happens BETWEEN tokens (gap bridging, operand reach).
178
- *
179
- * Tokens are disjoint, ascending, and cover every non-spacing byte — so
180
- * the gap between consecutive tokens is pure spacing BY CONSTRUCTION, a
181
- * structural fact the run recogniser leans on. */
182
- lex(query) {
183
- const { operands, operators } = this.alu.scan(query);
184
- const claimed = [
185
- ...operands.map((o) => ({ i: o.i, j: o.j, kind: "operand" })),
186
- ...operators.map((o) => ({ i: o.i, j: o.j, kind: "operator" })),
187
- ].sort((a, b) => a.i - b.i);
188
- const tokens = [];
189
- let p = 0;
190
- for (const c of [...claimed, END]) {
191
- for (const t of nonSpaceRuns(query, p, Math.min(c.i, query.length))) {
192
- tokens.push({ ...t, kind: "term" });
193
- }
194
- if (c !== END)
195
- tokens.push(c);
196
- p = c.j;
197
- }
198
- return tokens;
199
- }
200
- // ── (1) infix arithmetic ──────────────────────────────────────────────────
201
- /** The maximal infix-arithmetic runs in the query: an alternation of numeric
202
- * operands and SYMBOLIC operators (e.g. "2+3*4"), returned as [start, end)
203
- * ranges that begin and end on an operand.
204
- *
205
- * Consecutive tokens may be SEPARATED — "3 + 3" is the same run as "3+3".
206
- * The gap between two tokens is a bridgeable separator exactly when the
207
- * host's geometric segmenter reads it as at most one coherent run — the
208
- * same judgement the perception tree makes about spacing — so no character
209
- * is privileged as "the" separator. */
210
- arithmeticRuns(query, tokens) {
211
- const bridged = (from, to) => from >= to || this.host.segment(query.subarray(from, to)).length <= 1;
212
- const runs = [];
213
- let k = 0;
214
- while (k < tokens.length) {
215
- if (tokens[k].kind !== "operand") {
216
- k++;
217
- continue;
218
- }
219
- let end = k;
220
- while (end + 1 < tokens.length &&
221
- tokens[end + 1].kind !== "term" && // a term breaks the notation
222
- tokens[end + 1].kind !== tokens[end].kind && // alternates
223
- bridged(tokens[end].j, tokens[end + 1].i) // pure-spacing gap coheres
224
- )
225
- end++;
226
- while (end > k && tokens[end].kind === "operator")
227
- end--; // end on operand
228
- if (end > k)
229
- runs.push([tokens[k].i, tokens[end].j]);
230
- k = end + 1;
231
- }
232
- return runs;
233
- }
234
- /** Evaluate an infix-arithmetic run to its canonical result bytes, through
235
- * the kernel's recursive expression evaluator, or null if it does not
236
- * evaluate. A whole result stays an exact int; otherwise the canonical
237
- * rounded real — deterministic, so the search's chart memoises identical
238
- * results identically. */
239
- evalRun(runBytes) {
240
- const x = this.alu.evalExpression(runBytes, "", 0);
241
- if (x === null || !Number.isFinite(x))
242
- return null;
243
- return this.alu.codec.encode(Number.isInteger(x) ? int(BigInt(x)) : real(x));
244
- }
245
- // ── (2) operations named by NAME or MEANING ───────────────────────────────
246
- /** Recognise and apply the operations the query's TERMS name — the generic,
247
- * multimodal path. A term may name an operation literally (its bytes are a
248
- * registered surface form — no resonance cost) or by RESONANCE (its gist
249
- * lands on an operation's concept, any modality).
250
- *
251
- * Recognition PROPOSES, application DISPOSES: a surface form may be shared
252
- * by several operations ("zero" is both the constant and solve's
253
- * root-finding), so every literal claimant is kept, in registration order,
254
- * and the first whose application actually fires wins — disambiguation by
255
- * what the query supplies, not by a precedence table. Recognition runs
256
- * CONCURRENTLY — each term's reading is independent — and is memoised in
257
- * `readings` across fixpoint rounds (a surviving term is the same token
258
- * object), so each term resonates at most once per parse. Application is
259
- * then ordered and deterministic: an EXPRESSION op takes the function that
260
- * follows it ({@link applyToExpression}), any other op takes its arity's
261
- * worth of operands from the stream ({@link applyToStream}). Both read
262
- * the same composed stream — an expression's TEXT comes from the raw query
263
- * bytes by position, so composition never disturbs it, while a composed
264
- * operand serves as a finished point/bound or argument. */
265
- async operations(query, tokens, readings) {
266
- const terms = tokens.filter((t) => t.kind === "term");
267
- const anchors = this.alu.conceptAnchors();
268
- await Promise.all(terms.map(async (term) => {
269
- if (readings.has(term))
270
- return;
271
- const span = query.subarray(term.i, term.j);
272
- const key = latin1(span);
273
- const literal = this.alu.lookupOperator(key);
274
- if (literal.length > 0) {
275
- readings.set(term, literal);
276
- return;
277
- }
278
- const hit = this.meaningMemo.get(key);
279
- if (hit !== undefined) {
280
- readings.set(term, hit);
281
- return;
282
- }
283
- const m = await this.host.meaningOf(span, anchors);
284
- const meant = m ? [m] : [];
285
- if (this.meaningMemo.size >= QueryParser.MEANING_MEMO_MAX) {
286
- this.meaningMemo.clear();
287
- }
288
- this.meaningMemo.set(key, meant);
289
- readings.set(term, meant);
290
- }));
291
- const out = [];
292
- for (const term of terms) {
293
- for (const name of readings.get(term)) {
294
- const result = this.alu.isExpressionOp(name)
295
- ? this.applyToExpression(query, name, term, tokens)
296
- : await this.applyToStream(query, name, term, tokens);
297
- if (result) {
298
- out.push(result);
299
- break; // the first claimant that fires owns the term
300
- }
301
- }
302
- }
303
- return out;
304
- }
305
- /** Apply a NUMERICAL-LAYER op — one whose first operand is an EXPRESSION (a
306
- * function), declared by the op's own `expression` trait. The registry's
307
- * arity says how many trailing numeric operands are its points/bounds
308
- * (arity − 1); the bytes between the operator and those points — with
309
- * non-math filler stripped by {@link cleanExprText} — are the expression,
310
- * evaluated by a recursive application of the kernel. */
311
- applyToExpression(query, name, term, tokens) {
312
- const operands = tokens.filter((t) => t.kind === "operand" && t.i >= term.j);
313
- const arity = this.alu.arityOf(name);
314
- const points = arity - 1;
315
- const exprEnd = operands.length > points
316
- ? operands[operands.length - points].i
317
- : operands[0]?.i ?? query.length;
318
- const cleaned = this.cleanExprText(latin1(query.subarray(term.j, exprEnd)));
319
- if (cleaned.length === 0)
320
- return null;
321
- const args = [UTF8.encode(cleaned)];
322
- for (const o of operands.slice(-points)) {
323
- args.push(o.value ?? query.subarray(o.i, o.j));
324
- }
325
- if (args.length !== arity)
326
- return null; // under-supplied → decline
327
- const bytes = this.alu.applyBytesTyped(name, args, (idx) => idx === 0);
328
- if (bytes === null)
329
- return null;
330
- return { i: term.i, j: operands[operands.length - 1].j, bytes };
331
- }
332
- /** Apply any other op to the OPERAND STREAM after the operator: the numeric
333
- * operands and symbol terms that follow it, merged nearest-first, each
334
- * within the host's reach of the token before it — so "sqrt 144",
335
- * "gcd 12 18", and "opposite large" are one rule, and the NEAREST token is
336
- * the operand ("opposite large 5" inverts "large", not the 5).
337
- *
338
- * Two structural refinements make this read like notation rather than a
339
- * special case:
340
- *
341
- * • WORD-INFIX — an under-supplied operator borrows the numeric operand
342
- * immediately BEFORE it (within reach), so "7 minus 2" applies
343
- * subtract(7, 2) exactly as "7 - 2" would: a synonym is notation too.
344
- * • GROUNDED-ONLY SYMBOLS — when every operand is a symbol, a result that
345
- * merely echoes an operand means resonance grounded nothing (an inverse
346
- * with no learnt opposition), and the rule stays silent rather than
347
- * invent meaning. Numeric identities ("max 3 7" → "7") are real
348
- * results and pass.
349
- *
350
- * A NULLARY op never fires from a bare term: a computation must consume
351
- * something, or any prose word that happens to name a constant would be
352
- * rewritten. Symbol operands get their resonance (the opposite each may
353
- * need) pre-resolved in one prefetch. */
354
- async applyToStream(query, name, term, tokens) {
355
- const arity = this.alu.arityOf(name);
356
- if (arity === 0)
357
- return null; // a constant consumes nothing → not a rule
358
- const picked = [];
359
- let from = term.j;
360
- for (const tok of tokens) {
361
- if (tok.i < term.j || tok.kind === "operator")
362
- continue;
363
- if (picked.length === arity)
364
- break;
365
- if (tok.i - from > this.host.reach)
366
- break; // next token too far
367
- picked.push(tok);
368
- from = tok.j;
369
- }
370
- // WORD-INFIX: borrow the numeric operand just before the operator.
371
- let start = term.i;
372
- if (picked.length === arity - 1) {
373
- let before;
374
- for (const t of tokens) {
375
- if (t.j > term.i)
376
- break;
377
- if (t.kind === "operand")
378
- before = t;
379
- }
380
- if (before && term.i - before.j <= this.host.reach) {
381
- picked.unshift(before);
382
- start = before.i;
383
- }
384
- }
385
- if (picked.length !== arity)
386
- return null; // under-supplied → decline
387
- const args = picked.map((t) => t.value ?? query.subarray(t.i, t.j));
388
- const symbols = picked.flatMap((t, k) => t.kind === "term" ? [args[k]] : []);
389
- const resonance = symbols.length > 0
390
- ? await prefetchOpposites(this.resonance, symbols)
391
- : NO_RESONANCE;
392
- const bytes = this.alu.applyBytes(name, args, resonance);
393
- if (bytes === null)
394
- return null;
395
- if (symbols.length === args.length && args.some((a) => bytesEqual(bytes, a))) {
396
- return null; // an all-symbol result echoing an operand grounded nothing
397
- }
398
- return { i: start, j: picked[picked.length - 1].j, bytes };
399
- }
400
- /** Strip non-math filler tokens from a raw expression string — keep numbers,
401
- * operators, parens, names the GRAMMAR resolves (unary functions,
402
- * registered constants), and single-RUNE identifiers. The rune rule is the
403
- * mirror of {@link "./alu.js".Alu.conceptAnchors}' compound rule: a compound
404
- * name carries distributional meaning (it is either a resolvable operation
405
- * or filler — "of", "at", "the"), while a bare atom carries none and can
406
- * only be the expression's free variable. Dropping the filler leaves the
407
- * evaluator clean notation. */
408
- cleanExprText(raw) {
409
- const g = this.alu.grammar;
410
- const toks = g.tokenize(raw);
411
- if (!toks)
412
- return ""; // not a tokenizable expression — stay silent
413
- const keep = [];
414
- for (const t of toks) {
415
- if (t.kind !== "name" ||
416
- g.isFunction(t.text) || g.isConstant(t.text) || t.text.length === 1) {
417
- keep.push(t.text);
418
- }
419
- }
420
- return keep.join("");
421
- }
422
- }
423
- const UTF8 = new TextEncoder();
424
- /** Sentinel closing the lex walk (never emitted). */
425
- const END = { i: Infinity, j: Infinity, kind: "operator" };
426
- /** Collapse each EVALUATED arithmetic run into one virtual OPERAND token
427
- * carrying the run's result — the composed stream named operations consume,
428
- * so an infix sub-expression is a single finished operand ("sum 1*3 4"
429
- * applies add(3, 4)) exactly as the grammar nests expressions. A run that
430
- * did not evaluate keeps its original tokens. One ascending merge walk. */
431
- function compose(tokens, results) {
432
- if (results.length === 0)
433
- return tokens;
434
- const sorted = [...results].sort((a, b) => a.i - b.i);
435
- const out = [];
436
- let k = 0;
437
- for (const r of sorted) {
438
- while (k < tokens.length && tokens[k].i < r.i)
439
- out.push(tokens[k++]);
440
- const inside = [];
441
- while (k < tokens.length && tokens[k].j <= r.j)
442
- inside.push(tokens[k++]);
443
- if (r.bytes !== null) {
444
- out.push({ i: r.i, j: r.j, kind: "operand", value: r.bytes });
445
- }
446
- else
447
- out.push(...inside);
448
- }
449
- out.push(...tokens.slice(k));
450
- return out;
451
- }
452
- /** The AUTHORITY law: a span strictly contained in a larger computed span is
453
- * that computation's material — the outer computation consumed it — so only
454
- * the outermost readings survive. Overlapping-but-not-nested spans are
455
- * rival readings the host's search may still weigh against each other. */
456
- function authoritative(spans) {
457
- return spans.filter((s) => !spans.some((o) => o !== s && o.i <= s.i && s.j <= o.j && o.j - o.i > s.j - s.i));
458
- }
459
- /** Keep the first occurrence of each (span, bytes) result. */
460
- function dedup(spans) {
461
- const seen = new Set();
462
- return spans.filter((s) => {
463
- const key = s.i + "," + s.j + "," + latin1(s.bytes);
464
- if (seen.has(key))
465
- return false;
466
- seen.add(key);
467
- return true;
468
- });
469
- }
@@ -1,55 +0,0 @@
1
- import type { ResonanceSync } from "./operation.js";
2
- /** A labelled concept form: the canonical operation name and one of its
3
- * surface forms, as bytes. The host resonates opaque spans against these to
4
- * answer "which operation does this span MEAN?" (see parser.ts AluHost). */
5
- export interface ConceptAnchor {
6
- name: string;
7
- form: Uint8Array;
8
- }
9
- /** The async resonance capability the host provides. Both methods may return
10
- * null when resonance finds nothing above the host's own threshold — ALU then
11
- * declines to guess (operation unrecognised, inverse left unchanged). This
12
- * keeps synthesis graph-evidenced: ALU never invents meaning resonance did not
13
- * supply. */
14
- export interface AluResonance {
15
- /** The canonical operation a span's MEANING names, found by resonance over the
16
- * operation concepts — the GENERIC, modality-agnostic recognition path. This
17
- * is how an operation that is NOT literally spelled (no "∫" for an integral,
18
- * no "+" for a sum drawn or spoken) is still recognised: the span's gist
19
- * resonates with the operation's concept. Returns the canonical op name, or
20
- * null when nothing resonates above threshold. */
21
- recogniseOp(bytes: Uint8Array): Promise<string | null>;
22
- /** The resonant opposite of a symbol's bytes (its antonym / inverse in the
23
- * resonance space, any modality), or null. The host finds it by halo
24
- * resonance over the negated concept. */
25
- opposite(bytes: Uint8Array): Promise<Uint8Array | null>;
26
- }
27
- /** A AluResonance that knows nothing — the default when the host wires none in,
28
- * so the kernel runs fully decoupled (operations resolve by literal forms only,
29
- * and a symbol inverse is left unchanged). */
30
- export declare const NO_ALU_RESONANCE: AluResonance;
31
- /** Pre-resolve the resonant opposite of each symbol in `symbols`, awaiting the
32
- * host's async resonance once per distinct span, and return a SYNCHRONOUS
33
- * snapshot the op callbacks read during the search. Keyed by the latin1 view
34
- * of the bytes (a lossless, stable string key — the same device the search's
35
- * chart uses). This is the async→sync bridge for the polymorphic inverse,
36
- * mirroring how a concept hop's target is pre-resolved and read synchronously. */
37
- export declare function prefetchOpposites(resonance: AluResonance, symbols: Iterable<Uint8Array>): Promise<ResonanceSync>;
38
- /** Pre-resolve BOTH capabilities a computation may need synchronously — the
39
- * resonant opposite of a symbol (for the polymorphic inverse) AND the operation
40
- * a symbol's MEANING names (for a higher-order nd op's function argument) — over
41
- * one set of candidate spans, and return a single {@link ResonanceSync}. Each
42
- * distinct span is awaited once per capability. This is the unified async→sync
43
- * bridge the host uses for an nd computation, where the same spans may serve as
44
- * inverse operands and as a reduce/map/filter operator. Either lookup yields
45
- * null for a span that resonates with nothing, so callbacks decline rather than
46
- * guess. */
47
- export declare function prefetchResonance(resonance: AluResonance, spans: Iterable<Uint8Array>): Promise<ResonanceSync>;
48
- /** Pre-resolve, for each candidate span, the operation its MEANING names —
49
- * awaiting the host's async gist resonance once per distinct span — and return
50
- * a synchronous map keyed by the span's latin1 bytes → canonical op name. This
51
- * is the async→sync bridge for the GENERIC operation-recognition path: a span
52
- * the literal scan could not classify (no operator symbol) but whose gist
53
- * resonates with an operation's concept. Spans that resonate with nothing are
54
- * omitted, so the caller treats a miss as "not an operation". */
55
- export declare function prefetchRecognisedOps(resonance: AluResonance, spans: Iterable<Uint8Array>): Promise<Map<string, string>>;
@@ -1,126 +0,0 @@
1
- // resonance.ts — ALU's window onto meaning, and how the host pre-resolves it.
2
- //
3
- // ALU computes on bytes of any modality, but WHICH operation a byte span invokes
4
- // — and what the opposite of a symbol is — are questions of MEANING, and only
5
- // resonance can read meaning from an opaque span. Two behaviours need it, and
6
- // BOTH are generic (any operation, any modality), not special cases:
7
- //
8
- // • operation recognition — the operation a query asks for is, in general, NOT
9
- // literally spelled. "2+2" carries a "+", but "the integral of …", "the
10
- // limit as …", "the derivative of …", or the analogous request expressed as
11
- // an image / audio gesture carry NO operator symbol at all. The operation
12
- // must be recognised from the span's GIST resonating with the operation's
13
- // CONCEPT. This is the primary, generic recognition path; the literal
14
- // symbol scan (alu.ts `scan`) is merely the easy special case layered under
15
- // it. Recognition is by gist, so it is modality-agnostic: a "+" drawn, a
16
- // "plus" spoken, and the byte "+" all resonate toward the same `add`
17
- // concept.
18
- //
19
- // • the polymorphic inverse — the opposite of a SYMBOL (the bytes of a learnt
20
- // form, any modality) is its RESONANT opposite, found in the resonance
21
- // space, not by arithmetic. The inverse of a number is its negation; the
22
- // inverse of a form is its antonym/complement.
23
- //
24
- // Both are ASYNC in SEMA (they hit the gist / halo index), but the
25
- // lightest-derivation search is SYNCHRONOUS. So — exactly as src/mind/pipeline.ts hoists
26
- // concept hops and connectors into Maps before the search and reads them
27
- // synchronously inside the rules — ALU splits each capability in two:
28
- //
29
- // AluResonance (async) — what the HOST implements over its resonance index.
30
- // Called only during pre-resolution.
31
- // ResonanceSync (sync) — the pre-resolved snapshot the op callbacks / rules
32
- // read (ResonanceSync is declared in operation.ts).
33
- //
34
- // {@link prefetchOpposites} and {@link prefetchRecognisedOps} turn the async side
35
- // into synchronous lookups for a known set of spans; the host calls them during
36
- // its pre-resolution pass. This file is the ENTIRE coupling surface to SEMA —
37
- // ALU imports nothing from the mind or store; the host supplies a AluResonance
38
- // built over its own perception + resonance (gist nearness to the operation
39
- // vocabulary ALU exposes via `conceptForms`, and halo resonance for the
40
- // opposite).
41
- import { latin1 } from "../../bytes.js";
42
- /** A AluResonance that knows nothing — the default when the host wires none in,
43
- * so the kernel runs fully decoupled (operations resolve by literal forms only,
44
- * and a symbol inverse is left unchanged). */
45
- export const NO_ALU_RESONANCE = {
46
- recogniseOp: async () => null,
47
- opposite: async () => null,
48
- };
49
- /** Pre-resolve the resonant opposite of each symbol in `symbols`, awaiting the
50
- * host's async resonance once per distinct span, and return a SYNCHRONOUS
51
- * snapshot the op callbacks read during the search. Keyed by the latin1 view
52
- * of the bytes (a lossless, stable string key — the same device the search's
53
- * chart uses). This is the async→sync bridge for the polymorphic inverse,
54
- * mirroring how a concept hop's target is pre-resolved and read synchronously. */
55
- export async function prefetchOpposites(resonance, symbols) {
56
- const table = new Map();
57
- const seen = new Set();
58
- for (const bytes of symbols) {
59
- const key = latin1(bytes);
60
- if (seen.has(key))
61
- continue;
62
- seen.add(key);
63
- const opp = await resonance.opposite(bytes);
64
- if (opp)
65
- table.set(key, opp);
66
- }
67
- return {
68
- opposite: (bytes) => table.get(latin1(bytes)) ?? null,
69
- // Opposites-only prefetch carries no op recognition; a higher-order nd op
70
- // resolving through this falls back to literal forms / canonical names.
71
- recogniseOp: () => null,
72
- };
73
- }
74
- /** Pre-resolve BOTH capabilities a computation may need synchronously — the
75
- * resonant opposite of a symbol (for the polymorphic inverse) AND the operation
76
- * a symbol's MEANING names (for a higher-order nd op's function argument) — over
77
- * one set of candidate spans, and return a single {@link ResonanceSync}. Each
78
- * distinct span is awaited once per capability. This is the unified async→sync
79
- * bridge the host uses for an nd computation, where the same spans may serve as
80
- * inverse operands and as a reduce/map/filter operator. Either lookup yields
81
- * null for a span that resonates with nothing, so callbacks decline rather than
82
- * guess. */
83
- export async function prefetchResonance(resonance, spans) {
84
- const opposites = new Map();
85
- const ops = new Map();
86
- const seen = new Set();
87
- for (const bytes of spans) {
88
- const key = latin1(bytes);
89
- if (seen.has(key))
90
- continue;
91
- seen.add(key);
92
- const [opp, op] = await Promise.all([
93
- resonance.opposite(bytes),
94
- resonance.recogniseOp(bytes),
95
- ]);
96
- if (opp)
97
- opposites.set(key, opp);
98
- if (op)
99
- ops.set(key, op);
100
- }
101
- return {
102
- opposite: (bytes) => opposites.get(latin1(bytes)) ?? null,
103
- recogniseOp: (bytes) => ops.get(latin1(bytes)) ?? null,
104
- };
105
- }
106
- /** Pre-resolve, for each candidate span, the operation its MEANING names —
107
- * awaiting the host's async gist resonance once per distinct span — and return
108
- * a synchronous map keyed by the span's latin1 bytes → canonical op name. This
109
- * is the async→sync bridge for the GENERIC operation-recognition path: a span
110
- * the literal scan could not classify (no operator symbol) but whose gist
111
- * resonates with an operation's concept. Spans that resonate with nothing are
112
- * omitted, so the caller treats a miss as "not an operation". */
113
- export async function prefetchRecognisedOps(resonance, spans) {
114
- const table = new Map();
115
- const seen = new Set();
116
- for (const bytes of spans) {
117
- const key = latin1(bytes);
118
- if (seen.has(key))
119
- continue;
120
- seen.add(key);
121
- const op = await resonance.recogniseOp(bytes);
122
- if (op)
123
- table.set(key, op);
124
- }
125
- return table;
126
- }