Skip to content

Commit e7ad9c3

Browse files
author
MesTTo
committed
perf(core): incremental env build (extend per atom, not rebuild per query); oracle 270/270
1 parent 91b0954 commit e7ad9c3

2 files changed

Lines changed: 43 additions & 23 deletions

File tree

packages/core/src/eval.ts

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -146,34 +146,52 @@ export function extractRules(atoms: readonly Atom[]): Array<[Atom, Atom]> {
146146
return out;
147147
}
148148

149-
export function buildEnv(atoms: Atom[], gt: GroundingTable): MinEnv {
150-
const rules = extractRules(atoms);
151-
const ruleIndex = new Map<string, Array<[Atom, Atom]>>();
152-
const varRules: Array<[Atom, Atom]> = [];
153-
for (const [lhs, rhs] of rules) {
149+
/** An empty environment for grounding table `gt`. Grow it with `addAtomToEnv`. */
150+
export function emptyEnv(gt: GroundingTable): MinEnv {
151+
return {
152+
ruleIndex: new Map(),
153+
varRules: [],
154+
sigs: new Map(),
155+
gt,
156+
atoms: [],
157+
types: new Map(),
158+
imports: new Map(),
159+
exprTypes: [],
160+
};
161+
}
162+
163+
/** Incorporate one atom into `env` (mutating): rule index, signatures, types, and the atom list.
164+
* Lets a sequential runner extend the env per atom instead of rebuilding it each query (Phase-15
165+
* optimization; the 270/270 oracle gates it). */
166+
export function addAtomToEnv(env: MinEnv, x: Atom): void {
167+
env.atoms.push(x);
168+
if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
169+
const lhs = x.items[1]!;
170+
const rhs = x.items[2]!;
154171
const k = headKey(lhs);
155-
if (k === undefined) varRules.push([lhs, rhs]);
172+
if (k === undefined) env.varRules.push([lhs, rhs]);
156173
else {
157-
const cur = ruleIndex.get(k) ?? [];
158-
cur.push([lhs, rhs]);
159-
ruleIndex.set(k, cur);
174+
const cur = env.ruleIndex.get(k);
175+
if (cur === undefined) env.ruleIndex.set(k, [[lhs, rhs]]);
176+
else cur.push([lhs, rhs]);
160177
}
161178
}
162-
const sigs = new Map<string, Atom[]>();
163-
const types = new Map<string, Atom[]>();
164-
const exprTypes: Array<[Atom, Atom]> = [];
165-
for (const x of atoms) {
166-
if (x.kind !== "expr" || opOf(x) !== ":" || x.items.length !== 3) continue;
179+
if (x.kind === "expr" && opOf(x) === ":" && x.items.length === 3) {
167180
const subj = x.items[1]!;
168181
const t = x.items[2]!;
169182
if (subj.kind === "sym") {
170-
if (opOf(t) === "->" && t.kind === "expr") sigs.set(subj.name, t.items.slice(1));
171-
types.set(subj.name, [...(types.get(subj.name) ?? []), t]);
183+
if (opOf(t) === "->" && t.kind === "expr") env.sigs.set(subj.name, t.items.slice(1));
184+
env.types.set(subj.name, [...(env.types.get(subj.name) ?? []), t]);
172185
} else if (subj.kind === "expr") {
173-
exprTypes.push([subj, t]);
186+
env.exprTypes.push([subj, t]);
174187
}
175188
}
176-
return { ruleIndex, varRules, sigs, gt, atoms, types, imports: new Map(), exprTypes };
189+
}
190+
191+
export function buildEnv(atoms: Atom[], gt: GroundingTable): MinEnv {
192+
const env = emptyEnv(gt);
193+
for (const x of atoms) addAtomToEnv(env, x);
194+
return env;
177195
}
178196

179197
function candidates(env: MinEnv, toEval: Atom): Array<[Atom, Atom]> {

packages/core/src/runner.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { type Atom, gint, gfloat, gbool } from "./atom";
55
import { Tokenizer } from "./tokenizer";
66
import { parseAll, format } from "./parser";
7-
import { type St, type MinEnv, buildEnv, initSt, mettaEval } from "./eval";
7+
import { type St, type MinEnv, buildEnv, addAtomToEnv, initSt, mettaEval } from "./eval";
88
import { stdTable } from "./builtins";
99
import { PRELUDE_SRC } from "./prelude";
1010

@@ -42,15 +42,17 @@ export function evalSequential(
4242
imports: Map<string, Atom[]> = new Map(),
4343
): QueryResult[] {
4444
const out: QueryResult[] = [];
45-
const kb: Atom[] = [];
4645
let st: St = initSt();
47-
const prelude = preludeAtoms();
46+
// Build the env once and extend it per non-bang atom (Phase-15 optimization: the old code
47+
// rebuilt the whole env on every query). Sequential semantics hold because each atom is added
48+
// before the queries that follow it. The 270/270 oracle gates this.
49+
const env: MinEnv = buildEnv([...preludeAtoms()], stdTable());
50+
env.imports = imports;
4851
for (const { atom, bang } of atoms) {
4952
if (!bang) {
50-
kb.push(atom);
53+
addAtomToEnv(env, atom);
5154
continue;
5255
}
53-
const env: MinEnv = { ...buildEnv([...prelude, ...kb], stdTable()), imports };
5456
const [pairs, st2] = mettaEval(env, fuel, st, [], atom);
5557
st = st2;
5658
out.push({ query: atom, results: pairs.map((p) => p[0]) });

0 commit comments

Comments
 (0)