Skip to content

Commit 9ceea68

Browse files
committed
IxVM: context-suffix memo keys for closed terms + drop dead KValNode
Two changes to the Aiur kernel core, both behavior-preserving. Closed-term context normalization in whnf / k_infer / k_is_def_eq: a closed term (`expr_lbr(e) == 0`) reads nothing from the local binder-type context `types` — its only reader, `types_lookup`, is reached via a `BVar` lookup, which a closed term has none of. So the result is independent of `types`; collapse it to `Nil`. The same closed subterm appearing under different binder depths then shares one memo key `(e, Nil, top, addrs)` instead of missing on a per-depth `types`, so Aiur's content-memoization reuses it. Open terms keep their real context. Sound: a closed term reduces and infers only over closed subterms. Remove the dead `KValNode`/`KVal`/`KValEnv` NbE value domain: defined but referenced nowhere (the live kernel runs on de-Bruijn `KExpr`); vestigial from an abandoned NbE direction. Measured with `ix check --ixe arena.ixe --claim <CheckEnv-digest>` over the TutorialDefs arena (694 consts): 7,159,028,984 -> 7,151,454,776 FFT (-0.11%). `lake test -- --ignored ixvm`: 297 pass, 0 fail. (The closed-term win is larger on a faster ingress base, where the kernel core is a bigger share of total.)
1 parent 3fe83fe commit 9ceea68

4 files changed

Lines changed: 26 additions & 30 deletions

File tree

Ix/IxVM/Kernel/DefEq.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ def defEq := ⟦
3939
-- ============================================================================
4040
fn k_is_def_eq(a: KExpr, b: KExpr, types: List‹KExpr›,
4141
top: List‹&KConstantInfo›, addrs: List‹Addr›) -> G {
42+
-- When both sides are closed, the context can't affect the result;
43+
-- collapse it so closed comparisons share a memo key across contexts.
44+
-- `expr_lbr >= 0`, so the sum is 0 iff both sides are closed.
45+
let lbr = expr_lbr(a) + expr_lbr(b);
46+
let types = match lbr {
47+
0 => store(ListNode.Nil),
48+
_ => types,
49+
};
4250
-- Tier 1: pointer equality short-circuit.
4351
match ptr_val(a) - ptr_val(b) {
4452
0 => 1,

Ix/IxVM/Kernel/Infer.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ def infer := ⟦
5454
-- ============================================================================
5555
fn k_infer(e: KExpr, types: List‹KExpr›,
5656
top: List‹&KConstantInfo›, addrs: List‹Addr›) -> KExpr {
57+
-- Closed terms don't depend on the local context: collapse it so the
58+
-- same closed subterm under different binder depths shares a memo key.
59+
let lbr = expr_lbr(e);
60+
let types = match lbr {
61+
0 => store(ListNode.Nil),
62+
_ => types,
63+
};
5764
match load(e) {
5865
KExprNode.BVar(i) => types_lookup(types, i),
5966

Ix/IxVM/Kernel/Whnf.lean

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,17 @@ def whnf := ⟦
224224
KExprNode.Forall(_, _) => e,
225225
KExprNode.BVar(_) => e,
226226
_ =>
227-
let pair = collect_spine(e);
228-
match pair {
229-
(head, spine) => whnf_with_spine(head, spine, types, top, addrs),
227+
-- Closed-term context normalization: when `e` has no loose BVars,
228+
-- whnf's result cannot depend on `types` (every spine major is
229+
-- closed, so the `k_infer`/`is_prop_type` calls in the struct-iota
230+
-- path never hit a BVar). Pass `Nil` so the same closed term whnf'd
231+
-- under different contexts shares one memo key
232+
-- `(head, spine, Nil, top, addrs)` -> cache hits. Open `e` keeps its
233+
-- real context. Sound: a closed term reduces only to closed terms.
234+
let (head, spine) = collect_spine(e);
235+
match expr_lbr(e) {
236+
0 => whnf_with_spine(head, spine, store(ListNode.Nil), top, addrs),
237+
_ => whnf_with_spine(head, spine, types, top, addrs),
230238
},
231239
}
232240
}

Ix/IxVM/KernelTypes.lean

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,33 +50,6 @@ def kernelTypes := ⟦
5050

5151
type KExpr = &KExprNode
5252

53-
-- ============================================================================
54-
-- Values (NbE semantic domain)
55-
-- ============================================================================
56-
57-
enum KValNode {
58-
Srt(&KLevel),
59-
Lit(KLiteral),
60-
Lam(KVal, KExpr, KValEnv),
61-
Pi(KVal, KExpr, KValEnv),
62-
Ctor(G, List‹&KLevel›, G, List‹KVal›),
63-
FVar(G, KVal, List‹KVal›),
64-
Axiom(G, List‹&KLevel›, List‹KVal›),
65-
Defn(G, List‹&KLevel›, List‹KVal›),
66-
Thm(G, List‹&KLevel›, List‹KVal›),
67-
Opaque(G, List‹&KLevel›, List‹KVal›),
68-
Quot(G, List‹&KLevel›, List‹KVal›),
69-
Induct(G, List‹&KLevel›, List‹KVal›),
70-
Rec(G, List‹&KLevel›, List‹KVal›),
71-
Proj(G, G, KVal, List‹KVal›),
72-
Thunk(KExpr, KValEnv)
73-
}
74-
75-
type KVal = &KValNode
76-
77-
-- Value environment (de Bruijn indexed, front = most recent binder)
78-
type KValEnv = List‹KVal›
79-
8053
-- ============================================================================
8154
-- Recursor Rule
8255
--

0 commit comments

Comments
 (0)