Fermat's Last Theorem in Lean 4

← all definition modules

Definitions/Def_ModularCurve_ModuliPlace.lean

definition module

Places of the modular function field from moduli test data

Throughout K is a field and N a natural number, and F_N= modularFunctionFieldFullC K N is the intermediate field of K((q)) generated over K by the series qExpand K d (jqModC K) for the nonzero divisors d\mid N; jqNFull K N d hd names the generator indexed by d, and jModElt is the case d=1, the q-expansion of j (whose coefficient in degree -1 is 1, whence jModElt_sub_algebraMap_ne_zero: j-c\neq 0 for every c\in K).

The section ComapPlace builds places by pullback. For a ring homomorphism \varphi\colon F\to\Omega of fields and a place W of \Omega over K — a proper valuation subring containing the image of K in which every ideal is principal, with integer-valued order function ordeIdx φ W is the least positive value of \operatorname{ord}_W\circ\varphi on F^{\times}; it divides every such value, so an f attaining it gives an irreducible element and \varphi^{-1}(\mathcal O_W) is a proper principal ideal ring. Under the hypotheses that \varphi commutes with the structure maps of K and that \operatorname{ord}_W(\varphi f)>0 for some f\neq 0, ComapPlace.place is the place of F over K with valuation ring \varphi^{-1}(\mathcal O_W).

The structure ModuliTestDatum K N x Ω, for x in ModuliPoint N K (the quotient of pairs consisting of an elliptic Weierstrass curve and a point of exact order N, by the relation generated by variable changes together with replacing the generator by a coprime multiple) and \Omega a field extension of K in the same universe, bundles: a place W of \Omega/K; a Weierstrass curve \mathcal E over \mathcal O_W whose reduction modulo the maximal ideal has nonzero discriminant; a point g of exact order N on the base change of \mathcal E to \Omega; a ring homomorphism \rho\colon\kappa(W)\to K splitting the structure map, hence an isomorphism (resEquiv); the assertion that the reduction reduceHom of g again has exact order N and that the reduced pair, transported by \rho, represents x; and a K-algebra embedding \psi\colon F_N\to\Omega pinned at all generators, namely for each nonzero d\mid N and each algebraically closed \Omega-algebra \Omega' the image of \psi(\tilde\jmath_d) in \Omega' equals cyclicQuotientJ of \mathcal E_{\Omega'} at the subgroup generated by (N/d)\,g and at level d, that is c_4^3/\Delta of the curve obtained by iterating prime-degree Vélu quotients along the prime factorisation of d. Consequences drawn here: \psi(\tilde\jmath_1)=j(\mathcal E_\Omega), the element j(\mathcal E)-j(x) lies in \mathfrak m_W, so ModuliTestDatum.place, the pullback of W along \psi, is a place of F_N/K with positive order at j-j(x). For M\mid N, restrictLevel turns a datum of level N into one of level M with generator (N/M)g and embedding \psi precomposed with F_M\subseteq F_N, whose place is the restriction of the original along that inclusion.

Finally, IsModuliPlaceOf K N x v asserts that the valuation ring of v is the pullback along \psi of W's for some test datum for x; moduliPlaceOfPoint K N x chooses such a v when one exists and otherwise returns qInftyPlaceMod, the place of q-expansions of nonnegative order; and moduliPlace K N E C, for a Weierstrass curve E over K and a subgroup C of its affine points, returns moduliPlaceOfPoint at the class of (E,g) when E is elliptic and C=\langle g\rangle with g of exact order N (independent of the chosen generator, by ModuliPoint.mk_eq_mk_of_zmultiples_eq), and the same q-expansion place otherwise. The further lemmas record that moduliPlaceOfPoint is a place of the asserted kind whenever one exists, is the unique one under a conditional uniqueness hypothesis, and has positive order at j-j(E).

Relation to Mathlib

Mathlib supplies valuation subrings, their pullbacks along ring homomorphisms and the criteria for discrete valuation rings used here, together with Weierstrass curves and their affine point groups; the notions of a place of a field over K, the modular function field generated by q-expansions, the moduli quotient ModuliPoint, reduction of points reduceHom and the iterated Vélu quotient cyclicQuotientJ are the project's own.

Where it is used

These definitions attach to an elliptic curve over K with a cyclic subgroup of order N a place of the level-N modular function field, so that pairs (E,C) can be used as points of the modular curve; the positivity of the order at j-j(E) records that the resulting place is not the place of q-expansions playing the role of the cusp, and restrictLevel makes the level-lowering degeneracy compatible with this assignment.

References

  1. J. Vélu, Isogénies entre courbes elliptiques, C. R. Acad. Sci. Paris Sér. A 273 (1971), 238–241
  2. N. M. Katz and B. Mazur, Arithmetic Moduli of Elliptic Curves, Annals of Mathematics Studies 108, Princeton University Press, 1985
  3. F. Diamond and J. Shurman, A First Course in Modular Forms, Graduate Texts in Mathematics 228, Springer, 2005

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

Imports

Imported by

  • no other definition module

Declarations

Source

import Mathlib
import Definitions.Def_ModularCurve_X0ModL
import Definitions.Def_ModularCurve_QAdicPlaceMod
import Definitions.Def_ModularCurve_ModuliPointMap
import Definitions.Def_WeierstrassCurve_ReduceHom
import Definitions.Def_WeierstrassCurve_CyclicQuotientJ
import Definitions.Def_AlgebraicCurve_Correspondence

set_option autoImplicit false

noncomputable section

open IsLocalRing AlgebraicCurve WeierstrassCurve WeierstrassCurve.Affine

namespace ModularCurve

universe u

section Generators

variable (K : Type*) [Field K] (N : ℕ)

theorem jqNModC_mem_full {d : ℕ} [NeZero d] (hd : d ∣ N) :
    jqNModC K dmodularFunctionFieldFullC K N :=
  jqModCd_mem_full K N hd

def jqNFull (d : ℕ) [NeZero d] (hd : d ∣ N) : modularFunctionFieldFullC K N :=
jqNModC K d, jqNModC_mem_full K N hd⟩

@[simp] theorem coe_jqNFull (d : ℕ) [NeZero d] (hd : d ∣ N) :
    (jqNFull K N d hd : LaurentSeries K) = jqNModC K d := rfl

theorem jqNFull_one : jqNFull K N 1 (one_dvd N) = jModElt K (jqModC_mem_full K N) :=
  Subtype.ext (jqNModC_one K)

theorem inclusion_jqNFull [NeZero N] {M : ℕ} [NeZero M] (hMN : M ∣ N) (d : ℕ) [NeZero d]
    (hd : d ∣ M) :
    IntermediateField.inclusion (full_degeneracyC_le K hMN) (jqNFull K M d hd) =
      jqNFull K N d (hd.trans hMN) := rfl

theorem jModElt_sub_algebraMap_ne_zero (c : K) :
    jModElt K (jqModC_mem_full K N) - algebraMap K (modularFunctionFieldFullC K N) c ≠ 0 := by
  intro h
  have h1 : (jqModC K : LaurentSeries K) - algebraMap K (LaurentSeries K) c = 0 := by
    have h2 := congrArg (fun f : modularFunctionFieldFullC K N => (f : LaurentSeries K)) h
    simpa [jModElt] using h2
  have h3 := congrArg (fun f : LaurentSeries K => f.coeff (-1)) h1
  simp only [HahnSeries.coeff_sub, coeff_jqModC_neg_one, algebraMap_laurentSeries_eq_single,
    HahnSeries.coeff_single_of_ne (show (-1 : ℤ) ≠ 0 by norm_num), sub_zero,
    HahnSeries.coeff_zero] at h3
  exact one_ne_zero h3

theorem ModuliPlaceAux.div_mul_div_cancel_of_dvd {d M N : ℕ} (hd : d ∣ M) (hMN : M ∣ N) (hM : M ≠ 0) :
    M / d * (N / M) = N / d := by
  rw [Nat.div_mul_div_comm hd hMN, mul_comm d M, Nat.mul_div_mul_left N d (Nat.pos_of_ne_zero hM)]

end Generators

namespace ComapPlace

variable {K F Ω : Type*} [Field K] [Field F] [Field Ω] [Algebra K Ω] (φ : F →+* Ω) (W : Place K Ω)

theorem mem_iff_ord_nonneg {a : Ω} (ha : a ≠ 0) : a ∈ W.toValuationSubring ↔ 0 ≤ W.ord a := by
  obtain ⟨π, hπ⟩ := IsDiscreteValuationRing.exists_irreducible W.toValuationSubring
  constructor
  · intro hmem
    obtain ⟨n, u, hu⟩ :=
      IsDiscreteValuationRing.eq_unit_mul_pow_irreducible
        (x := (⟨a, hmem⟩ : W.toValuationSubring)) (by simpa [Subtype.ext_iff] using ha) hπ
    have hcoe : a = ((u : W.toValuationSubring) : Ω) * ((π : Ω) ^ (n : ℤ)) := by
      have h := congrArg Subtype.val hu
      push_cast at h
      rw [zpow_natCast]
      exact h
    rw [hcoe, W.ord_unit_smul_zpow u hπ (n : ℤ)]
    exact Int.natCast_nonneg n
  · intro h
    obtain ⟨u, hu⟩ := W.exists_unit_mul_zpow ha hπ
    rw [hu, show W.ord a = (((W.ord a).toNat : ℕ) : ℤ) from (Int.toNat_of_nonneg h).symm,
      zpow_natCast]
    exact mul_mem (u : W.toValuationSubring).2 (pow_mem (π : W.toValuationSubring).2 _)

theorem ord_pos_of_mem_maximalIdeal {a : W.toValuationSubring}
    (ha : a ∈ maximalIdeal W.toValuationSubring) (ha0 : a ≠ 0) : 0 < W.ord (a : Ω) := by
  obtain ⟨π, hπ⟩ := IsDiscreteValuationRing.exists_irreducible W.toValuationSubring
  obtain ⟨n, u, hu⟩ := IsDiscreteValuationRing.eq_unit_mul_pow_irreducible ha0 hπ
  have hn : n ≠ 0 := by
    rintro rfl
    rw [pow_zero, mul_one] at hu
    exact (IsLocalRing.mem_maximalIdeal _).mp ha (hu ▸ u.isUnit)
  have hcoe : (a : Ω) = ((u : W.toValuationSubring) : Ω) * ((π : Ω) ^ (n : ℤ)) := by
    have h := congrArg Subtype.val hu
    push_cast at h
    rw [zpow_natCast]
    exact h
  rw [hcoe, W.ord_unit_smul_zpow u hπ (n : ℤ)]
  exact_mod_cast Nat.pos_of_ne_zero hn

def eIdx : ℕ := sInf {n : ℕ | 0 < n ∧ ∃ f : F, f ≠ 0 ∧ W.ord (φ f) = n}

variableW}

theorem mem_comap_iff_ord_nonneg {f : F} (hf : f ≠ 0) :
    f ∈ W.toValuationSubring.comap φ ↔ 0 ≤ W.ord (φ f) := by
  rw [ValuationSubring.mem_comap]
  exact mem_iff_ord_nonneg W ((map_ne_zero φ).mpr hf)

theorem eIdx_le_ord {f : F} (hf : f ≠ 0) (hpos : 0 < W.ord (φ f)) :
    (eIdx φ W : ℤ) ≤ W.ord (φ f) := by
  have h := Nat.sInf_le
    (s := {n : ℕ | 0 < n ∧ ∃ f : F, f ≠ 0 ∧ W.ord (φ f) = n})
    (m := (W.ord (φ f)).toNat) ⟨by omega, f, hf, by omega⟩
  rw [eIdx]
  omega

theorem isUnit_mk_comap_iff {f : F} (hf : f ≠ 0) (hmem : f ∈ W.toValuationSubring.comap φ) :
    IsUnit (⟨f, hmem⟩ : W.toValuationSubring.comap φ) ↔ W.ord (φ f) = 0 := by
  constructor
  · rintro h
    obtain ⟨b, hb⟩ := isUnit_iff_exists_inv.mp h
    have hb' : f * (b : F) = 1 := by
      simpa [Subtype.ext_iff] using hb
    have hbne : (b : F) ≠ 0 := by
      intro h0
      rw [h0, mul_zero] at hb'
      exact zero_ne_one hb'
    have hsum : W.ord (φ f) + W.ord (φ (b : F)) = 0 := by
      rw [← W.ord_mul ((map_ne_zero φ).mpr hf) ((map_ne_zero φ).mpr hbne), ← map_mul, hb',
        map_one, W.ord_one]
    have h1 : 0 ≤ W.ord (φ f) := (mem_comap_iff_ord_nonneg hf).mp hmem
    have h2 : 0 ≤ W.ord (φ (b : F)) := (mem_comap_iff_ord_nonneg hbne).mp b.2
    omega
  · intro h0
    have hinv : f⁻¹ ∈ W.toValuationSubring.comap φ :=
      (mem_comap_iff_ord_nonneg (inv_ne_zero hf)).mpr (by rw [map_inv₀, W.ord_inv]; omega)
    exact ⟨⟨⟨f, hmem⟩, ⟨f⁻¹, hinv⟩, Subtype.ext (mul_inv_cancel₀ hf),
      Subtype.ext (inv_mul_cancel₀ hf)⟩, rfl⟩

variable (hex : ∃ f : F, f ≠ 00 < W.ord (φ f))
include hex

theorem eIdx_set_nonempty :
    {n : ℕ | 0 < n ∧ ∃ f : F, f ≠ 0 ∧ W.ord (φ f) = n}.Nonempty := by
  obtain ⟨f, hf0, hf⟩ := hex
  exact ⟨(W.ord (φ f)).toNat, by omega, f, hf0, by omega⟩

theorem eIdx_pos : 0 < eIdx φ W :=
  (Nat.sInf_mem (eIdx_set_nonempty hex)).1

theorem exists_ord_eq_eIdx : ∃ f : F, f ≠ 0 ∧ W.ord (φ f) = eIdx φ W :=
  (Nat.sInf_mem (eIdx_set_nonempty hex)).2

theorem eIdx_dvd_ord {f : F} (hf : f ≠ 0) : (eIdx φ W : ℤ) ∣ W.ord (φ f) := by
  obtain ⟨g, hg0, hge⟩ := exists_ord_eq_eIdx hex
  set e : ℤ := (eIdx φ W : ℤ) with he
  have hepos : 0 < e := by
    have := eIdx_pos hex
    omega
  set m : ℤ := W.ord (φ f) with hm
  set q : ℤ := m / e with hq
  have hgq : φ (g ^ (-q)) = (φ g) ^ (-q) := map_zpow₀ _ _ _
  have hr : W.ord (φ (f * g ^ (-q))) = m - e * q := by
    rw [map_mul, W.ord_mul ((map_ne_zero φ).mpr hf)
      (by rw [hgq]; exact zpow_ne_zero _ ((map_ne_zero φ).mpr hg0)), hgq, W.ord_zpow, hge,
      ← hm]
    ring
  have hmod := Int.emod_nonneg m (by omega : e ≠ 0)
  have hmod' := Int.emod_lt_of_pos m hepos
  have hbridge : m % e = m - e * q := by
    rw [hq]
    exact Int.emod_def m e
  rcases eq_or_lt_of_le (show (0 : ℤ) ≤ m - e * q by omega) with heq | hlt
  · exact ⟨q, by omega⟩
  · exfalso
    have hfg : f * g ^ (-q) ≠ 0 := mul_ne_zero hf (zpow_ne_zero _ hg0)
    have hle := eIdx_le_ord (φ := φ) (W := W) hfg (by omega)
    rw [hr, ← he] at hle
    omega

theorem irreducible_mk_comap {g : F} (hg0 : g ≠ 0) (hmem : g ∈ W.toValuationSubring.comap φ)
    (hge : W.ord (φ g) = eIdx φ W) :
    Irreducible (⟨g, hmem⟩ : W.toValuationSubring.comap φ) := by
  have hepos : 0 < eIdx φ W := eIdx_pos hex
  constructor
  · rw [isUnit_mk_comap_iff hg0 hmem, hge]
    omega
  · rintro ⟨a, ha⟩ ⟨b, hb⟩ hab
    have hab' : g = a * b := by simpa [Subtype.ext_iff] using hab
    have ha0 : a ≠ 0 := by
      rintro rfl
      exact hg0 (by simpa using hab')
    have hb0 : b ≠ 0 := by
      rintro rfl
      exact hg0 (by simpa using hab')
    have hsum : W.ord (φ a) + W.ord (φ b) = eIdx φ W := by
      rw [← W.ord_mul ((map_ne_zero φ).mpr ha0) ((map_ne_zero φ).mpr hb0), ← map_mul, ← hab',
        hge]
    have ha' : 0 ≤ W.ord (φ a) := (mem_comap_iff_ord_nonneg ha0).mp ha
    have hb' : 0 ≤ W.ord (φ b) := (mem_comap_iff_ord_nonneg hb0).mp hb
    rcases eq_or_lt_of_le ha' with ha0' | hapos
    · exact Or.inl ((isUnit_mk_comap_iff ha0 ha).mpr ha0'.symm)
    rcases eq_or_lt_of_le hb' with hb0' | hbpos
    · exact Or.inr ((isUnit_mk_comap_iff hb0 hb).mpr hb0'.symm)
    exfalso
    have h1 := eIdx_le_ord (φ := φ) (W := W) ha0 hapos
    have h2 := eIdx_le_ord (φ := φ) (W := W) hb0 hbpos
    omega

theorem isPrincipalIdealRing_comap : IsPrincipalIdealRing (W.toValuationSubring.comap φ) := by
  obtain ⟨g, hg0, hge⟩ := exists_ord_eq_eIdx hex
  have hepos : 0 < eIdx φ W := eIdx_pos hex
  have hgmem : g ∈ W.toValuationSubring.comap φ :=
    (mem_comap_iff_ord_nonneg hg0).mpr (by omega)
  refine (IsDiscreteValuationRing.ofHasUnitMulPowIrreducibleFactorization
    ⟨⟨g, hgmem⟩, irreducible_mk_comap hex hg0 hgmem hge, ?_⟩).toIsPrincipalIdealRing
  rintro ⟨f, hmem⟩ hx
  have hf : f ≠ 0 := by simpa [Subtype.ext_iff] using hx
  obtain ⟨c, hc⟩ := eIdx_dvd_ord hex hf
  have hnonneg : 0 ≤ W.ord (φ f) := (mem_comap_iff_ord_nonneg hf).mp hmem
  have hcnonneg : 0 ≤ c := by
    by_contra hneg
    have hcle : c ≤ -1 := by omega
    have : (eIdx φ W : ℤ) * c ≤ (eIdx φ W : ℤ) * -1 :=
      mul_le_mul_of_nonneg_left hcle (by omega)
    omega
  set n : ℕ := c.toNat with hn
  have hcn : (n : ℤ) = c := Int.toNat_of_nonneg hcnonneg
  refine ⟨n, ?_⟩
  have hgn : g ^ n ≠ 0 := pow_ne_zero _ hg0
  have hdiv0 : f / g ^ n ≠ 0 := div_ne_zero hf hgn
  have hu0 : W.ord (φ (f / g ^ n)) = 0 := by
    have hkey : φ (f / g ^ n) = φ f * (φ g) ^ (-(n : ℤ)) := by
      rw [div_eq_mul_inv, map_mul, map_inv₀, map_pow, ← zpow_natCast (φ g) n, ← zpow_neg]
    rw [hkey, W.ord_mul ((map_ne_zero φ).mpr hf) (zpow_ne_zero _ ((map_ne_zero φ).mpr hg0)),
      W.ord_zpow, hge, hc, ← hcn]
    ring
  have humem : f / g ^ n ∈ W.toValuationSubring.comap φ :=
    (mem_comap_iff_ord_nonneg hdiv0).mpr (le_of_eq hu0.symm)
  have hu : IsUnit (⟨f / g ^ n, humem⟩ : W.toValuationSubring.comap φ) :=
    (isUnit_mk_comap_iff hdiv0 humem).mpr hu0
  refine ⟨hu.unit, ?_⟩
  refine Subtype.ext ?_
  have hcoe : ((hu.unit : W.toValuationSubring.comap φ) : F) = f / g ^ n := by
    rw [IsUnit.unit_spec]
  push_cast
  rw [hcoe, mul_comm, div_mul_cancel₀]
  exact hgn

theorem comap_ne_top : W.toValuationSubring.comap φ ≠ ⊤ := by
  obtain ⟨f, hf0, hf⟩ := hex
  intro htop
  have : f⁻¹ ∈ W.toValuationSubring.comap φ := htop ▸ trivial
  rw [mem_comap_iff_ord_nonneg (inv_ne_zero hf0), map_inv₀, W.ord_inv] at this
  omega

variable [Algebra K F]

omit hex in

def place (hφ : ∀ c : K, φ (algebraMap K F c) = algebraMap K Ω c)
    (hex : ∃ f : F, f ≠ 00 < W.ord (φ f)) : Place K F where
  toValuationSubring := W.toValuationSubring.comap φ
  algebraMap_mem' a := by
    rw [ValuationSubring.mem_comap, hφ]
    exact W.algebraMap_mem' a
  ne_top' := comap_ne_top hex
  isPrincipalIdealRing' := isPrincipalIdealRing_comap hex

omit hex in
@[simp] theorem place_toValuationSubring (hφ : ∀ c : K, φ (algebraMap K F c) = algebraMap K Ω c)
    (hex : ∃ f : F, f ≠ 00 < W.ord (φ f)) :
    (place hφ hex).toValuationSubring = W.toValuationSubring.comap φ := rfl

theorem ord_place_pos (hφ : ∀ c : K, φ (algebraMap K F c) = algebraMap K Ω c)
    {f : F} (hf : f ≠ 0) (hpos : 0 < W.ord (φ f)) : 0 < (place hφ hex).ord f := by
  have hmem : f ∈ W.toValuationSubring.comap φ := (mem_comap_iff_ord_nonneg hf).mpr hpos.le
  have hnot : ¬IsUnit (⟨f, hmem⟩ : W.toValuationSubring.comap φ) := by
    rw [isUnit_mk_comap_iff hf hmem]
    omega
  have hne : (⟨f, hmem⟩ : W.toValuationSubring.comap φ) ≠ 0 := fun h0 =>
    hf (congrArg Subtype.val h0)
  have hmax : (⟨f, hmem⟩ : W.toValuationSubring.comap φ) ∈
      maximalIdeal (W.toValuationSubring.comap φ) := (IsLocalRing.mem_maximalIdeal _).mpr hnot
  exact ord_pos_of_mem_maximalIdeal (place hφ hex) (a := ⟨f, hmem⟩) hmax hne

end ComapPlace

section TestDatum

variable (K : Type u) [Field K] [DecidableEq K] (N : ℕ)

structure ModuliTestDatum (x : ModuliPoint N K) (Ω : Type u) [Field Ω] [DecidableEq Ω]
    [Algebra K Ω] where

  W : Place K Ω

  curve : WeierstrassCurve W.toValuationSubring

  map_Δ_ne_zero : (curve.map (residue W.toValuationSubring)).Δ ≠ 0

  gen : (curve.map W.toValuationSubring.subtype).toAffine.Point

  addOrderOf_gen : addOrderOf gen = N

  res : ResidueField W.toValuationSubring →+* K

  res_algebraMap : ∀ c : K, res (algebraMap K (ResidueField W.toValuationSubring) c) = c

  reduction :
    letI := Classical.decEq (ResidueField W.toValuationSubring)
    ∃ hord : addOrderOf (reduceHom map_Δ_ne_zero gen) = N,
      ModuliPoint.map res
        (Quot.mk _ (⟨curve.map (residue W.toValuationSubring),
          ⟨isUnit_iff_ne_zero.mpr map_Δ_ne_zero⟩, reduceHom map_Δ_ne_zero gen, hord⟩ :
            Gamma0Pair N (ResidueField W.toValuationSubring))) = x

  emb : modularFunctionFieldFullC K N →ₐ[K] Ω

  emb_jqNFull : ∀ (Ω' : Type u) [Field Ω'] [DecidableEq Ω'] [IsAlgClosed Ω'] [Algebra Ω Ω']
      (d : ℕ) [NeZero d] (hd : d ∣ N),
      algebraMap Ω Ω' (emb (jqNFull K N d hd)) =
        ((curve.map W.toValuationSubring.subtype).map (algebraMap Ω Ω')).cyclicQuotientJ
          (AddSubgroup.zmultiples (WeierstrassCurve.mapPoint (algebraMap Ω Ω') ((N / d) • gen))) d

def IsModuliPlaceOf (x : ModuliPoint N K) (v : Place K (modularFunctionFieldFullC K N)) : Prop :=
  ∃ (Ω : Type u) (_ : Field Ω) (_ : DecidableEq Ω) (_ : Algebra K Ω) (D : ModuliTestDatum K N x Ω),
    v.toValuationSubring = D.W.toValuationSubring.comap D.emb.toRingHom

def moduliPlaceOfPoint (x : ModuliPoint N K) : Place K (modularFunctionFieldFullC K N) :=
  haveI := Classical.dec (∃ v, IsModuliPlaceOf K N x v)
  if h : ∃ v, IsModuliPlaceOf K N x v then h.choose else qInftyPlaceMod K (jqModC_mem_full K N)

def moduliPlace (E : WeierstrassCurve K) (C : AddSubgroup E.toAffine.Point) :
    Place K (modularFunctionFieldFullC K N) :=
  haveI := Classical.dec
    (E.IsElliptic ∧ ∃ g : E.toAffine.Point, addOrderOf g = N ∧ AddSubgroup.zmultiples g = C)
  if h : E.IsElliptic ∧ ∃ g : E.toAffine.Point, addOrderOf g = N ∧ AddSubgroup.zmultiples g = C then
    moduliPlaceOfPoint K N (Quot.mk _ (⟨E, h.1, h.2.choose, h.2.choose_spec.1⟩ : Gamma0Pair N K))
  else qInftyPlaceMod K (jqModC_mem_full K N)

end TestDatum

namespace ModuliTestDatum

variable {K : Type u} [Field K] [DecidableEq K] {N : ℕ} {x : ModuliPoint N K}
  {Ω : Type u} [Field Ω] [DecidableEq Ω] [Algebra K Ω] (D : ModuliTestDatum K N x Ω)

theorem isUnit_Δ : IsUnit D.curve.Δ := by
  have h := D.map_Δ_ne_zero
  rw [WeierstrassCurve.map_Δ] at h
  exact (residue_ne_zero_iff_isUnit _).mp h

instance isElliptic_curve : D.curve.IsElliptic := ⟨D.isUnit_Δ

instance isElliptic_generic : (D.curve.map D.W.toValuationSubring.subtype).IsElliptic :=
  inferInstance

instance isElliptic_reduced : (D.curve.map (residue D.W.toValuationSubring)).IsElliptic :=
  inferInstance

theorem res_injective : Function.Injective D.res := D.res.injective

theorem res_surjective : Function.Surjective D.res := fun c => ⟨_, D.res_algebraMap c⟩

def resEquiv : ResidueField D.W.toValuationSubring ≃+* K :=
  RingEquiv.ofBijective D.resD.res_injective, D.res_surjective

@[simp] theorem resEquiv_apply (a : ResidueField D.W.toValuationSubring) : D.resEquiv a = D.res a :=
  rfl

theorem algebraMap_res (a : ResidueField D.W.toValuationSubring) :
    algebraMap K (ResidueField D.W.toValuationSubring) (D.res a) = a :=
  D.res_injective (D.res_algebraMap _)

theorem res_residue_algebraMap (c : K) :
    D.res (residue D.W.toValuationSubring (algebraMap K D.W.toValuationSubring c)) = c :=
  D.res_algebraMap c

theorem res_residue_j : D.res (residue D.W.toValuationSubring D.curve.j) = x.j := by
  letI := Classical.decEq (ResidueField D.W.toValuationSubring)
  obtain ⟨hord, hx⟩ := D.reduction
  have h := congrArg ModuliPoint.j hx
  rw [ModuliPoint.j_map, ModuliPoint.j_mk, WeierstrassCurve.map_j] at h
  exact h

theorem emb_jqNFull_one :
    D.emb (jqNFull K N 1 (one_dvd N)) = (D.curve.map D.W.toValuationSubring.subtype).j := by
  letI := Classical.decEq (AlgebraicClosure Ω)
  have h := D.emb_jqNFull (AlgebraicClosure Ω) 1 (one_dvd N)
  rw [cyclicQuotientJ_one, WeierstrassCurve.map_c₄, WeierstrassCurve.map_Δ, ← map_pow,
    ← map_div₀] at h
  rw [(algebraMap Ω (AlgebraicClosure Ω)).injective h, WeierstrassCurve.j, div_eq_mul_inv, mul_comm,
    Units.val_inv_eq_inv_val, WeierstrassCurve.coe_Δ']

theorem emb_jModElt :
    D.emb (jModElt K (jqModC_mem_full K N)) = ((D.curve.j : D.W.toValuationSubring) : Ω) := by
  rw [← jqNFull_one, emb_jqNFull_one, WeierstrassCurve.map_j]
  rfl

theorem emb_algebraMap (c : K) : D.emb (algebraMap K _ c) = algebraMap K Ω c := D.emb.commutes c

theorem emb_jModElt_sub :
    D.emb (jModElt K (jqModC_mem_full K N) - algebraMap K _ x.j) =
      ((D.curve.j - algebraMap K D.W.toValuationSubring x.j : D.W.toValuationSubring) : Ω) := by
  rw [map_sub, emb_jModElt, emb_algebraMap]
  rfl

theorem j_sub_mem_maximalIdeal :
    (D.curve.j - algebraMap K D.W.toValuationSubring x.j) ∈ maximalIdeal D.W.toValuationSubring := by
  rw [← residue_eq_zero_iff, ← map_eq_zero_iff _ D.res_injective, map_sub, map_sub, res_residue_j,
    res_residue_algebraMap, sub_self]

theorem ord_emb_jModElt_sub_pos :
    0 < D.W.ord (D.emb (jModElt K (jqModC_mem_full K N) - algebraMap K _ x.j)) := by
  rw [emb_jModElt_sub]
  refine ComapPlace.ord_pos_of_mem_maximalIdeal D.W D.j_sub_mem_maximalIdeal ?_
  intro h0
  have h1 : D.emb (jModElt K (jqModC_mem_full K N) - algebraMap K _ x.j) = 0 := by
    rw [emb_jModElt_sub, h0]; rfl
  exact jModElt_sub_algebraMap_ne_zero K N x.j ((map_eq_zero_iff _ D.emb.toRingHom.injective).mp h1)

theorem exists_ord_emb_pos :
    ∃ f : modularFunctionFieldFullC K N, f ≠ 00 < D.W.ord (D.emb.toRingHom f) :=
  ⟨_, jModElt_sub_algebraMap_ne_zero K N x.j, D.ord_emb_jModElt_sub_pos

def place : Place K (modularFunctionFieldFullC K N) :=
  ComapPlace.place (φ := D.emb.toRingHom) (W := D.W) (fun c => D.emb.commutes c) D.exists_ord_emb_pos

@[simp] theorem place_toValuationSubring :
    D.place.toValuationSubring = D.W.toValuationSubring.comap D.emb.toRingHom := rfl

theorem mem_place_iff (f : modularFunctionFieldFullC K N) :
    f ∈ D.place.toValuationSubringD.emb f ∈ D.W.toValuationSubring := Iff.rfl

theorem ord_place_jModElt_sub_pos :
    0 < D.place.ord (jModElt K (jqModC_mem_full K N) - algebraMap K _ x.j) :=
  ComapPlace.ord_place_pos D.exists_ord_emb_pos _ (jModElt_sub_algebraMap_ne_zero K N x.j)
    D.ord_emb_jModElt_sub_pos

theorem isModuliPlaceOf_place : IsModuliPlaceOf K N x D.place :=
  ⟨Ω, ‹_›, ‹_›, ‹_›, D, rfl⟩

variable {D} in
theorem isModuliPlaceOf_iff_eq_place {v : Place K (modularFunctionFieldFullC K N)} :
    v.toValuationSubring = D.W.toValuationSubring.comap D.emb.toRingHom ↔ v = D.place :=
fun h => Place.ext h, fun h => h ▸ rfl⟩

theorem restrictAlong_place_toValuationSubring {F : Type*} [Field F] [Algebra K F]
    (φ : F →ₐ[K] modularFunctionFieldFullC K N) (hφ : φ.toRingHom.IsIntegral) :
    (D.place.restrictAlong φ hφ).toValuationSubring =
      D.W.toValuationSubring.comap (D.emb.toRingHom.comp φ.toRingHom) := rfl

theorem emb_jqNFull_self [NeZero N] (Ω' : Type u) [Field Ω'] [DecidableEq Ω'] [IsAlgClosed Ω']
    [Algebra Ω Ω'] :
    algebraMap Ω Ω' (D.emb (jqNFull K N N dvd_rfl)) =
      ((D.curve.map D.W.toValuationSubring.subtype).map (algebraMap Ω Ω')).cyclicQuotientJ
        (AddSubgroup.zmultiples (WeierstrassCurve.mapPoint (algebraMap Ω Ω') D.gen)) N := by
  rw [D.emb_jqNFull Ω' N dvd_rfl, Nat.div_self (Nat.pos_of_ne_zero (NeZero.ne N)), one_smul]

theorem addOrderOf_div_smul_gen [NeZero N] {d : ℕ} (hd : d ∣ N) :
    addOrderOf ((N / d) • D.gen) = d := by
  have hN : N ≠ 0 := NeZero.ne N
  have hd0 : 0 < d := Nat.pos_of_dvd_of_pos hd (Nat.pos_of_ne_zero hN)
  have hq : 0 < N / d := Nat.div_pos (Nat.le_of_dvd (Nat.pos_of_ne_zero hN) hd) hd0
  rw [addOrderOf_nsmul' _ hq.ne', D.addOrderOf_gen, Nat.gcd_eq_right (Nat.div_dvd_of_dvd hd),
    Nat.div_div_self hd hN]

section RestrictLevel

variable [NeZero N] {M : ℕ} [NeZero M]

omit [NeZero M] in

theorem addOrderOf_levelGen (hMN : M ∣ N) : addOrderOf ((N / M) • D.gen) = M :=
  D.addOrderOf_div_smul_gen hMN

theorem addOrderOf_reduceHom_levelGen (hMN : M ∣ N) :
    letI := Classical.decEq (ResidueField D.W.toValuationSubring)
    addOrderOf (reduceHom D.map_Δ_ne_zero ((N / M) • D.gen)) = M := by
  letI := Classical.decEq (ResidueField D.W.toValuationSubring)
  obtain ⟨hord, -⟩ := D.reduction
  have hN : N ≠ 0 := NeZero.ne N
  have hM0 : 0 < M := Nat.pos_of_ne_zero (NeZero.ne M)
  have hq : 0 < N / M := Nat.div_pos (Nat.le_of_dvd (Nat.pos_of_ne_zero hN) hMN) hM0
  rw [map_nsmul, addOrderOf_nsmul' _ hq.ne', hord, Nat.gcd_eq_right (Nat.div_dvd_of_dvd hMN),
    Nat.div_div_self hMN hN]

variable (hMN : M ∣ N) (x' : ModuliPoint M K)
  (hx' : letI := Classical.decEq (ResidueField D.W.toValuationSubring)
    ModuliPoint.map D.res
      (Quot.mk _ (⟨D.curve.map (residue D.W.toValuationSubring),
        ⟨isUnit_iff_ne_zero.mpr D.map_Δ_ne_zero⟩, reduceHom D.map_Δ_ne_zero ((N / M) • D.gen),
          D.addOrderOf_reduceHom_levelGen hMN⟩ :
            Gamma0Pair M (ResidueField D.W.toValuationSubring))) = x')

def restrictLevel : ModuliTestDatum K M x' Ω where
  W := D.W
  curve := D.curve
  map_Δ_ne_zero := D.map_Δ_ne_zero
  gen := (N / M) • D.gen
  addOrderOf_gen := D.addOrderOf_levelGen hMN
  res := D.res
  res_algebraMap := D.res_algebraMap
  reduction := ⟨D.addOrderOf_reduceHom_levelGen hMN, hx'⟩
  emb := D.emb.comp (IntermediateField.inclusion (full_degeneracyC_le K hMN))
  emb_jqNFull Ω' _ _ _ _ d _ hd := by
    have hsmul : (M / d) • ((N / M) • D.gen) = (N / d) • D.gen := by
      rw [smul_smul, ModuliPlaceAux.div_mul_div_cancel_of_dvd hd hMN (NeZero.ne M)]
    have h := D.emb_jqNFull Ω' d (hd.trans hMN)
    rw [← hsmul] at h
    exact h

@[simp] theorem restrictLevel_W : (D.restrictLevel hMN x' hx').W = D.W := rfl

@[simp] theorem restrictLevel_curve : (D.restrictLevel hMN x' hx').curve = D.curve := rfl

@[simp] theorem restrictLevel_gen : (D.restrictLevel hMN x' hx').gen = (N / M) • D.gen := rfl

@[simp] theorem restrictLevel_res : (D.restrictLevel hMN x' hx').res = D.res := rfl

@[simp] theorem restrictLevel_emb :
    (D.restrictLevel hMN x' hx').emb =
      D.emb.comp (IntermediateField.inclusion (full_degeneracyC_le K hMN)) :=
  rfl

theorem restrictLevel_emb_jqNFull (d : ℕ) [NeZero d] (hd : d ∣ M) :
    (D.restrictLevel hMN x' hx').emb (jqNFull K M d hd) = D.emb (jqNFull K N d (hd.trans hMN)) :=
  rfl

theorem restrictLevel_place_toValuationSubring :
    (D.restrictLevel hMN x' hx').place.toValuationSubring =
      D.place.toValuationSubring.comap
        (IntermediateField.inclusion (full_degeneracyC_le K hMN)).toRingHom := rfl

theorem restrictAlong_inclusion_place
    (hι : (IntermediateField.inclusion (full_degeneracyC_le K hMN)).toRingHom.IsIntegral) :
    D.place.restrictAlong (IntermediateField.inclusion (full_degeneracyC_le K hMN)) hι =
      (D.restrictLevel hMN x' hx').place :=
  Place.ext rfl

include hx' in

theorem isModuliPlaceOf_restrictAlong_inclusion
    (hι : (IntermediateField.inclusion (full_degeneracyC_le K hMN)).toRingHom.IsIntegral)
    {v : Place K (modularFunctionFieldFullC K N)}
    (hv : v.toValuationSubring = D.W.toValuationSubring.comap D.emb.toRingHom) :
    IsModuliPlaceOf K M x'
      (v.restrictAlong (IntermediateField.inclusion (full_degeneracyC_le K hMN)) hι) := by
  have hv' : v = D.place := Place.ext hv
  subst hv'
  refine ⟨Ω, ‹_›, ‹_›, ‹_›, D.restrictLevel hMN x' hx', ?_⟩
  exact congrArg Place.toValuationSubring (D.restrictAlong_inclusion_place hMN x' hx' hι)

end RestrictLevel

end ModuliTestDatum

section API

variable (K : Type u) [Field K] [DecidableEq K] (N : ℕ)

variable {K N} in

theorem IsModuliPlaceOf.ord_jModElt_sub_pos {x : ModuliPoint N K}
    {v : Place K (modularFunctionFieldFullC K N)} (hv : IsModuliPlaceOf K N x v) :
    0 < v.ord (jModElt K (jqModC_mem_full K N) - algebraMap K _ x.j) := by
  obtain ⟨Ω, _, _, _, D, hD⟩ := hv
  rw [ModuliTestDatum.isModuliPlaceOf_iff_eq_place.mp hD]
  exact D.ord_place_jModElt_sub_pos

theorem isModuliPlaceOf_moduliPlaceOfPoint {x : ModuliPoint N K}
    (h : ∃ v, IsModuliPlaceOf K N x v) : IsModuliPlaceOf K N x (moduliPlaceOfPoint K N x) := by
  rw [moduliPlaceOfPoint, dif_pos h]
  exact h.choose_spec

theorem moduliPlaceOfPoint_of_not_exists {x : ModuliPoint N K}
    (h : ¬∃ v, IsModuliPlaceOf K N x v) :
    moduliPlaceOfPoint K N x = qInftyPlaceMod K (jqModC_mem_full K N) := by
  rw [moduliPlaceOfPoint, dif_neg h]

theorem moduliPlaceOfPoint_eq_of_forall_eq {x : ModuliPoint N K}
    (huniq : ∀ v v', IsModuliPlaceOf K N x v → IsModuliPlaceOf K N x v' → v = v')
    {v : Place K (modularFunctionFieldFullC K N)} (hv : IsModuliPlaceOf K N x v) :
    moduliPlaceOfPoint K N x = v :=
  huniq _ _ (isModuliPlaceOf_moduliPlaceOfPoint K N ⟨v, hv⟩) hv

theorem ModuliTestDatum.moduliPlaceOfPoint_eq_place {x : ModuliPoint N K}
    (huniq : ∀ v v', IsModuliPlaceOf K N x v → IsModuliPlaceOf K N x v' → v = v')
    {Ω : Type u} [Field Ω] [DecidableEq Ω] [Algebra K Ω] (D : ModuliTestDatum K N x Ω) :
    moduliPlaceOfPoint K N x = D.place :=
  moduliPlaceOfPoint_eq_of_forall_eq K N huniq D.isModuliPlaceOf_place

theorem moduliPlace_of_not {E : WeierstrassCurve K} {C : AddSubgroup E.toAffine.Point}
    (h : ¬(E.IsElliptic ∧ ∃ g : E.toAffine.Point, addOrderOf g = N ∧ AddSubgroup.zmultiples g = C)) :
    moduliPlace K N E C = qInftyPlaceMod K (jqModC_mem_full K N) := by
  rw [moduliPlace, dif_neg h]

theorem moduliPlace_of_not_isElliptic {E : WeierstrassCurve K} (hE : ¬E.IsElliptic)
    (C : AddSubgroup E.toAffine.Point) :
    moduliPlace K N E C = qInftyPlaceMod K (jqModC_mem_full K N) :=
  moduliPlace_of_not K N fun h => hE h.1

variable {K N} in
omit [DecidableEq K] in

theorem ModuliPlaceAux.heq_vcInvFun_one (E : WeierstrassCurve K) (P : E.toAffine.Point) :
    HEq (Point.vcInvFun (1 : VariableChange K) E.toAffine P) P := by
  have hE : ((1 : VariableChange K) • E.toAffine).toAffine = E.toAffine := one_smul _ _
  cases P with
  | zero => exact Point.heq_zero hE
  | some x y h =>
    refine Point.heq_some hE ?_ ?_
    · simp [vcXInv, VariableChange.one_def]
    · simp [vcYInv, VariableChange.one_def]

variable {K N} in

theorem ModuliPoint.mk_eq_mk_of_zmultiples_eq [NeZero N] {E : WeierstrassCurve K} [hE : E.IsElliptic]
    {g g' : E.toAffine.Point} (hg : addOrderOf g = N) (hg' : addOrderOf g' = N)
    (h : AddSubgroup.zmultiples g = AddSubgroup.zmultiples g') :
    (Quot.mk _ (⟨E, hE, g, hg⟩ : Gamma0Pair N K) : ModuliPoint N K) =
      Quot.mk _ (⟨E, hE, g', hg'⟩ : Gamma0Pair N K) := by

  have hmem : g' ∈ AddSubgroup.zmultiples g := h ▸ AddSubgroup.mem_zmultiples g'
  obtain ⟨m, hm⟩ := AddSubgroup.mem_zmultiples_iff.mp hmem
  have hN0 : N ≠ 0 := NeZero.ne N
  have hN : (N : ℤ) ≠ 0 := by exact_mod_cast hN0
  set a : ℕ := (m % (N : ℤ)).toNat with ha
  have ham : (a : ℤ) = m % (N : ℤ) := Int.toNat_of_nonneg (Int.emod_nonneg _ hN)
  set k : ℕ := a + N with hk
  have hag : a • g = g' := by
    rw [← hm, ← natCast_zsmul, ham, ← hg, mod_addOrderOf_zsmul]
  have hkg : k • g = g' := by
    rw [hk, add_nsmul, hag, ← hg, addOrderOf_nsmul_eq_zero, add_zero]
  have hk0 : k ≠ 0 := by
    rw [hk]; omega
  have hcop : k.Coprime N := by
    have h1 : addOrderOf (k • g) = N := by rw [hkg, hg']
    rw [addOrderOf_nsmul' g hk0, hg] at h1
    have h2 : N.gcd k = 1 := by
      have h3 := Nat.div_mul_cancel (Nat.gcd_dvd_left N k)
      rw [h1] at h3
      exact Nat.eq_of_mul_eq_mul_left (Nat.pos_of_ne_zero hN0) (h3.trans (mul_one N).symm)
    exact Nat.coprime_comm.mp h2
  refine Quot.sound ⟨1, one_smul _ _, k, hcop, ?_⟩

  show HEq g' (k • Point.vcInvFun (1 : VariableChange K) E.toAffine g)
  rw [← hkg]
  have hE1 : ((1 : VariableChange K) • E.toAffine).toAffine = E.toAffine := one_smul _ _
  exact (Point.heq_nsmul hE1 k (ModuliPlaceAux.heq_vcInvFun_one E g)).symm

theorem moduliPlace_zmultiples [NeZero N] (E : WeierstrassCurve K) [hE : E.IsElliptic]
    (g : E.toAffine.Point) (hg : addOrderOf g = N) :
    moduliPlace K N E (AddSubgroup.zmultiples g) =
      moduliPlaceOfPoint K N (Quot.mk _ (⟨E, hE, g, hg⟩ : Gamma0Pair N K)) := by
  have h : E.IsElliptic ∧ ∃ g' : E.toAffine.Point, addOrderOf g' = N ∧
      AddSubgroup.zmultiples g' = AddSubgroup.zmultiples g := ⟨hE, g, hg, rfl⟩
  rw [moduliPlace, dif_pos h]
  congr 1
  exact ModuliPoint.mk_eq_mk_of_zmultiples_eq h.2.choose_spec.1 hg h.2.choose_spec.2

theorem isModuliPlaceOf_moduliPlace [NeZero N] (E : WeierstrassCurve K) [hE : E.IsElliptic]
    (g : E.toAffine.Point) (hg : addOrderOf g = N)
    (h : ∃ v, IsModuliPlaceOf K N (Quot.mk _ (⟨E, hE, g, hg⟩ : Gamma0Pair N K)) v) :
    IsModuliPlaceOf K N (Quot.mk _ (⟨E, hE, g, hg⟩ : Gamma0Pair N K))
      (moduliPlace K N E (AddSubgroup.zmultiples g)) := by
  rw [moduliPlace_zmultiples K N E g hg]
  exact isModuliPlaceOf_moduliPlaceOfPoint K N h

theorem ord_moduliPlace_jModElt_sub_pos [NeZero N] (E : WeierstrassCurve K) [hE : E.IsElliptic]
    (g : E.toAffine.Point) (hg : addOrderOf g = N)
    (h : ∃ v, IsModuliPlaceOf K N (Quot.mk _ (⟨E, hE, g, hg⟩ : Gamma0Pair N K)) v) :
    0 < (moduliPlace K N E (AddSubgroup.zmultiples g)).ord
      (jModElt K (jqModC_mem_full K N) - algebraMap K _ E.j) :=
  (isModuliPlaceOf_moduliPlace K N E g hg h).ord_jModElt_sub_pos

end API

end ModularCurve

end

Statements phrased using this module (94)