l3lab/ntp-mathlib huggingface dataset:
instance isNormalClosure_normalClosure [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    IsNormalClosure F K (normalClosure F K L) := by
  have ⟨φ⟩ := ne
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
⊢ IsNormalClosure F K ↥(normalClosure F K L)

Next tactic:
apply (h.isAlgebraic'.of_injective φ φ.injective).isNormalClosure_normalClosure
instance isNormalClosure_normalClosure [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    IsNormalClosure F K (normalClosure F K L) := by
  have ⟨φ⟩ := ne
  apply (h.isAlgebraic'.of_injective φ φ.injective).isNormalClosure_normalClosure
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
⊢ ∀ (x : K), Splits (algebraMap F L) (minpoly F x)

Next tactic:
simp_rw [← minpoly.algHom_eq _ φ.injective]
instance isNormalClosure_normalClosure [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    IsNormalClosure F K (normalClosure F K L) := by
  have ⟨φ⟩ := ne
  apply (h.isAlgebraic'.of_injective φ φ.injective).isNormalClosure_normalClosure
  simp_rw [← minpoly.algHom_eq _ φ.injective]
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
⊢ ∀ (x : K), Splits (algebraMap F L) (minpoly F (φ x))

Next tactic:
exact fun _ ↦ h.splits _
theorem normalClosure_eq_iSup_adjoin' [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
⊢ normalClosure F K L = ⨆ x, adjoin F (rootSet (minpoly F x) L)

Next tactic:
have ⟨φ⟩ := ne
theorem normalClosure_eq_iSup_adjoin' [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
  have ⟨φ⟩ := ne
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
⊢ normalClosure F K L = ⨆ x, adjoin F (rootSet (minpoly F x) L)

Next tactic:
refine h.isAlgebraic'.of_injective φ φ.injective
    |>.normalClosure_eq_iSup_adjoin_of_splits fun x ↦ ?_
theorem normalClosure_eq_iSup_adjoin' [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
  have ⟨φ⟩ := ne
  refine h.isAlgebraic'.of_injective φ φ.injective
    |>.normalClosure_eq_iSup_adjoin_of_splits fun x ↦ ?_
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
x : K
⊢ Splits (algebraMap F L) (minpoly F x)

Next tactic:
rw [← minpoly.algHom_eq _ φ.injective]
theorem normalClosure_eq_iSup_adjoin' [ne : Nonempty (K →ₐ[F] L)] [h : Normal F L] :
    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
  have ⟨φ⟩ := ne
  refine h.isAlgebraic'.of_injective φ φ.injective
    |>.normalClosure_eq_iSup_adjoin_of_splits fun x ↦ ?_
  rw [← minpoly.algHom_eq _ φ.injective]
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
ne : Nonempty (K →ₐ[F] L)
h : Normal F L
φ : K →ₐ[F] L
x : K
⊢ Splits (algebraMap F L) (minpoly F (φ x))

Next tactic:
apply h.splits
instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
h : Normal F L
⊢ Normal F ↥(normalClosure F K L)

Next tactic:
obtain _ | φ := isEmpty_or_nonempty (K →ₐ[F] L)
instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
  obtain _ | φ := isEmpty_or_nonempty (K →ₐ[F] L)
  · 

Proof state:
case inl
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
h : Normal F L
h✝ : IsEmpty (K →ₐ[F] L)
⊢ Normal F ↥(normalClosure F K L)

Next tactic:
rw [normalClosure, iSup_of_empty]
instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
  obtain _ | φ := isEmpty_or_nonempty (K →ₐ[F] L)
  · rw [normalClosure, iSup_of_empty]; 

Proof state:
case inl
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
h : Normal F L
h✝ : IsEmpty (K →ₐ[F] L)
⊢ Normal F ↥⊥

Next tactic:
exact Normal.of_algEquiv (botEquiv F L).symm
instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
  obtain _ | φ := isEmpty_or_nonempty (K →ₐ[F] L)
  · rw [normalClosure, iSup_of_empty]; exact Normal.of_algEquiv (botEquiv F L).symm
  · 

Proof state:
case inr
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁴ : Field F
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Algebra F K
inst✝ : Algebra F L
h : Normal F L
φ : Nonempty (K →ₐ[F] L)
⊢ Normal F ↥(normalClosure F K L)

Next tactic:
exact (isNormalClosure_normalClosure F K L).normal
instance is_finiteDimensional [FiniteDimensional F K] :
    FiniteDimensional F (normalClosure F K L) := by
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Algebra F K
inst✝¹ : Algebra F L
inst✝ : FiniteDimensional F K
⊢ FiniteDimensional F ↥(normalClosure F K L)

Next tactic:
haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f ↦
    f.toLinearMap.finiteDimensional_range
instance is_finiteDimensional [FiniteDimensional F K] :
    FiniteDimensional F (normalClosure F K L) := by
  haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f ↦
    f.toLinearMap.finiteDimensional_range
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Algebra F K
inst✝¹ : Algebra F L
inst✝ : FiniteDimensional F K
this : ∀ (f : K →ₐ[F] L), FiniteDimensional F ↥(AlgHom.fieldRange f)
⊢ FiniteDimensional F ↥(normalClosure F K L)

Next tactic:
apply IntermediateField.finiteDimensional_iSup_of_finite
instance : IsScalarTower F K (normalClosure F K L) := by
  

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
inst✝¹ : Algebra K L
inst✝ : IsScalarTower F K L
⊢ IsScalarTower F K ↥(normalClosure F K L)

Next tactic:
apply of_algebraMap_eq'
instance : IsScalarTower F K (normalClosure F K L) := by
  apply of_algebraMap_eq'
  

Proof state:
case h
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
inst✝¹ : Algebra K L
inst✝ : IsScalarTower F K L
⊢ algebraMap F ↥(normalClosure F K L) = RingHom.comp (algebraMap K ↥(normalClosure F K L)) (algebraMap F K)

Next tactic:
ext x
instance : IsScalarTower F K (normalClosure F K L) := by
  apply of_algebraMap_eq'
  ext x
  

Proof state:
case h.a.a
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
inst✝¹ : Algebra K L
inst✝ : IsScalarTower F K L
x : F
⊢ ↑((algebraMap F ↥(normalClosure F K L)) x) =
    ↑((RingHom.comp (algebraMap K ↥(normalClosure F K L)) (algebraMap F K)) x)

Next tactic:
exact algebraMap_apply F K L x
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
⊢ Nonempty (↥(⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')) →ₐ[F] L)

Next tactic:
rw [← gc.l_iSup]
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
⊢ Nonempty (↥(IntermediateField.adjoin F (⨆ x, rootSet (minpoly F x) L')) →ₐ[F] L)

Next tactic:
refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
x : L'
hx : x ∈ ⨆ x, rootSet (minpoly F x) L'
⊢ IsIntegral F x ∧ Splits (algebraMap F L) (minpoly F x)

Next tactic:
obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      

Proof state:
case intro
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
x : L'
hx✝ : x ∈ ⨆ x, rootSet (minpoly F x) L'
y : K
hx : x ∈ rootSet (minpoly F y) L'
⊢ IsIntegral F x ∧ Splits (algebraMap F L) (minpoly F x)

Next tactic:
refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
      

Proof state:
case intro
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
x : L'
hx✝ : x ∈ ⨆ x, rootSet (minpoly F x) L'
y : K
hx : x ∈ rootSet (minpoly F y) L'
⊢ Splits (algebraMap F L) (minpoly F x)

Next tactic:
by_cases iy : IsIntegral F y
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
      by_cases iy : IsIntegral F y
      · 

Proof state:
case pos
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
x : L'
hx✝ : x ∈ ⨆ x, rootSet (minpoly F x) L'
y : K
hx : x ∈ rootSet (minpoly F y) L'
iy : IsIntegral F y
⊢ Splits (algebraMap F L) (minpoly F x)

Next tactic:
exact splits_of_splits_of_dvd _ (minpoly.ne_zero iy)
          (h y) (minpoly.dvd F x (mem_rootSet.mp hx).2)
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
      by_cases iy : IsIntegral F y
      · exact splits_of_splits_of_dvd _ (minpoly.ne_zero iy)
          (h y) (minpoly.dvd F x (mem_rootSet.mp hx).2)
      · 

Proof state:
case neg
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
x : L'
hx✝ : x ∈ ⨆ x, rootSet (minpoly F x) L'
y : K
hx : x ∈ rootSet (minpoly F y) L'
iy : ¬IsIntegral F y
⊢ Splits (algebraMap F L) (minpoly F x)

Next tactic:
simp [minpoly.eq_zero iy] at hx
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
      by_cases iy : IsIntegral F y
      · exact splits_of_splits_of_dvd _ (minpoly.ne_zero iy)
          (h y) (minpoly.dvd F x (mem_rootSet.mp hx).2)
      · simp [minpoly.eq_zero iy] at hx
  { toFun := (φ.comp <| inclusion <| normalClosure_le_iSup_adjoin alg).comp ∘
      (normalClosure.algHomEquiv F K L').symm
    inj' := fun _ _ h ↦ (normalClosure.algHomEquiv F K L').symm.injective <| by
      

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h✝ : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
φ : ↥(⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')) →ₐ[F] L :=
  Nonempty.some (_ : Nonempty (↥(⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')) →ₐ[F] L))
x✝¹ x✝ : K →ₐ[F] L'
h :
  (AlgHom.comp
          (AlgHom.comp φ
            (inclusion (_ : normalClosure F K L' ≤ ⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')))) ∘
        ⇑(normalClosure.algHomEquiv F K L').symm)
      x✝¹ =
    (AlgHom.comp
          (AlgHom.comp φ
            (inclusion (_ : normalClosure F K L' ≤ ⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')))) ∘
        ⇑(normalClosure.algHomEquiv F K L').symm)
      x✝
⊢ (normalClosure.algHomEquiv F K L').symm x✝¹ = (normalClosure.algHomEquiv F K L').symm x✝

Next tactic:
rw [FunLike.ext'_iff] at h ⊢
open Cardinal in
/-- An extension `L/F` in which every minimal polynomial of `K/F` splits is maximal with respect
  to `F`-embeddings of `K`, in the sense that `K →ₐ[F] L` achieves maximal cardinality.
  We construct an explicit injective function from an arbitrary `K →ₐ[F] L'` into `K →ₐ[F] L`,
  using an embedding of `normalClosure F K L'` into `L`. -/
noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic F K)
    (h : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (L' : Type*) [Field L'] [Algebra F L'] :
    (K →ₐ[F] L') ↪ (K →ₐ[F] L) :=
  let φ : ↑(⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L')) →ₐ[F] L :=
    Nonempty.some <| by
      rw [← gc.l_iSup]
      refine nonempty_algHom_adjoin_of_splits fun x hx ↦ ?_
      obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
      refine ⟨isAlgebraic_iff_isIntegral.mp (isAlgebraic_of_mem_rootSet hx), ?_⟩
      by_cases iy : IsIntegral F y
      · exact splits_of_splits_of_dvd _ (minpoly.ne_zero iy)
          (h y) (minpoly.dvd F x (mem_rootSet.mp hx).2)
      · simp [minpoly.eq_zero iy] at hx
  { toFun := (φ.comp <| inclusion <| normalClosure_le_iSup_adjoin alg).comp ∘
      (normalClosure.algHomEquiv F K L').symm
    inj' := fun _ _ h ↦ (normalClosure.algHomEquiv F K L').symm.injective <| by
      rw [FunLike.ext'_iff] at h ⊢
      

Proof state:
F : Type u_1
K : Type u_2
L : Type u_3
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Field L
inst✝³ : Algebra F K
inst✝² : Algebra F L
alg : IsAlgebraic F K
h✝ : ∀ (x : K), Splits (algebraMap F L) (minpoly F x)
L' : Type u_4
inst✝¹ : Field L'
inst✝ : Algebra F L'
φ : ↥(⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')) →ₐ[F] L :=
  Nonempty.some (_ : Nonempty (↥(⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')) →ₐ[F] L))
x✝¹ x✝ : K →ₐ[F] L'
h :
  ⇑((AlgHom.comp
            (AlgHom.comp φ
              (inclusion (_ : normalClosure F K L' ≤ ⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')))) ∘
          ⇑(normalClosure.algHomEquiv F K L').symm)
        x✝¹) =
    ⇑((AlgHom.comp
            (AlgHom.comp φ
              (inclusion (_ : normalClosure F K L' ≤ ⨆ x, IntermediateField.adjoin F (rootSet (minpoly F x) L')))) ∘
          ⇑(normalClosure.algHomEquiv F K L').symm)
        x✝)
⊢ ⇑((normalClosure.algHomEquiv F K L').symm x✝¹) = ⇑((normalClosure.algHomEquiv F K L').symm x✝)

Next tactic:
exact (φ.comp _).injective.comp_left h
lemma normalClosure_of_normal [Normal F K] : normalClosure F K L = K :=
by 

Proof state:
F : Type u_1
K✝ : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K✝
inst✝³ : Field L
inst✝² : Algebra F K✝
inst✝¹ : Algebra F L
K K' : IntermediateField F L
inst✝ : Normal F ↥K
⊢ normalClosure F (↥K) L = K

Next tactic:
simp only [normalClosure_def, AlgHom.fieldRange_of_normal, iSup_const]
lemma normalClosure_def' : normalClosure F K L = ⨆ f : L →ₐ[F] L, K.map f := by
  

Proof state:
F : Type u_1
K✝ : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K✝
inst✝³ : Field L
inst✝² : Algebra F K✝
inst✝¹ : Algebra F L
K K' : IntermediateField F L
inst✝ : Normal F L
⊢ normalClosure F (↥K) L = ⨆ f, map f K

Next tactic:
refine' (normalClosure_def F K L).trans (le_antisymm (iSup_le (fun f ↦ _)) (iSup_le (fun f ↦ _)))
lemma normalClosure_def' : normalClosure F K L = ⨆ f : L →ₐ[F] L, K.map f := by
  refine' (normalClosure_def F K L).trans (le_antisymm (iSup_le (fun f ↦ _)) (iSup_le (fun f ↦ _)))
  · 

Proof state:
case refine'_1
F : Type u_1
K✝ : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K✝
inst✝³ : Field L
inst✝² : Algebra F K✝
inst✝¹ : Algebra F L
K K' : IntermediateField F L
inst✝ : Normal F L
f : ↥K →ₐ[F] L
⊢ AlgHom.fieldRange f ≤ ⨆ f, map f K

Next tactic:
exact le_iSup_of_le (f.liftNormal L) (fun b ⟨a, h⟩ ↦ ⟨a, a.2, h ▸ f.liftNormal_commutes L a⟩)
lemma normalClosure_def' : normalClosure F K L = ⨆ f : L →ₐ[F] L, K.map f := by
  refine' (normalClosure_def F K L).trans (le_antisymm (iSup_le (fun f ↦ _)) (iSup_le (fun f ↦ _)))
  · exact le_iSup_of_le (f.liftNormal L) (fun b ⟨a, h⟩ ↦ ⟨a, a.2, h ▸ f.liftNormal_commutes L a⟩)
  · 

Proof state:
case refine'_2
F : Type u_1
K✝ : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K✝
inst✝³ : Field L
inst✝² : Algebra F K✝
inst✝¹ : Algebra F L
K K' : IntermediateField F L
inst✝ : Normal F L
f : L →ₐ[F] L
⊢ map f K ≤ ⨆ f, AlgHom.fieldRange f

Next tactic:
exact le_iSup_of_le (f.comp K.val) (fun b ⟨a, h⟩ ↦ ⟨⟨a, h.1⟩, h.2⟩)
lemma normalClosure_def'' : normalClosure F K L = ⨆ f : L ≃ₐ[F] L, K.map f := by
  

Proof state:
F : Type u_1
K✝ : Type u_2
L : Type u_3
inst✝⁵ : Field F
inst✝⁴ : Field K✝
inst✝³ : Field L
inst✝² : Algebra F K✝
inst✝¹ : Algebra F L
K K' : IntermediateField F L
inst✝ : Normal F L
⊢ normalClosure F (↥K) L = ⨆ f, map (↑f) K

Next tactic:
refine' (normalClosure_def' K).trans (le_antisymm (iSup_le (fun f ↦ _)) (iSup_le (fun f ↦ _)))