l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by
  classical
  exact if hp0 : p = 0 then
    if hn0 : n = 0 then by simp [hp0, hn0]
    else by 

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n✝ : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
n : ℕ
hp0 : p = 0
hn0 : ¬n = 0
⊢ natDegree (p ^ n) = n * natDegree p

Next tactic:
rw [hp0, zero_pow (Nat.pos_of_ne_zero hn0)]
@[simp]
theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by
  classical
  exact if hp0 : p = 0 then
    if hn0 : n = 0 then by simp [hp0, hn0]
    else by rw [hp0, zero_pow (Nat.pos_of_ne_zero hn0)]; 

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n✝ : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
n : ℕ
hp0 : p = 0
hn0 : ¬n = 0
⊢ natDegree 0 = n * natDegree 0

Next tactic:
simp
@[simp]
theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by
  classical
  exact if hp0 : p = 0 then
    if hn0 : n = 0 then by simp [hp0, hn0]
    else by rw [hp0, zero_pow (Nat.pos_of_ne_zero hn0)]; simp
  else
    natDegree_pow'
      (by 

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n✝ : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
n : ℕ
hp0 : ¬p = 0
⊢ leadingCoeff p ^ n ≠ 0

Next tactic:
rw [← leadingCoeff_pow, Ne.def, leadingCoeff_eq_zero]
@[simp]
theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by
  classical
  exact if hp0 : p = 0 then
    if hn0 : n = 0 then by simp [hp0, hn0]
    else by rw [hp0, zero_pow (Nat.pos_of_ne_zero hn0)]; simp
  else
    natDegree_pow'
      (by rw [← leadingCoeff_pow, Ne.def, leadingCoeff_eq_zero]; 

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n✝ : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
n : ℕ
hp0 : ¬p = 0
⊢ ¬p ^ n = 0

Next tactic:
exact pow_ne_zero _ hp0
theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
hq : q ≠ 0
⊢ degree p ≤ degree (p * q)

Next tactic:
classical
  exact if hp : p = 0 then by simp only [hp, zero_mul, le_refl]
  else by
    rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq];
      exact WithBot.coe_le_coe.2 (Nat.le_add_right _ _)
theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by
  classical
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
hq : q ≠ 0
⊢ degree p ≤ degree (p * q)

Next tactic:
exact if hp : p = 0 then by simp only [hp, zero_mul, le_refl]
  else by
    rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq];
      exact WithBot.coe_le_coe.2 (Nat.le_add_right _ _)
theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by
  classical
  exact if hp : p = 0 then by 

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
hq : q ≠ 0
hp : p = 0
⊢ degree p ≤ degree (p * q)

Next tactic:
simp only [hp, zero_mul, le_refl]
theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by
  classical
  exact if hp : p = 0 then by simp only [hp, zero_mul, le_refl]
  else by
    

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
hq : q ≠ 0
hp : ¬p = 0
⊢ degree p ≤ degree (p * q)

Next tactic:
rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq]
theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by
  classical
  exact if hp : p = 0 then by simp only [hp, zero_mul, le_refl]
  else by
    rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq];
      

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q p : R[X]
hq : q ≠ 0
hp : ¬p = 0
⊢ ↑(natDegree p) ≤ ↑(natDegree p) + ↑(natDegree q)

Next tactic:
exact WithBot.coe_le_coe.2 (Nat.le_add_right _ _)
theorem natDegree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h1 : p ∣ q
h2 : q ≠ 0
⊢ natDegree p ≤ natDegree q

Next tactic:
rcases h1 with ⟨q, rfl⟩
theorem natDegree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by
  rcases h1 with ⟨q, rfl⟩; 

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h2 : p * q ≠ 0
⊢ natDegree p ≤ natDegree (p * q)

Next tactic:
rw [mul_ne_zero_iff] at h2
theorem natDegree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by
  rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2
  

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h2 : p ≠ 0 ∧ q ≠ 0
⊢ natDegree p ≤ natDegree (p * q)

Next tactic:
rw [natDegree_mul h2.1 h2.2]
theorem natDegree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by
  rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2
  rw [natDegree_mul h2.1 h2.2]; 

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h2 : p ≠ 0 ∧ q ≠ 0
⊢ natDegree p ≤ natDegree p + natDegree q

Next tactic:
exact Nat.le_add_right _ _
theorem degree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h1 : p ∣ q
h2 : q ≠ 0
⊢ degree p ≤ degree q

Next tactic:
rcases h1 with ⟨q, rfl⟩
theorem degree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by
  rcases h1 with ⟨q, rfl⟩; 

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h2 : p * q ≠ 0
⊢ degree p ≤ degree (p * q)

Next tactic:
rw [mul_ne_zero_iff] at h2
theorem degree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by
  rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2
  

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h2 : p ≠ 0 ∧ q ≠ 0
⊢ degree p ≤ degree (p * q)

Next tactic:
exact degree_le_mul_left p h2.2
theorem eq_zero_of_dvd_of_degree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : degree q < degree p) :
    q = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h₁ : p ∣ q
h₂ : degree q < degree p
⊢ q = 0

Next tactic:
by_contra hc
theorem eq_zero_of_dvd_of_degree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : degree q < degree p) :
    q = 0 := by
  by_contra hc
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h₁ : p ∣ q
h₂ : degree q < degree p
hc : ¬q = 0
⊢ False

Next tactic:
exact (lt_iff_not_ge _ _).mp h₂ (degree_le_of_dvd h₁ hc)
theorem eq_zero_of_dvd_of_natDegree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : natDegree q < natDegree p) :
    q = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h₁ : p ∣ q
h₂ : natDegree q < natDegree p
⊢ q = 0

Next tactic:
by_contra hc
theorem eq_zero_of_dvd_of_natDegree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : natDegree q < natDegree p) :
    q = 0 := by
  by_contra hc
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h₁ : p ∣ q
h₂ : natDegree q < natDegree p
hc : ¬q = 0
⊢ False

Next tactic:
exact (lt_iff_not_ge _ _).mp h₂ (natDegree_le_of_dvd h₁ hc)
theorem not_dvd_of_degree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h0 : q ≠ 0
hl : degree q < degree p
⊢ ¬p ∣ q

Next tactic:
by_contra hcontra
theorem not_dvd_of_degree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q := by
  by_contra hcontra
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h0 : q ≠ 0
hl : degree q < degree p
hcontra : p ∣ q
⊢ False

Next tactic:
exact h0 (eq_zero_of_dvd_of_degree_lt hcontra hl)
theorem not_dvd_of_natDegree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) :
    ¬p ∣ q := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h0 : q ≠ 0
hl : natDegree q < natDegree p
⊢ ¬p ∣ q

Next tactic:
by_contra hcontra
theorem not_dvd_of_natDegree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) :
    ¬p ∣ q := by
  by_contra hcontra
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p✝ q✝ p q : R[X]
h0 : q ≠ 0
hl : natDegree q < natDegree p
hcontra : p ∣ q
⊢ False

Next tactic:
exact h0 (eq_zero_of_dvd_of_natDegree_lt hcontra hl)
/-- This lemma is useful for working with the `intDegree` of a rational function. -/
theorem natDegree_sub_eq_of_prod_eq {p₁ p₂ q₁ q₂ : R[X]} (hp₁ : p₁ ≠ 0) (hq₁ : q₁ ≠ 0)
    (hp₂ : p₂ ≠ 0) (hq₂ : q₂ ≠ 0) (h_eq : p₁ * q₂ = p₂ * q₁) :
    (p₁.natDegree : ℤ) - q₁.natDegree = (p₂.natDegree : ℤ) - q₂.natDegree := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q p₁ p₂ q₁ q₂ : R[X]
hp₁ : p₁ ≠ 0
hq₁ : q₁ ≠ 0
hp₂ : p₂ ≠ 0
hq₂ : q₂ ≠ 0
h_eq : p₁ * q₂ = p₂ * q₁
⊢ ↑(natDegree p₁) - ↑(natDegree q₁) = ↑(natDegree p₂) - ↑(natDegree q₂)

Next tactic:
rw [sub_eq_sub_iff_add_eq_add]
/-- This lemma is useful for working with the `intDegree` of a rational function. -/
theorem natDegree_sub_eq_of_prod_eq {p₁ p₂ q₁ q₂ : R[X]} (hp₁ : p₁ ≠ 0) (hq₁ : q₁ ≠ 0)
    (hp₂ : p₂ ≠ 0) (hq₂ : q₂ ≠ 0) (h_eq : p₁ * q₂ = p₂ * q₁) :
    (p₁.natDegree : ℤ) - q₁.natDegree = (p₂.natDegree : ℤ) - q₂.natDegree := by
  rw [sub_eq_sub_iff_add_eq_add]
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q p₁ p₂ q₁ q₂ : R[X]
hp₁ : p₁ ≠ 0
hq₁ : q₁ ≠ 0
hp₂ : p₂ ≠ 0
hq₂ : q₂ ≠ 0
h_eq : p₁ * q₂ = p₂ * q₁
⊢ ↑(natDegree p₁) + ↑(natDegree q₂) = ↑(natDegree p₂) + ↑(natDegree q₁)

Next tactic:
norm_cast
/-- This lemma is useful for working with the `intDegree` of a rational function. -/
theorem natDegree_sub_eq_of_prod_eq {p₁ p₂ q₁ q₂ : R[X]} (hp₁ : p₁ ≠ 0) (hq₁ : q₁ ≠ 0)
    (hp₂ : p₂ ≠ 0) (hq₂ : q₂ ≠ 0) (h_eq : p₁ * q₂ = p₂ * q₁) :
    (p₁.natDegree : ℤ) - q₁.natDegree = (p₂.natDegree : ℤ) - q₂.natDegree := by
  rw [sub_eq_sub_iff_add_eq_add]
  norm_cast
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q p₁ p₂ q₁ q₂ : R[X]
hp₁ : p₁ ≠ 0
hq₁ : q₁ ≠ 0
hp₂ : p₂ ≠ 0
hq₂ : q₂ ≠ 0
h_eq : p₁ * q₂ = p₂ * q₁
⊢ natDegree p₁ + natDegree q₂ = natDegree p₂ + natDegree q₁

Next tactic:
rw [← natDegree_mul hp₁ hq₂, ← natDegree_mul hp₂ hq₁, h_eq]
theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q : R[X]
h : IsUnit p
⊢ natDegree p = 0

Next tactic:
nontriviality R
theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by
  nontriviality R
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q : R[X]
h : IsUnit p
✝ : Nontrivial R
⊢ natDegree p = 0

Next tactic:
obtain ⟨q, hq⟩ := h.exists_right_inv
theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by
  nontriviality R
  obtain ⟨q, hq⟩ := h.exists_right_inv
  

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q✝ : R[X]
h : IsUnit p
✝ : Nontrivial R
q : R[X]
hq : p * q = 1
⊢ natDegree p = 0

Next tactic:
have := natDegree_mul (left_ne_zero_of_mul_eq_one hq) (right_ne_zero_of_mul_eq_one hq)
theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by
  nontriviality R
  obtain ⟨q, hq⟩ := h.exists_right_inv
  have := natDegree_mul (left_ne_zero_of_mul_eq_one hq) (right_ne_zero_of_mul_eq_one hq)
  

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q✝ : R[X]
h : IsUnit p
✝ : Nontrivial R
q : R[X]
hq : p * q = 1
this : natDegree (p * q) = natDegree p + natDegree q
⊢ natDegree p = 0

Next tactic:
rw [hq, natDegree_one, eq_comm, add_eq_zero_iff] at this
theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by
  nontriviality R
  obtain ⟨q, hq⟩ := h.exists_right_inv
  have := natDegree_mul (left_ne_zero_of_mul_eq_one hq) (right_ne_zero_of_mul_eq_one hq)
  rw [hq, natDegree_one, eq_comm, add_eq_zero_iff] at this
  

Proof state:
case intro
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : Semiring R
inst✝ : NoZeroDivisors R
p q✝ : R[X]
h : IsUnit p
✝ : Nontrivial R
q : R[X]
hq : p * q = 1
this : natDegree p = 0 ∧ natDegree q = 0
⊢ natDegree p = 0

Next tactic:
exact this.1
theorem irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) :
    Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : p ≠ 1
⊢ Irreducible p ↔ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → f = 1 ∨ g = 1

Next tactic:
refine'
    ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h =>
      ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg =>
        (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) _ _ _).symm.imp (isUnit_of_mul_eq_one f _)
          (isUnit_of_mul_eq_one g _)⟩⟩
theorem irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) :
    Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by
  refine'
    ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h =>
      ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg =>
        (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) _ _ _).symm.imp (isUnit_of_mul_eq_one f _)
          (isUnit_of_mul_eq_one g _)⟩⟩
  · 

Proof state:
case refine'_1
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : p ≠ 1
h : ∀ (f g : R[X]), Monic f → Monic g → f * g = p → f = 1 ∨ g = 1
f g : R[X]
hfg : p = f * g
⊢ Monic (g * C (leadingCoeff f))

Next tactic:
rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, mul_comm, ← hfg, ← Monic]
theorem irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) :
    Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by
  refine'
    ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h =>
      ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg =>
        (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) _ _ _).symm.imp (isUnit_of_mul_eq_one f _)
          (isUnit_of_mul_eq_one g _)⟩⟩
  · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, mul_comm, ← hfg, ← Monic]
  · 

Proof state:
case refine'_2
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : p ≠ 1
h : ∀ (f g : R[X]), Monic f → Monic g → f * g = p → f = 1 ∨ g = 1
f g : R[X]
hfg : p = f * g
⊢ Monic (f * C (leadingCoeff g))

Next tactic:
rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, ← hfg, ← Monic]
theorem irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) :
    Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by
  refine'
    ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h =>
      ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg =>
        (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) _ _ _).symm.imp (isUnit_of_mul_eq_one f _)
          (isUnit_of_mul_eq_one g _)⟩⟩
  · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, mul_comm, ← hfg, ← Monic]
  · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, ← hfg, ← Monic]
  · 

Proof state:
case refine'_3
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : p ≠ 1
h : ∀ (f g : R[X]), Monic f → Monic g → f * g = p → f = 1 ∨ g = 1
f g : R[X]
hfg : p = f * g
⊢ g * C (leadingCoeff f) * (f * C (leadingCoeff g)) = p

Next tactic:
rw [mul_mul_mul_comm, ← C_mul, ← leadingCoeff_mul, ← hfg, hp.leadingCoeff, C_1, mul_one,
      mul_comm, ← hfg]
theorem Monic.irreducible_iff_natDegree (hp : p.Monic) :
    Irreducible p ↔
      p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ Irreducible p ↔ p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0

Next tactic:
by_cases hp1 : p = 1
theorem Monic.irreducible_iff_natDegree (hp : p.Monic) :
    Irreducible p ↔
      p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by
  by_cases hp1 : p = 1; · 

Proof state:
case pos
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : p = 1
⊢ Irreducible p ↔ p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0

Next tactic:
simp [hp1]
theorem Monic.irreducible_iff_natDegree (hp : p.Monic) :
    Irreducible p ↔
      p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by
  by_cases hp1 : p = 1; · simp [hp1]
  

Proof state:
case neg
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : ¬p = 1
⊢ Irreducible p ↔ p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0

Next tactic:
rw [irreducible_of_monic hp hp1, and_iff_right hp1]
theorem Monic.irreducible_iff_natDegree (hp : p.Monic) :
    Irreducible p ↔
      p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by
  by_cases hp1 : p = 1; · simp [hp1]
  rw [irreducible_of_monic hp hp1, and_iff_right hp1]
  

Proof state:
case neg
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : ¬p = 1
⊢ (∀ (f g : R[X]), Monic f → Monic g → f * g = p → f = 1 ∨ g = 1) ↔
    ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0

Next tactic:
refine' forall₄_congr fun a b ha hb => _
theorem Monic.irreducible_iff_natDegree (hp : p.Monic) :
    Irreducible p ↔
      p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by
  by_cases hp1 : p = 1; · simp [hp1]
  rw [irreducible_of_monic hp hp1, and_iff_right hp1]
  refine' forall₄_congr fun a b ha hb => _
  

Proof state:
case neg
R : Type u
S : Type v
T : Type w
a✝ b✝ : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
hp1 : ¬p = 1
a b : R[X]
ha : Monic a
hb : Monic b
⊢ a * b = p → a = 1 ∨ b = 1 ↔ a * b = p → natDegree a = 0 ∨ natDegree b = 0

Next tactic:
rw [ha.natDegree_eq_zero_iff_eq_one, hb.natDegree_eq_zero_iff_eq_one]
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ Irreducible p ↔ p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree g ∉ Ioc 0 (natDegree p / 2)

Next tactic:
simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  

Proof state:
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ (p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0) ↔
    p ≠ 1 ∧ ∀ (f g : R[X]), Monic f → Monic g → f * g = p → ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)

Next tactic:
apply and_congr_right'
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  apply and_congr_right'
  

Proof state:
case h
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ (∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0) ↔
    ∀ (f g : R[X]), Monic f → Monic g → f * g = p → ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)

Next tactic:
constructor
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  apply and_congr_right'
  constructor <;> 

Proof state:
case h.mp
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ (∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0) →
    ∀ (f g : R[X]), Monic f → Monic g → f * g = p → ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)

Next tactic:
intro h f g hf hg he
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  apply and_congr_right'
  constructor <;> 

Proof state:
case h.mpr
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
⊢ (∀ (f g : R[X]), Monic f → Monic g → f * g = p → ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)) →
    ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0

Next tactic:
intro h f g hf hg he
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  apply and_congr_right'
  constructor <;> intro h f g hf hg he <;> 

Proof state:
case h.mp
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
h : ∀ (f g : R[X]), Monic f → Monic g → f * g = p → natDegree f = 0 ∨ natDegree g = 0
f g : R[X]
hf : Monic f
hg : Monic g
he : f * g = p
⊢ ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)

Next tactic:
subst he
theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧
    ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by
  simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two]
  apply and_congr_right'
  constructor <;> intro h f g hf hg he <;> 

Proof state:
case h.mpr
R : Type u
S : Type v
T : Type w
a b : R
n : ℕ
inst✝¹ : CommSemiring R
inst✝ : NoZeroDivisors R
p q : R[X]
hp : Monic p
h : ∀ (f g : R[X]), Monic f → Monic g → f * g = p → ¬(0 < natDegree g ∧ natDegree g + natDegree g ≤ natDegree p)
f g : R[X]
hf : Monic f
hg : Monic g
he : f * g = p
⊢ natDegree f = 0 ∨ natDegree g = 0

Next tactic:
subst he