Skip to content

IxVM def-eq: rebase open pairs to their minimum loose index - #546

Open
arthurpaulino wants to merge 1 commit into
mainfrom
ap/ixvm
Open

IxVM def-eq: rebase open pairs to their minimum loose index#546
arthurpaulino wants to merge 1 commit into
mainfrom
ap/ixvm

Conversation

@arthurpaulino

Copy link
Copy Markdown
Member

Algebra.kerTensorProductMapIdToAlgHomEquiv._proof_1 (mathlib) never finished: not in 300s natively, against 593ms for the reference kernel on the same subject. Instrumenting both kernels showed the pair space was NOT the problem — IxVM visits 15,085 distinct (a,b) pairs against the reference's 5,941 — but each pair was being recomputed once per context spelling: 2.48M distinct (a,b,types) def-eq keys, 164x per pair, and the whole delta cascade re-ran under each key (26.1M delta unfolds against the reference's 11,544, concentrated on the DFunLike.coe / *.toFun instance-projection towers).

The prefix trim cannot canonicalize these pairs. The proof binds its section variables (types, rings, instances) OUTERMOST, so a tower pair under the inner binders has a loose range spanning the whole context; the trim keeps every inner frame, and every comparison site spells those (unreferenced) inner frames differently. The reference is immune because its def-eq opens binders with fvars: compared bodies have lbr = 0 and its context key collapses to empty, so tower obligations cache on content alone.

Fix, the de Bruijn equivalent of that key insensitivity: g = min of the two sides' minimum loose indices — no loose BVar below g exists in either side, so lowering both by g and dropping the g innermost frames is a bijection on derivations (context strengthening by unreferenced frames, the same argument as the existing base=0 -> Nil arm). Def-eq returns a bit, so nothing lifts back, and one edit site covers every downstream circuit. Depth-shifted copies of the same tower also lower to the same hash-consed pair, merging pairs across binder depths. New expr_glb (memoized min-loose-index with an lbr fast path) supports it; the lowering is the pre-existing expr_lower.

A depth threshold (rebase only past base > 8) was measured and rejected: it recovered only a third of the overhead on binder-heavy Init proofs for no gain on the mathlib constant.

Measured: the constant's subject-only check completes in 13s (4.7e10 FFT) where it previously never terminated, and its FULL 8,753-constant closure now checks in 77s. All 34 previously-fixed mathlib constants pass full-closure in 40s total. Guard set flat: goCache_Inv_of_Inv 112s, goCache.eq_def 42s, ofBitVec_not 3s, ofDays 6s. Both suites green. Pins re-harvested: +0.0% to +6.4% (the worst are binder-heavy proofs paying the glb walk with nothing to rebase — the price of the unconditional form). New pinned fixture deepRebase minimizes the outer-reference telescope shape.

`Algebra.kerTensorProductMapIdToAlgHomEquiv._proof_1` (mathlib) never
finished: not in 300s natively, against 593ms for the reference kernel
on the same subject. Instrumenting both kernels showed the pair space
was NOT the problem — IxVM visits 15,085 distinct (a,b) pairs against
the reference's 5,941 — but each pair was being recomputed once per
context spelling: 2.48M distinct (a,b,types) def-eq keys, 164x per
pair, and the whole delta cascade re-ran under each key (26.1M delta
unfolds against the reference's 11,544, concentrated on the
DFunLike.coe / *.toFun instance-projection towers).

The prefix trim cannot canonicalize these pairs. The proof binds its
section variables (types, rings, instances) OUTERMOST, so a tower pair
under the inner binders has a loose range spanning the whole context;
the trim keeps every inner frame, and every comparison site spells
those (unreferenced) inner frames differently. The reference is immune
because its def-eq opens binders with fvars: compared bodies have
lbr = 0 and its context key collapses to empty, so tower obligations
cache on content alone.

Fix, the de Bruijn equivalent of that key insensitivity: `g = min` of
the two sides' minimum loose indices — no loose BVar below `g` exists
in either side, so lowering both by `g` and dropping the `g` innermost
frames is a bijection on derivations (context strengthening by
unreferenced frames, the same argument as the existing base=0 -> Nil
arm). Def-eq returns a bit, so nothing lifts back, and one edit site
covers every downstream circuit. Depth-shifted copies of the same
tower also lower to the same hash-consed pair, merging pairs across
binder depths. New `expr_glb` (memoized min-loose-index with an lbr
fast path) supports it; the lowering is the pre-existing `expr_lower`.

A depth threshold (rebase only past base > 8) was measured and
rejected: it recovered only a third of the overhead on binder-heavy
Init proofs for no gain on the mathlib constant.

Measured: the constant's subject-only check completes in 13s (4.7e10
FFT) where it previously never terminated, and its FULL 8,753-constant
closure now checks in 77s. All 34 previously-fixed mathlib constants
pass full-closure in 40s total. Guard set flat: goCache_Inv_of_Inv
112s, goCache.eq_def 42s, ofBitVec_not 3s, ofDays 6s. Both suites
green. Pins re-harvested: +0.0% to +6.4% (the worst are binder-heavy
proofs paying the glb walk with nothing to rebase — the price of the
unconditional form). New pinned fixture `deepRebase` minimizes the
outer-reference telescope shape.
@arthurpaulino
arthurpaulino enabled auto-merge (squash) August 11, 2026 01:02
@arthurpaulino

Copy link
Copy Markdown
Member Author

!benchmark aiur fresh

@argument-ci-bot

argument-ci-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

!benchmark — main vs fde291e

backends: aiur=prove · envs: InitStd · set: primary · shard: 0 · baseline: fresh (base-SHA run, bencher bypassed)

aiur · InitStd · prove — main from: base run @ fc4f43a (fresh — bencher bypassed)

13 constants · 9 with regressions · 6 with improvements (|Δ| > 3.0% on any metric).

comparison table (13 constants)
constant prove-time (main) prove-time (PR) Δ% throughput (const/s) (main) throughput (const/s) (PR) Δ% peak-ram (main) peak-ram (PR) Δ% execute-time (main) execute-time (PR) Δ% verify-time (main) verify-time (PR) Δ% proof-size (main) proof-size (PR) Δ% fft-cost (main) fft-cost (PR) Δ%
ByteArray.utf8DecodeChar?_utf8EncodeChar_append 46.915 s 43.943 s -6.3% (1.07× faster) 🟢 57.360 61.240 +6.8% (1.07× faster) 🟢 99.73 GiB 94.54 GiB -5.2% (1.05× smaller) 🟢 11.867 s 10.507 s -11.5% (1.13× faster) 🟢 133.2 ms 134.5 ms +1.0% 22.13 MiB 22.32 MiB +0.9% 199.20B 188.89B -5.2% (1.05× fewer) 🟢
Array.extract_append 46.431 s 43.562 s -6.2% (1.07× faster) 🟢 33.210 35.400 +6.6% (1.07× faster) 🟢 89.12 GiB 84.52 GiB -5.2% (1.05× smaller) 🟢 12.063 s 10.323 s -14.4% (1.17× faster) 🟢 218.4 ms 134.4 ms -38.5% (1.63× faster) 🟢 22.05 MiB 22.22 MiB +0.8% 179.21B 158.39B -11.6% (1.13× fewer) 🟢
Char.ofOrdinal_le_of_le 34.636 s 32.892 s -5.0% (1.05× faster) 🟢 76.390 80.440 +5.3% (1.05× faster) 🟢 72.76 GiB 69.49 GiB -4.5% 🟢 7.777 s 7.407 s -4.8% 🟢 166.6 ms 144.5 ms -13.3% (1.15× faster) 🟢 22.10 MiB 22.27 MiB +0.8% 142.15B 136.46B -4.0% 🟢
Vector.extract_append._proof_2 27.320 s 23.621 s -13.5% (1.16× faster) 🟢 47.660 55.120 +15.7% (1.16× faster) 🟢 56.16 GiB 45.16 GiB -19.6% (1.24× smaller) 🟢 6.630 s 5.683 s -14.3% (1.17× faster) 🟢 131.0 ms 139.1 ms +6.1% (1.06× slower) ⚠️ 21.84 MiB 21.93 MiB +0.4% 105.40B 93.15B -11.6% (1.13× fewer) 🟢
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq 20.789 s 20.652 s -0.7% 87.160 87.740 +0.7% 45.77 GiB 45.46 GiB -0.7% 4.063 s 3.933 s -3.2% 🟢 130.5 ms 142.1 ms +8.9% (1.09× slower) ⚠️ 21.94 MiB 22.11 MiB +0.8% 77.70B 77.07B -0.8%
String.split 19.597 s 19.818 s +1.1% 90.060 89.060 -1.1% 43.53 GiB 43.37 GiB -0.4% 3.652 s 3.686 s +0.9% 137.0 ms 144.7 ms +5.6% (1.06× slower) ⚠️ 22.14 MiB 22.31 MiB +0.8% 69.78B 69.93B +0.2%
List.mergeSort 13.637 s 13.794 s +1.2% 106.180 104.970 -1.1% 28.73 GiB 29.08 GiB +1.2% 2.725 s 2.708 s -0.6% 141.1 ms 137.5 ms -2.5% 21.99 MiB 22.16 MiB +0.8% 51.10B 51.50B +0.8%
Vector.append 4.245 s 4.447 s +4.8% ⚠️ 114.260 109.060 -4.6% ⚠️ 7.74 GiB 7.86 GiB +1.5% 704.7 ms 732.1 ms +3.9% ⚠️ 126.0 ms 131.5 ms +4.4% ⚠️ 20.50 MiB 20.69 MiB +0.9% 10.77B 11.35B +5.4% (1.05× more) ⚠️
Nat.gcd_comm 3.543 s 3.671 s +3.6% ⚠️ 110.070 106.240 -3.5% ⚠️ 6.85 GiB 7.28 GiB +6.4% (1.06× larger) ⚠️ 564.4 ms 593.8 ms +5.2% (1.05× slower) ⚠️ 119.7 ms 130.0 ms +8.6% (1.09× slower) ⚠️ 20.27 MiB 20.44 MiB +0.8% 7.86B 8.03B +2.3%
String.append 2.521 s 2.628 s +4.3% ⚠️ 120.610 115.680 -4.1% ⚠️ 4.76 GiB 4.81 GiB +1.0% 421.1 ms 429.9 ms +2.1% 116.9 ms 117.1 ms +0.2% 19.51 MiB 19.70 MiB +1.0% 4.31B 4.43B +2.8%
Int.gcd 2.103 s 2.186 s +4.0% ⚠️ 98.890 95.130 -3.8% ⚠️ 5.65 GiB 5.64 GiB -0.1% 362.4 ms 366.9 ms +1.2% 123.4 ms 119.6 ms -3.1% 🟢 19.07 MiB 19.24 MiB +0.9% 2.78B 2.85B +2.5%
Nat.sub_le_of_le_add 1.935 s 2.004 s +3.6% ⚠️ 87.860 84.820 -3.5% ⚠️ 5.45 GiB 5.48 GiB +0.5% 366.5 ms 364.2 ms -0.6% 118.0 ms 116.4 ms -1.4% 19.43 MiB 19.60 MiB +0.9% 2.37B 2.43B +2.5%
Nat.add_comm 1.077 s 1.093 s +1.4% 38.990 38.440 -1.4% 3.53 GiB 4.28 GiB +21.2% (1.21× larger) ⚠️ 258.3 ms 262.4 ms +1.6% 103.5 ms 104.5 ms +0.9% 17.58 MiB 17.75 MiB +1.0% 400.49M 404.01M +0.9%

Workflow logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant