First checkout
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.lake/
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Root module: imports all chapters of "Algebra in Lean".
|
||||
import AlgebraInLean.LittleFermat
|
||||
import AlgebraInLean.Cauchy
|
||||
@@ -0,0 +1,268 @@
|
||||
/-
|
||||
Algebra in Lean — Chapter 18
|
||||
============================
|
||||
|
||||
This file accompanies the lecture notes "Algebra und Zahlentheorie"
|
||||
(Stefan Kebekus, CC-BY 4.0). It translates the central key lemma
|
||||
(`lem:zsl`) and Cauchy's theorem (`Satz_von_Cauchy`) from Chapter 18
|
||||
into Lean, following the proof of the lecture notes sentence by
|
||||
sentence. The German original of every sentence is quoted as a comment
|
||||
directly above the Lean code that implements it.
|
||||
-/
|
||||
import Mathlib
|
||||
|
||||
namespace AlgebraInLean
|
||||
|
||||
open Equiv.Perm
|
||||
open Equiv.Perm.VectorsProdEqOne
|
||||
open MulAction
|
||||
|
||||
/-!
|
||||
# The key lemma and Cauchy's theorem
|
||||
|
||||
## The key lemma
|
||||
|
||||
**Lemma (Zentrales Schlüssellemma).** *Es sei m ∈ ℕ 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₀ = { m ∈ M : ∀ g ∈ G: g·m = m }
|
||||
die Menge der Fixpunkte. Dann ist |M| ≡ |M₀| (mod p).*
|
||||
|
||||
How does Mathlib say all this?
|
||||
|
||||
* "eine Gruppe der Ordnung p^m": Mathlib has a predicate `IsPGroup p G`
|
||||
for this ("the order of every element is a power of p" — for finite
|
||||
groups this is equivalent, by Cauchy's theorem below!). The lemma
|
||||
`IsPGroup.of_card` converts our hypothesis `Nat.card G = p ^ m` into
|
||||
it.
|
||||
|
||||
* "die auf einer endlichen Menge M operiert": an action of `G` on `M` is
|
||||
a typeclass, `[MulAction G M]`; finiteness of `M` is the typeclass
|
||||
`[Finite M]`.
|
||||
|
||||
* The set of fixed points is `MulAction.fixedPoints G M`, and the
|
||||
congruence `|M| ≡ |M₀| (mod p)` is written
|
||||
`Nat.card M ≡ Nat.card (fixedPoints G M) [MOD p]`.
|
||||
|
||||
The proof in the lecture notes decomposes M into orbits and quotes the
|
||||
Bahnengleichung. This is *exactly* how Mathlib proves the statement
|
||||
`IsPGroup.card_modEq_card_fixedPoints` — so here, just as the lecture
|
||||
notes quote Satz 17.2.6, we simply cite the library.
|
||||
-/
|
||||
|
||||
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
|
||||
|
||||
/-!
|
||||
## Cauchy's theorem
|
||||
|
||||
**Satz (Satz von Cauchy).** *Wenn die Ordnung einer endlichen Gruppe
|
||||
durch p teilbar ist, dann existiert ein Element von Ordnung p.*
|
||||
|
||||
We follow the proof of the lecture notes sentence by sentence. The
|
||||
proof constructs a clever auxiliary set with a clever group action, so
|
||||
this time there is real work to do *before* the final theorem: we set up
|
||||
the set and the action first.
|
||||
|
||||
„Betrachte die Menge M = { (a₁, …, a_p) ∈ G ⨯ ⋯ ⨯ G : a₁·a₂ ⋯ a_p = e }.“
|
||||
|
||||
Mathlib knows this set. A p-tuple of group elements is a
|
||||
`List.Vector G p` — a list of length p — and M is the set
|
||||
`Equiv.Perm.vectorsProdEqOne G p` of all vectors whose entries multiply
|
||||
to 1.
|
||||
|
||||
„Gegeben ein Tupel (a₁, …, a_p) ∈ M, dann stellen wir erst einmal fest,
|
||||
dass der letzte Eintrag des Tupels durch die ersten Einträge eindeutig
|
||||
bestimmt ist, a_p = (a₁ ⋯ a_{p-1})⁻¹. Wir erhalten die folgende
|
||||
Gleichung: |M| = |G^{p-1}| = |G|^{p-1}.“
|
||||
|
||||
This, too, is already in Mathlib: the bijection
|
||||
(a₁, …, a_{p-1}) ↦ (a₁, …, a_{p-1}, (a₁ ⋯ a_{p-1})⁻¹) is
|
||||
`VectorsProdEqOne.vectorEquiv`, and the resulting counting formula is
|
||||
`VectorsProdEqOne.card`:
|
||||
-/
|
||||
|
||||
#check @Equiv.Perm.VectorsProdEqOne.card
|
||||
-- ∀ (G : Type u_1) [inst : Group G] (n : ℕ) [inst_1 : Fintype G],
|
||||
-- Fintype.card ↥(vectorsProdEqOne G n) = Fintype.card G ^ (n - 1)
|
||||
|
||||
/-!
|
||||
„Als Nächstes brauchen wir eine schicke Gruppenwirkung, denn wir wollen
|
||||
das zentrale Schlüssellemma anwenden. Dazu lassen wir die zyklische
|
||||
Gruppe ℤ/(p) auf M durch zyklisches Vertauschen wirken.“
|
||||
|
||||
The cyclic shift of a vector `v ∈ vectorsProdEqOne G p` by k places is
|
||||
`VectorsProdEqOne.rotate v k`. The footnote of the lecture notes — the
|
||||
shift maps M to itself „weil in jeder Gruppe aus a·b = e auch b·a = e
|
||||
gilt“ — is the Mathlib lemma `List.prod_rotate_eq_one_of_prod_eq_one`,
|
||||
which is used in the very definition of `rotate`.
|
||||
|
||||
To let ℤ/(p) act *as a group* we must check the action axioms: rotating
|
||||
by 0 does nothing, and rotating by j + k is the same as rotating by k
|
||||
and then by j. Mathlib provides `rotate_zero`, `rotate_rotate` and
|
||||
`rotate_length` (rotating by the full length p does nothing); from the
|
||||
last one we first derive that rotation only depends on the shift
|
||||
*modulo p* — this is why ℤ/(p), and not just ℕ, acts on M.
|
||||
-/
|
||||
|
||||
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]
|
||||
|
||||
/-- „Dazu lassen wir die zyklische Gruppe ℤ/(p) auf M durch zyklisches
|
||||
Vertauschen wirken.“ — An element k of ℤ/(p) acts by rotating k places.
|
||||
|
||||
Two technical remarks. Mathlib's `MulAction` wants a multiplicatively
|
||||
written group, while ℤ/(p) = `ZMod p` is written additively; the wrapper
|
||||
`Multiplicative` performs the change of notation. The assumption
|
||||
`[NeZero p]` excludes p = 0, where "rotation by a residue class" would
|
||||
make no sense. -/
|
||||
instance rotateAction {G : Type*} [Group G] {p : ℕ} [NeZero p] :
|
||||
MulAction (Multiplicative (ZMod p)) (vectorsProdEqOne G p) where
|
||||
smul k v := rotate v (Multiplicative.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 ((Multiplicative.toAdd j + Multiplicative.toAdd k).val) =
|
||||
rotate (rotate v (Multiplicative.toAdd k).val) (Multiplicative.toAdd j).val
|
||||
rw [ZMod.val_add, rotate_mod, rotate_rotate, Nat.add_comm]
|
||||
|
||||
/-!
|
||||
„Die Fixpunktmenge dieser Wirkung ist M₀ = { (a, …, a) ∈ G^p : a^p = e }.“
|
||||
|
||||
In other words: a tuple is a fixed point if and only if it is constant,
|
||||
i.e. its underlying list is `List.replicate p a` — the list (a, …, a) —
|
||||
for some a. (The condition a^p = e then holds automatically, because
|
||||
the entries of a tuple in M multiply to e.) The key step is the lemma
|
||||
`List.rotate_one_eq_self_iff_eq_replicate`: a list that is unchanged by
|
||||
the cyclic shift by *one* place is constant.
|
||||
-/
|
||||
|
||||
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
|
||||
· -- A fixed point is in particular fixed by 1 ∈ ℤ/(p), so it is
|
||||
-- unchanged by the cyclic shift by one place …
|
||||
intro hv
|
||||
have h1 : rotate v 1 = v := by
|
||||
have h := hv (Multiplicative.ofAdd (1 : ZMod p))
|
||||
rwa [show Multiplicative.ofAdd (1 : ZMod p) • v
|
||||
= rotate v (1 : ZMod p).val from rfl, ZMod.val_one] at h
|
||||
-- … and hence constant.
|
||||
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
|
||||
· -- Conversely, a constant tuple is unchanged by every cyclic shift.
|
||||
rintro ⟨a, ha⟩ g
|
||||
apply Subtype.ext
|
||||
apply Subtype.ext
|
||||
show (v : List.Vector G p).toList.rotate (Multiplicative.toAdd g).val =
|
||||
(v : List.Vector G p).toList
|
||||
rw [ha, List.rotate_replicate]
|
||||
|
||||
/-!
|
||||
Now we can put the pieces together, following the lecture notes line by
|
||||
line.
|
||||
-/
|
||||
|
||||
theorem cauchy {G : Type*} [Group G] [Fintype G] {p : ℕ} (hp : p.Prime)
|
||||
(hdvd : p ∣ Fintype.card G) : ∃ a : G, orderOf a = p := by
|
||||
-- Register the consequences of primality that instance search needs:
|
||||
have : Fact p.Prime := ⟨hp⟩
|
||||
have : NeZero p := ⟨hp.ne_zero⟩
|
||||
have : Fact (1 < p) := ⟨hp.one_lt⟩
|
||||
-- „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)“ has order p = p¹, so the key lemma
|
||||
-- applies to the rotation action and gives |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 (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p)) [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 (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p)) := by
|
||||
have hp1 : p - 1 ≠ 0 := by have := hp.one_lt; omega
|
||||
have h0 : (0 : ℕ) ≡ Nat.card (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p)) [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
|
||||
_ ≡ _ [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₀ ∈ fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p) :=
|
||||
(mem_fixedPoints_iff_replicate v₀).mpr ⟨1, rfl⟩
|
||||
-- M₀ is nonempty and its cardinality is divisible by p ≥ 2, so
|
||||
-- |M₀| ≥ p > 1 …
|
||||
have := Fintype.ofFinite (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p))
|
||||
have hlt : 1 < Fintype.card (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p)) := by
|
||||
rw [← Nat.card_eq_fintype_card]
|
||||
have hpos : 0 < Nat.card (fixedPoints (Multiplicative (ZMod p))
|
||||
(vectorsProdEqOne G p)) := 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
|
||||
-- The tuple w lies in M, so its entries multiply to e; being constant,
|
||||
-- this says exactly 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
|
||||
-- and a ≠ e, because otherwise w would be the tuple (e, …, e) = v₀:
|
||||
have hne : a ≠ 1 := by
|
||||
rintro rfl
|
||||
exact hw (Subtype.ext (Subtype.ext (Subtype.ext ha)))
|
||||
-- „Nach Satz 17.4.11 hat a dann automatisch die Ordnung p.“
|
||||
exact ⟨a, orderOf_eq_prime hpow hne⟩
|
||||
|
||||
/-!
|
||||
## Remarks
|
||||
|
||||
1. Mathlib's version of Cauchy's theorem is
|
||||
`exists_prime_orderOf_dvd_card`; its proof is the same
|
||||
counting argument, organized slightly differently.
|
||||
|
||||
2. **Exercise** (Satz 18.2.3 of the lecture notes): *Es sei p eine
|
||||
Primzahl und G eine nichttriviale Gruppe, deren Ordnung eine p-Potenz
|
||||
ist. Dann ist das Zentrum von G nicht trivial.* Prove this in Lean:
|
||||
apply `key_lemma` to the conjugation action of G on itself — or find
|
||||
the statement in Mathlib. Replace the `sorry` below by a proof.
|
||||
-/
|
||||
|
||||
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
|
||||
|
||||
end AlgebraInLean
|
||||
@@ -0,0 +1,105 @@
|
||||
/-
|
||||
Algebra in Lean — pilot file
|
||||
============================
|
||||
|
||||
This file accompanies the lecture notes "Algebra und Zahlentheorie"
|
||||
(Stefan Kebekus, CC-BY 4.0). It translates one theorem of the notes —
|
||||
Fermat's little theorem, `satz:kleinerFermat` in Chapter 17 — into Lean,
|
||||
following the proof of the lecture notes *sentence by sentence*. The
|
||||
German original of every sentence is quoted as a comment directly above
|
||||
the Lean code that implements it, so you can see how the standard
|
||||
phrases of a lecture-style proof translate into Lean/Mathlib.
|
||||
-/
|
||||
import Mathlib
|
||||
|
||||
namespace AlgebraInLean
|
||||
|
||||
/-!
|
||||
# Fermat's little theorem
|
||||
|
||||
**Satz (Kleiner Satz von Fermat).** *Es sei p ∈ ℕ eine Primzahl und es
|
||||
sei a ∈ ℤ irgendeine Zahl. Dann ist a^p ≡ a (mod p).*
|
||||
|
||||
Before we can state this in Lean, we need to know how Mathlib speaks
|
||||
about the objects involved.
|
||||
|
||||
* The ring ℤ/(p) of residue classes is called `ZMod p`. The residue
|
||||
class of an integer `a : ℤ` is written `(a : ZMod p)` — Lean inserts
|
||||
the canonical ring morphism ℤ → ℤ/(p) automatically ("coercion").
|
||||
|
||||
* The congruence `a ≡ b (mod p)` for integers is written
|
||||
`a ≡ b [ZMOD p]`.
|
||||
|
||||
* The multiplicative group 𝔽_p^* is the group of *units* of the ring
|
||||
`ZMod p`, written `(ZMod p)ˣ`. A unit `u : (ZMod p)ˣ` remembers its
|
||||
inverse; the underlying ring element is again written `(u : ZMod p)`.
|
||||
|
||||
* The lecture notes say "es sei p eine Primzahl". In Lean we carry the
|
||||
primality of `p` as a hypothesis `hp : p.Prime`. Some facts —
|
||||
for instance that ℤ/(p) is a field — are found by Lean's automation
|
||||
only if the hypothesis is registered as an *instance*; this is what
|
||||
the first line `have : Fact p.Prime := ⟨hp⟩` of the proof does.
|
||||
-/
|
||||
|
||||
theorem little_fermat (p : ℕ) (hp : p.Prime) (a : ℤ) :
|
||||
a ^ p ≡ a [ZMOD p] := by
|
||||
have : Fact p.Prime := ⟨hp⟩
|
||||
-- The congruence „a^p ≡ a (mod p)“ means precisely that a^p and a have
|
||||
-- the same residue class in ℤ/(p). So we may prove an *equation* in
|
||||
-- the ring `ZMod p` instead; the goal becomes
|
||||
-- (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.3.6 («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
|
||||
|
||||
/-!
|
||||
## Remarks
|
||||
|
||||
1. Mathlib of course already contains Fermat's little theorem; the
|
||||
statement about residue classes is `ZMod.pow_card`. You can find
|
||||
such lemmas yourself with the tactic `exact?`, or by searching on
|
||||
https://leansearch.net or https://loogle.lean-lang.org.
|
||||
-/
|
||||
|
||||
example (p : ℕ) [Fact p.Prime] (a : ZMod p) : a ^ p = a :=
|
||||
ZMod.pow_card a
|
||||
|
||||
/-!
|
||||
2. **Exercise** (this is `bem:kleinerFermat` of the lecture notes).
|
||||
In applications one often uses the equivalent formulation
|
||||
a^(p−1) ≡ 1 (mod p) for a not divisible by p. Derive it from
|
||||
`little_fermat` — or give a direct proof following the ideas above.
|
||||
Replace the `sorry` below by a proof.
|
||||
-/
|
||||
|
||||
theorem little_fermat' (p : ℕ) (hp : p.Prime) (a : ℤ) (ha : ¬ (p : ℤ) ∣ a) :
|
||||
a ^ (p - 1) ≡ 1 [ZMOD p] := by
|
||||
sorry
|
||||
|
||||
end AlgebraInLean
|
||||
@@ -1,2 +1,40 @@
|
||||
# AlgebraInLean
|
||||
# Algebra in Lean
|
||||
|
||||
A hands-on introduction to formalizing algebra with the proof assistant
|
||||
[Lean](https://lean-lang.org) and its mathematical library
|
||||
[Mathlib](https://leanprover-community.github.io). The course accompanies
|
||||
the lecture notes *Algebra und Zahlentheorie* (Stefan Kebekus,
|
||||
Universität Freiburg) and is aimed at students who are learning algebra
|
||||
and have little prior experience with Lean.
|
||||
|
||||
Selected proofs from the lecture notes are translated into Lean
|
||||
*sentence by sentence*: the German original of each sentence is quoted
|
||||
as a comment directly above the Lean code implementing it, so you can
|
||||
see how the standard phrases of a lecture-style proof translate into
|
||||
Lean/Mathlib.
|
||||
|
||||
## Getting started
|
||||
|
||||
1. [Install Lean](https://leanprover-community.github.io/get_started.html)
|
||||
(`elan`, VS Code and the Lean 4 extension).
|
||||
2. Clone this repository and fetch the precompiled Mathlib cache:
|
||||
|
||||
```bash
|
||||
git clone <repository url>
|
||||
cd AlgebraInLean
|
||||
lake exe cache get
|
||||
```
|
||||
|
||||
3. Open the folder in VS Code and start with
|
||||
`AlgebraInLean/LittleFermat.lean`.
|
||||
|
||||
## Contents
|
||||
|
||||
| File | Lecture notes | Topic |
|
||||
|------|---------------|-------|
|
||||
| `AlgebraInLean/LittleFermat.lean` | Kapitel 17 | Fermat's little theorem via Lagrange |
|
||||
| `AlgebraInLean/Cauchy.lean` | Kapitel 18 | The key lemma on fixed points and Cauchy's theorem |
|
||||
|
||||
## License
|
||||
|
||||
CC-BY 4.0, like the lecture notes.
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
{"version": "1.2.0",
|
||||
"packagesDir": ".lake/packages",
|
||||
"packages":
|
||||
[{"url": "https://github.com/leanprover-community/mathlib4",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "",
|
||||
"rev": "87adeaebd370a3b6a41ac4f044fddd4bf81803ad",
|
||||
"name": "mathlib",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "87adeaebd370a3b6a41ac4f044fddd4bf81803ad",
|
||||
"inherited": false,
|
||||
"configFile": "lakefile.lean"},
|
||||
{"url": "https://github.com/leanprover-community/plausible",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "123d15766ba49356c02ebad2a4462dfe12d79899",
|
||||
"name": "plausible",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover-community/LeanSearchClient",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "f5c090429dff3cf66cb65562526c9ea6e8edfbcb",
|
||||
"name": "LeanSearchClient",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover-community/import-graph",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "bb3469a87774349fe01898d8bf2fc6a1ce6411ca",
|
||||
"name": "importGraph",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover-community/ProofWidgets4",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "222c58dad7706a6e7cae46c0edd65ea881d3ee27",
|
||||
"name": "proofwidgets",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.lean"},
|
||||
{"url": "https://github.com/leanprover-community/aesop",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "7db8190085343afde2f5d2cdcc9bac719b6ec02c",
|
||||
"name": "aesop",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "master",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover-community/quote4",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "ef42f8944eaf5b6cbfbe75d1917d824c7dd6cf33",
|
||||
"name": "Qq",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "master",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover-community/batteries",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover-community",
|
||||
"rev": "76e1c118b0700b4ceafe99532e887d6431625e1a",
|
||||
"name": "batteries",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover/lean4-cli",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover",
|
||||
"rev": "1319485273bf87833fa472afbcefdedecb16b45f",
|
||||
"name": "Cli",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "v4.33.0-rc2",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"}],
|
||||
"name": "AlgebraInLean",
|
||||
"lakeDir": ".lake",
|
||||
"fixedToolchain": false}
|
||||
@@ -0,0 +1,10 @@
|
||||
name = "AlgebraInLean"
|
||||
defaultTargets = ["AlgebraInLean"]
|
||||
|
||||
[[require]]
|
||||
name = "mathlib"
|
||||
git = "https://github.com/leanprover-community/mathlib4"
|
||||
rev = "87adeaebd370a3b6a41ac4f044fddd4bf81803ad"
|
||||
|
||||
[[lean_lib]]
|
||||
name = "AlgebraInLean"
|
||||
@@ -0,0 +1 @@
|
||||
leanprover/lean4:v4.33.0-rc2
|
||||
Reference in New Issue
Block a user