Closed nomeata closed 1 week ago
Mathlib CI status (docs):
Whoohoo, mathlib is green!
After having discussed this with Leo, I will move forward with this approach.
We can reduce the impact on mathlib (seen here) by rewriting some functions using structural recursion (I’m looking at you, Array.ofFn.go
and Nat.modCore
), but that can happen in separate PRs.
Another possible way to reduce the impact a bit is if the decides
tactics reduces more aggressively by default.
The PR says "by default". Is there a way to change the default for a given definition? Is slapping @[semireducible]
on the definition sufficient?
Perhaps rebase now that #4053 is in a nightly? Not essential.
No need to rebase for that, the diff will simply disappear if there is no conflict.
I plan to merge this once https://github.com/leanprover/lean4/pull/4098 and https://github.com/leanprover-community/batteries/pull/784 have landed.
I should trigger a stage0 update right afterwards, else it won’t have an effect on the released stdlib.
we keep running into examples where working with well-founded recursion is slow because defeq checks (which are all over the place, including failing ones that are back-tracked) unfold well-founded definitions.
The definition of a function defined by well-founded recursion should be an implementation detail that should only be peeked inside by the equation generator and the functional induction generator.
We now mark the mutual recursive function as irreducible (if the user did not set a flag explicitly), and use
withAtLeastTransparency .all
when producing the equations.Proofs can be fixed by using rewriting, or – a bit blunt, but nice for adjusting existing proofs – using
unseal
(a.k.a.attribute [local semireducible]
).Mathlib performance does not change a whole lot: http://speed.lean-fro.org/mathlib4/compare/08b82265-75db-4a28-b12b-08751b9ad04a/to/16f46d5e-28b1-41c4-a107-a6f6594841f8 Build instructions -0.126 %, four modules with significant instructions decrease.
To reduce impact, these definitions were changed:
Nat.mod
, to make1 % n
reduce definitionally, so that1
as aFin 2
literal works nicely. Theorems with largerFin
literals tend to need aunseal Nat.modCore
https://github.com/leanprover/lean4/pull/4098List.ofFn
rewritten to be structurally recursive and not go viaArray.ofFn
: https://github.com/leanprover-community/batteries/pull/784Alternative designs explored were
Making
WellFounded.fix
irreducible.One benefit is that recursive functions with equal definitions (possibly after instantiating fixed parameters) are defeq; this is used in mathlib to relate
OrdinalApprox.gfpApprox
with.lfpApprox
.But the downside is that one cannot use
unseal
in a targeted way, being explicit in which recursive function needs to be reducible here.And in cases where Lean does unwanted unfolding, we’d still unfold the recursive definition once to expose
WellFounded.fix
, leading to large terms for often no good reason.Defining
WellFounded.fix
to unroll defintionally once before hitting a irreducibleWellFounded.fixF
. This was explored in #4002. It shares most of the ups and downs with the previous variant, with the additional neat benefit that function calls that do not lead to recursive cases (e.g. a[]
base case) reduce nicely. This means that the majority of existingrfl
proofs continue to work.Issue #4051, which demonstrates how badly things can go if wf recursive functions can be unrolled, showed that making the recursive function irreducible there leads to noticeably faster elaboration than making
WellFounded.fix
irreducible; this is good evidence that the present PR is the way to go.This fixes https://github.com/leanprover/lean4/issues/3988