Fermat's Last Theorem in Lean 4

← all definition modules

Definitions/Def_ModularCurve_TateVeluRing.lean

definition module

Ring-level Vélu formulas and naturality of Tate toric points

Over an arbitrary commutative ring A with a Weierstrass curve W, the module defines division-free versions of Vélu's coordinate formulas, obtained from the field-level ones by replacing each quotient by Ring.inverse. For a finite set S \subseteq A \times A of points, veluXR W S x is x + \sum_{Q \in S} \bigl(t_Q\,\mathrm{inv}(x - Q_1) + u_Q\,\mathrm{inv}(x - Q_1)^2\bigr) and veluYR W S x y is y minus \sum_{Q \in S}\bigl(u_Q(2y + a_1x + a_3)\,\mathrm{inv}(x-Q_1)^3 + t_Q(a_1(x-Q_1) + y - Q_2)\,\mathrm{inv}(x-Q_1)^2 + (a_1u_Q - g_{x,Q}g_{y,Q})\,\mathrm{inv}(x-Q_1)^2\bigr), where g_x = 3x^2 + 2a_2x + a_4 - a_1y, g_y = -(2y + a_1x + a_3), t = 2g_x - a_1g_y, u = g_y^2 are the quantities veluGx, veluGy, veluT, veluU. Over a field these agree with WeierstrassCurve.veluX and WeierstrassCurve.veluY. Similarly vcXInvR C x = (u^{-1})^2(x - r) and vcYInvR C x y = (u^{-1})^3(y - t - s(x-r)) invert a change of variables C = (u,r,s,t) over a commutative ring, agreeing over a field with WeierstrassCurve.Affine.vcXInv and vcYInv. Finally toricXCoeff p c m names the coefficient function whose associated power series gives the first coordinate of the toric point tateToricPoint A p c: it is c\,\mathrm{inv}(1-c)^2 for m = 0 and otherwise \sum_{d \mid m,\ p \mid d} (m/d)\bigl(c^{m/d} + c^{-m/d}\bigr) - 2\,[p \mid m]\sum_{e \mid m/p} e.

The accompanying lemmas record naturality and unit criteria. Along a ring homomorphism f \colon A \to B the coefficientwise map A((q)) \to B((q)) commutes with HahnSeries.ofPowerSeries, with constants, with laurentOfInt, carries the Tate curve over A((q)) to that over B((q)), and carries tateToricPoint A p c to tateToricPoint B p (f c) provided 1 - c is a unit; f commutes with Ring.inverse at units, with the Vélu quantities, with vcXInvR/vcYInvR, and with veluXR/veluYR when \mathrm{Prod.map}\,f\,f is injective on S and all x - Q_1 are units. A power series with unit constant term gives a unit of A((q)); combined with the polynomial identity c w_c^2 - d w_d^2 = w_c^2 w_d^2 (c-d)(1 - cd) for w_c(1-c) = w_d(1-d) = 1, this shows that the difference of the first coordinates of tateToricPoint A p c and tateToricPoint A p d is a unit whenever 1 - c, 1 - d, c - d and 1 - cd are units.

Relation to Mathlib

Mathlib supplies WeierstrassCurve, VariableChange, Hahn and Laurent series and Ring.inverse; the Vélu coordinate maps veluX/veluY, the variable-change inverses vcXInv/vcYInv, the Tate curve over A((q)) and its toric points are project notions. The definitions here are the Ring.inverse analogues of those field-level formulas over an arbitrary commutative ring.

Where it is used

These ring-level formulas and their compatibility with base change supply the computation of the quotient of the Tate curve by the subgroup generated by a toric point over a cyclotomic base ring, and its specialisation to any field containing a primitive root of unity, which is how the relation between j(E_q) and j(q^d) is transferred from characteristic zero in the modular-curve part of the development.

References

  1. J. Vélu, Isogénies entre courbes elliptiques, C. R. Acad. Sci. Paris Sér. A 273 (1971), 238–241
  2. J. H. Silverman, Advanced Topics in the Arithmetic of Elliptic Curves, Graduate Texts in Mathematics 151, Springer, 1994, Chapter V (the Tate curve)

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

Imports

Imported by

Declarations

Source

import Mathlib
import Definitions.Def_ModularCurve_TateSlots
import Definitions.Def_ModularCurve_LaurentCoeff
import Definitions.Def_ModularCurve_KatzLevelPCusps
import Definitions.Def_WeierstrassCurve_Velu
import Definitions.Def_WeierstrassCurve_VeluPointMap
import Definitions.Def_WeierstrassCurve_VariableChangePointEquiv

set_option autoImplicit false

noncomputable section

open ModularCurve WeierstrassCurve

namespace ModularCurve.TateVeluRing

section Naturality

variable {A B : Type*} [CommRing A] [CommRing B] (f : A →+* B)

theorem coeff_ofPowerSeries_of_neg (g : PowerSeries A) {n : ℤ} (hn : n < 0) :
    (HahnSeries.ofPowerSeries ℤ A g).coeff n = 0 := by
  rw [HahnSeries.ofPowerSeries_apply]
  refine HahnSeries.embDomain_notin_range ?_
  rintro ⟨m, rfl⟩
  exact absurd (Int.natCast_nonneg m) (not_le.mpr hn)

theorem coeffMap_ofPowerSeries (g : PowerSeries A) :
    coeffMap f (HahnSeries.ofPowerSeries ℤ A g) = HahnSeries.ofPowerSeries ℤ B (g.map f) := by
  ext n
  rw [coeffMap_coeff]
  rcases lt_or_ge n 0 with hn | hn
  · rw [coeff_ofPowerSeries_of_neg g hn, coeff_ofPowerSeries_of_neg _ hn, map_zero]
  · obtain ⟨m, rfl⟩ := Int.eq_ofNat_of_zero_le hn
    simp only [HahnSeries.ofPowerSeries_apply_coeff, PowerSeries.coeff_map]

theorem coeffMap_ofPowerSeries_mk (F : ℕ → A) :
    coeffMap f (HahnSeries.ofPowerSeries ℤ A (PowerSeries.mk F)) =
      HahnSeries.ofPowerSeries ℤ B (PowerSeries.mk fun m => f (F m)) := by
  rw [coeffMap_ofPowerSeries, show PowerSeries.map f (PowerSeries.mk F) = PowerSeries.mk (fun m => f (F m)) from
    PowerSeries.ext fun m => by simp only [PowerSeries.coeff_map, PowerSeries.coeff_mk]]

theorem coeffMap_C (a : A) : coeffMap f (HahnSeries.C a) = HahnSeries.C (f a) :=
  HahnSeries.map_C a f

theorem coeffMap_comp_laurentOfInt : (coeffMap f).comp (laurentOfInt A) = laurentOfInt B := by
  refine RingHom.ext fun g => ?_
  rw [RingHom.comp_apply, laurentOfInt_apply, laurentOfInt_apply, coeffMap_ofPowerSeries]
  congr 1
  ext n
  simp only [PowerSeries.coeff_map, eq_intCast, map_intCast]

theorem tateLaurent_map_coeffMap : (tateLaurent A).map (coeffMap f) = tateLaurent B := by
  rw [tateLaurent, tateLaurent, WeierstrassCurve.map_map, coeffMap_comp_laurentOfInt]

theorem map_ringInverse_of_isUnit {a : A} (ha : IsUnit a) : f (Ring.inverse a) = Ring.inverse (f a) := by
  have h1 : f (Ring.inverse a) * f a = 1 := by rw [← map_mul, Ring.inverse_mul_cancel a ha, map_one]
  exact ((Ring.eq_mul_inverse_iff_mul_eq _ 1 _ (ha.map f)).mpr h1).trans (one_mul _)

theorem tateToricPoint_map (p : ℕ) (c : Aˣ) (hc : IsUnit (1 - (c : A))) :
    Prod.map (coeffMap f) (coeffMap f) (tateToricPoint A p c) = tateToricPoint B p (Units.map (f : A →* B) c) := by
  have hcoe : ((Units.map (f : A →* B) c : Bˣ) : B) = f (c : A) := rfl
  have hinv : f (Ring.inverse (1 - (c : A))) = Ring.inverse (1 - (Units.map (f : A →* B) c : B)) := by
    rw [map_ringInverse_of_isUnit f hc, map_sub, map_one, hcoe]
  have hcinv : f ((c⁻¹ : Aˣ) : A) = ((Units.map (f : A →* B) c)⁻¹ : Bˣ) := rfl
  refine Prod.ext ?_ ?_
  · simp only [Prod.map_fst, tateToricPoint_fst, coeffMap_ofPowerSeries_mk]
    congr 1; ext m; simp only [PowerSeries.coeff_mk]
    by_cases hm : m = 0
    · rw [if_pos hm, if_pos hm, map_mul, map_pow, hinv, hcoe]
    · rw [if_neg hm, if_neg hm]
      simp only [map_sub, map_sum, map_mul, map_natCast, map_add, map_pow, map_ofNat, hcinv, hcoe,
        apply_ite f, map_zero]
  · simp only [Prod.map_snd, tateToricPoint_snd, coeffMap_ofPowerSeries_mk]
    congr 1; ext m; simp only [PowerSeries.coeff_mk]
    by_cases hm : m = 0
    · rw [if_pos hm, if_pos hm, map_mul, map_pow, map_pow, hinv, hcoe]
    · rw [if_neg hm, if_neg hm]
      simp only [map_sub, map_sum, map_mul, map_natCast, map_add, map_pow, hcinv, hcoe,
        apply_ite f, map_zero]

end Naturality

section VeluR

variable {A : Type*} [CommRing A] (W : WeierstrassCurve A)

noncomputable def veluXR (S : Finset (A × A)) (x : A) : A :=
  x + ∑ Q ∈ S, (W.veluT Q.1 Q.2 * Ring.inverse (x - Q.1) + W.veluU Q.1 Q.2 * Ring.inverse (x - Q.1) ^ 2)

noncomputable def veluYR (S : Finset (A × A)) (x y : A) : A :=
  y - ∑ Q ∈ S, (W.veluU Q.1 Q.2 * (2 * y + W.a₁ * x + W.a₃) * Ring.inverse (x - Q.1) ^ 3
    + W.veluT Q.1 Q.2 * (W.a₁ * (x - Q.1) + y - Q.2) * Ring.inverse (x - Q.1) ^ 2
    + (W.a₁ * W.veluU Q.1 Q.2 - W.veluGx Q.1 Q.2 * W.veluGy Q.1 Q.2) * Ring.inverse (x - Q.1) ^ 2)

theorem veluXR_eq_veluX {F : Type*} [Field F] (W : WeierstrassCurve F) (S : Finset (F × F)) (x : F) :
    veluXR W S x = W.veluX S x := by
  unfold veluXR WeierstrassCurve.veluX
  simp only [Ring.inverse_eq_inv', div_eq_mul_inv, inv_pow]

theorem veluYR_eq_veluY {F : Type*} [Field F] (W : WeierstrassCurve F) (S : Finset (F × F)) (x y : F) :
    veluYR W S x y = W.veluY S x y := by
  unfold veluYR WeierstrassCurve.veluY
  simp only [Ring.inverse_eq_inv', div_eq_mul_inv, inv_pow]

variable {B : Type*} [CommRing B] (f : A →+* B)

theorem map_veluT (x y : A) : (W.map f).veluT (f x) (f y) = f (W.veluT x y) := by
  simp only [WeierstrassCurve.veluT, WeierstrassCurve.veluGx, WeierstrassCurve.veluGy,
    WeierstrassCurve.map_a₁, WeierstrassCurve.map_a₂, WeierstrassCurve.map_a₃,
    WeierstrassCurve.map_a₄, map_sub, map_mul, map_add, map_neg, map_pow, map_ofNat]

theorem map_veluU (x y : A) : (W.map f).veluU (f x) (f y) = f (W.veluU x y) := by
  simp only [WeierstrassCurve.veluU, WeierstrassCurve.veluGy,
    WeierstrassCurve.map_a₁, WeierstrassCurve.map_a₃, map_mul, map_add, map_neg, map_pow, map_ofNat]

theorem map_veluGx (x y : A) : (W.map f).veluGx (f x) (f y) = f (W.veluGx x y) := by
  simp only [WeierstrassCurve.veluGx, WeierstrassCurve.map_a₁, WeierstrassCurve.map_a₂,
    WeierstrassCurve.map_a₄, map_sub, map_mul, map_add, map_pow, map_ofNat]

theorem map_veluGy (x y : A) : (W.map f).veluGy (f x) (f y) = f (W.veluGy x y) := by
  simp only [WeierstrassCurve.veluGy, WeierstrassCurve.map_a₁, WeierstrassCurve.map_a₃,
    map_mul, map_add, map_neg, map_ofNat]

theorem map_veluXR [DecidableEq (B × B)] (S : Finset (A × A)) (x : A)
    (hinj : Set.InjOn (Prod.map f f) S) (hunit : ∀ Q ∈ S, IsUnit (x - Q.1)) :
    f (veluXR W S x) = veluXR (W.map f) (S.image (Prod.map f f)) (f x) := by
  unfold veluXR
  rw [Finset.sum_image hinj, map_add, map_sum]
  refine congrArg _ (Finset.sum_congr rfl fun Q hQ => ?_)
  have h := map_ringInverse_of_isUnit f (hunit Q hQ)
  rw [map_sub] at h
  simp only [Prod.map_fst, Prod.map_snd, map_veluT, map_veluU, map_add, map_mul, map_pow, h]

theorem map_veluYR [DecidableEq (B × B)] (S : Finset (A × A)) (x y : A)
    (hinj : Set.InjOn (Prod.map f f) S) (hunit : ∀ Q ∈ S, IsUnit (x - Q.1)) :
    f (veluYR W S x y) = veluYR (W.map f) (S.image (Prod.map f f)) (f x) (f y) := by
  unfold veluYR
  rw [Finset.sum_image hinj, map_sub, map_sum]
  refine congrArg _ (Finset.sum_congr rfl fun Q hQ => ?_)
  have h := map_ringInverse_of_isUnit f (hunit Q hQ)
  rw [map_sub] at h
  simp only [Prod.map_fst, Prod.map_snd, map_veluT, map_veluU, map_veluGx, map_veluGy,
    WeierstrassCurve.map_a₁, WeierstrassCurve.map_a₃, map_add, map_sub, map_mul, map_pow, map_ofNat, h]

end VeluR

section VcR

variable {A : Type*} [CommRing A]

def vcXInvR (C : WeierstrassCurve.VariableChange A) (x : A) : A := ((C.u⁻¹ : Aˣ) : A) ^ 2 * (x - C.r)

def vcYInvR (C : WeierstrassCurve.VariableChange A) (x y : A) : A :=
  ((C.u⁻¹ : Aˣ) : A) ^ 3 * (y - C.t - C.s * (x - C.r))

theorem vcXInvR_eq {F : Type*} [Field F] (C : WeierstrassCurve.VariableChange F) (x : F) :
    vcXInvR C x = WeierstrassCurve.Affine.vcXInv C x := rfl

theorem vcYInvR_eq {F : Type*} [Field F] (C : WeierstrassCurve.VariableChange F) (x y : F) :
    vcYInvR C x y = WeierstrassCurve.Affine.vcYInv C x y := rfl

variable {B : Type*} [CommRing B] (f : A →+* B)

theorem map_vcXInvR (C : WeierstrassCurve.VariableChange A) (x : A) :
    f (vcXInvR C x) = vcXInvR (C.map f) (f x) := by
  simp only [vcXInvR, WeierstrassCurve.VariableChange.map_u, WeierstrassCurve.VariableChange.map_r, map_mul,
    map_sub, map_pow, Units.coe_map_inv, MonoidHom.coe_coe]

theorem map_vcYInvR (C : WeierstrassCurve.VariableChange A) (x y : A) :
    f (vcYInvR C x y) = vcYInvR (C.map f) (f x) (f y) := by
  simp only [vcYInvR, WeierstrassCurve.VariableChange.map_u, WeierstrassCurve.VariableChange.map_r,
    WeierstrassCurve.VariableChange.map_s, WeierstrassCurve.VariableChange.map_t, map_mul, map_sub, map_pow,
    Units.coe_map_inv, MonoidHom.coe_coe]

end VcR

section LaurentUnits

variable {A : Type*} [CommRing A]

theorem isUnit_ofPowerSeries_mk {F : ℕ → A} (h0 : IsUnit (F 0)) :
    IsUnit (HahnSeries.ofPowerSeries ℤ A (PowerSeries.mk F)) := by
  refine (PowerSeries.isUnit_iff_constantCoeff.mpr ?_).map _
  rwa [← PowerSeries.coeff_zero_eq_constantCoeff_apply, PowerSeries.coeff_mk]

def toricXCoeff (p : ℕ) (c : Aˣ) (m : ℕ) : A :=
  if m = 0 then (c : A) * Ring.inverse (1 - (c : A)) ^ 2
  else (∑ d ∈ m.divisors, if p ∣ d then
          ((m / d : ℕ) : A) * ((c : A) ^ (m / d) + ((c⁻¹ : Aˣ) : A) ^ (m / d)) else 0)
    - 2 * (if p ∣ m then ∑ e ∈ (m / p).divisors, (e : A) else 0)

theorem tateToricPoint_fst_eq_mk (p : ℕ) (c : Aˣ) :
    (tateToricPoint A p c).1 = HahnSeries.ofPowerSeries ℤ A (PowerSeries.mk (toricXCoeff p c)) := rfl

theorem tateToricPoint_fst_sub (p : ℕ) (c d : Aˣ) :
    (tateToricPoint A p c).1 - (tateToricPoint A p d).1 =
      HahnSeries.ofPowerSeries ℤ A (PowerSeries.mk fun m => toricXCoeff p c m - toricXCoeff p d m) := by
  rw [tateToricPoint_fst_eq_mk, tateToricPoint_fst_eq_mk, ← map_sub,
    show PowerSeries.mk (toricXCoeff p c) - PowerSeries.mk (toricXCoeff p d) =
      PowerSeries.mk (fun m => toricXCoeff p c m - toricXCoeff p d m) from
    PowerSeries.ext fun m => by simp only [map_sub, PowerSeries.coeff_mk]]

theorem toricXCoeff_zero (p : ℕ) (c : Aˣ) : toricXCoeff p c 0 = (c : A) * Ring.inverse (1 - (c : A)) ^ 2 := by
  simp [toricXCoeff]

theorem head_sub_head (c d wc wd : A) (hc : wc * (1 - c) = 1) (hd : wd * (1 - d) = 1) :
    c * wc ^ 2 - d * wd ^ 2 = wc ^ 2 * wd ^ 2 * ((c - d) * (1 - c * d)) := by
  linear_combination (-(c * wc ^ 2 * (wd * (1 - d) + 1))) * hd + (d * wd ^ 2 * (wc * (1 - c) + 1)) * hc

theorem isUnit_tateToricPoint_fst_sub (p : ℕ) (c d : Aˣ) (hc : IsUnit (1 - (c : A))) (hd : IsUnit (1 - (d : A)))
    (hcd : IsUnit ((c : A) - d)) (hcd' : IsUnit (1 - (c : A) * d)) :
    IsUnit ((tateToricPoint A p c).1 - (tateToricPoint A p d).1) := by
  rw [tateToricPoint_fst_sub]
  refine isUnit_ofPowerSeries_mk ?_
  simp only [toricXCoeff_zero]
  rw [head_sub_head (c : A) d _ _ (Ring.inverse_mul_cancel _ hc) (Ring.inverse_mul_cancel _ hd)]
  exact (((hc.ringInverse.pow 2).mul (hd.ringInverse.pow 2)).mul (hcd.mul hcd'))

end LaurentUnits

end ModularCurve.TateVeluRing

end

Statements phrased using this module (1)