Lean Kernel Arena / perf/shift-cascade

Test "perf/shift-cascade"

Expected: 👍 accept · Size: 256.3 KB · Lines: 5.1 k · lean4export: 3.1.0 · Lean: 4.29.1 · 📄 Declaration · 🔗 Source

Stress test for cascading substitution overhead in kernel let processing.

N nested let bindings inside a lambda, where each value references the outer lambda parameter and the previous binding:

fun (a : Nat → Nat) => let f₁ := fun x => a x let f₂ := fun x => a (f₁ x) ... let fₙ := fun x => a (fₙ₋₁ x) fₙ 0

The kernel processes each let by substituting the value into the body. Each value has a free bvar (references a), so substitution under inner binders creates shifted copies. In a de Bruijn kernel with deferred shifts, these Shift(val, offset) wrappers accumulate: step k must traverse through O(k) wrappers from previous steps, giving O(N²) total work.

A locally-nameless kernel substitutes fvars that need no shifting, giving O(N) total.

N=1000 in the Lean source. Increase to stress further.

Checker Result ⏱️ 🧠
mathgraph 👍 3 ms (÷17) 46.4 MB (-27%)
ind-models 👍 79 ms (+70%) 101.7 MB (+59%)
official-nightly 👍 46 ms (0%) 66.2 MB (+3%)
evmlean 👍 8.9 s (×193) 188.9 MB (×3.0)
nanoda 👍 7 ms (÷7.1) 4.2 MB (÷15)
mini 👍 1.8 s (×40) 70.1 MB (+10%)
lean4lean 👍 49 ms (+5%) 96.0 MB (+50%)
sokonanoda 👍 3 ms (÷17) 46.4 MB (-27%)
zignodamus 👍 3 ms (÷17) 7.2 MB (÷8.8)
nanoclo 👍 5 ms (÷9.5) 64.4 MB (+1%)
nanobruijn 👍 164 ms (×3.6) 41.5 MB (-35%)
kiota 👍 1.1 s (×23) 462.3 MB (×7.2)
official 👍 46 ms (0%) 63.9 MB (0%)
vow-lean-kernel 👍 317 ms (×6.9) 11.8 MB (÷5.4)
rpylean 👍 7 ms (÷6.9) 18.2 MB (÷3.5)
official-v4.28.0 👍 55 ms (+18%) 75.1 MB (+17%)
still-nanoda 👍 6 ms (÷7.1) 4.0 MB (÷16)
nyaya 👍 32 ms (-31%) 15.0 MB (÷4.3)
parse-only 👍 41 ms (-10%) 64.0 MB (0%)