l3lab/ntp-mathlib huggingface dataset:
theorem mapAccumr₂_comm (f : α → α → σ → σ × γ) (comm : ∀ a₁ a₂ s, f a₁ a₂ s = f a₂ a₁ s) :
    mapAccumr₂ f xs ys s = mapAccumr₂ f ys xs s := by
  induction xs, ys using Vector.inductionOn₂ generalizing s <;> 

Proof state:
case cons
α : Type
n : ℕ
xs ys : Vector α n
σ γ : Type
f : α → α → σ → σ × γ
comm : ∀ (a₁ a₂ : α) (s : σ), f a₁ a₂ s = f a₂ a₁ s
n✝ : ℕ
a✝¹ b✝ : α
x✝ y✝ : Vector α n✝
a✝ : ∀ {s : σ}, mapAccumr₂ f x✝ y✝ s = mapAccumr₂ f y✝ x✝ s
s : σ
⊢ mapAccumr₂ f (a✝¹ ::ᵥ x✝) (b✝ ::ᵥ y✝) s = mapAccumr₂ f (b✝ ::ᵥ y✝) (a✝¹ ::ᵥ x✝) s

Next tactic:
simp_all
theorem map₂_flip (f : α → β → γ) :
    map₂ f xs ys = map₂ (flip f) ys xs := by
  

Proof state:
α : Type u_2
n : ℕ
β : Type u_3
xs : Vector α n
ys : Vector β n
γ : Type u_1
f : α → β → γ
⊢ map₂ f xs ys = map₂ (flip f) ys xs

Next tactic:
induction xs, ys using Vector.inductionOn₂
theorem map₂_flip (f : α → β → γ) :
    map₂ f xs ys = map₂ (flip f) ys xs := by
  induction xs, ys using Vector.inductionOn₂ <;> 

Proof state:
case nil
α : Type u_2
n : ℕ
β : Type u_3
xs : Vector α n
ys : Vector β n
γ : Type u_1
f : α → β → γ
⊢ map₂ f nil nil = map₂ (flip f) nil nil

Next tactic:
simp_all[flip]
theorem map₂_flip (f : α → β → γ) :
    map₂ f xs ys = map₂ (flip f) ys xs := by
  induction xs, ys using Vector.inductionOn₂ <;> 

Proof state:
case cons
α : Type u_2
n : ℕ
β : Type u_3
xs : Vector α n
ys : Vector β n
γ : Type u_1
f : α → β → γ
n✝ : ℕ
a✝¹ : α
b✝ : β
x✝ : Vector α n✝
y✝ : Vector β n✝
a✝ : map₂ f x✝ y✝ = map₂ (flip f) y✝ x✝
⊢ map₂ f (a✝¹ ::ᵥ x✝) (b✝ ::ᵥ y✝) = map₂ (flip f) (b✝ ::ᵥ y✝) (a✝¹ ::ᵥ x✝)

Next tactic:
simp_all[flip]
theorem mapAccumr₂_flip (f : α → β → σ → σ × γ) :
    mapAccumr₂ f xs ys s = mapAccumr₂ (flip f) ys xs s := by
  

Proof state:
α : Type
n : ℕ
β : Type
xs : Vector α n
ys : Vector β n
σ γ : Type
s : σ
f : α → β → σ → σ × γ
⊢ mapAccumr₂ f xs ys s = mapAccumr₂ (flip f) ys xs s

Next tactic:
induction xs, ys using Vector.inductionOn₂
theorem mapAccumr₂_flip (f : α → β → σ → σ × γ) :
    mapAccumr₂ f xs ys s = mapAccumr₂ (flip f) ys xs s := by
  induction xs, ys using Vector.inductionOn₂ <;> 

Proof state:
case nil
α : Type
n : ℕ
β : Type
xs : Vector α n
ys : Vector β n
σ γ : Type
s : σ
f : α → β → σ → σ × γ
⊢ mapAccumr₂ f nil nil s = mapAccumr₂ (flip f) nil nil s

Next tactic:
simp_all[flip]
theorem mapAccumr₂_flip (f : α → β → σ → σ × γ) :
    mapAccumr₂ f xs ys s = mapAccumr₂ (flip f) ys xs s := by
  induction xs, ys using Vector.inductionOn₂ <;> 

Proof state:
case cons
α : Type
n : ℕ
β : Type
xs : Vector α n
ys : Vector β n
σ γ : Type
s : σ
f : α → β → σ → σ × γ
n✝ : ℕ
a✝¹ : α
b✝ : β
x✝ : Vector α n✝
y✝ : Vector β n✝
a✝ : mapAccumr₂ f x✝ y✝ s = mapAccumr₂ (flip f) y✝ x✝ s
⊢ mapAccumr₂ f (a✝¹ ::ᵥ x✝) (b✝ ::ᵥ y✝) s = mapAccumr₂ (flip f) (b✝ ::ᵥ y✝) (a✝¹ ::ᵥ x✝) s

Next tactic:
simp_all[flip]
/-- If `C` has a terminal object and `G` preserves terminal objects, then `D` has a terminal object
also.
Note this property is somewhat unique to (co)limits of the empty diagram: for general `J`, if `C`
has limits of shape `J` and `G` preserves them, then `D` does not necessarily have limits of shape
`J`.
-/
theorem hasTerminal_of_hasTerminal_of_preservesLimit [PreservesLimit (Functor.empty.{0} C) G] :
    HasTerminal D := ⟨fun F => by
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : PreservesLimit (Functor.empty C) G
F : Discrete PEmpty.{1} ⥤ D
⊢ HasLimit F

Next tactic:
haveI := HasLimit.mk ⟨_, isLimitOfHasTerminalOfPreservesLimit G⟩
/-- If `C` has a terminal object and `G` preserves terminal objects, then `D` has a terminal object
also.
Note this property is somewhat unique to (co)limits of the empty diagram: for general `J`, if `C`
has limits of shape `J` and `G` preserves them, then `D` does not necessarily have limits of shape
`J`.
-/
theorem hasTerminal_of_hasTerminal_of_preservesLimit [PreservesLimit (Functor.empty.{0} C) G] :
    HasTerminal D := ⟨fun F => by
  haveI := HasLimit.mk ⟨_, isLimitOfHasTerminalOfPreservesLimit G⟩
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : PreservesLimit (Functor.empty C) G
F : Discrete PEmpty.{1} ⥤ D
this : HasLimit (Functor.empty D)
⊢ HasLimit F

Next tactic:
apply hasLimitOfIso F.uniqueFromEmpty.symm
/-- If the terminal comparison map for `G` is an isomorphism, then `G` preserves terminal objects.
-/
def PreservesTerminal.ofIsoComparison [i : IsIso (terminalComparison G)] :
    PreservesLimit (Functor.empty C) G := by
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : HasTerminal D
i : IsIso (terminalComparison G)
⊢ PreservesLimit (Functor.empty C) G

Next tactic:
apply preservesLimitOfPreservesLimitCone terminalIsTerminal
/-- If the terminal comparison map for `G` is an isomorphism, then `G` preserves terminal objects.
-/
def PreservesTerminal.ofIsoComparison [i : IsIso (terminalComparison G)] :
    PreservesLimit (Functor.empty C) G := by
  apply preservesLimitOfPreservesLimitCone terminalIsTerminal
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : HasTerminal D
i : IsIso (terminalComparison G)
⊢ IsLimit (G.mapCone (asEmptyCone (⊤_ C)))

Next tactic:
apply (isLimitMapConeEmptyConeEquiv _ _).symm _
/-- If the terminal comparison map for `G` is an isomorphism, then `G` preserves terminal objects.
-/
def PreservesTerminal.ofIsoComparison [i : IsIso (terminalComparison G)] :
    PreservesLimit (Functor.empty C) G := by
  apply preservesLimitOfPreservesLimitCone terminalIsTerminal
  apply (isLimitMapConeEmptyConeEquiv _ _).symm _
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : HasTerminal D
i : IsIso (terminalComparison G)
⊢ IsTerminal (G.obj (⊤_ C))

Next tactic:
exact @IsLimit.ofPointIso _ _ _ _ _ _ _ (limit.isLimit (Functor.empty.{0} D)) i
/-- If there is any isomorphism `G.obj ⊤ ⟶ ⊤`, then `G` preserves terminal objects. -/
def preservesTerminalOfIsIso (f : G.obj (⊤_ C) ⟶ ⊤_ D) [i : IsIso f] :
    PreservesLimit (Functor.empty C) G := by
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : HasTerminal D
f : G.obj (⊤_ C) ⟶ ⊤_ D
i : IsIso f
⊢ PreservesLimit (Functor.empty C) G

Next tactic:
rw [Subsingleton.elim f (terminalComparison G)] at i
/-- If there is any isomorphism `G.obj ⊤ ⟶ ⊤`, then `G` preserves terminal objects. -/
def preservesTerminalOfIsIso (f : G.obj (⊤_ C) ⟶ ⊤_ D) [i : IsIso f] :
    PreservesLimit (Functor.empty C) G := by
  rw [Subsingleton.elim f (terminalComparison G)] at i
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasTerminal C
inst✝ : HasTerminal D
f : G.obj (⊤_ C) ⟶ ⊤_ D
i : IsIso (terminalComparison G)
⊢ PreservesLimit (Functor.empty C) G

Next tactic:
exact PreservesTerminal.ofIsoComparison G
instance : IsIso (terminalComparison G) := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝² : HasTerminal C
inst✝¹ : HasTerminal D
inst✝ : PreservesLimit (Functor.empty C) G
⊢ IsIso (terminalComparison G)

Next tactic:
rw [← PreservesTerminal.iso_hom]
instance : IsIso (terminalComparison G) := by
  rw [← PreservesTerminal.iso_hom]
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝² : HasTerminal C
inst✝¹ : HasTerminal D
inst✝ : PreservesLimit (Functor.empty C) G
⊢ IsIso (PreservesTerminal.iso G).hom

Next tactic:
infer_instance
/-- If `C` has an initial object and `G` preserves initial objects, then `D` has an initial object
also.
Note this property is somewhat unique to colimits of the empty diagram: for general `J`, if `C`
has colimits of shape `J` and `G` preserves them, then `D` does not necessarily have colimits of
shape `J`.
-/
theorem hasInitial_of_hasInitial_of_preservesColimit [PreservesColimit (Functor.empty.{0} C) G] :
    HasInitial D :=
  ⟨fun F => by
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : PreservesColimit (Functor.empty C) G
F : Discrete PEmpty.{1} ⥤ D
⊢ HasColimit F

Next tactic:
haveI := HasColimit.mk ⟨_, isColimitOfHasInitialOfPreservesColimit G⟩
/-- If `C` has an initial object and `G` preserves initial objects, then `D` has an initial object
also.
Note this property is somewhat unique to colimits of the empty diagram: for general `J`, if `C`
has colimits of shape `J` and `G` preserves them, then `D` does not necessarily have colimits of
shape `J`.
-/
theorem hasInitial_of_hasInitial_of_preservesColimit [PreservesColimit (Functor.empty.{0} C) G] :
    HasInitial D :=
  ⟨fun F => by
    haveI := HasColimit.mk ⟨_, isColimitOfHasInitialOfPreservesColimit G⟩
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : PreservesColimit (Functor.empty C) G
F : Discrete PEmpty.{1} ⥤ D
this : HasColimit (Functor.empty D)
⊢ HasColimit F

Next tactic:
apply hasColimitOfIso F.uniqueFromEmpty
/-- If the initial comparison map for `G` is an isomorphism, then `G` preserves initial objects.
-/
def PreservesInitial.ofIsoComparison [i : IsIso (initialComparison G)] :
    PreservesColimit (Functor.empty C) G := by
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : HasInitial D
i : IsIso (initialComparison G)
⊢ PreservesColimit (Functor.empty C) G

Next tactic:
apply preservesColimitOfPreservesColimitCocone initialIsInitial
/-- If the initial comparison map for `G` is an isomorphism, then `G` preserves initial objects.
-/
def PreservesInitial.ofIsoComparison [i : IsIso (initialComparison G)] :
    PreservesColimit (Functor.empty C) G := by
  apply preservesColimitOfPreservesColimitCocone initialIsInitial
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : HasInitial D
i : IsIso (initialComparison G)
⊢ IsColimit (G.mapCocone (asEmptyCocone (⊥_ C)))

Next tactic:
apply (isColimitMapCoconeEmptyCoconeEquiv _ _).symm _
/-- If the initial comparison map for `G` is an isomorphism, then `G` preserves initial objects.
-/
def PreservesInitial.ofIsoComparison [i : IsIso (initialComparison G)] :
    PreservesColimit (Functor.empty C) G := by
  apply preservesColimitOfPreservesColimitCocone initialIsInitial
  apply (isColimitMapCoconeEmptyCoconeEquiv _ _).symm _
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : HasInitial D
i : IsIso (initialComparison G)
⊢ IsInitial (G.obj (⊥_ C))

Next tactic:
exact @IsColimit.ofPointIso _ _ _ _ _ _ _ (colimit.isColimit (Functor.empty.{0} D)) i
/-- If there is any isomorphism `⊥ ⟶ G.obj ⊥`, then `G` preserves initial objects. -/
def preservesInitialOfIsIso (f : ⊥_ D ⟶ G.obj (⊥_ C)) [i : IsIso f] :
    PreservesColimit (Functor.empty C) G := by
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : HasInitial D
f : ⊥_ D ⟶ G.obj (⊥_ C)
i : IsIso f
⊢ PreservesColimit (Functor.empty C) G

Next tactic:
rw [Subsingleton.elim f (initialComparison G)] at i
/-- If there is any isomorphism `⊥ ⟶ G.obj ⊥`, then `G` preserves initial objects. -/
def preservesInitialOfIsIso (f : ⊥_ D ⟶ G.obj (⊥_ C)) [i : IsIso f] :
    PreservesColimit (Functor.empty C) G := by
  rw [Subsingleton.elim f (initialComparison G)] at i
  

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝¹ : HasInitial C
inst✝ : HasInitial D
f : ⊥_ D ⟶ G.obj (⊥_ C)
i : IsIso (initialComparison G)
⊢ PreservesColimit (Functor.empty C) G

Next tactic:
exact PreservesInitial.ofIsoComparison G
instance : IsIso (initialComparison G) := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝² : HasInitial C
inst✝¹ : HasInitial D
inst✝ : PreservesColimit (Functor.empty C) G
⊢ IsIso (initialComparison G)

Next tactic:
rw [← PreservesInitial.iso_hom]
instance : IsIso (initialComparison G) := by
  rw [← PreservesInitial.iso_hom]
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X : C
inst✝² : HasInitial C
inst✝¹ : HasInitial D
inst✝ : PreservesColimit (Functor.empty C) G
⊢ IsIso (PreservesInitial.iso G).inv

Next tactic:
infer_instance
/-- Every polynomial splits in the field extension `f : K →+* k` if `k` is algebraically closed.

See also `IsAlgClosed.splits_domain` for the case where `K` is algebraically closed.
-/
theorem IsAlgClosed.splits_codomain {k K : Type*} [Field k] [IsAlgClosed k] [Field K] {f : K →+* k}
    (p : K[X]) : p.Splits f := by 

Proof state:
k✝ : Type u
inst✝³ : Field k✝
k : Type u_1
K : Type u_2
inst✝² : Field k
inst✝¹ : IsAlgClosed k
inst✝ : Field K
f : K →+* k
p : K[X]
⊢ Splits f p

Next tactic:
convert IsAlgClosed.splits (p.map f)
/-- Every polynomial splits in the field extension `f : K →+* k` if `k` is algebraically closed.

See also `IsAlgClosed.splits_domain` for the case where `K` is algebraically closed.
-/
theorem IsAlgClosed.splits_codomain {k K : Type*} [Field k] [IsAlgClosed k] [Field K] {f : K →+* k}
    (p : K[X]) : p.Splits f := by convert IsAlgClosed.splits (p.map f); 

Proof state:
case a
k✝ : Type u
inst✝³ : Field k✝
k : Type u_1
K : Type u_2
inst✝² : Field k
inst✝¹ : IsAlgClosed k
inst✝ : Field K
f : K →+* k
p : K[X]
⊢ Splits f p ↔ Splits (RingHom.id k) (map f p)

Next tactic:
simp [splits_map_iff]
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
⊢ ∃ z, z ^ n = x

Next tactic:
have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
⊢ degree (X ^ n - C x) ≠ 0

Next tactic:
rw [degree_X_pow_sub_C hn x]
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
⊢ ↑n ≠ 0

Next tactic:
exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
  

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
this : degree (X ^ n - C x) ≠ 0
⊢ ∃ z, z ^ n = x

Next tactic:
obtain ⟨z, hz⟩ := exists_root (X ^ n - C x) this
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
  obtain ⟨z, hz⟩ := exists_root (X ^ n - C x) this
  · 

Proof state:
case intro
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
this : degree (X ^ n - C x) ≠ 0
z : k
hz : IsRoot (X ^ n - C x) z
⊢ ∃ z, z ^ n = x

Next tactic:
use z
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
  obtain ⟨z, hz⟩ := exists_root (X ^ n - C x) this
  · use z
    

Proof state:
case h
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
this : degree (X ^ n - C x) ≠ 0
z : k
hz : IsRoot (X ^ n - C x) z
⊢ z ^ n = x

Next tactic:
simp only [eval_C, eval_X, eval_pow, eval_sub, IsRoot.def] at hz
theorem exists_pow_nat_eq [IsAlgClosed k] (x : k) {n : ℕ} (hn : 0 < n) : ∃ z, z ^ n = x := by
  have : degree (X ^ n - C x) ≠ 0 := by
    rw [degree_X_pow_sub_C hn x]
    exact ne_of_gt (WithBot.coe_lt_coe.2 hn)
  obtain ⟨z, hz⟩ := exists_root (X ^ n - C x) this
  · use z
    simp only [eval_C, eval_X, eval_pow, eval_sub, IsRoot.def] at hz
    

Proof state:
case h
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
n : ℕ
hn : 0 < n
this : degree (X ^ n - C x) ≠ 0
z : k
hz : z ^ n - x = 0
⊢ z ^ n = x

Next tactic:
exact sub_eq_zero.1 hz
theorem exists_eq_mul_self [IsAlgClosed k] (x : k) : ∃ z, x = z * z := by
  

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
x : k
⊢ ∃ z, x = z * z

Next tactic:
rcases exists_pow_nat_eq x zero_lt_two with ⟨z, rfl⟩
theorem exists_eq_mul_self [IsAlgClosed k] (x : k) : ∃ z, x = z * z := by
  rcases exists_pow_nat_eq x zero_lt_two with ⟨z, rfl⟩
  

Proof state:
case intro
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
z : k
⊢ ∃ z_1, z ^ 2 = z_1 * z_1

Next tactic:
exact ⟨z, sq z⟩
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
⊢ roots p = 0 ↔ p = C (coeff p 0)

Next tactic:
refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by 

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
hp : p = C (coeff p 0)
⊢ roots p = 0

Next tactic:
rw [hp, roots_C]
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
  

Proof state:
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
h : roots p = 0
⊢ p = C (coeff p 0)

Next tactic:
rcases le_or_lt (degree p) 0 with hd | hd
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
  rcases le_or_lt (degree p) 0 with hd | hd
  · 

Proof state:
case inl
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
h : roots p = 0
hd : degree p ≤ 0
⊢ p = C (coeff p 0)

Next tactic:
exact eq_C_of_degree_le_zero hd
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
  rcases le_or_lt (degree p) 0 with hd | hd
  · exact eq_C_of_degree_le_zero hd
  · 

Proof state:
case inr
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
h : roots p = 0
hd : 0 < degree p
⊢ p = C (coeff p 0)

Next tactic:
obtain ⟨z, hz⟩ := IsAlgClosed.exists_root p hd.ne'
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
  rcases le_or_lt (degree p) 0 with hd | hd
  · exact eq_C_of_degree_le_zero hd
  · obtain ⟨z, hz⟩ := IsAlgClosed.exists_root p hd.ne'
    

Proof state:
case inr.intro
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
h : roots p = 0
hd : 0 < degree p
z : k
hz : IsRoot p z
⊢ p = C (coeff p 0)

Next tactic:
rw [← mem_roots (ne_zero_of_degree_gt hd), h] at hz
theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} :
    p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by
  refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩
  rcases le_or_lt (degree p) 0 with hd | hd
  · exact eq_C_of_degree_le_zero hd
  · obtain ⟨z, hz⟩ := IsAlgClosed.exists_root p hd.ne'
    rw [← mem_roots (ne_zero_of_degree_gt hd), h] at hz
    

Proof state:
case inr.intro
k : Type u
inst✝¹ : Field k
inst✝ : IsAlgClosed k
p : k[X]
h : roots p = 0
hd : 0 < degree p
z : k
hz : z ∈ 0
⊢ p = C (coeff p 0)

Next tactic:
simp at hz
theorem exists_eval₂_eq_zero_of_injective {R : Type*} [Ring R] [IsAlgClosed k] (f : R →+* k)
    (hf : Function.Injective f) (p : R[X]) (hp : p.degree ≠ 0) : ∃ x, p.eval₂ f x = 0 :=
  let ⟨x, hx⟩ := exists_root (p.map f) (by 

Proof state:
k : Type u
inst✝² : Field k
R : Type u_1
inst✝¹ : Ring R
inst✝ : IsAlgClosed k
f : R →+* k
hf : Function.Injective ⇑f
p : R[X]
hp : degree p ≠ 0
⊢ degree (map f p) ≠ 0

Next tactic:
rwa [degree_map_eq_of_injective hf]
theorem exists_eval₂_eq_zero_of_injective {R : Type*} [Ring R] [IsAlgClosed k] (f : R →+* k)
    (hf : Function.Injective f) (p : R[X]) (hp : p.degree ≠ 0) : ∃ x, p.eval₂ f x = 0 :=
  let ⟨x, hx⟩ := exists_root (p.map f) (by rwa [degree_map_eq_of_injective hf])
  ⟨x, by 

Proof state:
k : Type u
inst✝² : Field k
R : Type u_1
inst✝¹ : Ring R
inst✝ : IsAlgClosed k
f : R →+* k
hf : Function.Injective ⇑f
p : R[X]
hp : degree p ≠ 0
x : k
hx : IsRoot (map f p) x
⊢ eval₂ f x p = 0

Next tactic:
rwa [eval₂_eq_eval_map, ← IsRoot]
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
⊢ IsAlgClosed k

Next tactic:
refine ⟨fun p ↦ Or.inr ?_⟩
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  refine ⟨fun p ↦ Or.inr ?_⟩
  

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
p : k[X]
⊢ ∀ {g : k[X]}, Irreducible g → g ∣ map (RingHom.id k) p → degree g = 1

Next tactic:
intro q hq _
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  refine ⟨fun p ↦ Or.inr ?_⟩
  intro q hq _
  

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
p q : k[X]
hq : Irreducible q
a✝ : q ∣ map (RingHom.id k) p
⊢ degree q = 1

Next tactic:
have : Irreducible (q * C (leadingCoeff q)⁻¹) := by
    rw [← coe_normUnit_of_ne_zero hq.ne_zero]
    exact (associated_normalize _).irreducible hq
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  refine ⟨fun p ↦ Or.inr ?_⟩
  intro q hq _
  have : Irreducible (q * C (leadingCoeff q)⁻¹) := by
    

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
p q : k[X]
hq : Irreducible q
a✝ : q ∣ map (RingHom.id k) p
⊢ Irreducible (q * C (leadingCoeff q)⁻¹)

Next tactic:
rw [← coe_normUnit_of_ne_zero hq.ne_zero]
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  refine ⟨fun p ↦ Or.inr ?_⟩
  intro q hq _
  have : Irreducible (q * C (leadingCoeff q)⁻¹) := by
    rw [← coe_normUnit_of_ne_zero hq.ne_zero]
    

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
p q : k[X]
hq : Irreducible q
a✝ : q ∣ map (RingHom.id k) p
⊢ Irreducible (q * ↑(normUnit q))

Next tactic:
exact (associated_normalize _).irreducible hq
theorem of_exists_root (H : ∀ p : k[X], p.Monic → Irreducible p → ∃ x, p.eval x = 0) :
    IsAlgClosed k := by
  refine ⟨fun p ↦ Or.inr ?_⟩
  intro q hq _
  have : Irreducible (q * C (leadingCoeff q)⁻¹) := by
    rw [← coe_normUnit_of_ne_zero hq.ne_zero]
    exact (associated_normalize _).irreducible hq
  

Proof state:
k : Type u
inst✝ : Field k
H : ∀ (p : k[X]), Monic p → Irreducible p → ∃ x, eval x p = 0
p q : k[X]
hq : Irreducible q
a✝ : q ∣ map (RingHom.id k) p
this : Irreducible (q * C (leadingCoeff q)⁻¹)
⊢ degree q = 1

Next tactic:
obtain ⟨x, hx⟩ := H (q * C (leadingCoeff q)⁻¹) (monic_mul_leadingCoeff_inv hq.ne_zero) this