lean4-htt/tests/lean/run/4928.lean
Joachim Breitner f9dc77673b
feat: dedicated fix operator for well-founded recursion on Nat (#7965)
This PR lets recursive functions defined by well-founded recursion use a
different `fix` function when the termination measure is of type `Nat`.
This fix-point operator use structural recursion on “fuel”, initialized
by the given measure, and is thus reasonable to reduce, e.g. in `by
decide` proofs.

Extra provisions are in place that the fixpoint operator only starts
reducing when the fuel is fully known, to prevent “accidential” defeqs
when the remaining fuel for the recursive calls match the initial fuel
for that recursive argument.

To opt-out, the idiom `termination_by (n,0)` can be used.

We still use `@[irreducible]` as the default for such recursive
definitions, to avoid unexpected `defeq` lemmas. Making these functions
`@[semireducible]` by default showed performance regressions in lean.
When the measure is of type `Nat`, the system will accept an explicit
`@[semireducible]` without the usual warning.

Fixes #5234. Fixes: #11181.
2025-12-01 12:51:55 +00:00

61 lines
1.3 KiB
Text

/--
error: Failed: `fail` tactic was invoked
z : Nat
⊢ z - 1 < z
-/
#guard_msgs in
def g (z : Nat) (y : Nat) : Nat := g (z - 1) y
termination_by z
decreasing_by fail
/--
error: Failed: `fail` tactic was invoked
x : List Nat
⊢ sizeOf x.tail < sizeOf x
-/
#guard_msgs in
def h (x : List Nat) (y : Nat) : Nat := h x.tail y
termination_by x
decreasing_by fail
/--
error: Failed: `fail` tactic was invoked
x : List Nat
⊢ x.tail.length < x.length
-/
#guard_msgs in
def f (x : List Nat) (y : Nat) : Nat := f x.tail y
termination_by x.length
decreasing_by fail
/--
error: Failed: `fail` tactic was invoked
x : List Nat
⊢ x.tail.length < x.length
-/
#guard_msgs in
mutual
def f1 (x : List Nat) (y : Nat) : Nat := f2 x.tail y
termination_by x.length
decreasing_by fail
def f2 (x : List Nat) (y : Nat) : Nat := f1 x.tail y
termination_by x.length
decreasing_by fail
end
/--
error: Failed: `fail` tactic was invoked
x : List Nat
⊢ InvImage (fun x1 x2 => x1 < x2) (fun x => PSum.casesOn x (fun x => x.length) fun x => x.length) (PSum.inr x.tail)
(PSum.inl x)
-/
#guard_msgs in
set_option debug.rawDecreasingByGoal true in
mutual
def g1 (x : List Nat) (y : Nat) : Nat := g2 x.tail y
termination_by x.length
decreasing_by fail
def g2 (x : List Nat) (y : Nat) : Nat := g1 x.tail y
termination_by x.length
decreasing_by fail
end