Module docstring
{"# Univariate polynomials form a domain
Main results
Polynomial.instNoZeroDivisors:R[X]has no zero divisors ifRdoes notPolynomial.instDomain:R[X]is a domain ifRis "}
{"# Univariate polynomials form a domain
Polynomial.instNoZeroDivisors: R[X] has no zero divisors if R does notPolynomial.instDomain: R[X] is a domain if R is
"}Polynomial.instNoZeroDivisors
      instance
     : NoZeroDivisors R[X]
        instance : NoZeroDivisors R[X] where
  eq_zero_or_eq_zero_of_mul_eq_zero h := by
    rw [← leadingCoeff_eq_zero, ← leadingCoeff_eq_zero]
    refine eq_zero_or_eq_zero_of_mul_eq_zero ?_
    rw [← leadingCoeff_zero, ← leadingCoeff_mul, h]
        Polynomial.natDegree_mul
      theorem
     (hp : p ≠ 0) (hq : q ≠ 0) : (p * q).natDegree = p.natDegree + q.natDegree
        lemma natDegree_mul (hp : p ≠ 0) (hq : q ≠ 0) : (p*q).natDegree = p.natDegree + q.natDegree := by
  rw [← Nat.cast_inj (R := WithBot ℕ), ← degree_eq_natDegree (mul_ne_zero hp hq),
    Nat.cast_add, ← degree_eq_natDegree hp, ← degree_eq_natDegree hq, degree_mul]
        Polynomial.natDegree_smul
      theorem
     (ha : a ≠ 0) : (a • p).natDegree = p.natDegree
        lemma natDegree_smul (ha : a ≠ 0) : (a • p).natDegree = p.natDegree := by
  by_cases hp : p = 0
  · simp only [hp, smul_zero]
  · apply natDegree_eq_of_le_of_coeff_ne_zero
    · exact (natDegree_smul_le _ _).trans (le_refl _)
    · simpa only [coeff_smul, coeff_natDegree, smul_eq_mul, ne_eq, mul_eq_zero,
        leadingCoeff_eq_zero, not_or] using ⟨ha, hp⟩
        Polynomial.natDegree_pow
      theorem
     (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p
        @[simp]
lemma natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by
  classical
  obtain rfl | hp := eq_or_ne p 0
  · obtain rfl | hn := eq_or_ne n 0 <;> simp [*]
  exact natDegree_pow' <| by
    rw [← leadingCoeff_pow, Ne, leadingCoeff_eq_zero]; exact pow_ne_zero _ hp
        Polynomial.natDegree_le_of_dvd
      theorem
     (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree
        lemma natDegree_le_of_dvd (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by
  obtain ⟨q, rfl⟩ := h1
  rw [mul_ne_zero_iff] at h2
  rw [natDegree_mul h2.1 h2.2]; exact Nat.le_add_right _ _
        Polynomial.degree_le_of_dvd
      theorem
     (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q
        lemma degree_le_of_dvd (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by
  rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2
  exact degree_le_mul_left p h2.2
        Polynomial.not_dvd_of_degree_lt
      theorem
     (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q
        lemma not_dvd_of_degree_lt (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q := by
  by_contra hcontra
  exact h0 (eq_zero_of_dvd_of_degree_lt hcontra hl)
        Polynomial.not_dvd_of_natDegree_lt
      theorem
     (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) : ¬p ∣ q
        lemma not_dvd_of_natDegree_lt (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) :
    ¬p ∣ q := by
  by_contra hcontra
  exact h0 (eq_zero_of_dvd_of_natDegree_lt hcontra hl)
        Polynomial.natDegree_sub_eq_of_prod_eq
      theorem
     {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
        /-- This lemma is useful for working with the `intDegree` of a rational function. -/
lemma 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
  rw [← natDegree_mul hp₁ hq₂, ← natDegree_mul hp₂ hq₁, h_eq]
        Polynomial.instIsDomain
      instance
     : IsDomain R[X]
        instance : IsDomain R[X] := NoZeroDivisors.to_isDomain _