l3lab/ntp-mathlib huggingface dataset:
/-- If `S` is a nonempty subset of a finite group `G`, then `S ^ |G|` is a subgroup -/
@[to_additive (attr := simps!) smulCardAddSubgroup
  "If `S` is a nonempty subset of a finite add group `G`, then `|G| • S` is a subgroup"]
def powCardSubgroup {G : Type*} [Group G] [Fintype G] (S : Set G) (hS : S.Nonempty) : Subgroup G :=
  have one_mem : (1 : G) ∈ S ^ Fintype.card G := by
    obtain ⟨a, ha⟩ := hS
    rw [← pow_card_eq_one]
    

Proof state:
case intro
G✝ : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
G : Type u_6
inst✝¹ : Group G
inst✝ : Fintype G
S : Set G
a : G
ha : a ∈ S
⊢ ?m.422024 ^ Fintype.card G ∈ S ^ Fintype.card G
G✝ : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
G : Type u_6
inst✝¹ : Group G
inst✝ : Fintype G
S : Set G
a : G
ha : a ∈ S
⊢ G

Next tactic:
exact Set.pow_mem_pow ha (Fintype.card G)
/-- If `S` is a nonempty subset of a finite group `G`, then `S ^ |G|` is a subgroup -/
@[to_additive (attr := simps!) smulCardAddSubgroup
  "If `S` is a nonempty subset of a finite add group `G`, then `|G| • S` is a subgroup"]
def powCardSubgroup {G : Type*} [Group G] [Fintype G] (S : Set G) (hS : S.Nonempty) : Subgroup G :=
  have one_mem : (1 : G) ∈ S ^ Fintype.card G := by
    obtain ⟨a, ha⟩ := hS
    rw [← pow_card_eq_one]
    exact Set.pow_mem_pow ha (Fintype.card G)
  subgroupOfIdempotent (S ^ Fintype.card G) ⟨1, one_mem⟩ $ by
    

Proof state:
G✝ : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
G : Type u_6
inst✝¹ : Group G
inst✝ : Fintype G
S : Set G
hS : Set.Nonempty S
one_mem : 1 ∈ S ^ Fintype.card G
⊢ S ^ Fintype.card G * S ^ Fintype.card G = S ^ Fintype.card G

Next tactic:
classical!
/-- If `S` is a nonempty subset of a finite group `G`, then `S ^ |G|` is a subgroup -/
@[to_additive (attr := simps!) smulCardAddSubgroup
  "If `S` is a nonempty subset of a finite add group `G`, then `|G| • S` is a subgroup"]
def powCardSubgroup {G : Type*} [Group G] [Fintype G] (S : Set G) (hS : S.Nonempty) : Subgroup G :=
  have one_mem : (1 : G) ∈ S ^ Fintype.card G := by
    obtain ⟨a, ha⟩ := hS
    rw [← pow_card_eq_one]
    exact Set.pow_mem_pow ha (Fintype.card G)
  subgroupOfIdempotent (S ^ Fintype.card G) ⟨1, one_mem⟩ $ by
    classical!
    

Proof state:
G✝ : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
G : Type u_6
inst✝¹ : Group G
inst✝ : Fintype G
S : Set G
hS : Set.Nonempty S
one_mem : 1 ∈ S ^ Fintype.card G
em✝ : (a : Prop) → Decidable a
⊢ S ^ Fintype.card G * S ^ Fintype.card G = S ^ Fintype.card G

Next tactic:
apply (Set.eq_of_subset_of_card_le (Set.subset_mul_left _ one_mem) (ge_of_eq _)).symm
/-- If `S` is a nonempty subset of a finite group `G`, then `S ^ |G|` is a subgroup -/
@[to_additive (attr := simps!) smulCardAddSubgroup
  "If `S` is a nonempty subset of a finite add group `G`, then `|G| • S` is a subgroup"]
def powCardSubgroup {G : Type*} [Group G] [Fintype G] (S : Set G) (hS : S.Nonempty) : Subgroup G :=
  have one_mem : (1 : G) ∈ S ^ Fintype.card G := by
    obtain ⟨a, ha⟩ := hS
    rw [← pow_card_eq_one]
    exact Set.pow_mem_pow ha (Fintype.card G)
  subgroupOfIdempotent (S ^ Fintype.card G) ⟨1, one_mem⟩ $ by
    classical!
    apply (Set.eq_of_subset_of_card_le (Set.subset_mul_left _ one_mem) (ge_of_eq _)).symm
    

Proof state:
G✝ : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
G : Type u_6
inst✝¹ : Group G
inst✝ : Fintype G
S : Set G
hS : Set.Nonempty S
one_mem : 1 ∈ S ^ Fintype.card G
em✝ : (a : Prop) → Decidable a
⊢ Fintype.card ↑(S ^ Fintype.card G) = Fintype.card ↑(S ^ Fintype.card G * S ^ Fintype.card G)

Next tactic:
simp_rw [← pow_add,
        Group.card_pow_eq_card_pow_card_univ S (Fintype.card G + Fintype.card G) le_add_self]
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
⊢ orderOf x = 0

Next tactic:
rw [orderOf_eq_zero_iff']
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
⊢ ∀ (n : ℕ), 0 < n → x ^ n ≠ 1

Next tactic:
intro n hn hx
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  intro n hn hx
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
n : ℕ
hn : 0 < n
hx : x ^ n = 1
⊢ False

Next tactic:
replace hx : |x| ^ n = 1 := by simpa only [abs_one, abs_pow] using congr_arg abs hx
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  intro n hn hx
  replace hx : |x| ^ n = 1 := by 

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
n : ℕ
hn : 0 < n
hx : x ^ n = 1
⊢ |x| ^ n = 1

Next tactic:
simpa only [abs_one, abs_pow] using congr_arg abs hx
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  intro n hn hx
  replace hx : |x| ^ n = 1 := by simpa only [abs_one, abs_pow] using congr_arg abs hx
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
n : ℕ
hn : 0 < n
hx : |x| ^ n = 1
⊢ False

Next tactic:
cases' h.lt_or_lt with h h
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  intro n hn hx
  replace hx : |x| ^ n = 1 := by simpa only [abs_one, abs_pow] using congr_arg abs hx
  cases' h.lt_or_lt with h h
  · 

Proof state:
case inl
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h✝ : |x| ≠ 1
n : ℕ
hn : 0 < n
hx : |x| ^ n = 1
h : |x| < 1
⊢ False

Next tactic:
exact ((pow_lt_one (abs_nonneg x) h hn.ne').ne hx).elim
theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by
  rw [orderOf_eq_zero_iff']
  intro n hn hx
  replace hx : |x| ^ n = 1 := by simpa only [abs_one, abs_pow] using congr_arg abs hx
  cases' h.lt_or_lt with h h
  · exact ((pow_lt_one (abs_nonneg x) h hn.ne').ne hx).elim
  · 

Proof state:
case inr
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h✝ : |x| ≠ 1
n : ℕ
hn : 0 < n
hx : |x| ^ n = 1
h : 1 < |x|
⊢ False

Next tactic:
exact ((one_lt_pow h hn.ne').ne' hx).elim
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
⊢ orderOf x ≤ 2

Next tactic:
cases' ne_or_eq |x| 1 with h h
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · 

Proof state:
case inl
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| ≠ 1
⊢ orderOf x ≤ 2

Next tactic:
simp [orderOf_abs_ne_one h]
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  

Proof state:
case inr
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
x : G
h : |x| = 1
⊢ orderOf x ≤ 2

Next tactic:
rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
  · 

Proof state:
case inr.inl
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
h : |1| = 1
⊢ orderOf 1 ≤ 2

Next tactic:
simp
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
  · simp; 

Proof state:
case inr.inl
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
h : |1| = 1
⊢ 1 ≤ 2

Next tactic:
decide
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
  · simp; decide
  

Proof state:
case inr.inr
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
h : |(-1)| = 1
⊢ orderOf (-1) ≤ 2

Next tactic:
apply orderOf_le_of_pow_eq_one
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
  · simp; decide
  apply orderOf_le_of_pow_eq_one <;> 

Proof state:
case inr.inr.hn
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
h : |(-1)| = 1
⊢ 0 < 2

Next tactic:
norm_num
theorem LinearOrderedRing.orderOf_le_two : orderOf x ≤ 2 := by
  cases' ne_or_eq |x| 1 with h h
  · simp [orderOf_abs_ne_one h]
  rcases eq_or_eq_neg_of_abs_eq h with (rfl | rfl)
  · simp; decide
  apply orderOf_le_of_pow_eq_one <;> 

Proof state:
case inr.inr.h
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝ : LinearOrderedRing G
h : |(-1)| = 1
⊢ (-1) ^ 2 = 1

Next tactic:
norm_num
@[to_additive IsOfFinAddOrder.prod_mk]
theorem IsOfFinOrder.prod_mk : IsOfFinOrder a → IsOfFinOrder b → IsOfFinOrder (a, b) := by
  

Proof state:
G : Type u_1
H : Type u_2
A : Type u_3
α : Type u_4
β : Type u_5
inst✝¹ : Monoid α
inst✝ : Monoid β
x : α × β
a : α
b : β
⊢ IsOfFinOrder a → IsOfFinOrder b → IsOfFinOrder (a, b)

Next tactic:
simpa only [← orderOf_pos_iff, Prod.orderOf] using Nat.lcm_pos
theorem Normal.exists_isSplittingField [h : Normal F K] [FiniteDimensional F K] :
    ∃ p : F[X], IsSplittingField F K p := by
  

Proof state:
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
⊢ ∃ p, IsSplittingField F K p

Next tactic:
let s := Basis.ofVectorSpace F 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
  

Proof state:
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
⊢ ∃ p, IsSplittingField F K p

Next tactic:
refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
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
  refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
  

Proof state:
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
⊢ Subalgebra.toSubmodule (Algebra.adjoin F (rootSet (∏ x : ↑(Basis.ofVectorSpaceIndex F K), minpoly F (s x)) K)) =
    Subalgebra.toSubmodule ⊤

Next tactic:
rw [Algebra.top_toSubmodule, eq_top_iff, ← s.span_eq, Submodule.span_le, Set.range_subset_iff]
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
  refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
  rw [Algebra.top_toSubmodule, eq_top_iff, ← s.span_eq, Submodule.span_le, Set.range_subset_iff]
  

Proof state:
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
⊢ ∀ (y : ↑(Basis.ofVectorSpaceIndex F K)),
    s y ∈
      ↑(Subalgebra.toSubmodule (Algebra.adjoin F (rootSet (∏ x : ↑(Basis.ofVectorSpaceIndex F K), minpoly F (s x)) K)))

Next tactic:
refine' fun x =>
    Algebra.subset_adjoin
      (Multiset.mem_toFinset.mpr <|
        (mem_roots <|
              mt (Polynomial.map_eq_zero <| algebraMap F K).1 <|
                Finset.prod_ne_zero_iff.2 fun x _ => _).2 _)
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
  refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
  rw [Algebra.top_toSubmodule, eq_top_iff, ← s.span_eq, Submodule.span_le, Set.range_subset_iff]
  refine' fun x =>
    Algebra.subset_adjoin
      (Multiset.mem_toFinset.mpr <|
        (mem_roots <|
              mt (Polynomial.map_eq_zero <| algebraMap F K).1 <|
                Finset.prod_ne_zero_iff.2 fun x _ => _).2 _)
  · 

Proof state:
case refine'_1
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
x✝¹ x : ↑(Basis.ofVectorSpaceIndex F K)
x✝ : x ∈ Finset.univ
⊢ minpoly F (s x) ≠ 0

Next tactic:
exact minpoly.ne_zero (h.isIntegral (s x))
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
  refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
  rw [Algebra.top_toSubmodule, eq_top_iff, ← s.span_eq, Submodule.span_le, Set.range_subset_iff]
  refine' fun x =>
    Algebra.subset_adjoin
      (Multiset.mem_toFinset.mpr <|
        (mem_roots <|
              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))
  

Proof state:
case refine'_2
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
x : ↑(Basis.ofVectorSpaceIndex F K)
⊢ IsRoot (map (algebraMap F K) (∏ x : ↑(Basis.ofVectorSpaceIndex F K), minpoly F (s x))) (s x)

Next tactic:
rw [IsRoot.def, eval_map, ← aeval_def, AlgHom.map_prod]
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
  refine'
    ⟨∏ x, minpoly F (s x), splits_prod _ fun x _ => h.splits (s x),
      Subalgebra.toSubmodule.injective _⟩
  rw [Algebra.top_toSubmodule, eq_top_iff, ← s.span_eq, Submodule.span_le, Set.range_subset_iff]
  refine' fun x =>
    Algebra.subset_adjoin
      (Multiset.mem_toFinset.mpr <|
        (mem_roots <|
              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]
  

Proof state:
case refine'_2
F : Type u_1
K : Type u_2
inst✝³ : Field F
inst✝² : Field K
inst✝¹ : Algebra F K
h : Normal F K
inst✝ : FiniteDimensional F K
s : Basis (↑(Basis.ofVectorSpaceIndex F K)) F K := Basis.ofVectorSpace F K
x : ↑(Basis.ofVectorSpaceIndex F K)
⊢ ∏ x_1 : ↑(Basis.ofVectorSpaceIndex F K), (aeval (s x)) (minpoly F (s x_1)) = 0

Next tactic:
exact Finset.prod_eq_zero (Finset.mem_univ _) (minpoly.aeval _ _)
theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E :=
  normal_iff.2 fun x => by
    

Proof state:
F : Type u_1
K : Type u_2
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Algebra F K
E : Type u_3
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Algebra K E
inst✝ : IsScalarTower F K E
h : Normal F E
x : E
⊢ IsIntegral K x ∧ Splits (algebraMap K E) (minpoly K x)

Next tactic:
cases' h.out x with hx hhx
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
    

Proof state:
case intro
F : Type u_1
K : Type u_2
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Algebra F K
E : Type u_3
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Algebra K E
inst✝ : IsScalarTower F K E
h : Normal F E
x : E
hx : IsIntegral F x
hhx : Splits (algebraMap F E) (minpoly F x)
⊢ IsIntegral K x ∧ Splits (algebraMap K E) (minpoly K x)

Next tactic:
rw [algebraMap_eq F K E] at hhx
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 [algebraMap_eq F K E] at hhx
    

Proof state:
case intro
F : Type u_1
K : Type u_2
inst✝⁶ : Field F
inst✝⁵ : Field K
inst✝⁴ : Algebra F K
E : Type u_3
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Algebra K E
inst✝ : IsScalarTower F K E
h : Normal F E
x : E
hx : IsIntegral F x
hhx : Splits (RingHom.comp (algebraMap K E) (algebraMap F K)) (minpoly F x)
⊢ IsIntegral K x ∧ Splits (algebraMap K E) (minpoly K x)

Next tactic:
exact
      ⟨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)
          (minpoly.dvd_map_of_isScalarTower F K x)⟩
theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' := by
  

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

Next tactic:
rw [normal_iff] at h ⊢
theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' := by
  rw [normal_iff] at h ⊢
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
h : ∀ (x : E), IsIntegral F x ∧ Splits (algebraMap F E) (minpoly F x)
f : E ≃ₐ[F] E'
⊢ ∀ (x : E'), IsIntegral F x ∧ Splits (algebraMap F E') (minpoly F x)

Next tactic:
intro x
theorem Normal.of_algEquiv [h : Normal F E] (f : E ≃ₐ[F] E') : Normal F E' := by
  rw [normal_iff] at h ⊢
  intro x; 

Proof state:
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
h : ∀ (x : E), IsIntegral F x ∧ Splits (algebraMap F E) (minpoly F x)
f : E ≃ₐ[F] E'
x : E'
⊢ IsIntegral F x ∧ Splits (algebraMap F E') (minpoly F x)

Next tactic:
specialize h (f.symm x)
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)
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
f : E ≃ₐ[F] E'
x : E'
h : IsIntegral F ((AlgEquiv.symm f) x) ∧ Splits (algebraMap F E) (minpoly F ((AlgEquiv.symm f) x))
⊢ IsIntegral F x ∧ Splits (algebraMap F E') (minpoly F x)

Next tactic:
rw [← f.apply_symm_apply x, minpoly.algEquiv_eq, ← f.toAlgHom.comp_algebraMap]
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]
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
f : E ≃ₐ[F] E'
x : E'
h : IsIntegral F ((AlgEquiv.symm f) x) ∧ Splits (algebraMap F E) (minpoly F ((AlgEquiv.symm f) x))
⊢ IsIntegral F (f ((AlgEquiv.symm f) x)) ∧
    Splits (RingHom.comp (↑↑f) (algebraMap F E)) (minpoly F ((AlgEquiv.symm f) x))

Next tactic:
exact ⟨h.1.map f, splits_comp_of_splits _ _ h.2⟩
theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E := by
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
p : F[X]
hFEp : IsSplittingField F E p
⊢ Normal F E

Next tactic:
rcases eq_or_ne p 0 with (rfl | hp)
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)
  · 

Proof state:
case inl
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
hFEp : IsSplittingField F E 0
⊢ Normal F E

Next tactic:
have := hFEp.adjoin_rootSet
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
    

Proof state:
case inl
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
hFEp : IsSplittingField F E 0
this : Algebra.adjoin F (rootSet 0 E) = ⊤
⊢ Normal F E

Next tactic:
rw [rootSet_zero, Algebra.adjoin_empty] at this
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
    rw [rootSet_zero, Algebra.adjoin_empty] at this
    

Proof state:
case inl
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
hFEp : IsSplittingField F E 0
this : ⊥ = ⊤
⊢ Normal F E

Next tactic:
exact Normal.of_algEquiv
      (AlgEquiv.ofBijective (Algebra.ofId F E) (Algebra.bijective_algebraMap_iff.2 this.symm))
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
    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))
  

Proof state:
case inr
F : Type u_1
K : Type u_2
inst✝¹¹ : Field F
inst✝¹⁰ : Field K
inst✝⁹ : Algebra F K
E : Type u_3
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra K E
inst✝⁵ : IsScalarTower F K E
E' : Type u_4
inst✝⁴ : Field F
inst✝³ : Field E
inst✝² : Algebra F E
inst✝¹ : Field E'
inst✝ : Algebra F E'
p : F[X]
hFEp : IsSplittingField F E p
hp : p ≠ 0
⊢ Normal F E

Next tactic:
refine normal_iff.mpr fun x ↦ ?_