l3lab/ntp-mathlib huggingface dataset:
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  

Proof state:
case neg
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg : (restrictProd p q) f = (restrictProd p q) g
⊢ f = g

Next tactic:
classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
  · haveI : Fact (q.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_left q p)⟩
    have key :
      x =
        algebraMap q.SplittingField (p * q).SplittingField
          ((rootsEquivRoots q _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots q _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.2 _)
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  

Proof state:
case neg
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg : (restrictProd p q) f = (restrictProd p q) g
⊢ f = g

Next tactic:
simp only [restrictProd, restrictDvd_def] at hfg
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  

Proof state:
case neg
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (MonoidHom.prod (if hq : p * q = 0 then 1 else restrict p (SplittingField (p * q)))
        (if hq : p * q = 0 then 1 else restrict q (SplittingField (p * q))))
      f =
    (MonoidHom.prod (if hq : p * q = 0 then 1 else restrict p (SplittingField (p * q)))
        (if hq : p * q = 0 then 1 else restrict q (SplittingField (p * q))))
      g
⊢ f = g

Next tactic:
simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  

Proof state:
case neg
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
⊢ f = g

Next tactic:
ext (x hx)
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  

Proof state:
case neg.h
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ rootSet (p * q) (SplittingField (p * q))
⊢ f x = g x

Next tactic:
rw [rootSet_def, aroots_mul hpq] at hx
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  

Proof state:
case neg.h
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
⊢ f x = g x

Next tactic:
cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · 

Proof state:
case neg.h.inl
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots p (SplittingField (p * q))
⊢ f x = g x

Next tactic:
haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    

Proof state:
case neg.h.inl
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots p (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) p)
⊢ f x = g x

Next tactic:
have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    

Proof state:
case neg.h.inl
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots p (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) p)
key :
  x =
    (algebraMap (SplittingField p) (SplittingField (p * q)))
      ↑(Equiv.invFun (rootsEquivRoots p (SplittingField (p * q)))
          { val := x, property := (_ : x ∈ Multiset.toFinset (aroots p (SplittingField (p * q)))) })
⊢ f x = g x

Next tactic:
rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    

Proof state:
case neg.h.inl
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots p (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) p)
key :
  x =
    (algebraMap (SplittingField p) (SplittingField (p * q)))
      ↑(Equiv.invFun (rootsEquivRoots p (SplittingField (p * q)))
          { val := x, property := (_ : x ∈ Multiset.toFinset (aroots p (SplittingField (p * q)))) })
⊢ (algebraMap (SplittingField p) (SplittingField (p * q)))
      ((AlgEquiv.restrictNormal f (SplittingField p))
        ↑(Equiv.invFun (rootsEquivRoots p (SplittingField (p * q)))
            { val := x, property := (_ : x ∈ Multiset.toFinset (aroots p (SplittingField (p * q)))) })) =
    (algebraMap (SplittingField p) (SplittingField (p * q)))
      ((AlgEquiv.restrictNormal g (SplittingField p))
        ↑(Equiv.invFun (rootsEquivRoots p (SplittingField (p * q)))
            { val := x, property := (_ : x ∈ Multiset.toFinset (aroots p (SplittingField (p * q)))) }))

Next tactic:
exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
  · 

Proof state:
case neg.h.inr
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots q (SplittingField (p * q))
⊢ f x = g x

Next tactic:
haveI : Fact (q.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_left q p)⟩
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
  · haveI : Fact (q.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_left q p)⟩
    

Proof state:
case neg.h.inr
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots q (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) q)
⊢ f x = g x

Next tactic:
have key :
      x =
        algebraMap q.SplittingField (p * q).SplittingField
          ((rootsEquivRoots q _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots q _) ⟨x, _⟩).symm
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
  · haveI : Fact (q.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_left q p)⟩
    have key :
      x =
        algebraMap q.SplittingField (p * q).SplittingField
          ((rootsEquivRoots q _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots q _) ⟨x, _⟩).symm
    

Proof state:
case neg.h.inr
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots q (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) q)
key :
  x =
    (algebraMap (SplittingField q) (SplittingField (p * q)))
      ↑(Equiv.invFun (rootsEquivRoots q (SplittingField (p * q)))
          { val := x, property := (_ : x ∈ Multiset.toFinset (aroots q (SplittingField (p * q)))) })
⊢ f x = g x

Next tactic:
rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
/-- `Polynomial.Gal.restrictProd` is actually a subgroup embedding. -/
theorem restrictProd_injective : Function.Injective (restrictProd p q) := by
  by_cases hpq : p * q = 0
  · have : Unique (p * q).Gal := by rw [hpq]; infer_instance
    exact fun f g _ => Eq.trans (Unique.eq_default f) (Unique.eq_default g).symm
  intro f g hfg
  classical
  simp only [restrictProd, restrictDvd_def] at hfg
  simp only [dif_neg hpq, MonoidHom.prod_apply, Prod.mk.inj_iff] at hfg
  ext (x hx)
  rw [rootSet_def, aroots_mul hpq] at hx
  cases' Multiset.mem_add.mp (Multiset.mem_toFinset.mp hx) with h h
  · haveI : Fact (p.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_right p q)⟩
    have key :
      x =
        algebraMap p.SplittingField (p * q).SplittingField
          ((rootsEquivRoots p _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots p _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.1 _)
  · haveI : Fact (q.Splits (algebraMap F (p * q).SplittingField)) :=
      ⟨splits_of_splits_of_dvd _ hpq (SplittingField.splits (p * q)) (dvd_mul_left q p)⟩
    have key :
      x =
        algebraMap q.SplittingField (p * q).SplittingField
          ((rootsEquivRoots q _).invFun
            ⟨x, (@Multiset.mem_toFinset _ (Classical.decEq _) _ _).mpr h⟩) :=
      Subtype.ext_iff.mp (Equiv.apply_symm_apply (rootsEquivRoots q _) ⟨x, _⟩).symm
    rw [key, ← AlgEquiv.restrictNormal_commutes, ← AlgEquiv.restrictNormal_commutes]
    

Proof state:
case neg.h.inr
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
hpq : ¬p * q = 0
f g : Gal (p * q)
hfg :
  (restrict p (SplittingField (p * q))) f = (restrict p (SplittingField (p * q))) g ∧
    (restrict q (SplittingField (p * q))) f = (restrict q (SplittingField (p * q))) g
x : SplittingField (p * q)
hx : x ∈ ↑(Multiset.toFinset (aroots p (SplittingField (p * q)) + aroots q (SplittingField (p * q))))
h : x ∈ aroots q (SplittingField (p * q))
this : Fact (Splits (algebraMap F (SplittingField (p * q))) q)
key :
  x =
    (algebraMap (SplittingField q) (SplittingField (p * q)))
      ↑(Equiv.invFun (rootsEquivRoots q (SplittingField (p * q)))
          { val := x, property := (_ : x ∈ Multiset.toFinset (aroots q (SplittingField (p * q)))) })
⊢ (algebraMap (SplittingField q) (SplittingField (p * q)))
      ((AlgEquiv.restrictNormal f (SplittingField q))
        ↑(Equiv.invFun (rootsEquivRoots q (SplittingField (p * q)))
            { val := x, property := (_ : x ∈ Multiset.toFinset (aroots q (SplittingField (p * q)))) })) =
    (algebraMap (SplittingField q) (SplittingField (p * q)))
      ((AlgEquiv.restrictNormal g (SplittingField q))
        ↑(Equiv.invFun (rootsEquivRoots q (SplittingField (p * q)))
            { val := x, property := (_ : x ∈ Multiset.toFinset (aroots q (SplittingField (p * q)))) }))

Next tactic:
exact congr_arg _ (AlgEquiv.ext_iff.mp hfg.2 _)
theorem mul_splits_in_splittingField_of_mul {p₁ q₁ p₂ q₂ : F[X]} (hq₁ : q₁ ≠ 0) (hq₂ : q₂ ≠ 0)
    (h₁ : p₁.Splits (algebraMap F q₁.SplittingField))
    (h₂ : p₂.Splits (algebraMap F q₂.SplittingField)) :
    (p₁ * p₂).Splits (algebraMap F (q₁ * q₂).SplittingField) := by
  

Proof state:
F : Type u_1
inst✝² : Field F
p q : F[X]
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
p₁ q₁ p₂ q₂ : F[X]
hq₁ : q₁ ≠ 0
hq₂ : q₂ ≠ 0
h₁ : Splits (algebraMap F (SplittingField q₁)) p₁
h₂ : Splits (algebraMap F (SplittingField q₂)) p₂
⊢ Splits (algebraMap F (SplittingField (q₁ * q₂))) (p₁ * p₂)

Next tactic:
apply splits_mul