153 lines
5.9 KiB
Lean4
153 lines
5.9 KiB
Lean4
import VersoManual
|
||
import Manual.Meta
|
||
-- Minimal-Import statt `import Mathlib`: lädt nur den
|
||
-- benötigten Teil der Bibliothek und beschleunigt den
|
||
-- Buch-Build erheblich (ermittelt mit `#min_imports`).
|
||
import Mathlib.FieldTheory.Finite.Basic
|
||
|
||
open Verso.Genre Manual
|
||
open Verso.Genre.Manual.InlineLean
|
||
|
||
set_option pp.rawOnError true
|
||
set_option verso.docstring.allowMissing true
|
||
|
||
#doc (Manual) "Der kleine Satz von Fermat" =>
|
||
%%%
|
||
htmlSplit := .never
|
||
tag := "little-fermat"
|
||
file := "little-fermat"
|
||
%%%
|
||
|
||
Unser erster Beweis übersetzt Satz 17.5.1 des Skripts. Hier das
|
||
deutsche Original, Aussage und Beweis:
|
||
|
||
> *Satz 17.5.1 (Kleiner Satz von Fermat).* Es sei $`p \in \mathbb{N}`
|
||
eine Primzahl und es sei $`a \in \mathbb{Z}` irgendeine Zahl. Dann
|
||
ist $`a^p \equiv a \pmod{p}`.
|
||
|
||
> _Beweis._ Falls $`a` ein Vielfaches von $`p` ist, ist die Sache
|
||
klar. Ansonsten liefert die Restklasse von $`a` ein
|
||
nicht-verschwindendes Element
|
||
$`\overline{a} \in \mathbb{Z}/(p) = \mathbb{F}_p`, also ein Element
|
||
der multiplikativen Gruppe $`\mathbb{F}_p^*`, welche $`p-1` Elemente
|
||
hat. Nach dem Satz von Lagrange ist die Ordnung von
|
||
$`\overline{a}`, also die Größe der von $`\overline{a}` erzeugten
|
||
Untergruppe, ein Teiler von $`|\mathbb{F}_p^*| = p-1`. Es gilt also
|
||
$`\overline{a}^{p-1} = 1 \in \mathbb{F}_p^*`, oder äquivalent
|
||
$`a^p \equiv a \pmod{p}`. ∎
|
||
|
||
Fünf Sätze. Unser Ziel ist ein Lean-Beweis mit genau dieser Struktur —
|
||
jeder deutsche Satz kehrt als Kommentar über dem Lean-Code wieder, der
|
||
ihn umsetzt.
|
||
|
||
# Das Mathlib-Wörterbuch
|
||
|
||
Bevor wir den Satz überhaupt formulieren können, müssen wir wissen, wie
|
||
Mathlib über die beteiligten Objekte spricht.
|
||
|
||
* Der Restklassenring $`\mathbb{Z}/(p)` heißt `ZMod p`. Die
|
||
Restklasse einer ganzen Zahl `a : ℤ` schreibt sich `(a : ZMod p)` —
|
||
Lean fügt den kanonischen Ringmorphismus
|
||
$`\mathbb{Z} \to \mathbb{Z}/(p)` automatisch ein (eine _Koerzion_).
|
||
|
||
* Die Kongruenz $`a \equiv b \pmod{p}` für ganze Zahlen schreibt sich
|
||
`a ≡ b [ZMOD p]`.
|
||
|
||
* Die multiplikative Gruppe $`\mathbb{F}_p^*` ist die Gruppe der
|
||
_Einheiten_ des Rings `ZMod p`, geschrieben `(ZMod p)ˣ`. Eine
|
||
Einheit `u : (ZMod p)ˣ` kennt ihr Inverses; das zugrundeliegende
|
||
Ringelement schreibt sich wieder `(u : ZMod p)`.
|
||
|
||
* Das Skript sagt „es sei $`p` eine Primzahl“. In Lean führen wir die
|
||
Primalität von `p` als Hypothese `hp : p.Prime` mit. Manche
|
||
Tatsachen — etwa dass $`\mathbb{Z}/(p)` ein Körper ist — findet
|
||
Leans Automatisierung nur, wenn die Hypothese als _Instanz_
|
||
registriert ist; genau das leistet die erste Beweiszeile
|
||
`have : Fact p.Prime := ⟨hp⟩`.
|
||
|
||
# Der Beweis, Satz für Satz
|
||
|
||
```lean
|
||
theorem little_fermat (p : ℕ) (hp : p.Prime) (a : ℤ) :
|
||
a ^ p ≡ a [ZMOD p] := by
|
||
have : Fact p.Prime := ⟨hp⟩
|
||
-- Die Kongruenz „a^p ≡ a (mod p)“ bedeutet gerade, dass
|
||
-- a^p und a dieselbe Restklasse in ℤ/(p) haben. Wir
|
||
-- dürfen also stattdessen eine *Gleichung* im Ring
|
||
-- `ZMod p` zeigen; das Beweisziel wird
|
||
-- (a : ZMod p) ^ p = (a : ZMod p).
|
||
rw [← ZMod.intCast_eq_intCast_iff]
|
||
push_cast
|
||
-- „Falls a ein Vielfaches von p ist, ist die Sache klar.“
|
||
by_cases ha : (a : ZMod p) = 0
|
||
· rw [ha, zero_pow hp.ne_zero]
|
||
-- „Ansonsten liefert die Restklasse von a ein
|
||
-- nicht-verschwindendes Element ā ∈ ℤ/(p) = 𝔽_p, also
|
||
-- ein Element der multiplikativen Gruppe 𝔽_p^*, …“
|
||
· obtain ⟨u, hu⟩ : IsUnit (a : ZMod p) :=
|
||
isUnit_iff_ne_zero.mpr ha
|
||
rw [← hu]
|
||
-- „… welche p−1 Elemente hat.“
|
||
have card_units : Nat.card (ZMod p)ˣ = p - 1 := by
|
||
rw [Nat.card_eq_fintype_card, ZMod.card_units p]
|
||
-- „Nach Satz 17.2.4 («Satz von Lagrange») ist die
|
||
-- Ordnung von ā, also die Größe der von ā erzeugten
|
||
-- Untergruppe, ein Teiler von |𝔽_p^*| = p−1.“
|
||
have lagrange :
|
||
Nat.card (Subgroup.zpowers u) ∣
|
||
Nat.card (ZMod p)ˣ :=
|
||
Subgroup.card_subgroup_dvd_card (Subgroup.zpowers u)
|
||
have ord_dvd : orderOf u ∣ p - 1 := by
|
||
rw [← Nat.card_zpowers, ← card_units]
|
||
exact lagrange
|
||
-- „Es gilt also ā^(p−1) = 1 ∈ 𝔽_p^* …“
|
||
have pow_eq_one : u ^ (p - 1) = 1 :=
|
||
orderOf_dvd_iff_pow_eq_one.mp ord_dvd
|
||
-- „… oder äquivalent a^p ≡ a (mod p).“
|
||
have key : u ^ p = u := by
|
||
calc u ^ p
|
||
= u ^ (p - 1 + 1) := by
|
||
rw [Nat.sub_add_cancel hp.one_lt.le]
|
||
_ = u ^ (p - 1) * u := pow_succ u (p - 1)
|
||
_ = u := by rw [pow_eq_one, one_mul]
|
||
exact_mod_cast congrArg Units.val key
|
||
```
|
||
|
||
Man beachte, wie treu die Übersetzung ist. Die Fallunterscheidung
|
||
„Falls … ist die Sache klar / Ansonsten …“ wird zu `by_cases`; das
|
||
Zitat des Satzes von Lagrange wird zum Bibliothekslemma
|
||
`Subgroup.card_subgroup_dvd_card`; und die Formulierung „die Ordnung
|
||
von `ā`, also die Größe der von `ā` erzeugten Untergruppe“ ist genau
|
||
das Umschreiben mit `Nat.card_zpowers`, das `orderOf u` mit der
|
||
Mächtigkeit der von `u` erzeugten Untergruppe `Subgroup.zpowers u`
|
||
identifiziert.
|
||
|
||
# Bemerkungen
|
||
|
||
Mathlib enthält den kleinen Satz von Fermat natürlich längst; die
|
||
Aussage über Restklassen heißt `ZMod.pow_card`. Solche Lemmata findet
|
||
man selbst mit der Taktik `exact?` oder über die Suchmaschinen
|
||
[leansearch.net](https://leansearch.net) und
|
||
[loogle.lean-lang.org](https://loogle.lean-lang.org).
|
||
|
||
```lean
|
||
example (p : ℕ) [Fact p.Prime] (a : ZMod p) : a ^ p = a :=
|
||
ZMod.pow_card a
|
||
```
|
||
|
||
# Übungsaufgabe
|
||
|
||
Das ist die Bemerkung nach dem Satz im Skript: In Anwendungen
|
||
verwendet man häufig die äquivalente Formulierung
|
||
$`a^{p-1} \equiv 1 \pmod{p}` für nicht durch $`p` teilbare $`a`. Leiten Sie
|
||
sie aus `little_fermat` ab — oder geben Sie einen direkten Beweis nach
|
||
den Ideen oben. Öffnen Sie `AlgebraInLean/LittleFermat.lean` im
|
||
Übungs-Repository und ersetzen Sie das `sorry` durch einen Beweis.
|
||
|
||
```lean
|
||
theorem little_fermat' (p : ℕ) (hp : p.Prime) (a : ℤ)
|
||
(ha : ¬ (p : ℤ) ∣ a) :
|
||
a ^ (p - 1) ≡ 1 [ZMOD p] := by
|
||
sorry
|
||
```
|