@hviana/sema 0.1.9 → 0.2.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.
- package/dist/example/demo.d.ts +1 -0
- package/dist/example/demo.js +39 -0
- package/dist/example/train_base.d.ts +87 -0
- package/dist/example/train_base.js +2252 -0
- package/dist/src/alphabet.d.ts +7 -0
- package/dist/src/alphabet.js +33 -0
- package/dist/src/alu/src/alu.d.ts +185 -0
- package/dist/src/alu/src/alu.js +440 -0
- package/dist/src/alu/src/expr.d.ts +61 -0
- package/dist/src/alu/src/expr.js +318 -0
- package/dist/src/alu/src/index.d.ts +11 -0
- package/dist/src/alu/src/index.js +19 -0
- package/dist/src/alu/src/kernel-arith.d.ts +16 -0
- package/dist/src/alu/src/kernel-arith.js +264 -0
- package/dist/src/alu/src/kernel-bits.d.ts +19 -0
- package/dist/src/alu/src/kernel-bits.js +152 -0
- package/dist/src/alu/src/kernel-logic.d.ts +4 -0
- package/dist/src/alu/src/kernel-logic.js +60 -0
- package/dist/src/alu/src/kernel-nd.d.ts +3 -0
- package/dist/src/alu/src/kernel-nd.js +208 -0
- package/dist/src/alu/src/kernel-numeric.d.ts +54 -0
- package/dist/src/alu/src/kernel-numeric.js +366 -0
- package/dist/src/alu/src/operation.d.ts +168 -0
- package/dist/src/alu/src/operation.js +189 -0
- package/dist/src/alu/src/parser.d.ts +221 -0
- package/dist/src/alu/src/parser.js +577 -0
- package/dist/src/alu/src/resonance.d.ts +55 -0
- package/dist/src/alu/src/resonance.js +126 -0
- package/dist/src/alu/src/text.d.ts +31 -0
- package/dist/src/alu/src/text.js +73 -0
- package/dist/src/alu/src/value.d.ts +109 -0
- package/dist/src/alu/src/value.js +300 -0
- package/dist/src/alu/test/alu.test.d.ts +1 -0
- package/dist/src/alu/test/alu.test.js +764 -0
- package/dist/src/bytes.d.ts +14 -0
- package/dist/src/bytes.js +59 -0
- package/dist/src/canon.d.ts +26 -0
- package/dist/src/canon.js +57 -0
- package/dist/src/config.d.ts +111 -0
- package/dist/src/config.js +91 -0
- package/dist/src/derive/src/deduction.d.ts +125 -0
- package/dist/src/derive/src/deduction.js +155 -0
- package/dist/src/derive/src/index.d.ts +7 -0
- package/dist/src/derive/src/index.js +11 -0
- package/dist/src/derive/src/priority-queue.d.ts +20 -0
- package/dist/src/derive/src/priority-queue.js +73 -0
- package/dist/src/derive/src/rewrite.d.ts +56 -0
- package/dist/src/derive/src/rewrite.js +100 -0
- package/dist/src/derive/src/trie.d.ts +90 -0
- package/dist/src/derive/src/trie.js +217 -0
- package/dist/src/derive/test/derive.test.d.ts +1 -0
- package/dist/src/derive/test/derive.test.js +122 -0
- package/dist/src/extension.d.ts +37 -0
- package/dist/src/extension.js +7 -0
- package/dist/src/geometry.d.ts +148 -0
- package/dist/src/geometry.js +511 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.js +18 -0
- package/dist/src/ingest-cache.d.ts +41 -0
- package/dist/src/ingest-cache.js +161 -0
- package/dist/src/mind/articulation.d.ts +6 -0
- package/dist/src/mind/articulation.js +99 -0
- package/dist/src/mind/attention.d.ts +72 -0
- package/dist/src/mind/attention.js +898 -0
- package/dist/src/mind/canonical.d.ts +29 -0
- package/dist/src/mind/canonical.js +88 -0
- package/dist/src/mind/graph-search.d.ts +270 -0
- package/dist/src/mind/graph-search.js +927 -0
- package/dist/src/mind/index.d.ts +5 -0
- package/dist/src/mind/index.js +5 -0
- package/dist/src/mind/junction.d.ts +95 -0
- package/dist/src/mind/junction.js +262 -0
- package/dist/src/mind/learning.d.ts +47 -0
- package/dist/src/mind/learning.js +233 -0
- package/dist/src/mind/match.d.ts +113 -0
- package/dist/src/mind/match.js +446 -0
- package/dist/src/mind/mechanisms/alu.d.ts +4 -0
- package/dist/src/mind/mechanisms/alu.js +29 -0
- package/dist/src/mind/mechanisms/cast.d.ts +35 -0
- package/dist/src/mind/mechanisms/cast.js +461 -0
- package/dist/src/mind/mechanisms/confluence.d.ts +24 -0
- package/dist/src/mind/mechanisms/confluence.js +225 -0
- package/dist/src/mind/mechanisms/cover.d.ts +6 -0
- package/dist/src/mind/mechanisms/cover.js +179 -0
- package/dist/src/mind/mechanisms/extraction.d.ts +67 -0
- package/dist/src/mind/mechanisms/extraction.js +342 -0
- package/dist/src/mind/mechanisms/recall.d.ts +13 -0
- package/dist/src/mind/mechanisms/recall.js +235 -0
- package/dist/src/mind/mind.d.ts +273 -0
- package/dist/src/mind/mind.js +598 -0
- package/dist/src/mind/pipeline-mechanism.d.ts +142 -0
- package/dist/src/mind/pipeline-mechanism.js +213 -0
- package/dist/src/mind/pipeline.d.ts +20 -0
- package/dist/src/mind/pipeline.js +185 -0
- package/dist/src/mind/primitives.d.ts +63 -0
- package/dist/src/mind/primitives.js +251 -0
- package/dist/src/mind/rationale.d.ts +134 -0
- package/dist/src/mind/rationale.js +162 -0
- package/dist/src/mind/reasoning.d.ts +15 -0
- package/dist/src/mind/reasoning.js +162 -0
- package/dist/src/mind/recognition.d.ts +20 -0
- package/dist/src/mind/recognition.js +246 -0
- package/dist/src/mind/resonance.d.ts +23 -0
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +15 -0
- package/dist/src/mind/trace.js +73 -0
- package/dist/src/mind/traverse.d.ts +113 -0
- package/dist/src/mind/traverse.js +488 -0
- package/dist/src/mind/types.d.ts +186 -0
- package/dist/src/mind/types.js +84 -0
- package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
- package/dist/src/rabitq-ivf/src/database.js +201 -0
- package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
- package/dist/src/rabitq-ivf/src/index.js +4 -0
- package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
- package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
- package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
- package/dist/src/rabitq-ivf/src/prng.js +36 -0
- package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
- package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
- package/dist/src/sema.d.ts +31 -0
- package/dist/src/sema.js +63 -0
- package/dist/src/store-sqlite.d.ts +184 -0
- package/dist/src/store-sqlite.js +942 -0
- package/dist/src/store.d.ts +654 -0
- package/dist/src/store.js +1612 -0
- package/dist/src/vec.d.ts +31 -0
- package/dist/src/vec.js +109 -0
- package/package.json +1 -1
- package/src/mind/graph-search.ts +128 -46
- package/src/mind/mind.ts +37 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { OperationRegistry } from "./operation.js";
|
|
2
|
+
/** Apply a scalar kernel op by canonical name to numeric arguments, returning a
|
|
3
|
+
* number. The expression evaluator routes every step through this, so the
|
|
4
|
+
* arithmetic inside an integrand is the kernel's own. */
|
|
5
|
+
export type ApplyScalar = (name: string, args: number[]) => number;
|
|
6
|
+
/** Whether a name is a registered unary function the evaluator may call. */
|
|
7
|
+
export type IsUnaryFn = (name: string) => boolean;
|
|
8
|
+
export interface Token {
|
|
9
|
+
kind: "num" | "name" | "op" | "lparen" | "rparen";
|
|
10
|
+
text: string;
|
|
11
|
+
value?: number;
|
|
12
|
+
}
|
|
13
|
+
/** Tokenize an expression string: numerals (the irreducible floor), operator
|
|
14
|
+
* tokens (matched longest-first against `operators` — the registry's own
|
|
15
|
+
* symbolic surface forms), identifiers, and parentheses. When no operator
|
|
16
|
+
* vocabulary is given, each symbolic character stands alone (enough for name
|
|
17
|
+
* extraction). Returns null when a character fits none of these — the span is
|
|
18
|
+
* not a clean expression. */
|
|
19
|
+
export declare function tokenize(s: string, operators?: readonly string[]): Token[] | null;
|
|
20
|
+
/** The identifiers in `s` that are NOT known unary functions and NOT registered
|
|
21
|
+
* constants — the free-variable candidates. Used to auto-detect the variable
|
|
22
|
+
* when the caller did not name one. */
|
|
23
|
+
export declare function freeVariables(s: string, isUnaryFn: IsUnaryFn, isConstant?: (name: string) => boolean): string[];
|
|
24
|
+
/** The expression grammar, read off an operation registry once and reused for
|
|
25
|
+
* every evaluation. It resolves each token through the registry's own form
|
|
26
|
+
* index — infix binding from the `infix` trait, a prefix operator as the
|
|
27
|
+
* arity-1 claimant of a shared symbol, functions as arity-1 ops, constants as
|
|
28
|
+
* arity-0 ops — so the grammar and the kernel can never drift apart. */
|
|
29
|
+
export declare class ExprGrammar {
|
|
30
|
+
private readonly registry;
|
|
31
|
+
private readonly applyScalar;
|
|
32
|
+
/** Symbolic operator tokens, longest first (so "<=" wins over "<"). */
|
|
33
|
+
private readonly operatorTokens;
|
|
34
|
+
/** token → the infix op it names and its declared binding. */
|
|
35
|
+
private readonly infixTable;
|
|
36
|
+
/** token → the arity-1 (prefix) op it names. */
|
|
37
|
+
private readonly prefixTable;
|
|
38
|
+
/** The tightest infix tier — a prefix operator binds its operand up through
|
|
39
|
+
* it, so "-x^2" reads -(x^2) without a hardcoded rule. */
|
|
40
|
+
private readonly maxPrecedence;
|
|
41
|
+
constructor(registry: OperationRegistry, applyScalar: ApplyScalar);
|
|
42
|
+
/** Resolve an identifier to a registered op of the given arity: a surface
|
|
43
|
+
* form claimant of that arity first, else the canonical name itself. */
|
|
44
|
+
private resolveName;
|
|
45
|
+
/** Whether an identifier names a unary function. */
|
|
46
|
+
isFunction(name: string): boolean;
|
|
47
|
+
/** Whether an identifier names a nullary constant (an arity-0 op). */
|
|
48
|
+
isConstant(name: string): boolean;
|
|
49
|
+
/** Tokenize with this grammar's operator vocabulary. */
|
|
50
|
+
tokenize(s: string): Token[] | null;
|
|
51
|
+
/** The free-variable candidates of `s` under this grammar. */
|
|
52
|
+
freeVariables(s: string): string[];
|
|
53
|
+
/** Evaluate expression `s` with `variable` bound to `at`. Returns a number,
|
|
54
|
+
* or null if `s` is not a well-formed expression. Every binary/function/
|
|
55
|
+
* constant step is applied through the kernel, so the arithmetic is the
|
|
56
|
+
* kernel's own. When `variable` is empty, the single free variable is
|
|
57
|
+
* auto-detected; if there is more than one and none was named, evaluation
|
|
58
|
+
* declines (null) — a genuinely multivariate expression needs an explicit
|
|
59
|
+
* binding. */
|
|
60
|
+
eval(s: string, variable: string, at: number): number | null;
|
|
61
|
+
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// expr.ts — evaluate a symbolic EXPRESSION at a binding of its free variable.
|
|
2
|
+
//
|
|
3
|
+
// A numerical operation (a derivative, an integral, a limit — or any refinement
|
|
4
|
+
// the kernel can express) does not act on a number; it acts on a FUNCTION, and a
|
|
5
|
+
// function is an expression with a free variable. To refine such an operation,
|
|
6
|
+
// the engine must sample that expression at many points — and evaluating the
|
|
7
|
+
// expression is a RECURSIVE application of the very same ALU (its "+", "·",
|
|
8
|
+
// "sin", … are the registered ops). This module is that recursion.
|
|
9
|
+
//
|
|
10
|
+
// The grammar is NOT hardcoded: it is READ OFF the operation registry. An
|
|
11
|
+
// infix operator is any op registered with an `infix` trait (its precedence and
|
|
12
|
+
// associativity declared next to the op, kernel-arith.ts); a prefix operator is
|
|
13
|
+
// the arity-1 claimant of a shared symbol ("-" is negate before an operand,
|
|
14
|
+
// subtract between two); a function is any arity-1 op named by one of its
|
|
15
|
+
// surface forms; a CONSTANT is any arity-0 op (pi, e — registered like every
|
|
16
|
+
// other operation, kernel-numeric.ts). So extending the notation is extending
|
|
17
|
+
// the registry — no parser edits, no operator tables, no magic characters
|
|
18
|
+
// beyond the irreducible numeral floor.
|
|
19
|
+
//
|
|
20
|
+
// The free variable can be given explicitly or AUTO-DETECTED: when none is
|
|
21
|
+
// named, the single identifier that resolves to no registered op is taken as
|
|
22
|
+
// the variable. This keeps "x^2", "t*t", or a one-symbol form in any alphabet
|
|
23
|
+
// working without the caller having to spell out the variable.
|
|
24
|
+
const isDigit = (c) => c >= "0" && c <= "9";
|
|
25
|
+
// A "letter" for identifier purposes is any non-ASCII rune or an ASCII letter —
|
|
26
|
+
// so a variable or function name may be written in any script (multimodal /
|
|
27
|
+
// multilingual), not just A–Z. Operator glyphs (registered symbolic forms)
|
|
28
|
+
// are claimed BEFORE identifiers, so "·" and "≤" never read as names.
|
|
29
|
+
const isLetter = (c) => (c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c.charCodeAt(0) > 127;
|
|
30
|
+
const isSpace = (c) => c === " " || c === "\t" || c === "\n" || c === "\r";
|
|
31
|
+
/** Tokenize an expression string: numerals (the irreducible floor), operator
|
|
32
|
+
* tokens (matched longest-first against `operators` — the registry's own
|
|
33
|
+
* symbolic surface forms), identifiers, and parentheses. When no operator
|
|
34
|
+
* vocabulary is given, each symbolic character stands alone (enough for name
|
|
35
|
+
* extraction). Returns null when a character fits none of these — the span is
|
|
36
|
+
* not a clean expression. */
|
|
37
|
+
export function tokenize(s, operators) {
|
|
38
|
+
const toks = [];
|
|
39
|
+
let i = 0;
|
|
40
|
+
while (i < s.length) {
|
|
41
|
+
const c = s[i];
|
|
42
|
+
if (isSpace(c)) {
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (isDigit(c) || (c === "." && i + 1 < s.length && isDigit(s[i + 1]))) {
|
|
47
|
+
let j = i;
|
|
48
|
+
let seenDot = false;
|
|
49
|
+
while (j < s.length) {
|
|
50
|
+
if (isDigit(s[j]))
|
|
51
|
+
j++;
|
|
52
|
+
else if (s[j] === "." && !seenDot) {
|
|
53
|
+
seenDot = true;
|
|
54
|
+
j++;
|
|
55
|
+
}
|
|
56
|
+
else
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
// optional exponent
|
|
60
|
+
if (j < s.length && (s[j] === "e" || s[j] === "E")) {
|
|
61
|
+
let k = j + 1;
|
|
62
|
+
if (k < s.length && (s[k] === "+" || s[k] === "-"))
|
|
63
|
+
k++;
|
|
64
|
+
if (k < s.length && isDigit(s[k])) {
|
|
65
|
+
while (k < s.length && isDigit(s[k]))
|
|
66
|
+
k++;
|
|
67
|
+
j = k;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const text = s.slice(i, j);
|
|
71
|
+
const num = Number(text);
|
|
72
|
+
if (!Number.isFinite(num))
|
|
73
|
+
return null;
|
|
74
|
+
toks.push({ kind: "num", text, value: num });
|
|
75
|
+
i = j;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (c === "(") {
|
|
79
|
+
toks.push({ kind: "lparen", text: c });
|
|
80
|
+
i++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (c === ")") {
|
|
84
|
+
toks.push({ kind: "rparen", text: c });
|
|
85
|
+
i++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// A registered symbolic operator form, longest first — claimed before the
|
|
89
|
+
// identifier path so an operator GLYPH (·, ×, ≤, …) is an operator, not a
|
|
90
|
+
// name.
|
|
91
|
+
const op = operators?.find((f) => s.startsWith(f, i));
|
|
92
|
+
if (op !== undefined) {
|
|
93
|
+
toks.push({ kind: "op", text: op });
|
|
94
|
+
i += op.length;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (isLetter(c)) {
|
|
98
|
+
let j = i;
|
|
99
|
+
while (j < s.length && (isLetter(s[j]) || isDigit(s[j])))
|
|
100
|
+
j++;
|
|
101
|
+
toks.push({ kind: "name", text: s.slice(i, j) });
|
|
102
|
+
i = j;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Fallback for a symbolic character outside any vocabulary: its own token,
|
|
106
|
+
// so name extraction (freeVariables) still splits "a*b" without a grammar.
|
|
107
|
+
if (operators === undefined) {
|
|
108
|
+
toks.push({ kind: "op", text: c });
|
|
109
|
+
i++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
return null; // an unexpected character → not a clean expression
|
|
113
|
+
}
|
|
114
|
+
return toks;
|
|
115
|
+
}
|
|
116
|
+
/** The identifiers in `s` that are NOT known unary functions and NOT registered
|
|
117
|
+
* constants — the free-variable candidates. Used to auto-detect the variable
|
|
118
|
+
* when the caller did not name one. */
|
|
119
|
+
export function freeVariables(s, isUnaryFn, isConstant = () => false) {
|
|
120
|
+
const toks = tokenize(s);
|
|
121
|
+
if (!toks)
|
|
122
|
+
return [];
|
|
123
|
+
const out = [];
|
|
124
|
+
const seen = new Set();
|
|
125
|
+
for (let k = 0; k < toks.length; k++) {
|
|
126
|
+
const t = toks[k];
|
|
127
|
+
if (t.kind !== "name")
|
|
128
|
+
continue;
|
|
129
|
+
// A name immediately followed by "(" is a function call, not a variable.
|
|
130
|
+
const isCall = k + 1 < toks.length && toks[k + 1].kind === "lparen";
|
|
131
|
+
if (isCall || isUnaryFn(t.text) || isConstant(t.text))
|
|
132
|
+
continue;
|
|
133
|
+
if (!seen.has(t.text)) {
|
|
134
|
+
seen.add(t.text);
|
|
135
|
+
out.push(t.text);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
/** The expression grammar, read off an operation registry once and reused for
|
|
141
|
+
* every evaluation. It resolves each token through the registry's own form
|
|
142
|
+
* index — infix binding from the `infix` trait, a prefix operator as the
|
|
143
|
+
* arity-1 claimant of a shared symbol, functions as arity-1 ops, constants as
|
|
144
|
+
* arity-0 ops — so the grammar and the kernel can never drift apart. */
|
|
145
|
+
export class ExprGrammar {
|
|
146
|
+
registry;
|
|
147
|
+
applyScalar;
|
|
148
|
+
/** Symbolic operator tokens, longest first (so "<=" wins over "<"). */
|
|
149
|
+
operatorTokens;
|
|
150
|
+
/** token → the infix op it names and its declared binding. */
|
|
151
|
+
infixTable = new Map();
|
|
152
|
+
/** token → the arity-1 (prefix) op it names. */
|
|
153
|
+
prefixTable = new Map();
|
|
154
|
+
/** The tightest infix tier — a prefix operator binds its operand up through
|
|
155
|
+
* it, so "-x^2" reads -(x^2) without a hardcoded rule. */
|
|
156
|
+
maxPrecedence;
|
|
157
|
+
constructor(registry, applyScalar) {
|
|
158
|
+
this.registry = registry;
|
|
159
|
+
this.applyScalar = applyScalar;
|
|
160
|
+
const tokens = new Set();
|
|
161
|
+
let maxPrec = 0;
|
|
162
|
+
for (const { form, name } of registry.formEntries()) {
|
|
163
|
+
const op = registry.get(name);
|
|
164
|
+
const symbolic = form.length > 0 && !/[A-Za-z0-9]/.test(form);
|
|
165
|
+
if (!symbolic)
|
|
166
|
+
continue;
|
|
167
|
+
tokens.add(form);
|
|
168
|
+
if (op.infix && !this.infixTable.has(form)) {
|
|
169
|
+
this.infixTable.set(form, { name, syntax: op.infix });
|
|
170
|
+
maxPrec = Math.max(maxPrec, op.infix.precedence);
|
|
171
|
+
}
|
|
172
|
+
if (op.arity === 1 && !this.prefixTable.has(form)) {
|
|
173
|
+
this.prefixTable.set(form, name);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.operatorTokens = [...tokens].sort((a, b) => b.length - a.length);
|
|
177
|
+
this.maxPrecedence = maxPrec;
|
|
178
|
+
}
|
|
179
|
+
/** Resolve an identifier to a registered op of the given arity: a surface
|
|
180
|
+
* form claimant of that arity first, else the canonical name itself. */
|
|
181
|
+
resolveName(name, arity) {
|
|
182
|
+
for (const n of this.registry.lookupForm(name)) {
|
|
183
|
+
if (this.registry.get(n).arity === arity)
|
|
184
|
+
return n;
|
|
185
|
+
}
|
|
186
|
+
const own = this.registry.get(name);
|
|
187
|
+
return own && own.arity === arity ? name : null;
|
|
188
|
+
}
|
|
189
|
+
/** Whether an identifier names a unary function. */
|
|
190
|
+
isFunction(name) {
|
|
191
|
+
return this.resolveName(name, 1) !== null;
|
|
192
|
+
}
|
|
193
|
+
/** Whether an identifier names a nullary constant (an arity-0 op). */
|
|
194
|
+
isConstant(name) {
|
|
195
|
+
return this.resolveName(name, 0) !== null;
|
|
196
|
+
}
|
|
197
|
+
/** Tokenize with this grammar's operator vocabulary. */
|
|
198
|
+
tokenize(s) {
|
|
199
|
+
return tokenize(s, this.operatorTokens);
|
|
200
|
+
}
|
|
201
|
+
/** The free-variable candidates of `s` under this grammar. */
|
|
202
|
+
freeVariables(s) {
|
|
203
|
+
return freeVariables(s, (n) => this.isFunction(n), (n) => this.isConstant(n));
|
|
204
|
+
}
|
|
205
|
+
/** Evaluate expression `s` with `variable` bound to `at`. Returns a number,
|
|
206
|
+
* or null if `s` is not a well-formed expression. Every binary/function/
|
|
207
|
+
* constant step is applied through the kernel, so the arithmetic is the
|
|
208
|
+
* kernel's own. When `variable` is empty, the single free variable is
|
|
209
|
+
* auto-detected; if there is more than one and none was named, evaluation
|
|
210
|
+
* declines (null) — a genuinely multivariate expression needs an explicit
|
|
211
|
+
* binding. */
|
|
212
|
+
eval(s, variable, at) {
|
|
213
|
+
const toks = this.tokenize(s);
|
|
214
|
+
if (!toks || toks.length === 0)
|
|
215
|
+
return null;
|
|
216
|
+
let v = variable;
|
|
217
|
+
if (v === "") {
|
|
218
|
+
const fv = this.freeVariables(s);
|
|
219
|
+
if (fv.length === 1)
|
|
220
|
+
v = fv[0];
|
|
221
|
+
else if (fv.length > 1)
|
|
222
|
+
return null; // multivariate, no binding named
|
|
223
|
+
// fv.length === 0: a constant expression is fine.
|
|
224
|
+
}
|
|
225
|
+
let pos = 0;
|
|
226
|
+
const peek = () => toks[pos];
|
|
227
|
+
const next = () => toks[pos++];
|
|
228
|
+
const FAIL = Symbol("expr-fail");
|
|
229
|
+
const fail = () => {
|
|
230
|
+
throw FAIL;
|
|
231
|
+
};
|
|
232
|
+
const grammar = this;
|
|
233
|
+
// Precedence climbing over the registry-declared infix tiers.
|
|
234
|
+
function parseExpr(minPrec) {
|
|
235
|
+
let lhs = parseOperand();
|
|
236
|
+
for (;;) {
|
|
237
|
+
const t = peek();
|
|
238
|
+
if (!t || t.kind !== "op")
|
|
239
|
+
break;
|
|
240
|
+
const infix = grammar.infixTable.get(t.text);
|
|
241
|
+
if (!infix || infix.syntax.precedence < minPrec)
|
|
242
|
+
break;
|
|
243
|
+
next();
|
|
244
|
+
const nextMin = infix.syntax.rightAssoc
|
|
245
|
+
? infix.syntax.precedence
|
|
246
|
+
: infix.syntax.precedence + 1;
|
|
247
|
+
const rhs = parseExpr(nextMin);
|
|
248
|
+
lhs = grammar.applyScalar(infix.name, [lhs, rhs]);
|
|
249
|
+
}
|
|
250
|
+
return lhs;
|
|
251
|
+
}
|
|
252
|
+
// An operand: a prefix operator (the arity-1 claimant of its symbol,
|
|
253
|
+
// binding up through the tightest infix tier), or an atom.
|
|
254
|
+
function parseOperand() {
|
|
255
|
+
const t = peek();
|
|
256
|
+
if (t && t.kind === "op") {
|
|
257
|
+
const prefix = grammar.prefixTable.get(t.text);
|
|
258
|
+
if (prefix === undefined)
|
|
259
|
+
return fail();
|
|
260
|
+
next();
|
|
261
|
+
return grammar.applyScalar(prefix, [parseExpr(grammar.maxPrecedence)]);
|
|
262
|
+
}
|
|
263
|
+
return parseAtom();
|
|
264
|
+
}
|
|
265
|
+
function parseAtom() {
|
|
266
|
+
const t = peek();
|
|
267
|
+
if (!t)
|
|
268
|
+
fail();
|
|
269
|
+
if (t.kind === "num") {
|
|
270
|
+
next();
|
|
271
|
+
return t.value;
|
|
272
|
+
}
|
|
273
|
+
if (t.kind === "lparen") {
|
|
274
|
+
next();
|
|
275
|
+
const inner = parseExpr(0);
|
|
276
|
+
if (!peek() || peek().kind !== "rparen")
|
|
277
|
+
fail();
|
|
278
|
+
next();
|
|
279
|
+
return inner;
|
|
280
|
+
}
|
|
281
|
+
if (t.kind === "name") {
|
|
282
|
+
next();
|
|
283
|
+
// A function call: name "(" expr ")".
|
|
284
|
+
if (peek() && peek().kind === "lparen") {
|
|
285
|
+
const fn = grammar.resolveName(t.text, 1);
|
|
286
|
+
if (fn === null)
|
|
287
|
+
return fail();
|
|
288
|
+
next(); // (
|
|
289
|
+
const arg = parseExpr(0);
|
|
290
|
+
if (!peek() || peek().kind !== "rparen")
|
|
291
|
+
fail();
|
|
292
|
+
next(); // )
|
|
293
|
+
return grammar.applyScalar(fn, [arg]);
|
|
294
|
+
}
|
|
295
|
+
// Otherwise an identifier: the free variable, or a nullary constant
|
|
296
|
+
// resolved through the registry like any other operation.
|
|
297
|
+
if (t.text === v)
|
|
298
|
+
return at;
|
|
299
|
+
const konst = grammar.resolveName(t.text, 0);
|
|
300
|
+
if (konst !== null)
|
|
301
|
+
return grammar.applyScalar(konst, []);
|
|
302
|
+
return fail();
|
|
303
|
+
}
|
|
304
|
+
return fail();
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
const result = parseExpr(0);
|
|
308
|
+
if (pos !== toks.length)
|
|
309
|
+
return null; // trailing tokens → malformed
|
|
310
|
+
return Number.isFinite(result) ? result : null;
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
if (err === FAIL)
|
|
314
|
+
return null;
|
|
315
|
+
return null; // a kernel apply threw (e.g. ÷0 produced ∞) → decline
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { asBit, asInt, asReal, bit, coerce, decimalCodec, type Domain, formatReal, int, isNd, isNumeric, joinDomain, nd, parseValue, real, symbol, symbolSpans, tagOf, type Value, type ValueCodec, } from "./value.js";
|
|
2
|
+
export { type Arity, type EvalExpr, type InfixSyntax, NO_RESONANCE, type OpContext, type Operation, OperationRegistry, type OpFn, type OpRuntime, type OpTraits, type ResonanceSync, } from "./operation.js";
|
|
3
|
+
export { type AluResonance, type ConceptAnchor, NO_ALU_RESONANCE, prefetchOpposites, prefetchRecognisedOps, prefetchResonance, } from "./resonance.js";
|
|
4
|
+
export { type ApplyScalar, ExprGrammar, freeVariables, type IsUnaryFn, type Token, tokenize, } from "./expr.js";
|
|
5
|
+
export { type AluHost, type ComputedSpan, QueryParser, type Span, STRUCTURAL_HOST, } from "./parser.js";
|
|
6
|
+
export { registerNd } from "./kernel-nd.js";
|
|
7
|
+
export { registerLogic } from "./kernel-logic.js";
|
|
8
|
+
export { addBits, compareBits, mulBits, negateBits, registerBits, signBits, } from "./kernel-bits.js";
|
|
9
|
+
export { dot, linsolve, matMul, matVec, polyEval, registerArith, } from "./kernel-arith.js";
|
|
10
|
+
export { converge, cosSeries, diff, expSeries, integrate, interpolate, logNewton, odeSolve, optimize, powerEig, registerNumeric, regress, sinSeries, solve, sqrtNewton, topSingular, } from "./kernel-numeric.js";
|
|
11
|
+
export { Alu, type AluOptions, type OperandSpan, type OperatorSpan, } from "./alu.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// alu — the ALU sub-library: a tiny irreducible kernel from which arithmetic,
|
|
2
|
+
// logic, and numerical computation are all DERIVED.
|
|
3
|
+
//
|
|
4
|
+
// Self-contained in the spirit of derive/ and rabitq-ivf/: it imports only the
|
|
5
|
+
// pure byte helpers (../../bytes.js) and nothing else from SEMA. The host
|
|
6
|
+
// reaches meaning (operator synonymy, the symbolic inverse) through the injected
|
|
7
|
+
// AluResonance, pre-resolved into a synchronous snapshot before the search runs.
|
|
8
|
+
// See ./../README.md for the kernel and its derivation DAG.
|
|
9
|
+
export { asBit, asInt, asReal, bit, coerce, decimalCodec, formatReal, int, isNd, isNumeric, joinDomain, nd, parseValue, real, symbol, symbolSpans, tagOf, } from "./value.js";
|
|
10
|
+
export { NO_RESONANCE, OperationRegistry, } from "./operation.js";
|
|
11
|
+
export { NO_ALU_RESONANCE, prefetchOpposites, prefetchRecognisedOps, prefetchResonance, } from "./resonance.js";
|
|
12
|
+
export { ExprGrammar, freeVariables, tokenize, } from "./expr.js";
|
|
13
|
+
export { QueryParser, STRUCTURAL_HOST, } from "./parser.js";
|
|
14
|
+
export { registerNd } from "./kernel-nd.js";
|
|
15
|
+
export { registerLogic } from "./kernel-logic.js";
|
|
16
|
+
export { addBits, compareBits, mulBits, negateBits, registerBits, signBits, } from "./kernel-bits.js";
|
|
17
|
+
export { dot, linsolve, matMul, matVec, polyEval, registerArith, } from "./kernel-arith.js";
|
|
18
|
+
export { converge, cosSeries, diff, expSeries, integrate, interpolate, logNewton, odeSolve, optimize, powerEig, registerNumeric, regress, sinSeries, solve, sqrtNewton, topSingular, } from "./kernel-numeric.js";
|
|
19
|
+
export { Alu, } from "./alu.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OperationRegistry } from "./operation.js";
|
|
2
|
+
/** Register the arithmetic layer into `r`. */
|
|
3
|
+
export declare function registerArith(r: OperationRegistry): void;
|
|
4
|
+
/** Horner evaluation of a polynomial whose coefficients run constant-first
|
|
5
|
+
* (`coeffs[0]` is the constant term). Pure arithmetic over add/multiply. */
|
|
6
|
+
export declare function polyEval(coeffs: number[], x: number): number;
|
|
7
|
+
/** Dot product of two equal-length vectors — a fold of add over multiply. */
|
|
8
|
+
export declare function dot(a: number[], b: number[]): number;
|
|
9
|
+
/** Matrix · vector. */
|
|
10
|
+
export declare function matVec(m: number[][], v: number[]): number[];
|
|
11
|
+
/** Matrix · matrix. */
|
|
12
|
+
export declare function matMul(a: number[][], b: number[][]): number[][];
|
|
13
|
+
/** Solve A·x = b by Gaussian elimination with partial pivoting — structured
|
|
14
|
+
* arithmetic (add / multiply / divide / compare for the pivot), not a new
|
|
15
|
+
* primitive. Returns x, or null if A is singular to tolerance `tol`. */
|
|
16
|
+
export declare function linsolve(A: number[][], b: number[], tol?: number): number[] | null;
|