l3lab/ntp-mathlib huggingface dataset:
theorem AlgHom.fieldRange_of_normal [Algebra F K] {E : IntermediateField F K} [Normal F E]
    (f : E →ₐ[F] K) : f.fieldRange = E := by
-- Porting note: this was `IsScalarTower F E E := by infer_instance`.
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁹ : Field F
inst✝¹⁸ : Field K
inst✝¹⁷ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁶ : Field F
inst✝¹⁵ : Field K₁
inst✝¹⁴ : Field K₂
inst✝¹³ : Field K₃
inst✝¹² : Algebra F K₁
inst✝¹¹ : Algebra F K₂
inst✝¹⁰ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E✝ : Type u_6
inst✝⁹ : Field E✝
inst✝⁸ : Algebra F E✝
inst✝⁷ : Algebra E✝ K₁
inst✝⁶ : Algebra E✝ K₂
inst✝⁵ : Algebra E✝ K₃
inst✝⁴ : IsScalarTower F E✝ K₁
inst✝³ : IsScalarTower F E✝ K₂
inst✝² : IsScalarTower F E✝ K₃
inst✝¹ : Algebra F K
E : IntermediateField F K
inst✝ : Normal F ↥E
f : ↥E →ₐ[F] K
⊢ fieldRange f = E

Next tactic:
letI : Algebra E E := Algebra.id E
theorem AlgHom.fieldRange_of_normal [Algebra F K] {E : IntermediateField F K} [Normal F E]
    (f : E →ₐ[F] K) : f.fieldRange = E := by
-- Porting note: this was `IsScalarTower F E E := by infer_instance`.
  letI : Algebra E E := Algebra.id E
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁹ : Field F
inst✝¹⁸ : Field K
inst✝¹⁷ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁶ : Field F
inst✝¹⁵ : Field K₁
inst✝¹⁴ : Field K₂
inst✝¹³ : Field K₃
inst✝¹² : Algebra F K₁
inst✝¹¹ : Algebra F K₂
inst✝¹⁰ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E✝ : Type u_6
inst✝⁹ : Field E✝
inst✝⁸ : Algebra F E✝
inst✝⁷ : Algebra E✝ K₁
inst✝⁶ : Algebra E✝ K₂
inst✝⁵ : Algebra E✝ K₃
inst✝⁴ : IsScalarTower F E✝ K₁
inst✝³ : IsScalarTower F E✝ K₂
inst✝² : IsScalarTower F E✝ K₃
inst✝¹ : Algebra F K
E : IntermediateField F K
inst✝ : Normal F ↥E
f : ↥E →ₐ[F] K
this : Algebra ↥E ↥E := Algebra.id ↥E
⊢ fieldRange f = E

Next tactic:
let g := f.restrictNormal' E
theorem AlgHom.fieldRange_of_normal [Algebra F K] {E : IntermediateField F K} [Normal F E]
    (f : E →ₐ[F] K) : f.fieldRange = E := by
-- Porting note: this was `IsScalarTower F E E := by infer_instance`.
  letI : Algebra E E := Algebra.id E
  let g := f.restrictNormal' E
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁹ : Field F
inst✝¹⁸ : Field K
inst✝¹⁷ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁶ : Field F
inst✝¹⁵ : Field K₁
inst✝¹⁴ : Field K₂
inst✝¹³ : Field K₃
inst✝¹² : Algebra F K₁
inst✝¹¹ : Algebra F K₂
inst✝¹⁰ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E✝ : Type u_6
inst✝⁹ : Field E✝
inst✝⁸ : Algebra F E✝
inst✝⁷ : Algebra E✝ K₁
inst✝⁶ : Algebra E✝ K₂
inst✝⁵ : Algebra E✝ K₃
inst✝⁴ : IsScalarTower F E✝ K₁
inst✝³ : IsScalarTower F E✝ K₂
inst✝² : IsScalarTower F E✝ K₃
inst✝¹ : Algebra F K
E : IntermediateField F K
inst✝ : Normal F ↥E
f : ↥E →ₐ[F] K
this : Algebra ↥E ↥E := Algebra.id ↥E
g : ↥E ≃ₐ[F] ↥E := restrictNormal' f ↥E
⊢ fieldRange f = E

Next tactic:
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]
theorem AlgEquiv.restrictNormal_trans [Normal F E] :
    (χ.trans ω).restrictNormal E = (χ.restrictNormal E).trans (ω.restrictNormal E) :=
  AlgEquiv.ext fun _ =>
    (algebraMap E K₃).injective
      (by 

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
x✝ : E
⊢ (algebraMap E K₃) ((restrictNormal (trans χ ω) E) x✝) =
    (algebraMap E K₃) ((trans (restrictNormal χ E) (restrictNormal ω E)) x✝)

Next tactic:
simp only [AlgEquiv.trans_apply, AlgEquiv.restrictNormal_commutes]
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E →ₐ[F] K₁
⊢ (fun σ => AlgHom.comp (toAlgHom F E K₁) ↑σ) ((fun σ => AlgHom.restrictNormal' σ E) σ) = σ

Next tactic:
ext
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    

Proof state:
case H
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E →ₐ[F] K₁
x✝ : E
⊢ ((fun σ => AlgHom.comp (toAlgHom F E K₁) ↑σ) ((fun σ => AlgHom.restrictNormal' σ E) σ)) x✝ = σ x✝

Next tactic:
simp [AlgHom.restrictNormal']
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    simp [AlgHom.restrictNormal']
  right_inv σ := by
    

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E ≃ₐ[F] E
⊢ (fun σ => AlgHom.restrictNormal' σ E) ((fun σ => AlgHom.comp (toAlgHom F E K₁) ↑σ) σ) = σ

Next tactic:
ext
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    simp [AlgHom.restrictNormal']
  right_inv σ := by
    ext
    

Proof state:
case h
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E ≃ₐ[F] E
a✝ : E
⊢ ((fun σ => AlgHom.restrictNormal' σ E) ((fun σ => AlgHom.comp (toAlgHom F E K₁) ↑σ) σ)) a✝ = σ a✝

Next tactic:
simp only [AlgHom.restrictNormal', AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ofBijective]
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    simp [AlgHom.restrictNormal']
  right_inv σ := by
    ext
    simp only [AlgHom.restrictNormal', AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ofBijective]
    

Proof state:
case h
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E ≃ₐ[F] E
a✝ : E
⊢ (AlgHom.restrictNormal (AlgHom.comp (toAlgHom F E K₁) ↑σ) E) a✝ = σ a✝

Next tactic:
apply NoZeroSMulDivisors.algebraMap_injective E K₁
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    simp [AlgHom.restrictNormal']
  right_inv σ := by
    ext
    simp only [AlgHom.restrictNormal', AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ofBijective]
    apply NoZeroSMulDivisors.algebraMap_injective E K₁
    

Proof state:
case h.a
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E ≃ₐ[F] E
a✝ : E
⊢ (algebraMap E K₁) ((AlgHom.restrictNormal (AlgHom.comp (toAlgHom F E K₁) ↑σ) E) a✝) = (algebraMap E K₁) (σ a✝)

Next tactic:
rw [AlgHom.restrictNormal_commutes]
/-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an
 equivalence. -/
@[simps]
def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E where
  toFun σ := AlgHom.restrictNormal' σ E
  invFun σ := (IsScalarTower.toAlgHom F E K₁).comp σ.toAlgHom
  left_inv σ := by
    ext
    simp [AlgHom.restrictNormal']
  right_inv σ := by
    ext
    simp only [AlgHom.restrictNormal', AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ofBijective]
    apply NoZeroSMulDivisors.algebraMap_injective E K₁
    rw [AlgHom.restrictNormal_commutes]
    

Proof state:
case h.a
F : Type u_1
K : Type u_2
inst✝¹⁸ : Field F
inst✝¹⁷ : Field K
inst✝¹⁶ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K₁
inst✝¹³ : Field K₂
inst✝¹² : Field K₃
inst✝¹¹ : Algebra F K₁
inst✝¹⁰ : Algebra F K₂
inst✝⁹ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁸ : Field E
inst✝⁷ : Algebra F E
inst✝⁶ : Algebra E K₁
inst✝⁵ : Algebra E K₂
inst✝⁴ : Algebra E K₃
inst✝³ : IsScalarTower F E K₁
inst✝² : IsScalarTower F E K₂
inst✝¹ : IsScalarTower F E K₃
inst✝ : Normal F E
σ : E ≃ₐ[F] E
a✝ : E
⊢ (AlgHom.comp (toAlgHom F E K₁) ↑σ) ((algebraMap E E) a✝) = (algebraMap E K₁) (σ a✝)

Next tactic:
simp
/-- If `E/Kᵢ/F` are towers of fields with `E/F` normal then we can lift
  an algebra homomorphism `ϕ : K₁ →ₐ[F] K₂` to `ϕ.liftNormal E : E →ₐ[F] E`. -/
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.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
        ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
        (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 

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K
inst✝¹³ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹² : Field F
inst✝¹¹ : Field K₁
inst✝¹⁰ : Field K₂
inst✝⁹ : Field K₃
inst✝⁸ : Algebra F K₁
inst✝⁷ : Algebra F K₂
inst✝⁶ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : Algebra K₁ E
inst✝² : Algebra K₂ E
inst✝¹ : IsScalarTower F K₁ E
inst✝ : IsScalarTower F K₂ E
h : Normal F E
x : E
x✝ : x ∈ Set.univ
⊢ Splits (algebraMap K₁ E) (map (algebraMap F K₁) (minpoly F x))

Next tactic:
rw [splits_map_iff, ← @IsScalarTower.algebraMap_eq _ _ _ _ _ _ (_) (_) (_)]
/-- If `E/Kᵢ/F` are towers of fields with `E/F` normal then we can lift
  an algebra homomorphism `ϕ : K₁ →ₐ[F] K₂` to `ϕ.liftNormal E : E →ₐ[F] E`. -/
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.nonempty_algHom_of_adjoin_splits _ _ _ _ _ _ _
        ((IsScalarTower.toAlgHom F K₂ E).comp ϕ).toRingHom.toAlgebra _
        (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 _ _ _ _ _ _ (_) (_) (_)];
                

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K
inst✝¹³ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹² : Field F
inst✝¹¹ : Field K₁
inst✝¹⁰ : Field K₂
inst✝⁹ : Field K₃
inst✝⁸ : Algebra F K₁
inst✝⁷ : Algebra F K₂
inst✝⁶ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : Algebra K₁ E
inst✝² : Algebra K₂ E
inst✝¹ : IsScalarTower F K₁ E
inst✝ : IsScalarTower F K₂ E
h : Normal F E
x : E
x✝ : x ∈ Set.univ
⊢ Splits (algebraMap F E) (minpoly F x)

Next tactic:
exact (h.out x).2
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
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K
inst✝¹³ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹² : Field F
inst✝¹¹ : Field K₁
inst✝¹⁰ : Field K₂
inst✝⁹ : Field K₃
inst✝⁸ : Algebra F K₁
inst✝⁷ : Algebra F K₂
inst✝⁶ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : Algebra K₁ E
inst✝² : Algebra K₂ E
inst✝¹ : IsScalarTower F K₁ E
inst✝ : IsScalarTower F K₂ E
h : Normal F E
x y : E
⊢ minpoly F x = minpoly F y ↔ x ∈ MulAction.orbit (E ≃ₐ[F] E) y

Next tactic:
refine ⟨fun he ↦ ?_, fun ⟨f, he⟩ ↦ he ▸ minpoly.algEquiv_eq f y⟩
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⟩
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K
inst✝¹³ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹² : Field F
inst✝¹¹ : Field K₁
inst✝¹⁰ : Field K₂
inst✝⁹ : Field K₃
inst✝⁸ : Algebra F K₁
inst✝⁷ : Algebra F K₂
inst✝⁶ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : Algebra K₁ E
inst✝² : Algebra K₂ E
inst✝¹ : IsScalarTower F K₁ E
inst✝ : IsScalarTower F K₂ E
h : Normal F E
x y : E
he : minpoly F x = minpoly F y
⊢ x ∈ MulAction.orbit (E ≃ₐ[F] E) y

Next tactic:
obtain ⟨φ, hφ⟩ := exists_algHom_of_splits_of_aeval (normal_iff.mp h) (he ▸ minpoly.aeval F x)
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⟩
  obtain ⟨φ, hφ⟩ := exists_algHom_of_splits_of_aeval (normal_iff.mp h) (he ▸ minpoly.aeval F x)
  

Proof state:
case intro
F : Type u_1
K : Type u_2
inst✝¹⁵ : Field F
inst✝¹⁴ : Field K
inst✝¹³ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹² : Field F
inst✝¹¹ : Field K₁
inst✝¹⁰ : Field K₂
inst✝⁹ : Field K₃
inst✝⁸ : Algebra F K₁
inst✝⁷ : Algebra F K₂
inst✝⁶ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁵ : Field E
inst✝⁴ : Algebra F E
inst✝³ : Algebra K₁ E
inst✝² : Algebra K₂ E
inst✝¹ : IsScalarTower F K₁ E
inst✝ : IsScalarTower F K₂ E
h : Normal F E
x y : E
he : minpoly F x = minpoly F y
φ : E →ₐ[F] E
hφ : φ y = x
⊢ x ∈ MulAction.orbit (E ≃ₐ[F] E) y

Next tactic:
exact ⟨AlgEquiv.ofBijective φ (φ.normal_bijective F E E), hφ⟩
theorem isSolvable_of_isScalarTower [Normal F K₁] [h1 : IsSolvable (K₁ ≃ₐ[F] K₁)]
    [h2 : IsSolvable (E ≃ₐ[K₁] E)] : IsSolvable (E ≃ₐ[F] E) := by
  

Proof state:
F : Type u_1
K : Type u_2
inst✝¹⁶ : Field F
inst✝¹⁵ : Field K
inst✝¹⁴ : Algebra F K
K₁ : Type u_3
K₂ : Type u_4
K₃ : Type u_5
inst✝¹³ : Field F
inst✝¹² : Field K₁
inst✝¹¹ : Field K₂
inst✝¹⁰ : Field K₃
inst✝⁹ : Algebra F K₁
inst✝⁸ : Algebra F K₂
inst✝⁷ : Algebra F K₃
ϕ : K₁ →ₐ[F] K₂
χ : K₁ ≃ₐ[F] K₂
ψ : K₂ →ₐ[F] K₃
ω : K₂ ≃ₐ[F] K₃
E : Type u_6
inst✝⁶ : Field E
inst✝⁵ : Algebra F E
inst✝⁴ : Algebra K₁ E
inst✝³ : Algebra K₂ E
inst✝² : IsScalarTower F K₁ E
inst✝¹ : IsScalarTower F K₂ E
inst✝ : Normal F K₁
h1 : IsSolvable (K₁ ≃ₐ[F] K₁)
h2 : IsSolvable (E ≃ₐ[K₁] E)
⊢ IsSolvable (E ≃ₐ[F] E)

Next tactic:
let f : (E ≃ₐ[K₁] E) →* E ≃ₐ[F] E :=
    { toFun := fun ϕ =>
        AlgEquiv.ofAlgHom (ϕ.toAlgHom.restrictScalars F) (ϕ.symm.toAlgHom.restrictScalars F)
          (AlgHom.ext fun x => ϕ.apply_symm_apply x) (AlgHom.ext fun x => ϕ.symm_apply_apply x)
      map_one' := AlgEquiv.ext fun _ => rfl
      map_mul' := fun _ _ => AlgEquiv.ext fun _ => rfl }
theorem isUnit_iff_abs_eq {x : ℤ} : IsUnit x ↔ abs x = 1 := by
  

Proof state:
x : ℤ
⊢ IsUnit x ↔ |x| = 1

Next tactic:
rw [isUnit_iff_natAbs_eq, abs_eq_natAbs, ← Int.ofNat_one, coe_nat_inj']
theorem isUnit_sq {a : ℤ} (ha : IsUnit a) : a ^ 2 = 1 := by 

Proof state:
a : ℤ
ha : IsUnit a
⊢ a ^ 2 = 1

Next tactic:
rw [sq, isUnit_mul_self ha]
@[simp]
theorem units_sq (u : ℤˣ) : u ^ 2 = 1 := by
  

Proof state:
u : ℤˣ
⊢ u ^ 2 = 1

Next tactic:
rw [Units.ext_iff, Units.val_pow_eq_pow_val, Units.val_one, isUnit_sq u.isUnit]
@[simp]
theorem units_mul_self (u : ℤˣ) : u * u = 1 := by 

Proof state:
u : ℤˣ
⊢ u * u = 1

Next tactic:
rw [← sq, units_sq]
@[simp]
theorem units_inv_eq_self (u : ℤˣ) : u⁻¹ = u := by 

Proof state:
u : ℤˣ
⊢ u⁻¹ = u

Next tactic:
rw [inv_eq_iff_mul_eq_one, units_mul_self]
theorem units_div_eq_mul (u₁ u₂ : ℤˣ) : u₁ / u₂ = u₁ * u₂ := by
  

Proof state:
u₁ u₂ : ℤˣ
⊢ u₁ / u₂ = u₁ * u₂

Next tactic:
rw [div_eq_mul_inv, units_inv_eq_self]
@[simp]
theorem units_coe_mul_self (u : ℤˣ) : (u * u : ℤ) = 1 := by
  

Proof state:
u : ℤˣ
⊢ ↑u * ↑u = 1

Next tactic:
rw [← Units.val_mul, units_mul_self, Units.val_one]
theorem neg_one_pow_ne_zero {n : ℕ} : (-1 : ℤ) ^ n ≠ 0 := by 

Proof state:
n : ℕ
⊢ (-1) ^ n ≠ 0

Next tactic:
simp
theorem units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := by
  

Proof state:
u : ℤˣ
n : ℕ
⊢ u ^ n = u ^ (n % 2)

Next tactic:
conv =>
      lhs
      rw [← Nat.mod_add_div n 2];
      rw [pow_add, pow_mul, units_sq, one_pow, mul_one]
theorem units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := by
  conv =>
      

Proof state:
u : ℤˣ
n : ℕ
| u ^ n = u ^ (n % 2)

Next tactic:
lhs
      rw [← Nat.mod_add_div n 2];
      rw [pow_add, pow_mul, units_sq, one_pow, mul_one]
theorem units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := by
  conv =>
      

Proof state:
u : ℤˣ
n : ℕ
| u ^ n = u ^ (n % 2)

Next tactic:
lhs
theorem units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := by
  conv =>
      lhs
      

Proof state:
u : ℤˣ
n : ℕ
| u ^ n

Next tactic:
rw [← Nat.mod_add_div n 2]
theorem units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := by
  conv =>
      lhs
      rw [← Nat.mod_add_div n 2];
      

Proof state:
u : ℤˣ
n : ℕ
| u ^ (n % 2 + 2 * (n / 2))

Next tactic:
rw [pow_add, pow_mul, units_sq, one_pow, mul_one]
/-- A solution of a `LinearRecurrence` which satisfies certain initial conditions.
  We will prove this is the only such solution. -/
def mkSol (init : Fin E.order → α) : ℕ → α
  | n =>
    if h : n < E.order then init ⟨n, h⟩
    else
      ∑ k : Fin E.order,
        have _ : n - E.order + k < n := by
          

Proof state:
α : Type u_1
inst✝ : CommSemiring α
E : LinearRecurrence α
init : Fin E.order → α
x✝ : ℕ
n : ℕ := x✝
h : ¬n < E.order
k : Fin E.order
⊢ n - E.order + ↑k < n

Next tactic:
rw [add_comm, ← add_tsub_assoc_of_le (not_lt.mp h), tsub_lt_iff_left]
/-- A solution of a `LinearRecurrence` which satisfies certain initial conditions.
  We will prove this is the only such solution. -/
def mkSol (init : Fin E.order → α) : ℕ → α
  | n =>
    if h : n < E.order then init ⟨n, h⟩
    else
      ∑ k : Fin E.order,
        have _ : n - E.order + k < n := by
          rw [add_comm, ← add_tsub_assoc_of_le (not_lt.mp h), tsub_lt_iff_left]
          · 

Proof state:
α : Type u_1
inst✝ : CommSemiring α
E : LinearRecurrence α
init : Fin E.order → α
x✝ : ℕ
n : ℕ := x✝
h : ¬n < E.order
k : Fin E.order
⊢ ↑k + n < E.order + n

Next tactic:
exact add_lt_add_right k.is_lt n
/-- A solution of a `LinearRecurrence` which satisfies certain initial conditions.
  We will prove this is the only such solution. -/
def mkSol (init : Fin E.order → α) : ℕ → α
  | n =>
    if h : n < E.order then init ⟨n, h⟩
    else
      ∑ k : Fin E.order,
        have _ : n - E.order + k < n := by
          rw [add_comm, ← add_tsub_assoc_of_le (not_lt.mp h), tsub_lt_iff_left]
          · exact add_lt_add_right k.is_lt n
          · 

Proof state:
α : Type u_1
inst✝ : CommSemiring α
E : LinearRecurrence α
init : Fin E.order → α
x✝ : ℕ
n : ℕ := x✝
h : ¬n < E.order
k : Fin E.order
⊢ E.order ≤ ↑k + n

Next tactic:
convert add_le_add (zero_le (k : ℕ)) (not_lt.mp h)
/-- A solution of a `LinearRecurrence` which satisfies certain initial conditions.
  We will prove this is the only such solution. -/
def mkSol (init : Fin E.order → α) : ℕ → α
  | n =>
    if h : n < E.order then init ⟨n, h⟩
    else
      ∑ k : Fin E.order,
        have _ : n - E.order + k < n := by
          rw [add_comm, ← add_tsub_assoc_of_le (not_lt.mp h), tsub_lt_iff_left]
          · exact add_lt_add_right k.is_lt n
          · convert add_le_add (zero_le (k : ℕ)) (not_lt.mp h)
            

Proof state:
case h.e'_3
α : Type u_1
inst✝ : CommSemiring α
E : LinearRecurrence α
init : Fin E.order → α
x✝ : ℕ
n : ℕ := x✝
h : ¬n < E.order
k : Fin E.order
⊢ E.order = 0 + E.order

Next tactic:
simp only [zero_add]
/-- `E.mkSol` indeed gives solutions to `E`. -/
theorem is_sol_mkSol (init : Fin E.order → α) : E.IsSolution (E.mkSol init) := by
  

Proof state:
α : Type u_1
inst✝ : CommSemiring α
E : LinearRecurrence α
init : Fin E.order → α
⊢ IsSolution E (mkSol E init)

Next tactic:
intro n