Fermat's Last Theorem in Lean 4

← all definition modules

Definitions/Def_ModularCurve_KroneckerTransport.lean

definition module

Coefficient reduction of Laurent series and the Kronecker congruence

For a ring homomorphism f : R \to S of commutative rings, laurentMap f is the coefficientwise map R((q)) \to S((q)) of Laurent (Hahn) series, packaged as a ring homomorphism; its basic properties record the value on a coefficient, on a monomial HahnSeries.single k r, on the image of a power series, compatibility with the substitution operator q \mapsto q^N (qExpand), injectivity for injective f, and composition. Over \mathbb{Z}, jqInt is the integral j-expansion q^{-1}\,\mathrm{jNum}, where \mathrm{jNum} = E_4^3 \cdot \eta-unit{}^{-1} is the integral power series with constant term 1 fixed in the X_0 definitions; laurentMap along \mathbb{Z} \hookrightarrow \mathbb{Q} carries it to jq, and jqIntN N is its q \mapsto q^N substitute. The accompanying coefficient lemmas state that the coefficient of q^{-1} in jqInt is 1, that all lower coefficients vanish, and correspondingly that (\mathrm{jqInt})^b has coefficient 1 in degree -b and vanishes below. Reducing along \mathbb{Z} \to \mathbb{Z}/\ell gives jqMod ℓ and jqNMod ℓ N with the same leading-coefficient statements, and evalAtJInt, evalAtJMod ℓ are the evaluation homomorphisms \mathbb{Z}[X] \to \mathbb{Z}((q)), (\mathbb{Z}/\ell)[X] \to (\mathbb{Z}/\ell)((q)) sending X to jqInt, jqMod ℓ, compatible with reduction and with evalAtJ.

reduceModBivar ℓ is coefficientwise reduction \mathbb{Z}[X][Y] \to (\mathbb{Z}/\ell)[X][Y]. For a prime-power-free datum, KroneckerCongruence ℓ data is a predicate on a chosen modular-equation datum data : ModularPolynomialData ℓ (a structure carrying a monic bivariate \Phi, its degree \psi(\ell) in the outer variable, and the vanishing of \Phi at (j(q), j(q^\ell)) as fields): it asserts the identity \overline{\Phi} = (X^{\ell} - Y)(X - Y^{\ell}) in (\mathbb{Z}/\ell)[X][Y], with X the inner variable (the j(q) slot) and Y the outer one (the j(q^\ell) slot). Finally, for \ell prime, modularFunctionFieldMod ℓ N is the intermediate field (\mathbb{Z}/\ell)(\bar j(q), \bar j(q^N)) of (\mathbb{Z}/\ell)((q)), with its two generators exhibited as members.

Relation to Mathlib

Mathlib supplies HahnSeries.map together with its multiplicativity lemmas; laurentMap bundles these into a ring homomorphism of Laurent series rings, the analogue for Laurent series of Polynomial.mapRingHom. The Kronecker congruence and the integral and mod-\ell j-expansions are the project's own notions.

Where it is used

These definitions form the definitional layer for the Kronecker-congruence leg of the Eichler–Shimura relation: the modular equation for X_0(\ell), established over \mathbb{Q}((q)), is transported coefficientwise to characteristic \ell, where its reduction is required to factor as (X^{\ell} - Y)(X - Y^{\ell}).

References

  1. S. Lang, Elliptic Functions, 2nd edition, Graduate Texts in Mathematics 112, Springer, 1987, Chapter 5
  2. G. Shimura, Introduction to the Arithmetic Theory of Automorphic Functions, Publications of the Mathematical Society of Japan 11, Princeton University Press, 1971

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_ModularCurve_KroneckerTransport.lean

Imports

Imported by

Declarations

Source

import Mathlib
import Definitions.Def_ModularCurve_X0

noncomputable section

open PowerSeries HahnSeries IntermediateField

namespace ModularCurve

section LaurentMap

variable {R S T : Type*} [CommRing R] [CommRing S] [CommRing T]

def laurentMap (f : R →+* S) : LaurentSeries R →+* LaurentSeries S where
  toFun x := x.map f
  map_one' := HahnSeries.map_one (R := R) (S := S) f.toMonoidWithZeroHom
  map_mul' _ _ := HahnSeries.map_mul (R := R) (S := S) f.toNonUnitalRingHom
  map_zero' := by
    ext k
    show f ((0 : LaurentSeries R).coeff k) = (0 : LaurentSeries S).coeff k
    rw [HahnSeries.coeff_zero, HahnSeries.coeff_zero, map_zero]
  map_add' x y := by
    ext k
    show f ((x + y).coeff k) = (x.map f + y.map f).coeff k
    rw [HahnSeries.coeff_add, HahnSeries.coeff_add, map_add]
    rfl

@[simp]
theorem laurentMap_coeff (f : R →+* S) (x : LaurentSeries R) (k : ℤ) :
    (laurentMap f x).coeff k = f (x.coeff k) := rfl

@[simp]
theorem laurentMap_single (f : R →+* S) (k : ℤ) (r : R) :
    laurentMap f (HahnSeries.single k r) = HahnSeries.single k (f r) := by
  ext g
  rw [laurentMap_coeff, HahnSeries.coeff_single, HahnSeries.coeff_single, apply_ite f,
    map_zero]

theorem laurentMap_ofPowerSeries (f : R →+* S) (p : PowerSeries R) :
    laurentMap f (HahnSeries.ofPowerSeries ℤ R p) =
      HahnSeries.ofPowerSeries ℤ S (p.map f) := by
  ext k
  rw [laurentMap_coeff]
  rcases le_or_gt 0 k with hk | hk
  · lift k to ℕ using hk
    rw [HahnSeries.ofPowerSeries_apply_coeff, HahnSeries.ofPowerSeries_apply_coeff,
      PowerSeries.coeff_map]
  · rw [ofPowerSeries_coeff_of_neg _ hk, ofPowerSeries_coeff_of_neg _ hk, map_zero]

theorem laurentMap_qExpand (f : R →+* S) (N : ℕ) [NeZero N] (x : LaurentSeries R) :
    laurentMap f (qExpand R N x) = qExpand S N (laurentMap f x) := by
  ext k
  rw [laurentMap_coeff]
  by_cases hk : (N : ℤ) ∣ k
  · obtain ⟨m, rfl⟩ := hk
    rw [qExpand_coeff_mul, qExpand_coeff_mul, laurentMap_coeff]
  · rw [qExpand_coeff_of_not_dvd N x hk, qExpand_coeff_of_not_dvd N _ hk, map_zero]

theorem laurentMap_injective {f : R →+* S} (hf : Function.Injective f) :
    Function.Injective (laurentMap f) := by
  intro x y hxy
  ext k
  exact hf (by simpa using congrArg (fun z => z.coeff k) hxy)

theorem laurentMap_laurentMap (f : R →+* S) (g : S →+* T) (x : LaurentSeries R) :
    laurentMap g (laurentMap f x) = laurentMap (g.comp f) x := by
  ext k
  simp

end LaurentMap

section IntegralJ

def jqInt : LaurentSeries ℤ :=
  HahnSeries.single (-1 : ℤ) 1 * HahnSeries.ofPowerSeries ℤ ℤ jNum

theorem laurentMap_jqInt : laurentMap (Int.castRingHom ℚ) jqInt = jq := by
  rw [jqInt, map_mul, laurentMap_single, laurentMap_ofPowerSeries, jq, jNumQ, map_one]

def jqIntN (N : ℕ) [NeZero N] : LaurentSeries ℤ := qExpand ℤ N jqInt

theorem laurentMap_jqIntN (N : ℕ) [NeZero N] :
    laurentMap (Int.castRingHom ℚ) (jqIntN N) = jqN N := by
  rw [jqIntN, laurentMap_qExpand, laurentMap_jqInt, jqN]

theorem coeff_jqInt_cast (k : ℤ) : ((jqInt.coeff k : ℤ) : ℚ) = jq.coeff k := by
  rw [← laurentMap_jqInt, laurentMap_coeff]
  rfl

theorem coeff_jqInt_neg_one : jqInt.coeff (-1 : ℤ) = 1 :=
  Int.cast_injective (α := ℚ) (by rw [coeff_jqInt_cast, coeff_jq_neg_one, Int.cast_one])

theorem coeff_jqInt_of_lt {k : ℤ} (hk : k < -1) : jqInt.coeff k = 0 :=
  Int.cast_injective (α := ℚ) (by rw [coeff_jqInt_cast, coeff_jq_of_lt hk, Int.cast_zero])

theorem coeff_jqInt_pow_self (b : ℕ) : (jqInt ^ b).coeff (-(b : ℤ)) = 1 := by
  refine Int.cast_injective (α := ℚ) ?_
  have h : ((jqInt ^ b).coeff (-(b : ℤ)) : ℚ) = (jq ^ b).coeff (-(b : ℤ)) := by
    rw [← laurentMap_jqInt, ← map_pow, laurentMap_coeff]; rfl
  rw [h, coeff_jq_pow_self, Int.cast_one]

theorem coeff_jqInt_pow_of_lt {b : ℕ} {m : ℤ} (hm : m < -(b : ℤ)) :
    (jqInt ^ b).coeff m = 0 := by
  refine Int.cast_injective (α := ℚ) ?_
  have h : ((jqInt ^ b).coeff m : ℚ) = (jq ^ b).coeff m := by
    rw [← laurentMap_jqInt, ← map_pow, laurentMap_coeff]; rfl
  rw [h, coeff_jq_pow_of_lt hm, Int.cast_zero]

end IntegralJ

section ReduceModBivar

def reduceModBivar (ℓ : ℕ) :
    Polynomial (Polynomial ℤ) →+* Polynomial (Polynomial (ZMod ℓ)) :=
  Polynomial.mapRingHom (Polynomial.mapRingHom (Int.castRingHom (ZMod ℓ)))

@[simp] theorem reduceModBivar_X (ℓ : ℕ) :
    reduceModBivar ℓ Polynomial.X = Polynomial.X := by
  simp [reduceModBivar, Polynomial.coe_mapRingHom]

@[simp] theorem reduceModBivar_C_X (ℓ : ℕ) :
    reduceModBivar ℓ (Polynomial.C Polynomial.X) = Polynomial.C Polynomial.X := by
  simp [reduceModBivar, Polynomial.coe_mapRingHom]

end ReduceModBivar

def KroneckerCongruence (ℓ : ℕ) [NeZero ℓ] (data : ModularPolynomialData ℓ) : Prop :=
  reduceModBivar ℓ data.Φ =
    (Polynomial.C Polynomial.X ^ ℓ - Polynomial.X) *
      (Polynomial.C Polynomial.X - Polynomial.X ^ ℓ)

section IntegralEquation

def evalAtJInt : Polynomial ℤ →+* LaurentSeries ℤ :=
  Polynomial.eval₂RingHom (Int.castRingHom (LaurentSeries ℤ)) jqInt

@[simp]
theorem evalAtJInt_X : evalAtJInt Polynomial.X = jqInt :=
  Polynomial.eval₂_X _ _

theorem laurentMap_comp_evalAtJInt :
    (laurentMap (Int.castRingHom ℚ)).comp evalAtJInt = evalAtJ := by
  refine Polynomial.ringHom_ext' (Subsingleton.elim _ _) ?_
  rw [RingHom.comp_apply, evalAtJInt_X, laurentMap_jqInt, evalAtJ_X]

end IntegralEquation

section ModEquation

variable (ℓ : ℕ)

def jqMod : LaurentSeries (ZMod ℓ) := laurentMap (Int.castRingHom (ZMod ℓ)) jqInt

def jqNMod (N : ℕ) [NeZero N] : LaurentSeries (ZMod ℓ) := qExpand (ZMod ℓ) N (jqMod ℓ)

@[simp]
theorem jqNMod_one : jqNMod1 = jqMod ℓ := qExpand_one_apply _

theorem laurentMap_jqIntN_mod (N : ℕ) [NeZero N] :
    laurentMap (Int.castRingHom (ZMod ℓ)) (jqIntN N) = jqNMod ℓ N := by
  rw [jqIntN, laurentMap_qExpand, jqNMod, jqMod]

theorem coeff_jqMod (k : ℤ) : (jqMod ℓ).coeff k = (jqInt.coeff k : ZMod ℓ) := rfl

theorem coeff_jqMod_neg_one : (jqMod ℓ).coeff (-1 : ℤ) = 1 := by
  rw [coeff_jqMod, coeff_jqInt_neg_one, Int.cast_one]

theorem coeff_jqMod_of_lt {k : ℤ} (hk : k < -1) : (jqMod ℓ).coeff k = 0 := by
  rw [coeff_jqMod, coeff_jqInt_of_lt hk, Int.cast_zero]

theorem coeff_jqMod_pow_self (b : ℕ) : ((jqMod ℓ) ^ b).coeff (-(b : ℤ)) = 1 := by
  have h : ((jqMod ℓ) ^ b).coeff (-(b : ℤ)) = ((jqInt ^ b).coeff (-(b : ℤ)) : ZMod ℓ) := by
    rw [jqMod, ← map_pow, laurentMap_coeff]; rfl
  rw [h, coeff_jqInt_pow_self, Int.cast_one]

theorem coeff_jqMod_pow_of_lt {b : ℕ} {m : ℤ} (hm : m < -(b : ℤ)) :
    ((jqMod ℓ) ^ b).coeff m = 0 := by
  have h : ((jqMod ℓ) ^ b).coeff m = ((jqInt ^ b).coeff m : ZMod ℓ) := by
    rw [jqMod, ← map_pow, laurentMap_coeff]; rfl
  rw [h, coeff_jqInt_pow_of_lt hm, Int.cast_zero]

def evalAtJMod : Polynomial (ZMod ℓ) →+* LaurentSeries (ZMod ℓ) :=
  Polynomial.eval₂RingHom (algebraMap (ZMod ℓ) (LaurentSeries (ZMod ℓ))) (jqMod ℓ)

@[simp]
theorem evalAtJMod_X : evalAtJMod ℓ Polynomial.X = jqMod ℓ :=
  Polynomial.eval₂_X _ _

theorem evalAtJMod_comp_map :
    (evalAtJMod ℓ).comp (Polynomial.mapRingHom (Int.castRingHom (ZMod ℓ))) =
      (laurentMap (Int.castRingHom (ZMod ℓ))).comp evalAtJInt := by
  refine Polynomial.ringHom_ext' (Subsingleton.elim _ _) ?_
  rw [RingHom.comp_apply, RingHom.comp_apply, Polynomial.coe_mapRingHom, Polynomial.map_X,
    evalAtJMod_X, evalAtJInt_X, jqMod]

end ModEquation

section ModFunctionField

variable (ℓ : ℕ) [Fact ℓ.Prime]

def modularFunctionFieldMod (N : ℕ) [NeZero N] :
    IntermediateField (ZMod ℓ) (LaurentSeries (ZMod ℓ)) :=
  IntermediateField.adjoin (ZMod ℓ) {jqMod ℓ, jqNMod ℓ N}

theorem jqMod_mem (N : ℕ) [NeZero N] : jqMod ℓ ∈ modularFunctionFieldMod ℓ N :=
  IntermediateField.subset_adjoin _ _ (Set.mem_insert _ _)

theorem jqNMod_mem (N : ℕ) [NeZero N] : jqNMod ℓ N ∈ modularFunctionFieldMod ℓ N :=
  IntermediateField.subset_adjoin _ _ (Set.mem_insert_of_mem _ rfl)

end ModFunctionField

end ModularCurve

Statements phrased using this module (17)