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 · Timeout: 50.0 s · 📄 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 👍 4 ms (÷10) 52.3 MB (-22%)
sokonanoda 👍 4 ms (÷10) 46.1 MB (-32%)
nanoclo 👍 5 ms (÷9.6) 58.4 MB (-13%)
con-ron 👍 32 ms (-31%) 72.7 MB (+8%)
lazylean 👍 88 ms (+93%) 32.6 MB (÷2.1)
nanoda 👍 6 ms (÷7.1) 4.3 MB (÷16)
nanobruijn 👍 260 ms (×5.7) 62.8 MB (-7%)
con-leche 👍 16 ms (÷2.8) 30.0 MB (÷2.2)
eink0rn 👍 11 ms (÷4.0) 26.5 MB (÷2.5)
ind-models 👍 79 ms (+71%) 104.4 MB (+55%)
official 👍 46 ms (0%) 67.3 MB (0%)
lean4lean 👍 49 ms (+6%) 98.7 MB (+47%)
tenet 👍 151 ms (×3.3) 50.6 MB (-25%)
nanoclo-fortran 👍 13 ms (÷3.5) 7.6 MB (÷8.9)
lean4cobol 👍 143 ms (×3.1) 16.8 MB (÷4.0)
evmlean 👍 8.9 s (×194) 178.0 MB (×2.6)
mini 👍 1.8 s (×40) 70.7 MB (+5%)
overfull 💥 1.7 m 49.2 MB
kiota 👍 3.5 s (×77) 384.6 MB (×5.7)
canonical-min 👍 407 ms (×8.9) 1.1 GB (×16)
rpylean 👍 6 ms (÷7.1) 14.4 MB (÷4.7)
vow-lean-kernel 👍 317 ms (×6.9) 12.2 MB (÷5.5)
official-v4.28.0 👍 55 ms (+19%) 74.9 MB (+11%)
still-nanoda 👍 7 ms (÷7.0) 4.3 MB (÷16)
nyaya 👍 32 ms (-30%) 14.6 MB (÷4.6)
parse-only 👍 41 ms (-10%) 67.1 MB (0%)