Zulip Chat Archive

Stream: general

Topic: Well-founded induction with ENat


Peter Nelson (Jul 11 2023 at 12:52):

I'm having trouble getting well-founded induction (with decreasing_by) working with ENat. Here is a MWE

import Mathlib.Data.ENat.Basic

-- this easy lemma is provable by well-founded induction
theorem wf1 (P :   Prop) (h0 : P 0) (h :  k, 0 < k   t, t < k  (P t  P k)) (n : ) :
    P n := by
  refine' WellFounded.induction (r := (· < ·)) IsWellFounded.wf _ (fun x h'  _)
  obtain ((rfl : x = 0) | hpos) := eq_zero_or_pos
  · exact h0
  obtain t, ht, hPt := h x hpos
  exact hPt (h' _ ht)

-- Same lemma statement; this time, we try to prove it by invoking itself on a smaller value.
theorem wf2 (P :   Prop) (h0 : P 0) (h :  k, 0 < k   t, t < k  (P t  P k)) (n : ) :
    P n := by
  obtain ((rfl : n = 0) | hn) := eq_zero_or_pos
  · exact h0
  obtain t, ht, hPt := h n hn
  -- (`ht : t < n`) is in context, so we should be able to invoke wf2 on `t`
  exact hPt (wf2 P h0 h t)
  -- doesn't work - so explicitly give `termination_by` and `decreasing_by`
termination_by _ => n
decreasing_by
  simp_wf
  -- goal should simplify to `t < n`, but instead simplifies to `False` ??

It seems that the well-founded relation is unfolding to something trivial rather than < as it should; but I don't understand why.

Arthur Adjedj (Jul 11 2023 at 14:03):

The issue is that the well-founded relation that's inferred by termination_by is the wrong one, autogenerated using SizeOf. Using the correct measure solves the issue:

import Mathlib.Data.ENat.Basic
import Mathlib.Data.Nat.Cast.WithTop
theorem wf2 (P :   Prop) (h0 : P 0) (h :  k, 0 < k   t, t < k  (P t  P k)) (n : ) :
    P n := by
  obtain ((rfl : n = 0) | hn) := eq_zero_or_pos
  · exact h0
  have t, ht, hPt := h n hn
  exact hPt (wf2 P h0 h t)
termination_by' instWellFoundedRelationWithTopNat
decreasing_by {
  exact ht
}

Peter Nelson (Jul 11 2023 at 15:33):

Thank you! I didn't know about termination_by'; are there docs for the primed version anywhere?

Matthew Ballard (Jul 11 2023 at 15:37):

https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Help.20with.20termination_by/near/368743246 (and continuing discussion) is relevant.

Gabriel Ebner (Jul 11 2023 at 16:53):

You should add a WellFoundedRelation ENat instance, then this will work as expected:

import Mathlib.Data.ENat.Basic
import Mathlib.Data.Nat.Cast.WithTop

instance : WellFoundedRelation ENat where
  rel := (· < ·)
  wf := IsWellFounded.wf

theorem wf2 (P :   Prop) (h0 : P 0) (h :  k, 0 < k   t, t < k  (P t  P k)) (n : ) :
    P n := by
  obtain ((rfl : n = 0) | hn) := eq_zero_or_pos
  · exact h0
  have t, _ht, hPt := h n hn
  exact hPt (wf2 P h0 h t)
termination_by _ => n

Last updated: Dec 20 2023 at 11:08 UTC