l3lab/ntp-mathlib huggingface dataset:
theorem map_mod [Field k] (f : R →+* k) : (p % q).map f = p.map f % q.map f := by
  by_cases hq0 : q = 0
  · simp [hq0]
  · 

Proof state:
case neg
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : Field k
f : R →+* k
hq0 : ¬q = 0
⊢ map f (p % q) = map f p % map f q

Next tactic:
rw [mod_def, mod_def, leadingCoeff_map f, ← map_inv₀ f, ← map_C f, ← Polynomial.map_mul f,
      map_modByMonic f (monic_mul_leadingCoeff_inv hq0)]
theorem gcd_map [Field k] [DecidableEq R] [DecidableEq k] (f : R →+* k) :
    gcd (p.map f) (q.map f) = (gcd p q).map f :=
  GCD.induction p q (fun x => by 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : Field k
inst✝¹ : DecidableEq R
inst✝ : DecidableEq k
f : R →+* k
x : R[X]
⊢ EuclideanDomain.gcd (map f 0) (map f x) = map f (EuclideanDomain.gcd 0 x)

Next tactic:
simp_rw [Polynomial.map_zero, EuclideanDomain.gcd_zero_left]
theorem gcd_map [Field k] [DecidableEq R] [DecidableEq k] (f : R →+* k) :
    gcd (p.map f) (q.map f) = (gcd p q).map f :=
  GCD.induction p q (fun x => by simp_rw [Polynomial.map_zero, EuclideanDomain.gcd_zero_left])
    fun x y _ ih => by 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : Field k
inst✝¹ : DecidableEq R
inst✝ : DecidableEq k
f : R →+* k
x y : R[X]
x✝ : x ≠ 0
ih : EuclideanDomain.gcd (map f (y % x)) (map f x) = map f (EuclideanDomain.gcd (y % x) x)
⊢ EuclideanDomain.gcd (map f x) (map f y) = map f (EuclideanDomain.gcd x y)

Next tactic:
rw [gcd_val, ← map_mod, ih, ← gcd_val]
theorem eval₂_gcd_eq_zero [CommSemiring k] [DecidableEq R]
    {ϕ : R →+* k} {f g : R[X]} {α : k} (hf : f.eval₂ ϕ α = 0)
    (hg : g.eval₂ ϕ α = 0) : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0 := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p q : R[X]
inst✝¹ : CommSemiring k
inst✝ : DecidableEq R
ϕ : R →+* k
f g : R[X]
α : k
hf : eval₂ ϕ α f = 0
hg : eval₂ ϕ α g = 0
⊢ eval₂ ϕ α (EuclideanDomain.gcd f g) = 0

Next tactic:
rw [EuclideanDomain.gcd_eq_gcd_ab f g, Polynomial.eval₂_add, Polynomial.eval₂_mul,
    Polynomial.eval₂_mul, hf, hg, zero_mul, zero_mul, zero_add]
theorem root_left_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
    (hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : f.eval₂ ϕ α = 0 := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p q : R[X]
inst✝¹ : CommSemiring k
inst✝ : DecidableEq R
ϕ : R →+* k
f g : R[X]
α : k
hα : eval₂ ϕ α (EuclideanDomain.gcd f g) = 0
⊢ eval₂ ϕ α f = 0

Next tactic:
cases' EuclideanDomain.gcd_dvd_left f g with p hp
theorem root_left_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
    (hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : f.eval₂ ϕ α = 0 := by
  cases' EuclideanDomain.gcd_dvd_left f g with p hp
  

Proof state:
case intro
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p✝ q : R[X]
inst✝¹ : CommSemiring k
inst✝ : DecidableEq R
ϕ : R →+* k
f g : R[X]
α : k
hα : eval₂ ϕ α (EuclideanDomain.gcd f g) = 0
p : R[X]
hp : f = EuclideanDomain.gcd f g * p
⊢ eval₂ ϕ α f = 0

Next tactic:
rw [hp, Polynomial.eval₂_mul, hα, zero_mul]
theorem root_right_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
    (hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : g.eval₂ ϕ α = 0 := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p q : R[X]
inst✝¹ : CommSemiring k
inst✝ : DecidableEq R
ϕ : R →+* k
f g : R[X]
α : k
hα : eval₂ ϕ α (EuclideanDomain.gcd f g) = 0
⊢ eval₂ ϕ α g = 0

Next tactic:
cases' EuclideanDomain.gcd_dvd_right f g with p hp
theorem root_right_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
    (hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : g.eval₂ ϕ α = 0 := by
  cases' EuclideanDomain.gcd_dvd_right f g with p hp
  

Proof state:
case intro
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p✝ q : R[X]
inst✝¹ : CommSemiring k
inst✝ : DecidableEq R
ϕ : R →+* k
f g : R[X]
α : k
hα : eval₂ ϕ α (EuclideanDomain.gcd f g) = 0
p : R[X]
hp : g = EuclideanDomain.gcd f g * p
⊢ eval₂ ϕ α g = 0

Next tactic:
rw [hp, Polynomial.eval₂_mul, hα, zero_mul]
theorem isCoprime_map [Field k] (f : R →+* k) : IsCoprime (p.map f) (q.map f) ↔ IsCoprime p q := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : Field k
f : R →+* k
⊢ IsCoprime (map f p) (map f q) ↔ IsCoprime p q

Next tactic:
classical
  rw [← EuclideanDomain.gcd_isUnit_iff, ← EuclideanDomain.gcd_isUnit_iff, gcd_map, isUnit_map]
theorem isCoprime_map [Field k] (f : R →+* k) : IsCoprime (p.map f) (q.map f) ↔ IsCoprime p q := by
  classical
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : Field k
f : R →+* k
⊢ IsCoprime (map f p) (map f q) ↔ IsCoprime p q

Next tactic:
rw [← EuclideanDomain.gcd_isUnit_iff, ← EuclideanDomain.gcd_isUnit_iff, gcd_map, isUnit_map]
theorem mem_roots_map [CommRing k] [IsDomain k] {f : R →+* k} {x : k} (hp : p ≠ 0) :
    x ∈ (p.map f).roots ↔ p.eval₂ f x = 0 := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝² : Field R
p q : R[X]
inst✝¹ : CommRing k
inst✝ : IsDomain k
f : R →+* k
x : k
hp : p ≠ 0
⊢ x ∈ roots (map f p) ↔ eval₂ f x p = 0

Next tactic:
rw [mem_roots (map_ne_zero hp), IsRoot, Polynomial.eval_map]
theorem rootSet_monomial [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) {a : R}
    (ha : a ≠ 0) : (monomial n a).rootSet S = {0} := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a✝ b : R
n✝ : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
n : ℕ
hn : n ≠ 0
a : R
ha : a ≠ 0
⊢ rootSet ((monomial n) a) S = {0}

Next tactic:
classical
  rw [rootSet, aroots_monomial ha,
    Multiset.toFinset_nsmul _ _ hn, Multiset.toFinset_singleton, Finset.coe_singleton]
theorem rootSet_monomial [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) {a : R}
    (ha : a ≠ 0) : (monomial n a).rootSet S = {0} := by
  classical
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a✝ b : R
n✝ : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
n : ℕ
hn : n ≠ 0
a : R
ha : a ≠ 0
⊢ rootSet ((monomial n) a) S = {0}

Next tactic:
rw [rootSet, aroots_monomial ha,
    Multiset.toFinset_nsmul _ _ hn, Multiset.toFinset_singleton, Finset.coe_singleton]
theorem rootSet_C_mul_X_pow [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) {a : R}
    (ha : a ≠ 0) : rootSet (C a * X ^ n) S = {0} := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a✝ b : R
n✝ : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
n : ℕ
hn : n ≠ 0
a : R
ha : a ≠ 0
⊢ rootSet (C a * X ^ n) S = {0}

Next tactic:
rw [C_mul_X_pow_eq_monomial, rootSet_monomial hn ha]
theorem rootSet_X_pow [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) :
    (X ^ n : R[X]).rootSet S = {0} := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
n : ℕ
hn : n ≠ 0
⊢ rootSet (X ^ n) S = {0}

Next tactic:
rw [← one_mul (X ^ n : R[X]), ← C_1, rootSet_C_mul_X_pow hn]
theorem rootSet_X_pow [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) :
    (X ^ n : R[X]).rootSet S = {0} := by
  rw [← one_mul (X ^ n : R[X]), ← C_1, rootSet_C_mul_X_pow hn]
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
n : ℕ
hn : n ≠ 0
⊢ 1 ≠ 0

Next tactic:
exact one_ne_zero
theorem rootSet_prod [CommRing S] [IsDomain S] [Algebra R S] {ι : Type*} (f : ι → R[X])
    (s : Finset ι) (h : s.prod f ≠ 0) : (s.prod f).rootSet S = ⋃ i ∈ s, (f i).rootSet S := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
ι : Type u_1
f : ι → R[X]
s : Finset ι
h : Finset.prod s f ≠ 0
⊢ rootSet (Finset.prod s f) S = ⋃ i ∈ s, rootSet (f i) S

Next tactic:
classical
  simp only [rootSet, aroots, ← Finset.mem_coe]
  rw [Polynomial.map_prod, roots_prod, Finset.bind_toFinset, s.val_toFinset, Finset.coe_biUnion]
  rwa [← Polynomial.map_prod, Ne, map_eq_zero]
theorem rootSet_prod [CommRing S] [IsDomain S] [Algebra R S] {ι : Type*} (f : ι → R[X])
    (s : Finset ι) (h : s.prod f ≠ 0) : (s.prod f).rootSet S = ⋃ i ∈ s, (f i).rootSet S := by
  classical
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
ι : Type u_1
f : ι → R[X]
s : Finset ι
h : Finset.prod s f ≠ 0
⊢ rootSet (Finset.prod s f) S = ⋃ i ∈ s, rootSet (f i) S

Next tactic:
simp only [rootSet, aroots, ← Finset.mem_coe]
theorem rootSet_prod [CommRing S] [IsDomain S] [Algebra R S] {ι : Type*} (f : ι → R[X])
    (s : Finset ι) (h : s.prod f ≠ 0) : (s.prod f).rootSet S = ⋃ i ∈ s, (f i).rootSet S := by
  classical
  simp only [rootSet, aroots, ← Finset.mem_coe]
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
ι : Type u_1
f : ι → R[X]
s : Finset ι
h : Finset.prod s f ≠ 0
⊢ ↑(Multiset.toFinset (roots (map (algebraMap R S) (Finset.prod s f)))) =
    ⋃ i ∈ ↑s, ↑(Multiset.toFinset (roots (map (algebraMap R S) (f i))))

Next tactic:
rw [Polynomial.map_prod, roots_prod, Finset.bind_toFinset, s.val_toFinset, Finset.coe_biUnion]
theorem rootSet_prod [CommRing S] [IsDomain S] [Algebra R S] {ι : Type*} (f : ι → R[X])
    (s : Finset ι) (h : s.prod f ≠ 0) : (s.prod f).rootSet S = ⋃ i ∈ s, (f i).rootSet S := by
  classical
  simp only [rootSet, aroots, ← Finset.mem_coe]
  rw [Polynomial.map_prod, roots_prod, Finset.bind_toFinset, s.val_toFinset, Finset.coe_biUnion]
  

Proof state:
case a
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝³ : Field R
p q : R[X]
inst✝² : CommRing S
inst✝¹ : IsDomain S
inst✝ : Algebra R S
ι : Type u_1
f : ι → R[X]
s : Finset ι
h : Finset.prod s f ≠ 0
⊢ ∏ i in s, map (algebraMap R S) (f i) ≠ 0

Next tactic:
rwa [← Polynomial.map_prod, Ne, map_eq_zero]
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
⊢ IsRoot p (-(coeff p 0 / coeff p 1))

Next tactic:
have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
⊢ coeff p 1 ≠ 0

Next tactic:
have h' := natDegree_eq_of_degree_eq_some h
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
h' : natDegree p = One.one
⊢ coeff p 1 ≠ 0

Next tactic:
change natDegree p = 1 at h'
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
h' : natDegree p = 1
⊢ coeff p 1 ≠ 0

Next tactic:
rw [← h']
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
h' : natDegree p = 1
⊢ coeff p (natDegree p) ≠ 0

Next tactic:
exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
h' : natDegree p = 1
h0 : p = 0
⊢ False

Next tactic:
simp [h0] at h
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h' : natDegree p = 1
h0 : p = 0
h : ⊥ = 1
⊢ False

Next tactic:
contradiction
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
    

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
this : coeff p 1 ≠ 0
⊢ IsRoot p (-(coeff p 0 / coeff p 1))

Next tactic:
conv in p => rw [eq_X_add_C_of_degree_le_one (show degree p ≤ 1 by rw [h])]
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
    conv in p => 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
this : coeff p 1 ≠ 0
| p

Next tactic:
rw [eq_X_add_C_of_degree_le_one (show degree p ≤ 1 by rw [h])]
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
    conv in p => rw [eq_X_add_C_of_degree_le_one (show degree p ≤ 1 by 

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
this : coeff p 1 ≠ 0
⊢ degree p ≤ 1

Next tactic:
rw [h]
theorem exists_root_of_degree_eq_one (h : degree p = 1) : ∃ x, IsRoot p x :=
  ⟨-(p.coeff 0 / p.coeff 1), by
    have : p.coeff 1 ≠ 0 := by
      have h' := natDegree_eq_of_degree_eq_some h
      change natDegree p = 1 at h'; rw [← h']
      exact mt leadingCoeff_eq_zero.1 fun h0 => by simp [h0] at h; contradiction
    conv in p => rw [eq_X_add_C_of_degree_le_one (show degree p ≤ 1 by rw [h])]
    

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
h : degree p = 1
this : coeff p 1 ≠ 0
⊢ IsRoot (C (coeff p 1) * X + C (coeff p 0)) (-(coeff p 0 / coeff p 1))

Next tactic:
simp [IsRoot, mul_div_cancel' _ this]
theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ = (↑u⁻¹ : R[X]).coeff n := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝ : Field R
p q : R[X]
u : R[X]ˣ
n : ℕ
⊢ (coeff (↑u) n)⁻¹ = coeff (↑u⁻¹) n

Next tactic:
rw [eq_C_of_degree_eq_zero (degree_coe_units u), eq_C_of_degree_eq_zero (degree_coe_units u⁻¹),
    coeff_C, coeff_C, inv_eq_one_div]
theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ = (↑u⁻¹ : R[X]).coeff n := by
  rw [eq_C_of_degree_eq_zero (degree_coe_units u), eq_C_of_degree_eq_zero (degree_coe_units u⁻¹),
    coeff_C, coeff_C, inv_eq_one_div]
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝ : Field R
p q : R[X]
u : R[X]ˣ
n : ℕ
⊢ (1 / if n = 0 then coeff (↑u) 0 else 0) = if n = 0 then coeff (↑u⁻¹) 0 else 0

Next tactic:
split_ifs
theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ = (↑u⁻¹ : R[X]).coeff n := by
  rw [eq_C_of_degree_eq_zero (degree_coe_units u), eq_C_of_degree_eq_zero (degree_coe_units u⁻¹),
    coeff_C, coeff_C, inv_eq_one_div]
  split_ifs
  · 

Proof state:
case pos
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝ : Field R
p q : R[X]
u : R[X]ˣ
n : ℕ
h✝ : n = 0
⊢ 1 / coeff (↑u) 0 = coeff (↑u⁻¹) 0

Next tactic:
rw [div_eq_iff_mul_eq (coeff_coe_units_zero_ne_zero u), coeff_zero_eq_eval_zero,
        coeff_zero_eq_eval_zero, ← eval_mul, ← Units.val_mul, inv_mul_self]
theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ = (↑u⁻¹ : R[X]).coeff n := by
  rw [eq_C_of_degree_eq_zero (degree_coe_units u), eq_C_of_degree_eq_zero (degree_coe_units u⁻¹),
    coeff_C, coeff_C, inv_eq_one_div]
  split_ifs
  · rw [div_eq_iff_mul_eq (coeff_coe_units_zero_ne_zero u), coeff_zero_eq_eval_zero,
        coeff_zero_eq_eval_zero, ← eval_mul, ← Units.val_mul, inv_mul_self]
    

Proof state:
case pos
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝ : Field R
p q : R[X]
u : R[X]ˣ
n : ℕ
h✝ : n = 0
⊢ eval 0 ↑1 = 1

Next tactic:
simp
theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ = (↑u⁻¹ : R[X]).coeff n := by
  rw [eq_C_of_degree_eq_zero (degree_coe_units u), eq_C_of_degree_eq_zero (degree_coe_units u⁻¹),
    coeff_C, coeff_C, inv_eq_one_div]
  split_ifs
  · rw [div_eq_iff_mul_eq (coeff_coe_units_zero_ne_zero u), coeff_zero_eq_eval_zero,
        coeff_zero_eq_eval_zero, ← eval_mul, ← Units.val_mul, inv_mul_self]
    simp
  · 

Proof state:
case neg
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n✝ : ℕ
inst✝ : Field R
p q : R[X]
u : R[X]ˣ
n : ℕ
h✝ : ¬n = 0
⊢ 1 / 0 = 0

Next tactic:
simp
theorem monic_normalize [DecidableEq R] (hp0 : p ≠ 0) : Monic (normalize p) := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : DecidableEq R
hp0 : p ≠ 0
⊢ Monic (normalize p)

Next tactic:
rw [Ne.def, ← leadingCoeff_eq_zero, ← Ne.def, ← isUnit_iff_ne_zero] at hp0
theorem monic_normalize [DecidableEq R] (hp0 : p ≠ 0) : Monic (normalize p) := by
  rw [Ne.def, ← leadingCoeff_eq_zero, ← Ne.def, ← isUnit_iff_ne_zero] at hp0
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : DecidableEq R
hp0 : IsUnit (leadingCoeff p)
⊢ Monic (normalize p)

Next tactic:
rw [Monic, leadingCoeff_normalize, normalize_eq_one]
theorem monic_normalize [DecidableEq R] (hp0 : p ≠ 0) : Monic (normalize p) := by
  rw [Ne.def, ← leadingCoeff_eq_zero, ← Ne.def, ← isUnit_iff_ne_zero] at hp0
  rw [Monic, leadingCoeff_normalize, normalize_eq_one]
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝¹ : Field R
p q : R[X]
inst✝ : DecidableEq R
hp0 : IsUnit (leadingCoeff p)
⊢ IsUnit (leadingCoeff p)

Next tactic:
apply hp0
theorem leadingCoeff_div (hpq : q.degree ≤ p.degree) :
    (p / q).leadingCoeff = p.leadingCoeff / q.leadingCoeff := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
hpq : degree q ≤ degree p
⊢ leadingCoeff (p / q) = leadingCoeff p / leadingCoeff q

Next tactic:
by_cases hq : q = 0
theorem leadingCoeff_div (hpq : q.degree ≤ p.degree) :
    (p / q).leadingCoeff = p.leadingCoeff / q.leadingCoeff := by
  by_cases hq : q = 0
  · 

Proof state:
case pos
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
hpq : degree q ≤ degree p
hq : q = 0
⊢ leadingCoeff (p / q) = leadingCoeff p / leadingCoeff q

Next tactic:
simp [hq]
theorem leadingCoeff_div (hpq : q.degree ≤ p.degree) :
    (p / q).leadingCoeff = p.leadingCoeff / q.leadingCoeff := by
  by_cases hq : q = 0
  · simp [hq]
  

Proof state:
case neg
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
hpq : degree q ≤ degree p
hq : ¬q = 0
⊢ leadingCoeff (p / q) = leadingCoeff p / leadingCoeff q

Next tactic:
rw [div_def, leadingCoeff_mul, leadingCoeff_C,
    leadingCoeff_divByMonic_of_monic (monic_mul_leadingCoeff_inv hq) _, mul_comm,
    div_eq_mul_inv]
theorem leadingCoeff_div (hpq : q.degree ≤ p.degree) :
    (p / q).leadingCoeff = p.leadingCoeff / q.leadingCoeff := by
  by_cases hq : q = 0
  · simp [hq]
  rw [div_def, leadingCoeff_mul, leadingCoeff_C,
    leadingCoeff_divByMonic_of_monic (monic_mul_leadingCoeff_inv hq) _, mul_comm,
    div_eq_mul_inv]
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
hpq : degree q ≤ degree p
hq : ¬q = 0
⊢ degree (q * C (leadingCoeff q)⁻¹) ≤ degree p

Next tactic:
rwa [degree_mul_leadingCoeff_inv q hq]
theorem div_C_mul : p / (C a * q) = C a⁻¹ * (p / q) := by
  

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
⊢ p / (C a * q) = C a⁻¹ * (p / q)

Next tactic:
by_cases ha : a = 0
theorem div_C_mul : p / (C a * q) = C a⁻¹ * (p / q) := by
  by_cases ha : a = 0
  · 

Proof state:
case pos
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : a = 0
⊢ p / (C a * q) = C a⁻¹ * (p / q)

Next tactic:
simp [ha]
theorem div_C_mul : p / (C a * q) = C a⁻¹ * (p / q) := by
  by_cases ha : a = 0
  · simp [ha]
  

Proof state:
case neg
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : ¬a = 0
⊢ p / (C a * q) = C a⁻¹ * (p / q)

Next tactic:
simp only [div_def, leadingCoeff_mul, mul_inv, leadingCoeff_C, C.map_mul, mul_assoc]
theorem div_C_mul : p / (C a * q) = C a⁻¹ * (p / q) := by
  by_cases ha : a = 0
  · simp [ha]
  simp only [div_def, leadingCoeff_mul, mul_inv, leadingCoeff_C, C.map_mul, mul_assoc]
  

Proof state:
case neg
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : ¬a = 0
⊢ C a⁻¹ * (C (leadingCoeff q)⁻¹ * (p /ₘ (C a * (q * (C a⁻¹ * C (leadingCoeff q)⁻¹))))) =
    C a⁻¹ * (C (leadingCoeff q)⁻¹ * (p /ₘ (q * C (leadingCoeff q)⁻¹)))

Next tactic:
congr 3
theorem div_C_mul : p / (C a * q) = C a⁻¹ * (p / q) := by
  by_cases ha : a = 0
  · simp [ha]
  simp only [div_def, leadingCoeff_mul, mul_inv, leadingCoeff_C, C.map_mul, mul_assoc]
  congr 3
  

Proof state:
case neg.e_a.e_a.e_q
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : ¬a = 0
⊢ C a * (q * (C a⁻¹ * C (leadingCoeff q)⁻¹)) = q * C (leadingCoeff q)⁻¹

Next tactic:
rw [mul_left_comm q, ← mul_assoc, ← C.map_mul, mul_inv_cancel ha, C.map_one, one_mul]
theorem C_mul_dvd (ha : a ≠ 0) : C a * p ∣ q ↔ p ∣ q :=
  ⟨fun h => dvd_trans (dvd_mul_left _ _) h, fun ⟨r, hr⟩ =>
    ⟨C a⁻¹ * r, by
      

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : a ≠ 0
x✝ : p ∣ q
r : R[X]
hr : q = p * r
⊢ q = C a * p * (C a⁻¹ * r)

Next tactic:
rw [mul_assoc, mul_left_comm p, ← mul_assoc, ← C.map_mul, _root_.mul_inv_cancel ha, C.map_one,
        one_mul, hr]
theorem dvd_C_mul (ha : a ≠ 0) : p ∣ Polynomial.C a * q ↔ p ∣ q :=
  ⟨fun ⟨r, hr⟩ =>
    ⟨C a⁻¹ * r, by
      

Proof state:
R : Type u
S : Type v
k : Type y
A : Type z
a b : R
n : ℕ
inst✝ : Field R
p q : R[X]
ha : a ≠ 0
x✝ : p ∣ C a * q
r : R[X]
hr : C a * q = p * r
⊢ q = p * (C a⁻¹ * r)

Next tactic:
rw [mul_left_comm p, ← hr, ← mul_assoc, ← C.map_mul, _root_.inv_mul_cancel ha, C.map_one,
        one_mul]