Zulip Chat Archive

Stream: new members

Topic: contribution: induction on polynomial degree


Way Yan Win (Dec 07 2021 at 05:42):

Hi, it seems that (strong) induction on polynomial.nat_degree isn't supported yet, so as a first contribution to mathlib I'd like to add that. Here is the code I have, inspired by their analogues nat.strong_induction_on and nat.case_strong_induction_on:

import data.polynomial.degree.definitions

variables {R : Type*} [semiring R]

lemma polynomial_nat_degree_strong_induction_on {P : polynomial R  Prop}
  (p : polynomial R)
  (h :  (p : polynomial R) (n : ),
    ( (m : ), m < n 
      ( (p' : polynomial R), p'.nat_degree = m  P p')) 
        p.nat_degree = n  P p) :
  P p :=
begin
  generalize hd : p.nat_degree = d,
  revert hd p,
  apply nat.strong_induction_on d, clear d,
  intros n h' p,
  exact h p n h',
end

lemma polynomial_nat_degree_case_strong_induction_on {P : polynomial R  Prop}
  (p : polynomial R)
  (hz :  (p : polynomial R), p.nat_degree = 0  P p)
  (hi :  (p : polynomial R) (n : ),
    ( (m : ), m  n 
      ( (p' : polynomial R), p'.nat_degree = m  P p')) 
        p.nat_degree = n.succ  P p) :
  P p :=
begin
  generalize hd : p.nat_degree = d,
  revert hd p,
  apply nat.case_strong_induction_on d, clear d,
  { exact hz },
  { intros n h p, exact hi p n h }
end

If it is ok, can I have write access to the mathlib repository? My username is greysome.

Eric Wieser (Dec 07 2021 at 07:58):

I'd argue that strong induction on nat_degree is supported, and the spelling is pretty much what you have there. I don't think it makes much sense to duplicate nat strong_induction for every nat-valued property of other types.

Eric Wieser (Dec 07 2021 at 08:00):

Does induction h : p.nat_degree using nat.strong_induction_on do what you need?

Way Yan Win (Dec 07 2021 at 08:35):

ohh, I didn't know that was possible. thanks!

Way Yan Win (Dec 07 2021 at 08:41):

hmm wait actually there is a difference, because in the induction hypothesis there is an additional quantifier (namely, if for all m < n the property holds for all polynomials of degree m, then the property holds for all polynomials of degree n)

Way Yan Win (Dec 07 2021 at 08:44):

I think induction h : p.nat_degree using nat.strong_induction_on with i hi generalizing p would be correct

Eric Wieser (Dec 07 2021 at 08:55):

Ah, I forgot that it didn't generalize that automatically

Eric Wieser (Dec 07 2021 at 09:20):

If it is ok, can I have write access to the mathlib repository? My username is greysome.

I've sent an invite; even though I think the lemmas above are redundant, you're certainly welcome to contribute other things to mathlib

Yaël Dillies (Dec 07 2021 at 09:54):

This induction is a bit dull, but there are many inductions on the polynomials that we don't have. For example, p P -> p Q -> p (P * Q) and p (X - a)^n

Eric Rodriguez (Dec 07 2021 at 09:57):

That also needs p y for y in the base field or some similar condition

Eric Wieser (Dec 07 2021 at 10:23):

A variant of docs#polynomial.rec_on_horner for mv_polynomial might be nice too

Way Yan Win (Dec 09 2021 at 08:18):

Since we're already on this topic, there are some other results on polynomials that I've needed, which are oddly missing:

variables {R : Type*} [semiring R]
theorem nat_degree_pow_le (p : polynomial R) (n : ) : (p ^ n).nat_degree  n * p.nat_degree := sorry
theorem coeff_pow_degree_mul_degree (p : polynomial R) (n : ) : (p ^ n).coeff (n * p.nat_degree) = p.leading_coeff ^ n := sorry

This seems like a reasonable contribution since there's already nat_degree_mul_le and coeff_mul_degree_add_degree

Yaël Dillies (Dec 09 2021 at 08:27):

And maybe do the constant coeff version as well?

Eric Wieser (Dec 09 2021 at 08:34):

Note we already have docs#polynomial.nat_degree_pow and docs#polynomial.nat_degree_pow'; the new pow lemma should reference those and maybe go somewhere near them

Way Yan Win (Dec 09 2021 at 08:38):

Yaël Dillies said:

And maybe do the constant coeff version as well?

Which specific result is that?

Way Yan Win (Dec 09 2021 at 08:39):

Eric Wieser said:

Note we already have docs#polynomial.nat_degree_pow and docs#polynomial.nat_degree_pow'; the new pow lemma should reference those and maybe go somewhere near them

Ah ok I'll try that

Eric Wieser (Dec 09 2021 at 08:43):

If you're looking for more contributions, we should probably have the degree variant of that nat.degree lemma

Way Yan Win (Dec 09 2021 at 10:39):

Right now I'm trying to copy the proof for nat_degree_mul_le in nat_degree_pow_le:

import data.polynomial.degree.definitions
open polynomial

variables {R : Type*} [semiring R]

lemma nat_degree_pow_le {p : polynomial R} {n : } : nat_degree (p ^ n)  n * nat_degree p :=
begin
  apply nat_degree_le_of_degree_le,
  apply le_trans (degree_pow_le p n),
  rw [nsmul_eq_mul, with_bot.coe_mul],
  sorry
end

So I'm stuck at showing that ↑n * p.degree ≤ ↑n * ↑p.nat_degree. The other proof continued with refine add_le_add _ _, but the corresponding refine mul_le_mul_left' _ _ doesn't work. I suspect it's because with_bot.ordered_add_comm_monoid has been established but not with_bot.ordered_comm_monoid. Hopefully I'm on the right track with this?

Eric Wieser (Dec 09 2021 at 10:54):

Is it easier to prove the degree_pow_le version first?

Eric Wieser (Dec 09 2021 at 10:55):

Then do case analysis on whether p = 0 to handle the \bot and nat cases?

Ruben Van de Velde (Dec 09 2021 at 10:57):

Yeah, I don't think getting to a goal like p.degree ≤ ↑(p.nat_degree) is going to help you

Kevin Buzzard (Dec 09 2021 at 10:58):

Maybe direct induction on n is far less painful?

Ruben Van de Velde (Dec 09 2021 at 10:59):

rw [nat.cast_with_bot, degree_eq_nat_degree hp] will help though, after the case split

Eric Wieser (Dec 09 2021 at 11:04):

This is a mess, but works:

lemma nat_degree_pow_le {p : polynomial R} {n : } : nat_degree (p ^ n)  n * nat_degree p :=
begin
  by_cases hn : n = 0,
  { rw hn, simp },
  by_cases hpn : p ^ n = 0,
  { rw hpn, simp },
  have hp : p  0,
  { rintro rfl,
    apply hpn,
    simp [hn], },
  rw [with_bot.coe_le_coe, with_bot.coe_mul],
  rw [degree_eq_nat_degree hpn, degree_eq_nat_degree hp],
  convert degree_pow_le _ _,
  simp,
end

Ruben Van de Velde (Dec 09 2021 at 11:04):

Six lines with either approach:

import data.polynomial.degree

open polynomial

variables {R : Type*} [semiring R]
lemma nat_degree_pow_le {p : polynomial R} {n : } : nat_degree (p ^ n)  n * nat_degree p :=
begin
  obtain rfl|hp := eq_or_ne p 0,
  { obtain rfl|hn := eq_or_ne n 0; simp [*] },
  apply nat_degree_le_of_degree_le,
  apply le_trans (degree_pow_le p n),
  rw [nsmul_eq_mul, with_bot.coe_mul, nat.cast_with_bot, degree_eq_nat_degree hp],
  exact le_rfl,
end

lemma nat_degree_pow_le' {p : polynomial R} {n : } : nat_degree (p ^ n)  n * nat_degree p :=
begin
  induction n with n ih,
  { simp },
  { rw [pow_succ],
    apply le_trans nat_degree_mul_le,
    apply le_trans (add_le_add_left ih _),
    rw [nat.succ_mul, add_comm] },
end

Eric Wieser (Dec 09 2021 at 11:05):

I think proving it in terms of the degree version is nicer than using induction

Kevin Buzzard (Dec 09 2021 at 11:06):

despite the fact that the induction proof has fewer characters, is more primitive, and probably compiles more quickly? ;-)

Eric Wieser (Dec 09 2021 at 11:07):

Yes, because the one proved from degree gives a template for "how to prove things about nat_degree from things about degree" that you can blindly repeat

Eric Wieser (Dec 09 2021 at 11:07):

Of course, it would also be good to make the proof less messy.

Way Yan Win (Dec 09 2021 at 11:36):

Thanks, I'll try the above approaches then. I was initially worried that the proof will look different from the existing proofs, but I guess it's good to have something working at least


Last updated: Dec 20 2023 at 11:08 UTC