l3lab/ntp-mathlib huggingface dataset:
/-- Division by a monic polynomial doesn't change the leading coefficient. -/
theorem leadingCoeff_divByMonic_of_monic {R : Type u} [CommRing R] {p q : R[X]} (hmonic : q.Monic)
    (hdegree : q.degree ≤ p.degree) : (p /ₘ q).leadingCoeff = p.leadingCoeff := by
  nontriviality
  have h : q.leadingCoeff * (p /ₘ q).leadingCoeff ≠ 0 := by
    simpa [divByMonic_eq_zero_iff hmonic, hmonic.leadingCoeff,
      Nat.WithBot.one_le_iff_zero_lt] using hdegree
  nth_rw 2 [← modByMonic_add_div p hmonic]
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u
inst✝ : CommRing R
p q : R[X]
hmonic : Monic q
hdegree : degree q ≤ degree p
✝ : Nontrivial R
h : leadingCoeff q * leadingCoeff (p /ₘ q) ≠ 0
⊢ leadingCoeff (p /ₘ q) = leadingCoeff (p %ₘ q + q * (p /ₘ q))

Next tactic:
rw [leadingCoeff_add_of_degree_lt, leadingCoeff_monic_mul hmonic]
/-- Division by a monic polynomial doesn't change the leading coefficient. -/
theorem leadingCoeff_divByMonic_of_monic {R : Type u} [CommRing R] {p q : R[X]} (hmonic : q.Monic)
    (hdegree : q.degree ≤ p.degree) : (p /ₘ q).leadingCoeff = p.leadingCoeff := by
  nontriviality
  have h : q.leadingCoeff * (p /ₘ q).leadingCoeff ≠ 0 := by
    simpa [divByMonic_eq_zero_iff hmonic, hmonic.leadingCoeff,
      Nat.WithBot.one_le_iff_zero_lt] using hdegree
  nth_rw 2 [← modByMonic_add_div p hmonic]
  rw [leadingCoeff_add_of_degree_lt, leadingCoeff_monic_mul hmonic]
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u
inst✝ : CommRing R
p q : R[X]
hmonic : Monic q
hdegree : degree q ≤ degree p
✝ : Nontrivial R
h : leadingCoeff q * leadingCoeff (p /ₘ q) ≠ 0
⊢ degree (p %ₘ q) < degree (q * (p /ₘ q))

Next tactic:
rw [degree_mul' h, degree_add_divByMonic hmonic hdegree]
/-- Division by a monic polynomial doesn't change the leading coefficient. -/
theorem leadingCoeff_divByMonic_of_monic {R : Type u} [CommRing R] {p q : R[X]} (hmonic : q.Monic)
    (hdegree : q.degree ≤ p.degree) : (p /ₘ q).leadingCoeff = p.leadingCoeff := by
  nontriviality
  have h : q.leadingCoeff * (p /ₘ q).leadingCoeff ≠ 0 := by
    simpa [divByMonic_eq_zero_iff hmonic, hmonic.leadingCoeff,
      Nat.WithBot.one_le_iff_zero_lt] using hdegree
  nth_rw 2 [← modByMonic_add_div p hmonic]
  rw [leadingCoeff_add_of_degree_lt, leadingCoeff_monic_mul hmonic]
  rw [degree_mul' h, degree_add_divByMonic hmonic hdegree]
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u
inst✝ : CommRing R
p q : R[X]
hmonic : Monic q
hdegree : degree q ≤ degree p
✝ : Nontrivial R
h : leadingCoeff q * leadingCoeff (p /ₘ q) ≠ 0
⊢ degree (p %ₘ q) < degree p

Next tactic:
exact (degree_modByMonic_lt p hmonic).trans_le hdegree
theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
    leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a✝ b : R
n : ℕ
inst✝¹ : CommRing R
inst✝ : IsDomain R
p✝ q p : R[X]
hp : degree p ≠ 0
a : R
⊢ leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p

Next tactic:
nontriviality
theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
    leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
  nontriviality
  

Proof state:
R : Type u
S : Type v
T : Type w
a✝ b : R
n : ℕ
inst✝² : CommRing R
inst✝¹ : IsDomain R
p✝ q p : R[X]
hp : degree p ≠ 0
a : R
inst✝ : Nontrivial R
⊢ leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p

Next tactic:
cases' hp.lt_or_lt with hd hd
theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
    leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
  nontriviality
  cases' hp.lt_or_lt with hd hd
  · 

Proof state:
case inl
R : Type u
S : Type v
T : Type w
a✝ b : R
n : ℕ
inst✝² : CommRing R
inst✝¹ : IsDomain R
p✝ q p : R[X]
hp : degree p ≠ 0
a : R
inst✝ : Nontrivial R
hd : degree p < 0
⊢ leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p

Next tactic:
rw [degree_eq_bot.mp <| (Nat.WithBot.lt_zero_iff _).mp hd, zero_divByMonic]
theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
    leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
  nontriviality
  cases' hp.lt_or_lt with hd hd
  · rw [degree_eq_bot.mp <| (Nat.WithBot.lt_zero_iff _).mp hd, zero_divByMonic]
  

Proof state:
case inr
R : Type u
S : Type v
T : Type w
a✝ b : R
n : ℕ
inst✝² : CommRing R
inst✝¹ : IsDomain R
p✝ q p : R[X]
hp : degree p ≠ 0
a : R
inst✝ : Nontrivial R
hd : 0 < degree p
⊢ leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p

Next tactic:
refine' leadingCoeff_divByMonic_of_monic (monic_X_sub_C a) _
theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
    leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
  nontriviality
  cases' hp.lt_or_lt with hd hd
  · rw [degree_eq_bot.mp <| (Nat.WithBot.lt_zero_iff _).mp hd, zero_divByMonic]
  refine' leadingCoeff_divByMonic_of_monic (monic_X_sub_C a) _
  

Proof state:
case inr
R : Type u
S : Type v
T : Type w
a✝ b : R
n : ℕ
inst✝² : CommRing R
inst✝¹ : IsDomain R
p✝ q p : R[X]
hp : degree p ≠ 0
a : R
inst✝ : Nontrivial R
hd : 0 < degree p
⊢ degree (X - C a) ≤ degree p

Next tactic:
rwa [degree_X_sub_C, Nat.WithBot.one_le_iff_zero_lt]
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hdiv : p ∣ q
hdeg : natDegree q ≤ natDegree p
⊢ q = C (leadingCoeff q) * p

Next tactic:
obtain ⟨r, hr⟩ := hdiv
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  

Proof state:
case intro
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hdeg : natDegree q ≤ natDegree p
r : R[X]
hr : q = p * r
⊢ q = C (leadingCoeff q) * p

Next tactic:
obtain rfl | hq := eq_or_ne q 0
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · 

Proof state:
case intro.inl
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝ : CommRing R
p : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree 0 ≤ natDegree p
hr : 0 = p * r
⊢ 0 = C (leadingCoeff 0) * p

Next tactic:
simp
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hdeg : natDegree q ≤ natDegree p
r : R[X]
hr : q = p * r
hq : q ≠ 0
⊢ q = C (leadingCoeff q) * p

Next tactic:
have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by 

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hdeg : natDegree q ≤ natDegree p
r : R[X]
hr : q = p * r
hq : q ≠ 0
h : r = 0
⊢ False

Next tactic:
simp [h, hq] at hr
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hdeg : natDegree q ≤ natDegree p
r : R[X]
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ q = C (leadingCoeff q) * p

Next tactic:
rw [hr, natDegree_mul'] at hdeg
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; 

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ q = C (leadingCoeff q) * p
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree (p * r) ≤ natDegree p
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ leadingCoeff p * leadingCoeff r ≠ 0

Next tactic:
swap
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · 

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree (p * r) ≤ natDegree p
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ leadingCoeff p * leadingCoeff r ≠ 0

Next tactic:
rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree (p * r) ≤ natDegree p
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ r ≠ 0

Next tactic:
exact rzero
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    exact rzero
  

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = p * r
hq : q ≠ 0
rzero : r ≠ 0
⊢ q = C (leadingCoeff q) * p

Next tactic:
rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    exact rzero
  rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr
  · 

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = C (coeff r 0) * p
hq : q ≠ 0
rzero : r ≠ 0
⊢ q = C (leadingCoeff q) * p

Next tactic:
convert hr
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    exact rzero
  rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr
  · convert hr
    

Proof state:
case h.e'_3.h.e'_5.h.e'_6
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = C (coeff r 0) * p
hq : q ≠ 0
rzero : r ≠ 0
⊢ leadingCoeff q = coeff r 0

Next tactic:
convert leadingCoeff_C (coeff r 0) using 1
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    exact rzero
  rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr
  · convert hr
    convert leadingCoeff_C (coeff r 0) using 1
    

Proof state:
case h.e'_2
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = C (coeff r 0) * p
hq : q ≠ 0
rzero : r ≠ 0
⊢ leadingCoeff q = leadingCoeff (C (coeff r 0))

Next tactic:
rw [hr, leadingCoeff_mul_monic hp]
theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]}
    (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) :
    q = C q.leadingCoeff * p := by
  obtain ⟨r, hr⟩ := hdiv
  obtain rfl | hq := eq_or_ne q 0; · simp
  have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr
  rw [hr, natDegree_mul'] at hdeg; swap
  · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero]
    exact rzero
  rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr
  · convert hr
    convert leadingCoeff_C (coeff r 0) using 1
    rw [hr, leadingCoeff_mul_monic hp]
  · 

Proof state:
case intro.inr
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
r : R[X]
hdeg : natDegree p + natDegree r ≤ natDegree p
hr : q = r * p
hq : q ≠ 0
rzero : r ≠ 0
⊢ natDegree r = 0

Next tactic:
exact (add_right_inj _).1 (le_antisymm hdeg <| Nat.le.intro rfl)
theorem eq_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} (hp : p.Monic)
    (hq : q.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : q = p := by
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hq : Monic q
hdiv : p ∣ q
hdeg : natDegree q ≤ natDegree p
⊢ q = p

Next tactic:
convert eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le hp hdiv hdeg
theorem eq_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} (hp : p.Monic)
    (hq : q.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : q = p := by
  convert eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le hp hdiv hdeg
  

Proof state:
case h.e'_3
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝² : CommRing R✝
inst✝¹ : IsDomain R✝
p✝ q✝ : R✝[X]
R : Type u_1
inst✝ : CommRing R
p q : R[X]
hp : Monic p
hq : Monic q
hdiv : p ∣ q
hdeg : natDegree q ≤ natDegree p
⊢ p = C (leadingCoeff q) * p

Next tactic:
rw [hq.leadingCoeff, C_1, one_mul]
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
⊢ p = 0

Next tactic:
classical
  by_contra hp
  apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
  calc
    Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _
    _ ≤ natDegree p := Polynomial.card_roots' p
    _ < Fintype.card ι := hcard
    _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm
    _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range]
    _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_
  intro _
  simp only [Finset.mem_image, Finset.mem_univ, true_and, Multiset.mem_toFinset, mem_roots', ne_eq,
    IsRoot.def, forall_exists_index, hp, not_false_eq_true]
  rintro x rfl
  exact heval _
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
⊢ p = 0

Next tactic:
by_contra hp
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  by_contra hp
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
hp : ¬p = 0
⊢ False

Next tactic:
apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  by_contra hp
  apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
hp : ¬p = 0
⊢ card (Multiset.toFinset (roots p)) < card (Multiset.toFinset (roots p))

Next tactic:
calc
    Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _
    _ ≤ natDegree p := Polynomial.card_roots' p
    _ < Fintype.card ι := hcard
    _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm
    _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range]
    _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  by_contra hp
  apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
  calc
    Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _
    _ ≤ natDegree p := Polynomial.card_roots' p
    _ < Fintype.card ι := hcard
    _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm
    _ = Finset.card (Finset.univ.image f) := by 

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
hp : ¬p = 0
⊢ Fintype.card ↑(Set.range f) = card (image f univ)

Next tactic:
rw [← Set.toFinset_card, Set.toFinset_range]
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  by_contra hp
  apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
  calc
    Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _
    _ ≤ natDegree p := Polynomial.card_roots' p
    _ < Fintype.card ι := hcard
    _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm
    _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range]
    _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
hp : ¬p = 0
⊢ image f univ ≤ Multiset.toFinset (roots p)

Next tactic:
intro _
lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R]
    (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f)
    (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by
  classical
  by_contra hp
  apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset))
  calc
    Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _
    _ ≤ natDegree p := Polynomial.card_roots' p
    _ < Fintype.card ι := hcard
    _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm
    _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range]
    _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_
  intro _
  

Proof state:
R✝ : Type u
S : Type v
T : Type w
a b : R✝
n : ℕ
inst✝⁴ : CommRing R✝
inst✝³ : IsDomain R✝
p✝ q : R✝[X]
R : Type u_1
inst✝² : CommRing R
inst✝¹ : IsDomain R
p : R[X]
ι : Type u_2
inst✝ : Fintype ι
f : ι → R
hf : Function.Injective f
heval : ∀ (i : ι), eval (f i) p = 0
hcard : natDegree p < Fintype.card ι
hp : ¬p = 0
a✝ : R
⊢ a✝ ∈ image f univ → a✝ ∈ Multiset.toFinset (roots p)

Next tactic:
simp only [Finset.mem_image, Finset.mem_univ, true_and, Multiset.mem_toFinset, mem_roots', ne_eq,
    IsRoot.def, forall_exists_index, hp, not_false_eq_true]