Zulip Chat Archive

Stream: mathlib4

Topic: doing induction


Antoine Chambert-Loir (Aug 30 2024 at 17:40):

Imagine I want to prove a property of x : A, and I have a function f : A -> B, where B is well ordered. Can I do it by induction, thanks to some ‘termination-by‘ stuff? But I can't understand what I need to fill in. (This is to prove 'euclDivd‘ in branch#ACL/CombNS)

Antoine Chambert-Loir (Aug 30 2024 at 17:54):

A mwe could be

 import Init.WF

theorem hasP (A B : Type) (r : B  B  Prop) (hr : WellFounded r)
    (f : A  B) (P : A  Prop)  (a : A) : P a := by
  sorry

where, in the proof, I only apply hasP to elements b : A such that r b a.

Bjørn Kjos-Hanssen (Aug 30 2024 at 18:17):

The mwe theorem is false (P could be fun a => False)...?

Giacomo Stevanato (Aug 30 2024 at 18:24):

Have you seen WellFounded.induction?

I guess in your mwe you meant P and f to not be part of the theorem and instead something you defined yourself?

Edward van de Meent (Aug 30 2024 at 18:28):

i'd guess you need a statement saying that r is wellfounded on the range of f, along with a statement like wf_hyp : ∀ a, (∀ a', r (f a') (f a) → P a') → P a

Edward van de Meent (Aug 30 2024 at 18:29):

i think the first part is easily satisfied if r is a transitive relation?

Edward van de Meent (Aug 30 2024 at 18:29):

i'm not very sure though

Johan Commelin (Aug 30 2024 at 19:03):

You can indeed use termination by.
So just write the proof as usual, and put a sorry to get rid of the termination goal. Then focus on it separately when you are done

Johan Commelin (Aug 30 2024 at 19:04):

You can also use decreasing_by to apply your f

Antoine Chambert-Loir (Aug 31 2024 at 09:46):

Giacomo Stevanato said:

Have you seen WellFounded.induction?

I guess in your mwe you meant P and f to not be part of the theorem and instead something you defined yourself?

In my not minimal example (see branch#ACL/CombNS), fis a multivariate polynomial and P is a complicated property, so docs#WellFounded.induction does not immediately apply. Of course, I could set up some induction procedure, but my point was to have it on the spot, just having a function applying itself recursively, while checking that the things I apply it to are always strictly smaller than my initial stuff.

Giacomo Stevanato (Aug 31 2024 at 13:07):

Antoine Chambert-Loir said:

fis a multivariate polynomial and P is a complicated property, so docs#WellFounded.induction does not immediately apply.

I'm not sure why you think that is the case. From a quick glance it seems you should be able to apply it right after creating the instance of the well-founded relation.

Violeta Hernández (Aug 31 2024 at 13:08):

Sometimes induction lemmas don't like playing nice with apply, so you might want to use the induction or refine tactics with them instead.

Giacomo Stevanato (Aug 31 2024 at 13:09):

This seems to work for me:

diff --git a/Mathlib/Combinatorics/Nullstellensatz.lean b/Mathlib/Combinatorics/Nullstellensatz.lean
index 5b39e4d..18410f3 100644
--- a/Mathlib/Combinatorics/Nullstellensatz.lean
+++ b/Mathlib/Combinatorics/Nullstellensatz.lean
@@ -624,9 +624,11 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
       (∀ i, (h i * (S i).prod (fun (s : R) ↦ (X i - C s))).totalDegree ≤ f.totalDegree) ∧
       (∀ i, r.weightedTotalDegree (Finsupp.single i 1) < (S i).card) := by
   letI : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder
-  haveI wfr : WellFoundedRelation (MvPolynomial σ R) := {
+  let wfr : WellFoundedRelation (MvPolynomial σ R) := {
     rel := Function.onFun (· < ·) fun f ↦ f.lexHomDegree
     wf := WellFounded.onFun wellFounded_lt }
+  apply wfr.wf.induction f
+  intro f h_ind
   by_cases hD0 : f.lexHomDegree = ⊥
   · use fun _ ↦ 0, f
     rw [lexHomDegree_eq_bot_iff] at hD0
@@ -663,7 +665,7 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
       rw [lt_iff_le_and_ne, ← hd]
       exact ⟨le_lexHomDegree hc.2, fun h ↦ hc.1 (toLexHom.injective h)⟩
     · exact Ne.bot_lt' fun a ↦ hD0 a.symm
-  obtain ⟨h', r', Hf', Hh', Hr'⟩ := euclDivd S Sne f' -- hf'D
+  obtain ⟨h', r', Hf', Hh', Hr'⟩ := h_ind f' hf'D
   by_cases H : ∀ i, d i < (S i).card
   · -- First case, the monomial `d` is small, we just add it to the remainder
     use h', r' + monomial d (f.coeff d)
@@ -782,7 +784,7 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
       left
       simp only [lexHomDegree_degree]
       exact hf''_degree
-    obtain ⟨h'', r'', Hf'', Hh'', Hr''⟩ := euclDivd S Sne f'' -- hf''2
+    obtain ⟨h'', r'', Hf'', Hh'', Hr''⟩ := h_ind f'' hf''2
     use h' + h'' + single i (monomial d' (f.coeff d)), r' + r''
     constructor
     · nth_rewrite 1 [hf, Hf', hf'', Hf'']

Antoine Chambert-Loir (Aug 31 2024 at 13:12):

A similar thing worked for me as well (see commented out code just below), but I expected to be able to do it differently, by using directly the function on smaller arguments.

Violeta Hernández (Aug 31 2024 at 13:13):

FYI WellFoundedRelation is probably not what you want to be using. The purpose of that typeclass is to establish a default well-founded relation for the termination checker whenever you're working with a certain type. If you just want a well-founded predicate you can use WellFounded, and if you want a bundled version that works with typeclass inference you can use IsWellFounded or something stronger like WellFoundedLT or IsWellOrder.

Antoine Chambert-Loir (Aug 31 2024 at 13:25):

I had used IsWellFounded but devised an additional induction theorem for docs#MvPolynomial for lexicographic order (see the commented out proof of euclDivd in the branch). My question (sorry if I didn't make myself clearer) came out of wondering whether this additional theorem was indeed necessary or if it is possible to prove a theorem directly along the lines of the current attempt.
Maybe the difficulty is that I use the function twice, for two different arguments f' and f'', each of them smaller than the initial one. Possibly, terminating_by doesn't understand what I need.

By the way, the error message is

Not considering parameter R of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Not considering parameter #2 of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Not considering parameter σ of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Not considering parameter #4 of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Not considering parameter S of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Not considering parameter Sne of MvPolynomial.euclDivd:
  it is unchanged in the recursive calls
Cannot use parameter f:
  the type (σ →₀ ) →₀ R does not have a `.brecOn` recursor


Could not find a decreasing measure.
The arguments relate at each recursive call as follows:
(<, , =: relation proved, ? all proofs failed, _: no proof attempted)

1) 666:36-53
2) 785:43-61
Please use `termination_by` to specify a decreasing measure.

and the decreasing measures are proved in hf'D : f'.lexHomDegree < f.lexHomDegree (just before line 666) and hf''2 : f''.lexHomDegree < f.lexHomDegree (just before line 785). In both cases, MvPolynomial.lexHomDegree is a function from MvPolynomial α R to a type synonym LexHom (α →₀ N) of monomials α →₀ N but endowed with a well ordering (see instance on line 199, WellFoundedLT (LexHom (α →₀ N)).

Giacomo Stevanato (Aug 31 2024 at 13:51):

I believe you need to use WellFounded.wrap to use an arbitrary WellFounded relation with termination_by (or add an instance for that WellFoundedRelation outside the theorem, but this should be cleaner):

diff --git a/Mathlib/Combinatorics/Nullstellensatz.lean b/Mathlib/Combinatorics/Nullstellensatz.lean
index 5b39e4d..eb0ef5b 100644
--- a/Mathlib/Combinatorics/Nullstellensatz.lean
+++ b/Mathlib/Combinatorics/Nullstellensatz.lean
@@ -618,15 +618,13 @@ lemma prod_totalDegree [Nontrivial R] {ι : Type*} (i : ι) (s : Finset R) :
   rw [mem_support_iff, prod_leadCoeff]
   exact one_ne_zero

+noncomputable instance : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder
+
 theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPolynomial σ R) :
     ∃ (h : σ → MvPolynomial σ R) (r : MvPolynomial σ R),
       f = Finset.univ.sum (fun i => (h i) * (S i).prod (fun (s : R) ↦ (X i - C s))) + r ∧
       (∀ i, (h i * (S i).prod (fun (s : R) ↦ (X i - C s))).totalDegree ≤ f.totalDegree) ∧
       (∀ i, r.weightedTotalDegree (Finsupp.single i 1) < (S i).card) := by
-  letI : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder
-  haveI wfr : WellFoundedRelation (MvPolynomial σ R) := {
-    rel := Function.onFun (· < ·) fun f ↦ f.lexHomDegree
-    wf := WellFounded.onFun wellFounded_lt }
   by_cases hD0 : f.lexHomDegree = ⊥
   · use fun _ ↦ 0, f
     rw [lexHomDegree_eq_bot_iff] at hD0
@@ -654,7 +652,7 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
     split_ifs with h
     · simp [h]
     · simp [sub_zero, Ne.symm h]
-  haveI hf'D : f'.lexHomDegree < f.lexHomDegree := by
+  have : f'.lexHomDegree < f.lexHomDegree := by
     rw [hd]
     unfold lexHomDegree
     rw [Finset.sup_lt_iff]
@@ -777,7 +775,7 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
         apply lt_of_lt_of_le (b := (S i).card)
         simp only [bot_eq_zero', Finset.card_pos, Sne i]
         exact Nat.le_add_left (S i).card d'.degree
-    haveI hf''2 : f''.lexHomDegree < f.lexHomDegree := by
+    have : f''.lexHomDegree < f.lexHomDegree := by
       rw [LexHom.lt_iff]
       left
       simp only [lexHomDegree_degree]
@@ -834,6 +832,8 @@ theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty) (f : MvPoly
       apply lt_of_le_of_lt (weightedTotalDegree_add _)
       simp only [sup_lt_iff]
       exact ⟨Hr' i, Hr'' i⟩
+termination_by LexHom.wellFoundedLT.wf.wrap f.lexHomDegree
+decreasing_by repeat assumption

 /- -- OLD VERSION
 theorem euclDivd (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty)

Antoine Chambert-Loir (Aug 31 2024 at 14:06):

Thanks a lot, that's exactly the kind of things I expected was possible.
(repeat assumption did not work, though, but I could insert the proofs at this place.)


Last updated: May 02 2025 at 03:31 UTC