l3lab/ntp-mathlib huggingface dataset:
theorem surjective_ofLocalizationSpan : OfLocalizationSpan surjective := by
  introv R hs H
  skip
  letI := f.toAlgebra
  show Function.Surjective (Algebra.ofId R S)
  rw [← Algebra.range_top_iff_surjective, eq_top_iff]
  rintro x -
  obtain ⟨l, hl⟩ :=
    (Finsupp.mem_span_iff_total R s 1).mp (show _ ∈ Ideal.span s by rw [hs]; trivial)
  fapply
    Subalgebra.mem_of_finset_sum_eq_one_of_pow_smul_mem _ l.support (fun x : s => f x) fun x : s =>
      f (l x)
  · simp_rw [← _root_.map_mul, ← map_sum, ← f.map_one]; exact f.congr_arg hl
  · exact fun _ => Set.mem_range_self _
  · exact fun _ => Set.mem_range_self _
  · intro r
    obtain ⟨y, hy⟩ := H r (IsLocalization.mk' _ x (1 : Submonoid.powers (f r)))
    obtain ⟨z, ⟨_, n, rfl⟩, rfl⟩ := IsLocalization.mk'_surjective (Submonoid.powers (r : R)) y
    erw [IsLocalization.map_mk', IsLocalization.eq] at hy
    obtain ⟨⟨_, m, rfl⟩, hm⟩ := hy
    refine' ⟨m + n, _⟩
    dsimp at hm ⊢
    simp_rw [_root_.one_mul, ← _root_.mul_assoc, ← map_pow, ← f.map_mul, ← pow_add, map_pow] at hm
    

Proof state:
case intro.H.intro.intro.intro.mk.intro.intro.mk.intro
R S : Type u_1
inst✝¹ : CommRing R
inst✝ : CommRing S
f : R →+* S
s : Set R
hs : Ideal.span s = ⊤
H : ∀ (r : ↑s), (fun {X Y} [CommRing X] [CommRing Y] f => Function.Surjective ⇑f) (Localization.awayMap f ↑r)
this : Algebra R S := toAlgebra f
x : S
l : ↑s →₀ R
hl : (Finsupp.total (↑s) R R Subtype.val) l = 1
r : ↑s
z : R
n m : ℕ
hm : f (↑r ^ m * z) = f ↑r ^ (m + n) * x
⊢ f ↑r ^ (m + n) * x ∈ AlgHom.range (Algebra.ofId R S)

Next tactic:
exact ⟨_, hm⟩
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
⊢ ∃ G, Injective G ∧ IsCoseparator G

Next tactic:
haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this : WellPowered C
⊢ ∃ G, Injective G ∧ IsCoseparator G

Next tactic:
haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
⊢ ∃ G, Injective G ∧ IsCoseparator G

Next tactic:
let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
⊢ ∃ G, Injective G ∧ IsCoseparator G

Next tactic:
refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
⊢ f = 0

Next tactic:
refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
⊢ h ≫ f = 0

Next tactic:
suffices hh : factorThruImage (h ≫ f) = 0
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
hh : factorThruImage (h ≫ f) = 0
⊢ h ≫ f = 0

Next tactic:
rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  

Proof state:
case hh
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
⊢ factorThruImage (h ≫ f) = 0

Next tactic:
let R := Subobject.mk (factorThruImage (h ≫ f)).op
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  let R := Subobject.mk (factorThruImage (h ≫ f)).op
  

Proof state:
case hh
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
R : Subobject (op G) := Subobject.mk (factorThruImage (h ≫ f)).op
⊢ factorThruImage (h ≫ f) = 0

Next tactic:
let q₁ : image (h ≫ f) ⟶ unop R :=
    (Subobject.underlyingIso (factorThruImage (h ≫ f)).op).unop.hom
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  let R := Subobject.mk (factorThruImage (h ≫ f)).op
  let q₁ : image (h ≫ f) ⟶ unop R :=
    (Subobject.underlyingIso (factorThruImage (h ≫ f)).op).unop.hom
  

Proof state:
case hh
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
R : Subobject (op G) := Subobject.mk (factorThruImage (h ≫ f)).op
q₁ : image (h ≫ f) ⟶ (Subobject.underlying.obj R).unop :=
  (Iso.unop (Subobject.underlyingIso (factorThruImage (h ≫ f)).op)).hom
⊢ factorThruImage (h ≫ f) = 0

Next tactic:
let q₂ : unop (R : Cᵒᵖ) ⟶ piObj fun P : Subobject (op G) => unop P :=
    section_ (Pi.π (fun P : Subobject (op G) => (unop P : C)) R)
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  let R := Subobject.mk (factorThruImage (h ≫ f)).op
  let q₁ : image (h ≫ f) ⟶ unop R :=
    (Subobject.underlyingIso (factorThruImage (h ≫ f)).op).unop.hom
  let q₂ : unop (R : Cᵒᵖ) ⟶ piObj fun P : Subobject (op G) => unop P :=
    section_ (Pi.π (fun P : Subobject (op G) => (unop P : C)) R)
  

Proof state:
case hh
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
R : Subobject (op G) := Subobject.mk (factorThruImage (h ≫ f)).op
q₁ : image (h ≫ f) ⟶ (Subobject.underlying.obj R).unop :=
  (Iso.unop (Subobject.underlyingIso (factorThruImage (h ≫ f)).op)).hom
q₂ : (Subobject.underlying.obj R).unop ⟶ ∏ fun P => (Subobject.underlying.obj P).unop :=
  section_ (Pi.π (fun P => (Subobject.underlying.obj P).unop) R)
⊢ factorThruImage (h ≫ f) = 0

Next tactic:
let q : image (h ≫ f) ⟶ T := q₁ ≫ q₂ ≫ Injective.ι _
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  let R := Subobject.mk (factorThruImage (h ≫ f)).op
  let q₁ : image (h ≫ f) ⟶ unop R :=
    (Subobject.underlyingIso (factorThruImage (h ≫ f)).op).unop.hom
  let q₂ : unop (R : Cᵒᵖ) ⟶ piObj fun P : Subobject (op G) => unop P :=
    section_ (Pi.π (fun P : Subobject (op G) => (unop P : C)) R)
  let q : image (h ≫ f) ⟶ T := q₁ ≫ q₂ ≫ Injective.ι _
  

Proof state:
case hh
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
R : Subobject (op G) := Subobject.mk (factorThruImage (h ≫ f)).op
q₁ : image (h ≫ f) ⟶ (Subobject.underlying.obj R).unop :=
  (Iso.unop (Subobject.underlyingIso (factorThruImage (h ≫ f)).op)).hom
q₂ : (Subobject.underlying.obj R).unop ⟶ ∏ fun P => (Subobject.underlying.obj P).unop :=
  section_ (Pi.π (fun P => (Subobject.underlying.obj P).unop) R)
q : image (h ≫ f) ⟶ T := q₁ ≫ q₂ ≫ Injective.ι (∏ fun P => (Subobject.underlying.obj P).unop)
⊢ factorThruImage (h ≫ f) = 0

Next tactic:
exact zero_of_comp_mono q
    (by rw [← Injective.comp_factorThru q (Limits.image.ι (h ≫ f)), Limits.image.fac_assoc,
      Category.assoc, hf, comp_zero])
theorem has_injective_coseparator [HasLimits C] [EnoughInjectives C] (G : C) (hG : IsSeparator G) :
    ∃ G : C, Injective G ∧ IsCoseparator G := by
  haveI : WellPowered C := wellPowered_of_isDetector G hG.isDetector
  haveI : HasProductsOfShape (Subobject (op G)) C := hasProductsOfShape_of_small _ _
  let T : C := Injective.under (piObj fun P : Subobject (op G) => unop P)
  refine' ⟨T, inferInstance, (Preadditive.isCoseparator_iff _).2 fun X Y f hf => _⟩
  refine' (Preadditive.isSeparator_iff _).1 hG _ fun h => _
  suffices hh : factorThruImage (h ≫ f) = 0
  · rw [← Limits.image.fac (h ≫ f), hh, zero_comp]
  let R := Subobject.mk (factorThruImage (h ≫ f)).op
  let q₁ : image (h ≫ f) ⟶ unop R :=
    (Subobject.underlyingIso (factorThruImage (h ≫ f)).op).unop.hom
  let q₂ : unop (R : Cᵒᵖ) ⟶ piObj fun P : Subobject (op G) => unop P :=
    section_ (Pi.π (fun P : Subobject (op G) => (unop P : C)) R)
  let q : image (h ≫ f) ⟶ T := q₁ ≫ q₂ ≫ Injective.ι _
  exact zero_of_comp_mono q
    (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasLimits C
inst✝ : EnoughInjectives C
G : C
hG : IsSeparator G
this✝ : WellPowered C
this : HasProductsOfShape (Subobject (op G)) C
T : C := Injective.under (∏ fun P => (Subobject.underlying.obj P).unop)
X Y : C
f : X ⟶ Y
hf : ∀ (h : Y ⟶ T), f ≫ h = 0
h : G ⟶ X
R : Subobject (op G) := Subobject.mk (factorThruImage (h ≫ f)).op
q₁ : image (h ≫ f) ⟶ (Subobject.underlying.obj R).unop :=
  (Iso.unop (Subobject.underlyingIso (factorThruImage (h ≫ f)).op)).hom
q₂ : (Subobject.underlying.obj R).unop ⟶ ∏ fun P => (Subobject.underlying.obj P).unop :=
  section_ (Pi.π (fun P => (Subobject.underlying.obj P).unop) R)
q : image (h ≫ f) ⟶ T := q₁ ≫ q₂ ≫ Injective.ι (∏ fun P => (Subobject.underlying.obj P).unop)
⊢ factorThruImage (h ≫ f) ≫ q = 0

Next tactic:
rw [← Injective.comp_factorThru q (Limits.image.ι (h ≫ f)), Limits.image.fac_assoc,
      Category.assoc, hf, comp_zero]
theorem has_projective_separator [HasColimits C] [EnoughProjectives C] (G : C)
    (hG : IsCoseparator G) : ∃ G : C, Projective G ∧ IsSeparator G := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasColimits C
inst✝ : EnoughProjectives C
G : C
hG : IsCoseparator G
⊢ ∃ G, Projective G ∧ IsSeparator G

Next tactic:
obtain ⟨T, hT₁, hT₂⟩ := has_injective_coseparator (op G) ((isSeparator_op_iff _).2 hG)
theorem has_projective_separator [HasColimits C] [EnoughProjectives C] (G : C)
    (hG : IsCoseparator G) : ∃ G : C, Projective G ∧ IsSeparator G := by
  obtain ⟨T, hT₁, hT₂⟩ := has_injective_coseparator (op G) ((isSeparator_op_iff _).2 hG)
  

Proof state:
case intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : Abelian C
inst✝¹ : HasColimits C
inst✝ : EnoughProjectives C
G : C
hG : IsCoseparator G
T : Cᵒᵖ
hT₁ : Injective T
hT₂ : IsCoseparator T
⊢ ∃ G, Projective G ∧ IsSeparator G

Next tactic:
exact ⟨unop T, inferInstance, (isSeparator_unop_iff _).2 hT₂⟩
theorem wittPolynomial_eq_sum_C_mul_X_pow (n : ℕ) :
    wittPolynomial p R n = ∑ i in range (n + 1), C ((p : R) ^ i) * X i ^ p ^ (n - i) := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝¹ : CommRing R
inst✝ : DecidableEq R
n : ℕ
⊢ wittPolynomial p R n = ∑ i in range (n + 1), C (↑p ^ i) * X i ^ p ^ (n - i)

Next tactic:
apply sum_congr rfl
theorem wittPolynomial_eq_sum_C_mul_X_pow (n : ℕ) :
    wittPolynomial p R n = ∑ i in range (n + 1), C ((p : R) ^ i) * X i ^ p ^ (n - i) := by
  apply sum_congr rfl
  

Proof state:
p : ℕ
R : Type u_1
inst✝¹ : CommRing R
inst✝ : DecidableEq R
n : ℕ
⊢ ∀ x ∈ range (n + 1), (monomial fun₀ | x => p ^ (n - x)) (↑p ^ x) = C (↑p ^ x) * X x ^ p ^ (n - x)

Next tactic:
rintro i -
theorem wittPolynomial_eq_sum_C_mul_X_pow (n : ℕ) :
    wittPolynomial p R n = ∑ i in range (n + 1), C ((p : R) ^ i) * X i ^ p ^ (n - i) := by
  apply sum_congr rfl
  rintro i -
  

Proof state:
p : ℕ
R : Type u_1
inst✝¹ : CommRing R
inst✝ : DecidableEq R
n i : ℕ
⊢ (monomial fun₀ | i => p ^ (n - i)) (↑p ^ i) = C (↑p ^ i) * X i ^ p ^ (n - i)

Next tactic:
rw [monomial_eq, Finsupp.prod_single_index]
theorem wittPolynomial_eq_sum_C_mul_X_pow (n : ℕ) :
    wittPolynomial p R n = ∑ i in range (n + 1), C ((p : R) ^ i) * X i ^ p ^ (n - i) := by
  apply sum_congr rfl
  rintro i -
  rw [monomial_eq, Finsupp.prod_single_index]
  

Proof state:
p : ℕ
R : Type u_1
inst✝¹ : CommRing R
inst✝ : DecidableEq R
n i : ℕ
⊢ X i ^ 0 = 1

Next tactic:
rw [pow_zero]
@[simp]
theorem map_wittPolynomial (f : R →+* S) (n : ℕ) : map f (W n) = W n := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
f : R →+* S
n : ℕ
⊢ (map f) (W_ R n) = W_ S n

Next tactic:
rw [wittPolynomial, map_sum, wittPolynomial]
@[simp]
theorem map_wittPolynomial (f : R →+* S) (n : ℕ) : map f (W n) = W n := by
  rw [wittPolynomial, map_sum, wittPolynomial]
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
f : R →+* S
n : ℕ
⊢ ∑ x in range (n + 1), (map f) ((monomial fun₀ | x => p ^ (n - x)) (↑p ^ x)) =
    ∑ i in range (n + 1), (monomial fun₀ | i => p ^ (n - i)) (↑p ^ i)

Next tactic:
refine sum_congr rfl fun i _ => ?_
@[simp]
theorem map_wittPolynomial (f : R →+* S) (n : ℕ) : map f (W n) = W n := by
  rw [wittPolynomial, map_sum, wittPolynomial]
  refine sum_congr rfl fun i _ => ?_
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
f : R →+* S
n i : ℕ
x✝ : i ∈ range (n + 1)
⊢ (map f) ((monomial fun₀ | i => p ^ (n - i)) (↑p ^ i)) = (monomial fun₀ | i => p ^ (n - i)) (↑p ^ i)

Next tactic:
rw [map_monomial, RingHom.map_pow, map_natCast]
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n : ℕ
⊢ constantCoeff (W_ R n) = 0

Next tactic:
simp only [wittPolynomial, map_sum, constantCoeff_monomial]
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  simp only [wittPolynomial, map_sum, constantCoeff_monomial]
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n : ℕ
⊢ (∑ x in range (n + 1), if (fun₀ | x => p ^ (n - x)) = 0 then ↑p ^ x else 0) = 0

Next tactic:
rw [sum_eq_zero]
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  simp only [wittPolynomial, map_sum, constantCoeff_monomial]
  rw [sum_eq_zero]
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n : ℕ
⊢ ∀ x ∈ range (n + 1), (if (fun₀ | x => p ^ (n - x)) = 0 then ↑p ^ x else 0) = 0

Next tactic:
rintro i _
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  simp only [wittPolynomial, map_sum, constantCoeff_monomial]
  rw [sum_eq_zero]
  rintro i _
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n i : ℕ
a✝ : i ∈ range (n + 1)
⊢ (if (fun₀ | i => p ^ (n - i)) = 0 then ↑p ^ i else 0) = 0

Next tactic:
rw [if_neg]
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  simp only [wittPolynomial, map_sum, constantCoeff_monomial]
  rw [sum_eq_zero]
  rintro i _
  rw [if_neg]
  

Proof state:
case hnc
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n i : ℕ
a✝ : i ∈ range (n + 1)
⊢ ¬(fun₀ | i => p ^ (n - i)) = 0

Next tactic:
rw [Finsupp.single_eq_zero]
@[simp]
theorem constantCoeff_wittPolynomial [hp : Fact p.Prime] (n : ℕ) :
    constantCoeff (wittPolynomial p R n) = 0 := by
  simp only [wittPolynomial, map_sum, constantCoeff_monomial]
  rw [sum_eq_zero]
  rintro i _
  rw [if_neg]
  rw [Finsupp.single_eq_zero]
  

Proof state:
case hnc
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
hp : Fact (Nat.Prime p)
n i : ℕ
a✝ : i ∈ range (n + 1)
⊢ ¬p ^ (n - i) = 0

Next tactic:
exact ne_of_gt (pow_pos hp.1.pos _)
@[simp]
theorem wittPolynomial_zero : wittPolynomial p R 0 = X 0 := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
⊢ W_ R 0 = X 0

Next tactic:
simp only [wittPolynomial, X, sum_singleton, range_one, pow_zero, zero_add, tsub_self]
@[simp]
theorem wittPolynomial_one : wittPolynomial p R 1 = C (p : R) * X 1 + X 0 ^ p := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
⊢ W_ R 1 = C ↑p * X 1 + X 0 ^ p

Next tactic:
simp only [wittPolynomial_eq_sum_C_mul_X_pow, sum_range_succ_comm, range_one, sum_singleton,
    one_mul, pow_one, C_1, pow_zero, tsub_self, tsub_zero]
theorem aeval_wittPolynomial {A : Type*} [CommRing A] [Algebra R A] (f : ℕ → A) (n : ℕ) :
    aeval f (W_ R n) = ∑ i in range (n + 1), (p : A) ^ i * f i ^ p ^ (n - i) := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝⁴ : CommRing R
inst✝³ : DecidableEq R
S : Type u_2
inst✝² : CommRing S
A : Type u_3
inst✝¹ : CommRing A
inst✝ : Algebra R A
f : ℕ → A
n : ℕ
⊢ (aeval f) (W_ R n) = ∑ i in range (n + 1), ↑p ^ i * f i ^ p ^ (n - i)

Next tactic:
simp [wittPolynomial, AlgHom.map_sum, aeval_monomial, Finsupp.prod_single_index]
/-- Over the ring `ZMod (p^(n+1))`, we produce the `n+1`st Witt polynomial
by expanding the `n`th Witt polynomial by `p`.
-/
@[simp]
theorem wittPolynomial_zmod_self (n : ℕ) :
    W_ (ZMod (p ^ (n + 1))) (n + 1) = expand p (W_ (ZMod (p ^ (n + 1))) n) := by
  

Proof state:
p : ℕ
R : Type u_1
inst✝² : CommRing R
inst✝¹ : DecidableEq R
S : Type u_2
inst✝ : CommRing S
n : ℕ
⊢ W_ (ZMod (p ^ (n + 1))) (n + 1) = (expand p) (W_ (ZMod (p ^ (n + 1))) n)

Next tactic:
simp only [wittPolynomial_eq_sum_C_mul_X_pow]