Files
AlgebraInLean/Book/Cauchy.lean
T
2026-08-11 13:59:48 +02:00

336 lines
12 KiB
Lean4
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import VersoManual
import Manual.Meta
-- Minimal-Imports statt `import Mathlib`: lädt nur den
-- benötigten Teil der Bibliothek und beschleunigt den
-- Buch-Build erheblich (ermittelt mit `#min_imports`).
import Mathlib.Algebra.Field.ZMod
import Mathlib.Algebra.Torsor.Defs
import Mathlib.Data.Finite.Vector
import Mathlib.GroupTheory.PGroup
import Mathlib.GroupTheory.Perm.Cycle.Type
open Verso.Genre Manual
open Verso.Genre.Manual.InlineLean
set_option pp.rawOnError true
set_option verso.docstring.allowMissing true
#doc (Manual) "Das Schlüssellemma und der Satz von Cauchy" =>
%%%
htmlSplit := .never
tag := "cauchy"
file := "cauchy"
%%%
Dieses Kapitel übersetzt den Anfang von Kapitel 18 des Skripts: das
_zentrale Schlüssellemma_ über Fixpunkte von p-Gruppen-Wirkungen und
seine erste Anwendung, den Satz von Cauchy. Unterwegs werden wir zum
ersten Mal selbst etwas in Lean _definieren_: eine Gruppenwirkung.
# Das zentrale Schlüssellemma
> *Lemma 18.1.1 (Zentrales Schlüssellemma).* Es sei
$`m \in \mathbb{N}` und es sei $`p` eine Primzahl. Weiter sei $`G`
eine Gruppe der Ordnung $`p^m`, die auf einer endlichen Menge $`M`
operiert. Weiter sei
$`M_0 = \{ m \in M : g \cdot m = m \ \forall g \in G \}` die Menge
der Fixpunkte. Dann ist $`|M| \equiv |M_0| \pmod{p}`.
Wie sagt Mathlib das alles?
* eine Gruppe der Ordnung $`p^m`“: Dafür hat Mathlib ein Prädikat
`IsPGroup p G` (die Ordnung jedes Elements ist eine
$`p`-Potenz für endliche Gruppen ist das äquivalent, nach dem
Satz von Cauchy unten!). Das Lemma `IsPGroup.of_card` übersetzt
unsere Voraussetzung `Nat.card G = p ^ m` dorthin.
* die auf einer endlichen Menge `M` operiert: Eine Wirkung von `G`
auf `M` ist eine Typklasse, `[MulAction G M]`; die Endlichkeit von
`M` ist die Typklasse `[Finite M]`.
* Die Fixpunktmenge heißt `MulAction.fixedPoints G M`, und die
Kongruenz $`|M| \equiv |M_0| \pmod{p}` schreibt sich
`Nat.card M Nat.card (fixedPoints G M) [MOD p]`.
Der Beweis im Skript zerlegt `M` in Bahnen und zitiert die
Bahnengleichung. Genau so beweist Mathlib die Aussage
`IsPGroup.card_modEq_card_fixedPoints` wir zitieren hier also
einfach die Bibliothek, so wie das Skript an dieser Stelle Satz 17.2.1
zitiert.
```lean
open Equiv.Perm Equiv.Perm.VectorsProdEqOne
open MulAction Multiplicative
theorem key_lemma {p m : } (hp : p.Prime) {G : Type*}
[Group G] (hG : Nat.card G = p ^ m) (M : Type*)
[Finite M] [MulAction G M] :
Nat.card M Nat.card (fixedPoints G M) [MOD p] := by
have : Fact p.Prime := hp
exact (IsPGroup.of_card hG).card_modEq_card_fixedPoints M
```
(Die `open`-Zeilen holen die Namensräume, die wir in diesem Kapitel
brauchen, in den Geltungsbereich; `Equiv.Perm.vectorsProdEqOne` tritt
gleich auf.)
# Der Satz von Cauchy
> *Satz 18.1.2 (Satz von Cauchy).* Wenn die Ordnung einer endlichen
Gruppe durch $`p` teilbar ist, dann existiert ein Element von
Ordnung $`p`.
Wir folgen dem Beweis des Skripts Satz für Satz. Der Beweis
konstruiert eine raffinierte Hilfsmenge mit einer raffinierten
Gruppenwirkung diesmal gibt es also vor dem eigentlichen Satz echte
Arbeit: Wir bauen erst die Menge und die Wirkung.
## Die Menge M
Betrachte die Menge
$`M = \bigl\{ (a_1, \dots, a_p) \in G \times \dots \times G : a_1 \cdot a_2 \cdots a_p = e \bigr\}`.“
Mathlib kennt diese Menge. Ein $`p`-Tupel von Gruppenelementen ist
ein `List.Vector G p` eine Liste der Länge $`p` , und $`M` ist die
Menge `Equiv.Perm.vectorsProdEqOne G p` aller Vektoren, deren
Einträge sich zu 1 multiplizieren.
Gegeben ein Tupel $`(a_1, \dots, a_p) \in M`, dann stellen wir erst
einmal fest, dass der letzte Eintrag des Tupels durch die ersten
Einträge eindeutig bestimmt ist,
$`a_p = (a_1 \cdots a_{p-1})^{-1}`. Wir erhalten die folgende
Gleichung: $`|M| = |G^{p-1}| = |G|^{p-1}`.“
Auch das steht schon in Mathlib: Die Bijektion
$`(a_1, \dots, a_{p-1}) \mapsto (a_1, \dots, a_{p-1}, (a_1 \cdots a_{p-1})^{-1})`
heißt `VectorsProdEqOne.vectorEquiv`, und die resultierende
Zählformel ist `VectorsProdEqOne.card`:
```
VectorsProdEqOne.card (G : Type) [Group G] (n : ) [Fintype G] :
Fintype.card (vectorsProdEqOne G n) = Fintype.card G ^ (n - 1)
```
## Die Wirkung von /(p)
Als Nächstes brauchen wir eine schicke Gruppenwirkung, denn wir
wollen das zentrale Schlüssellemma anwenden. Dazu lassen wir die
zyklische Gruppe $`\mathbb{Z}/(p)` auf $`M` durch zyklisches
Vertauschen wirken.“
Der zyklische Shift eines Vektors `v vectorsProdEqOne G p` um
$`k` Stellen ist `VectorsProdEqOne.rotate v k`. Die Fußnote des
Skripts der Shift bildet $`M` auf sich ab, weil in jeder Gruppe
aus $`a \cdot b = e` auch $`b \cdot a = e` gilt ist das
Mathlib-Lemma
`List.prod_rotate_eq_one_of_prod_eq_one`, das schon in der Definition
von `rotate` steckt.
Damit $`\mathbb{Z}/(p)` _als Gruppe_ wirkt, müssen wir die
Wirkungsaxiome nachprüfen: Der Shift um 0 tut nichts, und der Shift
um $`j + k` ist der Shift um $`k` gefolgt vom Shift um $`j`. Mathlib
stellt `rotate_zero`, `rotate_rotate` und `rotate_length` bereit (der
Shift um die volle Länge $`p` tut nichts); daraus leiten wir zuerst
ab, dass der Shift nur von der Verschiebung _modulo p_ abhängt
genau deshalb wirkt $`\mathbb{Z}/(p)` und nicht bloß
$`\mathbb{N}`.
```lean
theorem rotate_mul {G : Type*} [Group G] {p : }
(v : vectorsProdEqOne G p) (q : ) :
rotate v (p * q) = v := by
induction q with
| zero => rw [Nat.mul_zero, rotate_zero]
| succ q ih =>
rw [Nat.mul_succ, rotate_rotate, ih, rotate_length]
theorem rotate_mod {G : Type*} [Group G] {p : }
(v : vectorsProdEqOne G p) (k : ) :
rotate v (k % p) = rotate v k := by
calc rotate v (k % p)
= rotate (rotate v (k % p)) (p * (k / p)) :=
(rotate_mul _ _).symm
_ = rotate v (k % p + p * (k / p)) :=
rotate_rotate _ _ _
_ = rotate v k := by rw [Nat.mod_add_div]
```
Nun können wir die Wirkung definieren. Zwei technische Anmerkungen.
Mathlibs `MulAction` erwartet eine multiplikativ geschriebene Gruppe;
$`\mathbb{Z}/(p)` = `ZMod p` ist aber additiv geschrieben. Der Wrapper
`Multiplicative` wechselt die Notation (dank
`open Multiplicative` oben schreiben sich seine Übergänge kurz
`toAdd` und `ofAdd`). Die Voraussetzung `[NeZero p]` schließt
`p = 0` aus, wo Shift um eine Restklasse sinnlos wäre.
```lean
instance rotateAction {G : Type*} [Group G] {p : }
[NeZero p] :
MulAction (Multiplicative (ZMod p))
(vectorsProdEqOne G p) where
smul k v := rotate v (toAdd k).val
one_smul v := by
show rotate v (ZMod.val 0) = v
rw [ZMod.val_zero, rotate_zero]
mul_smul j k v := by
show rotate v ((toAdd j + toAdd k).val) =
rotate (rotate v (toAdd k).val) (toAdd j).val
rw [ZMod.val_add, rotate_mod, rotate_rotate,
Nat.add_comm]
```
## Die Fixpunkte
Die Fixpunktmenge dieser Wirkung ist
$`M_0 = \{ (a, \dots, a) \in G^p : a^p = e \}`.“
Mit anderen Worten: Ein Tupel ist genau dann ein Fixpunkt, wenn es
konstant ist, seine Liste also für ein $`a` die Liste
`List.replicate p a` das ist $`(a, \dots, a)` ist. (Die
Bedingung $`a^p = e` gilt dann automatisch, weil sich die Einträge
eines Tupels in $`M` zu $`e` multiplizieren.) Der Schlüsselschritt ist das Lemma
`List.rotate_one_eq_self_iff_eq_replicate`: Eine Liste, die der
zyklische Shift um _eine_ Stelle nicht ändert, ist konstant.
```lean
theorem mem_fixedPoints_iff_replicate {G : Type*} [Group G]
{p : } [Fact (1 < p)] (v : vectorsProdEqOne G p) :
v fixedPoints (Multiplicative (ZMod p))
(vectorsProdEqOne G p)
a : G,
(v : List.Vector G p).toList
= List.replicate p a := by
rw [mem_fixedPoints]
constructor
· -- Ein Fixpunkt wird insbesondere von 1 ∈ /(p) fixiert,
-- bleibt also unter dem Shift um eine Stelle
-- unverändert …
intro hv
have h1 : rotate v 1 = v := by
have h := hv (ofAdd (1 : ZMod p))
rwa [show ofAdd (1 : ZMod p) v
= rotate v (1 : ZMod p).val from rfl,
ZMod.val_one] at h
-- … und ist daher konstant.
obtain a, ha :=
List.rotate_one_eq_self_iff_eq_replicate.mp
(Subtype.ext_iff.mp (Subtype.ext_iff.mp h1))
refine a, ha.trans ?_⟩
congr 1
exact (v : List.Vector G p).2
· -- Umgekehrt ändert kein zyklischer Shift ein konstantes
-- Tupel.
rintro a, ha g
apply Subtype.ext
apply Subtype.ext
show (v : List.Vector G p).toList.rotate (toAdd g).val =
(v : List.Vector G p).toList
rw [ha, List.rotate_replicate]
```
## Der Beweis
Jetzt setzen wir die Teile zusammen und folgen dem Skript Zeile für
Zeile.
```lean
theorem cauchy {G : Type*} [Group G] [Fintype G] {p : }
(hp : p.Prime) (hdvd : p Fintype.card G) :
a : G, orderOf a = p := by
-- Die Konsequenzen der Primalität, die die Instanzsuche
-- braucht:
have : Fact p.Prime := hp
have : NeZero p := hp.ne_zero
have : Fact (1 < p) := hp.one_lt
-- Abkürzung: M₀ ist die Fixpunktmenge der Wirkung.
set M₀ := fixedPoints (Multiplicative (ZMod p))
(vectorsProdEqOne G p)
-- „Wir erhalten die folgende Gleichung:
-- |M| = |G^{p-1}| = |G|^{p-1}.“
have hM : Nat.card (vectorsProdEqOne G p)
= Fintype.card G ^ (p - 1) := by
rw [Nat.card_eq_fintype_card, VectorsProdEqOne.card]
-- Die zyklische Gruppe /(p) hat Ordnung p = p¹; das
-- Schlüssellemma, angewandt auf die Rotationswirkung,
-- liefert |M| ≡ |M₀| (mod p):
have hZp :
Nat.card (Multiplicative (ZMod p)) = p ^ 1 := by
simp [Nat.card_eq_fintype_card]
have hcong :
Nat.card (vectorsProdEqOne G p)
Nat.card M₀ [MOD p] :=
key_lemma hp hZp (vectorsProdEqOne G p)
-- „Auf der anderen Seite folgt aus dem zentralen
-- Schlüssellemma, dass
-- |M₀| ≡ |M| ≡ |G|^{p-1} ≡ 0 (mod p) ist.“
have hdvdM0 : p Nat.card M₀ := by
have hp1 : p - 1 0 := by have := hp.one_lt; omega
have h0 : (0 : ) Nat.card M₀ [MOD p] :=
calc (0 : )
Fintype.card G ^ (p - 1) [MOD p] :=
(Nat.modEq_zero_iff_dvd.mpr
(dvd_pow hdvd hp1)).symm
_ = Nat.card (vectorsProdEqOne G p) := hM.symm
_ Nat.card M₀ [MOD p] := hcong
exact Nat.modEq_zero_iff_dvd.mp h0.symm
-- „Wegen (e, …, e) ∈ M₀ ist schon einmal klar, dass
-- M₀ ≠ ∅ ist.“
let v₀ : vectorsProdEqOne G p :=
List.Vector.replicate p 1,
(List.prod_replicate p 1).trans (one_pow p)
have hv₀ : v₀ M₀ :=
(mem_fixedPoints_iff_replicate v₀).mpr 1, rfl
-- M₀ ist nichtleer, und |M₀| ist durch p ≥ 2 teilbar,
-- also ist |M₀| ≥ p > 1 …
have := Fintype.ofFinite M₀
have hlt : 1 < Fintype.card M₀ := by
rw [ Nat.card_eq_fintype_card]
have hpos : 0 < Nat.card M₀ :=
Nat.card_pos_iff.mpr ⟨⟨⟨v₀, hv₀⟩⟩, inferInstance
have := Nat.le_of_dvd hpos hdvdM0
have := hp.one_lt
omega
-- „Also existiert mindestens ein a ≠ e mit a^p = e.“
obtain w, hw :=
Fintype.exists_ne_of_one_lt_card hlt v₀, hv₀
obtain a, ha :=
(mem_fixedPoints_iff_replicate w.1).mp w.2
-- Das Tupel w liegt in M, sein Produkt ist also e; weil
-- das Tupel konstant ist, heißt das genau a^p = e:
have hpow : a ^ p = 1 := by
have hprod : (w.1 : List.Vector G p).toList.prod = 1 :=
w.1.2
rwa [ha, List.prod_replicate] at hprod
-- Und a ≠ e, denn sonst wäre w das Tupel (e, …, e) = v₀:
have hne : a 1 := by
rintro rfl
exact hw (Subtype.ext (Subtype.ext (Subtype.ext ha)))
-- „Nach Satz 17.4.6 hat a dann automatisch die
-- Ordnung p.“
exact a, orderOf_eq_prime hpow hne
```
# Bemerkungen
Mathlibs Fassung des Satzes von Cauchy heißt
`exists_prime_orderOf_dvd_card`; ihr Beweis ist dasselbe Zählargument,
nur etwas anders organisiert.
# Übungsaufgabe
Das ist Satz 18.2.3 im Skript: _Es sei `p` eine Primzahl und `G` eine
nichttriviale Gruppe, deren Ordnung eine p-Potenz ist. Dann ist das
Zentrum von `G` nicht trivial._ Beweisen Sie das in Lean: Wenden Sie
`key_lemma` auf die Konjugationswirkung von `G` auf sich selbst an
oder finden Sie die Aussage in Mathlib. Öffnen Sie
`AlgebraInLean/Cauchy.lean` im Übungs-Repository und ersetzen Sie das
`sorry` durch einen Beweis.
```lean
theorem center_nontrivial {p m : } (hp : p.Prime)
{G : Type*} [Group G] [Finite G] (hm : m 0)
(hG : Nat.card G = p ^ m) :
Nontrivial (Subgroup.center G) := by
sorry
```