l3lab/ntp-mathlib huggingface dataset:
theorem natDegree_add_le_iff_left {n : ℕ} (p q : R[X]) (qn : q.natDegree ≤ n) :
    (p + q).natDegree ≤ n ↔ p.natDegree ≤ n := by
  refine' ⟨fun h => _, fun h => natDegree_add_le_of_degree_le h qn⟩
  refine' natDegree_le_iff_coeff_eq_zero.mpr fun m hm => _
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m✝ n✝ : ℕ
inst✝ : Semiring R
p✝ q✝ r : R[X]
n : ℕ
p q : R[X]
qn : natDegree q ≤ n
h : natDegree (p + q) ≤ n
m : ℕ
hm : n < m
⊢ coeff p m = 0

Next tactic:
convert natDegree_le_iff_coeff_eq_zero.mp h m hm using 1
theorem natDegree_add_le_iff_left {n : ℕ} (p q : R[X]) (qn : q.natDegree ≤ n) :
    (p + q).natDegree ≤ n ↔ p.natDegree ≤ n := by
  refine' ⟨fun h => _, fun h => natDegree_add_le_of_degree_le h qn⟩
  refine' natDegree_le_iff_coeff_eq_zero.mpr fun m hm => _
  convert natDegree_le_iff_coeff_eq_zero.mp h m hm using 1
  

Proof state:
case h.e'_2
R : Type u
S : Type v
ι : Type w
a b : R
m✝ n✝ : ℕ
inst✝ : Semiring R
p✝ q✝ r : R[X]
n : ℕ
p q : R[X]
qn : natDegree q ≤ n
h : natDegree (p + q) ≤ n
m : ℕ
hm : n < m
⊢ coeff p m = coeff (p + q) m

Next tactic:
rw [coeff_add, natDegree_le_iff_coeff_eq_zero.mp qn _ hm, add_zero]
theorem natDegree_add_le_iff_right {n : ℕ} (p q : R[X]) (pn : p.natDegree ≤ n) :
    (p + q).natDegree ≤ n ↔ q.natDegree ≤ n := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n✝ : ℕ
inst✝ : Semiring R
p✝ q✝ r : R[X]
n : ℕ
p q : R[X]
pn : natDegree p ≤ n
⊢ natDegree (p + q) ≤ n ↔ natDegree q ≤ n

Next tactic:
rw [add_comm]
theorem natDegree_add_le_iff_right {n : ℕ} (p q : R[X]) (pn : p.natDegree ≤ n) :
    (p + q).natDegree ≤ n ↔ q.natDegree ≤ n := by
  rw [add_comm]
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n✝ : ℕ
inst✝ : Semiring R
p✝ q✝ r : R[X]
n : ℕ
p q : R[X]
pn : natDegree p ≤ n
⊢ natDegree (q + p) ≤ n ↔ natDegree q ≤ n

Next tactic:
exact natDegree_add_le_iff_left _ _ pn
theorem natDegree_C_mul_le (a : R) (f : R[X]) : (C a * f).natDegree ≤ f.natDegree :=
  calc
    (C a * f).natDegree ≤ (C a).natDegree + f.natDegree := natDegree_mul_le
    _ = 0 + f.natDegree := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a✝ b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
a : R
f : R[X]
⊢ natDegree (C a) + natDegree f = 0 + natDegree f

Next tactic:
rw [natDegree_C a]
theorem natDegree_mul_C_le (f : R[X]) (a : R) : (f * C a).natDegree ≤ f.natDegree :=
  calc
    (f * C a).natDegree ≤ f.natDegree + (C a).natDegree := natDegree_mul_le
    _ = f.natDegree + 0 := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a✝ b : R
m n : ℕ
inst✝ : Semiring R
p q r f : R[X]
a : R
⊢ natDegree f + natDegree (C a) = natDegree f + 0

Next tactic:
rw [natDegree_C a]
theorem natDegree_C_mul_eq_of_mul_eq_one {ai : R} (au : ai * a = 1) :
    (C a * p).natDegree = p.natDegree :=
  le_antisymm (natDegree_C_mul_le a p)
    (calc
      p.natDegree = (1 * p).natDegree := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
ai : R
au : ai * a = 1
⊢ natDegree p = natDegree (1 * p)

Next tactic:
nth_rw 1 [← one_mul p]
theorem natDegree_C_mul_eq_of_mul_eq_one {ai : R} (au : ai * a = 1) :
    (C a * p).natDegree = p.natDegree :=
  le_antisymm (natDegree_C_mul_le a p)
    (calc
      p.natDegree = (1 * p).natDegree := by nth_rw 1 [← one_mul p]
      _ = (C ai * (C a * p)).natDegree := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
ai : R
au : ai * a = 1
⊢ natDegree (1 * p) = natDegree (C ai * (C a * p))

Next tactic:
rw [← C_1, ← au, RingHom.map_mul, ← mul_assoc]
theorem natDegree_mul_C_eq_of_mul_eq_one {ai : R} (au : a * ai = 1) :
    (p * C a).natDegree = p.natDegree :=
  le_antisymm (natDegree_mul_C_le p a)
    (calc
      p.natDegree = (p * 1).natDegree := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
ai : R
au : a * ai = 1
⊢ natDegree p = natDegree (p * 1)

Next tactic:
nth_rw 1 [← mul_one p]
theorem natDegree_mul_C_eq_of_mul_eq_one {ai : R} (au : a * ai = 1) :
    (p * C a).natDegree = p.natDegree :=
  le_antisymm (natDegree_mul_C_le p a)
    (calc
      p.natDegree = (p * 1).natDegree := by nth_rw 1 [← mul_one p]
      _ = (p * C a * C ai).natDegree := by 

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
ai : R
au : a * ai = 1
⊢ natDegree (p * 1) = natDegree (p * C a * C ai)

Next tactic:
rw [← C_1, ← au, RingHom.map_mul, ← mul_assoc]
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_mul_C_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_mul_C_eq_of_mul_ne_zero (h : p.leadingCoeff * a ≠ 0) :
    (p * C a).natDegree = p.natDegree := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : leadingCoeff p * a ≠ 0
⊢ natDegree (p * C a) = natDegree p

Next tactic:
refine' eq_natDegree_of_le_mem_support (natDegree_mul_C_le p a) _
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_mul_C_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_mul_C_eq_of_mul_ne_zero (h : p.leadingCoeff * a ≠ 0) :
    (p * C a).natDegree = p.natDegree := by
  refine' eq_natDegree_of_le_mem_support (natDegree_mul_C_le p a) _
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : leadingCoeff p * a ≠ 0
⊢ natDegree p ∈ support (p * C a)

Next tactic:
refine' mem_support_iff.mpr _
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_mul_C_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_mul_C_eq_of_mul_ne_zero (h : p.leadingCoeff * a ≠ 0) :
    (p * C a).natDegree = p.natDegree := by
  refine' eq_natDegree_of_le_mem_support (natDegree_mul_C_le p a) _
  refine' mem_support_iff.mpr _
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : leadingCoeff p * a ≠ 0
⊢ coeff (p * C a) (natDegree p) ≠ 0

Next tactic:
rwa [coeff_mul_C]
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_C_mul_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_C_mul_eq_of_mul_ne_zero (h : a * p.leadingCoeff ≠ 0) :
    (C a * p).natDegree = p.natDegree := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : a * leadingCoeff p ≠ 0
⊢ natDegree (C a * p) = natDegree p

Next tactic:
refine' eq_natDegree_of_le_mem_support (natDegree_C_mul_le a p) _
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_C_mul_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_C_mul_eq_of_mul_ne_zero (h : a * p.leadingCoeff ≠ 0) :
    (C a * p).natDegree = p.natDegree := by
  refine' eq_natDegree_of_le_mem_support (natDegree_C_mul_le a p) _
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : a * leadingCoeff p ≠ 0
⊢ natDegree p ∈ support (C a * p)

Next tactic:
refine' mem_support_iff.mpr _
/-- Although not explicitly stated, the assumptions of lemma `nat_degree_C_mul_eq_of_mul_ne_zero`
force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`.
-/
theorem natDegree_C_mul_eq_of_mul_ne_zero (h : a * p.leadingCoeff ≠ 0) :
    (C a * p).natDegree = p.natDegree := by
  refine' eq_natDegree_of_le_mem_support (natDegree_C_mul_le a p) _
  refine' mem_support_iff.mpr _
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
h : a * leadingCoeff p ≠ 0
⊢ coeff (C a * p) (natDegree p) ≠ 0

Next tactic:
rwa [coeff_C_mul]
theorem natDegree_add_coeff_mul (f g : R[X]) :
    (f * g).coeff (f.natDegree + g.natDegree) = f.coeff f.natDegree * g.coeff g.natDegree := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r f g : R[X]
⊢ coeff (f * g) (natDegree f + natDegree g) = coeff f (natDegree f) * coeff g (natDegree g)

Next tactic:
simp only [coeff_natDegree, coeff_mul_degree_add_degree]
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
qn : natDegree q ≤ n
⊢ coeff (p * q) (m + n) = coeff p m * coeff q n

Next tactic:
rcases eq_or_lt_of_le pm with (rfl | hm)
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> 

Proof state:
case inl
R : Type u
S : Type v
ι : Type w
a b : R
n : ℕ
inst✝ : Semiring R
p q r : R[X]
qn : natDegree q ≤ n
pm : natDegree p ≤ natDegree p
⊢ coeff (p * q) (natDegree p + n) = coeff p (natDegree p) * coeff q n

Next tactic:
rcases eq_or_lt_of_le qn with (rfl | hn)
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> 

Proof state:
case inr
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
qn : natDegree q ≤ n
hm : natDegree p < m
⊢ coeff (p * q) (m + n) = coeff p m * coeff q n

Next tactic:
rcases eq_or_lt_of_le qn with (rfl | hn)
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · 

Proof state:
case inl.inl
R : Type u
S : Type v
ι : Type w
a b : R
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ natDegree p
qn : natDegree q ≤ natDegree q
⊢ coeff (p * q) (natDegree p + natDegree q) = coeff p (natDegree p) * coeff q (natDegree q)

Next tactic:
exact natDegree_add_coeff_mul _ _
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · 

Proof state:
case inl.inr
R : Type u
S : Type v
ι : Type w
a b : R
n : ℕ
inst✝ : Semiring R
p q r : R[X]
qn : natDegree q ≤ n
pm : natDegree p ≤ natDegree p
hn : natDegree q < n
⊢ coeff (p * q) (natDegree p + n) = coeff p (natDegree p) * coeff q n

Next tactic:
rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    

Proof state:
case inl.inr
R : Type u
S : Type v
ι : Type w
a b : R
n : ℕ
inst✝ : Semiring R
p q r : R[X]
qn : natDegree q ≤ n
pm : natDegree p ≤ natDegree p
hn : natDegree q < n
⊢ coeff (p * q) (natDegree p + n) = 0

Next tactic:
exact natDegree_lt_coeff_mul (add_lt_add_left hn _)
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    exact natDegree_lt_coeff_mul (add_lt_add_left hn _)
  · 

Proof state:
case inr.inl
R : Type u
S : Type v
ι : Type w
a b : R
m : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
hm : natDegree p < m
qn : natDegree q ≤ natDegree q
⊢ coeff (p * q) (m + natDegree q) = coeff p m * coeff q (natDegree q)

Next tactic:
rw [coeff_eq_zero_of_natDegree_lt hm, zero_mul]
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    exact natDegree_lt_coeff_mul (add_lt_add_left hn _)
  · rw [coeff_eq_zero_of_natDegree_lt hm, zero_mul]
    

Proof state:
case inr.inl
R : Type u
S : Type v
ι : Type w
a b : R
m : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
hm : natDegree p < m
qn : natDegree q ≤ natDegree q
⊢ coeff (p * q) (m + natDegree q) = 0

Next tactic:
exact natDegree_lt_coeff_mul (add_lt_add_right hm _)
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    exact natDegree_lt_coeff_mul (add_lt_add_left hn _)
  · rw [coeff_eq_zero_of_natDegree_lt hm, zero_mul]
    exact natDegree_lt_coeff_mul (add_lt_add_right hm _)
  · 

Proof state:
case inr.inr
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
qn : natDegree q ≤ n
hm : natDegree p < m
hn : natDegree q < n
⊢ coeff (p * q) (m + n) = coeff p m * coeff q n

Next tactic:
rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
theorem coeff_mul_of_natDegree_le (pm : p.natDegree ≤ m) (qn : q.natDegree ≤ n) :
    (p * q).coeff (m + n) = p.coeff m * q.coeff n := by
  rcases eq_or_lt_of_le pm with (rfl | hm) <;> rcases eq_or_lt_of_le qn with (rfl | hn)
  · exact natDegree_add_coeff_mul _ _
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    exact natDegree_lt_coeff_mul (add_lt_add_left hn _)
  · rw [coeff_eq_zero_of_natDegree_lt hm, zero_mul]
    exact natDegree_lt_coeff_mul (add_lt_add_right hm _)
  · rw [coeff_eq_zero_of_natDegree_lt hn, mul_zero]
    

Proof state:
case inr.inr
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pm : natDegree p ≤ m
qn : natDegree q ≤ n
hm : natDegree p < m
hn : natDegree q < n
⊢ coeff (p * q) (m + n) = 0

Next tactic:
exact natDegree_lt_coeff_mul (add_lt_add hm hn)
theorem coeff_pow_of_natDegree_le (pn : p.natDegree ≤ n) :
    (p ^ m).coeff (m * n) = p.coeff n ^ m := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
⊢ coeff (p ^ m) (m * n) = coeff p n ^ m

Next tactic:
induction' m with m hm
theorem coeff_pow_of_natDegree_le (pn : p.natDegree ≤ n) :
    (p ^ m).coeff (m * n) = p.coeff n ^ m := by
  induction' m with m hm
  · 

Proof state:
case zero
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
⊢ coeff (p ^ Nat.zero) (Nat.zero * n) = coeff p n ^ Nat.zero

Next tactic:
simp
theorem coeff_pow_of_natDegree_le (pn : p.natDegree ≤ n) :
    (p ^ m).coeff (m * n) = p.coeff n ^ m := by
  induction' m with m hm
  · simp
  · 

Proof state:
case succ
R : Type u
S : Type v
ι : Type w
a b : R
m✝ n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
m : ℕ
hm : coeff (p ^ m) (m * n) = coeff p n ^ m
⊢ coeff (p ^ Nat.succ m) (Nat.succ m * n) = coeff p n ^ Nat.succ m

Next tactic:
rw [pow_succ', pow_succ', ← hm, Nat.succ_mul, coeff_mul_of_natDegree_le _ pn]
theorem coeff_pow_of_natDegree_le (pn : p.natDegree ≤ n) :
    (p ^ m).coeff (m * n) = p.coeff n ^ m := by
  induction' m with m hm
  · simp
  · rw [pow_succ', pow_succ', ← hm, Nat.succ_mul, coeff_mul_of_natDegree_le _ pn]
    

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m✝ n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
m : ℕ
hm : coeff (p ^ m) (m * n) = coeff p n ^ m
⊢ natDegree (p ^ m) ≤ m * n

Next tactic:
refine' natDegree_pow_le.trans (le_trans _ (le_refl _))
theorem coeff_pow_of_natDegree_le (pn : p.natDegree ≤ n) :
    (p ^ m).coeff (m * n) = p.coeff n ^ m := by
  induction' m with m hm
  · simp
  · rw [pow_succ', pow_succ', ← hm, Nat.succ_mul, coeff_mul_of_natDegree_le _ pn]
    refine' natDegree_pow_le.trans (le_trans _ (le_refl _))
    

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m✝ n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
m : ℕ
hm : coeff (p ^ m) (m * n) = coeff p n ^ m
⊢ m * natDegree p ≤ m * n

Next tactic:
exact mul_le_mul_of_nonneg_left pn m.zero_le
theorem coeff_pow_eq_ite_of_natDegree_le_of_le {o : ℕ}
    (pn : natDegree p ≤ n) (mno : m * n ≤ o) :
    coeff (p ^ m) o = if o = m * n then (coeff p n) ^ m else 0 := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
o : ℕ
pn : natDegree p ≤ n
mno : m * n ≤ o
⊢ coeff (p ^ m) o = if o = m * n then coeff p n ^ m else 0

Next tactic:
rcases eq_or_ne o (m * n) with rfl | h
theorem coeff_pow_eq_ite_of_natDegree_le_of_le {o : ℕ}
    (pn : natDegree p ≤ n) (mno : m * n ≤ o) :
    coeff (p ^ m) o = if o = m * n then (coeff p n) ^ m else 0 := by
  rcases eq_or_ne o (m * n) with rfl | h
  · 

Proof state:
case inl
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p ≤ n
mno : m * n ≤ m * n
⊢ coeff (p ^ m) (m * n) = if m * n = m * n then coeff p n ^ m else 0

Next tactic:
simpa only [ite_true] using coeff_pow_of_natDegree_le pn
theorem coeff_pow_eq_ite_of_natDegree_le_of_le {o : ℕ}
    (pn : natDegree p ≤ n) (mno : m * n ≤ o) :
    coeff (p ^ m) o = if o = m * n then (coeff p n) ^ m else 0 := by
  rcases eq_or_ne o (m * n) with rfl | h
  · simpa only [ite_true] using coeff_pow_of_natDegree_le pn
  · 

Proof state:
case inr
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
o : ℕ
pn : natDegree p ≤ n
mno : m * n ≤ o
h : o ≠ m * n
⊢ coeff (p ^ m) o = if o = m * n then coeff p n ^ m else 0

Next tactic:
simpa only [h, ite_false] using coeff_eq_zero_of_natDegree_lt $
      lt_of_le_of_lt (natDegree_pow_le_of_le m pn) (lt_of_le_of_ne mno h.symm)
theorem coeff_add_eq_right_of_lt (pn : p.natDegree < n) : (p + q).coeff n = q.coeff n := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p < n
⊢ coeff (p + q) n = coeff q n

Next tactic:
rw [add_comm]
theorem coeff_add_eq_right_of_lt (pn : p.natDegree < n) : (p + q).coeff n = q.coeff n := by
  rw [add_comm]
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
pn : natDegree p < n
⊢ coeff (q + p) n = coeff q n

Next tactic:
exact coeff_add_eq_left_of_lt pn
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
s : Finset S
h : Set.Pairwise {i | i ∈ s ∧ f i ≠ 0} (Ne on degree ∘ f)
⊢ degree (Finset.sum s f) = sup s fun i => degree (f i)

Next tactic:
classical
  induction' s using Finset.induction_on with x s hx IH
  · simp
  · simp only [hx, Finset.sum_insert, not_false_iff, Finset.sup_insert]
    specialize IH (h.mono fun _ => by simp (config := { contextual := true }))
    rcases lt_trichotomy (degree (f x)) (degree (s.sum f)) with (H | H | H)
    · rw [← IH, sup_eq_right.mpr H.le, degree_add_eq_right_of_degree_lt H]
    · rcases s.eq_empty_or_nonempty with (rfl | hs)
      · simp
      obtain ⟨y, hy, hy'⟩ := Finset.exists_mem_eq_sup s hs fun i => degree (f i)
      rw [IH, hy'] at H
      by_cases hx0 : f x = 0
      · simp [hx0, IH]
      have hy0 : f y ≠ 0 := by
        contrapose! H
        simpa [H, degree_eq_bot] using hx0
      refine' absurd H (h _ _ fun H => hx _)
      · simp [hx0]
      · simp [hy, hy0]
      · exact H.symm ▸ hy
    · rw [← IH, sup_eq_left.mpr H.le, degree_add_eq_left_of_degree_lt H]
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
s : Finset S
h : Set.Pairwise {i | i ∈ s ∧ f i ≠ 0} (Ne on degree ∘ f)
⊢ degree (Finset.sum s f) = sup s fun i => degree (f i)

Next tactic:
induction' s using Finset.induction_on with x s hx IH
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  induction' s using Finset.induction_on with x s hx IH
  · 

Proof state:
case empty
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
h : Set.Pairwise {i | i ∈ ∅ ∧ f i ≠ 0} (Ne on degree ∘ f)
⊢ degree (Finset.sum ∅ f) = sup ∅ fun i => degree (f i)

Next tactic:
simp
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  induction' s using Finset.induction_on with x s hx IH
  · simp
  · 

Proof state:
case insert
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
x : S
s : Finset S
hx : x ∉ s
IH : Set.Pairwise {i | i ∈ s ∧ f i ≠ 0} (Ne on degree ∘ f) → degree (Finset.sum s f) = sup s fun i => degree (f i)
h : Set.Pairwise {i | i ∈ insert x s ∧ f i ≠ 0} (Ne on degree ∘ f)
⊢ degree (Finset.sum (insert x s) f) = sup (insert x s) fun i => degree (f i)

Next tactic:
simp only [hx, Finset.sum_insert, not_false_iff, Finset.sup_insert]
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  induction' s using Finset.induction_on with x s hx IH
  · simp
  · simp only [hx, Finset.sum_insert, not_false_iff, Finset.sup_insert]
    

Proof state:
case insert
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
x : S
s : Finset S
hx : x ∉ s
IH : Set.Pairwise {i | i ∈ s ∧ f i ≠ 0} (Ne on degree ∘ f) → degree (Finset.sum s f) = sup s fun i => degree (f i)
h : Set.Pairwise {i | i ∈ insert x s ∧ f i ≠ 0} (Ne on degree ∘ f)
⊢ degree (f x + Finset.sum s fun x => f x) = degree (f x) ⊔ sup s fun i => degree (f i)

Next tactic:
specialize IH (h.mono fun _ => by simp (config := { contextual := true }))
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  induction' s using Finset.induction_on with x s hx IH
  · simp
  · simp only [hx, Finset.sum_insert, not_false_iff, Finset.sup_insert]
    specialize IH (h.mono fun _ => by 

Proof state:
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
x : S
s : Finset S
hx : x ∉ s
IH : Set.Pairwise {i | i ∈ s ∧ f i ≠ 0} (Ne on degree ∘ f) → degree (Finset.sum s f) = sup s fun i => degree (f i)
h : Set.Pairwise {i | i ∈ insert x s ∧ f i ≠ 0} (Ne on degree ∘ f)
x✝ : S
⊢ x✝ ∈ {i | i ∈ s ∧ f i ≠ 0} → x✝ ∈ {i | i ∈ insert x s ∧ f i ≠ 0}

Next tactic:
simp (config := { contextual := true })
theorem degree_sum_eq_of_disjoint (f : S → R[X]) (s : Finset S)
    (h : Set.Pairwise { i | i ∈ s ∧ f i ≠ 0 } (Ne on degree ∘ f)) :
    degree (s.sum f) = s.sup fun i => degree (f i) := by
  classical
  induction' s using Finset.induction_on with x s hx IH
  · simp
  · simp only [hx, Finset.sum_insert, not_false_iff, Finset.sup_insert]
    specialize IH (h.mono fun _ => by simp (config := { contextual := true }))
    

Proof state:
case insert
R : Type u
S : Type v
ι : Type w
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
f : S → R[X]
x : S
s : Finset S
hx : x ∉ s
h : Set.Pairwise {i | i ∈ insert x s ∧ f i ≠ 0} (Ne on degree ∘ f)
IH : degree (Finset.sum s f) = sup s fun i => degree (f i)
⊢ degree (f x + Finset.sum s fun x => f x) = degree (f x) ⊔ sup s fun i => degree (f i)

Next tactic:
rcases lt_trichotomy (degree (f x)) (degree (s.sum f)) with (H | H | H)