l3lab/ntp-mathlib huggingface dataset:
theorem finite_intermediateField_of_exists_primitive_element (halg : Algebra.IsAlgebraic F E)
    (h : ∃ α : E, F⟮α⟯ = ⊤) : Finite (IntermediateField F E) := by
  haveI := finiteDimensional_of_exists_primitive_element F E halg h
  obtain ⟨α, hprim⟩ := h
  -- Let `f` be the minimal polynomial of `α ∈ E` over `F`
  let f : F[X] := minpoly F α
  let G := { g : E[X] // g.Monic ∧ g ∣ f.map (algebraMap F E) }
  -- Then `f` has only finitely many monic factors
  have hfin : Finite G := @Finite.of_fintype _ <| fintypeSubtypeMonicDvd
    (f.map (algebraMap F E)) <| map_ne_zero (minpoly.ne_zero_of_finite F α)
  -- If `K` is an intermediate field of `E/F`, let `g` be the minimal polynomial of `α` over `K`
  -- which is a monic factor of `f`
  let g : IntermediateField F E → G := fun K ↦
    ⟨(minpoly K α).map (algebraMap K E), (minpoly.monic <| .of_finite K α).map _, by
      convert Polynomial.map_dvd (algebraMap K E) (minpoly.dvd_map_of_isScalarTower F K α)
      rw [Polynomial.map_map]; rfl⟩
  -- The map `K ↦ g` is injective
  have hinj : Function.Injective g := fun K K' heq ↦ by
    rw [Subtype.mk.injEq] at heq
    

Proof state:
F : Type u_1
E : Type u_2
inst✝² : Field F
inst✝¹ : Field E
inst✝ : Algebra F E
halg : Algebra.IsAlgebraic F E
this : FiniteDimensional F E
α : E
hprim : F⟮α⟯ = ⊤
f : F[X] := minpoly F α
G : Type u_2 := { g // Monic g ∧ g ∣ Polynomial.map (algebraMap F E) f }
hfin : Finite G
g : IntermediateField F E → G :=
  fun K =>
    { val := Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α),
      property :=
        (_ :
          Monic (Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α)) ∧
            Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α) ∣ Polynomial.map (algebraMap F E) f) }
K K' : IntermediateField F E
heq : Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α) = Polynomial.map (algebraMap (↥K') E) (minpoly (↥K') α)
⊢ K = K'

Next tactic:
apply_fun fun f : E[X] ↦ adjoin F (f.frange : Set E) at heq
theorem finite_intermediateField_of_exists_primitive_element (halg : Algebra.IsAlgebraic F E)
    (h : ∃ α : E, F⟮α⟯ = ⊤) : Finite (IntermediateField F E) := by
  haveI := finiteDimensional_of_exists_primitive_element F E halg h
  obtain ⟨α, hprim⟩ := h
  -- Let `f` be the minimal polynomial of `α ∈ E` over `F`
  let f : F[X] := minpoly F α
  let G := { g : E[X] // g.Monic ∧ g ∣ f.map (algebraMap F E) }
  -- Then `f` has only finitely many monic factors
  have hfin : Finite G := @Finite.of_fintype _ <| fintypeSubtypeMonicDvd
    (f.map (algebraMap F E)) <| map_ne_zero (minpoly.ne_zero_of_finite F α)
  -- If `K` is an intermediate field of `E/F`, let `g` be the minimal polynomial of `α` over `K`
  -- which is a monic factor of `f`
  let g : IntermediateField F E → G := fun K ↦
    ⟨(minpoly K α).map (algebraMap K E), (minpoly.monic <| .of_finite K α).map _, by
      convert Polynomial.map_dvd (algebraMap K E) (minpoly.dvd_map_of_isScalarTower F K α)
      rw [Polynomial.map_map]; rfl⟩
  -- The map `K ↦ g` is injective
  have hinj : Function.Injective g := fun K K' heq ↦ by
    rw [Subtype.mk.injEq] at heq
    apply_fun fun f : E[X] ↦ adjoin F (f.frange : Set E) at heq
    

Proof state:
F : Type u_1
E : Type u_2
inst✝² : Field F
inst✝¹ : Field E
inst✝ : Algebra F E
halg : Algebra.IsAlgebraic F E
this : FiniteDimensional F E
α : E
hprim : F⟮α⟯ = ⊤
f : F[X] := minpoly F α
G : Type u_2 := { g // Monic g ∧ g ∣ Polynomial.map (algebraMap F E) f }
hfin : Finite G
g : IntermediateField F E → G :=
  fun K =>
    { val := Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α),
      property :=
        (_ :
          Monic (Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α)) ∧
            Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α) ∣ Polynomial.map (algebraMap F E) f) }
K K' : IntermediateField F E
heq :
  adjoin F ↑(frange (Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α))) =
    adjoin F ↑(frange (Polynomial.map (algebraMap (↥K') E) (minpoly (↥K') α)))
⊢ K = K'

Next tactic:
simpa only [adjoin_minpoly_coeff_of_exists_primitive_element F hprim] using heq
theorem finite_intermediateField_of_exists_primitive_element (halg : Algebra.IsAlgebraic F E)
    (h : ∃ α : E, F⟮α⟯ = ⊤) : Finite (IntermediateField F E) := by
  haveI := finiteDimensional_of_exists_primitive_element F E halg h
  obtain ⟨α, hprim⟩ := h
  -- Let `f` be the minimal polynomial of `α ∈ E` over `F`
  let f : F[X] := minpoly F α
  let G := { g : E[X] // g.Monic ∧ g ∣ f.map (algebraMap F E) }
  -- Then `f` has only finitely many monic factors
  have hfin : Finite G := @Finite.of_fintype _ <| fintypeSubtypeMonicDvd
    (f.map (algebraMap F E)) <| map_ne_zero (minpoly.ne_zero_of_finite F α)
  -- If `K` is an intermediate field of `E/F`, let `g` be the minimal polynomial of `α` over `K`
  -- which is a monic factor of `f`
  let g : IntermediateField F E → G := fun K ↦
    ⟨(minpoly K α).map (algebraMap K E), (minpoly.monic <| .of_finite K α).map _, by
      convert Polynomial.map_dvd (algebraMap K E) (minpoly.dvd_map_of_isScalarTower F K α)
      rw [Polynomial.map_map]; rfl⟩
  -- The map `K ↦ g` is injective
  have hinj : Function.Injective g := fun K K' heq ↦ by
    rw [Subtype.mk.injEq] at heq
    apply_fun fun f : E[X] ↦ adjoin F (f.frange : Set E) at heq
    simpa only [adjoin_minpoly_coeff_of_exists_primitive_element F hprim] using heq
  -- Therefore there are only finitely many intermediate fields
  

Proof state:
case intro
F : Type u_1
E : Type u_2
inst✝² : Field F
inst✝¹ : Field E
inst✝ : Algebra F E
halg : Algebra.IsAlgebraic F E
this : FiniteDimensional F E
α : E
hprim : F⟮α⟯ = ⊤
f : F[X] := minpoly F α
G : Type u_2 := { g // Monic g ∧ g ∣ Polynomial.map (algebraMap F E) f }
hfin : Finite G
g : IntermediateField F E → G :=
  fun K =>
    { val := Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α),
      property :=
        (_ :
          Monic (Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α)) ∧
            Polynomial.map (algebraMap (↥K) E) (minpoly (↥K) α) ∣ Polynomial.map (algebraMap F E) f) }
hinj : Function.Injective g
⊢ Finite (IntermediateField F E)

Next tactic:
exact Finite.of_injective g hinj
@[simp]
theorem AlgHom.card (K : Type*) [Field K] [IsAlgClosed K] [Algebra F K] :
    Fintype.card (E →ₐ[F] K) = finrank F E := by
  

Proof state:
F : Type u_1
E : Type u_2
inst✝⁷ : Field F
inst✝⁶ : Field E
inst✝⁵ : Algebra F E
inst✝⁴ : FiniteDimensional F E
inst✝³ : IsSeparable F E
K : Type u_3
inst✝² : Field K
inst✝¹ : IsAlgClosed K
inst✝ : Algebra F K
⊢ Fintype.card (E →ₐ[F] K) = finrank F E

Next tactic:
convert (AlgHom.card_of_powerBasis (L := K) (Field.powerBasisOfFiniteOfSeparable F E)
    (IsSeparable.separable _ _) (IsAlgClosed.splits_codomain _)).trans (PowerBasis.finrank _).symm
@[simp]
theorem AlgHom.card_of_splits (L : Type*) [Field L] [Algebra F L]
    (hL : ∀ x : E, (minpoly F x).Splits (algebraMap F L)) :
    Fintype.card (E →ₐ[F] L) = finrank F E := by
  

Proof state:
F : Type u_1
E : Type u_2
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
L : Type u_3
inst✝¹ : Field L
inst✝ : Algebra F L
hL : ∀ (x : E), Splits (algebraMap F L) (minpoly F x)
⊢ Fintype.card (E →ₐ[F] L) = finrank F E

Next tactic:
rw [← Fintype.ofEquiv_card <| Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits
    (AlgebraicClosure L) (Algebra.IsAlgebraic.of_finite F E) _ hL]
@[simp]
theorem AlgHom.card_of_splits (L : Type*) [Field L] [Algebra F L]
    (hL : ∀ x : E, (minpoly F x).Splits (algebraMap F L)) :
    Fintype.card (E →ₐ[F] L) = finrank F E := by
  rw [← Fintype.ofEquiv_card <| Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits
    (AlgebraicClosure L) (Algebra.IsAlgebraic.of_finite F E) _ hL]
  

Proof state:
F : Type u_1
E : Type u_2
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
L : Type u_3
inst✝¹ : Field L
inst✝ : Algebra F L
hL : ∀ (x : E), Splits (algebraMap F L) (minpoly F x)
⊢ Fintype.card (E →ₐ[F] AlgebraicClosure L) = finrank F E

Next tactic:
convert AlgHom.card F E (AlgebraicClosure L)
theorem primitive_element_iff_minpoly_natDegree_eq (α : E) :
    F⟮α⟯ = ⊤ ↔ (minpoly F α).natDegree = finrank F E := by
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝⁸ : Field F✝
inst✝⁷ : Field E✝
inst✝⁶ : Algebra F✝ E✝
inst✝⁵ : FiniteDimensional F✝ E✝
inst✝⁴ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝³ : Field F
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : FiniteDimensional F E
α : E
⊢ F⟮α⟯ = ⊤ ↔ natDegree (minpoly F α) = finrank F E

Next tactic:
rw [← adjoin.finrank (IsIntegral.of_finite F α), ← finrank_top F E]
theorem primitive_element_iff_minpoly_natDegree_eq (α : E) :
    F⟮α⟯ = ⊤ ↔ (minpoly F α).natDegree = finrank F E := by
  rw [← adjoin.finrank (IsIntegral.of_finite F α), ← finrank_top F E]
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝⁸ : Field F✝
inst✝⁷ : Field E✝
inst✝⁶ : Algebra F✝ E✝
inst✝⁵ : FiniteDimensional F✝ E✝
inst✝⁴ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝³ : Field F
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : FiniteDimensional F E
α : E
⊢ F⟮α⟯ = ⊤ ↔ finrank F ↥F⟮α⟯ = finrank F ↥⊤

Next tactic:
refine ⟨fun h => ?_, fun h => eq_of_le_of_finrank_eq le_top h⟩
theorem primitive_element_iff_minpoly_natDegree_eq (α : E) :
    F⟮α⟯ = ⊤ ↔ (minpoly F α).natDegree = finrank F E := by
  rw [← adjoin.finrank (IsIntegral.of_finite F α), ← finrank_top F E]
  refine ⟨fun h => ?_, fun h => eq_of_le_of_finrank_eq le_top h⟩
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝⁸ : Field F✝
inst✝⁷ : Field E✝
inst✝⁶ : Algebra F✝ E✝
inst✝⁵ : FiniteDimensional F✝ E✝
inst✝⁴ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝³ : Field F
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : FiniteDimensional F E
α : E
h : F⟮α⟯ = ⊤
⊢ finrank F ↥F⟮α⟯ = finrank F ↥⊤

Next tactic:
exact congr_arg (fun K : IntermediateField F E => finrank F K) h
theorem primitive_element_iff_minpoly_degree_eq (α : E) :
    F⟮α⟯ = ⊤ ↔ (minpoly F α).degree = finrank F E := by
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝⁸ : Field F✝
inst✝⁷ : Field E✝
inst✝⁶ : Algebra F✝ E✝
inst✝⁵ : FiniteDimensional F✝ E✝
inst✝⁴ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝³ : Field F
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : FiniteDimensional F E
α : E
⊢ F⟮α⟯ = ⊤ ↔ degree (minpoly F α) = ↑(finrank F E)

Next tactic:
rw [degree_eq_iff_natDegree_eq, primitive_element_iff_minpoly_natDegree_eq]
theorem primitive_element_iff_minpoly_degree_eq (α : E) :
    F⟮α⟯ = ⊤ ↔ (minpoly F α).degree = finrank F E := by
  rw [degree_eq_iff_natDegree_eq, primitive_element_iff_minpoly_natDegree_eq]
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝⁸ : Field F✝
inst✝⁷ : Field E✝
inst✝⁶ : Algebra F✝ E✝
inst✝⁵ : FiniteDimensional F✝ E✝
inst✝⁴ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝³ : Field F
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : FiniteDimensional F E
α : E
⊢ minpoly F α ≠ 0

Next tactic:
exact minpoly.ne_zero_of_finite F α
theorem primitive_element_iff_algHom_eq_of_eval' (α : E) :
    F⟮α⟯ = ⊤ ↔ Function.Injective fun φ : E →ₐ[F] A ↦ φ α := by
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
⊢ F⟮α⟯ = ⊤ ↔ Function.Injective fun φ => φ α

Next tactic:
classical
  simp_rw [primitive_element_iff_minpoly_natDegree_eq, ← card_rootSet_eq_natDegree (K := A)
    (IsSeparable.separable F α) (hA _), ← toFinset_card,
    ← (Algebra.IsAlgebraic.of_finite F E).range_eval_eq_rootSet_minpoly_of_splits _ hA α,
    ← AlgHom.card_of_splits F E A hA, Fintype.card, toFinset_range, Finset.card_image_iff,
    Finset.coe_univ, ← injective_iff_injOn_univ]
theorem primitive_element_iff_algHom_eq_of_eval' (α : E) :
    F⟮α⟯ = ⊤ ↔ Function.Injective fun φ : E →ₐ[F] A ↦ φ α := by
  classical
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
⊢ F⟮α⟯ = ⊤ ↔ Function.Injective fun φ => φ α

Next tactic:
simp_rw [primitive_element_iff_minpoly_natDegree_eq, ← card_rootSet_eq_natDegree (K := A)
    (IsSeparable.separable F α) (hA _), ← toFinset_card,
    ← (Algebra.IsAlgebraic.of_finite F E).range_eval_eq_rootSet_minpoly_of_splits _ hA α,
    ← AlgHom.card_of_splits F E A hA, Fintype.card, toFinset_range, Finset.card_image_iff,
    Finset.coe_univ, ← injective_iff_injOn_univ]
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
⊢ F⟮α⟯ = ⊤ ↔ ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ

Next tactic:
refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
h : ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ
⊢ finrank (↥F⟮α⟯) E = finrank (↥⊤) E

Next tactic:
letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
  letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
h : ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ
this : Algebra (↥F⟮α⟯) A := RingHom.toAlgebra ↑(AlgHom.comp φ (val F⟮α⟯))
⊢ finrank (↥F⟮α⟯) E = finrank (↥⊤) E

Next tactic:
haveI := isSeparable_tower_top_of_isSeparable F F⟮α⟯ E
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
  letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra
  haveI := isSeparable_tower_top_of_isSeparable F F⟮α⟯ E
  

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
h : ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ
this✝ : Algebra (↥F⟮α⟯) A := RingHom.toAlgebra ↑(AlgHom.comp φ (val F⟮α⟯))
this : IsSeparable (↥F⟮α⟯) E
⊢ finrank (↥F⟮α⟯) E = finrank (↥⊤) E

Next tactic:
rw [IntermediateField.finrank_top, ← AlgHom.card_of_splits _ _ A, Fintype.card_eq_one_iff]
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
  letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra
  haveI := isSeparable_tower_top_of_isSeparable F F⟮α⟯ E
  rw [IntermediateField.finrank_top, ← AlgHom.card_of_splits _ _ A, Fintype.card_eq_one_iff]
  · 

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
h : ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ
this✝ : Algebra (↥F⟮α⟯) A := RingHom.toAlgebra ↑(AlgHom.comp φ (val F⟮α⟯))
this : IsSeparable (↥F⟮α⟯) E
⊢ ∃ x, ∀ (y : E →ₐ[↥F⟮α⟯] A), y = x

Next tactic:
exact ⟨{ __ := φ, commutes' := fun _ ↦ rfl }, fun ψ ↦ AlgHom.restrictScalars_injective F <|
      Eq.symm <| h _ (ψ.commutes <| AdjoinSimple.gen F α).symm⟩
theorem primitive_element_iff_algHom_eq_of_eval (α : E)
    (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by
  refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ,
    fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩
  letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra
  haveI := isSeparable_tower_top_of_isSeparable F F⟮α⟯ E
  rw [IntermediateField.finrank_top, ← AlgHom.card_of_splits _ _ A, Fintype.card_eq_one_iff]
  · exact ⟨{ __ := φ, commutes' := fun _ ↦ rfl }, fun ψ ↦ AlgHom.restrictScalars_injective F <|
      Eq.symm <| h _ (ψ.commutes <| AdjoinSimple.gen F α).symm⟩
  · 

Proof state:
F✝ : Type u_1
E✝ : Type u_2
inst✝¹¹ : Field F✝
inst✝¹⁰ : Field E✝
inst✝⁹ : Algebra F✝ E✝
inst✝⁸ : FiniteDimensional F✝ E✝
inst✝⁷ : IsSeparable F✝ E✝
F : Type u_3
E : Type u_4
inst✝⁶ : Field F
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : FiniteDimensional F E
inst✝² : IsSeparable F E
A : Type u_5
inst✝¹ : Field A
inst✝ : Algebra F A
hA : ∀ (x : E), Splits (algebraMap F A) (minpoly F x)
α : E
φ : E →ₐ[F] A
h : ∀ (ψ : E →ₐ[F] A), φ α = ψ α → φ = ψ
this✝ : Algebra (↥F⟮α⟯) A := RingHom.toAlgebra ↑(AlgHom.comp φ (val F⟮α⟯))
this : IsSeparable (↥F⟮α⟯) E
⊢ ∀ (x : E), Splits (algebraMap (↥F⟮α⟯) A) (minpoly (↥F⟮α⟯) x)

Next tactic:
exact fun x ↦ (IsIntegral.of_finite F x).minpoly_splits_tower_top (hA x)
/-- A choice of limit cone for a functor `F : J ⥤ TopCat`.
Generally you should just use `limit.cone F`, unless you need the actual definition
(which is in terms of `Types.limitCone`).
-/
def limitCone (F : J ⥤ TopCatMax.{v, u}) : Cone F where
  pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j }
  π :=
    { app := fun j =>
        { toFun := fun u => u.val j
          -- Porting note: `continuity` from the original mathlib3 proof failed here.
          continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) }
      naturality := fun X Y f => by
        -- Automation fails in various ways in this proof. Why?!
        

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ TopCatMax
X Y : J
f : X ⟶ Y
⊢ ((Functor.const J).obj (of ↑{u | ∀ {i j : J} (f : i ⟶ j), (F.map f) (u i) = u j})).map f ≫
      (fun j => ContinuousMap.mk fun u => ↑u j) Y =
    (fun j => ContinuousMap.mk fun u => ↑u j) X ≫ F.map f

Next tactic:
dsimp
/-- A choice of limit cone for a functor `F : J ⥤ TopCat`.
Generally you should just use `limit.cone F`, unless you need the actual definition
(which is in terms of `Types.limitCone`).
-/
def limitCone (F : J ⥤ TopCatMax.{v, u}) : Cone F where
  pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j }
  π :=
    { app := fun j =>
        { toFun := fun u => u.val j
          -- Porting note: `continuity` from the original mathlib3 proof failed here.
          continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) }
      naturality := fun X Y f => by
        -- Automation fails in various ways in this proof. Why?!
        dsimp
        

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ TopCatMax
X Y : J
f : X ⟶ Y
⊢ (𝟙 (of { x // ∀ {i j : J} (f : i ⟶ j), (F.map f) (x i) = x j }) ≫ ContinuousMap.mk fun u => ↑u Y) =
    (ContinuousMap.mk fun u => ↑u X) ≫ F.map f

Next tactic:
rw [Category.id_comp]
/-- A choice of limit cone for a functor `F : J ⥤ TopCat`.
Generally you should just use `limit.cone F`, unless you need the actual definition
(which is in terms of `Types.limitCone`).
-/
def limitCone (F : J ⥤ TopCatMax.{v, u}) : Cone F where
  pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j }
  π :=
    { app := fun j =>
        { toFun := fun u => u.val j
          -- Porting note: `continuity` from the original mathlib3 proof failed here.
          continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) }
      naturality := fun X Y f => by
        -- Automation fails in various ways in this proof. Why?!
        dsimp
        rw [Category.id_comp]
        

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ TopCatMax
X Y : J
f : X ⟶ Y
⊢ (ContinuousMap.mk fun u => ↑u Y) = (ContinuousMap.mk fun u => ↑u X) ≫ F.map f

Next tactic:
apply ContinuousMap.ext
/-- A choice of limit cone for a functor `F : J ⥤ TopCat`.
Generally you should just use `limit.cone F`, unless you need the actual definition
(which is in terms of `Types.limitCone`).
-/
def limitCone (F : J ⥤ TopCatMax.{v, u}) : Cone F where
  pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j }
  π :=
    { app := fun j =>
        { toFun := fun u => u.val j
          -- Porting note: `continuity` from the original mathlib3 proof failed here.
          continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) }
      naturality := fun X Y f => by
        -- Automation fails in various ways in this proof. Why?!
        dsimp
        rw [Category.id_comp]
        apply ContinuousMap.ext
        

Proof state:
case h
J : Type v
inst✝ : SmallCategory J
F : J ⥤ TopCatMax
X Y : J
f : X ⟶ Y
⊢ ∀ (a : { x // ∀ {i j : J} (f : i ⟶ j), (F.map f) (x i) = x j }),
    (ContinuousMap.mk fun u => ↑u Y) a = ((ContinuousMap.mk fun u => ↑u X) ≫ F.map f) a

Next tactic:
intro a
/-- A choice of limit cone for a functor `F : J ⥤ TopCat`.
Generally you should just use `limit.cone F`, unless you need the actual definition
(which is in terms of `Types.limitCone`).
-/
def limitCone (F : J ⥤ TopCatMax.{v, u}) : Cone F where
  pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j }
  π :=
    { app := fun j =>
        { toFun := fun u => u.val j
          -- Porting note: `continuity` from the original mathlib3 proof failed here.
          continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) }
      naturality := fun X Y f => by
        -- Automation fails in various ways in this proof. Why?!
        dsimp
        rw [Category.id_comp]
        apply ContinuousMap.ext
        intro a
        

Proof state:
case h
J : Type v
inst✝ : SmallCategory J
F : J ⥤ TopCatMax
X Y : J
f : X ⟶ Y
a : { x // ∀ {i j : J} (f : i ⟶ j), (F.map f) (x i) = x j }
⊢ (ContinuousMap.mk fun u => ↑u Y) a = ((ContinuousMap.mk fun u => ↑u X) ≫ F.map f) a

Next tactic:
exact (a.2 f).symm