Fermat's Last Theorem in Lean 4

← all definition modules

Definitions/Def_NumberField_NormResidueCharacter.lean

definition module

Norm-residue characters on narrow ray class groups

Throughout, K is a number field and m a nonzero natural number. The modulus used here is fm K m, the ideal m\mathcal{O}_K = Ideal.span {(m : π“ž K)}, which is shown to be nonzero; the narrow ray class group of K of modulus m\mathcal{O}_K is thereby finite and is equipped with a Fintype. The homomorphism nu is the project's norm class character normClassChar K m taken at the modulus m\mathcal{O}_K itself (via dvd_refl): it is the descent to the narrow ray class group of the multiplicative ray symbol built from normClass K m, which sends a height-one prime v to the unit class of N v = Ideal.absNorm v.asIdeal in (\mathbb{Z}/m)^\times when N v is coprime to m, and to 1 otherwise. For a Dirichlet character \psi modulo m with values in \mathbb{C}, chi K m ψ is the composite \psi \circ \nu, a monoid homomorphism from the narrow ray class group to \mathbb{C}; it is multiplicative in \psi and sends the trivial character to 1. The accompanying computations identify the associated ideal function M4aP2.chiIdeal of chi K m ψ: on a prime v it is 0 when v \mid m\mathcal{O}_K and \psi(N v \bmod m) otherwise (uniformly, \psi(N v), since \psi kills nonunits), and on a principal ideal (\alpha) with \alpha \neq 0 and \alpha - 1 \in m\mathcal{O}_K it is \psi of the sign of \mathrm{N}_{K/\mathbb{Q}}(\alpha). Correspondingly paritySet ψ is the empty set of real infinite places if \psi(-1) = 1 and the set of all of them otherwise; \psi(-1) is shown to be \pm 1.

A second group of declarations works over a field L that is an m-th cyclotomic extension of K, with \zeta \in L a primitive m-th root of unity. Here U0 K m hΞΆ is the image in (\mathbb{Z}/m)^\times of the cyclotomic character hΞΆ.autToPow K of \mathrm{Gal}(L/K), a subgroup of cardinality [L:K]. It is proved that N\mathfrak{P} \equiv 1 \pmod m for every prime \mathfrak{P} of L with m \notin \mathfrak{P}, that the fibre of primes of L above a prime of K is finite with at most [L:K] elements (its cardinality being that of the set of primes over the corresponding ideal), that a prime of L whose absolute norm is a rational prime has the same absolute norm as the prime of K below it, and that normClass K m v lies in U0 for every height-one prime v of K β€” via the cyclotomic index of an arithmetic Frobenius at a prime above v β€” whence nu takes values in U0 and its range is contained in U0.

Relation to Mathlib

Mathlib supplies DirichletCharacter, Ideal.absNorm, IsPrimitiveRoot.autToPow and the theory of primes over a prime in a Dedekind extension; the narrow ray class group, the ray symbol and the ideal-valued extension M4aP2.chiIdeal used here are the project's own notions, and U0 is simply the image of Mathlib's IsPrimitiveRoot.autToPow.

Where it is used

These characters supply the Hecke-character vocabulary used in the Artin/Langlands–Tunnell part of the argument, where Dirichlet characters modulo m are pulled back to narrow ray class characters of a number field and compared with cyclotomic data.

References

  1. E. Hecke, Über die L-Funktionen und den Dirichletschen Primzahlsatz fΓΌr einen beliebigen ZahlkΓΆrper, Nachrichten von der Gesellschaft der Wissenschaften zu GΓΆttingen (1917), Β§Β§1–2
  2. S. Lang, Algebraic Number Theory, Graduate Texts in Mathematics 110, Springer, 2nd ed., 1994, Chapters VI and VIII
  3. J. Neukirch, Algebraic Number Theory, Grundlehren der mathematischen Wissenschaften 322, Springer, 1999, Chapter VII

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

Imports

Imported by

  • no other definition module

Declarations

Source

import Mathlib
import Definitions.Def_LanglandsTunnell_NormClass
import Definitions.Def_NumberField_RayCharacterData

set_option autoImplicit false
set_option linter.unusedSectionVars false

noncomputable section

namespace NumberField.NormResidueChar

open NumberField NumberField.InfinitePlace IsDedekindDomain Deep.NTSupply
open LanglandsTunnell.P2.Artin
open scoped nonZeroDivisors Classical

variable (K : Type) [Field K] [NumberField K] (m : β„•) [NeZero m]

abbrev fm : Ideal (π“ž K) := Ideal.span {(m : π“ž K)}

theorem fm_ne_bot : fm K m β‰  βŠ₯ := by
  rw [fm, Ne, Ideal.span_singleton_eq_bot]
  exact_mod_cast NeZero.ne m

instance finite_G : Finite (NarrowRayClassGroup K (fm K m)) := Deep.NTSupply.finite K (fm_ne_bot K m)

noncomputable instance fintype_G : Fintype (NarrowRayClassGroup K (fm K m)) := Fintype.ofFinite _

def nu : NarrowRayClassGroup K (fm K m) β†’* (ZMod m)Λ£ := normClassChar K m (dvd_refl _)

def chi (ψ : DirichletCharacter β„‚ m) : NarrowRayClassGroup K (fm K m) β†’* β„‚ :=
  (Units.coeHom β„‚).comp ((MulChar.toUnitHom ψ).comp (nu K m))

theorem chi_apply (ψ : DirichletCharacter β„‚ m) (g : NarrowRayClassGroup K (fm K m)) :
    chi K m ψ g = ψ ((nu K m g : (ZMod m)ˣ) : ZMod m) := by
  simp [chi]

theorem chi_mul (ψ ΞΈ : DirichletCharacter β„‚ m) : chi K m (ψ * ΞΈ) = chi K m ψ * chi K m ΞΈ := by
  refine MonoidHom.ext fun g => ?_
  rw [MonoidHom.mul_apply, chi_apply, chi_apply, chi_apply, MulChar.mul_apply]

theorem chi_one : chi K m 1 = 1 := by
  refine MonoidHom.ext fun g => ?_
  rw [chi_apply, MonoidHom.one_apply, MulChar.one_apply_coe]

variable {K m}

theorem dvd_fm_iff (v : HeightOneSpectrum (π“ž K)) : v.asIdeal ∣ fm K m ↔ (m : π“ž K) ∈ v.asIdeal := by
  rw [fm, Ideal.dvd_span_singleton]

theorem absNorm_mem (v : HeightOneSpectrum (π“ž K)) : ((Ideal.absNorm v.asIdeal : β„•) : π“ž K) ∈ v.asIdeal :=
  Ideal.absNorm_mem v.asIdeal

theorem not_coprime_of_mem {v : HeightOneSpectrum (π“ž K)} (hv : (m : π“ž K) ∈ v.asIdeal) :
    Β¬ (Ideal.absNorm v.asIdeal).Coprime m := by
  intro hcop
  apply v.isPrime.ne_top
  rw [Ideal.eq_top_iff_one]
  have hg := Nat.gcd_eq_gcd_ab (Ideal.absNorm v.asIdeal) m
  rw [Nat.Coprime.gcd_eq_one hcop] at hg
  have h1' : (1 : π“ž K) = (Ideal.absNorm v.asIdeal : π“ž K) * (Nat.gcdA (Ideal.absNorm v.asIdeal) m : π“ž K) +
      (m : π“ž K) * (Nat.gcdB (Ideal.absNorm v.asIdeal) m : π“ž K) := by
    have := congrArg (fun z : β„€ => (z : π“ž K)) hg
    push_cast at this
    exact this
  rw [h1']
  exact v.asIdeal.add_mem (v.asIdeal.mul_mem_right _ (absNorm_mem v)) (v.asIdeal.mul_mem_right _ hv)

theorem coprime_of_not_mem {v : HeightOneSpectrum (π“ž K)} (hv : (m : π“ž K) βˆ‰ v.asIdeal) :
    (Ideal.absNorm v.asIdeal).Coprime m :=
  absNorm_coprime_of_not_dvd K m v (by rwa [dvd_fm_iff] at *)

theorem mk0_prime_mem_iff {𝔣 : Ideal (π“ž K)} (v : HeightOneSpectrum (π“ž K))
    (h : (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) β‰  0) :
    Units.mk0 (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) h ∈ coprimeToModulus K 𝔣 ↔ Β¬ v.asIdeal ∣ 𝔣 := by
  rw [mem_coprimeToModulus_iff]
  constructor
  Β· intro hc hv
    have := hc v hv
    rw [Units.val_mk0, FractionalIdeal.count_self] at this
    exact one_ne_zero this
  Β· intro hv w hw
    rw [Units.val_mk0]
    exact FractionalIdeal.count_maximal_coprime K w (fun h => hv (h β–Έ hw))

theorem chiIdeal_prime {𝔣 : Ideal (π“ž K)} (Ο‡ : NarrowRayClassGroup K 𝔣 β†’* β„‚)
    (v : HeightOneSpectrum (π“ž K)) :
    M4aP2.chiIdeal K 𝔣 Ο‡ (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) =
      if hv : v.asIdeal ∣ 𝔣 then 0 else Ο‡ (primeClass K 𝔣 v hv) := by
  have h0 : (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) β‰  0 := by
    rw [Ne, FractionalIdeal.coeIdeal_eq_zero]
    exact v.ne_bot
  rw [M4aP2.chiIdeal, dif_pos h0]
  by_cases hv : v.asIdeal ∣ 𝔣
  Β· rw [dif_pos hv, dif_neg (by rw [mk0_prime_mem_iff]; exact not_not.mpr hv)]
  Β· have hc : Units.mk0 (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) h0 ∈ coprimeToModulus K 𝔣 := by
      rwa [mk0_prime_mem_iff]
    rw [dif_neg hv, dif_pos hc, primeClass]
    have heq : (⟨Units.mk0 _ h0, hc⟩ : β†₯(coprimeToModulus K 𝔣)) =
        ⟨primeUnit K v, primeUnit_mem_coprimeToModulus K hv⟩ :=
      Subtype.ext (Units.ext (by rw [Units.val_mk0, primeUnit_val]))
    rw [heq]

theorem chi_primeClass (ψ : DirichletCharacter β„‚ m) (v : HeightOneSpectrum (π“ž K))
    (hv : ¬ v.asIdeal ∣ fm K m) :
    chi K m ψ (primeClass K (fm K m) v hv) = ψ (Ideal.absNorm v.asIdeal : ZMod m) := by
  rw [chi_apply, nu, normClassChar_primeClass, normClass_coe]
  exact coprime_of_not_mem (by rwa [dvd_fm_iff] at hv)

theorem chiIdeal_chi (ψ : DirichletCharacter β„‚ m) (v : HeightOneSpectrum (π“ž K)) :
    M4aP2.chiIdeal K (fm K m) (chi K m ψ) (v.asIdeal : FractionalIdeal (π“ž K)⁰ K) =
      ψ (Ideal.absNorm v.asIdeal : ZMod m) := by
  rw [chiIdeal_prime]
  by_cases hv : v.asIdeal ∣ fm K m
  Β· rw [dif_pos hv, eq_comm]
    apply MulChar.map_nonunit
    rw [ZMod.isUnit_iff_coprime]
    exact not_coprime_of_mem ((dvd_fm_iff v).mp hv)
  Β· rw [dif_neg hv, chi_primeClass]

def paritySet (ψ : DirichletCharacter β„‚ m) : Finset {w : InfinitePlace K // w.IsReal} :=
  if ψ (-1) = 1 then βˆ… else Finset.univ

theorem psi_neg_one_sq (ψ : DirichletCharacter β„‚ m) : ψ (-1) * ψ (-1) = 1 := by
  rw [← map_mul, neg_mul_neg, one_mul, map_one]

theorem psi_neg_one_eq (ψ : DirichletCharacter β„‚ m) : ψ (-1) = 1 ∨ ψ (-1) = -1 := by
  have h := psi_neg_one_sq ψ
  have : (ψ (-1) - 1) * (ψ (-1) + 1) = 0 := by ring_nf; rw [sq, h]; ring
  rcases mul_eq_zero.mp this with h1 | h1
  Β· left; exact sub_eq_zero.mp h1
  Β· right; exact eq_neg_of_add_eq_zero_left h1

theorem chiIdeal_chi_span (ψ : DirichletCharacter β„‚ m) {Ξ± : π“ž K} (hΞ± : Ξ± β‰  0)
    (h1 : α - 1 ∈ fm K m) :
    M4aP2.chiIdeal K (fm K m) (chi K m ψ) ((Ideal.span {Ξ±} : Ideal (π“ž K)) : FractionalIdeal (π“ž K)⁰ K) =
      ψ ((SignType.sign (Algebra.norm β„€ Ξ±) : β„€) : ZMod m) := by
  have hspan : (Ideal.span {Ξ±} : Ideal (π“ž K)) β‰  βŠ₯ := by
    rw [Ne, Ideal.span_singleton_eq_bot]; exact hΞ±
  have h0 : ((Ideal.span {Ξ±} : Ideal (π“ž K)) : FractionalIdeal (π“ž K)⁰ K) β‰  0 := by
    rw [Ne, FractionalIdeal.coeIdeal_eq_zero]; exact hspan
  have hcmem : Units.mk0 _ h0 ∈ coprimeToModulus K (fm K m) := by
    have h := principalUnit_mem_coprimeToModulus K hΞ± h1
    rw [mem_coprimeToModulus_iff] at h ⊒
    intro v hv
    have := h v hv
    rwa [principalUnit_val] at this
  rw [M4aP2.chiIdeal, dif_pos h0, dif_pos hcmem, chi_apply, nu, normClassChar, raySymbolDescend_mk,
    raySymbolHom_apply]
  have hcop : (Ideal.span {Ξ±} : Ideal (π“ž K)) βŠ” Ideal.span {(m : π“ž K)} = ⊀ := by
    rw [Ideal.eq_top_iff_one]
    have h1' : Ξ± - (Ξ± - 1) = 1 := by ring
    exact h1' β–Έ Submodule.sub_mem _
      (Ideal.mem_sup_left (Ideal.subset_span rfl))
      (Ideal.mem_sup_right h1)
  have hval : ((⟨Units.mk0 _ h0, hcmem⟩ : β†₯(coprimeToModulus K (fm K m))) : (FractionalIdeal (π“ž K)⁰ K)Λ£) =
      Units.mk0 _ h0 := rfl
  rw [hval, Units.val_mk0, raySymbol_normClass_coe K m hspan hcop, Ideal.absNorm_span_singleton]
  congr 1

  have hN1 : ((Algebra.norm β„€ Ξ± : β„€) : ZMod m) = 1 := norm_int_cast_eq_one_of_sub_one_mem K m h1
  have habs : ((Algebra.norm β„€ Ξ±).natAbs : β„€) = (SignType.sign (Algebra.norm β„€ Ξ±) : β„€) * Algebra.norm β„€ Ξ± := by
    rw [← Int.sign_eq_sign, Int.sign_mul_self_eq_natAbs]
  rw [← Int.cast_natCast (R := ZMod m) (Algebra.norm β„€ Ξ±).natAbs, habs, Int.cast_mul, hN1, mul_one]

section Cyclo

variable {L : Type} [Field L] [NumberField L] [Algebra K L] [IsCyclotomicExtension {m} K L]

theorem absNorm_cast_eq_one {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) (w : HeightOneSpectrum (π“ž L))
    (hw : (m : π“ž L) βˆ‰ w.asIdeal) : (Ideal.absNorm w.asIdeal : ZMod m) = 1 := by
  have hΞΆ' : IsPrimitiveRoot hΞΆ.toInteger m := hΞΆ.toInteger_isPrimitiveRoot
  have hcop : (Ideal.absNorm w.asIdeal).Coprime m := coprime_of_not_mem hw
  have hN1 : Ideal.absNorm w.asIdeal β‰  1 := by
    rw [Ne, Ideal.absNorm_eq_one_iff]; exact w.isPrime.ne_top
  haveI : w.asIdeal.IsMaximal := w.isPrime.isMaximal w.ne_bot
  letI : Field (π“ž L β§Έ w.asIdeal) := Ideal.Quotient.field w.asIdeal
  letI : Fintype (π“ž L β§Έ w.asIdeal) := Fintype.ofFinite _
  have hinj := Ideal.rootsOfUnityMapQuot_injective (I := w.asIdeal) m hN1 hcop
  have hdvd := Subgroup.card_dvd_of_injective _ hinj
  rw [hΞΆ'.card_rootsOfUnity, Nat.card_units, ← Submodule.cardQuot_apply,
    ← Ideal.absNorm_apply] at hdvd
  have hpos : 1 ≀ Ideal.absNorm w.asIdeal := Nat.one_le_iff_ne_zero.mpr (by
    rw [Ne, Ideal.absNorm_eq_zero_iff]; exact w.ne_bot)
  have : ((Ideal.absNorm w.asIdeal : β„•) : ZMod m) = ((Ideal.absNorm w.asIdeal - 1 + 1 : β„•) : ZMod m) := by
    rw [Nat.sub_add_cancel hpos]
  rw [this, Nat.cast_add, Nat.cast_one, (ZMod.natCast_eq_zero_iff _ _).mpr hdvd, zero_add]

theorem mem_primesOver_of_under_eq {w : HeightOneSpectrum (π“ž L)} {v : HeightOneSpectrum (π“ž K)}
    (h : w.under (π“ž K) = v) : w.asIdeal ∈ v.asIdeal.primesOver (π“ž L) := by
  refine ⟨w.isPrime, ⟨?_⟩⟩
  rw [← h]
  rfl

include m in

theorem ncard_primesOver_le (v : HeightOneSpectrum (π“ž K)) :
    (v.asIdeal.primesOver (π“ž L)).ncard ≀ Module.finrank K L := by
  haveI : IsGalois K L := IsCyclotomicExtension.isGalois {m} K L
  haveI : IsGaloisGroup (L ≃ₐ[K] L) (π“ž K) (π“ž L) :=
    IsGaloisGroup.of_isFractionRing (L ≃ₐ[K] L) (π“ž K) (π“ž L) K L
  haveI : v.asIdeal.IsMaximal := v.isPrime.isMaximal v.ne_bot
  have h := Ideal.ncard_primesOver_mul_ramificationIdxIn_mul_inertiaDegIn v.asIdeal (π“ž L) (L ≃ₐ[K] L)
  rw [IsGalois.card_aut_eq_finrank] at h
  have hpos : 0 < Module.finrank K L := Module.finrank_pos
  have hne : v.asIdeal.ramificationIdxIn (π“ž L) * v.asIdeal.inertiaDegIn (π“ž L) β‰  0 := by
    intro h0
    rw [h0, mul_zero] at h
    omega
  calc (v.asIdeal.primesOver (π“ž L)).ncard
      ≀ (v.asIdeal.primesOver (π“ž L)).ncard * (v.asIdeal.ramificationIdxIn (π“ž L) * v.asIdeal.inertiaDegIn (π“ž L)) :=
        Nat.le_mul_of_pos_right _ (Nat.pos_of_ne_zero hne)
    _ = Module.finrank K L := h

theorem ncard_fibre_eq (v : HeightOneSpectrum (π“ž K)) :
    {w : HeightOneSpectrum (π“ž L) | w.under (π“ž K) = v}.ncard = (v.asIdeal.primesOver (π“ž L)).ncard := by
  have hinj : Set.InjOn (fun w : HeightOneSpectrum (π“ž L) => w.asIdeal) {w | w.under (π“ž K) = v} :=
    fun _ _ _ _ h => HeightOneSpectrum.ext h
  rw [← hinj.ncard_image]
  congr 1
  ext I
  constructor
  · rintro ⟨w, hw, rfl⟩
    exact mem_primesOver_of_under_eq hw
  · rintro ⟨hI, hIo⟩
    have hIbot : I β‰  βŠ₯ := Ideal.ne_bot_of_liesOver_of_ne_bot v.ne_bot I
    refine ⟨⟨I, hI, hIbot⟩, ?_, rfl⟩
    apply HeightOneSpectrum.ext
    rw [HeightOneSpectrum.under_asIdeal]
    exact hIo.over.symm

theorem finite_fibre (v : HeightOneSpectrum (π“ž K)) :
    {w : HeightOneSpectrum (π“ž L) | w.under (π“ž K) = v}.Finite := by
  have hinj : Set.InjOn (fun w : HeightOneSpectrum (π“ž L) => w.asIdeal) {w | w.under (π“ž K) = v} :=
    fun _ _ _ _ h => HeightOneSpectrum.ext h
  haveI : v.asIdeal.IsMaximal := v.isPrime.isMaximal v.ne_bot
  refine Set.Finite.of_finite_image ?_ hinj
  refine (IsDedekindDomain.primesOver_finite v.asIdeal (π“ž L)).subset ?_
  rintro _ ⟨w, hw, rfl⟩
  exact mem_primesOver_of_under_eq hw

include m in
theorem ncard_fibre_le (v : HeightOneSpectrum (π“ž K)) :
    {w : HeightOneSpectrum (π“ž L) | w.under (π“ž K) = v}.ncard ≀ Module.finrank K L := by
  rw [ncard_fibre_eq]
  exact ncard_primesOver_le (m := m) v

theorem absNorm_under_eq_of_prime (w : HeightOneSpectrum (π“ž L)) (hp : (Ideal.absNorm w.asIdeal).Prime) :
    Ideal.absNorm (w.under (π“ž K)).asIdeal = Ideal.absNorm w.asIdeal := by
  haveI : w.asIdeal.IsMaximal := w.isPrime.isMaximal w.ne_bot
  set v := w.under (π“ž K)
  haveI : v.asIdeal.IsMaximal := v.isPrime.isMaximal v.ne_bot
  haveI : w.asIdeal.LiesOver v.asIdeal := ⟨rfl⟩
  letI : Field (π“ž K β§Έ v.asIdeal) := Ideal.Quotient.field _
  letI : Field (π“ž L β§Έ w.asIdeal) := Ideal.Quotient.field _
  have hpow : Nat.card (π“ž L β§Έ w.asIdeal) =
      Nat.card (π“ž K β§Έ v.asIdeal) ^ Module.finrank (π“ž K β§Έ v.asIdeal) (π“ž L β§Έ w.asIdeal) :=
    Module.natCard_eq_pow_finrank
  rw [← Submodule.cardQuot_apply, ← Ideal.absNorm_apply, ← Submodule.cardQuot_apply,
    ← Ideal.absNorm_apply] at hpow
  rw [hpow] at hp
  have hf := Nat.Prime.eq_one_of_pow hp
  rw [hpow, hf, pow_one]

variable (K m)

def U0 {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) : Subgroup (ZMod m)Λ£ := (hΞΆ.autToPow K).range

theorem card_U0 {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) : Nat.card (U0 K m hΞΆ) = Module.finrank K L := by
  haveI : IsGalois K L := IsCyclotomicExtension.isGalois {m} K L
  rw [U0, ← IsGalois.card_aut_eq_finrank K L, ← Nat.card_range_of_injective (hΞΆ.autToPow_injective K)]
  exact Nat.card_congr (Equiv.subtypeEquivRight (fun x => MonoidHom.mem_range))

theorem normClass_mem_U0 {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) (v : HeightOneSpectrum (π“ž K)) :
    normClass K m v ∈ U0 K m h΢ := by
  by_cases hv : (Ideal.absNorm v.asIdeal).Coprime m
  Β· haveI : IsGalois K L := IsCyclotomicExtension.isGalois {m} K L
    haveI : IsGaloisGroup (L ≃ₐ[K] L) (π“ž K) (π“ž L) :=
      IsGaloisGroup.of_isFractionRing (L ≃ₐ[K] L) (π“ž K) (π“ž L) K L
    haveI : v.asIdeal.IsMaximal := v.isPrime.isMaximal v.ne_bot

    have hker : RingHom.ker (algebraMap (π“ž K) (π“ž L)) ≀ v.asIdeal := by
      have hinj : Function.Injective (algebraMap (π“ž K) (π“ž L)) := by
        intro x y hxy
        have h' : algebraMap (π“ž K) L x = algebraMap (π“ž K) L y := by
          rw [IsScalarTower.algebraMap_apply (π“ž K) (π“ž L) L,
            IsScalarTower.algebraMap_apply (π“ž K) (π“ž L) L, hxy]
        rw [IsScalarTower.algebraMap_apply (π“ž K) K L, IsScalarTower.algebraMap_apply (π“ž K) K L] at h'
        exact RingOfIntegers.coe_injective ((algebraMap K L).injective h')
      rw [(RingHom.injective_iff_ker_eq_bot _).mp hinj]
      exact bot_le
    obtain ⟨Q, hQmax, hQv⟩ := Ideal.exists_ideal_over_maximal_of_isIntegral v.asIdeal hker
    haveI : Q.IsMaximal := hQmax
    have hunder : Q.under (π“ž K) = v.asIdeal := hQv
    have hmQ : (m : π“ž L) βˆ‰ Q := by
      intro hmem
      apply not_coprime_of_mem (K := K) (m := m) (v := v) _ hv
      have : algebraMap (π“ž K) (π“ž L) (m : π“ž K) ∈ Q := by rwa [map_natCast]
      rw [← Ideal.mem_comap] at this
      rw [← hunder]
      exact this
    haveI : Q.LiesOver v.asIdeal := ⟨hunder.symm⟩
    haveI : Finite (π“ž L β§Έ Q) := Q.finiteQuotientOfFreeOfNeBot
      (Ideal.ne_bot_of_liesOver_of_ne_bot v.ne_bot Q)
    set Ο† : L ≃ₐ[K] L := arithFrobAt (π“ž K) (L ≃ₐ[K] L) Q with hΟ†def
    have hΟ† : IsArithFrobAt (π“ž K) Ο† Q := IsArithFrobAt.arithFrobAt (π“ž K) (L ≃ₐ[K] L) Q
    have hΞΆ' : IsPrimitiveRoot hΞΆ.toInteger m := hΞΆ.toInteger_isPrimitiveRoot
    have hcardK : Nat.card (π“ž K β§Έ Q.under (π“ž K)) = Ideal.absNorm v.asIdeal := by
      rw [hunder, Ideal.absNorm_apply, Submodule.cardQuot_apply]
    have hφ΢' : Ο† β€’ hΞΆ.toInteger = hΞΆ.toInteger ^ Ideal.absNorm v.asIdeal := by
      have h := AlgHom.IsArithFrobAt.apply_of_pow_eq_one hφ h΢'.pow_eq_one hmQ
      rw [hcardK] at h
      exact h
    have hφ΢ : Ο† ΞΆ = ΞΆ ^ Ideal.absNorm v.asIdeal := by
      have h := congrArg (fun x : π“ž L => (x : L)) hφ΢'
      have h2 : ((Ο† β€’ hΞΆ.toInteger : π“ž L) : L) = Ο† ΞΆ := rfl
      simpa [h2, hΞΆ.coe_toInteger] using h
    have hspec := hΞΆ.autToPow_spec K Ο†
    rw [hφ΢] at hspec
    have hmod : ((hΞΆ.autToPow K Ο† : ZMod m)).val ≑ Ideal.absNorm v.asIdeal [MOD m] := by
      have hm : 0 < m := NeZero.pos m
      rw [← pow_mod_orderOf ΞΆ ((hΞΆ.autToPow K Ο† : ZMod m)).val, ← pow_mod_orderOf ΞΆ (Ideal.absNorm v.asIdeal),
        ← hΞΆ.eq_orderOf] at hspec
      exact hΞΆ.pow_inj (Nat.mod_lt _ hm) (Nat.mod_lt _ hm) hspec
    have heq : hΞΆ.autToPow K Ο† = normClass K m v := by
      apply Units.ext
      rw [normClass_coe K m v hv, ← ZMod.natCast_zmod_val ((hΞΆ.autToPow K Ο† : ZMod m)),
        ZMod.natCast_eq_natCast_iff]
      exact hmod
    rw [← heq]
    exact βŸ¨Ο†, rfl⟩
  Β· rw [normClass, dif_neg hv]
    exact one_mem _

theorem nu_mem_U0 {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) (g : NarrowRayClassGroup K (fm K m)) :
    nu K m g ∈ U0 K m h΢ := by
  obtain ⟨y, rfl⟩ := QuotientGroup.mk_surjective g
  have hmk : (QuotientGroup.mk y : NarrowRayClassGroup K (fm K m)) = NarrowRayClassGroup.mk K (fm K m) y := rfl
  rw [hmk, nu, normClassChar, raySymbolDescend_mk, raySymbolHom_apply, raySymbol]
  refine finprod_induction (· ∈ U0 K m h΢) (one_mem _) (fun x y hx hy => mul_mem hx hy) ?_
  intro v
  exact zpow_mem (normClass_mem_U0 K m hΞΆ v) _

theorem range_nu_le_U0 {ΞΆ : L} (hΞΆ : IsPrimitiveRoot ΞΆ m) : (nu K m).range ≀ U0 K m hΞΆ := by
  rintro _ ⟨g, rfl⟩
  exact nu_mem_U0 K m hΞΆ g

end Cyclo

end NumberField.NormResidueChar

end

Statements phrased using this module (0)

No statement module imports it directly (it is used through other definition modules or by proofs).