l3lab/ntp-mathlib huggingface dataset:
variable (R) in
theorem mem_lift_of_splits_of_roots_mem_range [Algebra R K] {f : K[X]}
    (hs : f.Splits (RingHom.id K)) (hm : f.Monic) (hr : ∀ a ∈ f.roots, a ∈ (algebraMap R K).range) :
    f ∈ Polynomial.lifts (algebraMap R K) := by
  rw [eq_prod_roots_of_monic_of_splits_id hm hs, lifts_iff_liftsRing]
  refine' Subring.multiset_prod_mem _ _ fun P hP => _
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁴ : CommRing R
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Field F
i : K →+* L
inst✝ : Algebra R K
f : K[X]
hs : Splits (RingHom.id K) f
hm : Monic f
hr : ∀ a ∈ roots f, a ∈ RingHom.range (algebraMap R K)
P : K[X]
hP : P ∈ Multiset.map (fun a => X - C a) (roots f)
⊢ P ∈ liftsRing (algebraMap R K)

Next tactic:
obtain ⟨b, hb, rfl⟩ := Multiset.mem_map.1 hP
variable (R) in
theorem mem_lift_of_splits_of_roots_mem_range [Algebra R K] {f : K[X]}
    (hs : f.Splits (RingHom.id K)) (hm : f.Monic) (hr : ∀ a ∈ f.roots, a ∈ (algebraMap R K).range) :
    f ∈ Polynomial.lifts (algebraMap R K) := by
  rw [eq_prod_roots_of_monic_of_splits_id hm hs, lifts_iff_liftsRing]
  refine' Subring.multiset_prod_mem _ _ fun P hP => _
  obtain ⟨b, hb, rfl⟩ := Multiset.mem_map.1 hP
  

Proof state:
case intro.intro
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁴ : CommRing R
inst✝³ : Field K
inst✝² : Field L
inst✝¹ : Field F
i : K →+* L
inst✝ : Algebra R K
f : K[X]
hs : Splits (RingHom.id K) f
hm : Monic f
hr : ∀ a ∈ roots f, a ∈ RingHom.range (algebraMap R K)
b : K
hb : b ∈ roots f
hP : X - C b ∈ Multiset.map (fun a => X - C a) (roots f)
⊢ X - C b ∈ liftsRing (algebraMap R K)

Next tactic:
exact Subring.sub_mem _ (X_mem_lifts _) (C'_mem_lifts (hr _ hb))
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Irreducible p
hdp : p ∣ map i f
⊢ degree p = 1

Next tactic:
rw [irreducible_iff_prime] at hp
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ map i f
⊢ degree p = 1

Next tactic:
rw [hs, ← Multiset.prod_toList] at hdp
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
⊢ degree p = 1

Next tactic:
obtain hd | hd := hp.2.2 _ _ hdp
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · 

Proof state:
case inl
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd : p ∣ C (i (leadingCoeff f))
⊢ degree p = 1

Next tactic:
refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
        

Proof state:
case inl
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd : p ∣ C (i (leadingCoeff f))
⊢ IsUnit (C (i (leadingCoeff f)))

Next tactic:
exact isUnit_C.2 ((leadingCoeff_ne_zero.2 hf0).isUnit.map i)
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
        exact isUnit_C.2 ((leadingCoeff_ne_zero.2 hf0).isUnit.map i)
      · 

Proof state:
case inr
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd : p ∣ List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
⊢ degree p = 1

Next tactic:
obtain ⟨q, hq, hd⟩ := hp.dvd_prod_iff.1 hd
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
        exact isUnit_C.2 ((leadingCoeff_ne_zero.2 hf0).isUnit.map i)
      · obtain ⟨q, hq, hd⟩ := hp.dvd_prod_iff.1 hd
        

Proof state:
case inr.intro.intro
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd✝ : p ∣ List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
q : L[X]
hq : q ∈ Multiset.toList (Multiset.map (fun a => X - C a) s)
hd : p ∣ q
⊢ degree p = 1

Next tactic:
obtain ⟨a, _, rfl⟩ := Multiset.mem_map.1 (Multiset.mem_toList.1 hq)
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
        exact isUnit_C.2 ((leadingCoeff_ne_zero.2 hf0).isUnit.map i)
      · obtain ⟨q, hq, hd⟩ := hp.dvd_prod_iff.1 hd
        obtain ⟨a, _, rfl⟩ := Multiset.mem_map.1 (Multiset.mem_toList.1 hq)
        

Proof state:
case inr.intro.intro.intro.intro
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd✝ : p ∣ List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
a : L
left✝ : a ∈ s
hq : X - C a ∈ Multiset.toList (Multiset.map (fun a => X - C a) s)
hd : p ∣ X - C a
⊢ degree p = 1

Next tactic:
rw [degree_eq_degree_of_associated ((hp.dvd_prime_iff_associated <| prime_X_sub_C a).1 hd)]
theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L}
    (hs : f.map i = C (i f.leadingCoeff) * (s.map fun a : L => X - C a).prod) : Splits i f :=
  letI := Classical.decEq K
  if hf0 : f = 0 then hf0.symm ▸ splits_zero i
  else
    Or.inr @fun p hp hdp => by
      rw [irreducible_iff_prime] at hp
      rw [hs, ← Multiset.prod_toList] at hdp
      obtain hd | hd := hp.2.2 _ _ hdp
      · refine' (hp.2.1 <| isUnit_of_dvd_unit hd _).elim
        exact isUnit_C.2 ((leadingCoeff_ne_zero.2 hf0).isUnit.map i)
      · obtain ⟨q, hq, hd⟩ := hp.dvd_prod_iff.1 hd
        obtain ⟨a, _, rfl⟩ := Multiset.mem_map.1 (Multiset.mem_toList.1 hq)
        rw [degree_eq_degree_of_associated ((hp.dvd_prime_iff_associated <| prime_X_sub_C a).1 hd)]
        

Proof state:
case inr.intro.intro.intro.intro
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f : K[X]
s : Multiset L
hs : map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)
this : DecidableEq K := Classical.decEq K
hf0 : ¬f = 0
p : L[X]
hp : Prime p
hdp : p ∣ C (i (leadingCoeff f)) * List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
hd✝ : p ∣ List.prod (Multiset.toList (Multiset.map (fun a => X - C a) s))
a : L
left✝ : a ∈ s
hq : X - C a ∈ Multiset.toList (Multiset.map (fun a => X - C a) s)
hd : p ∣ X - C a
⊢ degree (X - C a) = 1

Next tactic:
exact degree_X_sub_C a
theorem splits_of_splits_id {f : K[X]} : Splits (RingHom.id K) f → Splits i f :=
  UniqueFactorizationMonoid.induction_on_prime f (fun _ => splits_zero _)
    (fun _ hu _ => splits_of_degree_le_one _ ((isUnit_iff_degree_eq_zero.1 hu).symm ▸ by 

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f x✝¹ : K[X]
hu : IsUnit x✝¹
x✝ : Splits (RingHom.id K) x✝¹
⊢ 0 ≤ 1

Next tactic:
decide
theorem splits_of_splits_id {f : K[X]} : Splits (RingHom.id K) f → Splits i f :=
  UniqueFactorizationMonoid.induction_on_prime f (fun _ => splits_zero _)
    (fun _ hu _ => splits_of_degree_le_one _ ((isUnit_iff_degree_eq_zero.1 hu).symm ▸ by decide))
    fun a p ha0 hp ih hfi =>
    splits_mul _
      (splits_of_degree_eq_one _
        ((splits_of_splits_mul _ (mul_ne_zero hp.1 ha0) hfi).1.def.resolve_left hp.1 hp.irreducible
          (by 

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
f a p : K[X]
ha0 : a ≠ 0
hp : Prime p
ih : Splits (RingHom.id K) a → Splits i a
hfi : Splits (RingHom.id K) (p * a)
⊢ p ∣ map (RingHom.id K) p

Next tactic:
rw [map_id]
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
roots_mem_range : ∀ a ∈ roots (map (RingHom.comp j i) f), a ∈ RingHom.range j
⊢ Splits i f

Next tactic:
choose lift lift_eq using roots_mem_range
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
⊢ Splits i f

Next tactic:
rw [splits_iff_exists_multiset]
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  rw [splits_iff_exists_multiset]
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
⊢ ∃ s, map i f = C (i (leadingCoeff f)) * Multiset.prod (Multiset.map (fun a => X - C a) s)

Next tactic:
refine ⟨(f.map (j.comp i)).roots.pmap lift fun _ ↦ id, map_injective _ j.injective ?_⟩
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  rw [splits_iff_exists_multiset]
  refine ⟨(f.map (j.comp i)).roots.pmap lift fun _ ↦ id, map_injective _ j.injective ?_⟩
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
⊢ map j (map i f) =
    map j
      (C (i (leadingCoeff f)) *
        Multiset.prod
          (Multiset.map (fun a => X - C a)
            (Multiset.pmap lift (roots (map (RingHom.comp j i) f))
              (_ : ∀ x ∈ roots (map (RingHom.comp j i) f), x ∈ roots (map (RingHom.comp j i) f)))))

Next tactic:
conv_lhs => rw [Polynomial.map_map, eq_prod_roots_of_splits h]
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  rw [splits_iff_exists_multiset]
  refine ⟨(f.map (j.comp i)).roots.pmap lift fun _ ↦ id, map_injective _ j.injective ?_⟩
  conv_lhs => 

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
| map j (map i f)

Next tactic:
rw [Polynomial.map_map, eq_prod_roots_of_splits h]
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  rw [splits_iff_exists_multiset]
  refine ⟨(f.map (j.comp i)).roots.pmap lift fun _ ↦ id, map_injective _ j.injective ?_⟩
  conv_lhs => rw [Polynomial.map_map, eq_prod_roots_of_splits h]
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
⊢ C ((RingHom.comp j i) (leadingCoeff f)) *
      Multiset.prod (Multiset.map (fun a => X - C a) (roots (map (RingHom.comp j i) f))) =
    map j
      (C (i (leadingCoeff f)) *
        Multiset.prod
          (Multiset.map (fun a => X - C a)
            (Multiset.pmap lift (roots (map (RingHom.comp j i) f))
              (_ : ∀ x ∈ roots (map (RingHom.comp j i) f), x ∈ roots (map (RingHom.comp j i) f)))))

Next tactic:
simp_rw [Polynomial.map_mul, Polynomial.map_multiset_prod, Multiset.map_pmap, Polynomial.map_sub,
    map_C, map_X, lift_eq, Multiset.pmap_eq_map]
theorem splits_of_comp (j : L →+* F) {f : K[X]} (h : Splits (j.comp i) f)
    (roots_mem_range : ∀ a ∈ (f.map (j.comp i)).roots, a ∈ j.range) : Splits i f := by
  choose lift lift_eq using roots_mem_range
  rw [splits_iff_exists_multiset]
  refine ⟨(f.map (j.comp i)).roots.pmap lift fun _ ↦ id, map_injective _ j.injective ?_⟩
  conv_lhs => rw [Polynomial.map_map, eq_prod_roots_of_splits h]
  simp_rw [Polynomial.map_mul, Polynomial.map_multiset_prod, Multiset.map_pmap, Polynomial.map_sub,
    map_C, map_X, lift_eq, Multiset.pmap_eq_map]
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝³ : CommRing R
inst✝² : Field K
inst✝¹ : Field L
inst✝ : Field F
i : K →+* L
j : L →+* F
f : K[X]
h : Splits (RingHom.comp j i) f
lift : (a : F) → a ∈ roots (map (RingHom.comp j i) f) → L
lift_eq : ∀ (a : F) (a_1 : a ∈ roots (map (RingHom.comp j i) f)), j (lift a a_1) = a
⊢ C ((RingHom.comp j i) (leadingCoeff f)) *
      Multiset.prod (Multiset.map (fun a => X - C a) (roots (map (RingHom.comp j i) f))) =
    C (j (i (leadingCoeff f))) * Multiset.prod (Multiset.map (fun a => X - C a) (roots (map (RingHom.comp j i) f)))

Next tactic:
rfl
theorem splits_of_algHom {f : R[X]} (h : Splits (algebraMap R K) f) (e : K →ₐ[R] L) :
    Splits (algebraMap R L) f := by
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
f : R[X]
h : Splits (algebraMap R K) f
e : K →ₐ[R] L
⊢ Splits (algebraMap R L) f

Next tactic:
rw [← e.comp_algebraMap_of_tower R]
theorem splits_of_algHom {f : R[X]} (h : Splits (algebraMap R K) f) (e : K →ₐ[R] L) :
    Splits (algebraMap R L) f := by
  rw [← e.comp_algebraMap_of_tower R]; 

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
f : R[X]
h : Splits (algebraMap R K) f
e : K →ₐ[R] L
⊢ Splits (RingHom.comp (↑e) (algebraMap R K)) f

Next tactic:
exact splits_comp_of_splits _ _ h
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  

Proof state:
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
⊢ Splits (RingHom.id K) p ↔ Multiset.card (roots p) = natDegree p

Next tactic:
constructor
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · 

Proof state:
case mp
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
⊢ Splits (RingHom.id K) p → Multiset.card (roots p) = natDegree p

Next tactic:
intro H
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · intro H
    

Proof state:
case mp
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
H : Splits (RingHom.id K) p
⊢ Multiset.card (roots p) = natDegree p

Next tactic:
rw [natDegree_eq_card_roots H, map_id]
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · intro H
    rw [natDegree_eq_card_roots H, map_id]
  · 

Proof state:
case mpr
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
⊢ Multiset.card (roots p) = natDegree p → Splits (RingHom.id K) p

Next tactic:
intro hroots
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · intro H
    rw [natDegree_eq_card_roots H, map_id]
  · intro hroots
    

Proof state:
case mpr
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
hroots : Multiset.card (roots p) = natDegree p
⊢ Splits (RingHom.id K) p

Next tactic:
rw [splits_iff_exists_multiset (RingHom.id K)]
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · intro H
    rw [natDegree_eq_card_roots H, map_id]
  · intro hroots
    rw [splits_iff_exists_multiset (RingHom.id K)]
    

Proof state:
case mpr
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
hroots : Multiset.card (roots p) = natDegree p
⊢ ∃ s, map (RingHom.id K) p = C ((RingHom.id K) (leadingCoeff p)) * Multiset.prod (Multiset.map (fun a => X - C a) s)

Next tactic:
use p.roots
/-- A polynomial splits if and only if it has as many roots as its degree. -/
theorem splits_iff_card_roots {p : K[X]} :
    Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by
  constructor
  · intro H
    rw [natDegree_eq_card_roots H, map_id]
  · intro hroots
    rw [splits_iff_exists_multiset (RingHom.id K)]
    use p.roots
    

Proof state:
case h
R : Type u_1
F : Type u
K : Type v
L : Type w
inst✝⁵ : CommRing R
inst✝⁴ : Field K
inst✝³ : Field L
inst✝² : Field F
i : K →+* L
inst✝¹ : Algebra R K
inst✝ : Algebra R L
p : K[X]
hroots : Multiset.card (roots p) = natDegree p
⊢ map (RingHom.id K) p = C ((RingHom.id K) (leadingCoeff p)) * Multiset.prod (Multiset.map (fun a => X - C a) (roots p))

Next tactic:
simp only [RingHom.id_apply, map_id]