l3lab/ntp-mathlib huggingface dataset:
theorem cg_iff_countable [Countable (Σl, L.Functions l)] {s : L.Substructure M} :
    s.CG ↔ Countable s := by
  refine' ⟨_, fun h => ⟨s, h.to_set, s.closure_eq⟩⟩
  rintro ⟨s, h, rfl⟩
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
inst✝ : Countable ((l : ℕ) × Functions L l)
s : Set M
h : Set.Countable s
⊢ Countable ↥(LowerAdjoint.toFun (closure L) s)

Next tactic:
exact h.substructure_closure L
/-- An equivalent expression of `Structure.FG` in terms of `Set.Finite` instead of `Finset`. -/
theorem fg_iff : FG L M ↔ ∃ S : Set M, S.Finite ∧ closure L S = (⊤ : L.Substructure M) := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
⊢ FG L M ↔ ∃ S, Set.Finite S ∧ LowerAdjoint.toFun (closure L) S = ⊤

Next tactic:
rw [fg_def, Substructure.fg_def]
theorem FG.range {N : Type*} [L.Structure N] (h : FG L M) (f : M →[L] N) : f.range.FG := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : FG L M
f : M →[L] N
⊢ Substructure.FG (Hom.range f)

Next tactic:
rw [Hom.range_eq_map]
theorem FG.range {N : Type*} [L.Structure N] (h : FG L M) (f : M →[L] N) : f.range.FG := by
  rw [Hom.range_eq_map]
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : FG L M
f : M →[L] N
⊢ Substructure.FG (map f ⊤)

Next tactic:
exact (fg_def.1 h).map f
theorem FG.map_of_surjective {N : Type*} [L.Structure N] (h : FG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : FG L N := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : FG L M
f : M →[L] N
hs : Function.Surjective ⇑f
⊢ FG L N

Next tactic:
rw [← Hom.range_eq_top] at hs
theorem FG.map_of_surjective {N : Type*} [L.Structure N] (h : FG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : FG L N := by
  rw [← Hom.range_eq_top] at hs
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : FG L M
f : M →[L] N
hs : Hom.range f = ⊤
⊢ FG L N

Next tactic:
rw [fg_def, ← hs]
theorem FG.map_of_surjective {N : Type*} [L.Structure N] (h : FG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : FG L N := by
  rw [← Hom.range_eq_top] at hs
  rw [fg_def, ← hs]
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : FG L M
f : M →[L] N
hs : Hom.range f = ⊤
⊢ Substructure.FG (Hom.range f)

Next tactic:
exact h.range f
/-- An equivalent expression of `Structure.cg`. -/
theorem cg_iff : CG L M ↔ ∃ S : Set M, S.Countable ∧ closure L S = (⊤ : L.Substructure M) := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
⊢ CG L M ↔ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = ⊤

Next tactic:
rw [cg_def, Substructure.cg_def]
theorem CG.range {N : Type*} [L.Structure N] (h : CG L M) (f : M →[L] N) : f.range.CG := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : CG L M
f : M →[L] N
⊢ Substructure.CG (Hom.range f)

Next tactic:
rw [Hom.range_eq_map]
theorem CG.range {N : Type*} [L.Structure N] (h : CG L M) (f : M →[L] N) : f.range.CG := by
  rw [Hom.range_eq_map]
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : CG L M
f : M →[L] N
⊢ Substructure.CG (map f ⊤)

Next tactic:
exact (cg_def.1 h).map f
theorem CG.map_of_surjective {N : Type*} [L.Structure N] (h : CG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : CG L N := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : CG L M
f : M →[L] N
hs : Function.Surjective ⇑f
⊢ CG L N

Next tactic:
rw [← Hom.range_eq_top] at hs
theorem CG.map_of_surjective {N : Type*} [L.Structure N] (h : CG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : CG L N := by
  rw [← Hom.range_eq_top] at hs
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : CG L M
f : M →[L] N
hs : Hom.range f = ⊤
⊢ CG L N

Next tactic:
rw [cg_def, ← hs]
theorem CG.map_of_surjective {N : Type*} [L.Structure N] (h : CG L M) (f : M →[L] N)
    (hs : Function.Surjective f) : CG L N := by
  rw [← Hom.range_eq_top] at hs
  rw [cg_def, ← hs]
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
h : CG L M
f : M →[L] N
hs : Hom.range f = ⊤
⊢ Substructure.CG (Hom.range f)

Next tactic:
exact h.range f
theorem cg_iff_countable [Countable (Σl, L.Functions l)] : CG L M ↔ Countable M := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
inst✝ : Countable ((l : ℕ) × Functions L l)
⊢ CG L M ↔ Countable M

Next tactic:
rw [cg_def, Substructure.cg_iff_countable, topEquiv.toEquiv.countable_iff]
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
⊢ FG S ↔ Structure.FG L ↥S

Next tactic:
rw [Structure.fg_def]
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
⊢ FG S ↔ FG ⊤

Next tactic:
refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
  · 

Proof state:
case refine'_1
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : FG S
⊢ FG (map (Embedding.toHom (subtype S)) ⊤)

Next tactic:
rw [← Hom.range_eq_map, range_subtype]
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    

Proof state:
case refine'_1
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : FG S
⊢ FG S

Next tactic:
exact h
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · 

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : FG ⊤
⊢ FG S

Next tactic:
have h := h.map S.subtype.toHom
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · have h := h.map S.subtype.toHom
    

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h✝ : FG ⊤
h : FG (map (Embedding.toHom (subtype S)) ⊤)
⊢ FG S

Next tactic:
rw [← Hom.range_eq_map, range_subtype] at h
theorem Substructure.fg_iff_structure_fg (S : L.Substructure M) : S.FG ↔ Structure.FG L S := by
  rw [Structure.fg_def]
  refine' ⟨fun h => FG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · have h := h.map S.subtype.toHom
    rw [← Hom.range_eq_map, range_subtype] at h
    

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h✝ : FG ⊤
h : FG S
⊢ FG S

Next tactic:
exact h
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
⊢ CG S ↔ Structure.CG L ↥S

Next tactic:
rw [Structure.cg_def]
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
⊢ CG S ↔ CG ⊤

Next tactic:
refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
  · 

Proof state:
case refine'_1
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : CG S
⊢ CG (map (Embedding.toHom (subtype S)) ⊤)

Next tactic:
rw [← Hom.range_eq_map, range_subtype]
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    

Proof state:
case refine'_1
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : CG S
⊢ CG S

Next tactic:
exact h
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · 

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h : CG ⊤
⊢ CG S

Next tactic:
have h := h.map S.subtype.toHom
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · have h := h.map S.subtype.toHom
    

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h✝ : CG ⊤
h : CG (map (Embedding.toHom (subtype S)) ⊤)
⊢ CG S

Next tactic:
rw [← Hom.range_eq_map, range_subtype] at h
theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Structure.CG L S := by
  rw [Structure.cg_def]
  refine' ⟨fun h => CG.of_map_embedding S.subtype _, fun h => _⟩
  · rw [← Hom.range_eq_map, range_subtype]
    exact h
  · have h := h.map S.subtype.toHom
    rw [← Hom.range_eq_map, range_subtype] at h
    

Proof state:
case refine'_2
L : Language
M : Type u_1
inst✝ : Structure L M
S : Substructure L M
h✝ : CG ⊤
h : CG S
⊢ CG S

Next tactic:
exact h
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  

Proof state:
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
⊢ ∃ α, F⟮α⟯ = ⊤

Next tactic:
obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  

Proof state:
case intro
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
⊢ ∃ α, F⟮α⟯ = ⊤

Next tactic:
use α
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  

Proof state:
case h
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
⊢ F⟮↑α⟯ = ⊤

Next tactic:
apply eq_top_iff.mpr
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  

Proof state:
case h
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
⊢ ⊤ ≤ F⟮↑α⟯

Next tactic:
rintro x -
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  

Proof state:
case h
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
⊢ x ∈ F⟮↑α⟯

Next tactic:
by_cases hx : x = 0
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · 

Proof state:
case pos
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : x = 0
⊢ x ∈ F⟮↑α⟯

Next tactic:
rw [hx]
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    

Proof state:
case pos
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : x = 0
⊢ 0 ∈ F⟮↑α⟯

Next tactic:
exact F⟮α.val⟯.zero_mem
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · 

Proof state:
case neg
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
⊢ x ∈ F⟮↑α⟯

Next tactic:
obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
    

Proof state:
case neg.intro
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
n : ℤ
hn : (fun x => α ^ x) n = Units.mk0 x hx
⊢ x ∈ F⟮↑α⟯

Next tactic:
simp only at hn
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
    simp only at hn
    

Proof state:
case neg.intro
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
n : ℤ
hn : α ^ n = Units.mk0 x hx
⊢ x ∈ F⟮↑α⟯

Next tactic:
rw [show x = α ^ n by norm_cast; rw [hn, Units.val_mk0]]
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
    simp only at hn
    rw [show x = α ^ n by 

Proof state:
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
n : ℤ
hn : α ^ n = Units.mk0 x hx
⊢ x = ↑α ^ n

Next tactic:
norm_cast
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
    simp only at hn
    rw [show x = α ^ n by norm_cast; 

Proof state:
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
n : ℤ
hn : α ^ n = Units.mk0 x hx
⊢ x = ↑(α ^ n)

Next tactic:
rw [hn, Units.val_mk0]
/-- **Primitive element theorem** assuming E is finite. -/
theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α⟯ = ⊤ := by
  obtain ⟨α, hα⟩ := @IsCyclic.exists_generator Eˣ _ _
  use α
  apply eq_top_iff.mpr
  rintro x -
  by_cases hx : x = 0
  · rw [hx]
    exact F⟮α.val⟯.zero_mem
  · obtain ⟨n, hn⟩ := Set.mem_range.mp (hα (Units.mk0 x hx))
    simp only at hn
    rw [show x = α ^ n by norm_cast; rw [hn, Units.val_mk0]]
    

Proof state:
case neg.intro
F : Type u_1
inst✝³ : Field F
E : Type u_2
inst✝² : Field E
inst✝¹ : Algebra F E
inst✝ : Finite E
α : Eˣ
hα : ∀ (x : Eˣ), x ∈ Subgroup.zpowers α
x : E
hx : ¬x = 0
n : ℤ
hn : α ^ n = Units.mk0 x hx
⊢ ↑α ^ n ∈ F⟮↑α⟯

Next tactic:
exact zpow_mem (mem_adjoin_simple_self F (E := E) ↑α) n
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  

Proof state:
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
let sf := (f.map ϕ).roots
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  

Proof state:
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
let sg := (g.map ϕ).roots
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  

Proof state:
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
  

Proof state:
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
s : Finset E := Multiset.toFinset (Multiset.bind sf fun α' => Multiset.map (fun β' => -(α' - α) / (β' - β)) sg)
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
let s' := s.preimage ϕ fun x _ y _ h => ϕ.injective h
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
  let s' := s.preimage ϕ fun x _ y _ h => ϕ.injective h
  

Proof state:
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
s : Finset E := Multiset.toFinset (Multiset.bind sf fun α' => Multiset.map (fun β' => -(α' - α) / (β' - β)) sg)
s' : Finset F := Finset.preimage s ⇑ϕ (_ : ∀ x ∈ ⇑ϕ ⁻¹' ↑s, ∀ y ∈ ⇑ϕ ⁻¹' ↑s, ϕ x = ϕ y → x = y)
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
obtain ⟨c, hc⟩ := Infinite.exists_not_mem_finset s'
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
  let s' := s.preimage ϕ fun x _ y _ h => ϕ.injective h
  obtain ⟨c, hc⟩ := Infinite.exists_not_mem_finset s'
  

Proof state:
case intro
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
s : Finset E := Multiset.toFinset (Multiset.bind sf fun α' => Multiset.map (fun β' => -(α' - α) / (β' - β)) sg)
s' : Finset F := Finset.preimage s ⇑ϕ (_ : ∀ x ∈ ⇑ϕ ⁻¹' ↑s, ∀ y ∈ ⇑ϕ ⁻¹' ↑s, ϕ x = ϕ y → x = y)
c : F
hc : c ∉ s'
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
simp_rw [Finset.mem_preimage, Multiset.mem_toFinset, Multiset.mem_bind, Multiset.mem_map] at hc
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
  let s' := s.preimage ϕ fun x _ y _ h => ϕ.injective h
  obtain ⟨c, hc⟩ := Infinite.exists_not_mem_finset s'
  simp_rw [Finset.mem_preimage, Multiset.mem_toFinset, Multiset.mem_bind, Multiset.mem_map] at hc
  

Proof state:
case intro
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
s : Finset E := Multiset.toFinset (Multiset.bind sf fun α' => Multiset.map (fun β' => -(α' - α) / (β' - β)) sg)
s' : Finset F := Finset.preimage s ⇑ϕ (_ : ∀ x ∈ ⇑ϕ ⁻¹' ↑s, ∀ y ∈ ⇑ϕ ⁻¹' ↑s, ϕ x = ϕ y → x = y)
c : F
hc : ¬∃ a ∈ roots (Polynomial.map ϕ f), ∃ a_1 ∈ roots (Polynomial.map ϕ g), -(a - α) / (a_1 - β) = ϕ c
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
push_neg at hc
theorem primitive_element_inf_aux_exists_c (f g : F[X]) :
    ∃ c : F, ∀ α' ∈ (f.map ϕ).roots, ∀ β' ∈ (g.map ϕ).roots, -(α' - α) / (β' - β) ≠ ϕ c := by
  let sf := (f.map ϕ).roots
  let sg := (g.map ϕ).roots
  let s := (sf.bind fun α' => sg.map fun β' => -(α' - α) / (β' - β)).toFinset
  let s' := s.preimage ϕ fun x _ y _ h => ϕ.injective h
  obtain ⟨c, hc⟩ := Infinite.exists_not_mem_finset s'
  simp_rw [Finset.mem_preimage, Multiset.mem_toFinset, Multiset.mem_bind, Multiset.mem_map] at hc
  push_neg at hc
  

Proof state:
case intro
F : Type u_1
inst✝² : Field F
inst✝¹ : Infinite F
E : Type u_2
inst✝ : Field E
ϕ : F →+* E
α β : E
f g : F[X]
sf : Multiset E := roots (Polynomial.map ϕ f)
sg : Multiset E := roots (Polynomial.map ϕ g)
s : Finset E := Multiset.toFinset (Multiset.bind sf fun α' => Multiset.map (fun β' => -(α' - α) / (β' - β)) sg)
s' : Finset F := Finset.preimage s ⇑ϕ (_ : ∀ x ∈ ⇑ϕ ⁻¹' ↑s, ∀ y ∈ ⇑ϕ ⁻¹' ↑s, ϕ x = ϕ y → x = y)
c : F
hc : ∀ a ∈ roots (Polynomial.map ϕ f), ∀ a_1 ∈ roots (Polynomial.map ϕ g), -(a - α) / (a_1 - β) ≠ ϕ c
⊢ ∃ c, ∀ α' ∈ roots (Polynomial.map ϕ f), ∀ β' ∈ roots (Polynomial.map ϕ g), -(α' - α) / (β' - β) ≠ ϕ c

Next tactic:
exact ⟨c, hc⟩
/-- This is the heart of the proof of the primitive element theorem. It shows that if `F` is
infinite and `α` and `β` are separable over `F` then `F⟮α, β⟯` is generated by a single element. -/
theorem primitive_element_inf_aux [IsSeparable F E] : ∃ γ : E, F⟮α, β⟯ = F⟮γ⟯ := by
  

Proof state:
F : Type u_1
inst✝⁴ : Field F
inst✝³ : Infinite F
E : Type u_2
inst✝² : Field E
ϕ : F →+* E
α β : E
inst✝¹ : Algebra F E
inst✝ : IsSeparable F E
⊢ ∃ γ, F⟮α, β⟯ = F⟮γ⟯

Next tactic:
have hα := IsSeparable.isIntegral F α