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 $`\overline{a}`, also die Größe der von $`\overline{a}` 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 ```