field_theory.normalMathlib.FieldTheory.Normal

This file has been ported!

Changes since the initial port

The following section lists changes to this file in mathlib3 and mathlib4 that occured after the initial port. Most recent changes are shown first. Hovering over a commit will show all commits associated with the same mathlib3 commit.

Changes in mathlib3

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(last sync)

refactor(field_theory/splitting_field/is_splitting_field): use root_set (#19179)

Co-authored-by: Eric Rodriguez <ericrboidi@gmail.com>

Diff
@@ -138,9 +138,8 @@ local attribute [-instance] adjoin_root.has_smul
 lemma normal.of_is_splitting_field (p : F[X]) [hFEp : is_splitting_field F E p] : normal F E :=
 begin
   unfreezingI { rcases eq_or_ne p 0 with rfl | hp },
-  { have := hFEp.adjoin_roots,
-    simp only [polynomial.map_zero, roots_zero, multiset.to_finset_zero, finset.coe_empty,
-      algebra.adjoin_empty] at this,
+  { have := hFEp.adjoin_root_set,
+    simp only [root_set_zero, algebra.adjoin_empty] at this,
     exact normal.of_alg_equiv (alg_equiv.of_bijective (algebra.of_id F E)
       (algebra.bijective_algebra_map_iff.2 this.symm)) },
   refine normal_iff.2 (λ x, _),
@@ -197,7 +196,7 @@ begin
   dsimp only [S],
   rw [←finset.image_to_finset, finset.coe_image],
   apply eq.trans (algebra.adjoin_res_eq_adjoin_res F E C D
-    hFEp.adjoin_roots adjoin_root.adjoin_root_eq_top),
+    hFEp.adjoin_root_set adjoin_root.adjoin_root_eq_top),
   rw [set.image_singleton, ring_hom.algebra_map_to_algebra, adjoin_root.lift_root]
 end
 

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(first ported)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -121,7 +121,7 @@ variable (E : Type _) [Field E] [Algebra F E] [Algebra K E] [IsScalarTower F K E
 theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
   normal_iff.2 fun x => by
     cases' h.out x with hx hhx
-    rw [algebra_map_eq F K E] at hhx 
+    rw [algebra_map_eq F K E] at hhx
     exact
       ⟨IsIntegral.tower_top hx,
         Polynomial.splits_of_splits_of_dvd (algebraMap K E)
@@ -159,7 +159,7 @@ theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :
   normal_iff.2 fun x => by
     cases' h.out (f.symm x) with hx hhx
     have H := IsIntegral.map f.to_alg_hom hx
-    rw [AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_algHom, AlgEquiv.apply_symm_apply] at H 
+    rw [AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_algHom, AlgEquiv.apply_symm_apply] at H
     use H
     apply Polynomial.splits_of_splits_of_dvd (algebraMap F E') (minpoly.ne_zero hx)
     · rw [← AlgHom.comp_algebraMap f.to_alg_hom]
@@ -191,7 +191,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   by
   rcases eq_or_ne p 0 with (rfl | hp)
   · have := hFEp.adjoin_root_set
-    simp only [root_set_zero, Algebra.adjoin_empty] at this 
+    simp only [root_set_zero, Algebra.adjoin_empty] at this
     exact
       Normal.of_algEquiv
         (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
@@ -203,7 +203,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   let D := AdjoinRoot q
   haveI := Fact.mk q_irred
   let pbED := AdjoinRoot.powerBasis q_irred.ne_zero
-  haveI : FiniteDimensional E D := PowerBasis.finiteDimensional pbED
+  haveI : FiniteDimensional E D := PowerBasis.finite pbED
   have finrankED : FiniteDimensional.finrank E D = q.nat_degree := by
     rw [PowerBasis.finrank pbED, AdjoinRoot.powerBasis_dim]
   haveI : FiniteDimensional F D := FiniteDimensional.trans F E D
@@ -251,7 +251,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
       (Algebra.adjoin E {AdjoinRoot.root q}).restrictScalars F
     by
     rw [AdjoinRoot.adjoinRoot_eq_top, Subalgebra.restrictScalars_top, ←
-      @Subalgebra.restrictScalars_top F C] at this 
+      @Subalgebra.restrictScalars_top F C] at this
     exact top_le_iff.mpr (Subalgebra.restrictScalars_injective F this)
   dsimp only [S]
   rw [← Finset.image_toFinset, Finset.coe_image]
@@ -286,7 +286,7 @@ instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i
     rw [adjoin_le_iff, ← image_root_set ((h i.1).Splits i.2) (t i.1).val]
     exact fun _ ⟨a, _, h⟩ => h ▸ a.2
   have := hF.splits ⟨x, hx⟩
-  rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this 
+  rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
 #align intermediate_field.normal_supr IntermediateField.normal_iSup
 -/
@@ -561,7 +561,7 @@ theorem normalClosure_eq_iSup_adjoin [h : Normal F L] :
       minpoly.ne_zero
         ((isIntegral_algebraMap_iff (algebraMap K L).Injective).mp
           (h.is_integral (algebraMap K L x)))
-  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy 
+  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy
     let g :=
       (alg_hom_adjoin_integral_equiv F
             ((isIntegral_algebraMap_iff (algebraMap K L).Injective).mp
Diff
@@ -123,7 +123,7 @@ theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
     cases' h.out x with hx hhx
     rw [algebra_map_eq F K E] at hhx 
     exact
-      ⟨isIntegral_of_isScalarTower hx,
+      ⟨IsIntegral.tower_top hx,
         Polynomial.splits_of_splits_of_dvd (algebraMap K E)
           (Polynomial.map_ne_zero (minpoly.ne_zero hx))
           ((Polynomial.splits_map_iff (algebraMap F K) (algebraMap K E)).mpr hhx)
@@ -141,8 +141,7 @@ theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function
       minpoly.mem_range_of_degree_eq_one E x
         (h2.def.resolve_left (minpoly.ne_zero h1)
           (minpoly.irreducible
-            (isIntegral_of_isScalarTower
-              ((isIntegral_algebraMap_iff (algebraMap K E).Injective).mp h1)))
+            (IsIntegral.tower_top ((isIntegral_algebraMap_iff (algebraMap K E).Injective).mp h1)))
           (minpoly.dvd E x
             ((algebraMap K E).Injective
               (by
@@ -159,7 +158,7 @@ variable {F} {E} {E' : Type _} [Field E'] [Algebra F E']
 theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :=
   normal_iff.2 fun x => by
     cases' h.out (f.symm x) with hx hhx
-    have H := map_isIntegral f.to_alg_hom hx
+    have H := IsIntegral.map f.to_alg_hom hx
     rw [AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_algHom, AlgEquiv.apply_symm_apply] at H 
     use H
     apply Polynomial.splits_of_splits_of_dvd (algebraMap F E') (minpoly.ne_zero hx)
@@ -327,8 +326,8 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
         Or.resolve_left (h.splits z).def (minpoly.ne_zero (h.is_integral z)) (minpoly.irreducible _)
           (minpoly.dvd E _ (by simp [aeval_alg_hom_apply]))
       simp only [AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom]
-      suffices IsIntegral F _ by exact isIntegral_of_isScalarTower this
-      exact map_isIntegral ϕ (map_isIntegral (to_alg_hom F E K₁) (h.is_integral z))⟩
+      suffices IsIntegral F _ by exact IsIntegral.tower_top this
+      exact IsIntegral.map ϕ (IsIntegral.map (to_alg_hom F E K₁) (h.is_integral z))⟩
   map_zero' := Subtype.ext ϕ.map_zero
   map_one' := Subtype.ext ϕ.map_one
   map_add' x y := Subtype.ext (ϕ.map_add x y)
@@ -451,7 +450,7 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
       @IntermediateField.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
         ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
         (IntermediateField.adjoin_univ _ _) fun x hx =>
-        ⟨isIntegral_of_isScalarTower (h.out x).1,
+        ⟨IsIntegral.tower_top (h.out x).1,
           splits_of_splits_of_dvd _ (map_ne_zero (minpoly.ne_zero (h.out x).1))
             (by rw [splits_map_iff, ← IsScalarTower.algebraMap_eq]; exact (h.out x).2)
             (minpoly.dvd_map_of_isScalarTower F K₁ x)⟩
@@ -547,8 +546,8 @@ noncomputable def normalClosure : IntermediateField K L :=
 
 namespace normalClosure
 
-#print normalClosure.restrictScalars_eq_iSup_adjoin /-
-theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
+#print normalClosure_eq_iSup_adjoin /-
+theorem normalClosure_eq_iSup_adjoin [h : Normal F L] :
     (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) :=
   by
   refine' le_antisymm (iSup_le _) (iSup_le fun x => adjoin_le_iff.mpr fun y hy => _)
@@ -574,7 +573,7 @@ theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
         ⟨x, (g.lift_normal_commutes L (adjoin_simple.gen F x)).trans _⟩
     rw [Algebra.id.map_eq_id, RingHom.id_apply]
     apply PowerBasis.lift_gen
-#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
+#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure_eq_iSup_adjoin
 -/
 
 #print normalClosure.normal /-
Diff
@@ -232,7 +232,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   let S : Set D := ((p.map (algebraMap F E)).roots.map (algebraMap E D)).toFinset
   suffices ⊤ ≤ IntermediateField.adjoin C S
     by
-    refine' IntermediateField.algHom_mk_adjoin_splits' (top_le_iff.mp this) fun y hy => _
+    refine' IntermediateField.nonempty_algHom_of_adjoin_splits (top_le_iff.mp this) fun y hy => _
     rcases multiset.mem_map.mp (multiset.mem_to_finset.mp hy) with ⟨z, hz1, hz2⟩
     have Hz : IsIntegral F z := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) z
     use show IsIntegral C y from
@@ -448,7 +448,7 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
   @AlgHom.restrictScalars F K₁ E E _ _ _ _ _ _
       ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _ _ _ _ <|
     Nonempty.some <|
-      @IntermediateField.algHom_mk_adjoin_splits' _ _ _ _ _ _ _
+      @IntermediateField.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
         ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
         (IntermediateField.adjoin_univ _ _) fun x hx =>
         ⟨isIntegral_of_isScalarTower (h.out x).1,
Diff
@@ -377,8 +377,7 @@ theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f
   haveI : IsScalarTower F E E := by infer_instance
   let g := f.restrict_normal' E
   rw [← show E.val.comp ↑g = f from fun_like.ext_iff.mpr (f.restrict_normal_commutes E), ←
-    IntermediateField.AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map,
-    E.field_range_val]
+    AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map, E.field_range_val]
 #align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
 -/
 
Diff
@@ -3,10 +3,10 @@ Copyright (c) 2020 Kenny Lau. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 -/
-import Mathbin.FieldTheory.Adjoin
-import Mathbin.FieldTheory.Tower
-import Mathbin.GroupTheory.Solvable
-import Mathbin.RingTheory.PowerBasis
+import FieldTheory.Adjoin
+import FieldTheory.Tower
+import GroupTheory.Solvable
+import RingTheory.PowerBasis
 
 #align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
 
Diff
@@ -603,11 +603,9 @@ instance is_finiteDimensional [FiniteDimensional F K] : FiniteDimensional F (nor
 #align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
 -/
 
-#print normalClosure.isScalarTower /-
 instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
   IsScalarTower.subalgebra' F L L _
 #align normal_closure.is_scalar_tower normalClosure.isScalarTower
--/
 
 end normalClosure
 
Diff
@@ -332,7 +332,7 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
   map_zero' := Subtype.ext ϕ.map_zero
   map_one' := Subtype.ext ϕ.map_one
   map_add' x y := Subtype.ext (ϕ.map_add x y)
-  map_mul' x y := Subtype.ext (ϕ.map_mul x y)
+  map_mul' x y := Subtype.ext (ϕ.map_hMul x y)
   commutes' x := Subtype.ext (ϕ.commutes x)
 #align alg_hom.restrict_normal_aux AlgHom.restrictNormalAux
 -/
Diff
@@ -235,8 +235,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
     refine' IntermediateField.algHom_mk_adjoin_splits' (top_le_iff.mp this) fun y hy => _
     rcases multiset.mem_map.mp (multiset.mem_to_finset.mp hy) with ⟨z, hz1, hz2⟩
     have Hz : IsIntegral F z := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) z
-    use
-      show IsIntegral C y from
+    use show IsIntegral C y from
         isIntegral_of_noetherian (IsNoetherian.iff_fg.2 (FiniteDimensional.right F C D)) y
     apply splits_of_splits_of_dvd (algebraMap C E) (map_ne_zero (minpoly.ne_zero Hz))
     · rw [splits_map_iff, ← algebra_map_eq F C E]
Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2020 Kenny Lau. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
-
-! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit 9fb8964792b4237dac6200193a0d533f1b3f7423
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.FieldTheory.Adjoin
 import Mathbin.FieldTheory.Tower
 import Mathbin.GroupTheory.Solvable
 import Mathbin.RingTheory.PowerBasis
 
+#align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
+
 /-!
 # Normal field extensions
 
Diff
@@ -50,26 +50,36 @@ class Normal : Prop where
 
 variable {F K}
 
+#print Normal.isAlgebraic /-
 theorem Normal.isAlgebraic (h : Normal F K) (x : K) : IsAlgebraic F x :=
   Normal.is_algebraic' x
 #align normal.is_algebraic Normal.isAlgebraic
+-/
 
+#print Normal.isIntegral /-
 theorem Normal.isIntegral (h : Normal F K) (x : K) : IsIntegral F x :=
   isAlgebraic_iff_isIntegral.mp (h.IsAlgebraic x)
 #align normal.is_integral Normal.isIntegral
+-/
 
+#print Normal.splits /-
 theorem Normal.splits (h : Normal F K) (x : K) : Splits (algebraMap F K) (minpoly F x) :=
   Normal.splits' x
 #align normal.splits Normal.splits
+-/
 
+#print normal_iff /-
 theorem normal_iff : Normal F K ↔ ∀ x : K, IsIntegral F x ∧ Splits (algebraMap F K) (minpoly F x) :=
   ⟨fun h x => ⟨h.IsIntegral x, h.Splits x⟩, fun h =>
     ⟨fun x => (h x).1.IsAlgebraic F, fun x => (h x).2⟩⟩
 #align normal_iff normal_iff
+-/
 
+#print Normal.out /-
 theorem Normal.out : Normal F K → ∀ x : K, IsIntegral F x ∧ Splits (algebraMap F K) (minpoly F x) :=
   normal_iff.1
 #align normal.out Normal.out
+-/
 
 variable (F K)
 
@@ -84,6 +94,7 @@ variable {K}
 
 variable (K)
 
+#print Normal.exists_isSplittingField /-
 theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K] :
     ∃ p : F[X], IsSplittingField F K p :=
   by
@@ -103,11 +114,13 @@ theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K]
   rw [is_root.def, eval_map, ← aeval_def, AlgHom.map_prod]
   exact Finset.prod_eq_zero (Finset.mem_univ _) (minpoly.aeval _ _)
 #align normal.exists_is_splitting_field Normal.exists_isSplittingField
+-/
 
 section NormalTower
 
 variable (E : Type _) [Field E] [Algebra F E] [Algebra K E] [IsScalarTower F K E]
 
+#print Normal.tower_top_of_normal /-
 theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
   normal_iff.2 fun x => by
     cases' h.out x with hx hhx
@@ -119,7 +132,9 @@ theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
           ((Polynomial.splits_map_iff (algebraMap F K) (algebraMap K E)).mpr hhx)
           (minpoly.dvd_map_of_isScalarTower F K x)⟩
 #align normal.tower_top_of_normal Normal.tower_top_of_normal
+-/
 
+#print AlgHom.normal_bijective /-
 theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function.Bijective ϕ :=
   ⟨ϕ.toRingHom.Injective, fun x =>
     by
@@ -139,9 +154,11 @@ theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function
       y hy
     exact ⟨y, hy⟩⟩
 #align alg_hom.normal_bijective AlgHom.normal_bijective
+-/
 
 variable {F} {E} {E' : Type _} [Field E'] [Algebra F E']
 
+#print Normal.of_algEquiv /-
 theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :=
   normal_iff.2 fun x => by
     cases' h.out (f.symm x) with hx hhx
@@ -157,10 +174,13 @@ theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :
         Eq.trans (Polynomial.aeval_algHom_apply f.symm.to_alg_hom x (minpoly F (f.symm x))).symm
           (minpoly.aeval _ _)
 #align normal.of_alg_equiv Normal.of_algEquiv
+-/
 
+#print AlgEquiv.transfer_normal /-
 theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F E' :=
   ⟨fun h => Normal.of_algEquiv f, fun h => Normal.of_algEquiv f.symm⟩
 #align alg_equiv.transfer_normal AlgEquiv.transfer_normal
+-/
 
 -- seems to be causing a diamond in the below proof
 -- however, this may be a fluke and the proof below uses non-canonical `algebra` instances:
@@ -170,6 +190,7 @@ theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F
 -- salient in the future, or at least taking a closer look at the algebra instances it uses.
 attribute [-instance] AdjoinRoot.hasSmul
 
+#print Normal.of_isSplittingField /-
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E :=
   by
   rcases eq_or_ne p 0 with (rfl | hp)
@@ -244,11 +265,13 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
       (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_root_set AdjoinRoot.adjoinRoot_eq_top)
   rw [Set.image_singleton, RingHom.algebraMap_toAlgebra, AdjoinRoot.lift_root]
 #align normal.of_is_splitting_field Normal.of_isSplittingField
+-/
 
 end NormalTower
 
 namespace IntermediateField
 
+#print IntermediateField.normal_iSup /-
 /-- A compositum of normal extensions is normal -/
 instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] :
     Normal F (⨆ i, t i : IntermediateField F K) :=
@@ -271,14 +294,17 @@ instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i
   rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this 
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
 #align intermediate_field.normal_supr IntermediateField.normal_iSup
+-/
 
 variable {F K} {L : Type _} [Field L] [Algebra F L] [Algebra K L] [IsScalarTower F K L]
 
+#print IntermediateField.restrictScalars_normal /-
 @[simp]
 theorem restrictScalars_normal {E : IntermediateField K L} :
     Normal F (E.restrictScalars F) ↔ Normal F E :=
   Iff.rfl
 #align intermediate_field.restrict_scalars_normal IntermediateField.restrictScalars_normal
+-/
 
 end IntermediateField
 
@@ -290,6 +316,7 @@ section Restrict
 variable (E : Type _) [Field E] [Algebra F E] [Algebra E K₁] [Algebra E K₂] [Algebra E K₃]
   [IsScalarTower F E K₁] [IsScalarTower F E K₂] [IsScalarTower F E K₃]
 
+#print AlgHom.restrictNormalAux /-
 /-- Restrict algebra homomorphism to image of normal subfield -/
 def AlgHom.restrictNormalAux [h : Normal F E] :
     (toAlgHom F E K₁).range →ₐ[F] (toAlgHom F E K₂).range
@@ -312,19 +339,25 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
   map_mul' x y := Subtype.ext (ϕ.map_mul x y)
   commutes' x := Subtype.ext (ϕ.commutes x)
 #align alg_hom.restrict_normal_aux AlgHom.restrictNormalAux
+-/
 
+#print AlgHom.restrictNormal /-
 /-- Restrict algebra homomorphism to normal subfield -/
 def AlgHom.restrictNormal [Normal F E] : E →ₐ[F] E :=
   ((AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F E K₂)).symm.toAlgHom.comp
         (ϕ.restrictNormalAux E)).comp
     (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F E K₁)).toAlgHom
 #align alg_hom.restrict_normal AlgHom.restrictNormal
+-/
 
+#print AlgHom.restrictNormal' /-
 /-- Restrict algebra homomorphism to normal subfield (`alg_equiv` version) -/
 def AlgHom.restrictNormal' [Normal F E] : E ≃ₐ[F] E :=
   AlgEquiv.ofBijective (AlgHom.restrictNormal ϕ E) (AlgHom.normal_bijective F E E _)
 #align alg_hom.restrict_normal' AlgHom.restrictNormal'
+-/
 
+#print AlgHom.restrictNormal_commutes /-
 @[simp]
 theorem AlgHom.restrictNormal_commutes [Normal F E] (x : E) :
     algebraMap E K₂ (ϕ.restrictNormal E x) = ϕ (algebraMap E K₁ x) :=
@@ -332,13 +365,17 @@ theorem AlgHom.restrictNormal_commutes [Normal F E] (x : E) :
     (AlgEquiv.apply_symm_apply (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F E K₂))
       (ϕ.restrictNormalAux E ⟨IsScalarTower.toAlgHom F E K₁ x, x, rfl⟩))
 #align alg_hom.restrict_normal_commutes AlgHom.restrictNormal_commutes
+-/
 
+#print AlgHom.restrictNormal_comp /-
 theorem AlgHom.restrictNormal_comp [Normal F E] :
     (ψ.restrictNormal E).comp (ϕ.restrictNormal E) = (ψ.comp ϕ).restrictNormal E :=
   AlgHom.ext fun _ =>
     (algebraMap E K₃).Injective (by simp only [AlgHom.comp_apply, AlgHom.restrictNormal_commutes])
 #align alg_hom.restrict_normal_comp AlgHom.restrictNormal_comp
+-/
 
+#print AlgHom.fieldRange_of_normal /-
 theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f : E →ₐ[F] K) :
     f.fieldRange = E := by
   haveI : IsScalarTower F E E := by infer_instance
@@ -347,32 +384,42 @@ theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f
     IntermediateField.AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map,
     E.field_range_val]
 #align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
+-/
 
+#print AlgEquiv.restrictNormal /-
 /-- Restrict algebra isomorphism to a normal subfield -/
 def AlgEquiv.restrictNormal [h : Normal F E] : E ≃ₐ[F] E :=
   AlgHom.restrictNormal' χ.toAlgHom E
 #align alg_equiv.restrict_normal AlgEquiv.restrictNormal
+-/
 
+#print AlgEquiv.restrictNormal_commutes /-
 @[simp]
 theorem AlgEquiv.restrictNormal_commutes [Normal F E] (x : E) :
     algebraMap E K₂ (χ.restrictNormal E x) = χ (algebraMap E K₁ x) :=
   χ.toAlgHom.restrictNormal_commutes E x
 #align alg_equiv.restrict_normal_commutes AlgEquiv.restrictNormal_commutes
+-/
 
+#print AlgEquiv.restrictNormal_trans /-
 theorem AlgEquiv.restrictNormal_trans [Normal F E] :
     (χ.trans ω).restrictNormal E = (χ.restrictNormal E).trans (ω.restrictNormal E) :=
   AlgEquiv.ext fun _ =>
     (algebraMap E K₃).Injective
       (by simp only [AlgEquiv.trans_apply, AlgEquiv.restrictNormal_commutes])
 #align alg_equiv.restrict_normal_trans AlgEquiv.restrictNormal_trans
+-/
 
+#print AlgEquiv.restrictNormalHom /-
 /-- Restriction to an normal subfield as a group homomorphism -/
 def AlgEquiv.restrictNormalHom [Normal F E] : (K₁ ≃ₐ[F] K₁) →* E ≃ₐ[F] E :=
   MonoidHom.mk' (fun χ => χ.restrictNormal E) fun ω χ => χ.restrictNormal_trans ω E
 #align alg_equiv.restrict_normal_hom AlgEquiv.restrictNormalHom
+-/
 
 variable (F K₁ E)
 
+#print Normal.algHomEquivAut /-
 /-- If `K₁/E/F` is a tower of fields with `E/F` normal then `normal.alg_hom_equiv_aut` is an
  equivalence. -/
 @[simps]
@@ -390,6 +437,7 @@ def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E
     rw [AlgHom.restrictNormal_commutes]
     simp
 #align normal.alg_hom_equiv_aut Normal.algHomEquivAut
+-/
 
 end Restrict
 
@@ -398,6 +446,7 @@ section lift
 variable {F} {K₁ K₂} (E : Type _) [Field E] [Algebra F E] [Algebra K₁ E] [Algebra K₂ E]
   [IsScalarTower F K₁ E] [IsScalarTower F K₂ E]
 
+#print AlgHom.liftNormal /-
 /-- If `E/Kᵢ/F` are towers of fields with `E/F` normal then we can lift
   an algebra homomorphism `ϕ : K₁ →ₐ[F] K₂` to `ϕ.lift_normal E : E →ₐ[F] E`. -/
 noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
@@ -412,13 +461,17 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
             (by rw [splits_map_iff, ← IsScalarTower.algebraMap_eq]; exact (h.out x).2)
             (minpoly.dvd_map_of_isScalarTower F K₁ x)⟩
 #align alg_hom.lift_normal AlgHom.liftNormal
+-/
 
+#print AlgHom.liftNormal_commutes /-
 @[simp]
 theorem AlgHom.liftNormal_commutes [Normal F E] (x : K₁) :
     ϕ.liftNormal E (algebraMap K₁ E x) = algebraMap K₂ E (ϕ x) := by
   apply @AlgHom.commutes K₁ E E _ _ _ _
 #align alg_hom.lift_normal_commutes AlgHom.liftNormal_commutes
+-/
 
+#print AlgHom.restrict_liftNormal /-
 @[simp]
 theorem AlgHom.restrict_liftNormal (ϕ : K₁ →ₐ[F] K₁) [Normal F K₁] [Normal F E] :
     (ϕ.liftNormal E).restrictNormal K₁ = ϕ :=
@@ -426,19 +479,25 @@ theorem AlgHom.restrict_liftNormal (ϕ : K₁ →ₐ[F] K₁) [Normal F K₁] [N
     (algebraMap K₁ E).Injective
       (Eq.trans (AlgHom.restrictNormal_commutes _ K₁ x) (ϕ.liftNormal_commutes E x))
 #align alg_hom.restrict_lift_normal AlgHom.restrict_liftNormal
+-/
 
+#print AlgEquiv.liftNormal /-
 /-- If `E/Kᵢ/F` are towers of fields with `E/F` normal then we can lift
   an algebra isomorphism `ϕ : K₁ ≃ₐ[F] K₂` to `ϕ.lift_normal E : E ≃ₐ[F] E`. -/
 noncomputable def AlgEquiv.liftNormal [Normal F E] : E ≃ₐ[F] E :=
   AlgEquiv.ofBijective (χ.toAlgHom.liftNormal E) (AlgHom.normal_bijective F E E _)
 #align alg_equiv.lift_normal AlgEquiv.liftNormal
+-/
 
+#print AlgEquiv.liftNormal_commutes /-
 @[simp]
 theorem AlgEquiv.liftNormal_commutes [Normal F E] (x : K₁) :
     χ.liftNormal E (algebraMap K₁ E x) = algebraMap K₂ E (χ x) :=
   χ.toAlgHom.liftNormal_commutes E x
 #align alg_equiv.lift_normal_commutes AlgEquiv.liftNormal_commutes
+-/
 
+#print AlgEquiv.restrict_liftNormal /-
 @[simp]
 theorem AlgEquiv.restrict_liftNormal (χ : K₁ ≃ₐ[F] K₁) [Normal F K₁] [Normal F E] :
     (χ.liftNormal E).restrictNormal K₁ = χ :=
@@ -446,14 +505,18 @@ theorem AlgEquiv.restrict_liftNormal (χ : K₁ ≃ₐ[F] K₁) [Normal F K₁]
     (algebraMap K₁ E).Injective
       (Eq.trans (AlgEquiv.restrictNormal_commutes _ K₁ x) (χ.liftNormal_commutes E x))
 #align alg_equiv.restrict_lift_normal AlgEquiv.restrict_liftNormal
+-/
 
+#print AlgEquiv.restrictNormalHom_surjective /-
 theorem AlgEquiv.restrictNormalHom_surjective [Normal F K₁] [Normal F E] :
     Function.Surjective (AlgEquiv.restrictNormalHom K₁ : (E ≃ₐ[F] E) → K₁ ≃ₐ[F] K₁) := fun χ =>
   ⟨χ.liftNormal E, χ.restrict_liftNormal E⟩
 #align alg_equiv.restrict_normal_hom_surjective AlgEquiv.restrictNormalHom_surjective
+-/
 
 variable (F) (K₁) (E)
 
+#print isSolvable_of_isScalarTower /-
 theorem isSolvable_of_isScalarTower [Normal F K₁] [h1 : IsSolvable (K₁ ≃ₐ[F] K₁)]
     [h2 : IsSolvable (E ≃ₐ[K₁] E)] : IsSolvable (E ≃ₐ[F] E) :=
   by
@@ -468,6 +531,7 @@ theorem isSolvable_of_isScalarTower [Normal F K₁] [h1 : IsSolvable (K₁ ≃
       ⟨{ ϕ with commutes' := fun x => _ }, AlgEquiv.ext fun _ => rfl⟩
   exact Eq.trans (ϕ.restrict_normal_commutes K₁ x).symm (congr_arg _ (alg_equiv.ext_iff.mp hϕ x))
 #align is_solvable_of_is_scalar_tower isSolvable_of_isScalarTower
+-/
 
 end lift
 
@@ -477,15 +541,18 @@ open IntermediateField
 
 variable (F K) (L : Type _) [Field L] [Algebra F L] [Algebra K L] [IsScalarTower F K L]
 
+#print normalClosure /-
 /-- The normal closure of `K` in `L`. -/
 noncomputable def normalClosure : IntermediateField K L :=
   { (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield with
     algebraMap_mem' := fun r =>
       le_iSup (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
 #align normal_closure normalClosure
+-/
 
 namespace normalClosure
 
+#print normalClosure.restrictScalars_eq_iSup_adjoin /-
 theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) :=
   by
@@ -513,7 +580,9 @@ theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     rw [Algebra.id.map_eq_id, RingHom.id_apply]
     apply PowerBasis.lift_gen
 #align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
+-/
 
+#print normalClosure.normal /-
 instance normal [h : Normal F L] : Normal F (normalClosure F K L) :=
   by
   let ϕ := algebraMap K L
@@ -527,17 +596,22 @@ instance normal [h : Normal F L] : Normal F (normalClosure F K L) :=
             ((isIntegral_algebraMap_iff ϕ.injective).mp (h.is_integral (ϕ x))) rfl).symm ▸
         h.splits _)
 #align normal_closure.normal normalClosure.normal
+-/
 
+#print normalClosure.is_finiteDimensional /-
 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.to_linear_map.finite_dimensional_range
   apply IntermediateField.finiteDimensional_iSup_of_finite
 #align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
+-/
 
+#print normalClosure.isScalarTower /-
 instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
   IsScalarTower.subalgebra' F L L _
 #align normal_closure.is_scalar_tower normalClosure.isScalarTower
+-/
 
 end normalClosure
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit fd4551cfe4b7484b81c2c9ba3405edae27659676
+! leanprover-community/mathlib commit 9fb8964792b4237dac6200193a0d533f1b3f7423
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -173,9 +173,8 @@ attribute [-instance] AdjoinRoot.hasSmul
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E :=
   by
   rcases eq_or_ne p 0 with (rfl | hp)
-  · have := hFEp.adjoin_roots
-    simp only [Polynomial.map_zero, roots_zero, Multiset.toFinset_zero, Finset.coe_empty,
-      Algebra.adjoin_empty] at this 
+  · have := hFEp.adjoin_root_set
+    simp only [root_set_zero, Algebra.adjoin_empty] at this 
     exact
       Normal.of_algEquiv
         (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
@@ -242,7 +241,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   rw [← Finset.image_toFinset, Finset.coe_image]
   apply
     Eq.trans
-      (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_roots AdjoinRoot.adjoinRoot_eq_top)
+      (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_root_set AdjoinRoot.adjoinRoot_eq_top)
   rw [Set.image_singleton, RingHom.algebraMap_toAlgebra, AdjoinRoot.lift_root]
 #align normal.of_is_splitting_field Normal.of_isSplittingField
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit df76f43357840485b9d04ed5dee5ab115d420e87
+! leanprover-community/mathlib commit fd4551cfe4b7484b81c2c9ba3405edae27659676
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -16,6 +16,9 @@ import Mathbin.RingTheory.PowerBasis
 /-!
 # Normal field extensions
 
+> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
+> Any changes to this file require a corresponding PR to mathlib4.
+
 In this file we define normal field extensions and prove that for a finite extension, being normal
 is the same as being a splitting field (`normal.of_is_splitting_field` and
 `normal.exists_is_splitting_field`).
Diff
@@ -36,12 +36,14 @@ open Polynomial IsScalarTower
 
 variable (F K : Type _) [Field F] [Field K] [Algebra F K]
 
+#print Normal /-
 /-- Typeclass for normal field extension: `K` is a normal extension of `F` iff the minimal
 polynomial of every element `x` in `K` splits in `K`, i.e. every conjugate of `x` is in `K`. -/
 class Normal : Prop where
   is_algebraic' : Algebra.IsAlgebraic F K
   splits' (x : K) : Splits (algebraMap F K) (minpoly F x)
 #align normal Normal
+-/
 
 variable {F K}
 
@@ -68,10 +70,12 @@ theorem Normal.out : Normal F K → ∀ x : K, IsIntegral F x ∧ Splits (algebr
 
 variable (F K)
 
+#print normal_self /-
 instance normal_self : Normal F F :=
   ⟨fun x => isIntegral_algebraMap.IsAlgebraic F, fun x =>
     (minpoly.eq_X_sub_C' x).symm ▸ splits_X_sub_C _⟩
 #align normal_self normal_self
+-/
 
 variable {K}
 
Diff
@@ -338,7 +338,8 @@ theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f
   haveI : IsScalarTower F E E := by infer_instance
   let g := f.restrict_normal' E
   rw [← show E.val.comp ↑g = f from fun_like.ext_iff.mpr (f.restrict_normal_commutes E), ←
-    AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map, E.field_range_val]
+    IntermediateField.AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map,
+    E.field_range_val]
 #align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
 
 /-- Restrict algebra isomorphism to a normal subfield -/
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit 949dc57e616a621462062668c9f39e4e17b64b69
+! leanprover-community/mathlib commit df76f43357840485b9d04ed5dee5ab115d420e87
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -166,11 +166,12 @@ attribute [-instance] AdjoinRoot.hasSmul
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E :=
   by
   rcases eq_or_ne p 0 with (rfl | hp)
-  · haveI : is_splitting_field F F 0 := ⟨splits_zero _, Subsingleton.elim _ _⟩
+  · have := hFEp.adjoin_roots
+    simp only [Polynomial.map_zero, roots_zero, Multiset.toFinset_zero, Finset.coe_empty,
+      Algebra.adjoin_empty] at this 
     exact
-      (AlgEquiv.transfer_normal
-            ((is_splitting_field.alg_equiv F 0).trans (is_splitting_field.alg_equiv E 0).symm)).mp
-        (normal_self F)
+      Normal.of_algEquiv
+        (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
   refine' normal_iff.2 fun x => _
   have hFE : FiniteDimensional F E := is_splitting_field.finite_dimensional E p
   have Hx : IsIntegral F x := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) x
@@ -238,9 +239,6 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   rw [Set.image_singleton, RingHom.algebraMap_toAlgebra, AdjoinRoot.lift_root]
 #align normal.of_is_splitting_field Normal.of_isSplittingField
 
-instance (p : F[X]) : Normal F p.SplittingField :=
-  Normal.of_isSplittingField p
-
 end NormalTower
 
 namespace IntermediateField
Diff
@@ -104,7 +104,7 @@ variable (E : Type _) [Field E] [Algebra F E] [Algebra K E] [IsScalarTower F K E
 theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
   normal_iff.2 fun x => by
     cases' h.out x with hx hhx
-    rw [algebra_map_eq F K E] at hhx
+    rw [algebra_map_eq F K E] at hhx 
     exact
       ⟨isIntegral_of_isScalarTower hx,
         Polynomial.splits_of_splits_of_dvd (algebraMap K E)
@@ -139,7 +139,7 @@ theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :
   normal_iff.2 fun x => by
     cases' h.out (f.symm x) with hx hhx
     have H := map_isIntegral f.to_alg_hom hx
-    rw [AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_algHom, AlgEquiv.apply_symm_apply] at H
+    rw [AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_algHom, AlgEquiv.apply_symm_apply] at H 
     use H
     apply Polynomial.splits_of_splits_of_dvd (algebraMap F E') (minpoly.ne_zero hx)
     · rw [← AlgHom.comp_algebraMap f.to_alg_hom]
@@ -228,7 +228,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
       (Algebra.adjoin E {AdjoinRoot.root q}).restrictScalars F
     by
     rw [AdjoinRoot.adjoinRoot_eq_top, Subalgebra.restrictScalars_top, ←
-      @Subalgebra.restrictScalars_top F C] at this
+      @Subalgebra.restrictScalars_top F C] at this 
     exact top_le_iff.mpr (Subalgebra.restrictScalars_injective F this)
   dsimp only [S]
   rw [← Finset.image_toFinset, Finset.coe_image]
@@ -264,7 +264,7 @@ instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i
     rw [adjoin_le_iff, ← image_root_set ((h i.1).Splits i.2) (t i.1).val]
     exact fun _ ⟨a, _, h⟩ => h ▸ a.2
   have := hF.splits ⟨x, hx⟩
-  rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this
+  rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this 
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
 #align intermediate_field.normal_supr IntermediateField.normal_iSup
 
@@ -495,7 +495,7 @@ theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
       minpoly.ne_zero
         ((isIntegral_algebraMap_iff (algebraMap K L).Injective).mp
           (h.is_integral (algebraMap K L x)))
-  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy
+  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy 
     let g :=
       (alg_hom_adjoin_integral_equiv F
             ((isIntegral_algebraMap_iff (algebraMap K L).Injective).mp
Diff
@@ -28,9 +28,9 @@ is the same as being a splitting field (`normal.of_is_splitting_field` and
 
 noncomputable section
 
-open BigOperators
+open scoped BigOperators
 
-open Classical Polynomial
+open scoped Classical Polynomial
 
 open Polynomial IsScalarTower
 
Diff
@@ -185,9 +185,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   haveI : FiniteDimensional F D := FiniteDimensional.trans F E D
   rsuffices ⟨ϕ⟩ : Nonempty (D →ₐ[F] E)
   · rw [← WithBot.coe_one, degree_eq_iff_nat_degree_eq q_irred.ne_zero, ← finrankED]
-    have nat_lemma : ∀ a b c : ℕ, a * b = c → c ≤ a → 0 < c → b = 1 :=
-      by
-      intro a b c h1 h2 h3
+    have nat_lemma : ∀ a b c : ℕ, a * b = c → c ≤ a → 0 < c → b = 1 := by intro a b c h1 h2 h3;
       nlinarith
     exact
       nat_lemma _ _ _ (FiniteDimensional.finrank_mul_finrank F E D)
@@ -406,9 +404,7 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
         (IntermediateField.adjoin_univ _ _) fun x hx =>
         ⟨isIntegral_of_isScalarTower (h.out x).1,
           splits_of_splits_of_dvd _ (map_ne_zero (minpoly.ne_zero (h.out x).1))
-            (by
-              rw [splits_map_iff, ← IsScalarTower.algebraMap_eq]
-              exact (h.out x).2)
+            (by rw [splits_map_iff, ← IsScalarTower.algebraMap_eq]; exact (h.out x).2)
             (minpoly.dvd_map_of_isScalarTower F K₁ x)⟩
 #align alg_hom.lift_normal AlgHom.liftNormal
 
Diff
@@ -70,7 +70,7 @@ variable (F K)
 
 instance normal_self : Normal F F :=
   ⟨fun x => isIntegral_algebraMap.IsAlgebraic F, fun x =>
-    (minpoly.eq_x_sub_C' x).symm ▸ splits_X_sub_C _⟩
+    (minpoly.eq_X_sub_C' x).symm ▸ splits_X_sub_C _⟩
 #align normal_self normal_self
 
 variable {K}
Diff
@@ -248,7 +248,7 @@ end NormalTower
 namespace IntermediateField
 
 /-- A compositum of normal extensions is normal -/
-instance normal_supᵢ {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] :
+instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] :
     Normal F (⨆ i, t i : IntermediateField F K) :=
   by
   refine' ⟨is_algebraic_supr fun i => (h i).1, fun x => _⟩
@@ -262,13 +262,13 @@ instance normal_supᵢ {ι : Type _} (t : ι → IntermediateField F K) [h : ∀
     · exact Polynomial.splits_comp_of_splits _ (algebraMap (t i.1) K) ((h i.1).Splits i.2)
   have hE : E ≤ ⨆ i, t i :=
     by
-    refine' supᵢ_le fun i => supᵢ_le fun hi => le_supᵢ_of_le i.1 _
+    refine' iSup_le fun i => iSup_le fun hi => le_iSup_of_le i.1 _
     rw [adjoin_le_iff, ← image_root_set ((h i.1).Splits i.2) (t i.1).val]
     exact fun _ ⟨a, _, h⟩ => h ▸ a.2
   have := hF.splits ⟨x, hx⟩
   rw [minpoly_eq, Subtype.coe_mk, ← minpoly_eq] at this
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
-#align intermediate_field.normal_supr IntermediateField.normal_supᵢ
+#align intermediate_field.normal_supr IntermediateField.normal_iSup
 
 variable {F K} {L : Type _} [Field L] [Algebra F L] [Algebra K L] [IsScalarTower F K L]
 
@@ -480,18 +480,18 @@ variable (F K) (L : Type _) [Field L] [Algebra F L] [Algebra K L] [IsScalarTower
 noncomputable def normalClosure : IntermediateField K L :=
   { (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield with
     algebraMap_mem' := fun r =>
-      le_supᵢ (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
+      le_iSup (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
 #align normal_closure normalClosure
 
 namespace normalClosure
 
-theorem restrictScalars_eq_supᵢ_adjoin [h : Normal F L] :
+theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) :=
   by
-  refine' le_antisymm (supᵢ_le _) (supᵢ_le fun x => adjoin_le_iff.mpr fun y hy => _)
+  refine' le_antisymm (iSup_le _) (iSup_le fun x => adjoin_le_iff.mpr fun y hy => _)
   · rintro f _ ⟨x, rfl⟩
     refine'
-      le_supᵢ (fun x => adjoin F ((minpoly F x).rootSet L)) x
+      le_iSup (fun x => adjoin F ((minpoly F x).rootSet L)) x
         (subset_adjoin F ((minpoly F x).rootSet L) _)
     rw [mem_root_set_of_ne, AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom,
       Polynomial.aeval_algHom_apply, minpoly.aeval, map_zero]
@@ -506,18 +506,18 @@ theorem restrictScalars_eq_supᵢ_adjoin [h : Normal F L] :
               (h.is_integral (algebraMap K L x)))).symm
         ⟨y, hy⟩
     refine'
-      le_supᵢ (fun f : K →ₐ[F] L => f.fieldRange)
+      le_iSup (fun f : K →ₐ[F] L => f.fieldRange)
         ((g.lift_normal L).comp (IsScalarTower.toAlgHom F K L))
         ⟨x, (g.lift_normal_commutes L (adjoin_simple.gen F x)).trans _⟩
     rw [Algebra.id.map_eq_id, RingHom.id_apply]
     apply PowerBasis.lift_gen
-#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_supᵢ_adjoin
+#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
 
 instance normal [h : Normal F L] : Normal F (normalClosure F K L) :=
   by
   let ϕ := algebraMap K L
   rw [← IntermediateField.restrictScalars_normal, restrict_scalars_eq_supr_adjoin]
-  apply IntermediateField.normal_supᵢ F L _
+  apply IntermediateField.normal_iSup F L _
   intro x
   apply Normal.of_isSplittingField (minpoly F x)
   exact
@@ -531,7 +531,7 @@ instance is_finiteDimensional [FiniteDimensional F K] : FiniteDimensional F (nor
   by
   haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f =>
     f.to_linear_map.finite_dimensional_range
-  apply IntermediateField.finiteDimensional_supᵢ_of_finite
+  apply IntermediateField.finiteDimensional_iSup_of_finite
 #align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
 
 instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit d4437c68c8d350fc9d4e95e1e174409db35e30d7
+! leanprover-community/mathlib commit 949dc57e616a621462062668c9f39e4e17b64b69
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -155,18 +155,24 @@ theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F
   ⟨fun h => Normal.of_algEquiv f, fun h => Normal.of_algEquiv f.symm⟩
 #align alg_equiv.transfer_normal AlgEquiv.transfer_normal
 
+-- seems to be causing a diamond in the below proof
+-- however, this may be a fluke and the proof below uses non-canonical `algebra` instances:
+-- when I replaced all the instances inside the proof with the "canonical" instances we have,
+-- I had the (unprovable) goal (of the form) `adjoin_root.mk f (C x) = adjoin_root.mk f X`
+-- for some `x, f`. So maybe this is indeed the correct approach and rewriting this proof is
+-- salient in the future, or at least taking a closer look at the algebra instances it uses.
+attribute [-instance] AdjoinRoot.hasSmul
+
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E :=
   by
-  by_cases hp : p = 0
-  · have : is_splitting_field F F p := by
-      rw [hp]
-      exact ⟨splits_zero _, Subsingleton.elim _ _⟩
+  rcases eq_or_ne p 0 with (rfl | hp)
+  · haveI : is_splitting_field F F 0 := ⟨splits_zero _, Subsingleton.elim _ _⟩
     exact
       (AlgEquiv.transfer_normal
-            ((is_splitting_field.alg_equiv F p).trans (is_splitting_field.alg_equiv E p).symm)).mp
+            ((is_splitting_field.alg_equiv F 0).trans (is_splitting_field.alg_equiv E 0).symm)).mp
         (normal_self F)
   refine' normal_iff.2 fun x => _
-  haveI hFE : FiniteDimensional F E := is_splitting_field.finite_dimensional E p
+  have hFE : FiniteDimensional F E := is_splitting_field.finite_dimensional E p
   have Hx : IsIntegral F x := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) x
   refine' ⟨Hx, Or.inr _⟩
   rintro q q_irred ⟨r, hr⟩
@@ -174,13 +180,11 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   haveI := Fact.mk q_irred
   let pbED := AdjoinRoot.powerBasis q_irred.ne_zero
   haveI : FiniteDimensional E D := PowerBasis.finiteDimensional pbED
-  have finrankED : FiniteDimensional.finrank E D = q.nat_degree := PowerBasis.finrank pbED
-  letI : Algebra F D := RingHom.toAlgebra ((algebraMap E D).comp (algebraMap F E))
-  haveI : IsScalarTower F E D := of_algebra_map_eq fun _ => rfl
+  have finrankED : FiniteDimensional.finrank E D = q.nat_degree := by
+    rw [PowerBasis.finrank pbED, AdjoinRoot.powerBasis_dim]
   haveI : FiniteDimensional F D := FiniteDimensional.trans F E D
-  suffices Nonempty (D →ₐ[F] E) by
-    cases' this with ϕ
-    rw [← WithBot.coe_one, degree_eq_iff_nat_degree_eq q_irred.ne_zero, ← finrankED]
+  rsuffices ⟨ϕ⟩ : Nonempty (D →ₐ[F] E)
+  · rw [← WithBot.coe_one, degree_eq_iff_nat_degree_eq q_irred.ne_zero, ← finrankED]
     have nat_lemma : ∀ a b c : ℕ, a * b = c → c ≤ a → 0 < c → b = 1 :=
       by
       intro a b c h1 h2 h3
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit 00f91228655eecdcd3ac97a7fd8dbcb139fe990a
+! leanprover-community/mathlib commit d4437c68c8d350fc9d4e95e1e174409db35e30d7
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -333,6 +333,14 @@ theorem AlgHom.restrictNormal_comp [Normal F E] :
     (algebraMap E K₃).Injective (by simp only [AlgHom.comp_apply, AlgHom.restrictNormal_commutes])
 #align alg_hom.restrict_normal_comp AlgHom.restrictNormal_comp
 
+theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f : E →ₐ[F] K) :
+    f.fieldRange = E := by
+  haveI : IsScalarTower F E E := by infer_instance
+  let g := f.restrict_normal' E
+  rw [← show E.val.comp ↑g = f from fun_like.ext_iff.mpr (f.restrict_normal_commutes E), ←
+    AlgHom.map_fieldRange, g.field_range_eq_top, ← E.val.field_range_eq_map, E.field_range_val]
+#align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
+
 /-- Restrict algebra isomorphism to a normal subfield -/
 def AlgEquiv.restrictNormal [h : Normal F E] : E ≃ₐ[F] E :=
   AlgHom.restrictNormal' χ.toAlgHom E
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit 3d32bf9cef95940e3fe1ca0dd2412e0f21579f46
+! leanprover-community/mathlib commit 00f91228655eecdcd3ac97a7fd8dbcb139fe990a
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -522,6 +522,10 @@ instance is_finiteDimensional [FiniteDimensional F K] : FiniteDimensional F (nor
   apply IntermediateField.finiteDimensional_supᵢ_of_finite
 #align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
 
+instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
+  IsScalarTower.subalgebra' F L L _
+#align normal_closure.is_scalar_tower normalClosure.isScalarTower
+
 end normalClosure
 
 end normalClosure
Diff
@@ -70,7 +70,7 @@ variable (F K)
 
 instance normal_self : Normal F F :=
   ⟨fun x => isIntegral_algebraMap.IsAlgebraic F, fun x =>
-    (minpoly.eq_x_sub_C' x).symm ▸ splits_x_sub_c _⟩
+    (minpoly.eq_x_sub_C' x).symm ▸ splits_X_sub_C _⟩
 #align normal_self normal_self
 
 variable {K}
Diff
@@ -197,7 +197,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
       (AdjoinRoot.lift (algebraMap F D) (AdjoinRoot.root q)
         (by
           rw [algebra_map_eq F E D, ← eval₂_map, hr, AdjoinRoot.algebraMap_eq, eval₂_mul,
-            AdjoinRoot.eval₂_root, zero_mul]))
+            AdjoinRoot.eval₂_root, MulZeroClass.zero_mul]))
   letI : Algebra C E := RingHom.toAlgebra (AdjoinRoot.lift (algebraMap F E) x (minpoly.aeval F x))
   haveI : IsScalarTower F C D := of_algebra_map_eq fun x => (AdjoinRoot.lift_of _).symm
   haveI : IsScalarTower F C E := of_algebra_map_eq fun x => (AdjoinRoot.lift_of _).symm

Changes in mathlib4

mathlib3
mathlib4
chore: speed up a proof in FieldTheory/NormalClosure (#12199)

Speed up a proof which will otherwise timeout on nightly-testing.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -213,11 +213,11 @@ noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic
       · 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
+  let φ' := (φ.comp <| inclusion <| normalClosure_le_iSup_adjoin alg)
+  { toFun := φ'.comp ∘ (normalClosure.algHomEquiv F K L').symm
     inj' := fun _ _ h ↦ (normalClosure.algHomEquiv F K L').symm.injective <| by
       rw [DFunLike.ext'_iff] at h ⊢
-      exact (φ.comp _).injective.comp_left h }
+      exact φ'.injective.comp_left h }
 
 namespace IntermediateField
 
chore: rename IsRoot.definition back to IsRoot.def (#11999)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -83,7 +83,7 @@ theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K]
               mt (Polynomial.map_eq_zero <| algebraMap F K).1 <|
                 Finset.prod_ne_zero_iff.2 fun x _ => _).2 _)
   · exact minpoly.ne_zero (h.isIntegral (s x))
-  rw [IsRoot.definition, eval_map, ← aeval_def, AlgHom.map_prod]
+  rw [IsRoot.def, eval_map, ← aeval_def, AlgHom.map_prod]
   exact Finset.prod_eq_zero (Finset.mem_univ _) (minpoly.aeval _ _)
 #align normal.exists_is_splitting_field Normal.exists_isSplittingField
 
@@ -229,7 +229,7 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
       rw [← hx, ← hy]
       apply minpoly.mem_range_of_degree_eq_one E
       refine'
-        Or.resolve_left (h.splits z).def' (minpoly.ne_zero (h.isIntegral z)) (minpoly.irreducible _)
+        Or.resolve_left (h.splits z).def (minpoly.ne_zero (h.isIntegral z)) (minpoly.irreducible _)
           (minpoly.dvd E _ (by simp [aeval_algHom_apply]))
       simp only [AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom]
       suffices IsIntegral F _ by exact this.tower_top
style: replace '.-/' by '. -/' (#11938)

Purely automatic replacement. If this is in any way controversial; I'm happy to just close this PR.

Diff
@@ -82,7 +82,7 @@ lemma normalClosure_eq_iSup_adjoin_of_splits :
       le_iSup AlgHom.fieldRange φ ⟨x, hφ⟩
 
 /-- If `K/F` is algebraic, the "generated by roots" condition in IsNormalClosure can be replaced
-  by "generated by images of embeddings".-/
+  by "generated by images of embeddings". -/
 lemma isNormalClosure_iff : IsNormalClosure F K L ↔
     (∀ x : K, (minpoly F x).Splits (algebraMap F L)) ∧ normalClosure F K L = ⊤ := by
   refine ⟨fun ⟨splits, h⟩ ↦ ⟨splits, ?_⟩, fun ⟨splits, h⟩ ↦ ⟨splits, ?_⟩⟩ <;>
style: remove redundant instance arguments (#11581)

I removed some redundant instance arguments throughout Mathlib. To do this, I used VS Code's regex search. See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/repeating.20instances.20from.20variable.20command I closed the previous PR for this and reopened it.

Diff
@@ -148,7 +148,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
     exact ⟨hp, minpoly.ne_zero hx⟩
 #align normal.of_is_splitting_field Normal.of_isSplittingField
 
-instance Polynomial.SplittingField.instNormal [Field F] (p : F[X]) : Normal F p.SplittingField :=
+instance Polynomial.SplittingField.instNormal (p : F[X]) : Normal F p.SplittingField :=
   Normal.of_isSplittingField p
 #align polynomial.splitting_field.normal Polynomial.SplittingField.instNormal
 
chore: rename away from 'def' (#11548)

This will become an error in 2024-03-16 nightly, possibly not permanently.

Co-authored-by: Scott Morrison <scott@tqft.net>

Diff
@@ -83,7 +83,7 @@ theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K]
               mt (Polynomial.map_eq_zero <| algebraMap F K).1 <|
                 Finset.prod_ne_zero_iff.2 fun x _ => _).2 _)
   · exact minpoly.ne_zero (h.isIntegral (s x))
-  rw [IsRoot.def, eval_map, ← aeval_def, AlgHom.map_prod]
+  rw [IsRoot.definition, eval_map, ← aeval_def, AlgHom.map_prod]
   exact Finset.prod_eq_zero (Finset.mem_univ _) (minpoly.aeval _ _)
 #align normal.exists_is_splitting_field Normal.exists_isSplittingField
 
@@ -229,7 +229,7 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
       rw [← hx, ← hy]
       apply minpoly.mem_range_of_degree_eq_one E
       refine'
-        Or.resolve_left (h.splits z).def (minpoly.ne_zero (h.isIntegral z)) (minpoly.irreducible _)
+        Or.resolve_left (h.splits z).def' (minpoly.ne_zero (h.isIntegral z)) (minpoly.irreducible _)
           (minpoly.dvd E _ (by simp [aeval_algHom_apply]))
       simp only [AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom]
       suffices IsIntegral F _ by exact this.tower_top
chore(*): rename FunLike to DFunLike (#9785)

This prepares for the introduction of a non-dependent synonym of FunLike, which helps a lot with keeping #8386 readable.

This is entirely search-and-replace in 680197f combined with manual fixes in 4145626, e900597 and b8428f8. The commands that generated this change:

sed -i 's/\bFunLike\b/DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoFunLike\b/toDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/import Mathlib.Data.DFunLike/import Mathlib.Data.FunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bHom_FunLike\b/Hom_DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean     
sed -i 's/\binstFunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bfunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoo many metavariables to apply `fun_like.has_coe_to_fun`/too many metavariables to apply `DFunLike.hasCoeToFun`/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean

Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com>

Diff
@@ -216,7 +216,7 @@ noncomputable def Algebra.IsAlgebraic.algHomEmbeddingOfSplits (alg : IsAlgebraic
   { 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 ⊢
+      rw [DFunLike.ext'_iff] at h ⊢
       exact (φ.comp _).injective.comp_left h }
 
 namespace IntermediateField
chore(*): rename FunLike to DFunLike (#9785)

This prepares for the introduction of a non-dependent synonym of FunLike, which helps a lot with keeping #8386 readable.

This is entirely search-and-replace in 680197f combined with manual fixes in 4145626, e900597 and b8428f8. The commands that generated this change:

sed -i 's/\bFunLike\b/DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoFunLike\b/toDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/import Mathlib.Data.DFunLike/import Mathlib.Data.FunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bHom_FunLike\b/Hom_DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean     
sed -i 's/\binstFunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bfunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoo many metavariables to apply `fun_like.has_coe_to_fun`/too many metavariables to apply `DFunLike.hasCoeToFun`/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean

Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com>

Diff
@@ -273,7 +273,7 @@ theorem AlgHom.fieldRange_of_normal [Algebra F K] {E : IntermediateField F K} [N
 -- Porting note: this was `IsScalarTower F E E := by infer_instance`.
   letI : Algebra E E := Algebra.id E
   let g := f.restrictNormal' E
-  rw [← show E.val.comp ↑g = f from FunLike.ext_iff.mpr (f.restrictNormal_commutes E),
+  rw [← show E.val.comp ↑g = f from DFunLike.ext_iff.mpr (f.restrictNormal_commutes E),
     ← AlgHom.map_fieldRange, AlgEquiv.fieldRange_eq_top g, ← AlgHom.fieldRange_eq_map,
     IntermediateField.fieldRange_val]
 #align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
chore: split IntermediateField.Lifts out of FieldTheory/Adjoin (#9647)

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -3,7 +3,7 @@ Copyright (c) 2020 Kenny Lau. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 -/
-import Mathlib.FieldTheory.Adjoin
+import Mathlib.FieldTheory.Extension
 import Mathlib.FieldTheory.SplittingField.Construction
 import Mathlib.GroupTheory.Solvable
 
chore: tidy various files (#8818)
Diff
@@ -102,7 +102,7 @@ lemma isNormalClosure_normalClosure : IsNormalClosure F K (normalClosure F K L)
   rw [IntermediateField.map_iSup]
   refine (iSup_le fun f ↦ ?_ : normalClosure F K L ≤ _) x.2
   refine le_iSup_of_le (f.codRestrict _ fun x ↦ f.fieldRange_le_normalClosure ⟨x, rfl⟩) ?_
-  erw [AlgHom.map_fieldRange, AlgHom.val_comp_codRestrict]
+  rw [AlgHom.map_fieldRange, val, AlgHom.val_comp_codRestrict]
 
 end Algebra.IsAlgebraic
 
chore: tidy various files (#8818)
Diff
@@ -190,8 +190,7 @@ theorem splits_of_mem_adjoin {L} [Field L] [Algebra F L] {S : Set K}
     (splits x hx).2 fun y hy ↦ (le_iSup _ ⟨x, hx⟩ : _ ≤ E) (subset_adjoin F _ <| by exact hy)
   obtain ⟨φ⟩ := nonempty_algHom_adjoin_of_splits fun x hx ↦ ⟨(splits x hx).1, this x hx⟩
   convert splits_comp_of_splits _ E.val.toRingHom (normal.splits <| φ ⟨x, hx⟩)
-  rw [minpoly.algHom_eq _ φ.injective, ← minpoly.algHom_eq _ (adjoin F S).val.injective]
-  rfl
+  rw [minpoly.algHom_eq _ φ.injective, ← minpoly.algHom_eq _ (adjoin F S).val.injective, val_mk]
 
 instance normal_sup
     (E E' : IntermediateField F K) [Normal F E] [Normal F E'] :
feat: IsNormalClosure predicate (#8418)

Main changes are to the file NormalClosure:

  • Introduce predicate IsNormalClosure to characterize normal closures L/F of a field extension K/F by the conditions that every minimal polynomial of an element of K over F splits in L, and that L is generated by roots of such polynomials. (When K/F is not necessarily algebraic, the conditions actually says L/F is a normal closure of the algebraic closure of F in K over F.

  • IsNormalClosure.normal: a normal closure is always normal.

  • isNormalClosure_iff : if K/F is algebraic, the "generated by roots" condition in IsNormalClosure can be replaced by "generated by images of embeddings". To prove it, we split out the two inclusions in restrictScalars_eq_iSup_adjoin and golf its proof. restrictScalars_eq_iSup_adjoin is renamed to normalClosure_eq_iSup_adjoin as it has nothing to do with restrictScalars.

  • IsNormalClosure.lift: a normal closure of K/F embeds into any L/F such that the minpolys of K/F splits in L/F.

  • IsNormalClosure.equiv: normal closures are unique up to F-algebra isomorphisms.

  • isNormalClosure_normalClosure: normalClosure F K L is a valid normal closure if K/F is algebraic and all minpolys of K/F splits in L/F; in particular, if there is at least one F-embedding of K into L, and L/F is normal.

  • Algebra.IsAlgebraic.cardinal_mk_algHom_le_of_splits: if every minpoly of K/F splits in L/F, then L is maximal w.r.t. F-embeddings of K, in the sense that K →ₐ[F] L achieves maximal cardinality.

In the file Normal:

  • splits_of_mem_adjoin: If a set of algebraic elements in a field extension K/F have minimal polynomials that split in another extension L/F, then all minimal polynomials in the intermediate field generated by the set also split in L/F. This is in preparation for connecting IsNormalClosure and IsSplittingField.

In the file IntermediateField:

  • Add comap and show it forms a Galois connection with map.

In the file FieldTheory/Adjoin:

  • Add map_sup/iSup lemmas that follow from the Galois connection, plus an additional convenience lemma.

In the file RingTheory/Algebraic: add a lemma AlgHom.isAlgebraic_of_injective.

Co-authored-by: Jz Pan <acme_pjz@hotmail.com>

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -10,19 +10,37 @@ import Mathlib.Order.Closure
 #align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
 /-!
 # Normal closures
-The normal closure of a tower of fields `L/K/F` is the smallest intermediate field of `L/K` that
-contains the image of every `F`-algebra embedding `K →ₐ[F] L`.
 
-## Main Definitions
-- `normalClosure F K L` a tower of fields `L/K/F`.
+## Main definitions
+
+Given field extensions `K/F` and `L/F`, the predicate `IsNormalClosure F K L` says that the
+minimal polynomial of every element of `K` over `F` splits in `L`, and that `L` is generated
+by the roots of such minimal polynomials. These conditions uniquely characterize `L/F` up to
+`F`-algebra isomorphisms (`IsNormalClosure.equiv`).
+
+The explicit construction `normalClosure F K L` of a field extension `K/F` inside another
+field extension `L/F` is the smallest intermediate field of `L/F` that contains the image
+of every `F`-algebra embedding `K →ₐ[F] L`. It satisfies the `IsNormalClosure` predicate
+if `L/F` satisfies the abovementioned splitting condition, in particular if `L/K/F` form
+a tower and `L/F` is normal.
 -/
 
 open BigOperators IntermediateField IsScalarTower Polynomial
 
-variable (F K L : Type*) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F L] [Algebra K L]
-  [IsScalarTower F K L]
+variable (F K L : Type*) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F L]
 
-/-- The normal closure of `K` in `L`. -/
+/-- `L/F` is a normal closure of `K/F` if the minimal polynomial of every element of `K` over `F`
+  splits in `L`, and `L` is generated by roots of such minimal polynomials over `F`.
+  (Since the minimal polynomial of a transcendental element is 0,
+  the normal closure of `K/F` is the same as the normal closure over `F`
+  of the algebraic closure of `F` in `K`.) -/
+class IsNormalClosure : Prop where
+  splits (x : K) : (minpoly F x).Splits (algebraMap F L)
+  adjoin_rootSet : ⨆ x : K, adjoin F ((minpoly F x).rootSet L) = ⊤
+/- TODO: show `IsNormalClosure F K L ↔ IsNormalClosure F (integralClosure F K) L`; we can't state
+  this yet because `integralClosure F K` needs to have a `Field` instance. -/
+
+/-- The normal closure of `K/F` in `L/F`. -/
 noncomputable def normalClosure : IntermediateField F L :=
   ⨆ f : K →ₐ[F] L, f.fieldRange
 
@@ -31,62 +49,135 @@ lemma normalClosure_def : normalClosure F K L = ⨆ f : K →ₐ[F] L, f.fieldRa
 
 variable {F K L}
 
+/-- A normal closure is always normal. -/
+lemma IsNormalClosure.normal [h : IsNormalClosure F K L] : Normal F L :=
+  Normal.of_algEquiv topEquiv (h := h.adjoin_rootSet ▸ IntermediateField.normal_iSup (h :=
+    fun _ ↦ Normal.of_isSplittingField (hFEp := adjoin_rootSet_isSplittingField <| h.splits _)))
+
 lemma normalClosure_le_iff {K' : IntermediateField F L} :
     normalClosure F K L ≤ K' ↔ ∀ f : K →ₐ[F] L, f.fieldRange ≤ K' :=
   iSup_le_iff
 
-lemma AlgHom.fieldRange_le_normalClosure  (f : K →ₐ[F] L) : f.fieldRange ≤ normalClosure F K L :=
+lemma AlgHom.fieldRange_le_normalClosure (f : K →ₐ[F] L) : f.fieldRange ≤ normalClosure F K L :=
   le_iSup AlgHom.fieldRange f
 
+namespace Algebra.IsAlgebraic
+variable (alg : Algebra.IsAlgebraic F K)
+
+lemma normalClosure_le_iSup_adjoin :
+    normalClosure F K L ≤ ⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L) :=
+  iSup_le fun f _ ⟨x, hx⟩ ↦ le_iSup (α := IntermediateField F L) _ x <|
+    IntermediateField.subset_adjoin F _ <| by
+      rw [mem_rootSet_of_ne (minpoly.ne_zero <| isAlgebraic_iff_isIntegral.mp <| alg x), ← hx,
+        AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom, aeval_algHom_apply, minpoly.aeval, map_zero]
+
+variable (splits : ∀ x : K, (minpoly F x).Splits (algebraMap F L))
+
+lemma normalClosure_eq_iSup_adjoin_of_splits :
+    normalClosure F K L = ⨆ x : K, IntermediateField.adjoin F ((minpoly F x).rootSet L) :=
+  (alg.normalClosure_le_iSup_adjoin).antisymm <|
+    iSup_le fun x ↦ IntermediateField.adjoin_le_iff.mpr fun _ hy ↦
+      let ⟨φ, hφ⟩ := IntermediateField.exists_algHom_of_splits_of_aeval
+        (fun x ↦ ⟨isAlgebraic_iff_isIntegral.mp (alg x), splits x⟩) (mem_rootSet.mp hy).2
+      le_iSup AlgHom.fieldRange φ ⟨x, hφ⟩
+
+/-- If `K/F` is algebraic, the "generated by roots" condition in IsNormalClosure can be replaced
+  by "generated by images of embeddings".-/
+lemma isNormalClosure_iff : IsNormalClosure F K L ↔
+    (∀ x : K, (minpoly F x).Splits (algebraMap F L)) ∧ normalClosure F K L = ⊤ := by
+  refine ⟨fun ⟨splits, h⟩ ↦ ⟨splits, ?_⟩, fun ⟨splits, h⟩ ↦ ⟨splits, ?_⟩⟩ <;>
+    simpa only [alg.normalClosure_eq_iSup_adjoin_of_splits splits] using h
+-- TODO: IntermediateField.isNormalClosure_iff similar to IntermediateField.isSplittingField_iff
+
+/-- `normalClosure F K L` is a valid normal closure if `K/F` is algebraic
+  and all minimal polynomials of `K/F` splits in `L/F`. -/
+lemma isNormalClosure_normalClosure : IsNormalClosure F K (normalClosure F K L) := by
+  rw [alg.isNormalClosure_iff]; constructor
+  · rw [alg.normalClosure_eq_iSup_adjoin_of_splits splits]
+    exact fun x ↦ splits_of_splits (splits x) ((IntermediateField.subset_adjoin F _).trans <|
+      SetLike.coe_subset_coe.mpr <| by apply le_iSup _ x)
+  simp_rw [normalClosure, ← top_le_iff]
+  refine fun x _ ↦ (IntermediateField.val _).injective.mem_set_image.mp ?_
+  change x.val ∈ IntermediateField.map (IntermediateField.val _) _
+  rw [IntermediateField.map_iSup]
+  refine (iSup_le fun f ↦ ?_ : normalClosure F K L ≤ _) x.2
+  refine le_iSup_of_le (f.codRestrict _ fun x ↦ f.fieldRange_le_normalClosure ⟨x, rfl⟩) ?_
+  erw [AlgHom.map_fieldRange, AlgHom.val_comp_codRestrict]
+
+end Algebra.IsAlgebraic
+
+/-- A normal closure of `K/F` embeds into any `L/F`
+  where the minimal polynomials of `K/F` splits. -/
+noncomputable def IsNormalClosure.lift [h : IsNormalClosure F K L] {L'} [Field L'] [Algebra F L']
+    (splits : ∀ x : K, (minpoly F x).Splits (algebraMap F L')) : L →ₐ[F] L' := by
+  have := h.adjoin_rootSet; rw [← gc.l_iSup] at this
+  refine Nonempty.some <| nonempty_algHom_of_adjoin_splits
+    (fun x hx ↦ ⟨isAlgebraic_iff_isIntegral.mp (Normal.isAlgebraic h.normal x), ?_⟩) this
+  obtain ⟨y, hx⟩ := Set.mem_iUnion.mp hx
+  by_cases iy : IsIntegral F y
+  · exact splits_of_splits_of_dvd _ (minpoly.ne_zero iy)
+      (splits y) (minpoly.dvd F x (mem_rootSet.mp hx).2)
+  · simp [minpoly.eq_zero iy] at hx
+
+/-- Normal closures of `K/F` are unique up to F-algebra isomorphisms. -/
+noncomputable def IsNormalClosure.equiv {L'} [Field L'] [Algebra F L']
+    [h : IsNormalClosure F K L] [h' : IsNormalClosure F K L'] : L ≃ₐ[F] L' :=
+  have := h.normal
+  AlgEquiv.ofBijective _ <| And.left <|
+    Normal.isAlgebraic'.algHom_bijective₂
+      (IsNormalClosure.lift fun _ : K ↦ h'.splits _)
+      (IsNormalClosure.lift fun _ : K ↦ h.splits _)
+
 variable (F K L)
 
-namespace 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
+  simp_rw [← minpoly.algHom_eq _ φ.injective]
+  exact fun _ ↦ h.splits _
 
-theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
+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
-  classical
-  have hi : ∀ x : K, IsIntegral F x :=
-    fun x ↦ (isIntegral_algebraMap_iff (algebraMap K L).injective).mp (h.isIntegral _)
-  refine' le_antisymm (iSup_le _) (iSup_le fun x => adjoin_le_iff.mpr fun y hy => _)
-  · rintro f _ ⟨x, rfl⟩
-    refine' le_iSup (fun x => adjoin F ((minpoly F x).rootSet L)) x
-        (subset_adjoin F ((minpoly F x).rootSet L) _)
-    rw [mem_rootSet_of_ne (minpoly.ne_zero (hi x)), AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom,
-      Polynomial.aeval_algHom_apply, minpoly.aeval, map_zero]
-  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy
-    let g := (algHomAdjoinIntegralEquiv F (hi x)).symm ⟨y, hy⟩
-    refine' le_iSup (fun f : K →ₐ[F] L => f.fieldRange) ((g.liftNormal L).comp (toAlgHom F K L))
-        ⟨x, (g.liftNormal_commutes L (AdjoinSimple.gen F x)).trans _⟩
-    rw [Algebra.id.map_eq_id, RingHom.id_apply]
-    -- Porting note: in mathlib3 this next `apply` closed the goal.
-    -- Now it can't find a proof by unification, so we have to do it ourselves.
-    apply PowerBasis.lift_gen
-    change aeval y (minpoly F (AdjoinSimple.gen F x)) = 0
-    exact minpoly_gen F x ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
-
-#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
+  have ⟨φ⟩ := ne
+  refine h.isAlgebraic'.of_injective φ φ.injective
+    |>.normalClosure_eq_iSup_adjoin_of_splits fun x ↦ ?_
+  rw [← minpoly.algHom_eq _ φ.injective]
+  apply h.splits
+
+theorem normalClosure_eq_iSup_adjoin [Algebra K L] [IsScalarTower F K L] [Normal F L] :
+    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) :=
+  normalClosure_eq_iSup_adjoin' (ne := ⟨IsScalarTower.toAlgHom F K L⟩)
+#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure_eq_iSup_adjoin
+
+namespace normalClosure
+
+/-- All `F`-`AlgHom`s from `K` to `L` factor through the normal closure of `K/F` in `L/F`. -/
+noncomputable def algHomEquiv : (K →ₐ[F] normalClosure F K L) ≃ (K →ₐ[F] L) where
+  toFun := (normalClosure F K L).val.comp
+  invFun f := f.codRestrict _ fun x ↦ f.fieldRange_le_normalClosure ⟨x, rfl⟩
+  left_inv _ := rfl
+  right_inv _ := rfl
 
 instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
-  let ϕ := algebraMap K L
-  rw [← IntermediateField.restrictScalars_normal, restrictScalars_eq_iSup_adjoin]
-  -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply IntermediateField.normal_iSup (h := _)
-  intro x
-  -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply Normal.of_isSplittingField (p := minpoly F x) (hFEp := _)
-  exact adjoin_rootSet_isSplittingField (minpoly.algebraMap_eq ϕ.injective (A := F) x ▸ h.splits _)
+  obtain _ | φ := isEmpty_or_nonempty (K →ₐ[F] L)
+  · rw [normalClosure, iSup_of_empty]; exact Normal.of_algEquiv (botEquiv F L).symm
+  · exact (isNormalClosure_normalClosure F K L).normal
 #align normal_closure.normal normalClosure.normal
 
 instance is_finiteDimensional [FiniteDimensional F K] :
     FiniteDimensional F (normalClosure F K L) := by
-  haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f =>
+  haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f ↦
     f.toLinearMap.finiteDimensional_range
   apply IntermediateField.finiteDimensional_iSup_of_finite
 
-noncomputable instance algebra : Algebra K (normalClosure F K L) :=
+variable [Algebra K L] [IsScalarTower F K L]
+
+noncomputable instance algebra :
+    Algebra K (normalClosure F K L) :=
   IntermediateField.algebra
     { ⨆ f : K →ₐ[F] L, f.fieldRange with
-      algebraMap_mem' := fun r => (toAlgHom F K L).fieldRange_le_normalClosure ⟨r, rfl⟩ }
+      algebraMap_mem' := fun r ↦ (toAlgHom F K L).fieldRange_le_normalClosure ⟨r, rfl⟩ }
 
 instance : IsScalarTower F K (normalClosure F K L) := by
   apply of_algebraMap_eq'
@@ -102,13 +193,38 @@ lemma restrictScalars_eq :
 
 end normalClosure
 
+variable {F K L}
+
+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 ⊢
+      exact (φ.comp _).injective.comp_left h }
+
 namespace IntermediateField
 
-variable {F L}
 variable (K K' : IntermediateField F L)
 
 lemma le_normalClosure : K ≤ normalClosure F K L :=
-K.fieldRange_val.symm.trans_le K.val.fieldRange_le_normalClosure
+  K.fieldRange_val.symm.trans_le K.val.fieldRange_le_normalClosure
 
 lemma normalClosure_of_normal [Normal F K] : normalClosure F K L = K :=
 by simp only [normalClosure_def, AlgHom.fieldRange_of_normal, iSup_const]
feat: IsNormalClosure predicate (#8418)

Main changes are to the file NormalClosure:

  • Introduce predicate IsNormalClosure to characterize normal closures L/F of a field extension K/F by the conditions that every minimal polynomial of an element of K over F splits in L, and that L is generated by roots of such polynomials. (When K/F is not necessarily algebraic, the conditions actually says L/F is a normal closure of the algebraic closure of F in K over F.

  • IsNormalClosure.normal: a normal closure is always normal.

  • isNormalClosure_iff : if K/F is algebraic, the "generated by roots" condition in IsNormalClosure can be replaced by "generated by images of embeddings". To prove it, we split out the two inclusions in restrictScalars_eq_iSup_adjoin and golf its proof. restrictScalars_eq_iSup_adjoin is renamed to normalClosure_eq_iSup_adjoin as it has nothing to do with restrictScalars.

  • IsNormalClosure.lift: a normal closure of K/F embeds into any L/F such that the minpolys of K/F splits in L/F.

  • IsNormalClosure.equiv: normal closures are unique up to F-algebra isomorphisms.

  • isNormalClosure_normalClosure: normalClosure F K L is a valid normal closure if K/F is algebraic and all minpolys of K/F splits in L/F; in particular, if there is at least one F-embedding of K into L, and L/F is normal.

  • Algebra.IsAlgebraic.cardinal_mk_algHom_le_of_splits: if every minpoly of K/F splits in L/F, then L is maximal w.r.t. F-embeddings of K, in the sense that K →ₐ[F] L achieves maximal cardinality.

In the file Normal:

  • splits_of_mem_adjoin: If a set of algebraic elements in a field extension K/F have minimal polynomials that split in another extension L/F, then all minimal polynomials in the intermediate field generated by the set also split in L/F. This is in preparation for connecting IsNormalClosure and IsSplittingField.

In the file IntermediateField:

  • Add comap and show it forms a Galois connection with map.

In the file FieldTheory/Adjoin:

  • Add map_sup/iSup lemmas that follow from the Galois connection, plus an additional convenience lemma.

In the file RingTheory/Algebraic: add a lemma AlgHom.isAlgebraic_of_injective.

Co-authored-by: Jz Pan <acme_pjz@hotmail.com>

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -177,6 +177,22 @@ instance normal_iSup {ι : Type*} (t : ι → IntermediateField F K) [h : ∀ i,
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
 #align intermediate_field.normal_supr IntermediateField.normal_iSup
 
+/-- If a set of algebraic elements in a field extension `K/F` have minimal polynomials that
+  split in another extension `L/F`, then all minimal polynomials in the intermediate field
+  generated by the set also split in `L/F`. -/
+theorem splits_of_mem_adjoin {L} [Field L] [Algebra F L] {S : Set K}
+    (splits : ∀ x ∈ S, IsIntegral F x ∧ (minpoly F x).Splits (algebraMap F L)) {x : K}
+    (hx : x ∈ adjoin F S) : (minpoly F x).Splits (algebraMap F L) := by
+  let E : IntermediateField F L := ⨆ x : S, adjoin F ((minpoly F x.val).rootSet L)
+  have normal : Normal F E := normal_iSup (h := fun x ↦
+    Normal.of_isSplittingField (hFEp := adjoin_rootSet_isSplittingField (splits x x.2).2))
+  have : ∀ x ∈ S, (minpoly F x).Splits (algebraMap F E) := fun x hx ↦ splits_of_splits
+    (splits x hx).2 fun y hy ↦ (le_iSup _ ⟨x, hx⟩ : _ ≤ E) (subset_adjoin F _ <| by exact hy)
+  obtain ⟨φ⟩ := nonempty_algHom_adjoin_of_splits fun x hx ↦ ⟨(splits x hx).1, this x hx⟩
+  convert splits_comp_of_splits _ E.val.toRingHom (normal.splits <| φ ⟨x, hx⟩)
+  rw [minpoly.algHom_eq _ φ.injective, ← minpoly.algHom_eq _ (adjoin F S).val.injective]
+  rfl
+
 instance normal_sup
     (E E' : IntermediateField F K) [Normal F E] [Normal F E'] :
     Normal F (E ⊔ E' : IntermediateField F K) :=
chore(IntegralClosure): noncommutative generalizations and golfs (#8406)

Zulip

Initially I just wanted to add more dot notations for IsIntegral and IsAlgebraic (done in #8437); then I noticed near-duplicates Algebra.isIntegral_of_finite [Field R] [Ring A] and RingHom.IsIntegral.of_finite [CommRing R] [CommRing A] so I went on to generalize the latter to cover the former, and generalized everything in the IntegralClosure file to the noncommutative case whenever possible.

In the process I noticed more golfs, which result in this PR. Most notably, isIntegral_of_mem_of_FG is now proven using Cayley-Hamilton and doesn't depend on the Noetherian case isIntegral_of_noetherian; the latter is now proven using the former. In total the golfs makes mathlib 227 lines leaner (+487 -714).

The main changes are in the single file RingTheory/IntegralClosure:

  • Change the definition of Algebra.IsIntegral which makes it unfold to IsIntegral rather than RingHom.IsIntegralElem because the former has much more APIs.

  • Fix lemma names involving is_integral which are actually about IsIntegralElem: RingHom.is_integral_mapRingHom.isIntegralElem_map RingHom.is_integral_of_mem_closureRingHom.IsIntegralElem.of_mem_closure RingHom.is_integral_zero/oneRingHom.isIntegralElem_zero/one RingHom.is_integral_add/neg/sub/mul/of_mul_unitRingHom.IsIntegralElem.add/neg/sub/mul/of_mul_unit

  • Add a lemma Algebra.IsIntegral.of_injective.

  • Move isIntegral_of_(submodule_)noetherian down and golf them.

  • Remove (Algebra.)isIntegral_of_finite that work only over fields, in favor of the more general (Algebra.)isIntegral.of_finite.

  • Merge duplicate lemmas isIntegral_of_isScalarTower and isIntegral_tower_top_of_isIntegral into IsIntegral.tower_top.

  • Golf IsIntegral.of_mem_of_fg by first proving IsIntegral.of_finite using Cayley-Hamilton.

  • Add a docstring mentioning the Kurosh problem at Algebra.IsIntegral.finite. The negative solution to the problem means the theorem doesn't generalize to noncommutative algebras.

  • Golf IsIntegral.tmul and isField_of_isIntegral_of_isField(').

  • Combine isIntegral_trans_aux into isIntegral_trans and golf.

  • Add Algebra namespace to isIntegral_sup.

  • rename lemmas for dot notation: RingHom.isIntegral_transRingHom.IsIntegral.trans RingHom.isIntegral_quotient/tower_bot/top_of_isIntegralRingHom.IsIntegral.quotient/tower_bot/top isIntegral_of_mem_closure'IsIntegral.of_mem_closure' (and the '' version) isIntegral_of_surjectiveAlgebra.isIntegral_of_surjective

The next changed file is RingTheory/Algebraic:

  • Rename: of_larger_basetower_top (for consistency with IsIntegral) Algebra.isAlgebraic_of_finiteAlgebra.IsAlgebraic.of_finite Algebra.isAlgebraic_transAlgebra.IsAlgebraic.trans

  • Add new lemmasAlgebra.IsIntegral.isAlgebraic, isAlgebraic_algHom_iff, and Algebra.IsAlgebraic.of_injective to streamline some proofs.

The generalization from CommRing to Ring requires an additional lemma scaleRoots_eval₂_mul_of_commute in Polynomial/ScaleRoots.

A lemma Algebra.lmul_injective is added to Algebra/Bilinear (in order to golf the proof of IsIntegral.of_mem_of_fg).

In all other files, I merely fix the changed names, or use newly available dot notations.

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -46,7 +46,7 @@ theorem Normal.isAlgebraic (_ : Normal F K) (x : K) : IsAlgebraic F x :=
 #align normal.is_algebraic Normal.isAlgebraic
 
 theorem Normal.isIntegral (h : Normal F K) (x : K) : IsIntegral F x :=
-  isAlgebraic_iff_isIntegral.mp (h.isAlgebraic' x)
+  (h.isAlgebraic' x).isIntegral
 #align normal.is_integral Normal.isIntegral
 
 theorem Normal.splits (_ : Normal F K) (x : K) : Splits (algebraMap F K) (minpoly F x) :=
@@ -55,7 +55,7 @@ theorem Normal.splits (_ : Normal F K) (x : K) : Splits (algebraMap F K) (minpol
 
 theorem normal_iff : Normal F K ↔ ∀ x : K, IsIntegral F x ∧ Splits (algebraMap F K) (minpoly F x) :=
   ⟨fun h x => ⟨h.isIntegral x, h.splits x⟩, fun h =>
-    ⟨fun x => (h x).1.isAlgebraic F, fun x => (h x).2⟩⟩
+    ⟨fun x => (h x).1.isAlgebraic, fun x => (h x).2⟩⟩
 #align normal_iff normal_iff
 
 theorem Normal.out : Normal F K → ∀ x : K, IsIntegral F x ∧ Splits (algebraMap F K) (minpoly F x) :=
@@ -65,7 +65,7 @@ theorem Normal.out : Normal F K → ∀ x : K, IsIntegral F x ∧ Splits (algebr
 variable (F K)
 
 instance normal_self : Normal F F :=
-  ⟨fun _ => isIntegral_algebraMap.isAlgebraic F, fun x =>
+  ⟨fun _ => isIntegral_algebraMap.isAlgebraic, fun x =>
     (minpoly.eq_X_sub_C' x).symm ▸ splits_X_sub_C _⟩
 #align normal_self normal_self
 
@@ -96,7 +96,7 @@ theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
     cases' h.out x with hx hhx
     rw [algebraMap_eq F K E] at hhx
     exact
-      ⟨isIntegral_of_isScalarTower hx,
+      ⟨hx.tower_top,
         Polynomial.splits_of_splits_of_dvd (algebraMap K E)
           (Polynomial.map_ne_zero (minpoly.ne_zero hx))
           ((Polynomial.splits_map_iff (algebraMap F K) (algebraMap K E)).mpr hhx)
@@ -114,7 +114,7 @@ theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :
   rw [normal_iff] at h ⊢
   intro x; specialize h (f.symm x)
   rw [← f.apply_symm_apply x, minpoly.algEquiv_eq, ← f.toAlgHom.comp_algebraMap]
-  exact ⟨IsIntegral.map f h.1, splits_comp_of_splits _ _ h.2⟩
+  exact ⟨h.1.map f, splits_comp_of_splits _ _ h.2⟩
 #align normal.of_alg_equiv Normal.of_algEquiv
 
 theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F E' :=
@@ -217,8 +217,8 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
         Or.resolve_left (h.splits z).def (minpoly.ne_zero (h.isIntegral z)) (minpoly.irreducible _)
           (minpoly.dvd E _ (by simp [aeval_algHom_apply]))
       simp only [AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom]
-      suffices IsIntegral F _ by exact isIntegral_of_isScalarTower this
-      exact IsIntegral.map ϕ (IsIntegral.map (toAlgHom F E K₁) (h.isIntegral z))⟩
+      suffices IsIntegral F _ by exact this.tower_top
+      exact ((h.isIntegral z).map <| toAlgHom F E K₁).map ϕ⟩
   map_zero' := Subtype.ext ϕ.map_zero
   map_one' := Subtype.ext ϕ.map_one
   map_add' x y := Subtype.ext (ϕ.map_add x y)
@@ -320,7 +320,7 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
     Nonempty.some <|
       @IntermediateField.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
         ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
-        (fun x _ => ⟨isIntegral_of_isScalarTower (h.out x).1,
+        (fun x _ ↦ ⟨(h.out x).1.tower_top,
           splits_of_splits_of_dvd _ (map_ne_zero (minpoly.ne_zero (h.out x).1))
             -- Porting note: had to override typeclass inference below using `(_)`
             (by rw [splits_map_iff, ← @IsScalarTower.algebraMap_eq _ _ _ _ _ _ (_) (_) (_)];
chore(RingTheory/{Algebraic, Localization/Integral}): rename decls to use dot notation (#8437)

This PR tests a string-based tool for renaming declarations.

Inspired by this Zulip thread, I am trying to reduce the diff of #8406.

This PR makes the following renames:

| From | To |

Diff
@@ -114,7 +114,7 @@ theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :
   rw [normal_iff] at h ⊢
   intro x; specialize h (f.symm x)
   rw [← f.apply_symm_apply x, minpoly.algEquiv_eq, ← f.toAlgHom.comp_algebraMap]
-  exact ⟨map_isIntegral f h.1, splits_comp_of_splits _ _ h.2⟩
+  exact ⟨IsIntegral.map f h.1, splits_comp_of_splits _ _ h.2⟩
 #align normal.of_alg_equiv Normal.of_algEquiv
 
 theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F E' :=
@@ -131,7 +131,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
       (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
   refine normal_iff.mpr fun x ↦ ?_
   haveI : FiniteDimensional F E := IsSplittingField.finiteDimensional E p
-  have hx := isIntegral_of_finite F x
+  have hx := IsIntegral.of_finite F x
   let L := (p * minpoly F x).SplittingField
   have hL := splits_of_splits_mul' _ ?_ (SplittingField.splits (p * minpoly F x))
   · let j : E →ₐ[F] L := IsSplittingField.lift E p hL.1
@@ -218,7 +218,7 @@ def AlgHom.restrictNormalAux [h : Normal F E] :
           (minpoly.dvd E _ (by simp [aeval_algHom_apply]))
       simp only [AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom]
       suffices IsIntegral F _ by exact isIntegral_of_isScalarTower this
-      exact map_isIntegral ϕ (map_isIntegral (toAlgHom F E K₁) (h.isIntegral z))⟩
+      exact IsIntegral.map ϕ (IsIntegral.map (toAlgHom F E K₁) (h.isIntegral z))⟩
   map_zero' := Subtype.ext ϕ.map_zero
   map_one' := Subtype.ext ϕ.map_one
   map_add' x y := Subtype.ext (ϕ.map_add x y)
refactor: golf IntermediateField.Lifts (#8221)

Inspired by the IsAlgClosed.lift.SubfieldWithHom counterpart:

  • Change Lifts from a Sigma type to a structure with fields carrier and emb.

  • Change the definition of the partial order on Lifts to use IntermediateField.inclusion.

  • Use Subalgebra.iSupLift in the proof of Lifts.exists_upper_bound.

Also:

  • Inline multiple auxiliary definitions for Lifts.exists_upper_bound and Lifts.exists_lift_of_splits into the proofs proper.

  • Move the Supremum section much further up, in order to use the new lemma toSubalgebra_iSup_of_directed to prove stuff about Lifts (and golf a proof about CompactElement). isAlgebraic_iSup however can't be moved up, so I put it near adjoin.finiteDimensional, the last lemma it depends on.

Co-authored-by: acmepjz <acme_pjz@hotmail.com>

Diff
@@ -318,15 +318,15 @@ noncomputable def AlgHom.liftNormal [h : Normal F E] : E →ₐ[F] E :=
   @AlgHom.restrictScalars F K₁ E E _ _ _ _ _ _
       ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _ _ _ _ <|
     Nonempty.some <|
-      @IntermediateField.algHom_mk_adjoin_splits' _ _ _ _ _ _ _
+      @IntermediateField.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
         ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
-        (IntermediateField.adjoin_univ _ _) fun x _ =>
-        ⟨isIntegral_of_isScalarTower (h.out x).1,
+        (fun x _ => ⟨isIntegral_of_isScalarTower (h.out x).1,
           splits_of_splits_of_dvd _ (map_ne_zero (minpoly.ne_zero (h.out x).1))
             -- Porting note: had to override typeclass inference below using `(_)`
             (by rw [splits_map_iff, ← @IsScalarTower.algebraMap_eq _ _ _ _ _ _ (_) (_) (_)];
                 exact (h.out x).2)
-            (minpoly.dvd_map_of_isScalarTower F K₁ x)⟩
+            (minpoly.dvd_map_of_isScalarTower F K₁ x)⟩)
+        (IntermediateField.adjoin_univ _ _)
 #align alg_hom.lift_normal AlgHom.liftNormal
 
 @[simp]
@@ -370,21 +370,12 @@ theorem AlgEquiv.restrictNormalHom_surjective [Normal F K₁] [Normal F E] :
   ⟨χ.liftNormal E, χ.restrict_liftNormal E⟩
 #align alg_equiv.restrict_normal_hom_surjective AlgEquiv.restrictNormalHom_surjective
 
-open AdjoinRoot in
+open IntermediateField in
 theorem Normal.minpoly_eq_iff_mem_orbit [h : Normal F E] {x y : E} :
     minpoly F x = minpoly F y ↔ x ∈ MulAction.orbit (E ≃ₐ[F] E) y := by
   refine ⟨fun he ↦ ?_, fun ⟨f, he⟩ ↦ he ▸ minpoly.algEquiv_eq f y⟩
-  let Fx := AdjoinRoot (minpoly F x)
-  have hx : aeval x (minpoly F x) = 0 := minpoly.aeval F x
-  have hy : aeval y (minpoly F x) = 0 := he ▸ minpoly.aeval F y
-  let Ax : Algebra Fx E := (lift (algebraMap F E) x hx).toAlgebra
-  have Tx : IsScalarTower F Fx E := IsScalarTower.of_ring_hom (liftHom _ x hx)
-  let Ay : Algebra Fx E := (lift (algebraMap F E) y hy).toAlgebra
-  have Ty : IsScalarTower F Fx E := IsScalarTower.of_ring_hom (liftHom _ y hy)
-  haveI : Fact (Irreducible <| minpoly F x) := ⟨minpoly.irreducible <| h.isIntegral x⟩
-  let f : E ≃ₐ[F] E := @AlgEquiv.liftNormal F Fx Fx _ _ _ _ _ AlgEquiv.refl E _ _ Ay Ax Ty Tx _
-  refine ⟨f, (congr_arg f (lift_root hy).symm).trans <| Eq.trans ?_ (lift_root hx)⟩
-  exact @AlgEquiv.liftNormal_commutes F Fx Fx _ _ _ _ _ _ E _ _ Ay Ax Ty Tx _ (root _)
+  obtain ⟨φ, hφ⟩ := exists_algHom_of_splits_of_aeval (normal_iff.mp h) (he ▸ minpoly.aeval F x)
+  exact ⟨AlgEquiv.ofBijective φ (φ.normal_bijective F E E), hφ⟩
 
 variable (F K₁)
 
chore: golf IsSplittingField.algEquiv (#8142)

Also golfs Normal.of_algEquiv and Algebra.IsIntegral.of_finite and refactors Algebra.IsAlgebraic.bijective_of_isScalarTower.

Diff
@@ -110,24 +110,15 @@ theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function
 -- Porting note: `[Field F] [Field E] [Algebra F E]` added by hand.
 variable {F E} {E' : Type*} [Field F] [Field E] [Algebra F E] [Field E'] [Algebra F E']
 
-theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :=
-  normal_iff.2 fun x => by
-    cases' h.out (f.symm x) with hx hhx
-    have H := map_isIntegral f.toAlgHom hx
-    simp [AlgEquiv.toAlgHom_eq_coe] at H
-    use H
-    apply Polynomial.splits_of_splits_of_dvd (algebraMap F E') (minpoly.ne_zero hx)
-    · rw [← AlgHom.comp_algebraMap f.toAlgHom]
-      exact Polynomial.splits_comp_of_splits (algebraMap F E) f.toAlgHom.toRingHom hhx
-    · apply minpoly.dvd _ _
-      rw [← AddEquiv.map_eq_zero_iff f.symm.toAddEquiv]
-      exact
-        Eq.trans (Polynomial.aeval_algHom_apply f.symm.toAlgHom x (minpoly F (f.symm x))).symm
-          (minpoly.aeval _ _)
+theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' := by
+  rw [normal_iff] at h ⊢
+  intro x; specialize h (f.symm x)
+  rw [← f.apply_symm_apply x, minpoly.algEquiv_eq, ← f.toAlgHom.comp_algebraMap]
+  exact ⟨map_isIntegral f h.1, splits_comp_of_splits _ _ h.2⟩
 #align normal.of_alg_equiv Normal.of_algEquiv
 
 theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F E' :=
-  ⟨fun _ => Normal.of_algEquiv f, fun _ => Normal.of_algEquiv f.symm⟩
+  ⟨fun _ ↦ Normal.of_algEquiv f, fun _ ↦ Normal.of_algEquiv f.symm⟩
 #align alg_equiv.transfer_normal AlgEquiv.transfer_normal
 
 open IntermediateField
feat: Galois orbits in a normal extension are determined by minimal polynomials (#8028)

Add Normal.minpoly_eq_iff_mem_orbit: addresses https://github.com/leanprover-community/mathlib4/pull/6718/files#r1328899532

Also generalize AlgHom.normal_bijective to Algebra.IsAlgebraic.bijective_of_isScalarTower' and golf the proof using a set-theoretic lemma Surjective.of_comp_left (slow to build, awaiting CI).

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -104,26 +104,11 @@ theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
 #align normal.tower_top_of_normal Normal.tower_top_of_normal
 
 theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function.Bijective ϕ :=
-  ⟨ϕ.toRingHom.injective, fun x => by
-    letI : Algebra E K := ϕ.toRingHom.toAlgebra
-    obtain ⟨h1, h2⟩ := h.out (algebraMap K E x)
-    cases'
-      minpoly.mem_range_of_degree_eq_one E x
-        (h2.def.resolve_left (minpoly.ne_zero h1)
-          (minpoly.irreducible
-            (isIntegral_of_isScalarTower
-              ((isIntegral_algebraMap_iff (algebraMap K E).injective).mp h1)))
-          (minpoly.dvd E x
-            ((algebraMap K E).injective
-              (by
-                rw [RingHom.map_zero, aeval_map_algebraMap, ← aeval_algebraMap_apply]
-                exact minpoly.aeval F (algebraMap K E x))))) with
-      y hy
-    exact ⟨y, hy⟩⟩
+  h.isAlgebraic'.bijective_of_isScalarTower' ϕ
 #align alg_hom.normal_bijective AlgHom.normal_bijective
 
 -- Porting note: `[Field F] [Field E] [Algebra F E]` added by hand.
-variable {F} {E} {E' : Type*} [Field F] [Field E] [Algebra F E] [Field E'] [Algebra F E']
+variable {F E} {E' : Type*} [Field F] [Field E] [Algebra F E] [Field E'] [Algebra F E']
 
 theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :=
   normal_iff.2 fun x => by
@@ -394,7 +379,23 @@ theorem AlgEquiv.restrictNormalHom_surjective [Normal F K₁] [Normal F E] :
   ⟨χ.liftNormal E, χ.restrict_liftNormal E⟩
 #align alg_equiv.restrict_normal_hom_surjective AlgEquiv.restrictNormalHom_surjective
 
-variable (F) (K₁)
+open AdjoinRoot in
+theorem Normal.minpoly_eq_iff_mem_orbit [h : Normal F E] {x y : E} :
+    minpoly F x = minpoly F y ↔ x ∈ MulAction.orbit (E ≃ₐ[F] E) y := by
+  refine ⟨fun he ↦ ?_, fun ⟨f, he⟩ ↦ he ▸ minpoly.algEquiv_eq f y⟩
+  let Fx := AdjoinRoot (minpoly F x)
+  have hx : aeval x (minpoly F x) = 0 := minpoly.aeval F x
+  have hy : aeval y (minpoly F x) = 0 := he ▸ minpoly.aeval F y
+  let Ax : Algebra Fx E := (lift (algebraMap F E) x hx).toAlgebra
+  have Tx : IsScalarTower F Fx E := IsScalarTower.of_ring_hom (liftHom _ x hx)
+  let Ay : Algebra Fx E := (lift (algebraMap F E) y hy).toAlgebra
+  have Ty : IsScalarTower F Fx E := IsScalarTower.of_ring_hom (liftHom _ y hy)
+  haveI : Fact (Irreducible <| minpoly F x) := ⟨minpoly.irreducible <| h.isIntegral x⟩
+  let f : E ≃ₐ[F] E := @AlgEquiv.liftNormal F Fx Fx _ _ _ _ _ AlgEquiv.refl E _ _ Ay Ax Ty Tx _
+  refine ⟨f, (congr_arg f (lift_root hy).symm).trans <| Eq.trans ?_ (lift_root hx)⟩
+  exact @AlgEquiv.liftNormal_commutes F Fx Fx _ _ _ _ _ _ E _ _ Ay Ax Ty Tx _ (root _)
+
+variable (F K₁)
 
 theorem isSolvable_of_isScalarTower [Normal F K₁] [h1 : IsSolvable (K₁ ≃ₐ[F] K₁)]
     [h2 : IsSolvable (E ≃ₐ[K₁] E)] : IsSolvable (E ≃ₐ[F] E) := by
refactor: golf Normal.of_isSplittingField (#8004)

Before: Construction only imports Normal, which transitively imports IsSplittingField Now: Normal imports Construction, Construction only imports IsSplittingField So no extra transitive import is added to any file other than Construction and Normal. As a consequence, Polynomial.SplittingField.instNormal is moved from Construction to Normal.

adjoin_rootSet_eq_range is added to IsSplittingField.

splits_of_comp in Splits is extracted from splits_of_splits in IsSplittingField.

Source of proof: https://math.stackexchange.com/a/2585087/12932

Move Algebra.adjoin.liftSingleton from IsAlgClosed/Basic to Adjoin/Field in order to speed up lift_of_splits (renamed to add namespace Polynomial).

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -4,9 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 -/
 import Mathlib.FieldTheory.Adjoin
-import Mathlib.FieldTheory.Tower
+import Mathlib.FieldTheory.SplittingField.Construction
 import Mathlib.GroupTheory.Solvable
-import Mathlib.RingTheory.PowerBasis
 
 #align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
 
@@ -70,10 +69,6 @@ instance normal_self : Normal F F :=
     (minpoly.eq_X_sub_C' x).symm ▸ splits_X_sub_C _⟩
 #align normal_self normal_self
 
-variable {K}
-
-variable (K)
-
 theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K] :
     ∃ p : F[X], IsSplittingField F K p := by
   let s := Basis.ofVectorSpace F K
@@ -150,93 +145,37 @@ theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F
   ⟨fun _ => Normal.of_algEquiv f, fun _ => Normal.of_algEquiv f.symm⟩
 #align alg_equiv.transfer_normal AlgEquiv.transfer_normal
 
--- seems to be causing a diamond in the below proof
--- however, this may be a fluke and the proof below uses non-canonical `Algebra` instances:
--- when I replaced all the instances inside the proof with the "canonical" instances we have,
--- I had the (unprovable) goal (of the form) `AdjoinRoot.mk f (C x) = AdjoinRoot.mk f X`
--- for some `x, f`. So maybe this is indeed the correct approach and rewriting this proof is
--- salient in the future, or at least taking a closer look at the algebra instances it uses.
-attribute [-instance] AdjoinRoot.instSMulAdjoinRoot
+open IntermediateField
 
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E := by
   rcases eq_or_ne p 0 with (rfl | hp)
   · have := hFEp.adjoin_rootSet
-    simp only [rootSet_zero, Algebra.adjoin_empty] at this
-    exact
-      Normal.of_algEquiv
-        (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
-  refine' normal_iff.2 fun x => _
-  have hFE : FiniteDimensional F E := IsSplittingField.finiteDimensional E p
-  have Hx : IsIntegral F x := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) x
-  refine' ⟨Hx, Or.inr _⟩
-  rintro q q_irred ⟨r, hr⟩
-  let D := AdjoinRoot q
-  haveI := Fact.mk q_irred
-  let pbED := AdjoinRoot.powerBasis q_irred.ne_zero
-  haveI : FiniteDimensional E D := PowerBasis.finiteDimensional pbED
-  have finrankED : FiniteDimensional.finrank E D = q.natDegree := by
-    rw [PowerBasis.finrank pbED, AdjoinRoot.powerBasis_dim]
-  haveI : FiniteDimensional F D := FiniteDimensional.trans F E D
-  rsuffices ⟨ϕ⟩ : Nonempty (D →ₐ[F] E)
-  --Porting note: the `change` was `rw [← WithBot.coe_one]`
-  · change degree q = ↑(1 : ℕ)
-    rw [degree_eq_iff_natDegree_eq q_irred.ne_zero, ← finrankED]
-    have nat_lemma : ∀ a b c : ℕ, a * b = c → c ≤ a → 0 < c → b = 1 := by
-      intro a b c h1 h2 h3
-      nlinarith
-    exact
-      nat_lemma _ _ _ (FiniteDimensional.finrank_mul_finrank F E D)
-        (LinearMap.finrank_le_finrank_of_injective
-          (show Function.Injective ϕ.toLinearMap from ϕ.toRingHom.injective))
-        FiniteDimensional.finrank_pos
-  let C := AdjoinRoot (minpoly F x)
-  haveI Hx_irred := Fact.mk (minpoly.irreducible Hx)
--- Porting note: `heval` added since now Lean wants the proof explicitly in several places.
-  have heval : eval₂ (algebraMap F D) (AdjoinRoot.root q) (minpoly F x) = 0 := by
-    rw [algebraMap_eq F E D, ← eval₂_map, hr, AdjoinRoot.algebraMap_eq, eval₂_mul,
-      AdjoinRoot.eval₂_root, zero_mul]
-  letI : Algebra C D :=
-    RingHom.toAlgebra (AdjoinRoot.lift (algebraMap F D) (AdjoinRoot.root q) heval)
-  letI : Algebra C E := RingHom.toAlgebra (AdjoinRoot.lift (algebraMap F E) x (minpoly.aeval F x))
-  haveI : IsScalarTower F C D := of_algebraMap_eq fun y => (AdjoinRoot.lift_of heval).symm
-  haveI : IsScalarTower F C E := by
-    refine' of_algebraMap_eq fun y => (AdjoinRoot.lift_of _).symm
--- Porting note: the following proof was just `_`.
-    rw [← aeval_def, minpoly.aeval]
-  suffices Nonempty (D →ₐ[C] E) by exact Nonempty.map (AlgHom.restrictScalars F) this
-  let S : Set D := ((p.aroots E).map (algebraMap E D)).toFinset
-  suffices ⊤ ≤ IntermediateField.adjoin C S by
-    refine' IntermediateField.algHom_mk_adjoin_splits' (top_le_iff.mp this) fun y hy => _
-    rcases Multiset.mem_map.mp (Multiset.mem_toFinset.mp hy) with ⟨z, hz1, hz2⟩
-    have Hz : IsIntegral F z := isIntegral_of_noetherian (IsNoetherian.iff_fg.2 hFE) z
-    use
-      show IsIntegral C y from
-        isIntegral_of_noetherian (IsNoetherian.iff_fg.2 (FiniteDimensional.right F C D)) y
-    apply splits_of_splits_of_dvd (algebraMap C E) (map_ne_zero (minpoly.ne_zero Hz))
-    · rw [splits_map_iff, ← algebraMap_eq F C E]
-      exact
-        splits_of_splits_of_dvd _ hp hFEp.splits (minpoly.dvd F z (mem_aroots.mp hz1).2)
-    · apply minpoly.dvd
-      rw [← hz2, aeval_def, eval₂_map, ← algebraMap_eq F C D, algebraMap_eq F E D, ← hom_eval₂, ←
-        aeval_def, minpoly.aeval F z, RingHom.map_zero]
-  rw [← IntermediateField.toSubalgebra_le_toSubalgebra, IntermediateField.top_toSubalgebra]
-  apply ge_trans (IntermediateField.algebra_adjoin_le_adjoin C S)
-  suffices
-    (Algebra.adjoin C S).restrictScalars F =
-      (Algebra.adjoin E {AdjoinRoot.root q}).restrictScalars F by
-    rw [AdjoinRoot.adjoinRoot_eq_top, Subalgebra.restrictScalars_top, ←
-      @Subalgebra.restrictScalars_top F C] at this
-    exact top_le_iff.mpr (Subalgebra.restrictScalars_injective F this)
-/- Porting note: the `change` was `dsimp only [S]`. Using `set S ... with hS` doesn't work. -/
-  change Subalgebra.restrictScalars F (Algebra.adjoin C
-    (((p.aroots E).map (algebraMap E D)).toFinset : Set D)) = _
-  rw [← Finset.image_toFinset, Finset.coe_image]
-  apply
-    Eq.trans
-      (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_rootSet AdjoinRoot.adjoinRoot_eq_top)
-  rw [Set.image_singleton, RingHom.algebraMap_toAlgebra, AdjoinRoot.lift_root]
+    rw [rootSet_zero, Algebra.adjoin_empty] at this
+    exact Normal.of_algEquiv
+      (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
+  refine normal_iff.mpr fun x ↦ ?_
+  haveI : FiniteDimensional F E := IsSplittingField.finiteDimensional E p
+  have hx := isIntegral_of_finite F x
+  let L := (p * minpoly F x).SplittingField
+  have hL := splits_of_splits_mul' _ ?_ (SplittingField.splits (p * minpoly F x))
+  · let j : E →ₐ[F] L := IsSplittingField.lift E p hL.1
+    refine ⟨hx, splits_of_comp _ (j : E →+* L) (j.comp_algebraMap ▸ hL.2) fun a ha ↦ ?_⟩
+    rw [j.comp_algebraMap] at ha
+    letI : Algebra F⟮x⟯ L := ((algHomAdjoinIntegralEquiv F hx).symm ⟨a, ha⟩).toRingHom.toAlgebra
+    let j' : E →ₐ[F⟮x⟯] L := IsSplittingField.lift E (p.map (algebraMap F F⟮x⟯)) ?_
+    · change a ∈ j.range
+      rw [← IsSplittingField.adjoin_rootSet_eq_range E p j,
+            IsSplittingField.adjoin_rootSet_eq_range E p (j'.restrictScalars F)]
+      exact ⟨x, (j'.commutes _).trans (algHomAdjoinIntegralEquiv_symm_apply_gen F hx _)⟩
+    · rw [splits_map_iff, ← IsScalarTower.algebraMap_eq]; exact hL.1
+  · rw [Polynomial.map_ne_zero_iff (algebraMap F L).injective, mul_ne_zero_iff]
+    exact ⟨hp, minpoly.ne_zero hx⟩
 #align normal.of_is_splitting_field Normal.of_isSplittingField
 
+instance Polynomial.SplittingField.instNormal [Field F] (p : F[X]) : Normal F p.SplittingField :=
+  Normal.of_isSplittingField p
+#align polynomial.splitting_field.normal Polynomial.SplittingField.instNormal
+
 end NormalTower
 
 namespace IntermediateField
fix(FieldTheory): add the missing _root_ lost during porting (#7981)

You can tell this was a porting error because the #aligns were weird.

Diff
@@ -343,9 +343,9 @@ theorem AlgHom.fieldRange_of_normal [Algebra F K] {E : IntermediateField F K} [N
 -- Porting note: this was `IsScalarTower F E E := by infer_instance`.
   letI : Algebra E E := Algebra.id E
   let g := f.restrictNormal' E
-  rw [← show E.val.comp ↑g = f from FunLike.ext_iff.mpr (f.restrictNormal_commutes E), ←
-    IntermediateField.AlgHom.map_fieldRange, IntermediateField.AlgEquiv.fieldRange_eq_top g,
-      ← IntermediateField.AlgHom.fieldRange_eq_map, IntermediateField.fieldRange_val]
+  rw [← show E.val.comp ↑g = f from FunLike.ext_iff.mpr (f.restrictNormal_commutes E),
+    ← AlgHom.map_fieldRange, AlgEquiv.fieldRange_eq_top g, ← AlgHom.fieldRange_eq_map,
+    IntermediateField.fieldRange_val]
 #align alg_hom.field_range_of_normal AlgHom.fieldRange_of_normal
 
 /-- Restrict algebra isomorphism to a normal subfield -/
chore: removing unneeded maxHeartbeats (#7761)

Due to recent changes in core we can reduce or remove many set_option maxHeartbeats statements.

I have tried to be careful to not leave anything too close to the line, so don't be surprised if some of these can still be reduced further.

This reduces us from 96 maxHeartbeats statements to 44. (There are 10 false positives in meta or testing code.)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -227,8 +227,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
     rw [AdjoinRoot.adjoinRoot_eq_top, Subalgebra.restrictScalars_top, ←
       @Subalgebra.restrictScalars_top F C] at this
     exact top_le_iff.mpr (Subalgebra.restrictScalars_injective F this)
-/- Porting note: the `change` was `dsimp only [S]`. This is the step that requires increasing
-`maxHeartbeats`. Using `set S ... with hS` doesn't work. -/
+/- Porting note: the `change` was `dsimp only [S]`. Using `set S ... with hS` doesn't work. -/
   change Subalgebra.restrictScalars F (Algebra.adjoin C
     (((p.aroots E).map (algebraMap E D)).toFinset : Set D)) = _
   rw [← Finset.image_toFinset, Finset.coe_image]
chore(RingTheory): golf, generalize, fix docs (#7500)

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -266,7 +266,7 @@ instance normal_iSup {ι : Type*} (t : ι → IntermediateField F K) [h : ∀ i,
 instance normal_sup
     (E E' : IntermediateField F K) [Normal F E] [Normal F E'] :
     Normal F (E ⊔ E' : IntermediateField F K) :=
-  iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by intro i; cases i <;> infer_instance)
+  iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by rintro (_|_) <;> infer_instance)
 
 -- Porting note `[Field F] [Field K] [Algebra F K]` added by hand.
 variable {F K} {L : Type*} [Field F] [Field K] [Field L] [Algebra F L] [Algebra K L]
chore: replace minpoly.eq_of_algebraMap_eq by algebraMap_eq (#7228)

Also changes the repetitive names minpoly.minpoly_algHom/Equiv to minpoly.algHom/Equiv_eq

Diff
@@ -62,7 +62,7 @@ theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     -- Now it can't find a proof by unification, so we have to do it ourselves.
     apply PowerBasis.lift_gen
     change aeval y (minpoly F (AdjoinSimple.gen F x)) = 0
-    exact minpoly_gen (hi x) ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
+    exact minpoly_gen F x ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
 
 #align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
 
@@ -74,8 +74,7 @@ instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
   intro x
   -- Porting note: use the `(_)` trick to obtain an instance by unification.
   apply Normal.of_isSplittingField (p := minpoly F x) (hFEp := _)
-  exact adjoin_rootSet_isSplittingField ((minpoly.eq_of_algebraMap_eq ϕ.injective
-    ((isIntegral_algebraMap_iff ϕ.injective).mp (h.isIntegral (ϕ x))) rfl).symm ▸ h.splits _)
+  exact adjoin_rootSet_isSplittingField (minpoly.algebraMap_eq ϕ.injective (A := F) x ▸ h.splits _)
 #align normal_closure.normal normalClosure.normal
 
 instance is_finiteDimensional [FiniteDimensional F K] :
feat: roots in an algebra (#6740)

Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com>

Diff
@@ -204,7 +204,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
 -- Porting note: the following proof was just `_`.
     rw [← aeval_def, minpoly.aeval]
   suffices Nonempty (D →ₐ[C] E) by exact Nonempty.map (AlgHom.restrictScalars F) this
-  let S : Set D := ((p.map (algebraMap F E)).roots.map (algebraMap E D)).toFinset
+  let S : Set D := ((p.aroots E).map (algebraMap E D)).toFinset
   suffices ⊤ ≤ IntermediateField.adjoin C S by
     refine' IntermediateField.algHom_mk_adjoin_splits' (top_le_iff.mp this) fun y hy => _
     rcases Multiset.mem_map.mp (Multiset.mem_toFinset.mp hy) with ⟨z, hz1, hz2⟩
@@ -215,8 +215,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
     apply splits_of_splits_of_dvd (algebraMap C E) (map_ne_zero (minpoly.ne_zero Hz))
     · rw [splits_map_iff, ← algebraMap_eq F C E]
       exact
-        splits_of_splits_of_dvd _ hp hFEp.splits
-          (minpoly.dvd F z (Eq.trans (eval₂_eq_eval_map _) ((mem_roots (map_ne_zero hp)).mp hz1)))
+        splits_of_splits_of_dvd _ hp hFEp.splits (minpoly.dvd F z (mem_aroots.mp hz1).2)
     · apply minpoly.dvd
       rw [← hz2, aeval_def, eval₂_map, ← algebraMap_eq F C D, algebraMap_eq F E D, ← hom_eval₂, ←
         aeval_def, minpoly.aeval F z, RingHom.map_zero]
@@ -231,7 +230,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
 /- Porting note: the `change` was `dsimp only [S]`. This is the step that requires increasing
 `maxHeartbeats`. Using `set S ... with hS` doesn't work. -/
   change Subalgebra.restrictScalars F (Algebra.adjoin C
-    (((p.map (algebraMap F E)).roots.map (algebraMap E D)).toFinset : Set D)) = _
+    (((p.aroots E).map (algebraMap E D)).toFinset : Set D)) = _
   rw [← Finset.image_toFinset, Finset.coe_image]
   apply
     Eq.trans
refactor(FieldTheory/NormalClosure): change definition and add API (#6163)

This PR adds API and changes the definition of the normal closure of $F\leq K\leq L$ to be an intermediate field of L/F, rather than an intermediate field of L/K. For example, I think it would be more common to say that the normal closure of $\mathbb{Q}(\sqrt[3]{2})/\mathbb{Q}$ is $\mathbb{Q}(\sqrt[3]{2},\zeta_3)/\mathbb{Q}$ rather than $\mathbb{Q}(\sqrt[3]{2},\zeta_3)/\mathbb{Q}(\sqrt[3]{2})$. This change also means that the normal closure goes from being a dependent function (K : Type) → IntermediateField K L to being a non-dependent function Type → IntermediateField F L, making it easier to compare across the Galois corespondence.

Supersedes https://github.com/leanprover-community/mathlib/pull/18971

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Thomas Browning <tb65536@users.noreply.github.com>

Diff
@@ -5,6 +5,7 @@ Authors: Thomas Browning
 -/
 
 import Mathlib.FieldTheory.Normal
+import Mathlib.Order.Closure
 
 #align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
 /-!
@@ -22,16 +23,27 @@ variable (F K L : Type*) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F
   [IsScalarTower F K L]
 
 /-- The normal closure of `K` in `L`. -/
-noncomputable def normalClosure : IntermediateField K L :=
-  { (⨆ f : K →ₐ[F] L, f.fieldRange) with
-    algebraMap_mem' := fun r =>
-      le_iSup (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
-#align normal_closure normalClosure
+noncomputable def normalClosure : IntermediateField F L :=
+  ⨆ f : K →ₐ[F] L, f.fieldRange
+
+lemma normalClosure_def : normalClosure F K L = ⨆ f : K →ₐ[F] L, f.fieldRange :=
+  rfl
+
+variable {F K L}
+
+lemma normalClosure_le_iff {K' : IntermediateField F L} :
+    normalClosure F K L ≤ K' ↔ ∀ f : K →ₐ[F] L, f.fieldRange ≤ K' :=
+  iSup_le_iff
+
+lemma AlgHom.fieldRange_le_normalClosure  (f : K →ₐ[F] L) : f.fieldRange ≤ normalClosure F K L :=
+  le_iSup AlgHom.fieldRange f
+
+variable (F K L)
 
 namespace normalClosure
 
 theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
-    (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
+    normalClosure F K L = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
   classical
   have hi : ∀ x : K, IsIntegral F x :=
     fun x ↦ (isIntegral_algebraMap_iff (algebraMap K L).injective).mp (h.isIntegral _)
@@ -71,12 +83,89 @@ instance is_finiteDimensional [FiniteDimensional F K] :
   haveI : ∀ f : K →ₐ[F] L, FiniteDimensional F f.fieldRange := fun f =>
     f.toLinearMap.finiteDimensional_range
   apply IntermediateField.finiteDimensional_iSup_of_finite
-#align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
 
-instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
-  -- Porting note: the last argument here `(⨆ (f : K →ₐ[F] L), f.fieldRange).toSubalgebra`
-  -- was just written as `_` in mathlib3.
-  IsScalarTower.subalgebra' F L L (⨆ (f : K →ₐ[F] L), f.fieldRange).toSubalgebra
-#align normal_closure.is_scalar_tower normalClosure.isScalarTower
+noncomputable instance algebra : Algebra K (normalClosure F K L) :=
+  IntermediateField.algebra
+    { ⨆ f : K →ₐ[F] L, f.fieldRange with
+      algebraMap_mem' := fun r => (toAlgHom F K L).fieldRange_le_normalClosure ⟨r, rfl⟩ }
+
+instance : IsScalarTower F K (normalClosure F K L) := by
+  apply of_algebraMap_eq'
+  ext x
+  exact algebraMap_apply F K L x
+
+instance : IsScalarTower K (normalClosure F K L) L :=
+  of_algebraMap_eq' rfl
+
+lemma restrictScalars_eq :
+    (toAlgHom K (normalClosure F K L) L).fieldRange.restrictScalars F = normalClosure F K L :=
+  SetLike.ext' Subtype.range_val
 
 end normalClosure
+
+namespace IntermediateField
+
+variable {F L}
+variable (K K' : IntermediateField F L)
+
+lemma le_normalClosure : K ≤ normalClosure F K L :=
+K.fieldRange_val.symm.trans_le K.val.fieldRange_le_normalClosure
+
+lemma normalClosure_of_normal [Normal F K] : normalClosure F K L = K :=
+by simp only [normalClosure_def, AlgHom.fieldRange_of_normal, iSup_const]
+
+variable [Normal F L]
+
+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⟩)
+  · 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
+  refine' (normalClosure_def' K).trans (le_antisymm (iSup_le (fun f ↦ _)) (iSup_le (fun f ↦ _)))
+  · exact le_iSup_of_le (f.restrictNormal' L)
+      (fun b ⟨a, h⟩ ↦ ⟨a, h.1, h.2 ▸ f.restrictNormal_commutes L a⟩)
+  · exact le_iSup_of_le f le_rfl
+
+lemma normalClosure_mono (h : K ≤ K') : normalClosure F K L ≤ normalClosure F K' L := by
+  rw [normalClosure_def', normalClosure_def']
+  exact iSup_mono (fun f ↦ map_mono f h)
+
+variable (F L)
+
+/-- `normalClosure` as a `ClosureOperator`. -/
+@[simps]
+noncomputable def closureOperator : ClosureOperator (IntermediateField F L) where
+  toFun := fun K ↦ normalClosure F K L
+  monotone' := fun K K' ↦ normalClosure_mono K K'
+  le_closure' := le_normalClosure
+  idempotent' := fun K ↦ normalClosure_of_normal (normalClosure F K L)
+
+variable {K : IntermediateField F L} {F L}
+
+lemma normal_iff_normalClosure_eq : Normal F K ↔ normalClosure F K L = K :=
+⟨@normalClosure_of_normal (K := K), fun h ↦ h ▸ normalClosure.normal F K L⟩
+
+lemma normal_iff_normalClosure_le : Normal F K ↔ normalClosure F K L ≤ K :=
+normal_iff_normalClosure_eq.trans (le_normalClosure K).le_iff_eq.symm
+
+lemma normal_iff_forall_fieldRange_le : Normal F K ↔ ∀ σ : K →ₐ[F] L, σ.fieldRange ≤ K :=
+by rw [normal_iff_normalClosure_le, normalClosure_def, iSup_le_iff]
+
+lemma normal_iff_forall_map_le : Normal F K ↔ ∀ σ : L →ₐ[F] L, K.map σ ≤ K :=
+by rw [normal_iff_normalClosure_le, normalClosure_def', iSup_le_iff]
+
+lemma normal_iff_forall_map_le' : Normal F K ↔ ∀ σ : L ≃ₐ[F] L, K.map ↑σ ≤ K :=
+by rw [normal_iff_normalClosure_le, normalClosure_def'', iSup_le_iff]
+
+lemma normal_iff_forall_fieldRange_eq : Normal F K ↔ ∀ σ : K →ₐ[F] L, σ.fieldRange = K :=
+⟨@AlgHom.fieldRange_of_normal (E := K), normal_iff_forall_fieldRange_le.2 ∘ fun h σ ↦ (h σ).le⟩
+
+lemma normal_iff_forall_map_eq : Normal F K ↔ ∀ σ : L →ₐ[F] L, K.map σ = K :=
+⟨fun h σ ↦ (K.fieldRange_val ▸ AlgHom.map_fieldRange K.val σ).trans
+  (normal_iff_forall_fieldRange_eq.1 h _), fun h ↦ normal_iff_forall_map_le.2 (fun σ ↦ (h σ).le)⟩
+
+lemma normal_iff_forall_map_eq' : Normal F K ↔ ∀ σ : L ≃ₐ[F] L, K.map ↑σ = K :=
+⟨fun h σ ↦ normal_iff_forall_map_eq.1 h σ, fun h ↦ normal_iff_forall_map_le'.2 (fun σ ↦ (h σ).le)⟩
+
+end IntermediateField
chore: drop MulZeroClass. in mul_zero/zero_mul (#6682)

Search&replace MulZeroClass.mul_zero -> mul_zero, MulZeroClass.zero_mul -> zero_mul.

These were introduced by Mathport, as the full name of mul_zero is actually MulZeroClass.mul_zero (it's exported with the short name).

Diff
@@ -194,7 +194,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
 -- Porting note: `heval` added since now Lean wants the proof explicitly in several places.
   have heval : eval₂ (algebraMap F D) (AdjoinRoot.root q) (minpoly F x) = 0 := by
     rw [algebraMap_eq F E D, ← eval₂_map, hr, AdjoinRoot.algebraMap_eq, eval₂_mul,
-      AdjoinRoot.eval₂_root, MulZeroClass.zero_mul]
+      AdjoinRoot.eval₂_root, zero_mul]
   letI : Algebra C D :=
     RingHom.toAlgebra (AdjoinRoot.lift (algebraMap F D) (AdjoinRoot.root q) heval)
   letI : Algebra C E := RingHom.toAlgebra (AdjoinRoot.lift (algebraMap F E) x (minpoly.aeval F x))
chore: banish Type _ and Sort _ (#6499)

We remove all possible occurences of Type _ and Sort _ in favor of Type* and Sort*.

This has nice performance benefits.

Diff
@@ -18,7 +18,7 @@ contains the image of every `F`-algebra embedding `K →ₐ[F] L`.
 
 open BigOperators IntermediateField IsScalarTower Polynomial
 
-variable (F K L : Type _) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F L] [Algebra K L]
+variable (F K L : Type*) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F L] [Algebra K L]
   [IsScalarTower F K L]
 
 /-- The normal closure of `K` in `L`. -/
chore: banish Type _ and Sort _ (#6499)

We remove all possible occurences of Type _ and Sort _ in favor of Type* and Sort*.

This has nice performance benefits.

Diff
@@ -31,7 +31,7 @@ open scoped Classical Polynomial
 
 open Polynomial IsScalarTower
 
-variable (F K : Type _) [Field F] [Field K] [Algebra F K]
+variable (F K : Type*) [Field F] [Field K] [Algebra F K]
 
 /-- Typeclass for normal field extension: `K` is a normal extension of `F` iff the minimal
 polynomial of every element `x` in `K` splits in `K`, i.e. every conjugate of `x` is in `K`. -/
@@ -94,7 +94,7 @@ theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K]
 
 section NormalTower
 
-variable (E : Type _) [Field E] [Algebra F E] [Algebra K E] [IsScalarTower F K E]
+variable (E : Type*) [Field E] [Algebra F E] [Algebra K E] [IsScalarTower F K E]
 
 theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
   normal_iff.2 fun x => by
@@ -128,7 +128,7 @@ theorem AlgHom.normal_bijective [h : Normal F E] (ϕ : E →ₐ[F] K) : Function
 #align alg_hom.normal_bijective AlgHom.normal_bijective
 
 -- Porting note: `[Field F] [Field E] [Algebra F E]` added by hand.
-variable {F} {E} {E' : Type _} [Field F] [Field E] [Algebra F E] [Field E'] [Algebra F E']
+variable {F} {E} {E' : Type*} [Field F] [Field E] [Algebra F E] [Field E'] [Algebra F E']
 
 theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' :=
   normal_iff.2 fun x => by
@@ -244,7 +244,7 @@ end NormalTower
 namespace IntermediateField
 
 /-- A compositum of normal extensions is normal -/
-instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] :
+instance normal_iSup {ι : Type*} (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] :
     Normal F (⨆ i, t i : IntermediateField F K) := by
   refine' ⟨isAlgebraic_iSup fun i => (h i).1, fun x => _⟩
   obtain ⟨s, hx⟩ := exists_finset_of_mem_supr'' (fun i => (h i).1) x.2
@@ -270,7 +270,7 @@ instance normal_sup
   iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by intro i; cases i <;> infer_instance)
 
 -- Porting note `[Field F] [Field K] [Algebra F K]` added by hand.
-variable {F K} {L : Type _} [Field F] [Field K] [Field L] [Algebra F L] [Algebra K L]
+variable {F K} {L : Type*} [Field F] [Field K] [Field L] [Algebra F L] [Algebra K L]
   [Algebra F K] [IsScalarTower F K L]
 
 @[simp]
@@ -282,13 +282,13 @@ theorem restrictScalars_normal {E : IntermediateField K L} :
 end IntermediateField
 
 -- Porting note `[Field F]` added by hand.
-variable {F} {K} {K₁ K₂ K₃ : Type _} [Field F] [Field K₁] [Field K₂] [Field K₃] [Algebra F K₁]
+variable {F} {K} {K₁ K₂ K₃ : Type*} [Field F] [Field K₁] [Field K₂] [Field K₃] [Algebra F K₁]
   [Algebra F K₂] [Algebra F K₃] (ϕ : K₁ →ₐ[F] K₂) (χ : K₁ ≃ₐ[F] K₂) (ψ : K₂ →ₐ[F] K₃)
   (ω : K₂ ≃ₐ[F] K₃)
 
 section Restrict
 
-variable (E : Type _) [Field E] [Algebra F E] [Algebra E K₁] [Algebra E K₂] [Algebra E K₃]
+variable (E : Type*) [Field E] [Algebra F E] [Algebra E K₁] [Algebra E K₂] [Algebra E K₃]
   [IsScalarTower F E K₁] [IsScalarTower F E K₂] [IsScalarTower F E K₃]
 
 /-- Restrict algebra homomorphism to image of normal subfield -/
@@ -396,7 +396,7 @@ end Restrict
 
 section lift
 
-variable (E : Type _) [Field E] [Algebra F E] [Algebra K₁ E] [Algebra K₂ E] [IsScalarTower F K₁ E]
+variable (E : Type*) [Field E] [Algebra F E] [Algebra K₁ E] [Algebra K₂ E] [IsScalarTower F K₁ E]
   [IsScalarTower F K₂ E]
 
 /-- If `E/Kᵢ/F` are towers of fields with `E/F` normal then we can lift
chore(FieldTheory/NormalClosure): remove a porting note (#6315)
Diff
@@ -23,9 +23,7 @@ variable (F K L : Type _) [Field F] [Field K] [Field L] [Algebra F K] [Algebra F
 
 /-- The normal closure of `K` in `L`. -/
 noncomputable def normalClosure : IntermediateField K L :=
-  { (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield with
-    -- Porting note: could not inherit neg_mem
-    neg_mem' := fun _ hx => Subfield.neg_mem (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield hx
+  { (⨆ f : K →ₐ[F] L, f.fieldRange) with
     algebraMap_mem' := fun r =>
       le_iSup (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
 #align normal_closure normalClosure
refactor(FieldTheory/NormalClosure): Some golfs (#6289)

This PR extracts some golfs from #6163.

Diff
@@ -35,36 +35,24 @@ namespace normalClosure
 theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
   classical
+  have hi : ∀ x : K, IsIntegral F x :=
+    fun x ↦ (isIntegral_algebraMap_iff (algebraMap K L).injective).mp (h.isIntegral _)
   refine' le_antisymm (iSup_le _) (iSup_le fun x => adjoin_le_iff.mpr fun y hy => _)
   · rintro f _ ⟨x, rfl⟩
-    refine'
-      le_iSup (fun x => adjoin F ((minpoly F x).rootSet L)) x
+    refine' le_iSup (fun x => adjoin F ((minpoly F x).rootSet L)) x
         (subset_adjoin F ((minpoly F x).rootSet L) _)
-    rw [mem_rootSet_of_ne, AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom,
+    rw [mem_rootSet_of_ne (minpoly.ne_zero (hi x)), AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom,
       Polynomial.aeval_algHom_apply, minpoly.aeval, map_zero]
-    exact
-      minpoly.ne_zero
-        ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-          (h.isIntegral (algebraMap K L x)))
   · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy
-    let g :=
-      (algHomAdjoinIntegralEquiv F
-            ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-              (h.isIntegral (algebraMap K L x)))).symm
-        ⟨y, hy⟩
-    refine'
-      le_iSup (fun f : K →ₐ[F] L => f.fieldRange)
-        ((g.liftNormal L).comp (IsScalarTower.toAlgHom F K L))
+    let g := (algHomAdjoinIntegralEquiv F (hi x)).symm ⟨y, hy⟩
+    refine' le_iSup (fun f : K →ₐ[F] L => f.fieldRange) ((g.liftNormal L).comp (toAlgHom F K L))
         ⟨x, (g.liftNormal_commutes L (AdjoinSimple.gen F x)).trans _⟩
     rw [Algebra.id.map_eq_id, RingHom.id_apply]
     -- Porting note: in mathlib3 this next `apply` closed the goal.
     -- Now it can't find a proof by unification, so we have to do it ourselves.
     apply PowerBasis.lift_gen
     change aeval y (minpoly F (AdjoinSimple.gen F x)) = 0
-    suffices : minpoly F (AdjoinSimple.gen F x) = minpoly F x
-    · exact this ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
-    exact minpoly_gen ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-      (h.isIntegral (algebraMap K L x)))
+    exact minpoly_gen (hi x) ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
 
 #align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
 
@@ -72,15 +60,12 @@ instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
   let ϕ := algebraMap K L
   rw [← IntermediateField.restrictScalars_normal, restrictScalars_eq_iSup_adjoin]
   -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply @IntermediateField.normal_iSup F L _ _ _ _ _ (_)
+  apply IntermediateField.normal_iSup (h := _)
   intro x
   -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply @Normal.of_isSplittingField _ _ _ _ _ (minpoly F x) (_)
-  exact
-    adjoin_rootSet_isSplittingField
-      ((minpoly.eq_of_algebraMap_eq ϕ.injective
-            ((isIntegral_algebraMap_iff ϕ.injective).mp (h.isIntegral (ϕ x))) rfl).symm ▸
-        h.splits _)
+  apply Normal.of_isSplittingField (p := minpoly F x) (hFEp := _)
+  exact adjoin_rootSet_isSplittingField ((minpoly.eq_of_algebraMap_eq ϕ.injective
+    ((isIntegral_algebraMap_iff ϕ.injective).mp (h.isIntegral (ϕ x))) rfl).symm ▸ h.splits _)
 #align normal_closure.normal normalClosure.normal
 
 instance is_finiteDimensional [FiniteDimensional F K] :
refactor(FieldTheory/NormalClosure): move to new file (#6273)

This PR moves normalClosure to a separate file, in preparation for #6163.

Co-authored-by: Thomas Browning <tb65536@users.noreply.github.com>

refactor(FieldTheory/NormalClosure): move to new file (#6273)

This PR moves normalClosure to a separate file, in preparation for #6163.

Co-authored-by: Thomas Browning <tb65536@users.noreply.github.com>

Diff
@@ -474,89 +474,3 @@ theorem isSolvable_of_isScalarTower [Normal F K₁] [h1 : IsSolvable (K₁ ≃
 #align is_solvable_of_is_scalar_tower isSolvable_of_isScalarTower
 
 end lift
-
-section normalClosure
-
-open IntermediateField
-
-variable (F K)
-variable [Algebra F K]
-variable (L : Type _) [Field L] [Algebra F L] [Algebra K L] [IsScalarTower F K L]
-
-/-- The normal closure of `K` in `L`. -/
-noncomputable def normalClosure : IntermediateField K L :=
-  { (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield with
-    -- Porting note: could not inherit neg_mem
-    neg_mem' := fun _ hx => Subfield.neg_mem (⨆ f : K →ₐ[F] L, f.fieldRange).toSubfield hx
-    algebraMap_mem' := fun r =>
-      le_iSup (fun f : K →ₐ[F] L => f.fieldRange) (IsScalarTower.toAlgHom F K L) ⟨r, rfl⟩ }
-#align normal_closure normalClosure
-
-namespace normalClosure
-
-theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
-    (normalClosure F K L).restrictScalars F = ⨆ x : K, adjoin F ((minpoly F x).rootSet L) := by
-  refine' le_antisymm (iSup_le _) (iSup_le fun x => adjoin_le_iff.mpr fun y hy => _)
-  · rintro f _ ⟨x, rfl⟩
-    refine'
-      le_iSup (fun x => adjoin F ((minpoly F x).rootSet L)) x
-        (subset_adjoin F ((minpoly F x).rootSet L) _)
-    rw [mem_rootSet_of_ne, AlgHom.toRingHom_eq_coe, AlgHom.coe_toRingHom,
-      Polynomial.aeval_algHom_apply, minpoly.aeval, map_zero]
-    exact
-      minpoly.ne_zero
-        ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-          (h.isIntegral (algebraMap K L x)))
-  · rw [Polynomial.rootSet, Finset.mem_coe, Multiset.mem_toFinset] at hy
-    let g :=
-      (algHomAdjoinIntegralEquiv F
-            ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-              (h.isIntegral (algebraMap K L x)))).symm
-        ⟨y, hy⟩
-    refine'
-      le_iSup (fun f : K →ₐ[F] L => f.fieldRange)
-        ((g.liftNormal L).comp (IsScalarTower.toAlgHom F K L))
-        ⟨x, (g.liftNormal_commutes L (AdjoinSimple.gen F x)).trans _⟩
-    rw [Algebra.id.map_eq_id, RingHom.id_apply]
-    -- Porting note: in mathlib3 this next `apply` closed the goal.
-    -- Now it can't find a proof by unification, so we have to do it ourselves.
-    apply PowerBasis.lift_gen
-    change aeval y (minpoly F (AdjoinSimple.gen F x)) = 0
-    suffices : minpoly F (AdjoinSimple.gen F x) = minpoly F x
-    · exact this ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
-    exact minpoly_gen ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
-      (h.isIntegral (algebraMap K L x)))
-
-#align normal_closure.restrict_scalars_eq_supr_adjoin normalClosure.restrictScalars_eq_iSup_adjoin
-
-instance normal [h : Normal F L] : Normal F (normalClosure F K L) := by
-  let ϕ := algebraMap K L
-  rw [← IntermediateField.restrictScalars_normal, restrictScalars_eq_iSup_adjoin]
-  -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply @IntermediateField.normal_iSup F L _ _ _ _ _ (_)
-  intro x
-  -- Porting note: use the `(_)` trick to obtain an instance by unification.
-  apply @Normal.of_isSplittingField _ _ _ _ _ (minpoly F x) (_)
-  exact
-    adjoin_rootSet_isSplittingField
-      ((minpoly.eq_of_algebraMap_eq ϕ.injective
-            ((isIntegral_algebraMap_iff ϕ.injective).mp (h.isIntegral (ϕ x))) rfl).symm ▸
-        h.splits _)
-#align normal_closure.normal normalClosure.normal
-
-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
-  apply IntermediateField.finiteDimensional_iSup_of_finite
-#align normal_closure.is_finite_dimensional normalClosure.is_finiteDimensional
-
-instance isScalarTower : IsScalarTower F (normalClosure F K L) L :=
-  -- Porting note: the last argument here `(⨆ (f : K →ₐ[F] L), f.fieldRange).toSubalgebra`
-  -- was just written as `_` in mathlib3.
-  IsScalarTower.subalgebra' F L L (⨆ (f : K →ₐ[F] L), f.fieldRange).toSubalgebra
-#align normal_closure.is_scalar_tower normalClosure.isScalarTower
-
-end normalClosure
-
-end normalClosure
feat: Compositum of two normal field extensions is normal (#6077)

This is a quick consequence of normal_iSup which states than an arbitrary compositum of normal field extensions is normal.

Diff
@@ -264,6 +264,11 @@ instance normal_iSup {ι : Type _} (t : ι → IntermediateField F K) [h : ∀ i
   exact Polynomial.splits_comp_of_splits _ (inclusion hE).toRingHom this
 #align intermediate_field.normal_supr IntermediateField.normal_iSup
 
+instance normal_sup
+    (E E' : IntermediateField F K) [Normal F E] [Normal F E'] :
+    Normal F (E ⊔ E' : IntermediateField F K) :=
+  iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by intro i; cases i <;> infer_instance)
+
 -- Porting note `[Field F] [Field K] [Algebra F K]` added by hand.
 variable {F K} {L : Type _} [Field F] [Field K] [Field L] [Algebra F L] [Algebra K L]
   [Algebra F K] [IsScalarTower F K L]
chore: script to replace headers with #align_import statements (#5979)

Open in Gitpod

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2020 Kenny Lau. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
-
-! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit 9fb8964792b4237dac6200193a0d533f1b3f7423
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathlib.FieldTheory.Adjoin
 import Mathlib.FieldTheory.Tower
 import Mathlib.GroupTheory.Solvable
 import Mathlib.RingTheory.PowerBasis
 
+#align_import field_theory.normal from "leanprover-community/mathlib"@"9fb8964792b4237dac6200193a0d533f1b3f7423"
+
 /-!
 # Normal field extensions
 
chore: fix focusing dots (#5708)

This PR is the result of running

find . -type f -name "*.lean" -exec sed -i -E 's/^( +)\. /\1· /' {} \;
find . -type f -name "*.lean" -exec sed -i -E 'N;s/^( +·)\n +(.*)$/\1 \2/;P;D' {} \;

which firstly replaces . focusing dots with · and secondly removes isolated instances of such dots, unifying them with the following line. A new rule is placed in the style linter to verify this.

Diff
@@ -521,7 +521,7 @@ theorem restrictScalars_eq_iSup_adjoin [h : Normal F L] :
     apply PowerBasis.lift_gen
     change aeval y (minpoly F (AdjoinSimple.gen F x)) = 0
     suffices : minpoly F (AdjoinSimple.gen F x) = minpoly F x
-    . exact this ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
+    · exact this ▸ aeval_eq_zero_of_mem_rootSet (Multiset.mem_toFinset.mpr hy)
     exact minpoly_gen ((isIntegral_algebraMap_iff (algebraMap K L).injective).mp
       (h.isIntegral (algebraMap K L x)))
 
chore: tidy various files (#5458)
Diff
@@ -39,18 +39,18 @@ variable (F K : Type _) [Field F] [Field K] [Algebra F K]
 /-- Typeclass for normal field extension: `K` is a normal extension of `F` iff the minimal
 polynomial of every element `x` in `K` splits in `K`, i.e. every conjugate of `x` is in `K`. -/
 class Normal : Prop where
-  is_algebraic' : Algebra.IsAlgebraic F K
+  isAlgebraic' : Algebra.IsAlgebraic F K
   splits' (x : K) : Splits (algebraMap F K) (minpoly F x)
 #align normal Normal
 
 variable {F K}
 
 theorem Normal.isAlgebraic (_ : Normal F K) (x : K) : IsAlgebraic F x :=
-  Normal.is_algebraic' x
+  Normal.isAlgebraic' x
 #align normal.is_algebraic Normal.isAlgebraic
 
 theorem Normal.isIntegral (h : Normal F K) (x : K) : IsIntegral F x :=
-  isAlgebraic_iff_isIntegral.mp (h.is_algebraic' x)
+  isAlgebraic_iff_isIntegral.mp (h.isAlgebraic' x)
 #align normal.is_integral Normal.isIntegral
 
 theorem Normal.splits (_ : Normal F K) (x : K) : Splits (algebraMap F K) (minpoly F x) :=
@@ -89,8 +89,7 @@ theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K]
       (Multiset.mem_toFinset.mpr <|
         (mem_roots <|
               mt (Polynomial.map_eq_zero <| algebraMap F K).1 <|
-                Finset.prod_ne_zero_iff.2 fun x _ => _).2
-          _)
+                Finset.prod_ne_zero_iff.2 fun x _ => _).2 _)
   · exact minpoly.ne_zero (h.isIntegral (s x))
   rw [IsRoot.def, eval_map, ← aeval_def, AlgHom.map_prod]
   exact Finset.prod_eq_zero (Finset.mem_univ _) (minpoly.aeval _ _)
chore: change Field.toEuclideanDomain (#5266)

Modifying the definition of Field.toEuclideanDomain makes some declaration faster.

Co-authored-by: Sébastien Gouëzel

Diff
@@ -162,7 +162,6 @@ theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F
 -- salient in the future, or at least taking a closer look at the algebra instances it uses.
 attribute [-instance] AdjoinRoot.instSMulAdjoinRoot
 
-set_option maxHeartbeats 300000 in
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E := by
   rcases eq_or_ne p 0 with (rfl | hp)
   · have := hFEp.adjoin_rootSet
chore: forward-port leanprover-community/mathlib#19179 (#5022)

Strangely, making one proof use fewer simp lemmas has made the proof slower (and the hearbeats have been bumped accordingly)

Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au>

Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Kenny Lau, Thomas Browning, Patrick Lutz
 
 ! This file was ported from Lean 3 source module field_theory.normal
-! leanprover-community/mathlib commit df76f43357840485b9d04ed5dee5ab115d420e87
+! leanprover-community/mathlib commit 9fb8964792b4237dac6200193a0d533f1b3f7423
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -162,12 +162,11 @@ theorem AlgEquiv.transfer_normal (f : E ≃ₐ[F] E') : Normal F E ↔ Normal F
 -- salient in the future, or at least taking a closer look at the algebra instances it uses.
 attribute [-instance] AdjoinRoot.instSMulAdjoinRoot
 
-set_option maxHeartbeats 210000 in
+set_option maxHeartbeats 300000 in
 theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E := by
   rcases eq_or_ne p 0 with (rfl | hp)
-  · have := hFEp.adjoin_roots
-    simp only [Polynomial.map_zero, roots_zero, Multiset.toFinset_zero, Finset.coe_empty,
-      Algebra.adjoin_empty] at this
+  · have := hFEp.adjoin_rootSet
+    simp only [rootSet_zero, Algebra.adjoin_empty] at this
     exact
       Normal.of_algEquiv
         (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
@@ -241,7 +240,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
   rw [← Finset.image_toFinset, Finset.coe_image]
   apply
     Eq.trans
-      (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_roots AdjoinRoot.adjoinRoot_eq_top)
+      (Algebra.adjoin_res_eq_adjoin_res F E C D hFEp.adjoin_rootSet AdjoinRoot.adjoinRoot_eq_top)
   rw [Set.image_singleton, RingHom.algebraMap_toAlgebra, AdjoinRoot.lift_root]
 #align normal.of_is_splitting_field Normal.of_isSplittingField
 
chore: fix grammar 2/3 (#5002)

Part 2 of #5001

Diff
@@ -369,7 +369,7 @@ theorem AlgEquiv.restrictNormal_trans [Normal F E] :
       (by simp only [AlgEquiv.trans_apply, AlgEquiv.restrictNormal_commutes])
 #align alg_equiv.restrict_normal_trans AlgEquiv.restrictNormal_trans
 
-/-- Restriction to an normal subfield as a group homomorphism -/
+/-- Restriction to a normal subfield as a group homomorphism -/
 def AlgEquiv.restrictNormalHom [Normal F E] : (K₁ ≃ₐ[F] K₁) →* E ≃ₐ[F] E :=
   MonoidHom.mk' (fun χ => χ.restrictNormal E) fun ω χ => χ.restrictNormal_trans ω E
 #align alg_equiv.restrict_normal_hom AlgEquiv.restrictNormalHom
chore: fix many typos (#4967)

These are all doc fixes

Diff
@@ -197,7 +197,7 @@ theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] :
         FiniteDimensional.finrank_pos
   let C := AdjoinRoot (minpoly F x)
   haveI Hx_irred := Fact.mk (minpoly.irreducible Hx)
--- Porting note: `heval` added since now Lean wants the proof explictely in several places.
+-- Porting note: `heval` added since now Lean wants the proof explicitly in several places.
   have heval : eval₂ (algebraMap F D) (AdjoinRoot.root q) (minpoly F x) = 0 := by
     rw [algebraMap_eq F E D, ← eval₂_map, hr, AdjoinRoot.algebraMap_eq, eval₂_mul,
       AdjoinRoot.eval₂_root, MulZeroClass.zero_mul]
feat: port FieldTheory.Normal (#4856)

Co-authored-by: Vierkantor <vierkantor@vierkantor.com> Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au> Co-authored-by: Thomas Browning <tb65536@uw.edu> Co-authored-by: Scott Morrison <scott@tqft.net>

Dependencies 10 + 654

655 files ported (98.5%)
272686 lines ported (98.8%)
Show graph

The unported dependencies are