Fermat's Last Theorem in Lean 4

← all definition modules

Definitions/Def_MvFormalGroup_CartierModuleWittAction.lean

definition module

Witt vector action on Cartier modules of formal groups

Fix a prime p and a commutative ring R. The first half of the module produces, for each Witt vector w \in W(R), the family of polynomials giving multiplication by w on the Witt formal group. Writing \mathrm{cVec}\,w for the image of w under the coefficientwise map C \colon R \to R[X_0,X_1,\dots], the polynomial mulPoly p w n is the n-th Witt coordinate of the product of \mathrm{cVec}\,w with the tautological Witt vector (X_0,X_1,\dots), i.e. the Witt multiplication polynomial M_n(w_0,\dots,w_n;X_0,\dots,X_n); mulFam p w is the induced family of power series in R[[X_0,X_1,\dots]]. Its basic identities are established: additivity in w through the Witt addition polynomials, multiplicativity as composition of families, w=1 giving X_n, w=0 giving 0, value C(w_0)X_0 in degree 0, and C(a^{p^n})X_n for a Teichmüller representative (this last resting on WittVector.teichmuller_mul_coeff, proved for Witt vectors over an arbitrary commutative ring: ([a]\cdot y)_n = a^{p^n}y_n). Each mulPoly p w n is weighted homogeneous of degree p^n for the weights m \mapsto p^m; hence it has zero constant term and the family is substitutable, and isEndo_mulFam records that mulFam p w satisfies the project's predicate IsEndo p, namely substitutability, vanishing constant terms, and compatibility with the Witt addition family.

The second half uses this to define, for a commutative formal group law \Phi of dimension d over R, the additive endomorphism wittSMul w of CartierModule p Φ by precomposition with mulFam p w, and registers the resulting Module (WittVector p R) (CartierModule p Φ) instance; on the defining power series, (w \bullet f)_j = f_j(w \cdot X). The relations with the other operators are then proved: Teichmüller representatives act as the homotheties of the companion module, homotheties commute with the action, natural number scalars agree with the additive \mathbb{N}-action, F(w \bullet f) = \sigma(w) \bullet F f, w \bullet Vf = V(\sigma(w) \bullet f) and, over a perfect ring of characteristic p, V(w \bullet f) = \sigma^{-1}(w) \bullet Vf, together with VF = p in the module sense. Homomorphisms of formal groups induce W(R)-linear maps (mapLinear), the endomorphism action commutes with the Witt action, the tangent map satisfies \mathrm{tangent}(w \bullet f) = w_0 \cdot \mathrm{tangent}(f) (with a supporting lemma computing the degree-one coefficient of a substitution into a weight-graded family), and on the linear curves of the examples namespace the action is w \bullet \mathrm{addLinear}(v) = \mathrm{addLinear}(w_0 v).

Relation to Mathlib

Mathlib supplies the Witt vectors with their ring structure, Teichmüller representatives, Frobenius, Verschiebung and the IsPoly/IsPoly₂ machinery used here; the auxiliary lemmas WittVector.teichmuller_mul_coeff, WittVector.mk_coeff_eq, WittVector.map_peval and WittVector.peval_X are additions to that namespace. The Cartier module of a multivariate formal group law and its Witt vector module structure are the project's own.

Where it is used

The W(R)-module structure makes the Cartier module of a commutative formal group law an object of W(R)-linear algebra, with F semilinear for the Frobenius of W(R) and V for its inverse; this is the form in which Dieudonné-theoretic statements about formal groups are used in the study of special formal modules entering the construction of the relevant Shimura-type objects.

References

  1. M. Hazewinkel, Formal Groups and Applications, Pure and Applied Mathematics 78, Academic Press, 1978
  2. T. Zink, Cartiertheorie kommutativer formaler Gruppen, Teubner-Texte zur Mathematik 68, Teubner, 1984

References are suggested automatically and have not been individually verified.

English text generated automatically from the Lean source; the Lean statement is authoritative.

Source file: Definitions/Def_MvFormalGroup_CartierModuleWittAction.lean

Imports

Imported by

Declarations

Source

import Mathlib
import Definitions.Def_MvFormalGroup_NegV2
import Definitions.Def_MvFormalGroup_CartierModule
import Definitions.Def_MvFormalGroup_CartierModuleHomothety

set_option autoImplicit false

noncomputable section

universe u

open MvPolynomial in

theorem WittVector.teichmuller_mul_coeff (p : ℕ) [hp : Fact p.Prime] {A : Type u} [CommRing A]
    (a : A) (y : WittVector p A) (n : ℕ) :
    (WittVector.teichmuller p a * y).coeff n = a ^ p ^ n * y.coeff n := by

  let f : ∀ ⦃S : Type u⦄ [CommRing S], WittVector p S → WittVector p S → WittVector p S :=
    fun S _ x y => WittVector.teichmuller p (x.coeff 0) * y
  let g : ∀ ⦃S : Type u⦄ [CommRing S], WittVector p S → WittVector p S → WittVector p S :=
    fun S _ x y => WittVector.mk p fun n => x.coeff 0 ^ p ^ n * y.coeff n
  have hteich : WittVector.IsPoly p fun S _ (x : WittVector p S) =>
      WittVector.teichmuller p (x.coeff 0) := by
    refine ⟨⟨fun n => if n = 0 then X 0 else 0, ?_⟩⟩
    intro S _ x
    funext n
    cases n with
    | zero => simp [WittVector.teichmuller_coeff_zero]
    | succ n => simp [WittVector.teichmuller_coeff_pos p _ _ (Nat.succ_pos n)]
  have hf : WittVector.IsPoly₂ p f :=
    @WittVector.IsPoly₂.comp p _ _ _ WittVector.mulIsPoly₂ hteich (WittVector.idIsPolyI' p)
  have hg : WittVector.IsPoly₂ p g := by
    refine ⟨⟨fun n => X ((0 : Fin 2), 0) ^ p ^ n * X ((1 : Fin 2), n), ?_⟩⟩
    intro S _ x y
    funext n
    simp [g, WittVector.peval, Function.uncurry]
  have key := WittVector.IsPoly₂.ext hf hg (fun S _ x y n => by
    simp only [f, g, map_mul, WittVector.ghostComponent_teichmuller]
    rw [WittVector.ghostComponent_apply, WittVector.ghostComponent_apply, aeval_wittPolynomial,
      aeval_wittPolynomial, Finset.mul_sum]
    refine Finset.sum_congr rfl fun i hi => ?_
    have hi' : i ≤ n := Nat.lt_succ_iff.mp (Finset.mem_range.mp hi)
    simp only [WittVector.coeff_mk]
    rw [mul_pow, ← pow_mul, ← pow_add, Nat.add_sub_cancel' hi']
    ring) A (WittVector.mk p fun n => if n = 0 then a else 0) y
  have h0 : (WittVector.mk p fun n => if n = 0 then a else (0 : A)).coeff 0 = a := by simp
  simp only [f, g, h0] at key
  rw [key, WittVector.coeff_mk]

namespace MvFormalGroup

open MvPowerSeries WittLaw

theorem _root_.WittVector.mk_coeff_eq {p : ℕ} {A : Type*} [CommRing A] (x : WittVector p A) :
    WittVector.mk p (fun m => x.coeff m) = x := by
  ext m; rfl

theorem _root_.WittVector.map_peval {k : ℕ} {A B : Type*} [CommRing A] [CommRing B]
    {F : Type*} [FunLike F A B] [RingHomClass F A B]
    (φ : F) (Q : MvPolynomial (Fin k × ℕ) ℤ) (x : Fin k → ℕ → A) :
    φ (WittVector.peval Q x) = WittVector.peval Q fun i m => φ (x i m) := by
  unfold WittVector.peval
  let φ' : A →+* B := RingHomClass.toRingHom φ
  show φ' _ = _
  let ψ₁ : MvPolynomial (Fin k × ℕ) ℤ →+* B := φ'.comp (MvPolynomial.aeval (Function.uncurry x)).toRingHom
  let ψ₂ : MvPolynomial (Fin k × ℕ) ℤ →+* B :=
    (MvPolynomial.aeval (Function.uncurry fun i m => φ (x i m))).toRingHom
  have hψ : ψ₁ = ψ₂ := by
    refine MvPolynomial.ringHom_ext (fun r => ?_) (fun im => ?_)
    · exact RingHom.congr_fun (RingHom.ext_int (ψ₁.comp MvPolynomial.C) (ψ₂.comp MvPolynomial.C)) r
    · rcases im with ⟨i, m⟩
      simp [ψ₁, ψ₂, φ', Function.uncurry]
  exact RingHom.congr_fun hψ Q

theorem _root_.WittVector.peval_X {k : ℕ} (R : Type*) [CommRing R]
    (Q : MvPolynomial (Fin k × ℕ) ℤ) :
    WittVector.peval Q (fun i m => (MvPolynomial.X (i, m) : MvPolynomial (Fin k × ℕ) R)) =
      MvPolynomial.map (Int.castRingHom R) Q := by
  unfold WittVector.peval
  let ψ₁ : MvPolynomial (Fin k × ℕ) ℤ →+* MvPolynomial (Fin k × ℕ) R :=
    (MvPolynomial.aeval (Function.uncurry fun i m =>
      (MvPolynomial.X (i, m) : MvPolynomial (Fin k × ℕ) R))).toRingHom
  have hψ : ψ₁ = MvPolynomial.map (Int.castRingHom R) := by
    refine MvPolynomial.ringHom_ext (fun r => ?_) (fun im => ?_)
    · exact RingHom.congr_fun (RingHom.ext_int (ψ₁.comp MvPolynomial.C)
        ((MvPolynomial.map (Int.castRingHom R)).comp MvPolynomial.C)) r
    · rcases im with ⟨i, m⟩
      simp [ψ₁, Function.uncurry]
  exact RingHom.congr_fun hψ Q

namespace WittLaw

variable (p : ℕ) [hp : Fact p.Prime] {R : Type u} [CommRing R]

abbrev cVec {τ : Type} (w : WittVector p R) : WittVector p (MvPolynomial τ R) :=
  WittVector.map (MvPolynomial.C : R →+* MvPolynomial τ R) w

def mulPoly (w : WittVector p R) (n : ℕ) : MvPolynomial ℕ R :=
  (cVec p w * WittVector.mk p (MvPolynomial.X : ℕ → MvPolynomial ℕ R)).coeff n

def mulFam (w : WittVector p R) : ℕ → MvPowerSeries ℕ R := fun n => (mulPoly p w n : MvPowerSeries ℕ R)

variable {p}

@[simp] theorem mulFam_apply (w : WittVector p R) (n : ℕ) :
    mulFam p w n = (mulPoly p w n : MvPowerSeries ℕ R) := rfl

omit hp in

theorem coe_aeval {σ τ : Type*} (y : σ → MvPolynomial τ R) (P : MvPolynomial σ R) :
    ((MvPolynomial.aeval y P : MvPolynomial τ R) : MvPowerSeries τ R) =
      subst (fun i => (y i : MvPowerSeries τ R)) (P : MvPowerSeries σ R) := by
  rw [subst_coe]
  let ψ₁ : MvPolynomial σ R →ₐ[R] MvPowerSeries τ R :=
    (MvPolynomial.coeToMvPowerSeries.algHom R).comp (MvPolynomial.aeval y)
  let ψ₂ : MvPolynomial σ R →ₐ[R] MvPowerSeries τ R :=
    MvPolynomial.aeval fun i => (y i : MvPowerSeries τ R)
  have hψ : ψ₁ = ψ₂ := MvPolynomial.algHom_ext fun i => by simp [ψ₁, ψ₂]
  exact AlgHom.congr_fun hψ P

omit hp in

theorem coe_peval {k : ℕ} {τ : Type*} (Q : MvPolynomial (Fin k × ℕ) ℤ) (x : Fin k → ℕ → MvPolynomial τ R) :
    subst (fun im : Fin k × ℕ => (x im.1 im.2 : MvPowerSeries τ R))
      ((MvPolynomial.map (Int.castRingHom R) Q : MvPolynomial (Fin k × ℕ) R) :
        MvPowerSeries (Fin k × ℕ) R) =
      ((WittVector.peval Q x : MvPolynomial τ R) : MvPowerSeries τ R) := by
  rw [subst_coe]
  unfold WittVector.peval
  let ψ₁ : MvPolynomial (Fin k × ℕ) ℤ →+* MvPowerSeries τ R :=
    (MvPolynomial.aeval fun im : Fin k × ℕ => (x im.1 im.2 : MvPowerSeries τ R)).toRingHom.comp
      (MvPolynomial.map (Int.castRingHom R))
  let ψ₂ : MvPolynomial (Fin k × ℕ) ℤ →+* MvPowerSeries τ R :=
    (MvPolynomial.coeToMvPowerSeries.ringHom (σ := τ) (R := R)).comp
      (MvPolynomial.aeval (Function.uncurry x)).toRingHom
  have hψ : ψ₁ = ψ₂ := by
    refine MvPolynomial.ringHom_ext (fun r => ?_) (fun im => ?_)
    · exact RingHom.congr_fun (RingHom.ext_int (ψ₁.comp MvPolynomial.C) (ψ₂.comp MvPolynomial.C)) r
    · rcases im with ⟨i, m⟩
      simp [ψ₁, ψ₂, Function.uncurry]
  exact RingHom.congr_fun hψ Q

@[simp] theorem cVec_coeff {τ : Type} (w : WittVector p R) (m : ℕ) :
    (cVec p (τ := τ) w).coeff m = MvPolynomial.C (w.coeff m) :=
  WittVector.map_coeff _ _ _

@[simp] theorem cVec_add {τ : Type} (w₁ w₂ : WittVector p R) :
    cVec p (τ := τ) (w₁ + w₂) = cVec p w₁ + cVec p w₂ := map_add _ _ _

@[simp] theorem cVec_mul {τ : Type} (w₁ w₂ : WittVector p R) :
    cVec p (τ := τ) (w₁ * w₂) = cVec p w₁ * cVec p w₂ := map_mul _ _ _

@[simp] theorem cVec_one {τ : Type} : cVec p (τ := τ) (1 : WittVector p R) = 1 := map_one _

@[simp] theorem cVec_zero {τ : Type} : cVec p (τ := τ) (0 : WittVector p R) = 0 := map_zero _

theorem mulPoly_eq_peval (w : WittVector p R) (n : ℕ) :
    mulPoly p w n = WittVector.peval (WittVector.wittMul p n)
      ![fun m => MvPolynomial.C (w.coeff m), MvPolynomial.X] := by
  rw [mulPoly, WittVector.mul_coeff]
  congr 1

theorem aeval_mulPoly {τ : Type} (w : WittVector p R) (y : ℕ → MvPolynomial τ R) (n : ℕ) :
    MvPolynomial.aeval y (mulPoly p w n) = (cVec p w * WittVector.mk p y).coeff n := by
  rw [mulPoly, WittVector.mul_coeff, WittVector.mul_coeff,
    WittVector.map_peval (MvPolynomial.aeval y : MvPolynomial ℕ R →ₐ[R] MvPolynomial τ R)]
  congr 1
  funext i m
  fin_cases i
  · show MvPolynomial.aeval y ((cVec p (τ := ℕ) w).coeff m) = (cVec p (τ := τ) w).coeff m
    rw [cVec_coeff, cVec_coeff, MvPolynomial.aeval_C]
    rfl
  · show MvPolynomial.aeval y ((WittVector.mk p MvPolynomial.X).coeff m) = (WittVector.mk p y).coeff m
    rw [WittVector.coeff_mk, WittVector.coeff_mk, MvPolynomial.aeval_X]

theorem mulPoly_add (w₁ w₂ : WittVector p R) (n : ℕ) :
    mulPoly p (w₁ + w₂) n = WittVector.peval (WittVector.wittAdd p n) ![mulPoly p w₁, mulPoly p w₂] := by
  rw [mulPoly, cVec_add, add_mul, WittVector.add_coeff]
  rfl

theorem mulPoly_mul (w₁ w₂ : WittVector p R) (n : ℕ) :
    mulPoly p (w₁ * w₂) n = MvPolynomial.aeval (mulPoly p w₂) (mulPoly p w₁ n) := by
  rw [aeval_mulPoly, mulPoly, cVec_mul, mul_assoc]
  show _ = (cVec p w₁ * WittVector.mk p (fun m =>
    (cVec p w₂ * WittVector.mk p (MvPolynomial.X : ℕ → MvPolynomial ℕ R)).coeff m)).coeff n
  rw [WittVector.mk_coeff_eq]

theorem mulPoly_one (n : ℕ) : mulPoly p (1 : WittVector p R) n = MvPolynomial.X n := by
  rw [mulPoly, cVec_one, one_mul, WittVector.coeff_mk]

theorem mulPoly_zero (n : ℕ) : mulPoly p (0 : WittVector p R) n = 0 := by
  rw [mulPoly, cVec_zero, zero_mul, WittVector.zero_coeff]

theorem mulPoly_at_zero (w : WittVector p R) :
    mulPoly p w 0 = MvPolynomial.C (w.coeff 0) * MvPolynomial.X 0 := by
  rw [mulPoly, WittVector.mul_coeff_zero, cVec_coeff, WittVector.coeff_mk]

theorem mulPoly_teichmuller (a : R) (n : ℕ) :
    mulPoly p (WittVector.teichmuller p a) n = MvPolynomial.C (a ^ p ^ n) * MvPolynomial.X n := by
  rw [mulPoly, cVec, WittVector.map_teichmuller, WittVector.teichmuller_mul_coeff,
    WittVector.coeff_mk, map_pow]

def verPoly (R : Type u) [CommRing R] : ℕ → MvPolynomial ℕ R
  | 0 => 0
  | n + 1 => MvPolynomial.X n

omit hp in
@[simp] theorem verPoly_zero : verPoly R 0 = 0 := rfl

omit hp in
@[simp] theorem verPoly_succ (n : ℕ) : verPoly R (n + 1) = MvPolynomial.X n := rfl

omit hp in
theorem coe_verPoly (n : ℕ) : (verPoly R n : MvPowerSeries ℕ R) = verFam R n := by
  cases n with
  | zero => exact MvPolynomial.coe_zero
  | succ n => exact MvPolynomial.coe_X _

theorem frobenius_cVec {τ : Type} (w : WittVector p R) :
    WittVector.frobenius (cVec p (τ := τ) w) = cVec p (WittVector.frobenius w) :=
  (WittVector.IsPoly.map (WittVector.frobenius_isPoly p) _ w).symm

theorem aeval_verPoly_mulPoly (w : WittVector p R) (n : ℕ) :
    MvPolynomial.aeval (verPoly R) (mulPoly p w n) =
      Nat.casesOn n 0 fun k => mulPoly p (WittVector.frobenius w) k := by
  rw [aeval_mulPoly]
  have hV : WittVector.mk p (verPoly R) =
      WittVector.verschiebung (WittVector.mk p (MvPolynomial.X : ℕ → MvPolynomial ℕ R)) := by
    refine WittVector.ext fun m => ?_
    cases m with
    | zero => rw [WittVector.coeff_mk, WittVector.verschiebung_coeff_zero]; rfl
    | succ m => rw [WittVector.coeff_mk, WittVector.verschiebung_coeff_succ, WittVector.coeff_mk]; rfl
  rw [hV, mul_comm, ← WittVector.verschiebung_mul_frobenius, mul_comm, frobenius_cVec]
  cases n with
  | zero => exact WittVector.verschiebung_coeff_zero _
  | succ k => rw [WittVector.verschiebung_coeff_succ]; rfl

theorem mulPoly_pow_char [CharP R p] (w : WittVector p R) (n : ℕ) :
    mulPoly p w n ^ p =
      MvPolynomial.aeval (fun m => (MvPolynomial.X m : MvPolynomial ℕ R) ^ p)
        (mulPoly p (WittVector.frobenius w) n) := by
  rw [aeval_mulPoly, mulPoly, ← WittVector.coeff_frobenius_charP, map_mul, frobenius_cVec]
  congr 2
  refine WittVector.ext fun m => ?_
  rw [WittVector.coeff_frobenius_charP, WittVector.coeff_mk, WittVector.coeff_mk]

omit hp in

theorem isWeightedHomogeneous_peval_C_X {N : ℕ} {Q : MvPolynomial (Fin 2 × ℕ) ℤ}
    (hQ : MvPolynomial.IsWeightedHomogeneous (weight p ![0, 1]) Q N) (c : ℕ → R) :
    MvPolynomial.IsWeightedHomogeneous (fun m => p ^ m)
      (WittVector.peval Q ![fun m => MvPolynomial.C (c m), (MvPolynomial.X : ℕ → MvPolynomial ℕ R)])
      N := by
  classical
  unfold WittVector.peval
  set g : Fin 2 × ℕ → MvPolynomial ℕ R :=
    Function.uncurry ![fun m => MvPolynomial.C (c m), (MvPolynomial.X : ℕ → MvPolynomial ℕ R)]
    with hg
  rw [MvPolynomial.as_sum Q, map_sum]
  refine MvPolynomial.IsWeightedHomogeneous.sum _ _ _ fun e he => ?_
  have hwe : Finsupp.weight (weight p ![0, 1]) e = N := hQ (MvPolynomial.mem_support_iff.mp he)
  rw [MvPolynomial.aeval_monomial, eq_intCast, ← map_intCast (MvPolynomial.C (σ := ℕ) (R := R))]
  have hprod : MvPolynomial.IsWeightedHomogeneous (fun m => p ^ m)
      (e.prod fun im k => g im ^ k) N := by
    rw [Finsupp.prod, ← hwe, Finsupp.weight_apply, Finsupp.sum]
    refine MvPolynomial.IsWeightedHomogeneous.prod _ _ _ fun im _ => ?_
    rcases im with ⟨i, m⟩
    fin_cases i
    ·
      have h := (MvPolynomial.isWeightedHomogeneous_C (fun m => p ^ m) (c m)).pow (e (0, m))
      simp only [smul_zero] at h
      simpa [g, weight] using h
    · have h := (MvPolynomial.isWeightedHomogeneous_X (R := R) (fun m => p ^ m) m).pow (e (1, m))
      simpa [g, weight, smul_eq_mul, mul_comm] using h
  have := (MvPolynomial.isWeightedHomogeneous_C (fun m => p ^ m)
    ((MvPolynomial.coeff e Q : ℤ) : R)).mul hprod
  rwa [zero_add] at this

theorem isWeightedHomogeneous_mulPoly (w : WittVector p R) (n : ℕ) :
    MvPolynomial.IsWeightedHomogeneous (fun m => p ^ m) (mulPoly p w n) (p ^ n) := by
  rw [mulPoly_eq_peval]
  exact isWeightedHomogeneous_peval_C_X (isWeightedHomogeneous_wittMul p n) _

theorem weight_eq_of_coeff_mulFam_ne_zero (w : WittVector p R) {n : ℕ} {e : ℕ →₀ ℕ}
    (h : coeff e (mulFam p w n) ≠ 0) : Finsupp.weight (fun m => p ^ m) e = p ^ n := by
  rw [mulFam_apply, MvPolynomial.coeff_coe] at h
  exact isWeightedHomogeneous_mulPoly w n h

theorem constantCoeff_mulFam (w : WittVector p R) (n : ℕ) : (mulFam p w n).constantCoeff = 0 := by
  by_contra h
  have h' : coeff (0 : ℕ →₀ ℕ) (mulFam p w n) ≠ 0 := by
    rwa [coeff_zero_eq_constantCoeff_apply]
  have hw := weight_eq_of_coeff_mulFam_ne_zero w h'
  rw [map_zero] at hw
  exact absurd hw.symm (pow_ne_zero n hp.out.ne_zero)

theorem constantCoeff_mulPoly (w : WittVector p R) (n : ℕ) :
    MvPolynomial.constantCoeff (mulPoly p w n) = 0 := by
  have h := constantCoeff_mulFam w n
  rwa [mulFam_apply, ← coeff_zero_eq_constantCoeff_apply, MvPolynomial.coeff_coe,
    ← MvPolynomial.constantCoeff_eq] at h

theorem hasSubst_mulFam (w : WittVector p R) : HasSubst (mulFam p w) := by
  refine ⟨fun n => by rw [constantCoeff_mulFam]; exact IsNilpotent.zero, fun e => ?_⟩
  refine (Set.finite_lt_nat (Finsupp.weight (fun m => p ^ m) e)).subset fun n hn => ?_
  have hw := weight_eq_of_coeff_mulFam_ne_zero w hn
  show n < Finsupp.weight (fun m => p ^ m) e
  rw [hw]
  exact Nat.lt_pow_self hp.out.one_lt

def xVec (R : Type u) [CommRing R] (i : Fin 2) : WittVector p (MvPolynomial (Fin 2 × ℕ) R) :=
  WittVector.mk p fun m => MvPolynomial.X (i, m)

def addPolyR (R : Type u) [CommRing R] (m : ℕ) : MvPolynomial (Fin 2 × ℕ) R :=
  MvPolynomial.map (Int.castRingHom R) (WittVector.wittAdd p m)

theorem coe_addPolyR (m : ℕ) :
    (addPolyR (p := p) R m : MvPowerSeries (Fin 2 × ℕ) R) = addFam p R m := rfl

omit hp in
@[simp] theorem xVec_coeff (i : Fin 2) (m : ℕ) :
    (xVec (p := p) R i).coeff m = MvPolynomial.X (i, m) := rfl

theorem xVec_add : xVec (p := p) R 0 + xVec R 1 = WittVector.mk p (addPolyR (p := p) R) := by
  refine WittVector.ext fun m => ?_
  rw [WittVector.add_coeff]
  show WittVector.peval (WittVector.wittAdd p m) ![(xVec (p := p) R 0).coeff, (xVec (p := p) R 1).coeff] =
    addPolyR (p := p) R m
  rw [addPolyR, ← WittVector.peval_X R (WittVector.wittAdd p m)]
  congr 1
  funext i k
  fin_cases i <;> rfl

theorem pairFam_mulFam (w : WittVector p R) :
    pairFam (mulFam p w) = fun im : Fin 2 × ℕ =>
      (((cVec p w * xVec R im.1).coeff im.2 : MvPolynomial (Fin 2 × ℕ) R) :
        MvPowerSeries (Fin 2 × ℕ) R) := by
  funext ⟨i, m⟩
  rw [pairFam_apply, mulFam_apply, xVec, ← aeval_mulPoly, coe_aeval]
  congr 1
  funext k
  exact (MvPolynomial.coe_X _).symm

theorem subst_addFam_mulFam (w : WittVector p R) (n : ℕ) :
    subst (addFam p R) (mulFam p w n) =
      (((cVec p w * (xVec R 0 + xVec R 1)).coeff n : MvPolynomial (Fin 2 × ℕ) R) :
        MvPowerSeries (Fin 2 × ℕ) R) := by
  have h : addFam p R = fun i => (addPolyR (p := p) R i : MvPowerSeries (Fin 2 × ℕ) R) := rfl
  rw [h, mulFam_apply, ← coe_aeval, aeval_mulPoly, xVec_add]

theorem isEndo_mulFam (w : WittVector p R) : IsEndo p (mulFam p w) := by
  refine ⟨hasSubst_mulFam w, constantCoeff_mulFam w, fun n => ?_⟩

  have hR : subst (pairFam (mulFam p w)) (addFam p R n) =
      (((cVec p w * xVec R 0 + cVec p w * xVec R 1).coeff n : MvPolynomial (Fin 2 × ℕ) R) :
        MvPowerSeries (Fin 2 × ℕ) R) := by
    have key := coe_peval (R := R) (WittVector.wittAdd p n)
      (fun i m => (cVec p w * xVec (p := p) R i).coeff m)
    rw [WittVector.add_coeff, pairFam_mulFam, ← coe_addPolyR, addPolyR]
    refine key.trans ?_
    congr 2
    funext i
    fin_cases i <;> rfl
  rw [subst_addFam_mulFam, hR, mul_add]

theorem subst_mulFam_mulFam (w₁ w₂ : WittVector p R) (n : ℕ) :
    subst (mulFam p w₂) (mulFam p w₁ n) = mulFam p (w₁ * w₂) n := by
  rw [mulFam_apply, mulFam_apply, mulPoly_mul, coe_aeval]
  rfl

theorem mulFam_add (w₁ w₂ : WittVector p R) (n : ℕ) :
    mulFam p (w₁ + w₂) n = subst (fun im : Fin 2 × ℕ =>
      (Fin.cases (mulFam p w₁ im.2) (fun _ => mulFam p w₂ im.2) im.1 : MvPowerSeries ℕ R))
        (addFam p R n) := by
  have hfun : (fun im : Fin 2 × ℕ =>
      (Fin.cases (mulFam p w₁ im.2) (fun _ => mulFam p w₂ im.2) im.1 : MvPowerSeries ℕ R)) =
      fun im : Fin 2 × ℕ => ((![mulPoly p w₁, mulPoly p w₂] im.1 im.2 : MvPolynomial ℕ R) :
        MvPowerSeries ℕ R) := by
    funext ⟨i, m⟩
    fin_cases i <;> rfl
  rw [hfun, addFam, coe_peval, mulFam_apply, mulPoly_add]

theorem mulFam_one : mulFam p (1 : WittVector p R) = fun n => X n := by
  funext n
  rw [mulFam_apply, mulPoly_one, MvPolynomial.coe_X]

theorem mulFam_zero : mulFam p (0 : WittVector p R) = fun _ => 0 := by
  funext n
  rw [mulFam_apply, mulPoly_zero, MvPolynomial.coe_zero]

theorem mulFam_teichmuller (a : R) : mulFam p (WittVector.teichmuller p a) = teichFam p a := by
  funext n
  rw [mulFam_apply, mulPoly_teichmuller, MvPolynomial.coe_mul, MvPolynomial.coe_C,
    MvPolynomial.coe_X, teichFam_apply, smul_eq_C_mul]

theorem subst_verFam_mulFam (w : WittVector p R) (n : ℕ) :
    subst (verFam R) (mulFam p w n) =
      subst (mulFam p (WittVector.frobenius w)) (verFam R n) := by
  have hv : (verFam R) = fun m => (verPoly R m : MvPowerSeries ℕ R) := funext fun m => (coe_verPoly m).symm
  rw [mulFam_apply, hv, ← coe_aeval, aeval_verPoly_mulPoly]
  cases n with
  | zero =>
    show ((0 : MvPolynomial ℕ R) : MvPowerSeries ℕ R) = subst _ ((verPoly R 0 : MvPolynomial ℕ R) : MvPowerSeries ℕ R)
    rw [verPoly_zero, MvPolynomial.coe_zero, ← coe_substAlgHom (hasSubst_mulFam _), map_zero]
  | succ k =>
    show ((mulPoly p (WittVector.frobenius w) k : MvPolynomial ℕ R) : MvPowerSeries ℕ R) =
      subst _ ((verPoly R (k + 1) : MvPolynomial ℕ R) : MvPowerSeries ℕ R)
    rw [verPoly_succ, MvPolynomial.coe_X, subst_X (hasSubst_mulFam _), mulFam_apply]

theorem subst_mulFam_frobFam [CharP R p] (w : WittVector p R) (n : ℕ) :
    subst (mulFam p w) (frobFam p R n) =
      subst (frobFam p R) (mulFam p (WittVector.frobenius w) n) := by
  rw [frobFam_apply, subst_pow (hasSubst_mulFam w), subst_X (hasSubst_mulFam w), mulFam_apply,
    ← MvPolynomial.coe_pow, mulPoly_pow_char, coe_aeval, mulFam_apply]
  congr 1
  funext m
  rw [MvPolynomial.coe_pow, MvPolynomial.coe_X, frobFam_apply]

end WittLaw

namespace CartierModule

variable {p : ℕ} [hp : Fact p.Prime] {d d' : ℕ} {R : Type u} [CommRing R]
variable {Φ : MvFormalGroup d R} {Φ' : MvFormalGroup d' R}

def wittSMul [Φ.IsComm] (w : WittVector p R) : CartierModule p Φ →+ CartierModule p Φ :=
  precomp (WittLaw.isEndo_mulFam w)

@[simp] theorem toPowerSeries_wittSMul [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) :
    (wittSMul w f).toPowerSeries = fun j => subst (WittLaw.mulFam p w) (f.toPowerSeries j) := rfl

theorem wittSMul_one [Φ.IsComm] (f : CartierModule p Φ) : wittSMul (1 : WittVector p R) f = f := by
  apply CartierModule.ext
  funext j
  rw [toPowerSeries_wittSMul, WittLaw.mulFam_one]
  exact congrFun subst_self _

theorem wittSMul_zero_left [Φ.IsComm] (f : CartierModule p Φ) :
    wittSMul (0 : WittVector p R) f = 0 := by
  apply CartierModule.ext
  funext j
  rw [toPowerSeries_wittSMul, WittLaw.mulFam_zero]
  exact subst_zero_of_constantCoeff_eq_zero (f.constantCoeff_eq_zero j)

theorem wittSMul_mul [Φ.IsComm] (w₁ w₂ : WittVector p R) (f : CartierModule p Φ) :
    wittSMul (w₁ * w₂) f = wittSMul w₁ (wittSMul w₂ f) := by
  apply CartierModule.ext
  funext j
  show (precomp _ f).toPowerSeries j = (precomp _ (precomp _ f)).toPowerSeries j
  rw [precomp_precomp, toPowerSeries_precomp]
  show subst (WittLaw.mulFam p (w₁ * w₂)) (f.toPowerSeries j) = _
  congr 1
  funext n
  rw [WittLaw.subst_mulFam_mulFam, mul_comm]

theorem wittSMul_add_left [Φ.IsComm] (w₁ w₂ : WittVector p R) (f : CartierModule p Φ) :
    wittSMul (w₁ + w₂) f = wittSMul w₁ f + wittSMul w₂ f := by
  apply CartierModule.ext
  funext j
  have hf := f.constantCoeff_eq_zero
  have hS : HasSubst (fun im : Fin 2 × ℕ => (Fin.cases (WittLaw.mulFam p w₁ im.2)
      (fun _ => WittLaw.mulFam p w₂ im.2) im.1 : MvPowerSeries ℕ R)) :=
    WittLaw.hasSubst_finCases (WittLaw.hasSubst_mulFam w₁) (WittLaw.hasSubst_mulFam w₂)
  have hfam : WittLaw.mulFam p (w₁ + w₂) = fun k => subst (fun im : Fin 2 × ℕ =>
      (Fin.cases (WittLaw.mulFam p w₁ im.2) (fun _ => WittLaw.mulFam p w₂ im.2) im.1 :
        MvPowerSeries ℕ R)) (WittLaw.addFam p R k) :=
    funext (WittLaw.mulFam_add w₁ w₂)
  rw [toPowerSeries_wittSMul, toPowerSeries_add]
  show subst (WittLaw.mulFam p (w₁ + w₂)) (f.toPowerSeries j) = _
  rw [hfam, ← subst_comp_subst_apply (hasSubst_addFam p R) hS, f.subst_addFam,
    subst_subst_elim Φ (constantCoeff_inBlk 0 hf) (constantCoeff_inBlk 1 hf) hS]
  congr 1
  funext s
  rcases s with l | l
  · show subst _ (subst (blk 0) (f.toPowerSeries l)) = (wittSMul w₁ f).toPowerSeries l
    rw [subst_comp_subst_apply (hasSubst_blk 0) hS]
    congr 1
    funext m
    exact subst_X hS ((0 : Fin 2), m)
  · show subst _ (subst (blk 1) (f.toPowerSeries l)) = (wittSMul w₂ f).toPowerSeries l
    rw [subst_comp_subst_apply (hasSubst_blk 1) hS]
    congr 1
    funext m
    exact subst_X hS ((1 : Fin 2), m)

instance instModuleWittVector [Φ.IsComm] : Module (WittVector p R) (CartierModule p Φ) where
  smul w f := wittSMul w f
  one_smul := wittSMul_one
  mul_smul := wittSMul_mul
  smul_zero w := map_zero (wittSMul w)
  smul_add w := map_add (wittSMul w)
  add_smul := wittSMul_add_left
  zero_smul := wittSMul_zero_left

theorem smul_def [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) : w • f = wittSMul w f := rfl

theorem smul_eq_precomp [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) :
    w • f = precomp (WittLaw.isEndo_mulFam w) f := rfl

@[simp] theorem toPowerSeries_smul_witt [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) :
    (w • f).toPowerSeries = fun j => subst (WittLaw.mulFam p w) (f.toPowerSeries j) := rfl

theorem teichmuller_smul [Φ.IsComm] (a : R) (f : CartierModule p Φ) :
    WittVector.teichmuller p a • f = homothety a f := by
  apply CartierModule.ext
  funext j
  rw [toPowerSeries_smul_witt, toPowerSeries_homothety, WittLaw.mulFam_teichmuller]

theorem homothety_smul_witt [Φ.IsComm] (a : R) (w : WittVector p R) (f : CartierModule p Φ) :
    homothety a (w • f) = w • homothety a f := by
  rw [← teichmuller_smul, ← teichmuller_smul, smul_smul, smul_smul, mul_comm]

theorem natCast_smul_eq_nsmul' [Φ.IsComm] (n : ℕ) (f : CartierModule p Φ) :
    (n : WittVector p R) • f = n • f :=
  Nat.cast_smul_eq_nsmul _ n f

theorem frobenius_smul [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) :
    frobenius (w • f) = WittVector.frobenius w • frobenius f := by
  apply CartierModule.ext
  funext j
  show (precomp _ (precomp _ f)).toPowerSeries j = (precomp _ (precomp _ f)).toPowerSeries j
  rw [precomp_precomp, precomp_precomp]
  congr 1
  funext n
  exact WittLaw.subst_verFam_mulFam w n

theorem smul_verschiebung [Φ.IsComm] [CharP R p] (w : WittVector p R) (f : CartierModule p Φ) :
    w • verschiebung f = verschiebung (WittVector.frobenius w • f) := by
  apply CartierModule.ext
  funext j
  show (precomp _ (precomp _ f)).toPowerSeries j = (precomp _ (precomp _ f)).toPowerSeries j
  rw [precomp_precomp, precomp_precomp]
  congr 1
  funext n
  exact WittLaw.subst_mulFam_frobFam w n

theorem verschiebung_smul [Φ.IsComm] [CharP R p] [PerfectRing R p] (w : WittVector p R)
    (f : CartierModule p Φ) :
    verschiebung (w • f) = (WittVector.frobeniusEquiv p R).symm w • verschiebung f := by
  have hw : WittVector.frobenius ((WittVector.frobeniusEquiv p R).symm w) = w := by
    rw [← WittVector.frobeniusEquiv_apply]
    exact (WittVector.frobeniusEquiv p R).apply_symm_apply w
  rw [smul_verschiebung, hw]

theorem verschiebung_frobenius_eq_smul [Φ.IsComm] [CharP R p] (f : CartierModule p Φ) :
    verschiebung (frobenius f) = (p : WittVector p R) • f := by
  rw [verschiebung_frobenius, natCast_smul_eq_nsmul']

theorem map_smul_witt [Φ.IsComm] [Φ'.IsComm] (φ : Φ.Hom Φ') (w : WittVector p R)
    (f : CartierModule p Φ) : map φ (w • f) = w • map φ f :=
  map_precomp φ _ f

theorem endAct_smul_witt [Φ.IsComm] (φ : MvFormalGroup.End Φ) (w : WittVector p R)
    (f : CartierModule p Φ) : endAct φ (w • f) = w • endAct φ f :=
  map_precomp φ _ f

def mapLinear [Φ.IsComm] [Φ'.IsComm] (φ : Φ.Hom Φ') :
    CartierModule p Φ →ₗ[WittVector p R] CartierModule p Φ' :=
  { map φ with map_smul' := fun w f => map_smul_witt φ w f }

@[simp] theorem mapLinear_apply [Φ.IsComm] [Φ'.IsComm] (φ : Φ.Hom Φ') (f : CartierModule p Φ) :
    mapLinear φ f = map φ f := rfl

theorem coeff_single_zero_subst_of_weight {u : ℕ → MvPowerSeries ℕ R}
    (hu : ∀ n (e : ℕ →₀ ℕ), coeff e (u n) ≠ 0 → Finsupp.weight (fun m => p ^ m) e = p ^ n)
    (g : MvPowerSeries ℕ R) (hg : g.constantCoeff = 0) :
    coeff (Finsupp.single 0 1) (subst u g) =
      coeff (Finsupp.single 0 1) g * coeff (Finsupp.single 0 1) (u 0) := by
  classical

  have hu0 : ∀ n, (u n).constantCoeff = 0 := by
    intro n
    by_contra h
    have h' : coeff (0 : ℕ →₀ ℕ) (u n) ≠ 0 := by rwa [coeff_zero_eq_constantCoeff_apply]
    have hw := hu n 0 h'
    rw [map_zero] at hw
    exact absurd hw.symm (pow_ne_zero n hp.out.ne_zero)
  have hus : HasSubst u := by
    refine ⟨fun n => by rw [hu0]; exact IsNilpotent.zero, fun e => ?_⟩
    refine (Set.finite_lt_nat (Finsupp.weight (fun m => p ^ m) e)).subset fun n hn => ?_
    have hw := hu n e hn
    show n < Finsupp.weight (fun m => p ^ m) e
    rw [hw]
    exact Nat.lt_pow_self hp.out.one_lt

  have hord : ∀ n, ((p ^ n : ℕ) : ℕ∞) ≤ (u n).weightedOrder (fun m => p ^ m) := by
    intro n
    refine nat_le_weightedOrder (fun m => p ^ m) fun e he => ?_
    by_contra hne
    have hw := hu n e hne
    rw [hw] at he
    exact lt_irrefl _ he
  rw [coeff_subst hus]
  have hterm : ∀ e : ℕ →₀ ℕ, e ≠ Finsupp.single 0 1
      coeff e g • coeff (Finsupp.single 0 1) (e.prod fun n k => u n ^ k) = 0 := by
    intro e he
    by_cases he0 : e = 0
    · subst he0
      rw [coeff_zero_eq_constantCoeff_apply, hg, zero_smul]
    ·
      have hwt : (2 : ℕ∞) ≤ (e.prod fun n k => u n ^ k).weightedOrder (fun m => p ^ m) := by
        rw [Finsupp.prod]
        refine le_trans ?_ (le_weightedOrder_prod _ _ _)
        have hle : ∀ n ∈ e.support, ((e n * p ^ n : ℕ) : ℕ∞) ≤
            (u n ^ e n).weightedOrder (fun m => p ^ m) := by
          intro n _
          refine le_trans ?_ (le_weightedOrder_pow _ _)
          rw [Nat.cast_mul]
          calc ((e n : ℕ) : ℕ∞) * ((p ^ n : ℕ) : ℕ∞) = (e n) • ((p ^ n : ℕ) : ℕ∞) := by
                rw [nsmul_eq_mul]
            _ ≤ (e n) • (u n).weightedOrder (fun m => p ^ m) := nsmul_le_nsmul_right (hord n) _
        refine le_trans ?_ (Finset.sum_le_sum hle)
        rw [← Nat.cast_sum]
        have h2 : 2 ≤ ∑ n ∈ e.support, e n * p ^ n := by

          by_cases hsupp : ∃ n ∈ e.support, n ≠ 0
          · obtain ⟨n, hn, hn0⟩ := hsupp
            refine le_trans ?_ (Finset.single_le_sum (fun _ _ => Nat.zero_le _) hn)
            have hen : 1 ≤ e n := Nat.one_le_iff_ne_zero.mpr (Finsupp.mem_support_iff.mp hn)
            have hpn : 2 ≤ p ^ n := le_trans hp.out.two_le
              (Nat.le_self_pow hn0 p)
            calc 21 * p ^ n := by omega
              _ ≤ e n * p ^ n := Nat.mul_le_mul_right _ hen
          · push Not at hsupp
            have hes : e = Finsupp.single 0 (e 0) := by
              ext n
              by_cases hn : n = 0
              · subst hn; simp
              · rw [Finsupp.single_apply, if_neg (Ne.symm hn)]
                by_contra hne
                exact hn (hsupp n (Finsupp.mem_support_iff.mpr hne))
            have hk0 : e 00 := fun h => he0 (by rw [hes, h, Finsupp.single_zero])
            have hk1 : e 01 := fun h => he (by rw [hes, h])
            have hk : 2 ≤ e 0 := by omega
            have h0 : (0 : ℕ) ∈ e.support := Finsupp.mem_support_iff.mpr (by omega)
            refine le_trans ?_ (Finset.single_le_sum (fun _ _ => Nat.zero_le _) h0)
            simpa using hk
        exact_mod_cast h2
      have hzero : coeff (Finsupp.single 0 1) (e.prod fun n k => u n ^ k) = 0 := by
        refine coeff_eq_zero_of_lt_weightedOrder (fun m => p ^ m) (lt_of_lt_of_le ?_ hwt)
        rw [Finsupp.weight_apply, Finsupp.sum_single_index (by simp)]
        simp
      rw [hzero, smul_zero]
  rw [finsum_eq_single _ (Finsupp.single 0 1) hterm, Finsupp.prod_single_index (by simp), pow_one,
    smul_eq_mul]

theorem tangent_smul_witt [Φ.IsComm] (w : WittVector p R) (f : CartierModule p Φ) :
    tangent (w • f) = w.coeff 0tangent f := by
  classical
  funext j
  rw [tangent_apply, toPowerSeries_smul_witt, Pi.smul_apply, tangent_apply, smul_eq_mul]
  show coeff (Finsupp.single 0 1) (subst (WittLaw.mulFam p w) (f.toPowerSeries j)) = _
  rw [coeff_single_zero_subst_of_weight (fun n e h => WittLaw.weight_eq_of_coeff_mulFam_ne_zero w h)
    _ (f.constantCoeff_eq_zero j), WittLaw.mulFam_apply, WittLaw.mulPoly_at_zero,
    MvPolynomial.coeff_coe, MvPolynomial.coeff_C_mul, MvPolynomial.coeff_X_same, mul_one, mul_comm]

namespace Examples

theorem smul_addLinear (w : WittVector p R) (v : Fin d → R) :
    w • addLinear p v = addLinear p (w.coeff 0 • v) := by
  apply CartierModule.ext
  funext i
  rw [toPowerSeries_smul_witt, toPowerSeries_addLinear]
  show subst (WittLaw.mulFam p w) ((addLinear p v).toPowerSeries i) = _
  rw [toPowerSeries_addLinear, subst_smul (WittLaw.hasSubst_mulFam w),
    subst_X (WittLaw.hasSubst_mulFam w), WittLaw.mulFam_apply, WittLaw.mulPoly_at_zero,
    MvPolynomial.coe_mul, MvPolynomial.coe_C, MvPolynomial.coe_X, Pi.smul_apply, smul_eq_mul,
    ← smul_eq_C_mul, smul_smul, mul_comm]

end Examples

end CartierModule

end MvFormalGroup

end

Statements phrased using this module (125)