l3lab/ntp-mathlib huggingface dataset:
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  ext p
  have : m / m.gcd n ≠ 0 :=
    (Nat.div_ne_zero_iff $ gcd_ne_zero_right hn).2 $ gcd_le_left _ hm.ne_zero.bot_lt
  simp only [mem_primeFactors, ne_eq, this, not_false_eq_true, and_true, not_and, mem_sdiff,
    hm.ne_zero, hn, dvd_div_iff (gcd_dvd_left _ _)]
  refine ⟨fun hp ↦ ⟨⟨hp.1, dvd_of_mul_left_dvd hp.2⟩, fun _ hpn ↦ hp.1.not_unit $ hm _ $
    (mul_dvd_mul_right (dvd_gcd (dvd_of_mul_left_dvd hp.2) hpn) _).trans hp.2⟩, fun hp ↦
      ⟨hp.1.1, Coprime.mul_dvd_of_dvd_of_dvd ?_ (gcd_dvd_left _ _) hp.1.2⟩⟩
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hm : Squarefree m
hn : n ≠ 0
p : ℕ
this : m / gcd m n ≠ 0
hp : (Prime p ∧ p ∣ m) ∧ (Prime p → ¬p ∣ n)
⊢ Coprime (gcd m n) p

Next tactic:
rw [coprime_comm, hp.1.1.coprime_iff_not_dvd]
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  ext p
  have : m / m.gcd n ≠ 0 :=
    (Nat.div_ne_zero_iff $ gcd_ne_zero_right hn).2 $ gcd_le_left _ hm.ne_zero.bot_lt
  simp only [mem_primeFactors, ne_eq, this, not_false_eq_true, and_true, not_and, mem_sdiff,
    hm.ne_zero, hn, dvd_div_iff (gcd_dvd_left _ _)]
  refine ⟨fun hp ↦ ⟨⟨hp.1, dvd_of_mul_left_dvd hp.2⟩, fun _ hpn ↦ hp.1.not_unit $ hm _ $
    (mul_dvd_mul_right (dvd_gcd (dvd_of_mul_left_dvd hp.2) hpn) _).trans hp.2⟩, fun hp ↦
      ⟨hp.1.1, Coprime.mul_dvd_of_dvd_of_dvd ?_ (gcd_dvd_left _ _) hp.1.2⟩⟩
  rw [coprime_comm, hp.1.1.coprime_iff_not_dvd]
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hm : Squarefree m
hn : n ≠ 0
p : ℕ
this : m / gcd m n ≠ 0
hp : (Prime p ∧ p ∣ m) ∧ (Prime p → ¬p ∣ n)
⊢ ¬p ∣ gcd m n

Next tactic:
exact fun hpn ↦ hp.2 hp.1.1 $ hpn.trans $ gcd_dvd_right _ _
theorem prod_factors_toFinset_of_squarefree {n : ℕ} (hn : Squarefree n) :
    ∏ p in n.factors.toFinset, p = n := by
  

Proof state:
s : Finset ℕ
m n✝ p n : ℕ
hn : Squarefree n
⊢ ∏ p in List.toFinset (factors n), p = n

Next tactic:
rw [List.prod_toFinset _ hn.nodup_factors, List.map_id', Nat.prod_factors hn.ne_zero]
theorem isFibAux_two_mul {n a b n' a' b' : ℕ} (H : IsFibAux n a b)
    (hn : 2 * n = n') (h1 : a * (2 * b - a) = a') (h2 : a * a + b * b = b') :
    IsFibAux n' a' b' :=
  ⟨by 

Proof state:
n a b n' a' b' : ℕ
H : IsFibAux n a b
hn : 2 * n = n'
h1 : a * (2 * b - a) = a'
h2 : a * a + b * b = b'
⊢ fib n' = a'

Next tactic:
rw [← hn, fib_two_mul, H.1, H.2, ← h1]
theorem isFibAux_two_mul {n a b n' a' b' : ℕ} (H : IsFibAux n a b)
    (hn : 2 * n = n') (h1 : a * (2 * b - a) = a') (h2 : a * a + b * b = b') :
    IsFibAux n' a' b' :=
  ⟨by rw [← hn, fib_two_mul, H.1, H.2, ← h1],
   by 

Proof state:
n a b n' a' b' : ℕ
H : IsFibAux n a b
hn : 2 * n = n'
h1 : a * (2 * b - a) = a'
h2 : a * a + b * b = b'
⊢ fib (n' + 1) = b'

Next tactic:
rw [← hn, fib_two_mul_add_one, H.1, H.2, pow_two, pow_two, add_comm, h2]
theorem isFibAux_two_mul_add_one {n a b n' a' b' : ℕ} (H : IsFibAux n a b)
    (hn : 2 * n + 1 = n') (h1 : a * a + b * b = a') (h2 : b * (2 * a + b) = b') :
    IsFibAux n' a' b' :=
  ⟨by 

Proof state:
n a b n' a' b' : ℕ
H : IsFibAux n a b
hn : 2 * n + 1 = n'
h1 : a * a + b * b = a'
h2 : b * (2 * a + b) = b'
⊢ fib n' = a'

Next tactic:
rw [← hn, fib_two_mul_add_one, H.1, H.2, pow_two, pow_two, add_comm, h1]
theorem isFibAux_two_mul_add_one {n a b n' a' b' : ℕ} (H : IsFibAux n a b)
    (hn : 2 * n + 1 = n') (h1 : a * a + b * b = a') (h2 : b * (2 * a + b) = b') :
    IsFibAux n' a' b' :=
  ⟨by rw [← hn, fib_two_mul_add_one, H.1, H.2, pow_two, pow_two, add_comm, h1],
   by 

Proof state:
n a b n' a' b' : ℕ
H : IsFibAux n a b
hn : 2 * n + 1 = n'
h1 : a * a + b * b = a'
h2 : b * (2 * a + b) = b'
⊢ fib (n' + 1) = b'

Next tactic:
rw [← hn, fib_two_mul_add_two, H.1, H.2, h2]
theorem eraseLead_support (f : R[X]) : f.eraseLead.support = f.support.erase f.natDegree := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
⊢ support (eraseLead f) = Finset.erase (support f) (natDegree f)

Next tactic:
simp only [eraseLead, support_erase]
theorem eraseLead_coeff (i : ℕ) : f.eraseLead.coeff i = if i = f.natDegree then 0 else f.coeff i :=
  by 

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
⊢ coeff (eraseLead f) i = if i = natDegree f then 0 else coeff f i

Next tactic:
simp only [eraseLead, coeff_erase]
@[simp]
theorem eraseLead_coeff_natDegree : f.eraseLead.coeff f.natDegree = 0 := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
⊢ coeff (eraseLead f) (natDegree f) = 0

Next tactic:
simp [eraseLead_coeff]
theorem eraseLead_coeff_of_ne (i : ℕ) (hi : i ≠ f.natDegree) : f.eraseLead.coeff i = f.coeff i := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
hi : i ≠ natDegree f
⊢ coeff (eraseLead f) i = coeff f i

Next tactic:
simp [eraseLead_coeff, hi]
@[simp]
theorem eraseLead_zero : eraseLead (0 : R[X]) = 0 := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
⊢ eraseLead 0 = 0

Next tactic:
simp only [eraseLead, erase_zero]
@[simp]
theorem eraseLead_add_C_mul_X_pow (f : R[X]) :
    f.eraseLead + C f.leadingCoeff * X ^ f.natDegree = f := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
⊢ eraseLead f + C (leadingCoeff f) * X ^ natDegree f = f

Next tactic:
rw [C_mul_X_pow_eq_monomial, eraseLead_add_monomial_natDegree_leadingCoeff]
@[simp]
theorem self_sub_C_mul_X_pow {R : Type*} [Ring R] (f : R[X]) :
    f - C f.leadingCoeff * X ^ f.natDegree = f.eraseLead := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : Ring R
f : R[X]
⊢ f - C (leadingCoeff f) * X ^ natDegree f = eraseLead f

Next tactic:
rw [C_mul_X_pow_eq_monomial, self_sub_monomial_natDegree_leadingCoeff]
theorem eraseLead_ne_zero (f0 : 2 ≤ f.support.card) : eraseLead f ≠ 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
f0 : 2 ≤ card (support f)
⊢ eraseLead f ≠ 0

Next tactic:
rw [Ne, ← card_support_eq_zero, eraseLead_support]
theorem eraseLead_ne_zero (f0 : 2 ≤ f.support.card) : eraseLead f ≠ 0 := by
  rw [Ne, ← card_support_eq_zero, eraseLead_support]
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
f0 : 2 ≤ card (support f)
⊢ ¬card (Finset.erase (support f) (natDegree f)) = 0

Next tactic:
exact
    (zero_lt_one.trans_le <| (tsub_le_tsub_right f0 1).trans Finset.pred_card_le_card_erase).ne.symm
theorem lt_natDegree_of_mem_eraseLead_support {a : ℕ} (h : a ∈ (eraseLead f).support) :
    a < f.natDegree := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
a : ℕ
h : a ∈ support (eraseLead f)
⊢ a < natDegree f

Next tactic:
rw [eraseLead_support, mem_erase] at h
theorem lt_natDegree_of_mem_eraseLead_support {a : ℕ} (h : a ∈ (eraseLead f).support) :
    a < f.natDegree := by
  rw [eraseLead_support, mem_erase] at h
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
a : ℕ
h : a ≠ natDegree f ∧ a ∈ support f
⊢ a < natDegree f

Next tactic:
exact (le_natDegree_of_mem_supp a h.2).lt_of_ne h.1
theorem eraseLead_support_card_lt (h : f ≠ 0) : (eraseLead f).support.card < f.support.card := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
h : f ≠ 0
⊢ card (support (eraseLead f)) < card (support f)

Next tactic:
rw [eraseLead_support]
theorem eraseLead_support_card_lt (h : f ≠ 0) : (eraseLead f).support.card < f.support.card := by
  rw [eraseLead_support]
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
h : f ≠ 0
⊢ card (Finset.erase (support f) (natDegree f)) < card (support f)

Next tactic:
exact card_lt_card (erase_ssubset <| natDegree_mem_support_of_nonzero h)
theorem eraseLead_card_support {c : ℕ} (fc : f.support.card = c) :
    f.eraseLead.support.card = c - 1 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
c : ℕ
fc : card (support f) = c
⊢ card (support (eraseLead f)) = c - 1

Next tactic:
by_cases f0 : f = 0
theorem eraseLead_card_support {c : ℕ} (fc : f.support.card = c) :
    f.eraseLead.support.card = c - 1 := by
  by_cases f0 : f = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f : R[X]
c : ℕ
fc : card (support f) = c
f0 : f = 0
⊢ card (support (eraseLead f)) = c - 1

Next tactic:
rw [← fc, f0, eraseLead_zero, support_zero, card_empty]
theorem eraseLead_card_support {c : ℕ} (fc : f.support.card = c) :
    f.eraseLead.support.card = c - 1 := by
  by_cases f0 : f = 0
  · rw [← fc, f0, eraseLead_zero, support_zero, card_empty]
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
f : R[X]
c : ℕ
fc : card (support f) = c
f0 : ¬f = 0
⊢ card (support (eraseLead f)) = c - 1

Next tactic:
rw [eraseLead_support, card_erase_of_mem (natDegree_mem_support_of_nonzero f0), fc]
@[simp]
theorem eraseLead_monomial (i : ℕ) (r : R) : eraseLead (monomial i r) = 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
r : R
⊢ eraseLead ((monomial i) r) = 0

Next tactic:
classical
  by_cases hr : r = 0
  · subst r
    simp only [monomial_zero_right, eraseLead_zero]
  · rw [eraseLead, natDegree_monomial, if_neg hr, erase_monomial]
@[simp]
theorem eraseLead_monomial (i : ℕ) (r : R) : eraseLead (monomial i r) = 0 := by
  classical
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
r : R
⊢ eraseLead ((monomial i) r) = 0

Next tactic:
by_cases hr : r = 0
@[simp]
theorem eraseLead_monomial (i : ℕ) (r : R) : eraseLead (monomial i r) = 0 := by
  classical
  by_cases hr : r = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
r : R
hr : r = 0
⊢ eraseLead ((monomial i) r) = 0

Next tactic:
subst r
@[simp]
theorem eraseLead_monomial (i : ℕ) (r : R) : eraseLead (monomial i r) = 0 := by
  classical
  by_cases hr : r = 0
  · subst r
    

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
⊢ eraseLead ((monomial i) 0) = 0

Next tactic:
simp only [monomial_zero_right, eraseLead_zero]
@[simp]
theorem eraseLead_monomial (i : ℕ) (r : R) : eraseLead (monomial i r) = 0 := by
  classical
  by_cases hr : r = 0
  · subst r
    simp only [monomial_zero_right, eraseLead_zero]
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
f : R[X]
i : ℕ
r : R
hr : ¬r = 0
⊢ eraseLead ((monomial i) r) = 0

Next tactic:
rw [eraseLead, natDegree_monomial, if_neg hr, erase_monomial]
@[simp]
theorem eraseLead_X_pow (n : ℕ) : eraseLead (X ^ n : R[X]) = 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
n : ℕ
⊢ eraseLead (X ^ n) = 0

Next tactic:
rw [X_pow_eq_monomial, eraseLead_monomial]
@[simp]
theorem eraseLead_C_mul_X_pow (r : R) (n : ℕ) : eraseLead (C r * X ^ n) = 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
r : R
n : ℕ
⊢ eraseLead (C r * X ^ n) = 0

Next tactic:
rw [C_mul_X_pow_eq_monomial, eraseLead_monomial]
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
⊢ eraseLead (p + q) = eraseLead p + q

Next tactic:
ext n
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  

Proof state:
case a
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
n : ℕ
⊢ coeff (eraseLead (p + q)) n = coeff (eraseLead p + q) n

Next tactic:
by_cases nd : n = p.natDegree
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  by_cases nd : n = p.natDegree
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
n : ℕ
nd : n = natDegree p
⊢ coeff (eraseLead (p + q)) n = coeff (eraseLead p + q) n

Next tactic:
rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm]
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  by_cases nd : n = p.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm]
    

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
n : ℕ
nd : n = natDegree p
⊢ 0 = coeff (eraseLead p + q) (natDegree p)

Next tactic:
simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  by_cases nd : n = p.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
n : ℕ
nd : ¬n = natDegree p
⊢ coeff (eraseLead (p + q)) n = coeff (eraseLead p + q) n

Next tactic:
rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  by_cases nd : n = p.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
    

Proof state:
case neg.hnc
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
n : ℕ
nd : ¬n = natDegree p
⊢ ¬n = natDegree (p + q)

Next tactic:
rintro rfl
theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) :
    (p + q).eraseLead = p.eraseLead + q := by
  ext n
  by_cases nd : n = p.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
    rintro rfl
    

Proof state:
case neg.hnc
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree q < natDegree p
nd : ¬natDegree (p + q) = natDegree p
⊢ False

Next tactic:
exact nd (natDegree_add_eq_left_of_natDegree_lt pq)
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
⊢ eraseLead (p + q) = p + eraseLead q

Next tactic:
ext n
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  

Proof state:
case a
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
n : ℕ
⊢ coeff (eraseLead (p + q)) n = coeff (p + eraseLead q) n

Next tactic:
by_cases nd : n = q.natDegree
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  by_cases nd : n = q.natDegree
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
n : ℕ
nd : n = natDegree q
⊢ coeff (eraseLead (p + q)) n = coeff (p + eraseLead q) n

Next tactic:
rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm]
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  by_cases nd : n = q.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm]
    

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
n : ℕ
nd : n = natDegree q
⊢ 0 = coeff (p + eraseLead q) (natDegree q)

Next tactic:
simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  by_cases nd : n = q.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
n : ℕ
nd : ¬n = natDegree q
⊢ coeff (eraseLead (p + q)) n = coeff (p + eraseLead q) n

Next tactic:
rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  by_cases nd : n = q.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
    

Proof state:
case neg.hnc
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
n : ℕ
nd : ¬n = natDegree q
⊢ ¬n = natDegree (p + q)

Next tactic:
rintro rfl
theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) :
    (p + q).eraseLead = p + q.eraseLead := by
  ext n
  by_cases nd : n = q.natDegree
  · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm]
    simpa using (coeff_eq_zero_of_natDegree_lt pq).symm
  · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd]
    rintro rfl
    

Proof state:
case neg.hnc
R : Type u_1
inst✝ : Semiring R
f p q : R[X]
pq : natDegree p < natDegree q
nd : ¬natDegree (p + q) = natDegree q
⊢ False

Next tactic:
exact nd (natDegree_add_eq_right_of_natDegree_lt pq)
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
⊢ natDegree (eraseLead f) < natDegree f ∨ eraseLead f = 0

Next tactic:
by_cases h : f.support.card ≤ 1
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  by_cases h : f.support.card ≤ 1
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : card (support f) ≤ 1
⊢ natDegree (eraseLead f) < natDegree f ∨ eraseLead f = 0

Next tactic:
right
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  by_cases h : f.support.card ≤ 1
  · right
    

Proof state:
case pos.h
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : card (support f) ≤ 1
⊢ eraseLead f = 0

Next tactic:
rw [← C_mul_X_pow_eq_self h]
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  by_cases h : f.support.card ≤ 1
  · right
    rw [← C_mul_X_pow_eq_self h]
    

Proof state:
case pos.h
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : card (support f) ≤ 1
⊢ eraseLead (C (leadingCoeff f) * X ^ natDegree f) = 0

Next tactic:
simp
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  by_cases h : f.support.card ≤ 1
  · right
    rw [← C_mul_X_pow_eq_self h]
    simp
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : ¬card (support f) ≤ 1
⊢ natDegree (eraseLead f) < natDegree f ∨ eraseLead f = 0

Next tactic:
left
theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) :
    (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by
  by_cases h : f.support.card ≤ 1
  · right
    rw [← C_mul_X_pow_eq_self h]
    simp
  · left
    

Proof state:
case neg.h
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : ¬card (support f) ≤ 1
⊢ natDegree (eraseLead f) < natDegree f

Next tactic:
apply eraseLead_natDegree_lt (lt_of_not_ge h)
theorem eraseLead_natDegree_le (f : R[X]) : (eraseLead f).natDegree ≤ f.natDegree - 1 := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
⊢ natDegree (eraseLead f) ≤ natDegree f - 1

Next tactic:
rcases f.eraseLead_natDegree_lt_or_eraseLead_eq_zero with (h | h)
theorem eraseLead_natDegree_le (f : R[X]) : (eraseLead f).natDegree ≤ f.natDegree - 1 := by
  rcases f.eraseLead_natDegree_lt_or_eraseLead_eq_zero with (h | h)
  · 

Proof state:
case inl
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : natDegree (eraseLead f) < natDegree f
⊢ natDegree (eraseLead f) ≤ natDegree f - 1

Next tactic:
exact Nat.le_sub_one_of_lt h
theorem eraseLead_natDegree_le (f : R[X]) : (eraseLead f).natDegree ≤ f.natDegree - 1 := by
  rcases f.eraseLead_natDegree_lt_or_eraseLead_eq_zero with (h | h)
  · exact Nat.le_sub_one_of_lt h
  · 

Proof state:
case inr
R : Type u_1
inst✝ : Semiring R
f✝ f : R[X]
h : eraseLead f = 0
⊢ natDegree (eraseLead f) ≤ natDegree f - 1

Next tactic:
simp only [h, natDegree_zero, zero_le]
/-- An induction lemma for polynomials. It takes a natural number `N` as a parameter, that is
required to be at least as big as the `nat_degree` of the polynomial.  This is useful to prove
results where you want to change each term in a polynomial to something else depending on the
`nat_degree` of the polynomial itself and not on the specific `nat_degree` of each term. -/
theorem induction_with_natDegree_le (P : R[X] → Prop) (N : ℕ) (P_0 : P 0)
    (P_C_mul_pow : ∀ n : ℕ, ∀ r : R, r ≠ 0 → n ≤ N → P (C r * X ^ n))
    (P_C_add : ∀ f g : R[X], f.natDegree < g.natDegree → g.natDegree ≤ N → P f → P g → P (f + g)) :
    ∀ f : R[X], f.natDegree ≤ N → P f := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f : R[X]
P : R[X] → Prop
N : ℕ
P_0 : P 0
P_C_mul_pow : ∀ (n : ℕ) (r : R), r ≠ 0 → n ≤ N → P (C r * X ^ n)
P_C_add : ∀ (f g : R[X]), natDegree f < natDegree g → natDegree g ≤ N → P f → P g → P (f + g)
⊢ ∀ (f : R[X]), natDegree f ≤ N → P f

Next tactic:
intro f df
/-- An induction lemma for polynomials. It takes a natural number `N` as a parameter, that is
required to be at least as big as the `nat_degree` of the polynomial.  This is useful to prove
results where you want to change each term in a polynomial to something else depending on the
`nat_degree` of the polynomial itself and not on the specific `nat_degree` of each term. -/
theorem induction_with_natDegree_le (P : R[X] → Prop) (N : ℕ) (P_0 : P 0)
    (P_C_mul_pow : ∀ n : ℕ, ∀ r : R, r ≠ 0 → n ≤ N → P (C r * X ^ n))
    (P_C_add : ∀ f g : R[X], f.natDegree < g.natDegree → g.natDegree ≤ N → P f → P g → P (f + g)) :
    ∀ f : R[X], f.natDegree ≤ N → P f := by
  intro f df
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ : R[X]
P : R[X] → Prop
N : ℕ
P_0 : P 0
P_C_mul_pow : ∀ (n : ℕ) (r : R), r ≠ 0 → n ≤ N → P (C r * X ^ n)
P_C_add : ∀ (f g : R[X]), natDegree f < natDegree g → natDegree g ≤ N → P f → P g → P (f + g)
f : R[X]
df : natDegree f ≤ N
⊢ P f

Next tactic:
generalize hd : card f.support = c
/-- An induction lemma for polynomials. It takes a natural number `N` as a parameter, that is
required to be at least as big as the `nat_degree` of the polynomial.  This is useful to prove
results where you want to change each term in a polynomial to something else depending on the
`nat_degree` of the polynomial itself and not on the specific `nat_degree` of each term. -/
theorem induction_with_natDegree_le (P : R[X] → Prop) (N : ℕ) (P_0 : P 0)
    (P_C_mul_pow : ∀ n : ℕ, ∀ r : R, r ≠ 0 → n ≤ N → P (C r * X ^ n))
    (P_C_add : ∀ f g : R[X], f.natDegree < g.natDegree → g.natDegree ≤ N → P f → P g → P (f + g)) :
    ∀ f : R[X], f.natDegree ≤ N → P f := by
  intro f df
  generalize hd : card f.support = c
  

Proof state:
R : Type u_1
inst✝ : Semiring R
f✝ : R[X]
P : R[X] → Prop
N : ℕ
P_0 : P 0
P_C_mul_pow : ∀ (n : ℕ) (r : R), r ≠ 0 → n ≤ N → P (C r * X ^ n)
P_C_add : ∀ (f g : R[X]), natDegree f < natDegree g → natDegree g ≤ N → P f → P g → P (f + g)
f : R[X]
df : natDegree f ≤ N
c : ℕ
hd : card (support f) = c
⊢ P f

Next tactic:
revert f