l3lab/ntp-mathlib huggingface dataset:
theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable)
    (h_root : h.eval x = 0) (h_splits : Splits i h) (h_roots : ∀ y ∈ (h.map i).roots, y = i x) :
    h = C (leadingCoeff h) * (X - C x) := by
  have h_ne_zero : h ≠ 0 := by
    rintro rfl
    exact not_separable_zero h_sep
  apply Polynomial.eq_X_sub_C_of_splits_of_single_root i h_splits
  apply Finset.mk.inj
  · change _ = {i x}
    rw [Finset.eq_singleton_iff_unique_mem]
    constructor
    · apply Finset.mem_mk.mpr
      · 

Proof state:
case x.left
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i : F →+* K
x : F
h : F[X]
h_sep : Separable h
h_root : eval x h = 0
h_splits : Splits i h
h_roots : ∀ y ∈ roots (map i h), y = i x
h_ne_zero : h ≠ 0
⊢ i x ∈ roots (map i h)

Next tactic:
rw [mem_roots (show h.map i ≠ 0 from map_ne_zero h_ne_zero)]
theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable)
    (h_root : h.eval x = 0) (h_splits : Splits i h) (h_roots : ∀ y ∈ (h.map i).roots, y = i x) :
    h = C (leadingCoeff h) * (X - C x) := by
  have h_ne_zero : h ≠ 0 := by
    rintro rfl
    exact not_separable_zero h_sep
  apply Polynomial.eq_X_sub_C_of_splits_of_single_root i h_splits
  apply Finset.mk.inj
  · change _ = {i x}
    rw [Finset.eq_singleton_iff_unique_mem]
    constructor
    · apply Finset.mem_mk.mpr
      · rw [mem_roots (show h.map i ≠ 0 from map_ne_zero h_ne_zero)]
        

Proof state:
case x.left
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i : F →+* K
x : F
h : F[X]
h_sep : Separable h
h_root : eval x h = 0
h_splits : Splits i h
h_roots : ∀ y ∈ roots (map i h), y = i x
h_ne_zero : h ≠ 0
⊢ IsRoot (map i h) (i x)

Next tactic:
rw [IsRoot.def, ← eval₂_eq_eval_map, eval₂_hom, h_root]
theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable)
    (h_root : h.eval x = 0) (h_splits : Splits i h) (h_roots : ∀ y ∈ (h.map i).roots, y = i x) :
    h = C (leadingCoeff h) * (X - C x) := by
  have h_ne_zero : h ≠ 0 := by
    rintro rfl
    exact not_separable_zero h_sep
  apply Polynomial.eq_X_sub_C_of_splits_of_single_root i h_splits
  apply Finset.mk.inj
  · change _ = {i x}
    rw [Finset.eq_singleton_iff_unique_mem]
    constructor
    · apply Finset.mem_mk.mpr
      · rw [mem_roots (show h.map i ≠ 0 from map_ne_zero h_ne_zero)]
        rw [IsRoot.def, ← eval₂_eq_eval_map, eval₂_hom, h_root]
        

Proof state:
case x.left
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i : F →+* K
x : F
h : F[X]
h_sep : Separable h
h_root : eval x h = 0
h_splits : Splits i h
h_roots : ∀ y ∈ roots (map i h), y = i x
h_ne_zero : h ≠ 0
⊢ i 0 = 0

Next tactic:
exact RingHom.map_zero i
theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable)
    (h_root : h.eval x = 0) (h_splits : Splits i h) (h_roots : ∀ y ∈ (h.map i).roots, y = i x) :
    h = C (leadingCoeff h) * (X - C x) := by
  have h_ne_zero : h ≠ 0 := by
    rintro rfl
    exact not_separable_zero h_sep
  apply Polynomial.eq_X_sub_C_of_splits_of_single_root i h_splits
  apply Finset.mk.inj
  · change _ = {i x}
    rw [Finset.eq_singleton_iff_unique_mem]
    constructor
    · apply Finset.mem_mk.mpr
      · rw [mem_roots (show h.map i ≠ 0 from map_ne_zero h_ne_zero)]
        rw [IsRoot.def, ← eval₂_eq_eval_map, eval₂_hom, h_root]
        exact RingHom.map_zero i
      · 

Proof state:
case nodup
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i : F →+* K
x : F
h : F[X]
h_sep : Separable h
h_root : eval x h = 0
h_splits : Splits i h
h_roots : ∀ y ∈ roots (map i h), y = i x
h_ne_zero : h ≠ 0
⊢ Multiset.Nodup (roots (map i h))

Next tactic:
exact nodup_roots (Separable.map h_sep)
theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable)
    (h_root : h.eval x = 0) (h_splits : Splits i h) (h_roots : ∀ y ∈ (h.map i).roots, y = i x) :
    h = C (leadingCoeff h) * (X - C x) := by
  have h_ne_zero : h ≠ 0 := by
    rintro rfl
    exact not_separable_zero h_sep
  apply Polynomial.eq_X_sub_C_of_splits_of_single_root i h_splits
  apply Finset.mk.inj
  · change _ = {i x}
    rw [Finset.eq_singleton_iff_unique_mem]
    constructor
    · apply Finset.mem_mk.mpr
      · rw [mem_roots (show h.map i ≠ 0 from map_ne_zero h_ne_zero)]
        rw [IsRoot.def, ← eval₂_eq_eval_map, eval₂_hom, h_root]
        exact RingHom.map_zero i
      · exact nodup_roots (Separable.map h_sep)
    · 

Proof state:
case x.right
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i : F →+* K
x : F
h : F[X]
h_sep : Separable h
h_root : eval x h = 0
h_splits : Splits i h
h_roots : ∀ y ∈ roots (map i h), y = i x
h_ne_zero : h ≠ 0
⊢ ∀ x_1 ∈ { val := roots (map i h), nodup := (_ : Multiset.Nodup (roots (map i h))) }, x_1 = i x

Next tactic:
exact h_roots
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  

Proof state:
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
⊢ ∃ s, map i f = C (i (leadingCoeff f)) * ∏ a in s, (X - C a)

Next tactic:
obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  

Proof state:
case intro
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ ∃ s, map i f = C (i (leadingCoeff f)) * ∏ a in s, (X - C a)

Next tactic:
use s.toFinset
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  use s.toFinset
  

Proof state:
case h
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ map i f = C (i (leadingCoeff f)) * ∏ a in Multiset.toFinset s, (X - C a)

Next tactic:
rw [h, Finset.prod_eq_multiset_prod, ← Multiset.toFinset_eq]
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  use s.toFinset
  rw [h, Finset.prod_eq_multiset_prod, ← Multiset.toFinset_eq]
  

Proof state:
case h
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ Multiset.Nodup s

Next tactic:
apply nodup_of_separable_prod
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  use s.toFinset
  rw [h, Finset.prod_eq_multiset_prod, ← Multiset.toFinset_eq]
  apply nodup_of_separable_prod
  

Proof state:
case h.hs
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ Separable (Multiset.prod (Multiset.map (fun a => X - C a) s))

Next tactic:
apply Separable.of_mul_right
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  use s.toFinset
  rw [h, Finset.prod_eq_multiset_prod, ← Multiset.toFinset_eq]
  apply nodup_of_separable_prod
  apply Separable.of_mul_right
  

Proof state:
case h.hs.h
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ Separable (?h.hs.f * Multiset.prod (Multiset.map (fun a => X - C a) s))
case h.hs.f
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ K[X]

Next tactic:
rw [← h]
theorem exists_finset_of_splits (i : F →+* K) {f : F[X]} (sep : Separable f) (sp : Splits i f) :
    ∃ s : Finset K, f.map i = C (i f.leadingCoeff) * s.prod fun a : K => X - C a := by
  obtain ⟨s, h⟩ := (splits_iff_exists_multiset _).1 sp
  use s.toFinset
  rw [h, Finset.prod_eq_multiset_prod, ← Multiset.toFinset_eq]
  apply nodup_of_separable_prod
  apply Separable.of_mul_right
  rw [← h]
  

Proof state:
case h.hs.h
F : Type u
inst✝¹ : Field F
K : Type v
inst✝ : Field K
i✝ i : F →+* K
f : F[X]
sep : Separable f
sp : Splits i f
s : Multiset K
h : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
⊢ Separable (map i f)

Next tactic:
exact sep.map
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  

Proof state:
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
⊢ Separable f

Next tactic:
rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · 

Proof state:
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
⊢ ¬↑(natDegree f - 1) = ⊥

Next tactic:
rintro ⟨⟩
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
⊢ 0 < natDegree f

Next tactic:
rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
⊢ ¬f = C (coeff f 0)

Next tactic:
refine' fun hf1 => hf.not_unit _
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
  refine' fun hf1 => hf.not_unit _
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
hf1 : f = C (coeff f 0)
⊢ IsUnit f

Next tactic:
rw [hf1, isUnit_C, isUnit_iff_ne_zero]
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
  refine' fun hf1 => hf.not_unit _
  rw [hf1, isUnit_C, isUnit_iff_ne_zero]
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
hf1 : f = C (coeff f 0)
⊢ coeff f 0 ≠ 0

Next tactic:
intro hf2
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
  refine' fun hf1 => hf.not_unit _
  rw [hf1, isUnit_C, isUnit_iff_ne_zero]
  intro hf2
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
hf1 : f = C (coeff f 0)
hf2 : coeff f 0 = 0
⊢ False

Next tactic:
rw [hf2, C_0] at hf1
theorem _root_.Irreducible.separable [CharZero F] {f : F[X]} (hf : Irreducible f) :
    f.Separable := by
  rw [separable_iff_derivative_ne_zero hf, Ne, ← degree_eq_bot, degree_derivative_eq]
  · rintro ⟨⟩
  rw [pos_iff_ne_zero, Ne, natDegree_eq_zero_iff_degree_le_zero, degree_le_zero_iff]
  refine' fun hf1 => hf.not_unit _
  rw [hf1, isUnit_C, isUnit_iff_ne_zero]
  intro hf2
  rw [hf2, C_0] at hf1
  

Proof state:
case hp
F : Type u
inst✝² : Field F
K : Type v
inst✝¹ : Field K
inst✝ : CharZero F
f : F[X]
hf : Irreducible f
hf1 : f = 0
hf2 : coeff f 0 = 0
⊢ False

Next tactic:
exact absurd hf1 hf.ne_zero
variable {F} in
/-- If the minimal polynomial of `x : K` over `F` is separable, then `x` is integral over `F`,
because the minimal polynomial of a non-integral element is `0`, which is not separable. -/
theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : IsIntegral F x := by
  

Proof state:
F : Type u_1
K : Type u_2
inst✝² : CommRing F
inst✝¹ : Ring K
inst✝ : Algebra F K
x : K
h : Separable (minpoly F x)
⊢ IsIntegral F x

Next tactic:
cases subsingleton_or_nontrivial F
variable {F} in
/-- If the minimal polynomial of `x : K` over `F` is separable, then `x` is integral over `F`,
because the minimal polynomial of a non-integral element is `0`, which is not separable. -/
theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : IsIntegral F x := by
  cases subsingleton_or_nontrivial F
  · 

Proof state:
case inl
F : Type u_1
K : Type u_2
inst✝² : CommRing F
inst✝¹ : Ring K
inst✝ : Algebra F K
x : K
h : Separable (minpoly F x)
h✝ : Subsingleton F
⊢ IsIntegral F x

Next tactic:
haveI := Module.subsingleton F K
variable {F} in
/-- If the minimal polynomial of `x : K` over `F` is separable, then `x` is integral over `F`,
because the minimal polynomial of a non-integral element is `0`, which is not separable. -/
theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : IsIntegral F x := by
  cases subsingleton_or_nontrivial F
  · haveI := Module.subsingleton F K
    

Proof state:
case inl
F : Type u_1
K : Type u_2
inst✝² : CommRing F
inst✝¹ : Ring K
inst✝ : Algebra F K
x : K
h : Separable (minpoly F x)
h✝ : Subsingleton F
this : Subsingleton K
⊢ IsIntegral F x

Next tactic:
exact ⟨1, monic_one, Subsingleton.elim _ _⟩
variable {F} in
/-- If the minimal polynomial of `x : K` over `F` is separable, then `x` is integral over `F`,
because the minimal polynomial of a non-integral element is `0`, which is not separable. -/
theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : IsIntegral F x := by
  cases subsingleton_or_nontrivial F
  · haveI := Module.subsingleton F K
    exact ⟨1, monic_one, Subsingleton.elim _ _⟩
  · 

Proof state:
case inr
F : Type u_1
K : Type u_2
inst✝² : CommRing F
inst✝¹ : Ring K
inst✝ : Algebra F K
x : K
h : Separable (minpoly F x)
h✝ : Nontrivial F
⊢ IsIntegral F x

Next tactic:
exact of_not_not fun h' ↦ not_separable_zero (minpoly.eq_zero h' ▸ h)
/-- Transfer `IsSeparable` across an `AlgEquiv`. -/
theorem AlgEquiv.isSeparable [IsSeparable F K] : IsSeparable F E :=
  ⟨fun _ ↦ by 

Proof state:
F : Type u_1
K : Type u_2
inst✝⁵ : CommRing F
inst✝⁴ : Ring K
inst✝³ : Algebra F K
E : Type u_3
inst✝² : Ring E
inst✝¹ : Algebra F E
e : K ≃ₐ[F] E
inst✝ : IsSeparable F K
x✝ : E
⊢ Separable (minpoly F x✝)

Next tactic:
rw [← minpoly.algEquiv_eq e.symm]
/-- Transfer `IsSeparable` across an `AlgEquiv`. -/
theorem AlgEquiv.isSeparable [IsSeparable F K] : IsSeparable F E :=
  ⟨fun _ ↦ by rw [← minpoly.algEquiv_eq e.symm]; 

Proof state:
F : Type u_1
K : Type u_2
inst✝⁵ : CommRing F
inst✝⁴ : Ring K
inst✝³ : Algebra F K
E : Type u_3
inst✝² : Ring E
inst✝¹ : Algebra F E
e : K ≃ₐ[F] E
inst✝ : IsSeparable F K
x✝ : E
⊢ Separable (minpoly F ((symm e) x✝))

Next tactic:
exact IsSeparable.separable F _
instance isSeparable_self (F : Type*) [Field F] : IsSeparable F F :=
  ⟨fun x => by
    

Proof state:
F : Type u_1
inst✝ : Field F
x : F
⊢ Separable (minpoly F x)

Next tactic:
rw [minpoly.eq_X_sub_C']
instance isSeparable_self (F : Type*) [Field F] : IsSeparable F F :=
  ⟨fun x => by
    rw [minpoly.eq_X_sub_C']
    

Proof state:
F : Type u_1
inst✝ : Field F
x : F
⊢ Separable (X - C x)

Next tactic:
exact separable_X_sub_C
theorem IsSeparable.of_algHom (E' : Type*) [Field E'] [Algebra F E'] (f : E →ₐ[F] E')
    [IsSeparable F E'] : IsSeparable F E := by
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝⁹ : Field F
inst✝⁸ : Field K
inst✝⁷ : Field E
inst✝⁶ : Algebra F K
inst✝⁵ : Algebra F E
inst✝⁴ : Algebra K E
inst✝³ : IsScalarTower F K E
E' : Type u_4
inst✝² : Field E'
inst✝¹ : Algebra F E'
f : E →ₐ[F] E'
inst✝ : IsSeparable F E'
⊢ IsSeparable F E

Next tactic:
letI : Algebra E E' := RingHom.toAlgebra f.toRingHom
theorem IsSeparable.of_algHom (E' : Type*) [Field E'] [Algebra F E'] (f : E →ₐ[F] E')
    [IsSeparable F E'] : IsSeparable F E := by
  letI : Algebra E E' := RingHom.toAlgebra f.toRingHom
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝⁹ : Field F
inst✝⁸ : Field K
inst✝⁷ : Field E
inst✝⁶ : Algebra F K
inst✝⁵ : Algebra F E
inst✝⁴ : Algebra K E
inst✝³ : IsScalarTower F K E
E' : Type u_4
inst✝² : Field E'
inst✝¹ : Algebra F E'
f : E →ₐ[F] E'
inst✝ : IsSeparable F E'
this : Algebra E E' := RingHom.toAlgebra ↑f
⊢ IsSeparable F E

Next tactic:
haveI : IsScalarTower F E E' := IsScalarTower.of_algebraMap_eq fun x => (f.commutes x).symm
theorem IsSeparable.of_algHom (E' : Type*) [Field E'] [Algebra F E'] (f : E →ₐ[F] E')
    [IsSeparable F E'] : IsSeparable F E := by
  letI : Algebra E E' := RingHom.toAlgebra f.toRingHom
  haveI : IsScalarTower F E E' := IsScalarTower.of_algebraMap_eq fun x => (f.commutes x).symm
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝⁹ : Field F
inst✝⁸ : Field K
inst✝⁷ : Field E
inst✝⁶ : Algebra F K
inst✝⁵ : Algebra F E
inst✝⁴ : Algebra K E
inst✝³ : IsScalarTower F K E
E' : Type u_4
inst✝² : Field E'
inst✝¹ : Algebra F E'
f : E →ₐ[F] E'
inst✝ : IsSeparable F E'
this✝ : Algebra E E' := RingHom.toAlgebra ↑f
this : IsScalarTower F E E'
⊢ IsSeparable F E

Next tactic:
exact isSeparable_tower_bot_of_isSeparable F E E'
lemma IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁]
    [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂)
    (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁))
    [IsSeparable A₁ B₁] : IsSeparable A₂ B₂ := by
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝¹³ : Field F
inst✝¹² : Field K
inst✝¹¹ : Field E
inst✝¹⁰ : Algebra F K
inst✝⁹ : Algebra F E
inst✝⁸ : Algebra K E
inst✝⁷ : IsScalarTower F K E
A₁ : Type u_4
B₁ : Type u_5
A₂ : Type u_6
B₂ : Type u_7
inst✝⁶ : Field A₁
inst✝⁵ : Field B₁
inst✝⁴ : Field A₂
inst✝³ : Field B₂
inst✝² : Algebra A₁ B₁
inst✝¹ : Algebra A₂ B₂
e₁ : A₁ ≃+* A₂
e₂ : B₁ ≃+* B₂
he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp (↑e₂) (algebraMap A₁ B₁)
inst✝ : IsSeparable A₁ B₁
⊢ IsSeparable A₂ B₂

Next tactic:
letI := e₁.toRingHom.toAlgebra
lemma IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁]
    [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂)
    (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁))
    [IsSeparable A₁ B₁] : IsSeparable A₂ B₂ := by
  letI := e₁.toRingHom.toAlgebra
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝¹³ : Field F
inst✝¹² : Field K
inst✝¹¹ : Field E
inst✝¹⁰ : Algebra F K
inst✝⁹ : Algebra F E
inst✝⁸ : Algebra K E
inst✝⁷ : IsScalarTower F K E
A₁ : Type u_4
B₁ : Type u_5
A₂ : Type u_6
B₂ : Type u_7
inst✝⁶ : Field A₁
inst✝⁵ : Field B₁
inst✝⁴ : Field A₂
inst✝³ : Field B₂
inst✝² : Algebra A₁ B₁
inst✝¹ : Algebra A₂ B₂
e₁ : A₁ ≃+* A₂
e₂ : B₁ ≃+* B₂
he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp (↑e₂) (algebraMap A₁ B₁)
inst✝ : IsSeparable A₁ B₁
this : Algebra A₁ A₂ := RingHom.toAlgebra (RingEquiv.toRingHom e₁)
⊢ IsSeparable A₂ B₂

Next tactic:
letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra
lemma IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁]
    [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂)
    (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁))
    [IsSeparable A₁ B₁] : IsSeparable A₂ B₂ := by
  letI := e₁.toRingHom.toAlgebra
  letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra
  

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝¹³ : Field F
inst✝¹² : Field K
inst✝¹¹ : Field E
inst✝¹⁰ : Algebra F K
inst✝⁹ : Algebra F E
inst✝⁸ : Algebra K E
inst✝⁷ : IsScalarTower F K E
A₁ : Type u_4
B₁ : Type u_5
A₂ : Type u_6
B₂ : Type u_7
inst✝⁶ : Field A₁
inst✝⁵ : Field B₁
inst✝⁴ : Field A₂
inst✝³ : Field B₂
inst✝² : Algebra A₁ B₁
inst✝¹ : Algebra A₂ B₂
e₁ : A₁ ≃+* A₂
e₂ : B₁ ≃+* B₂
he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp (↑e₂) (algebraMap A₁ B₁)
inst✝ : IsSeparable A₁ B₁
this✝ : Algebra A₁ A₂ := RingHom.toAlgebra (RingEquiv.toRingHom e₁)
this : Algebra A₂ B₁ := RingHom.toAlgebra (RingHom.comp (algebraMap A₁ B₁) (RingEquiv.toRingHom (RingEquiv.symm e₁)))
⊢ IsSeparable A₂ B₂

Next tactic:
haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq
    (fun x ↦ by simp [RingHom.algebraMap_toAlgebra])
lemma IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁]
    [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂)
    (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁))
    [IsSeparable A₁ B₁] : IsSeparable A₂ B₂ := by
  letI := e₁.toRingHom.toAlgebra
  letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra
  haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq
    (fun x ↦ by 

Proof state:
F : Type u_1
K : Type u_2
E : Type u_3
inst✝¹³ : Field F
inst✝¹² : Field K
inst✝¹¹ : Field E
inst✝¹⁰ : Algebra F K
inst✝⁹ : Algebra F E
inst✝⁸ : Algebra K E
inst✝⁷ : IsScalarTower F K E
A₁ : Type u_4
B₁ : Type u_5
A₂ : Type u_6
B₂ : Type u_7
inst✝⁶ : Field A₁
inst✝⁵ : Field B₁
inst✝⁴ : Field A₂
inst✝³ : Field B₂
inst✝² : Algebra A₁ B₁
inst✝¹ : Algebra A₂ B₂
e₁ : A₁ ≃+* A₂
e₂ : B₁ ≃+* B₂
he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp (↑e₂) (algebraMap A₁ B₁)
inst✝ : IsSeparable A₁ B₁
this✝ : Algebra A₁ A₂ := RingHom.toAlgebra (RingEquiv.toRingHom e₁)
this : Algebra A₂ B₁ := RingHom.toAlgebra (RingHom.comp (algebraMap A₁ B₁) (RingEquiv.toRingHom (RingEquiv.symm e₁)))
x : A₁
⊢ (algebraMap A₁ B₁) x = (algebraMap A₂ B₁) ((algebraMap A₁ A₂) x)

Next tactic:
simp [RingHom.algebraMap_toAlgebra]