l3lab/ntp-mathlib huggingface dataset:
theorem le_natTrailingDegree_mul (h : p * q ≠ 0) :
    p.natTrailingDegree + q.natTrailingDegree ≤ (p * q).natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, mul_zero])
  -- Porting note: Needed to account for different coercion behaviour & add the lemma below
  have : ∀ (p : R[X]), WithTop.some (natTrailingDegree p) = Nat.cast (natTrailingDegree p) :=
    fun p ↦ rfl
  rw [← WithTop.coe_le_coe, WithTop.coe_add, this p, this q, this (p * q),
    ← trailingDegree_eq_natTrailingDegree hp, ← trailingDegree_eq_natTrailingDegree hq,
    ← trailingDegree_eq_natTrailingDegree h]
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : p * q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
this : ∀ (p : R[X]), ↑(natTrailingDegree p) = ↑(natTrailingDegree p)
⊢ trailingDegree p + trailingDegree q ≤ trailingDegree (p * q)

Next tactic:
exact le_trailingDegree_mul
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  

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

Next tactic:
rw [coeff_mul]
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
⊢ ∑ x in antidiagonal (natTrailingDegree p + natTrailingDegree q), coeff p x.1 * coeff q x.2 =
    trailingCoeff p * trailingCoeff q

Next tactic:
refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
⊢ ∀ b ∈ antidiagonal (natTrailingDegree p + natTrailingDegree q),
    b ≠ (natTrailingDegree p, natTrailingDegree q) → coeff p b.1 * coeff q b.2 = 0

Next tactic:
rintro ⟨i, j⟩ h₁ h₂
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  

Proof state:
case mk
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j) ∈ antidiagonal (natTrailingDegree p + natTrailingDegree q)
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
rw [mem_antidiagonal] at h₁
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  

Proof state:
case mk
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
by_cases hi : i < p.natTrailingDegree
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · 

Proof state:
case pos
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : i < natTrailingDegree p
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
  

Proof state:
case neg
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : ¬i < natTrailingDegree p
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
by_cases hj : j < q.natTrailingDegree
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
  by_cases hj : j < q.natTrailingDegree
  · 

Proof state:
case pos
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : ¬i < natTrailingDegree p
hj : j < natTrailingDegree q
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
rw [coeff_eq_zero_of_lt_natTrailingDegree hj, mul_zero]
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
  by_cases hj : j < q.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hj, mul_zero]
  

Proof state:
case neg
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : ¬i < natTrailingDegree p
hj : ¬j < natTrailingDegree q
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
rw [not_lt] at hi hj
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
  by_cases hj : j < q.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hj, mul_zero]
  rw [not_lt] at hi hj
  

Proof state:
case neg
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : natTrailingDegree p ≤ i
hj : natTrailingDegree q ≤ j
⊢ coeff p (i, j).1 * coeff q (i, j).2 = 0

Next tactic:
refine' (h₂ (Prod.ext_iff.mpr _).symm).elim
theorem coeff_mul_natTrailingDegree_add_natTrailingDegree : (p * q).coeff
    (p.natTrailingDegree + q.natTrailingDegree) = p.trailingCoeff * q.trailingCoeff := by
  rw [coeff_mul]
  refine'
    Finset.sum_eq_single (p.natTrailingDegree, q.natTrailingDegree) _ fun h =>
      (h (mem_antidiagonal.mpr rfl)).elim
  rintro ⟨i, j⟩ h₁ h₂
  rw [mem_antidiagonal] at h₁
  by_cases hi : i < p.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hi, zero_mul]
  by_cases hj : j < q.natTrailingDegree
  · rw [coeff_eq_zero_of_lt_natTrailingDegree hj, mul_zero]
  rw [not_lt] at hi hj
  refine' (h₂ (Prod.ext_iff.mpr _).symm).elim
  

Proof state:
case neg
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
i j : ℕ
h₁ : (i, j).1 + (i, j).2 = natTrailingDegree p + natTrailingDegree q
h₂ : (i, j) ≠ (natTrailingDegree p, natTrailingDegree q)
hi : natTrailingDegree p ≤ i
hj : natTrailingDegree q ≤ j
⊢ (natTrailingDegree p, natTrailingDegree q).1 = (i, j).1 ∧ (natTrailingDegree p, natTrailingDegree q).2 = (i, j).2

Next tactic:
exact (add_eq_add_iff_eq_and_eq hi hj).mp h₁.symm
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
⊢ trailingDegree (p * q) = trailingDegree p + trailingDegree q

Next tactic:
have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by 

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p = 0
⊢ trailingCoeff p * trailingCoeff q = 0

Next tactic:
rw [hp, trailingCoeff_zero, zero_mul]
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
⊢ trailingDegree (p * q) = trailingDegree p + trailingDegree q

Next tactic:
have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by 

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q = 0
⊢ trailingCoeff p * trailingCoeff q = 0

Next tactic:
rw [hq, trailingCoeff_zero, mul_zero]
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
⊢ trailingDegree (p * q) = trailingDegree p + trailingDegree q

Next tactic:
refine' le_antisymm _ le_trailingDegree_mul
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  refine' le_antisymm _ le_trailingDegree_mul
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
⊢ trailingDegree (p * q) ≤ trailingDegree p + trailingDegree q

Next tactic:
rw [trailingDegree_eq_natTrailingDegree hp, trailingDegree_eq_natTrailingDegree hq, ←
    ENat.coe_add]
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  refine' le_antisymm _ le_trailingDegree_mul
  rw [trailingDegree_eq_natTrailingDegree hp, trailingDegree_eq_natTrailingDegree hq, ←
    ENat.coe_add]
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
⊢ trailingDegree (p * q) ≤ ↑(natTrailingDegree p + natTrailingDegree q)

Next tactic:
apply le_trailingDegree_of_ne_zero
theorem trailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  refine' le_antisymm _ le_trailingDegree_mul
  rw [trailingDegree_eq_natTrailingDegree hp, trailingDegree_eq_natTrailingDegree hq, ←
    ENat.coe_add]
  apply le_trailingDegree_of_ne_zero
  

Proof state:
case h
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
⊢ coeff (p * q) (natTrailingDegree p + natTrailingDegree q) ≠ 0

Next tactic:
rwa [coeff_mul_natTrailingDegree_add_natTrailingDegree]
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
⊢ natTrailingDegree (p * q) = natTrailingDegree p + natTrailingDegree q

Next tactic:
have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by 

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p = 0
⊢ trailingCoeff p * trailingCoeff q = 0

Next tactic:
rw [hp, trailingCoeff_zero, zero_mul]
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
⊢ natTrailingDegree (p * q) = natTrailingDegree p + natTrailingDegree q

Next tactic:
have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by 

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q = 0
⊢ trailingCoeff p * trailingCoeff q = 0

Next tactic:
rw [hq, trailingCoeff_zero, mul_zero]
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  -- Porting note: Needed to account for different coercion behaviour & add the lemmas below
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
⊢ natTrailingDegree (p * q) = natTrailingDegree p + natTrailingDegree q

Next tactic:
have aux1 : ∀ n, Nat.cast n = WithTop.some (n) := fun n ↦ rfl
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  -- Porting note: Needed to account for different coercion behaviour & add the lemmas below
  have aux1 : ∀ n, Nat.cast n = WithTop.some (n) := fun n ↦ rfl
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
aux1 : ∀ (n : ℕ), ↑n = ↑n
⊢ natTrailingDegree (p * q) = natTrailingDegree p + natTrailingDegree q

Next tactic:
have aux2 : ∀ (p : R[X]), WithTop.some (natTrailingDegree p) = Nat.cast (natTrailingDegree p) :=
    fun p ↦ rfl
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  -- Porting note: Needed to account for different coercion behaviour & add the lemmas below
  have aux1 : ∀ n, Nat.cast n = WithTop.some (n) := fun n ↦ rfl
  have aux2 : ∀ (p : R[X]), WithTop.some (natTrailingDegree p) = Nat.cast (natTrailingDegree p) :=
    fun p ↦ rfl
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
aux1 : ∀ (n : ℕ), ↑n = ↑n
aux2 : ∀ (p : R[X]), ↑(natTrailingDegree p) = ↑(natTrailingDegree p)
⊢ natTrailingDegree (p * q) = natTrailingDegree p + natTrailingDegree q

Next tactic:
apply natTrailingDegree_eq_of_trailingDegree_eq_some
theorem natTrailingDegree_mul' (h : p.trailingCoeff * q.trailingCoeff ≠ 0) :
    (p * q).natTrailingDegree = p.natTrailingDegree + q.natTrailingDegree := by
  have hp : p ≠ 0 := fun hp => h (by rw [hp, trailingCoeff_zero, zero_mul])
  have hq : q ≠ 0 := fun hq => h (by rw [hq, trailingCoeff_zero, mul_zero])
  -- Porting note: Needed to account for different coercion behaviour & add the lemmas below
  have aux1 : ∀ n, Nat.cast n = WithTop.some (n) := fun n ↦ rfl
  have aux2 : ∀ (p : R[X]), WithTop.some (natTrailingDegree p) = Nat.cast (natTrailingDegree p) :=
    fun p ↦ rfl
  apply natTrailingDegree_eq_of_trailingDegree_eq_some
  

Proof state:
case h
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p q r : R[X]
h : trailingCoeff p * trailingCoeff q ≠ 0
hp : p ≠ 0
hq : q ≠ 0
aux1 : ∀ (n : ℕ), ↑n = ↑n
aux2 : ∀ (p : R[X]), ↑(natTrailingDegree p) = ↑(natTrailingDegree p)
⊢ trailingDegree (p * q) = ↑(natTrailingDegree p + natTrailingDegree q)

Next tactic:
rw [trailingDegree_mul' h, aux1 (natTrailingDegree p + natTrailingDegree q),
    WithTop.coe_add, aux2 p, aux2 q, ← trailingDegree_eq_natTrailingDegree hp, ←
    trailingDegree_eq_natTrailingDegree hq]
@[simp]
theorem trailingDegree_neg (p : R[X]) : trailingDegree (-p) = trailingDegree p := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Ring R
p : R[X]
⊢ trailingDegree (-p) = trailingDegree p

Next tactic:
unfold trailingDegree
@[simp]
theorem trailingDegree_neg (p : R[X]) : trailingDegree (-p) = trailingDegree p := by
  unfold trailingDegree
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Ring R
p : R[X]
⊢ Finset.min (support (-p)) = Finset.min (support p)

Next tactic:
rw [support_neg]
@[simp]
theorem natTrailingDegree_neg (p : R[X]) : natTrailingDegree (-p) = natTrailingDegree p := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Ring R
p : R[X]
⊢ natTrailingDegree (-p) = natTrailingDegree p

Next tactic:
simp [natTrailingDegree]
@[simp]
theorem natTrailingDegree_int_cast (n : ℤ) : natTrailingDegree (n : R[X]) = 0 := by
  

Proof state:
R : Type u
S : Type v
a b : R
n✝ m : ℕ
inst✝ : Ring R
n : ℤ
⊢ natTrailingDegree ↑n = 0

Next tactic:
simp only [← C_eq_int_cast, natTrailingDegree_C]
@[simp]
theorem nextCoeffUp_C_eq_zero (c : R) : nextCoeffUp (C c) = 0 := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
c : R
⊢ nextCoeffUp (C c) = 0

Next tactic:
rw [nextCoeffUp]
@[simp]
theorem nextCoeffUp_C_eq_zero (c : R) : nextCoeffUp (C c) = 0 := by
  rw [nextCoeffUp]
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
c : R
⊢ (if natTrailingDegree (C c) = 0 then 0 else coeff (C c) (natTrailingDegree (C c) + 1)) = 0

Next tactic:
simp
theorem nextCoeffUp_of_pos_natTrailingDegree (p : R[X]) (hp : 0 < p.natTrailingDegree) :
    nextCoeffUp p = p.coeff (p.natTrailingDegree + 1) := by
  

Proof state:
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p : R[X]
hp : 0 < natTrailingDegree p
⊢ nextCoeffUp p = coeff p (natTrailingDegree p + 1)

Next tactic:
rw [nextCoeffUp, if_neg]
theorem nextCoeffUp_of_pos_natTrailingDegree (p : R[X]) (hp : 0 < p.natTrailingDegree) :
    nextCoeffUp p = p.coeff (p.natTrailingDegree + 1) := by
  rw [nextCoeffUp, if_neg]
  

Proof state:
case hnc
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p : R[X]
hp : 0 < natTrailingDegree p
⊢ ¬natTrailingDegree p = 0

Next tactic:
contrapose! hp
theorem nextCoeffUp_of_pos_natTrailingDegree (p : R[X]) (hp : 0 < p.natTrailingDegree) :
    nextCoeffUp p = p.coeff (p.natTrailingDegree + 1) := by
  rw [nextCoeffUp, if_neg]
  contrapose! hp
  

Proof state:
case hnc
R : Type u
S : Type v
a b : R
n m : ℕ
inst✝ : Semiring R
p : R[X]
hp : natTrailingDegree p = 0
⊢ natTrailingDegree p ≤ 0

Next tactic:
simpa
theorem ne_zero_of_trailingDegree_lt {n : ℕ∞} (h : trailingDegree p < n) : p ≠ 0 := fun h₀ =>
  h.not_le (by 

Proof state:
R : Type u
S : Type v
a b : R
n✝ m : ℕ
inst✝ : Semiring R
p q : R[X]
ι : Type u_1
n : ℕ∞
h : trailingDegree p < n
h₀ : p = 0
⊢ n ≤ trailingDegree p

Next tactic:
simp [h₀]
theorem IsSymm.pow [CommSemiring α] [Fintype n] [DecidableEq n] {A : Matrix n n α} (h : A.IsSymm)
    (k : ℕ) :
    (A ^ k).IsSymm := by
  

Proof state:
α : Type u_1
β : Type u_2
n : Type u_3
m : Type u_4
R : Type u_5
inst✝² : CommSemiring α
inst✝¹ : Fintype n
inst✝ : DecidableEq n
A : Matrix n n α
h : IsSymm A
k : ℕ
⊢ IsSymm (A ^ k)

Next tactic:
rw [IsSymm, transpose_pow, h]
/-- A block matrix `A.fromBlocks B C D` is symmetric,
    if `A` and `D` are symmetric and `Bᵀ = C`. -/
theorem IsSymm.fromBlocks {A : Matrix m m α} {B : Matrix m n α} {C : Matrix n m α}
    {D : Matrix n n α} (hA : A.IsSymm) (hBC : Bᵀ = C) (hD : D.IsSymm) :
    (A.fromBlocks B C D).IsSymm := by
  

Proof state:
α : Type u_1
β : Type u_2
n : Type u_3
m : Type u_4
R : Type u_5
A : Matrix m m α
B : Matrix m n α
C : Matrix n m α
D : Matrix n n α
hA : IsSymm A
hBC : Bᵀ = C
hD : IsSymm D
⊢ IsSymm (Matrix.fromBlocks A B C D)

Next tactic:
have hCB : Cᵀ = B := by
    rw [← hBC]
    simp
/-- A block matrix `A.fromBlocks B C D` is symmetric,
    if `A` and `D` are symmetric and `Bᵀ = C`. -/
theorem IsSymm.fromBlocks {A : Matrix m m α} {B : Matrix m n α} {C : Matrix n m α}
    {D : Matrix n n α} (hA : A.IsSymm) (hBC : Bᵀ = C) (hD : D.IsSymm) :
    (A.fromBlocks B C D).IsSymm := by
  have hCB : Cᵀ = B := by
    

Proof state:
α : Type u_1
β : Type u_2
n : Type u_3
m : Type u_4
R : Type u_5
A : Matrix m m α
B : Matrix m n α
C : Matrix n m α
D : Matrix n n α
hA : IsSymm A
hBC : Bᵀ = C
hD : IsSymm D
⊢ Cᵀ = B

Next tactic:
rw [← hBC]
/-- A block matrix `A.fromBlocks B C D` is symmetric,
    if `A` and `D` are symmetric and `Bᵀ = C`. -/
theorem IsSymm.fromBlocks {A : Matrix m m α} {B : Matrix m n α} {C : Matrix n m α}
    {D : Matrix n n α} (hA : A.IsSymm) (hBC : Bᵀ = C) (hD : D.IsSymm) :
    (A.fromBlocks B C D).IsSymm := by
  have hCB : Cᵀ = B := by
    rw [← hBC]
    

Proof state:
α : Type u_1
β : Type u_2
n : Type u_3
m : Type u_4
R : Type u_5
A : Matrix m m α
B : Matrix m n α
C : Matrix n m α
D : Matrix n n α
hA : IsSymm A
hBC : Bᵀ = C
hD : IsSymm D
⊢ Bᵀᵀ = B

Next tactic:
simp