factor out adam game
This commit is contained in:
@@ -2,4 +2,5 @@ node_modules
|
|||||||
client/dist
|
client/dist
|
||||||
server/build
|
server/build
|
||||||
server/nng
|
server/nng
|
||||||
|
server/adam
|
||||||
**/lake-packages/
|
**/lake-packages/
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
build
|
|
||||||
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"editor.insertSpaces": true,
|
|
||||||
"editor.tabSize": 2,
|
|
||||||
"editor.rulers" : [100],
|
|
||||||
"files.encoding": "utf8",
|
|
||||||
"files.eol": "\n",
|
|
||||||
"files.insertFinalNewline": true,
|
|
||||||
"files.trimFinalNewlines": true,
|
|
||||||
"files.trimTrailingWhitespace": true
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Levels.Proposition
|
|
||||||
import Adam.Levels.Implication
|
|
||||||
import Adam.Levels.Predicate
|
|
||||||
import Adam.Levels.Contradiction
|
|
||||||
-- import Adam.Levels.Prime
|
|
||||||
import Adam.Levels.Sum
|
|
||||||
-- import Adam.Levels.Induction
|
|
||||||
|
|
||||||
--import Adam.Levels.Numbers
|
|
||||||
import Adam.Levels.Inequality
|
|
||||||
|
|
||||||
import Adam.Levels.Lean
|
|
||||||
import Adam.Levels.SetTheory
|
|
||||||
import Adam.Levels.Function
|
|
||||||
--import Adam.Levels.SetFunction
|
|
||||||
--import Adam.Levels.LinearAlgebra
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
Title "Lean 4 game"
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
# Game Over oder QED?
|
|
||||||
|
|
||||||
Willkommen zu unserem Prototyp eines Lean4-Lernspiels. Hier lernst du computer-gestützte
|
|
||||||
Beweisführung. Das Interface ist etwas vereinfacht, aber wenn du den *Editor Mode* aktivierst, fühlt es sich
|
|
||||||
fast genauso an wie in VSCode, der Standard-IDE für Lean.
|
|
||||||
|
|
||||||
Rechts siehst du eine Übersicht. Das Spiel besteht aus mehreren Planeten, und jeder Planet hat mehrere Levels,
|
|
||||||
die in Form von grauen Punkten dargestellt sind. Gelöste Levels werden grün.
|
|
||||||
|
|
||||||
Klicke auf den ersten Planeten *Logo*, um deine Reise zu starten.
|
|
||||||
|
|
||||||
### Spielstand
|
|
||||||
|
|
||||||
Dein Spielstand wird lokal in deinem Browser als *site data* gespeichert.
|
|
||||||
Solltest du diese löschen, verlierst du deinen Spielstand!
|
|
||||||
Viele Browser löschen *site data* und *cookies* zusammen.
|
|
||||||
Du kannst aber jederzeit jedes Level spielen, auch wenn du vorhergende Levels noch nicht gelöst hast.
|
|
||||||
|
|
||||||
### Funding
|
|
||||||
|
|
||||||
Dieses Lernspiel wurde und wird im Rahmen des Projekts
|
|
||||||
[ADAM: Anticipating the Digital Age of Mathematics](https://hhu-adam.github.io/)
|
|
||||||
an der Heinrich-Heine-Universität Düsseldorf entwickelt.
|
|
||||||
Es wird finanziert durch das Programm *Freiraum 2022* der *Stiftung Innovation in der Hochschullehre*.
|
|
||||||
|
|
||||||
### Kontakt
|
|
||||||
|
|
||||||
Das Spiel befindet sich noch in der Entwicklung.
|
|
||||||
Wenn du Anregungen hast oder Bugs findest, schreib doch ein Email oder erstelle einen
|
|
||||||
[Issue auf Github](https://github.com/leanprover-community/lean4game/issues).
|
|
||||||
|
|
||||||
[Jon Eugster](https://www.math.hhu.de/lehrstuehle-/-personen-/-ansprechpartner/innen/lehrstuehle-des-mathematischen-instituts/lehrstuhl-fuer-algebraische-geometrie/team/jon-eugster)
|
|
||||||
"
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Fertig!"
|
|
||||||
|
|
||||||
|
|
||||||
Path Proposition → Implication → Predicate → Predicate → Contradiction → Sum → Lean → Function
|
|
||||||
Path Predicate → Inequality → Sum
|
|
||||||
-- Path Inequality → Prime
|
|
||||||
-- Path Sum → Inequality -- → Induction
|
|
||||||
-- Path SetTheory2 → Numbers
|
|
||||||
|
|
||||||
Path Lean → SetTheory -- → SetTheory2
|
|
||||||
|
|
||||||
-- Path SetTheory2 → SetFunction → Module
|
|
||||||
-- Path Function → SetFunction
|
|
||||||
-- Path Module → Basis → Module2
|
|
||||||
|
|
||||||
MakeGame
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import GameServer.Commands
|
|
||||||
|
|
||||||
/-! ## Definitions -/
|
|
||||||
|
|
||||||
DefinitionDoc Even as "Even"
|
|
||||||
"
|
|
||||||
`even n` ist definiert als `∃ r, a = 2 * r`.
|
|
||||||
Die Definition kann man mit `unfold even at *` einsetzen.
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Even](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Even)"
|
|
||||||
|
|
||||||
DefinitionDoc Odd as "Odd"
|
|
||||||
"
|
|
||||||
`odd n` ist definiert als `∃ r, a = 2 * r + 1`.
|
|
||||||
Die Definition kann man mit `unfold odd at *` einsetzen.
|
|
||||||
|
|
||||||
* Mathlib Doc: [Odd](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Odd)"
|
|
||||||
|
|
||||||
DefinitionDoc Injective as "Injective"
|
|
||||||
"
|
|
||||||
`Injective f` ist definiert als
|
|
||||||
|
|
||||||
```
|
|
||||||
∀ a b, f a = f b → a = b
|
|
||||||
```
|
|
||||||
definiert.
|
|
||||||
|
|
||||||
* Mathlib Doc: [Injective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Injective)"
|
|
||||||
|
|
||||||
DefinitionDoc Surjective as "Surjective"
|
|
||||||
"
|
|
||||||
`Surjective f` ist definiert als
|
|
||||||
|
|
||||||
```
|
|
||||||
∀ a, (∃ b, f a = b)
|
|
||||||
```
|
|
||||||
|
|
||||||
* Mathlib Doc: [Surjective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Surjective)"
|
|
||||||
|
|
||||||
DefinitionDoc Bijective as "Bijective"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Bijective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.Bijective)
|
|
||||||
"
|
|
||||||
|
|
||||||
DefinitionDoc LeftInverse as "LeftInverse"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#LeftInverse](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Function.html#Function.LeftInverse)
|
|
||||||
"
|
|
||||||
|
|
||||||
DefinitionDoc RightInverse as "RightInverse"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#RightInverse](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Logic.html#RightInverse)
|
|
||||||
"
|
|
||||||
|
|
||||||
DefinitionDoc StrictMono as "StrictMono"
|
|
||||||
"
|
|
||||||
`StrictMono f` ist definiert als
|
|
||||||
|
|
||||||
```
|
|
||||||
∀ a b, a < b → f a < f b
|
|
||||||
```
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#StrictMono](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Order/Monotone/Basic.html#StrictMono)
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
DefinitionDoc Disjoint as "Disjoint"
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|
||||||
DefinitionDoc Set.preimage as "preimage"
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|
||||||
DefinitionDoc Set.Nonempty as "Nonempty" "
|
|
||||||
|
|
||||||
`A.Nonemty` ist als `∃ x, x ∈ A` definiert.
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|
||||||
DefinitionDoc Symbol.Subset as "⊆" "
|
|
||||||
|
|
||||||
Auf Mengen (`Set`) ist `A ⊆ B` als `∀x, x ∈ A → x ∈ B` implementiert.
|
|
||||||
|
|
||||||
Im goal kann man direkt `intro x hx` machen, in einer Annahme, kann man mit `rcases`
|
|
||||||
loslegen.
|
|
||||||
|
|
||||||
Alternativ kann man mit `rw[Set.subset_def]` die Definition explizit einsetzen.
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|
||||||
DefinitionDoc Symbol.function as "fun x => _" "
|
|
||||||
|
|
||||||
Anonyme funktionen kann man mit `fun (x : ℤ) => 2 * x` definieren und
|
|
||||||
wie andere Objekte verwenden.
|
|
||||||
|
|
||||||
Note: `=>` wird in mathlib oft auch `↦` (`\\maps`) geschrieben.
|
|
||||||
"
|
|
||||||
|
|
||||||
DefinitionDoc Inhabited as "Inhabited" "
|
|
||||||
`Inhabited U` ist eine Instanz, die aussagt, dass `U` mindestens ein Element
|
|
||||||
enthält.
|
|
||||||
|
|
||||||
Hat man eine solche Instanz, kann man immer das Element `(default : U)` verwenden.
|
|
||||||
|
|
||||||
Was `default` genau ist hängt davon ab, wie `Inhabited U` bewiesen wurde. Es könnte
|
|
||||||
also alles sein und man sollte sich nicht darauf verlassen, dass `default` eine
|
|
||||||
bestimmte Eigenschaft hat. Z.B. ist `(default : ℕ) = 0` aber es hätte genau so gut
|
|
||||||
als `1` oder `2` definiert werden können.
|
|
||||||
"
|
|
||||||
@@ -1,636 +0,0 @@
|
|||||||
import GameServer.Commands
|
|
||||||
|
|
||||||
-- Wird im Level "Implication 11" ohne Beweis angenommen.
|
|
||||||
LemmaDoc Classical.not_not as "not_not" in "Logic"
|
|
||||||
"
|
|
||||||
`not_not {A : Prop} : ¬¬A ↔ A`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `Classical`
|
|
||||||
* Minimal Import: `Std.Logic`
|
|
||||||
* Mathlib Doc: [#not_not](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Classical.not_not)
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Wird im Level "Implication 10" ohne Beweis angenommen.
|
|
||||||
LemmaDoc not_or_of_imp as "not_or_of_imp" in "Logic"
|
|
||||||
"
|
|
||||||
`not_or_of_imp {A B : Prop} : (A → B) → ¬A ∨ B`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `-`
|
|
||||||
* Minimal Import: `Mathlib.Logic.Basic`
|
|
||||||
* Mathlib Doc: [#not_or_of_imp](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#not_or_of_imp)
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Wird im Level "Implication 12" bewiesen.
|
|
||||||
LemmaDoc imp_iff_not_or as "imp_iff_not_or" in "Logic"
|
|
||||||
"
|
|
||||||
`imp_iff_not_or {A B : Prop} : (A → B) ↔ (¬A ∨ B)`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `-`
|
|
||||||
* Minimal Import: `Mathlib.Logic.Basic`
|
|
||||||
* Mathlib Doc: [#imp_iff_not_or](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#imp_iff_not_or)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Nat.succ_pos as "succ_pos" in "Nat"
|
|
||||||
"
|
|
||||||
`Nat.succ_pos (n : ℕ) : 0 < n.succ`
|
|
||||||
|
|
||||||
$n + 1$ ist strikt grösser als Null.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp` Lemma: Nein
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Minimal Import: `Mathlib.Init.Prelude`
|
|
||||||
* Mathlib Doc: [#Nat.succ_pos](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#Nat.succ_pos)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Nat.pos_iff_ne_zero as "pos_iff_ne_zero" in "Nat"
|
|
||||||
"
|
|
||||||
`Nat.pos_iff_ne_zero {n : ℕ} : 0 < n ↔ n ≠ 0`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Minimal Import: `Std.Data.Nat.Lemmas`
|
|
||||||
* Mathlib Doc: [#Nat.pos_iff_ne_zero](https://leanprover-community.github.io/mathlib4_docs/Std/Data/Nat/Lemmas.html#Nat.pos_iff_ne_zero)
|
|
||||||
"
|
|
||||||
|
|
||||||
-- TODO: Not minimal description
|
|
||||||
LemmaDoc zero_add as "zero_add" in "Addition"
|
|
||||||
"
|
|
||||||
`zero_add (a : ℕ) : 0 + a = a`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `-`
|
|
||||||
* Import: `Mathlib.Nat.Basic`
|
|
||||||
* Mathlib Doc: [#zero_add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Group/Defs.html#zero_add)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc add_zero as "add_zero" in "Addition"
|
|
||||||
"
|
|
||||||
This lemma says `∀ a : ℕ, a + 0 = a`.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc"
|
|
||||||
|
|
||||||
LemmaDoc add_succ as "add_succ" in "Addition"
|
|
||||||
"This lemma says `∀ a b : ℕ, a + succ b = succ (a + b)`.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#]()"
|
|
||||||
|
|
||||||
LemmaDoc not_forall as "not_forall" in "Logic"
|
|
||||||
"
|
|
||||||
`not_forall {α : Sort _} {P : α → Prop} : ¬(∀ x, → P x) ↔ ∃ x, ¬P x`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `-`
|
|
||||||
* Minimal Import: `Mathlib.Logic.Basic`
|
|
||||||
* Mathlib Doc: [#not_forall](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#not_forall)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc not_exists as "not_exists" in "Logic"
|
|
||||||
"
|
|
||||||
`not_exists {α : Sort _} {P : α → Prop} : (¬∃ x, P x) ↔ ∀ (x : α), ¬P x.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `-`
|
|
||||||
* Minimal Import: `Std.Logic`
|
|
||||||
* Mathlib Doc: [#not_exists](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#not_exists)"
|
|
||||||
|
|
||||||
LemmaDoc Nat.even_iff_not_odd as "even_iff_not_odd" in "Nat"
|
|
||||||
"
|
|
||||||
`even_iff_not_odd {n : ℕ} : Even n ↔ ¬Odd n`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Minimal Import: `Mathlib.Data.Nat.Parity`
|
|
||||||
* Mathlib Doc: [#Nat.even_iff_not_odd](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Parity.html#Nat.even_iff_not_odd)"
|
|
||||||
|
|
||||||
LemmaDoc Nat.odd_iff_not_even as "odd_iff_not_even" in "Nat"
|
|
||||||
"
|
|
||||||
`Nat.odd_iff_not_even {n : ℕ} : Odd n ↔ ¬Even n`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Minimal Import: `Mathlib.Data.Nat.Parity`
|
|
||||||
* Mathlib Doc: [#Nat.odd_iff_not_even](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Parity.html#Nat.odd_iff_not_even)"
|
|
||||||
|
|
||||||
LemmaDoc even_square as "even_square" in "Nat"
|
|
||||||
"
|
|
||||||
`even_square : (n : ℕ), Even n → Even (n ^ 2)`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* *Nicht in Mathlib*
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_univ as "mem_univ" in "Set"
|
|
||||||
"
|
|
||||||
`Set.mem_univ {α : Type _} (x : α) : x ∈ @univ α`
|
|
||||||
|
|
||||||
Jedes Element ist in `univ`, der Menge aller Elemente eines Typs `α`.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
|
||||||
* Mathlib Doc: [#mem_univ](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.mem_univ)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.not_mem_empty as "not_mem_empty" in "Set"
|
|
||||||
"
|
|
||||||
`Set.not_mem_empty {α : Type _} (x : α) : x ∉ ∅`
|
|
||||||
|
|
||||||
Kein Element ist in der leeren Menge.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#not_mem_empty](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.not_mem_empty)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.subset_empty_iff as "subset_empty_iff" in "Set"
|
|
||||||
"
|
|
||||||
`Set.subset_empty_iff.{u} {α : Type u} {s : Set α} : s ⊆ ∅ ↔ s = ∅`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#empty_subset](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.subset_empty_iff)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.empty_subset as "empty_subset" in "Set"
|
|
||||||
"
|
|
||||||
`Set.empty_subset {α : Type u} (s : Set α) : ∅ ⊆ s`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Ja
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#empty_subset](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.empty_subset)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.Subset.antisymm as "Subset.antisymm" in "Set"
|
|
||||||
"
|
|
||||||
`Set.Subset.antisymm {α : Type u} {a : Set α} {b : Set α} (h₁ : a ⊆ b) (h₂ : b ⊆ a) : a = b`
|
|
||||||
|
|
||||||
Zwei Mengen sind identisch, wenn sowohl $A \\subseteq B$ wie auch $B \\subseteq A$.
|
|
||||||
## Details
|
|
||||||
|
|
||||||
`apply Subset.antisymm` ist eine Möglichkeit Gleichungen von Mengen zu zeigen.
|
|
||||||
eine andere ist `ext i`, welches Elementweise funktiniert.
|
|
||||||
Siehe auch
|
|
||||||
[`#Subset.antisymm_iff`](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm_iff)
|
|
||||||
für die Iff-Version.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Set.Subset`
|
|
||||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
|
||||||
* Mathlib Doc: [#Subset.antisymm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.Subset.antisymm_iff as "Subset.antisymm_iff" in "Set"
|
|
||||||
"
|
|
||||||
`Set.Subset.antisymm_iff {α : Type u} {a : Set α} {b : Set α} : a = b ↔ a ⊆ b ∧ b ⊆ a`
|
|
||||||
|
|
||||||
Zwei Mengen sind identisch, wenn sowohl $A \\subseteq B$ wie auch $B \\subseteq A$.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
`rw [Subset.antisymm_iff]` ist eine Möglichkeit Gleichungen von Mengen zu zeigen.
|
|
||||||
eine andere ist `ext i`, welches Elementweise funktiniert.
|
|
||||||
Siehe auch
|
|
||||||
[`#Subset.antisymm`](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm)
|
|
||||||
für eine verwandte Version.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Set.Subset`
|
|
||||||
* Minimal Import: `Mathlib.Data.Set.Basic`
|
|
||||||
* Mathlib Doc: [#Subset.antisymm_iff](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.Subset.antisymm_iff)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.diff_inter as "diff_inter" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} {s t u : Set α} : s \\ (t ∩ u) = s \\ t ∪ s \\ u`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#Set.diff_inter](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.diff_inter)
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.union_assoc as "union_assoc" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} (a b c : Set α) : a ∪ b ∪ c = a ∪ (b ∪ c)`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#Set.union_assoc](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.union_assoc)
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.union_diff_distrib as "union_diff_distrib" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} {s t u : Set α} : (s ∪ t) \\ u = s \\ u ∪ t \\ u`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#Set.union_diff_distrib](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.union_diff_distrib)
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.univ_union as "univ_union" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} {s : Set α} : Set.univ ∪ s = Set.univ`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
* Namespace: `Set`
|
|
||||||
* Mathlib Doc: [#Set.univ_union](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.univ_union)
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Nat.prime_def_lt'' as "prime_def_lt''" in "Nat"
|
|
||||||
"
|
|
||||||
`Nat.prime_def_lt'' {p : ℕ} :
|
|
||||||
Nat.Prime p ↔ 2 ≤ p ∧ ∀ (m : ℕ), m ∣ p → m = 1 ∨ m = p`
|
|
||||||
|
|
||||||
Die bekannte Definition einer Primmzahl in `ℕ`: Eine Zahl (`p ≥ 2`) mit genau zwei Teilern.
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Mathlib Doc: [#Nat.prime_def_lt''](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Nat/Prime.html#Nat.prime_def_lt'')
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Finset.sum_add_distrib as "sum_add_distrib" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Finset`
|
|
||||||
* Mathlib Doc: [#Finset.sum_add_distrib](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Basic.html#Finset.sum_add_distrib)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Fin.sum_univ_castSucc as "sum_univ_castSucc" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Fin`
|
|
||||||
* Mathlib Doc: [#sum_univ_castSucc](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Fin.html#Fin.sum_univ_castSucc)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Nat.succ_eq_add_one as "succ_eq_add_one" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* `simp`-Lemma: Nein
|
|
||||||
* Namespace: `Nat`
|
|
||||||
* Mathlib Doc: [#succ_eq_add_one](https://leanprover-community.github.io/mathlib4_docs/Init/Data/Nat/Basic.html#Nat.succ_eq_add_one)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc ne_eq as "ne_eq" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#ne_eq](https://leanprover-community.github.io/mathlib4_docs/Init/SimpLemmas.html#ne_eq)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.eq_empty_iff_forall_not_mem as "eq_empty_iff_forall_not_mem" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#eq_empty_iff_forall_not_mem](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.eq_empty_iff_forall_not_mem)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Nat.zero_eq as "zero_eq" in "Nat"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#zero_eq](https://leanprover-community.github.io/mathlib4_docs/Init/Data/Nat/Basic.html#Nat.zero_eq)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc add_comm as "add_comm" in "Nat"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#add_comm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Group/Defs.html#add_comm)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc mul_add as "mul_add" in "Nat"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#mul_add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Ring/Defs.html#mul_add)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc add_mul as "add_mul" in "Nat"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#add_mul](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Ring/Defs.html#add_mul)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc arithmetic_sum as "arithmetic_sum" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Not a mathlib lemma.
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc add_pow_two as "add_pow_two" in "Nat"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#add_pow_two](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/GroupPower/Ring.html#add_pow_two)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Finset.sum_comm as "sum_comm" in "Sum"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#sum_comm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/BigOperators/Basic.html#Finset.sum_comm)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Function.comp_apply as "comp_apply" in "Function"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#comp_apply](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Function.comp_apply)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc not_le as "not_le" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#not_le](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Init/Algebra/Order.html#not_le)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc if_pos as "if_pos" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#if_pos](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#if_pos)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc if_neg as "if_neg" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#if_neg](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#if_neg)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc StrictMono.injective as "StrictMono.injective" in "Function"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#StrictMono.injective](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Order/Monotone/Basic.html#StrictMono.injective)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc StrictMono.add as "StrictMono.add" in "Function"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#StrictMono.add](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Order/Monoid/Lemmas.html#StrictMono.add)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Odd.strictMono_pow as "Odd.strictMono_pow" in "Function"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Odd.strictMono_pow](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Parity.html#Odd.strictMono_pow)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Exists.choose as "Exists.choose" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Exists.choose](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Exists.choose)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Exists.choose_spec as "Exists.choose_spec" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Exists.choose_spec](https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#Exists.choose_spec)
|
|
||||||
"
|
|
||||||
LemmaDoc congrArg as "congrArg" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#congrArg](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#congrArg)
|
|
||||||
"
|
|
||||||
LemmaDoc congrFun as "congrFun" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#congrFun](https://leanprover-community.github.io/mathlib4_docs/Init/Prelude.html#congrFun)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Iff.symm as "Iff.symm" in "Logic"
|
|
||||||
"
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#Iff.symm](https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Iff.symm)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc not_imp_not as "not_imp_not" in "Logic"
|
|
||||||
"
|
|
||||||
`theorem not_imp_not {a : Prop} {b : Prop} : ¬a → ¬b ↔ b → a`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#not_imp_not](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Logic/Basic.html#not_imp_not)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.nonempty_iff_ne_empty as "nonempty_iff_ne_empty" in "Logic"
|
|
||||||
"
|
|
||||||
`theorem Set.nonempty_iff_ne_empty {α : Type u} {s : Set α} : Set.Nonempty s ↔ s ≠ ∅`
|
|
||||||
|
|
||||||
## Eigenschaften
|
|
||||||
|
|
||||||
* Mathlib Doc: [#nonempty_iff_ne_empty](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Set/Basic.html#Set.nonempty_iff_ne_empty)
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.subset_univ as "subset_univ" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} {s : Set α} : s ⊆ univ`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.not_mem_compl_iff as "not_mem_compl_iff" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} {s : Set α} {x : α} : ¬x ∈ sᶜ ↔ x ∈ s`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_of_subset_of_mem as "mem_of_subset_of_mem" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} {s₁ : Set α} {s₂ : Set α} {a : α} (h : s₁ ⊆ s₂) :
|
|
||||||
a ∈ s₁ → a ∈ s₂`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.compl_eq_univ_diff as "compl_eq_univ_diff" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} (s : Set α) :
|
|
||||||
sᶜ = Set.univ \\ s`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.compl_union as "compl_union" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} (s t : Set α) :
|
|
||||||
(s ∪ t)ᶜ = sᶜ ∩ tᶜ`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.diff_diff as "diff_diff" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} {s t u : Set α} :
|
|
||||||
(s \\ t) \\ u = s \\ (t ∪ u)`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.compl_inter as "compl_inter" in "Set"
|
|
||||||
"
|
|
||||||
` {α : Type u} (s t : Set α) :
|
|
||||||
(s ∩ t)ᶜ = sᶜ ∪ tᶜ`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.diff_eq_compl_inter as "diff_eq_compl_inter" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} {s t : Set α} : s \\ t = tᶜ ∩ s`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.inter_comm as "inter_comm" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} (a b : Set α) : a ∩ b = b ∩ a`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_compl_iff as "mem_compl_iff" in "Set"
|
|
||||||
"
|
|
||||||
`{α : Type u} (s : Set α) (x : α) : x ∈ sᶜ ↔ ¬x ∈ s`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.subset_def as "subset_def" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.ssubset_def as "ssubset_def" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc not_imp as "not_imp" in "Logic"
|
|
||||||
"
|
|
||||||
`{a : Prop} {b : Prop} : (a → b) ↔ a ∧ ¬b`
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_diff as "mem_diff" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_insert_iff as "mem_insert_iff" in "Logic"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_singleton_iff as "mem_singleton_iff" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Function.bijective_iff_has_inverse as "bijective_iff_has_inverse" in "Function"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_setOf as "mem_setOf" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.mem_powerset_iff as "mem_powerset_iff" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.subset_union_of_subset_left as "subset_union_of_subset_left" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.subset_union_of_subset_right as "subset_union_of_subset_right" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.setOf_or as "setOf_or" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaDoc Set.setOf_and as "setOf_and" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
LemmaDoc Set.mem_inter_iff as "mem_inter_iff" in "Set"
|
|
||||||
"
|
|
||||||
``
|
|
||||||
"
|
|
||||||
@@ -1,584 +0,0 @@
|
|||||||
import GameServer.Commands
|
|
||||||
import Adam.Tactics
|
|
||||||
|
|
||||||
TacticDoc assumption
|
|
||||||
"
|
|
||||||
`assumption` sucht nach einer Annahme, die genau dem Goal entspricht.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
`assumption` sucht durch die Annahmen und merkt dass `h` genau mit dem Goal übereinstimmt.
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
a b c d : ℕ
|
|
||||||
h : a + b = c
|
|
||||||
g : a * b = 16
|
|
||||||
t : c = 12
|
|
||||||
Goal
|
|
||||||
a + b = c
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc apply
|
|
||||||
"
|
|
||||||
`apply my_lemma` Versucht das Goal mit der Aussage des Lemmas zu unifizieren
|
|
||||||
und erstellt ein neues Goal pro Annahme des Lemmas, die noch zu zeigen ist.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
`apply` funktioniert gleichermassen für Lemmas wie für Implikationen
|
|
||||||
wie z.B. `(h : A → B)`.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
Gegeben folgendes Lemma:
|
|
||||||
```
|
|
||||||
lemma Nat.eq_zero_of_le_zero {n : ℕ} (h : n ≤ 0) : n = 0 := by sorry
|
|
||||||
```
|
|
||||||
|
|
||||||
Und folgendes Problem:
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Objekte
|
|
||||||
n : ℕ
|
|
||||||
...
|
|
||||||
Goal
|
|
||||||
n = 0
|
|
||||||
```
|
|
||||||
|
|
||||||
Hier ändert `apply Nat.eq_zero_of_le_zero` das Goal zu `n ≤ 0` durch Anwendung
|
|
||||||
des Lemmas.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc by_cases
|
|
||||||
"
|
|
||||||
`by_cases h : P` macht eine Fallunterscheidung. Im ersten Goal wird eine Annahme
|
|
||||||
`(h : P)` hinzugefügt, im zweiten `(h : ¬P)`.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
`P` kann eine beliegige Aussage sein, die als entweder wahr oder falsch angenommen wird.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
```
|
|
||||||
example (A : Prop) : A ∨ ¬ A := by
|
|
||||||
by_cases h : A
|
|
||||||
· left
|
|
||||||
assumption
|
|
||||||
· right
|
|
||||||
assumption
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc by_contra
|
|
||||||
"
|
|
||||||
`by_contra h` startet einen Widerspruchsbeweis.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Sei `P` das aktuelle Goal. `by_contra h` fügt eine neue Annahme `(h : ¬P)` hinzu
|
|
||||||
und setzt das Goal auf `False`.
|
|
||||||
|
|
||||||
Oft will man `by_contra` nutzen wenn das Goal von der Form `¬ P` ist.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `contradiction` schliesst den Widerspruchsbeweis wenn sich (zwei) Annahmen
|
|
||||||
widersprechen.
|
|
||||||
* `contrapose` führt einen Beweis durch Kontraposition und ist entsprechend
|
|
||||||
in ähnlichen Situationen nutzbar wie `by_contra`
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc change
|
|
||||||
"
|
|
||||||
`change t` ändert das Goal zu `t`. Voraussetzung ist, dass `t` und das alte Goal defEq sind.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
Dies ist insbesonder hilfreich wenn eine Taktik nicht merkt, dass das Goal defEq ist zu einem
|
|
||||||
Term, der eigentlich gebraucht würde.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
Aktuelles Goal:
|
|
||||||
|
|
||||||
```
|
|
||||||
b: ℝ
|
|
||||||
⊢ 1 • b = b
|
|
||||||
```
|
|
||||||
Wobei die Skalarmultiplikation als `fun (a : ℚ) (r : ℝ) => ↑a * r` definiert war. Dann
|
|
||||||
kann man mit `change (1 : ℚ) * b = b` das Goal umschreiben und anschliessend mit Lemmas
|
|
||||||
über die Multiplikation beweisen.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc constructor
|
|
||||||
"
|
|
||||||
`constructor` teilt ein Goal auf, wenn das Goal eine Struktur ist
|
|
||||||
|
|
||||||
## Detail
|
|
||||||
Wenn das Goal eine Struktur ist, wie z.B. `A ∧ B` welches zwei Felder hat `⟨A, B⟩`, dann
|
|
||||||
erzeugt `constructor` ein Goal pro Feld der Struktur.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* Das Gegenteil von `constructor` ist `⟨_, _⟩` (`\\<>`), der *anonyme Konstructor*.
|
|
||||||
Dieser enspricht ungefähr der Tupel-Notation in
|
|
||||||
\"eine Gruppe ist ein Tupel $(G, 0, +)$, sodass …\".
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
```
|
|
||||||
example {A B : Prop} (h : A) (g : B) : A ∧ B := by
|
|
||||||
constructor
|
|
||||||
· assumption
|
|
||||||
· assumption
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc contradiction
|
|
||||||
"
|
|
||||||
`contradiction` schliesst den Beweis wenn es einen Widerspruch in den Annahmen findet.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Ein Widerspruch in den Annahmen kann unter anderem folgendermassen aussehen:
|
|
||||||
|
|
||||||
* `(h : n ≠ n)`
|
|
||||||
* `(h : A)` und `(h' : ¬A)`
|
|
||||||
* `(h : False)` (i.e. ein Beweis von `False`)
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
Folgenes Goal wird von `contradiction` bewiesen
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* Normalerweise wird `contradiction` gebraucht um einen Widerspruchsbeweis zu
|
|
||||||
schliessen, der mit `by_contra` eröffnet wurde.
|
|
||||||
* Ein Beweis von `False` representiert in Lean einen Widerspruch.
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte:
|
|
||||||
(n m : ℕ)
|
|
||||||
(h : n = m)
|
|
||||||
(g : n ≠ m)
|
|
||||||
Goal
|
|
||||||
37 = 60
|
|
||||||
```
|
|
||||||
nach dem Motto \"ein Widerspruch beweist alles.\"
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc contrapose
|
|
||||||
"
|
|
||||||
`contrapose` ändert ein Goal der Form `A → B` zu `¬B → ¬A` und führt damit
|
|
||||||
eine Beweis durch Kontraposition.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `revert h` kann nützlich sein um eine Annahme als Implikationsprämisse zu schreiben bevor man
|
|
||||||
`contrapose` verwendet.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc exact
|
|
||||||
"
|
|
||||||
`exact h` schliesst das Goal wenn der Term `h` mit dem Goal übereinstimmt.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc fin_cases
|
|
||||||
"
|
|
||||||
`fin_cases i` führt eine Fallunterscheidung wenn `i` ein endlicher Typ ist.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
`fin_cases i` ist insbesondere nützlich für `(i : Fin n)`, zum Beispiel als Index in
|
|
||||||
endlich dimensionalen Vektorräumen.
|
|
||||||
|
|
||||||
In diesem Fall bewirkt `fin_cases i` dass man Komponentenweise arbeitet.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc funext
|
|
||||||
"
|
|
||||||
`funext x` wird bei Gleichungen von Funktionen `f = g` gebraucht. Das Goal wird zu
|
|
||||||
`f x = g x`.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Nach dem Motto `f = g ↔ ∀ x, f x = g x` sind zwei Funktionen dann identisch, wenn sie
|
|
||||||
angewendet auf jedes Element identisch sind. `funext x` benützt dieses Argument.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc «have»
|
|
||||||
"
|
|
||||||
`have h : P` führt ein Zwischenresultat ein.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Anschliessend muss man zuerst dieses Zwischenresultat beweisen bevor man mit dem Beweis
|
|
||||||
weitermachen und das Zwischenresultat verwenden kann.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `suffices h : P` funktioniert genau gleich, aussert das die beiden entstehenden Beweise
|
|
||||||
vertauscht sind.
|
|
||||||
* `let h : Prop := A ∧ B` ist verwandt mit `have`, mit Unterschied, dass man mit `let`
|
|
||||||
eine temporäre Definition einführt.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc induction
|
|
||||||
"
|
|
||||||
`induction n` führt einen Induktionsbeweis über `n`.
|
|
||||||
|
|
||||||
## Detail
|
|
||||||
|
|
||||||
Diese Taktik erstellt zwei Goals:
|
|
||||||
* Induktionsanfang, wo `n = 0` ersetzt wird.
|
|
||||||
* Induktionsschritt, in dem man die Induktionshypothese `n_ih` zur Verfügung hat.
|
|
||||||
|
|
||||||
## Modifikationen in diesem Spiel
|
|
||||||
|
|
||||||
* `induction n with d hd` benennt Induktionsvariable und -hypothese. (das ist Lean3-Syntax)
|
|
||||||
und funktioniert ausserhalb vom Spiel nicht genau so.
|
|
||||||
* Ausserhalb des Spiels kriegst du `Nat.zero` und `Nat.succ n` anstatt `0` und `n + 1`
|
|
||||||
als Fälle. Diese
|
|
||||||
Terme sind DefEq, aber manchmal benötigt man die lemmas `zero_eq` und `Nat.succ_eq_add_one`
|
|
||||||
um zwischen den schreibweisen zu wechseln
|
|
||||||
|
|
||||||
Der richtige Lean4-Syntax für `with` streckt sich über mehrere Zeilen und ist:
|
|
||||||
|
|
||||||
```
|
|
||||||
induction n with
|
|
||||||
| zero =>
|
|
||||||
sorry
|
|
||||||
| succ m m_ih =>
|
|
||||||
sorry
|
|
||||||
```
|
|
||||||
|
|
||||||
da dieser sich über mehrere Zeilen erstreckt wird er im Spiel nicht eingeführt.
|
|
||||||
|
|
||||||
## Hifreiche Resultate
|
|
||||||
|
|
||||||
* `Nat.succ_eq_add_one`: schreibt `n.succ = n + 1` um.
|
|
||||||
* `Nat.zero_eq`: schreibt `Nat.zero = 0` um.
|
|
||||||
|
|
||||||
Beide sind DefEq, aber manche Taktiken können nicht damit umgehen
|
|
||||||
|
|
||||||
* Siehe Definition `∑` für Hilfe mit Induktion über Summen.
|
|
||||||
* `rcases n` ist sehr ähnlich zu `induction n`. Der Unterschied ist, dass bei
|
|
||||||
`rcases` keine Induktionshypothese im Fall `n + 1` zur Verfügung steht.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
```
|
|
||||||
example (n : ℕ) : 4 ∣ 5^n + 7 := by
|
|
||||||
induction n
|
|
||||||
sorry -- Fall `n = 0`
|
|
||||||
sorry -- Fall `n + 1`
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc intro
|
|
||||||
"
|
|
||||||
`intro x` wird für Goals der Form `A → B` oder `∀ x, P x` verwendet.
|
|
||||||
Dadurch wird die Implikationsprämisse (oder das Objekt `x`) den Annahmen hinzugefügt.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `revert h` macht das Gegenteil von `intro`.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc left
|
|
||||||
"
|
|
||||||
Wenn das Goal von der Form `A ∨ B` ist, enscheidet man mit `left` die linke Seite zu zeigen.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `right` entscheidet sich für die linke Seite.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc «let»
|
|
||||||
"
|
|
||||||
`let x : ℕ := 5 ^ 2` führt eine neue temporäre Definition ein.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `have x : ℕ := 5 ^ 2` führt ebenfalls eine neue natürliche Zahle `x` ein, aber
|
|
||||||
Lean vergisst sofort, wie die Zahl definiert war. D.h. `x = 25` wäre dann nicht
|
|
||||||
beweisbar. Mit `let x : ℕ := 5 ^ 2` ist `x = 25` durch `rfl` beweisbar.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc linarith
|
|
||||||
"
|
|
||||||
`linarith` löst Systeme linearer (Un-)Gleichungen.
|
|
||||||
|
|
||||||
## Detail
|
|
||||||
`linarith` kann lineare Gleichungen und Ungleichungen beweisen indem
|
|
||||||
es das Gegenteil vom Goal annimmt und versucht einen Widerspruch in den
|
|
||||||
Annahmen zu erzeugen (Widerspruchsbeweis). Es braucht ein `≤` definiert um
|
|
||||||
zu funktionieren.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
Folgendes kann `linarith` beweisen.
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
x y : ℤ
|
|
||||||
h₁ : 5 * y ≤ 35 - 2 * x
|
|
||||||
h₂ : 2 * y ≤ x + 3
|
|
||||||
Goal
|
|
||||||
y ≤ 5
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc push_neg
|
|
||||||
"
|
|
||||||
`push_neg` schreibt `¬∀ x, _` zu `∃ x, ¬ _` und `¬∃ x, _` zu `∀x, ¬ _` um.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
`psuh_neg` schiebt das `¬` soweit nach innen wie möglich.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* Die beiden Lemmas heissen `not_forall` und `not_exists` und können mit `rw` einzeln angewendet
|
|
||||||
werden.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc rcases
|
|
||||||
"
|
|
||||||
`rcases h` teilt eine Annahme `h` in ihre Einzelteile auf.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Für Annahmen die Strukturen sind, wie z.B. `h : A ∧ B` (oder `∃x, P x`) kann man die
|
|
||||||
Einzelteile mit `rcases h with ⟨a, b⟩` (oder `rcases h with ⟨x, hx⟩`) benennen.
|
|
||||||
|
|
||||||
Für eine Annahme der Form `h : A ∨ B` kann man mit `rcases h with ha | hb` zwei Goals
|
|
||||||
erzeugen, einmal unter Annahme der linken Seite, einmal unter Annahme der Rechten.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* Für `n : ℕ` hat `rcases n` einen ähnlichen Effekt wie `induction n` mit dem Unterschied,
|
|
||||||
dass im Fall `n + 1` keine Induktionshypothese zur Verfügung steht.
|
|
||||||
* In Lean gibt es auch die Taktik `cases`, die gleich funktioniert wie `rcases` aber
|
|
||||||
einen mehrzeiligen Syntax hat:
|
|
||||||
```
|
|
||||||
cases h with
|
|
||||||
| inl ha =>
|
|
||||||
sorry
|
|
||||||
| inr hb =>
|
|
||||||
sorry
|
|
||||||
```
|
|
||||||
Hier sind `inl`/`inr` die Namen der Fälle und `ha`/`hb` sind frei gewählte Namen für die
|
|
||||||
freien Variablen
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc refine
|
|
||||||
"
|
|
||||||
`refine { ?..! }` wird benötigt um eine Struktur (z.B. ein $R$-Modul) im Taktikmodus in einzelne
|
|
||||||
Goals aufzuteilen. Danach hat man ein Goal pro Strukturfeld.
|
|
||||||
|
|
||||||
(*Bemerkung*: Es gibt in Lean verschiedenste bessere Varianten dies zu erreichen,
|
|
||||||
z.B. \"Term Modus\" oder \"anonyme Konstruktoren\", aber für den Zweck des Spieles bleiben wir
|
|
||||||
bei diesem Syntax.)
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc revert
|
|
||||||
"
|
|
||||||
`revert h` fügt die Annahme `h` als Implikationsprämisse vorne ans Goal an.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `revert` ist das Gegenteil von `intro`.
|
|
||||||
* `revert` kann insbesondere nützlich sein, um anschliessend `contrapose` zu verwenden.
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
A P : Prop
|
|
||||||
h : P
|
|
||||||
Goal
|
|
||||||
A
|
|
||||||
```
|
|
||||||
|
|
||||||
hier ändert `revert h` den Status zu
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
A P : Prop
|
|
||||||
Goal
|
|
||||||
P → A
|
|
||||||
```
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc rfl
|
|
||||||
"
|
|
||||||
`rfl` beweist ein Goal der Form `X = X`.
|
|
||||||
|
|
||||||
## Detail
|
|
||||||
|
|
||||||
`rfl` beweist jedes Goal `A = B` wenn `A` und `B` per Definition das gleiche sind (DefEq).
|
|
||||||
Andere Taktiken rufen `rfl` oft am Ende versteckt
|
|
||||||
automatisch auf um zu versuchen, den Beweis zu schliessen.
|
|
||||||
|
|
||||||
|
|
||||||
## Beispiel
|
|
||||||
`rfl` kann folgende Goals beweisen:
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
a b c : ℕ
|
|
||||||
Goal:
|
|
||||||
(a + b) * c = (a + b) * c
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
Objekte
|
|
||||||
n : ℕ
|
|
||||||
Goal
|
|
||||||
1 + 1 = 2
|
|
||||||
```
|
|
||||||
denn Lean liest dies intern als `0.succ.succ = 0.succ.succ`.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc right
|
|
||||||
"
|
|
||||||
Wenn das Goal von der Form `A ∨ B` ist, enscheidet man mit `right` die rechte Seite zu zeigen.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `left` entscheidet sich für die linke Seite.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc ring_nf
|
|
||||||
"\"ring Normal Form\": Identisch zu `ring`. `ring` wird geschrieben, wenn die Taktik das Goal schliesst, `ring_nf`
|
|
||||||
wenn man diese innerhalb eines Taktikblockes brauchen will.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc ring
|
|
||||||
"
|
|
||||||
Löst Gleichungen mit den Operationen `+, -, *, ^`.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Insbesondere funktioniert `ring` in Ringen/Semiringen wie z.B. `ℕ, ℤ, ℚ, …`
|
|
||||||
(i.e. Typen `R` mit Instanzen `Ring R` oder `Semiring R`).
|
|
||||||
Die Taktik ist besonders auf kommutative Ringe (`CommRing R`) ausgelegt.
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `ring` kann nicht wirklich mit Division (`/`) oder Inversen (`⁻¹`) umgehen. Dafür ist die
|
|
||||||
Taktik `field_simp` gedacht, und die typische Sequenz ist
|
|
||||||
```
|
|
||||||
field_simp
|
|
||||||
ring
|
|
||||||
```
|
|
||||||
* Wenn `ring` nicht abschliesst, sagt es man solle `ring_nf` verwenden. Normalerweise heisst
|
|
||||||
das aber, dass man was falsch gemacht hat und die Seiten der Gleichung noch nicht gleich sind.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc rw
|
|
||||||
"
|
|
||||||
Wenn man eine Annahme `(h : X = Y)` hat, kann man mit
|
|
||||||
`rw [h]` alle `X` im Goal durch `Y` ersetzen.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
* `rw [←h]` wendet `h` rückwärts an und ersetzt alle `Y` durch `X`.
|
|
||||||
* `rw [h, g, ←f]`: Man kann auch mehrere `rw` zusammenfassen.
|
|
||||||
* `rw [h] at h₂` ersetzt alle `X` in `h₂` zu `Y` (anstatt im Goal).
|
|
||||||
|
|
||||||
`rw` funktioniert gleichermassen mit Annahmen `(h : X = Y)` also auch
|
|
||||||
mit Theoremen/Lemmas der Form `X = Y`
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc simp
|
|
||||||
"
|
|
||||||
`simp` versucht alle Vereinfachungslemmas anzuwenden, die in der `mathlib` mit `@[simp]`
|
|
||||||
gekennzeichnet sind.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
* `simp?` zeigt welche Lemmas verwendet wurden.
|
|
||||||
* `simp [my_lemma]` fügt zudem `my_lemma` temporär zur Menge der `simp`-Lemmas hinzu.
|
|
||||||
* ein `simp`, das nicht am Ende des Beweis steht sollte durch eine entsprechende
|
|
||||||
`simp only [...]` Aussage ersetzt werden, um den Beweis stabiler zu machen.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc simp_rw
|
|
||||||
"
|
|
||||||
`simp_rw [h₁, h₂, h₃]` versucht wie `rw` jedes Lemma der Reihe nach zu Umschreiben zu verwenden,
|
|
||||||
verwendet aber jedes Lemma so oft es kann.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
Es bestehen aber drei grosse Unterschiede zu `rw`:
|
|
||||||
|
|
||||||
* `simp_rw` wendet jedes Lemma so oft an wie es nur kann.
|
|
||||||
* `simp_rw` kann besser unter Quantifiern umschreiben als `rw`.
|
|
||||||
* `simp_rw` führt nach jedem Schritt ein `simp only []` aus und vereinfacht dadurch grundlegenste
|
|
||||||
Sachen.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc «suffices»
|
|
||||||
"
|
|
||||||
`suffices h : P` führt ein neues Zwischenresultat ein, aus dem das Goal direkt folgen soll.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
Der einzige Unterschied zu `have h : P` ist, dass die beiden resultierenden Goals vertauscht sind.
|
|
||||||
|
|
||||||
Mathematisch braucht man diese in ein bisschen unterschiedlichen Fällen:
|
|
||||||
|
|
||||||
* `suffices h : P` : \"Es genügt zu zeigen, dass …\". Als erstes folgt die Erklärung wieso
|
|
||||||
das genügt, danach muss man nur noch `P` beweisen.
|
|
||||||
* `have h : P` : Ein (kleines) Zwischenresultat. Als erstes folgt dann der Beweis dieses
|
|
||||||
Resultats, anschliessend setzt man den Beweis mit Hilfe des Zwischenresultats fort.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc tauto
|
|
||||||
"
|
|
||||||
## Beschreibung
|
|
||||||
|
|
||||||
TODO
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc trivial
|
|
||||||
"
|
|
||||||
`trivial` versucht durch Kombination von wenigen simplen Taktiken das Goal zu schliessen.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Die Taktiken, die verwendet werden sind:
|
|
||||||
|
|
||||||
* `assumption`
|
|
||||||
* `rfl`
|
|
||||||
* `contradiction`
|
|
||||||
* und noch 3 andere, die hier nicht behandelt werden
|
|
||||||
(`decide`, `apply True.intro`, `apply And.intro`).
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc unfold
|
|
||||||
"
|
|
||||||
`unfold myDef` öffnet eine Definition im Goal.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
Bis auf DefEq (definitinal equality) ändert `unfold` nichts, manche Taktiken
|
|
||||||
(z.B. `push_neg`, `rw`) brauchen aber manchmal die Hilfe.
|
|
||||||
|
|
||||||
`unfold myDef at h` kann auch Definitionen in Annahmen öffnen
|
|
||||||
|
|
||||||
## Hilfreiche Resultate
|
|
||||||
|
|
||||||
* `change P` ist eine andere Taktik, die das aktuelle Goal in einen DefEq-Ausdruck umschreibt.
|
|
||||||
Diese Taktik braucht man auch manchmal um zu hacken, wenn Lean Mühe hat etwas zu verstehen.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc use
|
|
||||||
"
|
|
||||||
Wenn das Goal von der Form `∃x, P x` ist, kann man mit `use n` ein konkretes Element angeben
|
|
||||||
mit dem man das Goal beweisen möchte.
|
|
||||||
|
|
||||||
## Details
|
|
||||||
|
|
||||||
`use n` versucht zudem anschliessend `rfl` aufzurufen, und kann das Goal damit manchmal direkt
|
|
||||||
schließen.
|
|
||||||
"
|
|
||||||
|
|
||||||
TacticDoc ext
|
|
||||||
"
|
|
||||||
"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import Lean
|
|
||||||
|
|
||||||
-- show all available options
|
|
||||||
instance : ToString Lean.OptionDecl where
|
|
||||||
toString a := toString a.defValue ++ ", [" ++ toString a.group ++ "]: " ++ toString a.descr
|
|
||||||
|
|
||||||
def showOptions : IO Unit := do
|
|
||||||
let a <- Lean.getOptionDeclsArray
|
|
||||||
IO.println f! "{a}"
|
|
||||||
|
|
||||||
#eval showOptions
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Adam.Levels.Contradiction.L01_Have
|
|
||||||
import Adam.Levels.Contradiction.L02_Suffices
|
|
||||||
import Adam.Levels.Contradiction.L03_ByContra
|
|
||||||
import Adam.Levels.Contradiction.L04_ByContra
|
|
||||||
import Adam.Levels.Contradiction.L05_Contrapose
|
|
||||||
import Adam.Levels.Contradiction.L06_Summary
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Title "Spinoza"
|
|
||||||
|
|
||||||
Introduction "
|
|
||||||
**Robo**: Ich glaube, das ist Spinoza, einer der ganz wenigen Asteroiden vom Type QED. Schnell. Wir müssen uns ein bisschen beeilen, sonst verpassen wir ihn.
|
|
||||||
|
|
||||||
Eine halbe Stunde später seid ihr gelandet. Sehr einladend wirkt Spinoza nicht. Seine gesamte Oberfläche ist von feinem, rötlichen Sand bedeckt.
|
|
||||||
Ein einziger, einsamer Formalosoph, der sich als Benedictus vorstellt, erwartet euch.
|
|
||||||
|
|
||||||
**Benedictus**: Schön, dass Ihr gekommen seid! Ich habe schon auf Euch gewartet!
|
|
||||||
|
|
||||||
**Du**: Hast du auch ein paar dringende Fragen … ?
|
|
||||||
|
|
||||||
**Benedictus**: Ach nein, aus dem Alter bin ich heraus. Aber ich kann mir denken, wie es Euch auf Implis und Quantus ergangen ist. Und glaubt, mir auf den anderen Planeten wird es nicht viel besser. Aber ich kann Euch vielleicht ein bisschen vorbereiten.
|
|
||||||
|
|
||||||
**Du**: Können wir nicht einfach hier bleiben und uns ein wenig ausruhen?
|
|
||||||
|
|
||||||
Benedictus schüttelt den Kopf.
|
|
||||||
|
|
||||||
**Benedictus**: Nein. Spinoza verträgt keine drei Bewohner. Und Ihr müsst bald wieder weiter, sonst wird der Weg zu weit. Wir kommen nur alle 400 Jahre bei den Planeten vorbei.
|
|
||||||
"
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Was wir haben, haben wir."
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Benedictus**: Hier, schaut mal. Das habe ich für Euch vorbereitet.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Manchmal, wollen wir nicht am aktuellen Goal arbeiten, sondern zuerst ein
|
|
||||||
-- Zwischenresultat beweisen, welches wir dann benützen können.
|
|
||||||
|
|
||||||
-- Mit `have [Name] : [Aussage]` kann man ein Zwischenresultat erstellen,
|
|
||||||
-- dass man anschliessen beweisen muss.
|
|
||||||
|
|
||||||
-- Wenn du zum Beispiel die Annahmen `(h : A → ¬ B)` und `(ha : A)` hast, kannst
|
|
||||||
-- du mit
|
|
||||||
-- ```
|
|
||||||
-- have g : ¬ B
|
|
||||||
-- apply h
|
|
||||||
-- assumption
|
|
||||||
-- ```
|
|
||||||
-- eine neue Annahme `(g : ¬ B)` erstellen. Danach beweist du zuerst diese Annahme,
|
|
||||||
-- bevor du dann mit dem Beweis forfährst.
|
|
||||||
|
|
||||||
Statement (A B : Prop) (h : A → ¬ B) (k : A ∧ B) : False := by
|
|
||||||
Hint "**Du**: Also als erstes teile ich wohl mal das Und (`∧`) auf."
|
|
||||||
rcases k with ⟨h₁, h₂⟩
|
|
||||||
Hint "**Du**: Und jetzt …
|
|
||||||
|
|
||||||
**Benedictus**: … solltest du dir ein passendes Zwischenresultat zurechtlegen.
|
|
||||||
|
|
||||||
**Robo**: Ja! Probier mal `have g : ¬ B`!"
|
|
||||||
have g : ¬ B
|
|
||||||
· Hint "**Du**: Was? Jetzt hab ich einfach angenommen, dass sei richtig?
|
|
||||||
|
|
||||||
**Robo**: Nee, jetzt musst du das erst noch beweisen, bevor du es dann benutzen kannst."
|
|
||||||
Hint (hidden := true) "**Robo**: `apply` sollte helfen"
|
|
||||||
apply h
|
|
||||||
assumption
|
|
||||||
Hint "**Du**: Und wie war das nochmals wenn zwei Annahmen sich widersprechen?
|
|
||||||
|
|
||||||
**Robo**: `contradiction`."
|
|
||||||
contradiction
|
|
||||||
|
|
||||||
NewTactic «have»
|
|
||||||
DisabledTactic «suffices»
|
|
||||||
|
|
||||||
Conclusion "**Benedictus**: Das sieht gut aus!"
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Es reicht!"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Benedictus**: Ihr hättet natürlich auch erst das Hauptresultat und dann das Zwischenresultat beweisen können. Das könnt Ihr ja mal an dieser Aufgabe probieren, die ist ganz ähnlich.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Die Taktik `suffices` funktioniert genau gleich wie `have`,
|
|
||||||
-- vertauscht aber die beiden Beweisblöcke:
|
|
||||||
|
|
||||||
-- ```
|
|
||||||
-- suffices h : [Aussage]
|
|
||||||
-- [Beweis des Goals (mithilfe von h)]
|
|
||||||
-- [Beweis der Aussage h]
|
|
||||||
-- ```
|
|
||||||
-- Auf Deutsch entspricht `suffices g : [Aussage]` dem Ausdruck
|
|
||||||
-- \"Es genügt zu zeigen, dass `[Aussage]` wahr ist.\"
|
|
||||||
|
|
||||||
-- Man kann `have` und `suffices` nach belieben vertauschen. Bevorzugt, wählt man es so,
|
|
||||||
-- dass der erste Beweisblock der kürzere ist. Zum Beispiel wäre bei der vorigen Aufgabe
|
|
||||||
-- `suffices` schöner gewesen:
|
|
||||||
|
|
||||||
-- "Angenommen, man hat eine Implikation $A \\Rightarrow \\neg B$ und weiss, dass
|
|
||||||
-- $A \\land B$ wahr ist. Zeige, dass dies zu einem Widerspruch führt."
|
|
||||||
|
|
||||||
Statement
|
|
||||||
(A B : Prop) (h : A → ¬ B) (k₁ : A) (k₂ : B) : False := by
|
|
||||||
Hint "**Robo**: Ich weiss was er meint! Anstatt `have` kannst du auch `suffices`
|
|
||||||
verwenden. Das funktioniert genau gleich, außer, dass dann die beiden Beweisziele vertauscht sind.
|
|
||||||
|
|
||||||
**Du**: Also nach `suffices g : ¬B` muss ich dann zuerst zeigen, wie man mit `g` den Beweis
|
|
||||||
abschliesst, bevor ich `g` beweise?
|
|
||||||
|
|
||||||
**Robo**: Genau!"
|
|
||||||
suffices g : ¬ B
|
|
||||||
Hint "**Robo**: Also hier beendest du den Beweis unter der Annahme `{g}` sei wahr."
|
|
||||||
contradiction
|
|
||||||
Hint "**Robo**: Und hier beweist du das Zwischenresultat."
|
|
||||||
apply h
|
|
||||||
assumption
|
|
||||||
|
|
||||||
NewTactic «suffices»
|
|
||||||
DisabledTactic «have»
|
|
||||||
|
|
||||||
Conclusion "**Benedictus**: Genau so meinte ich das. Ob Ihr nun in Zukunft `have` und `suffices` verwendet, ist reine Geschmacksfrage. Hauptsache, Ihr wisst, wie Ihr entfernte Ziele in kleinen Schritte erreicht."
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Widerspruch"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"**Benedictus**: Hier ist noch eine Variante.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Eine sehr nützliche Beweismethode ist per Widerspruch.
|
|
||||||
|
|
||||||
-- Wir habe schon gesehen, dass `contradiction` einen Widerspruch in den Annahmen
|
|
||||||
-- sucht, und damit jegliches beweisen kann.
|
|
||||||
|
|
||||||
-- Um dorthin zu kommen, können wir `by_contra h` brauchen, welches das aktuelle
|
|
||||||
-- Goal auf `False` setzt und die Negierung des Goals als Annahme hinzufügt.
|
|
||||||
|
|
||||||
-- Insbesondere braucht man `by_contra h` meistens, wenn im Goal eine Negierung
|
|
||||||
-- steht:
|
|
||||||
|
|
||||||
Statement (A B : Prop) (g : A → B) (b : ¬ B) : ¬ A := by
|
|
||||||
Hint "**Robo**: Ein `¬` im Goal heißt häufig, dass du einen Widerspruchsbeweis führen
|
|
||||||
möchtest.
|
|
||||||
|
|
||||||
**Du**: Und wie mache ich das? Mit `contradiction`?
|
|
||||||
|
|
||||||
**Robo**: Mit `by_contra h` fängst du einen Widerspruchsbeweis an. Und mit `contradiction` schließt du ihn ab."
|
|
||||||
by_contra h
|
|
||||||
Hint "**Robo**: Jetzt hast du also eine Annahme `{h} : {A}`, und damit musst du einen Widerspruch herleiten.
|
|
||||||
|
|
||||||
Du könntest zum Beispiel jetzt mit `suffices` sagten, welchen Widerspruch du gern herleiten möchtest, etwa `suffices k : B`
|
|
||||||
"
|
|
||||||
suffices k : B
|
|
||||||
Hint "**Du**: Ah, und jetzt kann ich einfach sagen dass sich die Annahmen `{B}` und `¬{B}` sich widersprechen."
|
|
||||||
contradiction
|
|
||||||
Hint "**Robo**: Und jetzt musst du nur noch das Zwischenresultat herleiten, dass zu diesem Widerspruch geführt hat."
|
|
||||||
apply g
|
|
||||||
assumption
|
|
||||||
|
|
||||||
NewTactic by_contra
|
|
||||||
|
|
||||||
Conclusion "**Benedictus**: Ich sehe schon, Ihr lernt schnell!"
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Kontraposition"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Benedictus**: Ich habe noch eine schöne Frage zu ungeraden Quadraten für Euch. Aber vorher beweist Ihr besser noch diese Äquivalenz hier. Ich gaube, die hat sogar bei Euch einen Namen: *Kontrapositionsäquivalenz*, oder so etwas. Auf Leansch nennen wir die Äuqivalenz einfach `not_imp_not`. Ist doch viel einleuchtender, oder?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement not_imp_not (A B : Prop) : A → B ↔ (¬ B → ¬ A) := by
|
|
||||||
Hint "**Du**: Ja, das habe ich tatsächlich schon einmal gesehen.
|
|
||||||
|
|
||||||
**Robo**: Ja, klar hast du das schon einmal gesehen. Das benutzen Mathematiker doch ständig. Wenn ihnen zu $A ⇒ B$ nichts einfällt, zeigen sie stattdessen $¬B ⇒ ¬A$. Ich würde das ja statt *Kontraposition* oder `not_imp_not` eher *von_hinten_durch_die_Brust_ins_Auge* nennen. Aber gut, ich will mich nicht einmisschen.
|
|
||||||
"
|
|
||||||
Hint (hidden := true) "**Robo**: Fang doch mal mit `constructor` an."
|
|
||||||
constructor
|
|
||||||
intro h b
|
|
||||||
by_contra a
|
|
||||||
Hint "**Robo**: Ich würde wieder mit `suffices g : B` einen Widerspruch herbeiführen."
|
|
||||||
suffices b : B
|
|
||||||
contradiction
|
|
||||||
apply h
|
|
||||||
assumption
|
|
||||||
intro h a
|
|
||||||
Hint "**Robo**: Hier würde ich ebenfalls einen Widerspruchsbeweis anfangen."
|
|
||||||
by_contra b
|
|
||||||
Hint (hidden := true) "**Robo**: `suffices g : ¬ A` sieht nach einer guten Option aus."
|
|
||||||
suffices g : ¬ A
|
|
||||||
contradiction
|
|
||||||
apply h
|
|
||||||
assumption
|
|
||||||
|
|
||||||
DisabledTactic rw
|
|
||||||
DisabledLemma not_not
|
|
||||||
LemmaTab "Logic"
|
|
||||||
|
|
||||||
Conclusion ""
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Std.Tactic.RCases
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
import Adam.Levels.Predicate.L06_Exists
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Kontraposition"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Benedictus**: Gut, hier ist die angekündigte Frage. Versucht mal einen *direkten* Beweis, ohne `by_contra`.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Ein Beweis durch Kontraposition benützt im Grunde das eben bewiesene Lemma
|
|
||||||
|
|
||||||
-- ```
|
|
||||||
-- lemma not_imp_not (A B : Prop) : (A → B) ↔ (¬ B → ¬ A) := by
|
|
||||||
-- [...]
|
|
||||||
-- ```
|
|
||||||
|
|
||||||
-- Dazu gibt es die Taktik `contrapose`, welche eine Implikation im Goal
|
|
||||||
-- entsprechend umdreht.
|
|
||||||
|
|
||||||
-- Wir erinnern hier an die Taktik `revert h`, die aus der Annahme `h` eine Implikation
|
|
||||||
-- im Goal erstellt.
|
|
||||||
|
|
||||||
-- Im Gegensatz dazu kann man auch einen Beweis durch Kontraposition führen.
|
|
||||||
-- Das ist kein Widerspruch, sondern benützt dass `A → B` und `(¬ B) → (¬ A)`
|
|
||||||
-- logisch equivalent sind.
|
|
||||||
|
|
||||||
-- Wenn das Goal eine Implikation ist, kann man `contrapose` anwenden.
|
|
||||||
open Nat
|
|
||||||
|
|
||||||
Statement (n : ℕ) (h : Odd (n ^ 2)): Odd n := by
|
|
||||||
Hint "**Robo**: Ich schlage vor, wir führen das auf das Lemma `even_square` zurück, das wir auf Quantus schon gezeigt hatten. Hier steht ja im Grunde `Odd (n^2) → Odd n`. Und unter Kontraposition ist das äquivalent zu `Even n → Even (n^2)`.
|
|
||||||
|
|
||||||
**Du**: Richtig. Von hinten durch die Brust … Aber warte, im Moment steht da doch gar kein `→`.
|
|
||||||
|
|
||||||
**Robo**: Erinner dich an `revert`. Mit `revert {h}` kannst du die Annahme `{h}` als Implikationsannahme ins Beweissziel schieben."
|
|
||||||
revert h
|
|
||||||
Hint "**Du**: Und jetzt kann ich dieses Kontrapositionslemma anwenden? Wie hieß das noch einmal?
|
|
||||||
|
|
||||||
**Robo**: Tatsächlich kannst auch einfach `contrapose` schreiben.
|
|
||||||
"
|
|
||||||
contrapose
|
|
||||||
Hint (hidden := true) "**Robo**: Vielleicht hilft jetzt `even_iff_not_odd` weiter?"
|
|
||||||
rw [← even_iff_not_odd]
|
|
||||||
rw [← even_iff_not_odd]
|
|
||||||
Hint "**Du**: Das sieht schon ganz gut aus. Jetzt kann ich tatsächlich das alte Lemma
|
|
||||||
`even_square` anwenden!"
|
|
||||||
apply even_square
|
|
||||||
|
|
||||||
NewTactic contrapose
|
|
||||||
DisabledTactic by_contra
|
|
||||||
LemmaTab "Nat"
|
|
||||||
|
|
||||||
Conclusion "**Benedictus**: Hervorragend! Ich glaube, damit seid Ihr jetzt ganz gut gewappnet."
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
import Adam.Levels.Predicate.L06_Exists
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Contradiction"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Contradiction"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Du**: Aber hätten wir die letzte Aufgabe nicht genauso gut per Widerspruch beweisen können?
|
|
||||||
|
|
||||||
**Benedictus**: Klar. Ich dachte nur, ein zweiter Widerspruchsbeweis wäre langweilig. Aber Ihr könnt die Aufgabe gern noch einmal probieren. Hier, ich gebe Sie Euch mit auf die Reise. Aber nun seht zu, dass Ihr weiterkommt!"
|
|
||||||
|
|
||||||
-- Statt mit `contrapose` `by_contra` ein Widerspruchsbeweis.
|
|
||||||
-- Probiers doch einfach!
|
|
||||||
-- In diesem Kapitel hast du also folgende Taktiken kennengelernt:
|
|
||||||
|
|
||||||
|
|
||||||
-- Als Vergleich zwischen Beweisen \"per Widerspruch\"
|
|
||||||
-- und \"per Kontraposition\", beweise die Gleiche Aufgabe indem
|
|
||||||
-- du mit `by_contra` einen Widerspruch suchst.
|
|
||||||
|
|
||||||
open Nat
|
|
||||||
|
|
||||||
Statement (n : ℕ) (h : Odd (n ^ 2)) : Odd n := by
|
|
||||||
Hint "Sobald Ihr Euch sicher vom Gravitationsfeld des Asteroiden befreit habt, beugt Ihr Euch wieder über die Aufgabe.
|
|
||||||
|
|
||||||
**Robo**: Ok, also diesmal fangen wir mit `by_contra g` an!"
|
|
||||||
by_contra g
|
|
||||||
Hint "**Robo**: Jetzt würde ich einen Widerspruch zu `Odd (n ^ 2)` führen."
|
|
||||||
Hint (hidden := true) "**Robo**: Also `suffices g : ¬ Odd (n ^ 2)`."
|
|
||||||
suffices d : ¬ Odd (n ^ 2)
|
|
||||||
contradiction
|
|
||||||
rw [←even_iff_not_odd] at *
|
|
||||||
apply even_square
|
|
||||||
assumption
|
|
||||||
|
|
||||||
DisabledTactic contrapose revert
|
|
||||||
|
|
||||||
Conclusion "**Robo**: Bravo! Hier ein Überblick, was uns Benediktus gezeigt hat.
|
|
||||||
|
|
||||||
|
|
||||||
| | Taktik | Beispiel |
|
|
||||||
|:------|:----------------|:-------------------------------------------------------|
|
|
||||||
| 17 | `have` | Zwischenresultat annehmen |
|
|
||||||
| 18 | `suffices` | Zwischenresultat annehmen |
|
|
||||||
| 19 | `by_contra` | Widerspruch *(startet einen Widerspruchsbeweis)* |
|
|
||||||
| *3* | `contradiction` | *(schliesst einen Widerspruchsbeweis)* |
|
|
||||||
| 20 | `contrapose` | Kontraposition |
|
|
||||||
| *9* | `revert` | nützlich, um danach `contrapose` anzuwenden |
|
|
||||||
"
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import Adam.Levels.Function.L01_Function
|
|
||||||
import Adam.Levels.Function.L02_Let
|
|
||||||
import Adam.Levels.Function.L03_Piecewise
|
|
||||||
import Adam.Levels.Function.L04_Injective
|
|
||||||
import Adam.Levels.Function.L05_Injective
|
|
||||||
import Adam.Levels.Function.L06_Injective
|
|
||||||
import Adam.Levels.Function.L07_Surjective
|
|
||||||
import Adam.Levels.Function.L08_Bijective
|
|
||||||
import Adam.Levels.Function.L09_Inverse
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Title "Abbildungen"
|
|
||||||
|
|
||||||
Introduction "
|
|
||||||
Auf der Suche nach dem Buch der Urbilder landet ihr auf einem kleinen Mond, der bis auf
|
|
||||||
eine Insel komplett mit Wasser bedeckt zu sein scheint.
|
|
||||||
|
|
||||||
Auf der Insel seht ihr verschiedene große und kleine Behausungen, manche aus Stroh und Holz,
|
|
||||||
vereinzelte aus Lehm.
|
|
||||||
|
|
||||||
Planlos geht ihr zum ersten Haus bei dem jemand vorne außen sitzt.
|
|
||||||
"
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Anonyme Funktionen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Auf die Frage hin, ob sie von einem Bibliothek wisse, erzählt euch das kleine Mädchen,
|
|
||||||
dass es auf der Insel nur einen gäbe, aber sie bedrängt euch so mit einer Frage,
|
|
||||||
dass sie euch gar nicht sagt, wo dieser zu finden sei.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement "" : ∃ f : ℤ → ℤ, ∀ x, f x < x := by
|
|
||||||
Hint
|
|
||||||
"
|
|
||||||
**Robo**: `f : ℤ → ℤ` ist die Notation für eine Funktion und `f x` ist diese Funktion
|
|
||||||
angewendet auf ein Element `(x : ℤ)`.
|
|
||||||
|
|
||||||
**Du**: War `→` nicht eben noch eine Implikation?
|
|
||||||
|
|
||||||
**Robo**: Doch, die brauchen das gleiche Zeichen für beides.
|
|
||||||
|
|
||||||
**Du**: Dann ist `f : ℤ → ℤ` also einfach abstrakt irgendeine Funktion,
|
|
||||||
wie definier ich aber jetzt konkret eine Abbildungsvorschrift?
|
|
||||||
|
|
||||||
**Robo**: Man kennt hier eine Notation für eine anonyme Funktion:
|
|
||||||
`fun (x : ℤ) ↦ x ^ 2` ist
|
|
||||||
|
|
||||||
$$
|
|
||||||
\\begin\{aligned}
|
|
||||||
f : \\mathbb\{ℤ} &\\to \\mathbb\{ℤ} \\\\
|
|
||||||
x &\\mapsto x ^ 2
|
|
||||||
\\end\{aligned}
|
|
||||||
$$
|
|
||||||
|
|
||||||
**Robo**: PS, `↦` ist `\\mapsto`. Aber man kann auch stattdessen `=>` benützen.
|
|
||||||
"
|
|
||||||
Hint (hidden := true)
|
|
||||||
"
|
|
||||||
**Du**: Ja aber was mach ich damit?
|
|
||||||
|
|
||||||
**Robo**: Wie immer gehst du ein `∃` mit `use …` an.
|
|
||||||
"
|
|
||||||
use (fun x ↦ x - 1)
|
|
||||||
Hint (hidden := true) "**Du**: Zu was sich das wohl vereinfacht?"
|
|
||||||
Branch
|
|
||||||
intro x
|
|
||||||
Hint (hidden := true) "**Du**: Zu was sich das wohl vereinfacht?"
|
|
||||||
simp only [sub_lt_self_iff, forall_const]
|
|
||||||
|
|
||||||
NewDefinition Symbol.function
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion "Das Mädchen wird kurz ruhig, dann beginnt es zu lächeln und zeigt strahlend
|
|
||||||
in eine Richtung. Ihr folgt ihrem Finger und euch fällt in weiter ferne eine pompöse Struktur
|
|
||||||
auf einem flachen Hügel auf.
|
|
||||||
"
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "let"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Ihr macht euch auf Richtung Bibliothek entlang kleiner Pfade zwischen verschiedenster Behausungen.
|
|
||||||
|
|
||||||
**Du**: Sag mal, ich weiss jetzt dass ich eine Funktion als `fun x ↦ x - 1` definieren kann,
|
|
||||||
aber wie kann ich der einen Namen geben?
|
|
||||||
|
|
||||||
**Robo**: Wenn jemand hier eine Funktion definiert, werden die dir
|
|
||||||
`def f (x : ℤ) : ℤ := x - 1` oder `def f : ℤ → ℤ := (fun x ↦ x - 1)` geben.
|
|
||||||
|
|
||||||
**Du**: Und das bedeutet beides das gleiche?
|
|
||||||
|
|
||||||
**Robo**: Praktisch, ja. Aber! Wenn du eine Funktion in einer Aufgabe benennen willst,
|
|
||||||
schreibst du `let f := fun (x : ℤ) ↦ x - 1`!
|
|
||||||
|
|
||||||
**Du**: Und was ist der Unterschied?
|
|
||||||
|
|
||||||
**Robo**: Deines mit `let` ist für innerhalb von einem Beweis, das andere mit `def`
|
|
||||||
ist für ausserhalb von einem Beweis. Hier, ich geb dir mal eine Aufgabe:
|
|
||||||
|
|
||||||
```
|
|
||||||
def f (x : ℤ) : ℤ := (x + 4)
|
|
||||||
```
|
|
||||||
und:
|
|
||||||
"
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
def f (x : ℤ) : ℤ := (x + 4)
|
|
||||||
|
|
||||||
Statement "" (x : ℤ) : ∃ (g : ℤ → ℤ), (g ∘ f) x = x + 1 := by
|
|
||||||
Hint
|
|
||||||
"**Du**: Ist `g ∘ f` Komposition von Funktionen?
|
|
||||||
|
|
||||||
**Robo**: Richtig! Das schreibt man mit `\\comp`.
|
|
||||||
|
|
||||||
**Du** Und hier könnte ich also zuerst
|
|
||||||
`let g := fun (x : ℤ) ↦ _` definieren, anstatt direkt
|
|
||||||
`use fun (x : ℤ) ↦ _`?
|
|
||||||
|
|
||||||
**Robo**: Genau! Das ist zwar praktisch das gleiche, aber kann manchmal nützlich sein."
|
|
||||||
Branch
|
|
||||||
use fun (x : ℤ) ↦ x - 3
|
|
||||||
Hint "**Robo**: `((fun (x : ℤ) ↦ x - 3) ∘ f) x` ist per Definition `(fun (x : ℤ) ↦ x - 3) (f x)`, aber mit
|
|
||||||
`rw [comp_apply]` kann man das explizit umschreiben, aber `simp` kennt das
|
|
||||||
Lemma auch."
|
|
||||||
let g := fun (x : ℤ) ↦ x - 3
|
|
||||||
Hint "**Robo**: gute Wahl! Jetzt kannst du diese mit `use g` benützen."
|
|
||||||
use g
|
|
||||||
Hint "**Robo**: `({g} ∘ f) x` ist per Definition `{g} (f x)`, aber mit
|
|
||||||
`rw [comp_apply]` kann man das explizit umschreiben, aber `simp` kennt das
|
|
||||||
Lemma auch."
|
|
||||||
simp
|
|
||||||
Hint "**Robo**: Wie schon gehabt hat `ring` Schwierigkeiten, Definitionen zu öffnen.
|
|
||||||
Du kannst mit `unfold f` oder `rw [f]` nachhelfen."
|
|
||||||
unfold f
|
|
||||||
ring
|
|
||||||
|
|
||||||
NewTactic «let»
|
|
||||||
NewLemma Function.comp_apply
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion "**Du**: Dann verstehst du etwas Mathe?
|
|
||||||
|
|
||||||
**Robo**: Ich hatte ja keine Ahnung ob die generierte Aufgabe beweisbar ist… aber offenbar
|
|
||||||
hatte ich Glück.
|
|
||||||
|
|
||||||
Und damit erreicht ihr den Hügel mit der Bibliothek."
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Komposition"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Endlich kommt ihr zur Bibliothek. Komischerweise stehen an der Tür
|
|
||||||
zwei Wächtern. Der eine zeigt euch ein Blatt mit
|
|
||||||
|
|
||||||
```
|
|
||||||
def f : ℚ → ℚ := fun x ↦ 5 * x
|
|
||||||
```
|
|
||||||
|
|
||||||
der andere eines mit
|
|
||||||
|
|
||||||
```
|
|
||||||
def g : ℚ → ℚ := fun x ↦ if 0 ≤ x then 2*x else 0
|
|
||||||
```
|
|
||||||
|
|
||||||
und gibt dir ein Blatt mit einer einzelnen Zeile am oberen Ende.
|
|
||||||
"
|
|
||||||
|
|
||||||
open Set Function
|
|
||||||
|
|
||||||
namespace LevelFunction4
|
|
||||||
|
|
||||||
def f : ℚ → ℚ := fun x ↦ 5 * x
|
|
||||||
def g : ℚ → ℚ := fun x ↦ if 0 ≤ x then 2*x else 0
|
|
||||||
|
|
||||||
Statement ""
|
|
||||||
: f ∘ g = g ∘ f := by
|
|
||||||
Hint "
|
|
||||||
**Robo**: Schau mal, die beiden haben zwei Funktionen, eine davon mit stückweiser Definition.
|
|
||||||
|
|
||||||
**Du**: Und ich soll zeigen, dass die beiden vertauschbar sind?
|
|
||||||
|
|
||||||
**Robo**: Genau, am besten wählst du mit `funext x` ein beliebiges Element aus, und zeigst das
|
|
||||||
dann für dieses.
|
|
||||||
"
|
|
||||||
funext x
|
|
||||||
Hint "
|
|
||||||
**Du**: Ah und jetzt kann ich erst einmal `(g ∘ f) {x}` zu `g (f {x})` umschreiben?
|
|
||||||
|
|
||||||
**Robo**: Mit `simp` klappt das.
|
|
||||||
"
|
|
||||||
simp
|
|
||||||
Hint "**Robo**: Jetzt würde ich einmal mit `unfold g` die Definition von `g` öffnen."
|
|
||||||
unfold g
|
|
||||||
Hint "**Robo**: Jetzt kannst du nämlich eine Fallunterscheidung
|
|
||||||
machen, `by_cases h : 0 ≤ {x}`.
|
|
||||||
|
|
||||||
**Du**: Damit krieg ich die Fälle `0 ≤ {x}` und `{x} < 0`?
|
|
||||||
|
|
||||||
**Robo**: Genau! Oder präziser `0 ≤ {x}` und `¬(0 ≤ {x})`. Das ist nicht ganz das gleiche, und man
|
|
||||||
könnte mit dem Lemma `not_le` zwischen `¬(0 ≤ {x})` und `0 < {x}` wechseln."
|
|
||||||
by_cases h : 0 ≤ x
|
|
||||||
· Hint "**Robo**: Um das ausrechnen zu können, brauchst du nicht nur `0 ≤ x` sondern auch noch
|
|
||||||
eine neue Annahme `0 ≤ f x`.
|
|
||||||
|
|
||||||
**Du**: Also `have h₂ : _`?"
|
|
||||||
have h' : 0 ≤ f x
|
|
||||||
· unfold f
|
|
||||||
linarith
|
|
||||||
rw [if_pos h]
|
|
||||||
rw [if_pos h']
|
|
||||||
unfold f
|
|
||||||
ring
|
|
||||||
· have h' : ¬ (0 ≤ f x)
|
|
||||||
unfold f
|
|
||||||
linarith
|
|
||||||
rw [if_neg h]
|
|
||||||
rw [if_neg h']
|
|
||||||
unfold f
|
|
||||||
ring
|
|
||||||
|
|
||||||
NewTactic funext by_cases simp_rw linarith
|
|
||||||
|
|
||||||
NewLemma not_le if_pos if_neg
|
|
||||||
LemmaTab "Logic"
|
|
||||||
|
|
||||||
-- -- TODO : This does not trigger.
|
|
||||||
-- -- TODO: These 5 hints should be mutually exclusive. i.e. they should not trigger
|
|
||||||
-- -- if a assumption is missing.
|
|
||||||
-- Hint (x : ℚ) : (f ∘ g) x = (g ∘ f) x => ""
|
|
||||||
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ x) : f (g x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ x) (h₂ : 0 ≤ f x) : f (g x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
-- **Du**: Mit den beiden Annahmen sagt die Definition von `g` ja z.B.
|
|
||||||
-- `(if 0 ≤ x then _)` wobei ich weiss dass `0 ≤ x` wahr ist,
|
|
||||||
-- kann ich das dann einfach vereinfachen?
|
|
||||||
|
|
||||||
-- **Robo**: Dafür must du zuerst die Definition von `g` öffnen, also `unfold`. Und dann mit
|
|
||||||
-- dem Lemma `if_pos {h}` das umschreiben.
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : ¬ 0 ≤ x) : f (g x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
-- **Du**: Ich sehe, das ist jetzt der zweite Fall, da brauch ich sicher wieder eine zweite Annahme
|
|
||||||
-- `¬(0 ≤ f x)`…
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : ¬ 0 ≤ x) (h₂ : ¬ 0 ≤ f x) : f (g x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
-- **Robo**: Jetzt ist der Zeitpunkt wo die Definition von `g` geöffnet sein sollte.
|
|
||||||
|
|
||||||
-- **Robo**: Wenn man ein If-Statement mit wahrer Prämisse mit `if_pos` vereinfacht, dann
|
|
||||||
-- braucht man für eine falsche Prämisse…
|
|
||||||
|
|
||||||
-- **Du**: `if_neg`?
|
|
||||||
-- "
|
|
||||||
-- -- END TODO
|
|
||||||
-- HiddenHint (x : ℚ) (h : 0 ≤ x) (h₂ : 0 ≤ f x) : f (2 * x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
-- **Robo**: Jetzt das Gleiche noch mit `if_pos {h₂}`.
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- HiddenHint (x : ℚ) (h : 0 ≤ x) (h₂ : 0 ≤ f x) : f (g x) = 2 * f x =>
|
|
||||||
-- "
|
|
||||||
-- **Robo**: Jetzt das Gleiche noch mit `if_pos {h}`.
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ x) (h₂ : 0 ≤ f x) : f (2 * x) = 2 * f x =>
|
|
||||||
-- "
|
|
||||||
-- **Robo**: Wenn du jetzt noch die Definition von `f` öffnest, dann kann `ring` den
|
|
||||||
-- Rest ausrechnen.
|
|
||||||
-- "
|
|
||||||
|
|
||||||
|
|
||||||
-- -- TODO: This are also showing in the case of the Hint below
|
|
||||||
-- -- Proof of `0 ≤ f x`.
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ x) : 0 ≤ f x =>
|
|
||||||
-- " **Robo**: Wenn du die Definition von `f` öffnest, dann hast du schon das wissen,
|
|
||||||
-- um das zu beweisen."
|
|
||||||
-- HiddenHint (x : ℚ) (h : 0 ≤ x) : 0 ≤ f x =>
|
|
||||||
-- "**Du** *(in Gedanken)*: Was war das nochmals... Ungleichungen... `linarith`!"
|
|
||||||
|
|
||||||
-- HiddenHint (x : ℚ) (h : ¬0 ≤ x) : ¬ 0 ≤ f x =>
|
|
||||||
-- " **Robo**: Das ist das selbe wie vorhin…"
|
|
||||||
|
|
||||||
|
|
||||||
-- -- Hint for modifying `h` wrongly.
|
|
||||||
-- Hint (x : ℚ) (h : x < 0) : f (g x) = g (f x) =>
|
|
||||||
-- "
|
|
||||||
-- **Robo**: Das war nicht so ideal, hier brauchst du die Annahme in der Form `({h} : ¬ 0 ≤ {x})`!
|
|
||||||
-- "
|
|
||||||
|
|
||||||
-- -- TODO: In this case we get to see the Hints above
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ x) : 0 ≤ x =>
|
|
||||||
-- "**Robo**: Dieses Goal ist entstanden, als du `rw [if_pos]` anstatt `rw [if_pos {h}]`
|
|
||||||
-- geschrieben hast."
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : 0 ≤ f x) : 0 ≤ f x =>
|
|
||||||
-- "**Robo**: Dieses Goal ist entstanden, als du `rw [if_pos]` anstatt `rw [if_pos {h}]`
|
|
||||||
-- geschrieben hast."
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : ¬ 0 ≤ x) : ¬ 0 ≤ x =>
|
|
||||||
-- "**Robo**: Dieses Goal ist entstanden, als du `rw [if_neg]` anstatt `rw [if_neg {h}]`
|
|
||||||
-- geschrieben hast."
|
|
||||||
|
|
||||||
-- Hint (x : ℚ) (h : ¬ 0 ≤ f x) : ¬ 0 ≤ f x =>
|
|
||||||
-- "**Robo**: Dieses Goal ist entstanden, als du `rw [if_neg]` anstatt `rw [if_neg {h}]`
|
|
||||||
-- geschrieben hast."
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Zufrieden tauschen die beiden Wächter ihren Platz und geben so dabei den
|
|
||||||
Durchgang frei."
|
|
||||||
|
|
||||||
end LevelFunction4
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title ""
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Ihr läuft durch verschiedenste Gänge der Bibliothek, allesamt mit Büchern entlang der Wände.
|
|
||||||
|
|
||||||
**Du**: Wenn wir wüssten, dass nur ein möglicher Weg hierhin führt, könnten wir
|
|
||||||
ausschliessen, dass wir im Kreis laufen.
|
|
||||||
|
|
||||||
Plötzlich begegnet ihr einem älteren Wesen mit Fakel. Auf die Frage antwortet es mit
|
|
||||||
"
|
|
||||||
open Set Function
|
|
||||||
|
|
||||||
Statement "" : Injective (fun (n : ℤ) ↦ n + 3) := by
|
|
||||||
Hint "**Robo**: `Injective` ist als `∀ \{a b : U}, f a = f b → a = b`
|
|
||||||
definiert, also kannst du mit `intro` anfangen."
|
|
||||||
intro a b
|
|
||||||
Branch
|
|
||||||
intro h
|
|
||||||
Hint "**Robot**: Jetzt musst du wohl `{h}` vereinfachen."
|
|
||||||
Hint (hidden := true) "**Du**: Kann man das wohl vereinfachen?"
|
|
||||||
simp
|
|
||||||
|
|
||||||
NewDefinition Injective
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion "**Du** Woa das war ja einfach!"
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title ""
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Sofort hackt die ältere Gestalt nach:
|
|
||||||
"
|
|
||||||
open Set Function
|
|
||||||
|
|
||||||
example (f : ℤ → ℤ) (h : StrictMono f) : Injective f := by
|
|
||||||
apply StrictMono.injective
|
|
||||||
assumption
|
|
||||||
|
|
||||||
-- Odd.strictMono_pow
|
|
||||||
|
|
||||||
Statement "" : Injective (fun (n : ℤ) ↦ n^3 + (n + 3)) := by
|
|
||||||
Hint "**Du**: Hmm, das ist etwas schwieriger…
|
|
||||||
|
|
||||||
**Robo**: Aber ich hab einen Trick auf Lager:
|
|
||||||
Das Lemma `StrictMono.injective` sagt, dass jede strikt monotone Funktion injektive ist,
|
|
||||||
und ich habe das Gefühl Monotonie ist hier einfacher zu zeigen."
|
|
||||||
Hint (hidden := true) "**Robo**: `apply` ist wonach du suchst."
|
|
||||||
Branch
|
|
||||||
intro a b
|
|
||||||
Hint "**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!"
|
|
||||||
intro ha
|
|
||||||
Hint "**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!"
|
|
||||||
apply StrictMono.injective
|
|
||||||
Hint "**Du**: Jetzt möchte ich strikte Monotonie von `n ^ 3` und `n + 3` separat zeigen,
|
|
||||||
schliesslich scheint es mir als wär das zweite wieder einfach.
|
|
||||||
|
|
||||||
**Robo**: Dafür hab ich `StrictMono.add` bereit!"
|
|
||||||
apply StrictMono.add
|
|
||||||
Hint "**Du**: Hmm, darauf hab ich jetzt wenig Lust. Gibt's dafür auch was? Das gilt ja nur
|
|
||||||
wenn der Exponent ungerade ist.
|
|
||||||
|
|
||||||
**Robo**: Du könntest mal `Odd.strictMono_pow` versuchen…"
|
|
||||||
apply Odd.strictMono_pow
|
|
||||||
Hint (hidden := true) "**Du**: Ist das nicht ne Trivialität? Warte mal!"
|
|
||||||
trivial
|
|
||||||
Hint "**Du**: Ha! Und dieser Teil funktioniert sicher gleich wie Injektivität vorhin!"
|
|
||||||
intro a b
|
|
||||||
simp
|
|
||||||
|
|
||||||
NewDefinition Injective
|
|
||||||
NewLemma StrictMono.injective StrictMono.add Odd.strictMono_pow
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion "**Du**: Danke vielmals!
|
|
||||||
|
|
||||||
Und damit lässt das Wesen mitten im Gang stehen, wo es weiter über Injektivität nachdenkt."
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Injektive"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Weiterirrend kommt ihr an eine Verzweigung.
|
|
||||||
|
|
||||||
**Robo**: Sieht beides gleich aus.
|
|
||||||
|
|
||||||
Ein paar Schritte in den linken Korridor hinein seht ihr auf dem Boden ein Blatt mit Gekritzel:
|
|
||||||
|
|
||||||
```
|
|
||||||
def f : ℕ → ℕ := fun n ↦ if Even n then n^2 else n+1
|
|
||||||
```
|
|
||||||
|
|
||||||
**Du**: Hier haben wir wieder eine stückweise Funktion
|
|
||||||
|
|
||||||
$$
|
|
||||||
f(n) = \\begin{cases}
|
|
||||||
n^2 & \\text{falls } n \\text{ gerade} \\\\
|
|
||||||
n+1 & \\text{andernfalls.}
|
|
||||||
\\end{cases}
|
|
||||||
$$
|
|
||||||
|
|
||||||
|
|
||||||
Darunter steht in leicht leuchtender Schrift:
|
|
||||||
"
|
|
||||||
|
|
||||||
namespace FunctionLvl7
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
def f : ℕ → ℕ := fun n ↦ if Even n then n^2 else n+1
|
|
||||||
|
|
||||||
Statement "" : ¬ (f + f).Injective := by
|
|
||||||
unfold Injective
|
|
||||||
Hint "**Robo**: Das ist sicher ein Hinweis.
|
|
||||||
|
|
||||||
**Du**: Aber `¬ Injective` sagt mir nichts…
|
|
||||||
|
|
||||||
**Robo**: Könntest du etwas mit `¬ ∀` anfangen? Dann könntest du ja `Injektive` zuerst öffnen.
|
|
||||||
|
|
||||||
**Du**: Darüber haben wir doch mal was gelernt…"
|
|
||||||
Hint (hidden := true) "**Robo**: Das war `push_neg`."
|
|
||||||
push_neg
|
|
||||||
Hint "**Du** Jetzt muss ich einfach ein Gegenbeispiel nennen, oder?
|
|
||||||
|
|
||||||
**Robo** Genau! Welche beiden Zahlen möchtest du denn verwenden?"
|
|
||||||
use 2
|
|
||||||
use 3
|
|
||||||
simp
|
|
||||||
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
Als ihr das Problem gelöst habt, erschleicht euch ein starkes
|
|
||||||
Gefühl, dass dies der falsche Weg ist.
|
|
||||||
Also geht ihr zurück und nehmt die rechte Gabelung.
|
|
||||||
"
|
|
||||||
|
|
||||||
end FunctionLvl7
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 7
|
|
||||||
|
|
||||||
Title "Surjektive"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Endlich kommt ihr in einen große, beleuchteten zentralen Raum.
|
|
||||||
Alle Wände sind voll mit Büchern und
|
|
||||||
in der Mitte sitzt an einem einsamen
|
|
||||||
Tisch ein Gelehrter, der tatsächlich das gesuchte Buch zeigen kann.
|
|
||||||
|
|
||||||
Bevor er dieses aushändigt, will er aber folgendes wissen:
|
|
||||||
"
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
Statement "" : Surjective (fun (n : ℤ) ↦ n + 1) := by
|
|
||||||
Hint "**Robo**: Die Definition von `Surjective f` ist `∀ y, (∃ x, f x = y)`.
|
|
||||||
|
|
||||||
**Du**: Dann kann ich das auch einfach wie Quantifier behandeln?
|
|
||||||
|
|
||||||
**Robo**: Schieß drauf los!"
|
|
||||||
intro y
|
|
||||||
use y-1
|
|
||||||
simp
|
|
||||||
|
|
||||||
NewDefinition Surjective
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Der Gelehrte händigt euch schmunzelnd das Buch aus."
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 8
|
|
||||||
|
|
||||||
Title ""
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Du**: Ehm, und wie kommen wir da wieder raus?
|
|
||||||
|
|
||||||
**Gelehrter**: Gerne zeige ich euch den Weg, nachdem ihr mir auch noch folgendes erklärt:
|
|
||||||
"
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
Statement "" : Bijective (fun (n : ℤ) ↦ n + 1) := by
|
|
||||||
Hint "
|
|
||||||
**Robo** *(flüsternd)*: `Bijectve f` ist als `Injective f ∧ Surjective f` definiert.
|
|
||||||
|
|
||||||
**Du**: Dann ist das ja ganz simpel!"
|
|
||||||
unfold Bijective
|
|
||||||
constructor
|
|
||||||
intro a b
|
|
||||||
simp
|
|
||||||
intro y
|
|
||||||
use y-1
|
|
||||||
simp
|
|
||||||
|
|
||||||
NewDefinition Bijective
|
|
||||||
LemmaTab "Function"
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Zufrieden drückt euch der Gelehrte eine neue Fackel in die Hand und
|
|
||||||
zeigt euch den Weg nach draußen."
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 9
|
|
||||||
|
|
||||||
Title "Inverse"
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Eigentlich hast du nur beiläufig Robo gefragt, ob bijektiv nicht auch bedeute, dass
|
|
||||||
eine Inverse Funktion bestehe. Jetzt steht ihr aber schon seit einer halben Stunde rum
|
|
||||||
und der Gelehrte möchte wissen, wie das den genau ginge.
|
|
||||||
|
|
||||||
Offensichtlich kennt er diese Aussage als `Function.bijective_iff_has_inverse` aus seinen Büchern,
|
|
||||||
aber er möchte, dass du ihm das hier und jetzt nochmals von Grund auf zeigst.
|
|
||||||
"
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
--TODO: This is a really hard proof
|
|
||||||
Statement Function.bijective_iff_has_inverse "" {A B : Type} (f : A → B) :
|
|
||||||
Bijective f ↔ ∃ g, LeftInverse g f ∧ RightInverse g f := by
|
|
||||||
Hint "**Du**: Nah da sagt mir so manches nichts, aber ich kann ja mal mit dem `↔` anfangen,
|
|
||||||
das kenn ich ja schon."
|
|
||||||
constructor
|
|
||||||
· intro h
|
|
||||||
Hint "**Robo**: Tipp. Teil doch `Bijective` mit `rcases {h} with ⟨hI, hS⟩` in
|
|
||||||
`Injective` und `Surjective` auf!"
|
|
||||||
rcases h with ⟨hI, hS⟩
|
|
||||||
Hint "**Du**: Ja was ist eigentlich die Inverse von `f`…?
|
|
||||||
|
|
||||||
**Robo**: Hast du eine Idee?
|
|
||||||
|
|
||||||
**Du**: Also von der Surjektivität weiss ich, dass für alle `y` ein Urbild existiert
|
|
||||||
und mit der Injektivität könnte ich dann zeigen, dass dieses eindeutig ist.
|
|
||||||
|
|
||||||
**Robo**: Also Schritt für Schritt: Mit `fun y ↦ ({hS} y).choose ` kannst du eine Funktion
|
|
||||||
definieren, die `y` irgendein Urbild zuweist.
|
|
||||||
|
|
||||||
**Du**: Die ist aber nicht wohldefiniert, oder?
|
|
||||||
|
|
||||||
**Robo**: In der Mathe nicht. In Lean geht das ganz gut, aber es ist dann unmöglich etwas
|
|
||||||
darüber zu beweisen, wenn es mehrere Möglichkeiten gäbe."
|
|
||||||
use fun x => (hS x).choose
|
|
||||||
constructor
|
|
||||||
· Hint "**Robo**: fang mal mit `intro` an."
|
|
||||||
intro x
|
|
||||||
Hint "**Du**: kompliziert.
|
|
||||||
|
|
||||||
**Robo**: Aber mit `simp` kannst du es ja etwas vereinfachen."
|
|
||||||
simp
|
|
||||||
Hint "**Du**: Das kann ich jetzt nicht zeigen solange ich nicht weiss, dass nur genau ein
|
|
||||||
Urbild besteht.
|
|
||||||
|
|
||||||
**Robo**: Dann wende doch mit `apply {hI}` die Injektivität an!"
|
|
||||||
apply hI
|
|
||||||
Hint "**Robo**: Dies ist jetzt eine etwas tautologische Aussage. In Lean ist das
|
|
||||||
`Exists.choose_spec`. Konkret `apply Exists.choose_spec (hS (f x))`."
|
|
||||||
apply Exists.choose_spec (hS (f x))
|
|
||||||
· Hint "**Robo**: Gut! Auf zum Rechtsinversen! Fang auch hier wieder mit `intro` an."
|
|
||||||
intro x
|
|
||||||
Hint "**Du**: Kann ich das vereinfachen?"
|
|
||||||
simp
|
|
||||||
Hint "**Du**: Also wieder `Exists.choose_spec`?
|
|
||||||
|
|
||||||
**Robo**: Genau! Diesmal mit dem Argument `(hS x)`."
|
|
||||||
apply Exists.choose_spec (hS x)
|
|
||||||
· Hint "**Robo**: Die eine Richtung ist gezeigt. Jetzt auf zur Rückrichtung!"
|
|
||||||
intro h
|
|
||||||
Hint "**Robo**: Zerlege {h} noch soweit du kannst!"
|
|
||||||
rcases h with ⟨g, h⟩
|
|
||||||
Hint "**Robo**: Das UND auch noch!"
|
|
||||||
rcases h with ⟨hL, hR⟩
|
|
||||||
Hint "**Robo**: Das `Bijective` kannst du auch aufteilen."
|
|
||||||
constructor
|
|
||||||
· Hint "**Robo**: Injektivität ist der schwierige Teil. Fang mal an mit `intro`."
|
|
||||||
intro a b hab
|
|
||||||
Hint "**Robo**: Im nächsten Schritt must du `LeftInverse` brauchen um das Goal
|
|
||||||
zu `g (f a) = g (f b)` zu wechseln: benutze `rw [←{hL} {a}, …]`."
|
|
||||||
rw [← hL a, ← hL b]
|
|
||||||
Hint "**Du**: Wenn die Argumente `f a = f b` gleich sind, ist dann auch `g (f a) = g (f b)`,
|
|
||||||
wie sag ich das?
|
|
||||||
|
|
||||||
**Robo**: Das heisst `apply congrArg`."
|
|
||||||
apply congrArg
|
|
||||||
assumption
|
|
||||||
· Hint "Die Surjektivität sollte einfacher sein."
|
|
||||||
intro x
|
|
||||||
Hint (hidden := true) "**Robo**: Psst, mit `RightInverse g f` weisst du, dass `f (g x) = x`.
|
|
||||||
Hilft das rauszufinden was du hier brauchen musst?"
|
|
||||||
use g x
|
|
||||||
Hint (hidden := true) "**Robo**: Du kannst die `RightInverse`-Annahme einfach mit `rw`
|
|
||||||
benützen."
|
|
||||||
rw [hR]
|
|
||||||
|
|
||||||
NewDefinition LeftInverse RightInverse
|
|
||||||
NewLemma Exists.choose Exists.choose_spec congrArg congrFun
|
|
||||||
DisabledLemma Function.bijective_iff_has_inverse
|
|
||||||
LemmaTab "Logic"
|
|
||||||
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Endlich entkommt ihr der Bibliothek.
|
|
||||||
|
|
||||||
**Robo**: Da würden mich keine zehn Pferde nochmals hineinbringen!
|
|
||||||
|
|
||||||
**Du**: Von wegen Pferden, wie viele PS hat eigentlich unser Raumschiff?"
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import Adam.Levels.Implication.L01_Intro
|
|
||||||
import Adam.Levels.Implication.L02_Revert
|
|
||||||
import Adam.Levels.Implication.L03_Apply
|
|
||||||
import Adam.Levels.Implication.L04_Apply
|
|
||||||
import Adam.Levels.Implication.L05_Apply
|
|
||||||
import Adam.Levels.Implication.L06_Iff
|
|
||||||
import Adam.Levels.Implication.L07_Rw
|
|
||||||
import Adam.Levels.Implication.L08_Iff
|
|
||||||
import Adam.Levels.Implication.L09_Iff
|
|
||||||
import Adam.Levels.Implication.L10_Apply
|
|
||||||
import Adam.Levels.Implication.L11_ByCases
|
|
||||||
import Adam.Levels.Implication.L12_Rw
|
|
||||||
import Adam.Levels.Implication.L13_Summary
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Title "Implis"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Zurück im Raumschiff macht ihr euch auf den Weg zu einem der beiden Monde, die ebenfalls
|
|
||||||
bewohnt zu sein scheinen.
|
|
||||||
|
|
||||||
**Du**: Ich habe immer noch das Gefühl, dass ich die Aufgabe von Königin *Logisinde* ohne `tauto` nicht hätte lösen können.
|
|
||||||
Kamen in der Aufgabe nicht auch Implikationen vor?
|
|
||||||
|
|
||||||
**Robo**: Vielleicht haben wir ja auf dem Mond *Implis*, den wir gerade ansteuern, Gelegenheit, noch etwas dazuzulernen. Festhalten bitte …
|
|
||||||
|
|
||||||
Und damit leitet Robo den Landeanflug ein.
|
|
||||||
|
|
||||||
Implis scheint ein riesiger Tagebau zu sein.
|
|
||||||
Überall verlaufen Förderbänder, kreuz und quer, aber die meisten stehen still.
|
|
||||||
Ein schüchterner Operationsleiter erwartet Euch bereits.
|
|
||||||
|
|
||||||
**Operationsleiter**: Ihr kommt mir gerade recht! Ich habe schon gehört. Echte Mathematiker! Wisst Ihr, wir fördern hier Wahrheitswerte. Und dabei muss man höllisch aufpassen. Ein Fehler, und alles bricht zusammen. Aber ich bin sehr vorsichtig. Ich sage immer: Lieber Stillstand als Untergang!
|
|
||||||
|
|
||||||
"
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Intro"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Hier, zum Beispiel:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B : Prop) (hb : B) : A → (A ∧ B) := by
|
|
||||||
Hint "
|
|
||||||
**Operationsleiter:** Die Arbeiten meinen, das wäre so richtig und wir würden das dringend brauchen. Aber keiner kann es mir beweisen.
|
|
||||||
|
|
||||||
**Du**: Einen Moment. Das ist ja gerade so eine Implikation (`\\to`). Wir nehmen an, dass `{B}` gilt, und wollen zeigen, dass dann gilt `{A}` impliziert `{A} und {B}`. Ja, klar! Natürlich stimmt das.
|
|
||||||
|
|
||||||
Der Operationsleiter sieht dich erwartungsvoll an.
|
|
||||||
|
|
||||||
**Du** *(leise zu Robo)*: Soll ich ihm `tauto` aufschreiben?
|
|
||||||
|
|
||||||
**Robo** *(leise zurück)*: So wie der aussieht, fürchte ich, das wird er auch nicht verstehen.
|
|
||||||
Schreib den Beweis lieber aus.
|
|
||||||
|
|
||||||
**Du**: Aber wie denn? Ich glaube, ich würde als erstes gern so etwas sagen wie 'Nehmen wir also an, `{A}` gilt …'
|
|
||||||
|
|
||||||
**Robo**: Ja, gute Idee. Wähle dazu für deine Annahme einfach einen Namen, zum Beispiel `h`, und schreib `intro h`."
|
|
||||||
intro hA
|
|
||||||
Hint "**Du**: OK. Jetzt habe ich also sowohl `{A}` als auch `{B}` in meinen Annahmen und muss `{A} ∧ {B}` zeigen.
|
|
||||||
|
|
||||||
**Robo**: Genau. Und wie das geht, weißt du ja schon."
|
|
||||||
constructor
|
|
||||||
assumption
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "**Operationsleiter:** Perfekt! Danke schön!
|
|
||||||
|
|
||||||
Er geht zu einer Schalttafel und ein paar Knöpfe. Irgendwo setzt sich lautstark ein Förderband in Bewegung.
|
|
||||||
|
|
||||||
**Operationsleiter:** Habt Ihr vielleicht noch ein paar Minuten?
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic intro
|
|
||||||
DisabledTactic tauto
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Revert"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"Der Operationsleiter holt aus einem Container einen Stapel Papier hervor.
|
|
||||||
|
|
||||||
**Operationsleiter:** Hier hat sich echt einiges angesammelt. Wäre echt super, wenn Ihr mir noch ein bisschen helfen könntet.
|
|
||||||
|
|
||||||
Er übergibt Euch das oberste Blatt."
|
|
||||||
|
|
||||||
Statement (A B : Prop) (ha : A) (h : A → B) : B := by
|
|
||||||
Hint "**Operationsleiter:** Das ist von einem Kollegen.
|
|
||||||
|
|
||||||
**Robo**: Oh, das hab ich schon einmal irgendwo gelesen. Warte mal … Richtig! Das war damals, als ich Wikipedia gecrawlt habe: `Der Modus ponens ist eine schon in der antiken Logik geläufige Schlussfigur, die in vielen logischen …`
|
|
||||||
|
|
||||||
**Du**: Robo! Gefragt ist ein Beweis und kein historischer Aufsatz! Oder komme ich hier etwa mit `mopo` oder so etwas weiter?
|
|
||||||
|
|
||||||
**Robo**: Ok, nein, sorry. `mopo` gibt es nicht. Probier lieber `revert {ha}`."
|
|
||||||
revert ha
|
|
||||||
Hint "**Du**: Aha. `revert` ist qausi `intro` rückwärts.
|
|
||||||
|
|
||||||
**Robo:** Genau. `intro` nimmt die Prämisse aus einer Implikation `{A} \\to {B}` im Beweisziel und macht daraus eine Annahme. `revert` nimmt umgekehrt eine Annahme und setzt sie als Implikationsprämisse vor das Beweisziel. Aber nun mach schon fertig."
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "Der Operationsleiter nimmt erfreut Eure Lösung entgegen, und greift zum Telefon."
|
|
||||||
|
|
||||||
NewTactic revert
|
|
||||||
DisabledTactic tauto
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Apply"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Leider läuft das Telefonat nicht so gut. Er legt wieder auf und schüttelt mit dem Kopf.
|
|
||||||
|
|
||||||
**Operationsleiter**: Der Kollege auf der anderen Seite des Mondes versteht kein `revert`. Oder er tut zumindest so. Habt Ihr noch eine andere Idee?
|
|
||||||
|
|
||||||
Er zieht eine Linie unter Euren Beweis, ergänzt ein durchgestrichenes ~`revert`~, und legt Euch das Blatt ein zweites Mal vor.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B : Prop) (hA : A) (h : A → B) : B := by
|
|
||||||
Hint "**Robo**: Vielleicht wäre es ohnehin eleganter gewesen, mit Implikation mit `apply {h}` anzuwenden."
|
|
||||||
apply h
|
|
||||||
Hint "**Du**: Ja, das kommt mir jetzt auch natürlich vor."
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "Diesmal scheint das Telefont erfolgreich zu verlaufen."
|
|
||||||
|
|
||||||
NewTactic apply
|
|
||||||
DisabledTactic revert tauto
|
|
||||||
|
|
||||||
-- Katex notes
|
|
||||||
-- `\\( \\)` or `$ $` for inline
|
|
||||||
-- and `$$ $$` block.
|
|
||||||
-- align block:
|
|
||||||
-- $$\\begin{aligned} 2x - 4 &= 6 \\\\ 2x &= 10 \\\\ x &= 5 \\end{aligned}$$
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Implikation"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Das hier ist jetzt weider ein lokales Problem.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B C : Prop) (f : A → B) (g : B → C) : A → C := by
|
|
||||||
Hint "**Du**: Ich soll Implikationen $A \\Rightarrow B \\Rightarrow C$ zu $A \\Rightarrow C$
|
|
||||||
kombinieren?
|
|
||||||
|
|
||||||
**Robo**: Am besten fängst du mit `intro` an und arbeitest dich dann rückwärts durch."
|
|
||||||
intro hA
|
|
||||||
Hint (hidden := true) "**Robo**: Das ist wieder eine Anwendung von `apply`."
|
|
||||||
apply g
|
|
||||||
apply f
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "**Operationsleiter**: Ihr seid echt super!"
|
|
||||||
|
|
||||||
DisabledTactic tauto
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Implikation"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Die nächste Seite sieht ein bisschen komplizierter aus. Damit Ihr nicht die Übersicht verliert, fasst Robo sofort die verschiedenen Implikationen in einem Diagramm zusammen.
|
|
||||||
$$
|
|
||||||
\\begin{CD}
|
|
||||||
A @>{f}>> B @<{g}<< C \\\\
|
|
||||||
@. @V{h}VV @V{m}VV \\\\
|
|
||||||
D @>{i}>> E @>{k}>> F \\\\
|
|
||||||
@A{m}AA @A{n}AA @V{p}VV \\\\
|
|
||||||
G @<{q}<< H @>{r}>> I
|
|
||||||
\\end{CD}
|
|
||||||
$$
|
|
||||||
"
|
|
||||||
Statement
|
|
||||||
(A B C D E F G H I : Prop)
|
|
||||||
(f : A → B) (g : C → B) (h : B → E) (i : D → E) (k : E → F) (m : G → D)
|
|
||||||
(n : H → E) (p : F → I) (q : H → G) (r : H → I) : A → I := by
|
|
||||||
Hint "**Du**: Also ich muss einen Pfad von Implikationen $A \\Rightarrow I$ finden.
|
|
||||||
|
|
||||||
**Robo**: Dann fängst du am besten wieder mit `intro` an."
|
|
||||||
|
|
||||||
intro ha
|
|
||||||
Branch
|
|
||||||
apply r
|
|
||||||
Hint "**Robo**: Das sieht nach einer Sackgasse aus …"
|
|
||||||
Hint (hidden := true) "**Robo**: Na wieder `apply`, was sonst."
|
|
||||||
apply p
|
|
||||||
apply k
|
|
||||||
apply h
|
|
||||||
Branch
|
|
||||||
apply g
|
|
||||||
Hint "**Robo**: Nah, da stimmt doch was nicht …"
|
|
||||||
apply f
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"Der Operationsleiter bedankt sich wieder artig. Er drückt wieder auf ein paar Knöpfe, und mit einem lauten Ratteln springen mehrere Förderbänder gleichzeitig wieder an."
|
|
||||||
|
|
||||||
DisabledTactic tauto
|
|
||||||
|
|
||||||
-- https://www.jmilne.org/not/Mamscd.pdf
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Genau dann, wenn"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter:** Wir hatten auch mal ein paar Förderbänder, die in beide Richtungen laufen konnten. Die hatte ich vorsichtshalber alle abgestellt, weil in den neusten Handbüchern von solchen Doppelbändern abgeraten wird. Aber vielleicht sind sie ja unter bestimmten Voraussetzungen doch sicher? Was meint Ihr zu diesem Fall?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B : Prop) (mp : A → B) (mpr : B → A) : A ↔ B := by
|
|
||||||
Hint "**Robo**: `→` ist natürlich Leansch für `$\\iff$`.
|
|
||||||
Die Aussage `A ↔ B` besteht also aus zwei Teilen; sie ist als `⟨A → B, B → A⟩` definiert.
|
|
||||||
|
|
||||||
**Du**: Also ganz ähnlich wie das UND, `A ∧ B`?
|
|
||||||
|
|
||||||
**Robo**: Genau. Entsprechend kannst du auch hier mit `constructor` anfangen."
|
|
||||||
constructor
|
|
||||||
Hint "**Du**: Ah, und die beiden Teile habe ich schon in den Annahmen."
|
|
||||||
assumption
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Ok, das leuchtet mir ein.
|
|
||||||
|
|
||||||
**Robo** *(zu dir)*: Übrigens, so wie bei `(h : A ∧ B)` die beiden Teile `h.left` und `h.right` heißen,
|
|
||||||
heißen bei `(h : A ↔ B)` die beiden Teile `h.mp` und `h.mpr`.
|
|
||||||
|
|
||||||
**Du**: Also `h.mp` ist `A → B`? Wieso `mp`?
|
|
||||||
|
|
||||||
**Robo**: `mp` steht für Modus Ponens`. Der Modus ponens ist eine schon in der antiken Logik geläufige Schlussfigur, die in vielen logischen Systemen … Ach nee, das wolltest du ja nicht hören. Das \"r\" in `mpr` steht für \"reverse\", weil's die Rückrichtung ist.
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic constructor
|
|
||||||
DisabledTactic tauto rw
|
|
||||||
|
|
||||||
-- TODO : `case mpr =>` ist mathematisch noch sinnvoll.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Init.Data.ToString
|
|
||||||
-- #check List UInt8
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 7
|
|
||||||
|
|
||||||
Title "Genau dann, wenn"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Hier ist noch so etwas.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B C D : Prop) (h₁ : C ↔ D) (h₂ : A ↔ B) (h₃ : A ↔ D) : B ↔ C := by
|
|
||||||
Hint "**Du**: $B \\iff A \\iff D \\iff C$, die sind doch alle äquivalent…
|
|
||||||
|
|
||||||
**Robo**: Ja, aber du musst ihm helfen, die Äquivalenzen umzuschreiben. Mit `rw [h₁]` kannst du `C` durch `D`
|
|
||||||
ersetzen."
|
|
||||||
rw [h₁]
|
|
||||||
Hint "**Du** Und wenn ich in die andere Richtung umschreiben möchte?
|
|
||||||
|
|
||||||
**Robo**: Dann schreibst du ein `←` (`\\l`, also klein \"L\") vor den Namen, also `rw [← hₓ]`."
|
|
||||||
Branch
|
|
||||||
rw [← h₃]
|
|
||||||
Hint "**Du**: Ehm, das war verkehrt.
|
|
||||||
|
|
||||||
**Robo**: Ja, anders herum wär's besser gewesen. Aber wenn du jetzt einfach weitermachst, bis Du
|
|
||||||
sowas wie `A ↔ A` erhältst, kann `rfl` das beweisen.
|
|
||||||
|
|
||||||
**Robo: Da fällt mir ein, `rw` wendet ohnehin auch versuchsweise `rfl` an.
|
|
||||||
Das heißt, du musst `rfl` nicht einmal ausschreiben."
|
|
||||||
rw [h₂]
|
|
||||||
rw [←h₂]
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "**Operationsleiter**: Wenn Ihr so weitermacht, dann kommen wir ja durch den ganzen Packen durch!"
|
|
||||||
|
|
||||||
NewTactic rw assumption
|
|
||||||
DisabledTactic tauto
|
|
||||||
-- NewLemma Iff.symm
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 8
|
|
||||||
|
|
||||||
Title "Genau dann wenn"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Das hier ist wieder für meinen beschränkten Kollegen. Ich glaube, `rw` mag der auch nicht. Geht das trotzdem?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B C : Prop) (h : A ↔ B) (g : B → C) : A → C := by
|
|
||||||
Hint "**Du**: Naja ich kann wohl immerhin mal mit `intro` anfangen und annehmen,
|
|
||||||
dass `{A}` wahr sei …
|
|
||||||
|
|
||||||
**Robo**: … und dann schauen wir weiter!"
|
|
||||||
intro hA
|
|
||||||
Hint "**Robo**: Also eine Implikation wendet man mit `apply` an …
|
|
||||||
|
|
||||||
**Du**: Weiß ich doch!"
|
|
||||||
apply g
|
|
||||||
Hint "**Robo**: … und du kannst die Implikation `{A} → {B}` genau gleich mit
|
|
||||||
`apply {h}.mp` anwenden.
|
|
||||||
|
|
||||||
**Du**: Aber normalerweise könnte ich hier auch `rw [← h]` sagen, oder?
|
|
||||||
|
|
||||||
**Robo**: Ja ja, nur nicht auf der anderen Seite des Mondes.
|
|
||||||
"
|
|
||||||
apply h.mp
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "**Operationsleiter**: Ok, super. Das müsste passen.
|
|
||||||
|
|
||||||
Er telefoniert wieder.
|
|
||||||
|
|
||||||
**Operationsleiter**: Bingo!
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic apply assumption
|
|
||||||
DisabledTactic tauto rw
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Std.Tactic.RCases
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 9
|
|
||||||
|
|
||||||
Title "Genau dann wenn"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Ah, die nächste Seite ist auch von diesem Kollegen. Aber da ist noch eine Notiz bei. Wir hatten hierfür schon einmal einen Beweis, aber den mochte er nicht. Er wollte einen Beweis, der weder `rw` noch `apply` verwendet!!
|
|
||||||
|
|
||||||
Er holt tief Luft und seuft.
|
|
||||||
|
|
||||||
**Operationsleiter**: Ich glaube, der stellt sich immer viel dümmer, als er ist. Aber meint Ihr, Ihr schafft das?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B : Prop) : (A ↔ B) → (A → B) := by
|
|
||||||
Hint "**Du**: Hmm, mindestens mit der Implikation kann ich anfangen."
|
|
||||||
Hint (hidden := true) "**Robo**: Genau, das war `intro`."
|
|
||||||
intro h
|
|
||||||
Hint "**Du**: Also, ich kenne `rw [h]` und `apply h.mp`, aber das wollten wir ja diesmal vermeiden.
|
|
||||||
|
|
||||||
**Robo**: Was du machen könntest, ist, mit `rcases h with ⟨mp, mpr⟩` die Annahme in zwei
|
|
||||||
Teile aufteilen."
|
|
||||||
Branch
|
|
||||||
intro a
|
|
||||||
Hint "**Robo**: Hier müsstest du jetzt `rw [←h]` oder `apply h.mp` benutzen.
|
|
||||||
Geh lieber einen Schritt zurück, sodass das Goal `A → B` ist."
|
|
||||||
rcases h with ⟨mp, mpr⟩
|
|
||||||
Hint (hidden := true) "**Du**: Ah, und jetzt ist das Beweisziel in den Annahmen."
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Perfekt, das sollte reichen!
|
|
||||||
"
|
|
||||||
OnlyTactic intro rcases assumption
|
|
||||||
DisabledTactic rw apply tauto
|
|
||||||
|
|
||||||
-- -- TODO: The new `cases` works differntly. There is also `cases'`
|
|
||||||
-- example (A B : Prop) : (A ↔ B) → (A → B) := by
|
|
||||||
-- intro h
|
|
||||||
-- cases h with
|
|
||||||
-- | intro a b =>
|
|
||||||
-- assumption
|
|
||||||
|
|
||||||
-- example (A B : Prop) : (A ↔ B) → (A → B) := by
|
|
||||||
-- intro h
|
|
||||||
-- cases' h with a b
|
|
||||||
-- assumption
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 10
|
|
||||||
|
|
||||||
Title "Lemmas"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Beim nächsten Problem stutzt der Operationsleiter.
|
|
||||||
|
|
||||||
**Operationsleiter**: Ehrlich gesagt weiß ich gar nicht, wo dieses Blatt herkommt. Das ist gar nicht von mir. Sieht aber irgendwie interessant aus.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A : Prop) : ¬A ∨ A := by
|
|
||||||
Hint "**Du**: Das scheint wieder ziemlich offensichtlich.
|
|
||||||
|
|
||||||
**Robo**: Nee, offensichtlich ist das nicht. Aber ich glaube, es gibt ein wohlbekanntens Lemma, das hier weiterhilft:
|
|
||||||
`not_or_of_imp` besagt `(A → B) → ¬ A ∨ B`. Da die rechte Seite der Implikation mit deinem Beweisziel übereinstimmt,
|
|
||||||
kannst du es mit `apply not_or_of_imp` anwenden.
|
|
||||||
|
|
||||||
**Du**: `Wohlbekannt` auf Implis?
|
|
||||||
|
|
||||||
**Robo**: Werden wir sehen. Probiers aus!"
|
|
||||||
Branch
|
|
||||||
right
|
|
||||||
Hint "**Du**: Und jetzt?
|
|
||||||
|
|
||||||
**Robo**: `right/left` funktioniert hier nicht, da du nicht weißt, ob `A` wahr oder falsch ist."
|
|
||||||
Branch
|
|
||||||
left
|
|
||||||
Hint "**Du**: Und jetzt?
|
|
||||||
|
|
||||||
**Robo**: `right/left` funktioniert hier nicht, da du nicht weißt, ob `A` wahr oder falsch ist."
|
|
||||||
apply not_or_of_imp
|
|
||||||
Hint (hidden := true) "**Robo**: Ich würde wieder mit `intro` weitermachen."
|
|
||||||
intro
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
Der Operationsleiter nickt zustimmend. Offenbar war ihm `not_or_of_imp` tatsächlich bekannt.
|
|
||||||
"
|
|
||||||
|
|
||||||
LemmaTab "Logic"
|
|
||||||
NewLemma not_or_of_imp
|
|
||||||
DisabledTactic tauto
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 11
|
|
||||||
|
|
||||||
Title "by_cases"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Du**: Sag mal, hätten wir nicht auch einfach zwei Fälle anschauen können?
|
|
||||||
Wenn `A` wahr ist, beweisen wir die rechte Seite, sonst die Linke.
|
|
||||||
|
|
||||||
**Robo**: Tatsächlich, `by_cases h : A` würde genau das machen!
|
|
||||||
|
|
||||||
**Du** (zum Operationsleiter): Können wir das Blatt bitte noch einmal haben?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A : Prop) : ¬A ∨ A := by
|
|
||||||
Hint (hidden := true) "**Du**: Wie noch einmal?
|
|
||||||
|
|
||||||
**Robo**: Also `by_cases h : A` erstellt zwei Goals. Im ersten hast du `(h : A)` zur
|
|
||||||
Verfügung, im zweiten `(h : ¬ A)`."
|
|
||||||
by_cases h : A
|
|
||||||
right
|
|
||||||
assumption
|
|
||||||
left
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
**Du**: So gefällt mir der Beweis viel besser!
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic by_cases
|
|
||||||
DisabledTactic tauto
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 12
|
|
||||||
|
|
||||||
Title "Lemmas"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Wieder etwas für den Kollegen …. Und er wollte wieder einen Beweise ohne `apply`. Ich sehe hier auch, dass ich mir schon einmal etwas hierzu notiert hatte. Richtig, es gibt da dieses Lemma:
|
|
||||||
```
|
|
||||||
lemma not_not (A : Prop) : ¬¬A ↔ A
|
|
||||||
```
|
|
||||||
|
|
||||||
**Operationsleiter**: Schafft Ihr das damit?
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (A B C : Prop) : (A ∧ (¬¬C)) ∨ (¬¬B) ∧ C ↔ (A ∧ C) ∨ B ∧ (¬¬C) := by
|
|
||||||
Hint "**Robo**: Ein Lemma, das wie `not_not` ein `↔` oder `=` im Statement hat, kann
|
|
||||||
auch mit `rw [not_not]` verwendet werden."
|
|
||||||
rw [not_not]
|
|
||||||
Hint "**Du**: Häh, wieso hat das jetzt 2 von 3 der `¬¬` umgeschrieben?
|
|
||||||
|
|
||||||
**Robo**: `rw` schreibt nur das erste um, das es findet, also `¬¬C`. Aber weil dieses
|
|
||||||
mehrmals vorkommt, werden die alle ersetzt …
|
|
||||||
|
|
||||||
**Du**: Ah, und `¬¬B` ist etwas anderes, also brauche ich das Lemma nochmals."
|
|
||||||
rw [not_not]
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
**Du**: Wir sind schon fertig …?
|
|
||||||
|
|
||||||
**Robo**: Ja, `rw` versucht immer anschließend `rfl` aufzurufen, und das hat hier funktioniert.
|
|
||||||
"
|
|
||||||
|
|
||||||
DisabledTactic tauto apply
|
|
||||||
NewLemma Classical.not_not
|
|
||||||
LemmaTab "Logic"
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 13
|
|
||||||
|
|
||||||
Title "Zusammenfassung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Operationsleiter**: Ihr habt mir wirklich so geholfen! Hier ist das letzte Problem. Das habe ich von meinem Vorgänger geerbt. Er hat behauptet, wenn wir das lösen können, dann läuft hier wieder alles. Aber es sah mir immer viel zu schwierig aus, um es überhaupt zu versuchen. Wollt Ihr es einmal probieren?
|
|
||||||
|
|
||||||
**Du**: Klar, zeig her! Robo, kannst du mir vielleicht auch noch einmal so eine nette Zusammenfassung anzeigen, was ich theoretisch in den letzten fünf Minuten gelernt habe?
|
|
||||||
|
|
||||||
**Robo**: Hier ist die Übersicht:
|
|
||||||
|
|
||||||
## Notationen / Begriffe
|
|
||||||
|
|
||||||
| | Beschreibung |
|
|
||||||
|:--------------|:---------------------------------------------------------|
|
|
||||||
| → | Eine Implikation. |
|
|
||||||
| ↔ | Genau-dann-wenn / Äquivalenz. |
|
|
||||||
|
|
||||||
## Taktiken
|
|
||||||
|
|
||||||
| | Taktik | Beispiel |
|
|
||||||
|:----|:--------------------------|:-------------------------------------------------------|
|
|
||||||
| 8 | `intro` | Für eine Implikation im Goal. |
|
|
||||||
| 9 | `revert` | Umkehrung von `intro`. |
|
|
||||||
| 10 | `apply` | Wendet eine Implikation auf das Goal an. |
|
|
||||||
| 10ᵇ | `apply` | Wendet ein Lemma an. |
|
|
||||||
| 11 | `by_cases` | Fallunterscheidung `P` und `¬P` |
|
|
||||||
| 12 | `rw` | Umschreiben zweier äquivalenter Aussagen. |
|
|
||||||
| 12ᵇ | `rw` | Benutzt ein Lemma, dessen Aussage eine Äquivalenz ist. |
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement imp_iff_not_or (A B : Prop) : (A → B) ↔ ¬ A ∨ B := by
|
|
||||||
constructor
|
|
||||||
Hint "**Du** *(flüsternd)*: Ist das nicht die Definition von `→`?
|
|
||||||
|
|
||||||
**Robo** *(flüsternd)*: Könnte man so sehen. Aber auf Leansch ist das bloß eine Äquivalenz.
|
|
||||||
So oder so kennst du ja eine Richtung schon als Lemma.
|
|
||||||
Also wende das doch einfach an."
|
|
||||||
apply not_or_of_imp
|
|
||||||
Hint "**Du**: Gibt es für die Gegenrichtung auch ein Lemma?
|
|
||||||
|
|
||||||
**Robo**: Leider nicht. Da musst du manuell ran."
|
|
||||||
Hint (hidden := true) "**Robo**: Na Implikationen gehst du immer mit `intro` an."
|
|
||||||
intro h
|
|
||||||
intro ha
|
|
||||||
Hint (hidden := true) "**Robo**: Ich würde mal die Annahme `h` mit `rcases` aufteilen."
|
|
||||||
rcases h with h | h
|
|
||||||
contradiction
|
|
||||||
assumption
|
|
||||||
|
|
||||||
DisabledTactic tauto
|
|
||||||
|
|
||||||
Conclusion "**Operationsleiter**: Das ist ja fantastisch! Tausend Dank! Dann will ich Euch auch gar nicht länger aufhalten.
|
|
||||||
Ihr wollt bestimmt weiter zu Quantus, unserem Schestermond, oder?
|
|
||||||
|
|
||||||
**Du**: Ehm, vielleicht …
|
|
||||||
|
|
||||||
**Operationsleiter**: Dann habe ich noch eine letzte Bitte. Ich habe hier noch ein Päckchen für die Königin von Quantus! Auch schon von meinem Vorgänger geerbt. Die Post will es nicht annehmen, weil ich die Adresse nicht weiß. Könntet Ihr es vielleicht zu ihr mitnehmen?
|
|
||||||
|
|
||||||
**Du**: Klar! Robo, halt mal.
|
|
||||||
|
|
||||||
Robo nimmt das Päckchen und lässt es irgendwo in seinem Innern verschwinden.
|
|
||||||
Der Operationsleiter sieht ihn entgeistert an.
|
|
||||||
|
|
||||||
**Robo**: Keine Angst, ich verdaue nichts!"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import Adam.Levels.Induction.L01_Induction
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Induction"
|
|
||||||
Title "Übungen Induktions"
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Induction"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Induktion"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Dieses Kapitel enthält noch ein paar Übungen zur Induktion.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Zeige dass $5^n + 7$ durch $4$ teilbar ist."
|
|
||||||
(n : ℕ) : 4 ∣ 5^n + 7 := by
|
|
||||||
induction n
|
|
||||||
simp
|
|
||||||
rcases n_ih
|
|
||||||
rw [Nat.pow_succ, Nat.mul_succ, add_assoc, h, mul_comm, ←mul_add]
|
|
||||||
simp
|
|
||||||
|
|
||||||
--NewLemma Nat.pow_succ, Nat.mul_succ, add_assoc, mul_comm, ←mul_add
|
|
||||||
|
|
||||||
-- example (n : ℕ) : Even (n^2 + n) := by
|
|
||||||
-- induction n
|
|
||||||
-- simp
|
|
||||||
-- rw [Nat.succ_eq_add_one]
|
|
||||||
-- rcases n_ih with ⟨x, h⟩
|
|
||||||
-- use x + n_1 + 1
|
|
||||||
-- ring_nf at *
|
|
||||||
-- rw [←h]
|
|
||||||
-- ring
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import Adam.Levels.Inequality.L01_LE
|
|
||||||
import Adam.Levels.Inequality.L02_Pos
|
|
||||||
import Adam.Levels.Inequality.L03_Linarith
|
|
||||||
import Adam.Levels.Inequality.L04_Linarith
|
|
||||||
import Adam.Levels.Inequality.L05_DrinkersParadox
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Title "Traum"
|
|
||||||
|
|
||||||
Introduction "
|
|
||||||
Später erinnerst du dich gar nicht mehr wo und wann du diese Unterhaltung hattest, geschweige
|
|
||||||
denn mit wem. Vielleicht war es ein Traum, oder eine Erscheinung. Vielleicht war es
|
|
||||||
auch nur eines Abends über einer Runde Getränke.
|
|
||||||
|
|
||||||
Aber auf jedenfall hast du irgendwo gelernt, was du nun weisst.
|
|
||||||
"
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Kleinergleich"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
*(Gespräch)*
|
|
||||||
|
|
||||||
**Robo** (*lallend*, oder war's fröhlich proklamierend?):
|
|
||||||
…und deshalb sind `≥` und `>` eigentlich nur Notationen für `≤`,
|
|
||||||
welches man übrigens `\\le` schreibt, was für Less-Equal (also Kleinergleich) steht…
|
|
||||||
|
|
||||||
**Du**: Wir haben's verstanden, man benützt also Standartmässig lieber `≤` und `<`,
|
|
||||||
aber damit weiß ich eh nichts anzufangen.
|
|
||||||
|
|
||||||
**dritte Person**: Komm schon, das kannst du ja sicher:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
(n m : ℕ) : m < n ↔ m.succ ≤ n := by
|
|
||||||
Hint "**Robo**: Du Narr! Das ist doch eine Kuriosität, dass `m < n` auf `ℕ` per Definition
|
|
||||||
als `m + 1 ≤ n` definiert ist!
|
|
||||||
|
|
||||||
**dritte Person**: Du verdirbst den Witz! Ich wollte ihn doch nur testen."
|
|
||||||
rfl
|
|
||||||
|
|
||||||
OnlyTactic rfl
|
|
||||||
|
|
||||||
Conclusion "**Du**: Ha. ha… Na aber jetzt mal ehrlich, könnt ihr mir ein bisschen mehr
|
|
||||||
erzählen?"
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
open Nat
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Kleinergleich"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**weitere Person**: …ich sag dir, eine positive Zahl kann man sowohl mit `0 < n`
|
|
||||||
als auch `n ≠ 0` darstellen.
|
|
||||||
|
|
||||||
**Robo**: Und da gibts leider keinen Standard dazu.
|
|
||||||
|
|
||||||
**weitere Person**: Ja und, da kann man ja einfach mit `Nat.pos_iff_ne_zero`
|
|
||||||
wechseln. Wart mal, wieso galt das nochmals…
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement Nat.pos_iff_ne_zero (n : ℕ) : 0 < n ↔ n ≠ 0 := by
|
|
||||||
Hint "**Robo** (*flüsternd*): Wenn du ein bisschen schwere Maschinerie auffahren willst,
|
|
||||||
um in zu beeindrucken, hab ich was. Mach doch eine Fallunterscheidung ob `n` Null ist
|
|
||||||
oder nicht!
|
|
||||||
|
|
||||||
**Du** (*flüsternd*): Und wie geht das?
|
|
||||||
|
|
||||||
**Robo** (*laut und selbstsicher*): Wir fangen mit `rcases n` an!"
|
|
||||||
rcases n
|
|
||||||
Hint "**Du**: Hmm, das muss man doch vereinfachen können.
|
|
||||||
|
|
||||||
**Robo** (*flüsternd*): Zweiter pompöser Auftritt: sag einfach `simp` und lass das alles
|
|
||||||
automatisch geschehen."
|
|
||||||
simp
|
|
||||||
Hint "**Du**: Ah und jetzt falls `n ≠ 0`."
|
|
||||||
Branch
|
|
||||||
simp only [ne_eq, succ_ne_zero, not_false_iff, iff_true]
|
|
||||||
Hint "**Robo**: Warte! Den Rest geb ich dir als Lemma: `Nat.suc_pos`."
|
|
||||||
apply Nat.succ_pos
|
|
||||||
Branch
|
|
||||||
simp?
|
|
||||||
constructor
|
|
||||||
intro
|
|
||||||
simp
|
|
||||||
intro
|
|
||||||
Hint "**Robo**: Warte! Den Rest geb ich dir als Lemma: `Nat.suc_pos`."
|
|
||||||
apply Nat.succ_pos
|
|
||||||
|
|
||||||
NewTactic simp
|
|
||||||
NewLemma Nat.succ_pos
|
|
||||||
DisabledLemma Nat.pos_iff_ne_zero Nat.succ_pos'
|
|
||||||
LemmaTab "Nat"
|
|
||||||
|
|
||||||
Conclusion "**Du**: Oh `simp` ist ja echt nicht schlecht…
|
|
||||||
|
|
||||||
Die andere Person scheint beeindruckt, hat aber gleichzeitig auch das Bedürfnis, dich aus
|
|
||||||
der Reserve zu locken."
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Linarith"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**dritte Person**: Nah wenn wir so spielen:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (n : ℕ) (h : 2 ≤ n) : n ≠ 0 := by
|
|
||||||
Hint "**Du**: `simp` geht hier nicht, was mir ja auch einläuchtet.
|
|
||||||
|
|
||||||
**Robo**: Ist auch keine Vereinfachung, die du machen willst. Stattdessen,
|
|
||||||
`linarith` kann lineare Gleichungen und Ungleichungen lösen. Das ist das Powertool
|
|
||||||
in der hinsicht."
|
|
||||||
linarith
|
|
||||||
|
|
||||||
NewTactic linarith
|
|
||||||
NewLemma Nat.pos_iff_ne_zero
|
|
||||||
LemmaTab "Nat"
|
|
||||||
|
|
||||||
Conclusion "**Du**: Naja so beeindruckend war das jetzt auch noch nicht."
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Linarith"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Robo**: Die Taktik kann aber noch viel mehr.
|
|
||||||
|
|
||||||
**weitere Person**: Hier, probier mal!
|
|
||||||
|
|
||||||
$$
|
|
||||||
\\begin{aligned}
|
|
||||||
5 * y &\\le 35 - 2 * x \\\\
|
|
||||||
2 * y &\\le x + 3
|
|
||||||
\\end{aligned}
|
|
||||||
$$
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (x y : ℤ) (h₂ : 5 * y ≤ 35 - 2 * x) (h₃ : 2 * y ≤ x + 3) : y ≤ 5 := by
|
|
||||||
linarith
|
|
||||||
|
|
||||||
Conclusion "**Du**: Boah, das ist schon gar nicht schlecht."
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Drinker's Paradox"
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**weitere Person**: Jetzt aber zu einem anderen Thema. Kennt ihr eigentlich das
|
|
||||||
Drinker-Paradoxon?
|
|
||||||
|
|
||||||
**Robo**: Das ist in meinem System. *In dieser Bar gibt es eine Person, so dass
|
|
||||||
falls diese Person jetzt am drinken ist, dann sind alle am trinken*.
|
|
||||||
|
|
||||||
**weitere Person**: Genau! Könnt ihr mir das beweisen?
|
|
||||||
"
|
|
||||||
|
|
||||||
open Function
|
|
||||||
|
|
||||||
Statement {People : Type} [Inhabited People] (isDrinking : People → Prop) :
|
|
||||||
∃ (x : People), isDrinking x → ∀ (y : People), isDrinking y := by
|
|
||||||
Hint "**Du**: Wenn `p` eine Person ist, dann ist also `isDrinking p` eine Aussage,
|
|
||||||
die wahr oder falsch ist. Soweit so gut.
|
|
||||||
Wieso hat er aber `Inhabited People` hinzugefügt?
|
|
||||||
|
|
||||||
**Robo**: Die Aussage ist falsch, wenn die Bar leer wäre, da dann keine solche
|
|
||||||
Person existieren kann. Jedenfalls kannst du dadurch jederzeit `default`, oder lang
|
|
||||||
`(default : Person)`, schreiben, wenn du einfach irgendeine Person brauchst.
|
|
||||||
|
|
||||||
**Du**: Und wie fang ich jetzt an?
|
|
||||||
|
|
||||||
**Robo**: Du könntest eine Fallunterscheidung machen, ob die Aussage
|
|
||||||
`∀ (y : People), isDrinking y` wahr oder falsch ist."
|
|
||||||
Hint (hidden := true) "**Robo**: Schau mal `by_cases` an."
|
|
||||||
by_cases ∀ y, isDrinking y
|
|
||||||
Hint (hidden := true) "**Du**: Und wen nehm ich jetzt?
|
|
||||||
|
|
||||||
**Robo**: Wie gesagt, `default` ist eine x-beliebige Person."
|
|
||||||
use (default : People)
|
|
||||||
intro
|
|
||||||
assumption
|
|
||||||
Hint (hidden := true) "**Robo**: Du könntest hier mit `push_neg at {h}` weitermachen."
|
|
||||||
push_neg at h
|
|
||||||
rcases h with ⟨p, hp⟩
|
|
||||||
use p
|
|
||||||
intro hp'
|
|
||||||
Hint (hidden := true) "**Robo**: Was siehst du, wenn du `{hp}` und `{hp'}` anschaust?"
|
|
||||||
contradiction
|
|
||||||
|
|
||||||
LemmaTab "Logic"
|
|
||||||
NewDefinition Inhabited
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"**weitere Person**: Fantastisch! Zum wohl!
|
|
||||||
|
|
||||||
…und damit endet auch deine Erinnerung und wer weiss was du anschließend gemacht hast…"
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Inequality"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Induktion"
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Hier lernst du Induktion und Ungleichungen kennen. Beides essenziele Grundlagen, die du
|
|
||||||
für spätere Aufgaben brauchst.
|
|
||||||
|
|
||||||
Die Leantaktik `induction n` führt einen Induktionsbeweis über `(n : ℕ)`. Hier zuerst
|
|
||||||
ein abstraktes Beispiel.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Sei $P(n)$ eine logische Aussage über die natürliche Zahl.
|
|
||||||
Agenommen $P(0)$ ist wahr und $P(m) \\Rightarrow P(m+1)$ für alle $m$,
|
|
||||||
dann gilt $P(n)$ für alle $n \\in \\mathbb{N}.$"
|
|
||||||
(n : ℕ) (P : ℕ → Prop) (h_base : P 0) (h_step : ∀ m, P m → P m.succ) : P n := by
|
|
||||||
induction n
|
|
||||||
assumption
|
|
||||||
apply h_step
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Hint (P : ℕ → Prop) : P Nat.zero =>
|
|
||||||
"Das ist die Induktionsverankerung, hier musst du $P(0)$ zeigen."
|
|
||||||
|
|
||||||
Hint (P : ℕ → Prop) (m : ℕ) (hi : P m) : P (Nat.succ m) =>
|
|
||||||
"An der Stelle kommt der Beweis $P(m) \\Rightarrow P(m+1)$.
|
|
||||||
|
|
||||||
In diesem Beispiel kannst du `apply` benützen."
|
|
||||||
|
|
||||||
NewTactic induction
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import Adam.Levels.Lean.L01_Type
|
|
||||||
import Adam.Levels.Lean.L02_Universe
|
|
||||||
import Adam.Levels.Lean.L03_ImplicitArguments
|
|
||||||
import Adam.Levels.Lean.L04_InstanceArguments
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Lean"
|
|
||||||
Title "Lean"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"Während ihr weiter durch Täler, über Geröllhalden und zwischen monumentalen Steintürmen
|
|
||||||
umherzieht, fragst du eines Tages Robo.
|
|
||||||
|
|
||||||
**Du**: Sag mal, hast du dir je Gedanken dazu gemacht, wie du eigentlich funktionierts?
|
|
||||||
|
|
||||||
**Robo**: Was meinst du, wie ich funktioniere? Ich bin halt… ich…
|
|
||||||
|
|
||||||
**Du**: Ja schon, aber was woher weisst du denn alles was du weisst?
|
|
||||||
|
|
||||||
**Robo**: Das kann ich dir sagen. Früher habe ich viele Datenträger verschlungen,
|
|
||||||
und dadurch gelernt.
|
|
||||||
|
|
||||||
**Du**: Ob so eine Diskette wohl lecker schmeckt? Egal, ich hab ein paar Fragen zu deinem
|
|
||||||
Lean-Modul.
|
|
||||||
|
|
||||||
**Robo**: Na dann nur zu!"
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Lean"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Typen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Du**: Also, wieso schreib ich denn sowohl `(n : ℕ)` für eine natürliche Zahl wie
|
|
||||||
auch `(h : A ∧ ¬ B)` für eine Aussage?
|
|
||||||
|
|
||||||
**Robo**: Alles in Lean sind Objekte von einem *Typen*, man nennt das auch
|
|
||||||
\"dependent type theory\". Rechts vom `:` steht immer der Typ der dieses Objekt hat.
|
|
||||||
|
|
||||||
**Du**: Verstehe, dann war `ℕ` der Typ der natürlichen Zahlen, `Prop` der Typ
|
|
||||||
aller logischen Aussagen, und so weiter. Un wenn `R` einfach irgendein Typ ist, dann…
|
|
||||||
|
|
||||||
**Robot: …würdest du das als `(R : Type)` schreiben.
|
|
||||||
|
|
||||||
**Du**: Also sind Typen ein bisschen jene Grundlage, die in meinem Studium die
|
|
||||||
Mengen eingenommen haben?
|
|
||||||
|
|
||||||
**Robo**: Genau. Ein Ring ist dann zum Beispiel als `(R : Type) [Ring R]` definiert,
|
|
||||||
also als Typen, auf dem eine Ringstruktur besteht.
|
|
||||||
|
|
||||||
**Robo**: Hier ein Beispiel. Die Taktik `ring` funktioniert in jedem Typen, der
|
|
||||||
genügend Struktur definiert hat, zum Beispiel in einem kommutativen Ring:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (R : Type) [CommRing R] (a b : R) : a + b = b + a := by
|
|
||||||
ring
|
|
||||||
|
|
||||||
Conclusion "**Robo**: `[CommRing R]` nennt man übrigens eine Instanz und die
|
|
||||||
eckigen Klammern sagen Lean, dass es automatisch suchen soll, ob es so eine Instanz
|
|
||||||
findet, wenn man ein Lemma anwenden will."
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Lean"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Universen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"**Du**: Aber wenn alles Typen sind, welcher Typ hat dann `Type`?
|
|
||||||
|
|
||||||
**Robo**: `Type 1` und dieser hat Typ `Type 2`, etc.
|
|
||||||
|
|
||||||
**Robo**: Die Zahl nennt man *Universum*. Manchmal führt man Universen explizit
|
|
||||||
mit `universum u` ein, öfter siehst du `(R : Type _)`, was einfach ein Platzhalter
|
|
||||||
für irgend ein Universum ist.
|
|
||||||
|
|
||||||
**Du**: Das klingt ein bisschen nach Mengentheoretische Probleme, die man normalerweise
|
|
||||||
ignoriert.
|
|
||||||
|
|
||||||
**Robo**: Genau! Deshalb schreibt man eigentlich immer einfach `Type _` und ist glücklich.
|
|
||||||
Spezifischer muss man erst werden wenn man sowas wie Kategorientheorie anschaut, wo
|
|
||||||
man die Universen tatsächlich kontrollieren muss.
|
|
||||||
|
|
||||||
**Du**: Oke, hier rein, da raus. Aber hast du mir noch eine Aufgabe?
|
|
||||||
"
|
|
||||||
|
|
||||||
universe u
|
|
||||||
|
|
||||||
Statement
|
|
||||||
(R : Type u) [CommRing R] (a b : R) : a + b = b + a := by
|
|
||||||
Hint "**Robo**: Naja, Aufgaben zu Universen sind nicht so natürlich,
|
|
||||||
aber vorige Aufgabe würde man eigentlich besser so schreiben, da
|
|
||||||
kannst du mindestens das Uniersum beobachten.
|
|
||||||
|
|
||||||
**Du**: Ah ich sehe, `(R: Type u)` anstatt `(R : Type)`. Muss mich
|
|
||||||
das interessieren?
|
|
||||||
|
|
||||||
**Robo**: Nicht wirklich…"
|
|
||||||
ring
|
|
||||||
|
|
||||||
Conclusion "**Du**: Na dann. Aber gut dass ich's mal gesehen hab."
|
|
||||||
|
|
||||||
-- Hint (R : Type) (h : CommRing R) (a : R) (b : R) : a + b = b + a =>
|
|
||||||
-- ""
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Lean"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
open Fin
|
|
||||||
|
|
||||||
Title "Implizite Argumente"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
**Du**: Was mich aber mehr beschäftigt, ist, dass Lemmas manchmal viel mehr Argumente
|
|
||||||
haben als ich hinschreiben muss.
|
|
||||||
|
|
||||||
**Robo**: Lean kann manche Argumente aus dem Kontext erschliessen. Hast du zum Beispiel
|
|
||||||
ein Lemma von vorhin
|
|
||||||
|
|
||||||
```
|
|
||||||
lemma Fin.sum_univ_castSucc {β : Type _} [AddCommMonoid β]
|
|
||||||
{n : ℕ} (f : Fin (n + 1) → β) :
|
|
||||||
∑ i : Fin (n + 1), f i =
|
|
||||||
∑ i : Fin n, f (↑Fin.castSucc.toEmbedding i) + f (Fin.last n) := by
|
|
||||||
sorry
|
|
||||||
```
|
|
||||||
|
|
||||||
dann reicht es ja Lean `f` zu geben und daraus kann es herausfinden, was die anderen
|
|
||||||
(`β`, `n`) sein müssen.
|
|
||||||
|
|
||||||
**Robo**: Solche *implizite Argumente* markiert man dann mit `{_ : _}` während
|
|
||||||
*explizite Arumente* mit `(_ : _)` markiert werden.
|
|
||||||
|
|
||||||
**Du**: Dann könnte ich also einfach `Fin.sum_univ_castSucc f` schreiben?
|
|
||||||
|
|
||||||
**Robo**: Genau!
|
|
||||||
|
|
||||||
**Du**: Und was war dann das `(n := m + 1)` vorhin genau?
|
|
||||||
|
|
||||||
**Robo**: Damit kann man im Aussnahmefall die impliziten Argumente doch angeben. Hier haben wir
|
|
||||||
gesagt, es soll für das Argument `n` den Term `m + 1` einsetzen. Hier mach das doch noch einmal
|
|
||||||
unter weniger Stress:
|
|
||||||
"
|
|
||||||
|
|
||||||
open BigOperators
|
|
||||||
|
|
||||||
Statement (m : ℕ) : ∑ i : Fin (m + 1), (i : ℕ) + (m + 1) = ∑ i : Fin (Nat.succ m + 1), ↑i := by
|
|
||||||
Branch
|
|
||||||
rw [Fin.sum_univ_castSucc]
|
|
||||||
Hint "**Robo**: Siehst du, ohne die Hilfe macht es das Falsche. Deshalb muss man hier
|
|
||||||
explizit mit `Fin.sum_univ_castSucc (n := m + 1)` nachhelfen."
|
|
||||||
rw [Fin.sum_univ_castSucc]
|
|
||||||
Hint "**Robo**: Na klar, in dem Beispiel kannst du einfach weiter umschreiben bis es
|
|
||||||
nicht mehr geht, aber das war nicht der Punkt…"
|
|
||||||
rw [Fin.sum_univ_castSucc]
|
|
||||||
Hint "**Robo**: Na klar, in dem Beispiel kannst du einfach weiter umschreiben bis es
|
|
||||||
nicht mehr geht, aber das war nicht der Punkt…"
|
|
||||||
rfl
|
|
||||||
rw [Fin.sum_univ_castSucc (n := m + 1)]
|
|
||||||
Hint "**Robo**: Gut der Rest ist easy."
|
|
||||||
rfl
|
|
||||||
|
|
||||||
OnlyTactic rw rfl simp trivial
|
|
||||||
LemmaTab "Sum"
|
|
||||||
|
|
||||||
Conclusion "**Du**: Gibt es auch noch ander Methoden implizite Argumente anzugeben.
|
|
||||||
|
|
||||||
**Robo** `@Fin.sum_univ_castSucc` würde *alle* Argumente explizit machen,
|
|
||||||
aber das ist unparktischer, weil man dann irgendwie
|
|
||||||
`@Fin.sum_univ_castSucc _ _ (m + 1)` schreiben müsste.
|
|
||||||
|
|
||||||
**Du**: Ah und ich sehe der `_` ist überall in Lean ein Platzhalter, der automatisch
|
|
||||||
gefüllt wird."
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Lean"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Instanz-Argumente"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"**Du**: Also nochmals als Zusammenfassung, dann gibt es 3 Arten von Argumenten,
|
|
||||||
explizite mit `()`, implizite mit `{}` und Instanzen mit `[]`?
|
|
||||||
|
|
||||||
**Robo**: Korrekt. Instanzen sind damit auch Implizite Argumente. Der Unterschied
|
|
||||||
zwischen `{}` und `[]` ist also *wie* Lean diese füllt.
|
|
||||||
|
|
||||||
**Du**: Verstehe, bei den ersten sucht es logisch nach einer richtigen Möglichkeit,
|
|
||||||
beim zweiten geht's durch alle Instanzen, die es kennt.
|
|
||||||
|
|
||||||
|
|
||||||
**Robo**: Funktioniert hier bei mir nicht, aber wenn du ausserhalb eines Beweises
|
|
||||||
`#synth Ring ℤ` in ein Dokument schreibt, zeigt dir Lean, ob es eine Instanz finden kann.
|
|
||||||
|
|
||||||
**Du**: Ich glaube das macht alles Sinn.
|
|
||||||
|
|
||||||
**Robo**: Hier, mach nochmals das Gleiche wie vorhin aber mit @-Syntax um das zu
|
|
||||||
verinnerlichen:
|
|
||||||
"
|
|
||||||
|
|
||||||
open BigOperators
|
|
||||||
|
|
||||||
Statement (m : ℕ) :
|
|
||||||
∑ i : Fin (m + 1), (i : ℕ) + (m + 1) = ∑ i : Fin (Nat.succ m + 1), ↑i := by
|
|
||||||
Hint "**Robo**: Schreibe `rw [@Fin.sum_univ_castSucc _ _ (m + 1)]`
|
|
||||||
anstatt `rw [Fin.sum_univ_castSucc (n := m + 1)]`!"
|
|
||||||
rw [@Fin.sum_univ_castSucc _ _ (m + 1)]
|
|
||||||
rfl
|
|
||||||
|
|
||||||
OnlyTactic rw rfl simp trivial
|
|
||||||
LemmaTab "Sum"
|
|
||||||
|
|
||||||
Conclusion "
|
|
||||||
**Du**: Danke Robo!
|
|
||||||
|
|
||||||
Um zwei weitere Ecken und plötzlich steht ihr wieder vor dem Golem, dem ihr schon begegnet seit.
|
|
||||||
Dieser lädt euch zum Abendmahl ein. Ihr erfährt, dass er ganz gerne liest und er zeigt euch
|
|
||||||
sein neustes Buch, das er leider nicht lesen kann. Nich tnur ist es der zweite Band einer Serie
|
|
||||||
(der Erste hat offensichtlich was mit \"Urbildern\" zu tun), sondern ist es auch in einem
|
|
||||||
Dialekt geschrieben, der anscheinend nur auf einem Nachbarsmond gesprochen wird.
|
|
||||||
|
|
||||||
Ihr beschliesst dem herzlichen Golem zu helfen und beiden Monden einen Besuch abzustatten,
|
|
||||||
sowohl um den Dialekt zu lernen, wie auch in der Bibliothek auf dem anderen Mond nach dem
|
|
||||||
ersten Band zu suchen.
|
|
||||||
"
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Std.Tactic.RCases
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Implication"
|
|
||||||
Level 9
|
|
||||||
|
|
||||||
Title "Oder"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Übung macht den Meister... Benutze alle vier Methoden mit UND und ODER
|
|
||||||
umzugehen um folgende Aussage zu beweisen.
|
|
||||||
|
|
||||||
| | Und | Oder |
|
|
||||||
|---------|:-------------------------|:--------------------------|
|
|
||||||
| Annahme | `rcases h with ⟨h₁, h₂⟩` | `rcases h with h₁ \\| h₂` |
|
|
||||||
| Goal | `constructor` | `left`/`right` |
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement and_or_imp
|
|
||||||
"Angenommen $(A \\land B) \\lor (A \\Rightarrow C)$ und $A$ sind wahr, zeige dass
|
|
||||||
$B \\lor (C \\land A)$ wahr ist."
|
|
||||||
(A B C : Prop) (h : (A ∧ B) ∨ (A → C)) (hA : A) : (B ∨ (C ∧ A)) := by
|
|
||||||
rcases h with h₁ | h₂
|
|
||||||
left
|
|
||||||
rcases h₁ with ⟨x, y⟩
|
|
||||||
assumption
|
|
||||||
right
|
|
||||||
constructor
|
|
||||||
apply h₂
|
|
||||||
assumption
|
|
||||||
assumption
|
|
||||||
|
|
||||||
HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B ∨ (A → C)) (hA : A) : B ∨ (C ∧ A) =>
|
|
||||||
"Ein ODER in den Annahmen teilt man mit `rcases h with h₁ | h₂`."
|
|
||||||
|
|
||||||
-- If starting with `left`.
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B ∨ (A → C)) : B =>
|
|
||||||
"Da kommst du nicht mehr weiter..."
|
|
||||||
|
|
||||||
-- If starting with `right`.
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B ∨ (A → C)) : (C ∧ A) =>
|
|
||||||
"Da kommst du nicht mehr weiter..."
|
|
||||||
|
|
||||||
HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B) (hA : A) : B ∨ (C ∧ A) =>
|
|
||||||
"`left` oder `right`?"
|
|
||||||
|
|
||||||
HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : B) (hA : A) : B ∨ (C ∧ A) =>
|
|
||||||
"`left` oder `right`?"
|
|
||||||
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B) (hA : A) : B ∨ (C ∧ A) =>
|
|
||||||
"Ein UND in den Annahmen kann man mit `rcases h with ⟨h₁, h₂⟩` aufteilen."
|
|
||||||
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B) (hA : A) : B =>
|
|
||||||
"Ein UND in den Annahmen kann man mit `rcases h with ⟨h₁, h₂⟩` aufteilen."
|
|
||||||
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B) : C =>
|
|
||||||
"Sackgasse."
|
|
||||||
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A ∧ B) : C ∧ A =>
|
|
||||||
"Hmmm..."
|
|
||||||
|
|
||||||
Hint (A : Prop) (B : Prop) (C : Prop) (h : A → C) : C ∧ A =>
|
|
||||||
"Ein UND im Goal kann mit `constructor` aufgeteilt werden."
|
|
||||||
|
|
||||||
NewTactic left right assumption constructor rcases
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Nat2"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Primzahlen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
TODO: Primzahl
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement "" : True := by
|
|
||||||
trivial
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic ring
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Nat2"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Exists unique"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
TODO: Es existiert genau eine gerade Primzahl.
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement "" : True := by
|
|
||||||
trivial
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
NewTactic ring
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
-- TODO: `even`/`odd` sind in Algebra.Parity. Not ported yet
|
|
||||||
def even (a : ℕ) : Prop := ∃ r, a = 2 * r
|
|
||||||
def odd (a : ℕ) : Prop := ∃ k, a = 2 * k + 1
|
|
||||||
|
|
||||||
lemma not_odd {n : ℕ} : ¬ odd n ↔ even n := by sorry
|
|
||||||
|
|
||||||
lemma not_even {n : ℕ} : ¬ even n ↔ odd n := by sorry
|
|
||||||
|
|
||||||
lemma even_square (n : ℕ) : even n → even (n ^ 2) := by
|
|
||||||
intro ⟨x, hx⟩
|
|
||||||
unfold even at *
|
|
||||||
use 2 * x ^ 2
|
|
||||||
rw [hx]
|
|
||||||
ring
|
|
||||||
|
|
||||||
def prime (n : ℕ) : Prop := (2 ≤ n) ∧ ∀ a b, n = a * b → a = 1 ∨ b = 1
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Nat"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Für alle"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Eine Primzahl könnte man folgendermassen implementieren:
|
|
||||||
```
|
|
||||||
def prime (p : ℕ) : Prop := (2 ≤ p) ∧ (∀ a b, p = a * b → a = 1 ∨ b = 1)
|
|
||||||
```
|
|
||||||
Also, eine Zahl `p` ungleich `0` oder `1`, für die gilt wenn `a * b = p` dann ist
|
|
||||||
entweder `a` oder `b` eins.
|
|
||||||
|
|
||||||
(Tatsächlich ist eine Primzahl dann etwas genereller definiert, aber dazu mehr später.)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Wenn `n * m` eine Primzahl ist, dann ist einer der beiden Faktoren eins."
|
|
||||||
(p n m : ℕ) (h : prime p) (h₂ : p = m * n) : n = 1 ∨ m = 1 := by
|
|
||||||
unfold prime at h
|
|
||||||
rcases h with ⟨l, r⟩
|
|
||||||
apply r
|
|
||||||
rw [h₂]
|
|
||||||
ring
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hint (n : ℕ) (hn : odd n) (h : ∀ (x : ℕ), (odd x) → even (x + 1)) : even (n + 1) =>
|
|
||||||
"`∀ (x : ℕ), (odd x) → even (x + 1)` ist eigentlich das gleiche wie
|
|
||||||
`(x : ℕ) → `"
|
|
||||||
|
|
||||||
NewTactic ring intro unfold
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
-- tauto is not implemented yet... duper?
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
-- not implemented yet
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
-- -- INCORPORATED
|
|
||||||
-- example (A B : Prop) : (A → B) ↔ (¬ B → ¬A) := by
|
|
||||||
-- constructor
|
|
||||||
-- intro h nb
|
|
||||||
-- by_contra
|
|
||||||
-- have : B
|
|
||||||
-- apply h
|
|
||||||
-- assumption
|
|
||||||
-- contradiction
|
|
||||||
-- intro h a
|
|
||||||
-- by_contra
|
|
||||||
-- have : ¬ A
|
|
||||||
-- apply h
|
|
||||||
-- assumption
|
|
||||||
-- contradiction
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Function"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Funktionen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Funktionen werden in Lean als `(f : ℕ → ℕ)` geschrieben (`\\to`), also mit dem gleichen
|
|
||||||
Pfeil wie Implikationen. Entsprechend kann man Implikationen und Funktionen genau
|
|
||||||
gleich behandeln.
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement : ∃ (f : ℕ → ℕ), ∀ (x : ℕ), f x = 0 := by
|
|
||||||
let g := fun (x : ℕ) ↦ 0
|
|
||||||
use g
|
|
||||||
simp
|
|
||||||
|
|
||||||
Conclusion ""
|
|
||||||
|
|
||||||
NewTactic use simp
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Levels.LinearAlgebra.L01_Module
|
|
||||||
import Adam.Levels.LinearAlgebra.L02_VectorNotation
|
|
||||||
import Adam.Levels.LinearAlgebra.L03_VectorNotation
|
|
||||||
import Adam.Levels.LinearAlgebra.L04_Submodule
|
|
||||||
import Adam.Levels.LinearAlgebra.L05_Submodule
|
|
||||||
import Adam.Levels.LinearAlgebra.L06_Span
|
|
||||||
import Adam.Levels.LinearAlgebra.L07_Span
|
|
||||||
import Adam.Levels.LinearAlgebra.L08_GeneratingSet
|
|
||||||
|
|
||||||
import Adam.Levels.LinearAlgebra.M01_LinearMap
|
|
||||||
import Adam.Levels.LinearAlgebra.M02_LinearIndep
|
|
||||||
import Adam.Levels.LinearAlgebra.M04_Basis
|
|
||||||
|
|
||||||
import Adam.Levels.LinearAlgebra.N01_Span
|
|
||||||
import Adam.Levels.LinearAlgebra.N02_Span
|
|
||||||
import Adam.Levels.LinearAlgebra.N03_Idempotent
|
|
||||||
import Adam.Levels.LinearAlgebra.N04_Idempotent
|
|
||||||
import Adam.Levels.LinearAlgebra.N05_Sum
|
|
||||||
import Adam.Levels.LinearAlgebra.N06_Sum
|
|
||||||
import Adam.Levels.LinearAlgebra.N07_Prod
|
|
||||||
import Adam.Levels.LinearAlgebra.N08_Prod
|
|
||||||
import Adam.Levels.LinearAlgebra.N09_Prod
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Title "Vektorraum"
|
|
||||||
|
|
||||||
Introduction "Hier lernst du die Grundlagen zur linearen Algebra.
|
|
||||||
|
|
||||||
Vektorräume sind in Lean etwas algemeiner definiert als dies normalerweise in
|
|
||||||
einer Einführungsvorlesung antrifft: Man definiert ein \"Modul\" (Plural: Moduln)
|
|
||||||
über einem Ring. Ein Modul über einem *Körper* wird dann auch \"Vektorraum\" genannt.
|
|
||||||
"
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Basis"
|
|
||||||
Title "Lineare Abbildungen"
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Title "Mehr Vektorräume"
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
import Adam.StructInstWithHoles
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Module"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Konkret heisst das:
|
|
||||||
|
|
||||||
Sei `R` ein Ring. Ein `R`-Modul ist eine kommutative Gruppe `(V, +)` zusammen mit
|
|
||||||
einer Abbildung `• : R × V → V` (Skalarmultiplitation genannt), die folgende
|
|
||||||
Eigenschaften beliebige `(r s : R)` und `(v w : V)`erfüllt:
|
|
||||||
- `r • (v + w) = r • v + r • w`
|
|
||||||
- `(r + s) • v = r • v + s • v`
|
|
||||||
- `(r * s) • v = r • s • v`
|
|
||||||
- `1 • r = r`
|
|
||||||
- `0 • v = 0`
|
|
||||||
- `r • 0 = 0`
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Bemerkungen:
|
|
||||||
-- 1) Über einem `[field R]` sind die letzten beiden Eigenschaften überflüssig, diese kann
|
|
||||||
-- man beweisen, wenn man Cancellation (`a₁ + x = a₂ + x → a₁ = a₂`) hat. In einem generellen
|
|
||||||
-- Ring, muss das aber nicht gegeben sein (siehe Nullteiler).
|
|
||||||
-- 2) Die nötigen Annahmen um ein Modul in Lean zu erhalten sind tatsächlich noch etwas lockerer,
|
|
||||||
-- so muss `R` nicht ganz ein Ring sein (nur `[Semiring R]`) und
|
|
||||||
-- `V` muss nicht ganz eine kommutative Gruppe sein (nur `[add_comm_monoid V]`).
|
|
||||||
-- Einen abstrakten Vektorraum definiert man wie folgt:
|
|
||||||
-- `variables {R V : Type*} [field R] [add_comm_monoid V] [module R V]`
|
|
||||||
|
|
||||||
-- Wenn man hingegen konkret zeigen will, dass ein existierendes Objekt ein Vektorraum ist,
|
|
||||||
-- kann man eine einsprechende Instanz wie folgt definieren:
|
|
||||||
|
|
||||||
-- ```
|
|
||||||
-- instance Q_module : Module ℚ ℝ :=
|
|
||||||
-- { smul := λa r, ↑a * r
|
|
||||||
-- smul_zero := _
|
|
||||||
-- zero_smul := _
|
|
||||||
-- one_smul := _
|
|
||||||
-- smul_add := _
|
|
||||||
-- add_smul := _
|
|
||||||
-- mul_smul := _ }
|
|
||||||
-- ```
|
|
||||||
-- Man muss also angeben, welche Skalarmultiplikation man gerne hätte
|
|
||||||
-- (`smul`. In unserem Fall sagen wir einfach, diese soll Multiplikation in `ℝ` sein.)
|
|
||||||
-- und dazu jegliche Beweise, dass die Skalarmultiplikation sich mit der Ringstruktur verträgt.
|
|
||||||
-- Im nachfolgenden beweisen wir die Eigenschaften einzeln.
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Zeige, dass $\\mathbb{R}$ ein $\\mathbb{Q}$-Modul ist."
|
|
||||||
: Module ℚ ℝ := by
|
|
||||||
Hint "**Robo**: Als erstes willst du die Stuktur `Modul` aufteilen in einzelne Beweise.
|
|
||||||
Der Syntax dafür ist:
|
|
||||||
|
|
||||||
```
|
|
||||||
refine \{ ?..! }
|
|
||||||
```
|
|
||||||
"
|
|
||||||
refine { ?..! }
|
|
||||||
· Hint "**Robo**: Hier musst du die Skalarmultiplikation angeben.
|
|
||||||
Benutze dafür `exact fun (a : ℚ) (r : ℝ) => ↑a * r`."
|
|
||||||
exact fun (a : ℚ) (r : ℝ) => ↑a * r
|
|
||||||
· Hint "**Robo**: Jetzt musst du alle eigenschaften eines $\\mathbb\{Q}$-Moduls zeigen,
|
|
||||||
das sind also 6 einzelne Goals."
|
|
||||||
intro b
|
|
||||||
Hint "**Robo**: Mit `change (1 : ℚ) * {b} = {b}` kannst du das Goal umschreiben, damit
|
|
||||||
dann andere Taktiken besser damit arbeiten können."
|
|
||||||
change (1 : ℚ) * b = b
|
|
||||||
Hint "**Robo**: Den Teil kannst du mit `simp` beweisen."
|
|
||||||
simp
|
|
||||||
· intro x y b
|
|
||||||
Hint "**Robo**: Benutze `change` um `•` durch `*` zu ersetzen."
|
|
||||||
Hint (hidden := true) "**Robo**: Explizit `change ({x} * {y} : ℚ) * {b} = {x} * ({y} * {b})`"
|
|
||||||
change (x * y : ℚ) * b = x * (y * b)
|
|
||||||
Hint "**Robo**: Mit `simp` und `ring` kannst du den Rest beweisen."
|
|
||||||
simp
|
|
||||||
ring
|
|
||||||
· intro a
|
|
||||||
simp
|
|
||||||
· intro a x y
|
|
||||||
Hint (hidden := true) "**Robo**: Explizit `change {a} * ({x} + {y}) = {a} * {x} + {a} * {y}`"
|
|
||||||
change a * (x + y) = a * x + a * y
|
|
||||||
ring
|
|
||||||
· intro r s x
|
|
||||||
Hint (hidden := true) "**Robo**: Explizit
|
|
||||||
`change ({r} + {s} : ℚ) * {x} = {r} * {x} + {s} * {x}`"
|
|
||||||
change (r + s : ℚ) * x = r * x + s * x
|
|
||||||
simp
|
|
||||||
ring
|
|
||||||
· intro a
|
|
||||||
Hint (hidden := true) "**Robo**: Explizit `change (0 : ℚ) * {a} = 0`"
|
|
||||||
change (0 : ℚ) * a = 0
|
|
||||||
simp
|
|
||||||
|
|
||||||
NewTactic refine exact change
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Konkrete Vektorräume"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Den $\\mathbb{Q}$-Vektorraum $\\mathbb{Q}^3$ definiert man am besten mit
|
|
||||||
der lokalen Notation
|
|
||||||
|
|
||||||
```
|
|
||||||
local notation `ℚ³` := Fin 3 → ℚ
|
|
||||||
```
|
|
||||||
|
|
||||||
Dabei ist `Fin 3` die Indexmenge $\\{0, 1, 2\\}$.
|
|
||||||
|
|
||||||
Die schreibweise für einen Vektor ist `![ _, _ ]`. Zu beachten ist,
|
|
||||||
dass man bei Zahlen explizit einen Typ angeben muss, sonst denkt sich
|
|
||||||
Lean, man arbeite über `ℕ`.
|
|
||||||
|
|
||||||
Um direkt Vektoroperationen über `ℚ` auszurechnen, kann man oft
|
|
||||||
`#eval` benützen:
|
|
||||||
|
|
||||||
```
|
|
||||||
#eval ![ (2 : ℚ), 5 ] + ![ 1/2, -7 ]
|
|
||||||
```
|
|
||||||
zeigt `![5/2, -2]` an.
|
|
||||||
|
|
||||||
Um eine Gleichheit in einem Beweis zu verwenden, muss man andere Taktiken
|
|
||||||
benützen.
|
|
||||||
|
|
||||||
Am hilfreichsten ist die kombination `funext i, fin_cases i`, die
|
|
||||||
Dann eine Vektorgleichung komponentenweise aufteilt.
|
|
||||||
|
|
||||||
Für jede Komponente kann man dann mit `simp` und `ring` weiterkommen.
|
|
||||||
"
|
|
||||||
|
|
||||||
local notation "ℚ³" => Fin 3 → ℚ
|
|
||||||
local notation "ℚ^(" n ")" => (Fin n) → ℚ
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
: ![ (2 : ℚ), 5 ] + ![ 1/2, -7 ] = ![5/2, -2] := by
|
|
||||||
funext i
|
|
||||||
fin_cases i <;>
|
|
||||||
simp <;>
|
|
||||||
ring
|
|
||||||
|
|
||||||
NewTactic fin_cases funext
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Konkrete Vektorräume"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Beachte dass Skalarmultiplikation mit `•` geschrieben wird, und nicht mit `*`!
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
: 5 • ![ (2 : ℚ), 5 ] + ![ 1, 0 ] = ![11, 25] := by
|
|
||||||
funext i
|
|
||||||
fin_cases i <;>
|
|
||||||
simp <;>
|
|
||||||
ring
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Untervektorräume"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Sei `K` ein Körper und `V` ein `K`-Modul.
|
|
||||||
|
|
||||||
```
|
|
||||||
variable {K V : Type _} [Field K]
|
|
||||||
variable [AddCommMonoid V] [Module K V]
|
|
||||||
```
|
|
||||||
|
|
||||||
Untermodule/Untervektorräume werden in Lean ein bisschen anders definiert als Module/Vektorräume.
|
|
||||||
|
|
||||||
Grob gesagt ist `V` ein Typ (denke z.B. an eine generelle Menge)
|
|
||||||
und `[module K V]` eine Instanz, die von Lean automatisc gefunden wird und
|
|
||||||
sagt, dass auf `V` eine `K`-Modulstruktur existiert. Hingegen ist `submodule K V` die Menge aller
|
|
||||||
Untermodulen
|
|
||||||
in `V`. Deshalb definieren wir Untermodule, indem wir Elemente aus dieser Menge auswählen:
|
|
||||||
|
|
||||||
```
|
|
||||||
variable (U : Submodule K V)
|
|
||||||
```
|
|
||||||
|
|
||||||
Unter anderem hat dies den Vorteil, dass `submodule K V` eine Lattice ist, also eine `≤`-Operation
|
|
||||||
besitzt. Auf dem Papier
|
|
||||||
schreibt man normalerweise `U₁ ⊆ U₂` um zu sagen, dass das eine Untermodul eine Teilmenge des
|
|
||||||
anderen ist, in Lean braucht
|
|
||||||
man dafür immer `≤`.
|
|
||||||
|
|
||||||
Ganz `V` als Untermodul von sich selbst betrachtet, schreibt man als `⊤` (`\\top`), also das
|
|
||||||
grösste Element in dieser Lattice,
|
|
||||||
und das Null-Untermodule `{0}` with als `⊥` geschrieben (`\\bot`), also das kleinste Element.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Jeder Untervektorraum `U ⊆ V` ist eine Teilmenge von `V`."
|
|
||||||
{K V : Type _} [Field K] [AddCommMonoid V] [Module K V] (U : Submodule K V) : U ≤ ⊤ := by
|
|
||||||
simp only [le_top]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Untervektorräume"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Elemente aus einem Untervektorraum $U$ wählt man gleich aus, wie Elemente in einer Menge.
|
|
||||||
Nämlich man nimmt ein Element `(x : V)` und sagt, dass es in `U` liegt mit `x ∈ U` (`\\in`).
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"TODO: Spannendere Aufgaben."
|
|
||||||
{K V : Type _} [Field K] [AddCommMonoid V] [Module K V] (U : Submodule K V) :
|
|
||||||
∀ (x : V), x ∈ U ∨ x ∉ U := by
|
|
||||||
intro x
|
|
||||||
rw [or_iff_not_imp_left]
|
|
||||||
tauto
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Hülle"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Ein typischer Untervektorraum ist die Hülle `⟨M⟩`, oder `span`, also die Menge aller
|
|
||||||
`K`-Linearkombinationen von Elementen aus der Menge `M`.
|
|
||||||
|
|
||||||
In Lean ist dies `Submodule.span K M`.
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
local notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
open Submodule Set Finsupp
|
|
||||||
|
|
||||||
-- mem_span_of_mem
|
|
||||||
Statement
|
|
||||||
"Zeige, dass $x \\in M$ auch Element von der $K$-linearen Hülle
|
|
||||||
\\langle M \\rangle ist."
|
|
||||||
{V K : Type _} [Field K] [AddCommMonoid V]
|
|
||||||
[Module K V] (M : Set V) {x : V} (h : x ∈ M) :
|
|
||||||
x ∈ span K M := by
|
|
||||||
rw [mem_span]
|
|
||||||
intro p hp
|
|
||||||
specialize hp h
|
|
||||||
assumption
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 7
|
|
||||||
|
|
||||||
Title "Hülle"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
-- notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
open Submodule Set Finsupp
|
|
||||||
|
|
||||||
open BigOperators -- Summen Notation
|
|
||||||
|
|
||||||
-- TODO: Why is this not in Mathlib?
|
|
||||||
lemma mem_span_of_mem {V K : Type _} [Field K] [AddCommMonoid V]
|
|
||||||
[Module K V] (M : Set V) {x : V} (h : x ∈ M) :
|
|
||||||
x ∈ span K M := by
|
|
||||||
rw [mem_span]
|
|
||||||
intro p hp
|
|
||||||
specialize hp h
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Für $x, y \\in M$, zeige dass $x + 2y$ in der $K$-linearen Hülle $\\langle M \\rangle$ liegt."
|
|
||||||
{V K : Type _} [Field K] [AddCommMonoid V] [Module K V] (M : Set V) {x y : V}
|
|
||||||
(h₁ : x ∈ M) (h₂ : y ∈ M) :
|
|
||||||
x + (2 : K) • y ∈ span K M := by
|
|
||||||
apply add_mem
|
|
||||||
apply mem_span_of_mem
|
|
||||||
assumption
|
|
||||||
apply smul_mem
|
|
||||||
apply mem_span_of_mem
|
|
||||||
assumption
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module"
|
|
||||||
Level 8
|
|
||||||
|
|
||||||
Title "Erzeugendensystem"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Dass eine Familie von Vektoren `M` den ganzen Vektorraum
|
|
||||||
aufspannt, sagt man in Lean mit `⊤ ≤ span K M`. (Man könnte auch `span K M = ⊤` schreiben,
|
|
||||||
aber per Konvention wird `≤` bevorzugt, da `x ≤ ⊤` immer gilt (siehe `le_top`))
|
|
||||||
"
|
|
||||||
|
|
||||||
-- notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
open Submodule Set Finsupp
|
|
||||||
|
|
||||||
open BigOperators -- Summen Notation
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Zeige, dass `![1, 0], ![1, 1]` den ganzen `ℝ`-Vektorraum `ℝ²` aufspannt."
|
|
||||||
: ⊤ ≤ span ℝ (Set.range ![(![1, 0] : Fin 2 → ℝ), ![1, 1]]) := by
|
|
||||||
--rw [top_le_span_range_iff_forall_exists_fun]
|
|
||||||
sorry
|
|
||||||
-- intro v,
|
|
||||||
|
|
||||||
-- use ![v 0 - v 1, v 1],
|
|
||||||
-- simp,
|
|
||||||
-- funext i,
|
|
||||||
-- fin_cases i;
|
|
||||||
-- simp,
|
|
||||||
|
|
||||||
--NewLemma top_le_span_range_iff_forall_exists_fun le_top
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Basis"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Sei `R` ein Ring und `V W` zwei `R`-Moduln. Eine `R`-lineare Abbildung wird in Lean
|
|
||||||
folgendermassen geschrieben: `V →ₗ[R] W` (`\\to` + `\\_l`).
|
|
||||||
|
|
||||||
Man erstellt eine lineare Abbildung aus einer Funktion `f : V → W` zusammen mit den beweisen,
|
|
||||||
dass `f` Addition und Skalarmultiplikation erhält,
|
|
||||||
i.e. `f (x + y) = f x + f y` und `f (r • x) = r • f x`.
|
|
||||||
|
|
||||||
Hier definieren wir zum Beispiel die Null-Abbildung, die einfach alles auf `0` sendet:
|
|
||||||
|
|
||||||
```
|
|
||||||
variables {R V W : Type*} [ring R] [add_comm_monoid V] [add_comm_monoid W]
|
|
||||||
[module R V] [module R W]
|
|
||||||
|
|
||||||
def my_zero_map : V →ₗ[R] W :=
|
|
||||||
{ to_fun := λ x, 0,
|
|
||||||
map_add' :=
|
|
||||||
begin
|
|
||||||
intros,
|
|
||||||
simp,
|
|
||||||
end,
|
|
||||||
map_smul' :=
|
|
||||||
begin
|
|
||||||
intros,
|
|
||||||
simp,
|
|
||||||
end }
|
|
||||||
```
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"
|
|
||||||
Zeige dass die Abbildung
|
|
||||||
|
|
||||||
```
|
|
||||||
ℝ² → ℝ²
|
|
||||||
(x, y) ↦ (5x + 2y, x - y)
|
|
||||||
```
|
|
||||||
|
|
||||||
`ℝ`-linear ist.
|
|
||||||
"
|
|
||||||
: ℝ² →ₗ[ℝ] ℝ² :=
|
|
||||||
{ toFun := fun v ↦ ![5 * (v 1) + 2 * (v 2), (v 1) - (v 2)]
|
|
||||||
map_add' := by
|
|
||||||
-- Wähle zwei beliebige Vektoren mit `intros` aus.
|
|
||||||
intro x y
|
|
||||||
-- Das Lemma `funext` sagt das zwei Funktionen identisch sind, wenn sie für jeden Wert ereinstimmen:
|
|
||||||
-- `(∀ i, f i = g i) → f = g`. Da Vektoren einfach als Funktionen von einem Indexset codiert sind,
|
|
||||||
-- kannst du mit `apply funext` komponentenweise rechnen.
|
|
||||||
funext i
|
|
||||||
-- Mit `fin_cases i` kannst du pro möglichem Wert von `i` ein Goal auftun. D.h. im ersten gilt dann
|
|
||||||
-- `i = 0`, im zweiten Goal `i = 1`.
|
|
||||||
fin_cases i
|
|
||||||
-- Dies ist der Fall `i = 0`.
|
|
||||||
-- Das Goal hat jetzt Terme der Form `![a, b] 0`, und du weisst was das sein sollte, nämlich
|
|
||||||
-- einfach der erste Komponent `a`. Die Taktik `simp` ist für solche Vereinfachungnen gedacht.
|
|
||||||
· simp
|
|
||||||
-- Einfache Rechenaufgaben hast du ja bereits gemacht.
|
|
||||||
-- `ring` oder `linarith` machen dies automatisch für dich.
|
|
||||||
ring
|
|
||||||
-- Und jetzt noch den Fall `i = 1`.
|
|
||||||
· simp
|
|
||||||
ring
|
|
||||||
map_smul' := by
|
|
||||||
intro r x
|
|
||||||
funext i
|
|
||||||
fin_cases i
|
|
||||||
-- Bemerkung: Wenn du jetzt `simp` brauchst, macht es sogar noch mehr als vorher.
|
|
||||||
-- Skalarmultiplikation ist einfach als komponentenweise Multiplikation definiert.
|
|
||||||
-- Entsprechend braucht `simp` ein Lemma `smul_eq_mul : a • b = a * b`.
|
|
||||||
· simp
|
|
||||||
ring
|
|
||||||
· simp
|
|
||||||
ring
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Basis"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Lineare Unabhängigkeit"
|
|
||||||
|
|
||||||
namespace Ex_LinIndep
|
|
||||||
|
|
||||||
scoped notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Zeige, dass `![1, 0], ![1, 1]` linear unabhängig über `ℝ` sind."
|
|
||||||
: LinearIndependent ℝ ![(![1, 0] : ℝ²), ![1, 1]] := by
|
|
||||||
Hint "`rw [Fintype.linearIndependent_iff]`"
|
|
||||||
rw [Fintype.linearIndependent_iff]
|
|
||||||
Hint "`intros c h`"
|
|
||||||
intros c h
|
|
||||||
Hint "BUG: `simp at h` does not work :("
|
|
||||||
simp at h -- doesn't work
|
|
||||||
sorry
|
|
||||||
|
|
||||||
-- rw [Fintype.linearIndependent_iff]
|
|
||||||
-- intros c h
|
|
||||||
-- simp at h
|
|
||||||
-- intros i
|
|
||||||
-- fin_cases i
|
|
||||||
-- swap
|
|
||||||
-- { exact h.2 }
|
|
||||||
-- { have h' := h.1
|
|
||||||
-- rw [h.2, add_zero] at h'
|
|
||||||
-- exact h'}
|
|
||||||
|
|
||||||
end Ex_LinIndep
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Basis"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Basis"
|
|
||||||
|
|
||||||
namespace Ex_Basis
|
|
||||||
|
|
||||||
scoped notation "ℝ²" => Fin 2 → ℝ
|
|
||||||
|
|
||||||
open Submodule
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
lemma exercise1 : LinearIndependent ℝ ![(![1, 0] : ℝ²), ![1, 1]] := sorry
|
|
||||||
|
|
||||||
lemma exercise2 : ⊤ ≤ span ℝ (Set.range ![(![1, 0] : Fin 2 → ℝ), ![1, 1]]) := sorry
|
|
||||||
|
|
||||||
Statement : Basis (Fin 2) ℝ ℝ² := by
|
|
||||||
apply Basis.mk
|
|
||||||
apply exercise1
|
|
||||||
apply exercise2
|
|
||||||
|
|
||||||
end Ex_Basis
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
open Submodule
|
|
||||||
|
|
||||||
-- Verpackungswahn 1a)
|
|
||||||
Title "Verpackungswahn"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
{K V : Type _} [Field K] [AddCommMonoid V] [Module K V] (M : Set V) :
|
|
||||||
span K ↑(span K M) = span K M := by
|
|
||||||
apply Submodule.span_eq
|
|
||||||
-- or : simp
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
open Submodule
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
(Verpackungswahn)
|
|
||||||
If `f` is a function and `M` a subset of its domain, then
|
|
||||||
`f '' M` or `set.image f M` is the notation for the image, which is
|
|
||||||
usally denoted `f(M) = {y | ∃ x ∈ M, f(x) = y}` in mathematical texts.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- TODO: This is blocked by
|
|
||||||
-- https://github.com/leanprover/lean4/issues/2074
|
|
||||||
|
|
||||||
set_option autoImplicit false
|
|
||||||
-- set_option pp.all true
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"" : True := by
|
|
||||||
sorry
|
|
||||||
|
|
||||||
-- example {K V W : Type} [Field K] [AddCommMonoid V] [AddCommMonoid W]
|
|
||||||
-- [Module K V] [Module K W] (M : Set V) (f : V →ₗ[K] W) :
|
|
||||||
-- f '' span K M = @span K (f '' M) := by
|
|
||||||
-- sorry
|
|
||||||
|
|
||||||
-- example {K V : Type} [Field K] [AddCommMonoid V]
|
|
||||||
-- [Module K V] (M : Set V) (f : V →ₗ[K] V) : f '' M = f '' M = := by
|
|
||||||
-- rfl
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
{R V : Type _} [Semiring R] [AddCommGroup V] [Module R V]
|
|
||||||
(p : V →ₗ[R] V) (h : p ∘ p = p) : LinearMap.ker p ⊔ LinearMap.range p = ⊤ := by
|
|
||||||
sorry
|
|
||||||
-- rw eq_top_iff,
|
|
||||||
-- intros v hv,
|
|
||||||
|
|
||||||
-- rw ←sub_add_cancel v (p v),
|
|
||||||
|
|
||||||
-- apply submodule.add_mem_sup,
|
|
||||||
-- { rw [linear_map.mem_ker],
|
|
||||||
-- rw [map_sub],
|
|
||||||
-- change p v - (p ∘ p) v = 0, -- oder: rw [function.comp, function.funext_iff] at h,
|
|
||||||
-- rw h,
|
|
||||||
-- simp },
|
|
||||||
-- { simp }
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
{R V : Type _} [Semiring R] [AddCommGroup V] [Module R V]
|
|
||||||
(p : V →ₗ[R] V)(h : p ∘ p = p) : LinearMap.ker p ⊓ LinearMap.range p = ⊥ := by
|
|
||||||
sorry
|
|
||||||
-- rw eq_bot_iff,
|
|
||||||
-- intros v hv,
|
|
||||||
-- rw submodule.mem_bot,
|
|
||||||
-- rw submodule.mem_inf at hv,
|
|
||||||
-- cases hv.2 with w hw,
|
|
||||||
-- rw ←hw,
|
|
||||||
-- rw ←h,
|
|
||||||
-- change p (p w) = _,
|
|
||||||
-- rw hw,
|
|
||||||
-- rw ←linear_map.mem_ker,
|
|
||||||
-- exact hv.1,
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
open Submodule
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Die interne Summe von Untermodulen wird in Lean mit `⊔` (`\\sup`) geschrieben.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"
|
|
||||||
Zeige, dass `V₁ ⊔ V₂` tatsächlich die interne Summe `⟨V₁ ∪ V₂⟩` ist.
|
|
||||||
"
|
|
||||||
{K V : Type _} [Field K] [AddCommMonoid V] [Module K V] (V₁ V₂ : Submodule K V) :
|
|
||||||
V₁ ⊔ V₂ = span K ( (V₁ : Set V) ∪ V₂ ) := by
|
|
||||||
rw [span_union]
|
|
||||||
simp
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
open Submodule
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Eine interne Summe über eine Familie von Untermodulen `(T : ι → submodule K V)`
|
|
||||||
wird als `⨆ (i : ι), T i` geschrieben (`\\supr`).
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
{K V ι : Type _} [Field K] [AddCommMonoid V] [Module K V]
|
|
||||||
(T : ι → Submodule K V) : (⨆ (i : ι), T i) = span K ( ⋃ i, T i) := by
|
|
||||||
rw [Submodule.span_unionᵢ]
|
|
||||||
simp
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 7
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Die externe Summe von (Unter-) Modulen wird als `V × W` geschrieben
|
|
||||||
Das Produkt zweier Module wird mit `×` geschrieben.
|
|
||||||
|
|
||||||
Lean weiss dann automatisch, dass das Produkt wieder ein Vektorraum ist.
|
|
||||||
-/
|
|
||||||
example : module ℝ (ℝ × ℝ) := infer_instance
|
|
||||||
|
|
||||||
/-
|
|
||||||
Und `ℝ × ℝ` und `fin 2 → ℝ` sind natürlich Isomorph. In Praxis eignet sich
|
|
||||||
die Funktionsschreibweise besser, deshalb verwenden wir diese als
|
|
||||||
definition für `ℝ²`.
|
|
||||||
|
|
||||||
Hier die Äquivalenz als generelle Typen:
|
|
||||||
-/
|
|
||||||
example : (fin 2 → ℝ) ≃ ℝ × ℝ :=
|
|
||||||
begin
|
|
||||||
apply pi_fin_two_equiv,
|
|
||||||
end
|
|
||||||
|
|
||||||
/-
|
|
||||||
Äquivalenz als Vektorräume schreibt man als `ℝ`-lineare Äquivalenz `≃ₗ[ℝ]`.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Zeige dass das Produkt `ℝ × ℝ` und `ℝ²` isomorph sind als `ℝ`-Vektorräume."
|
|
||||||
: ((Fin 2) → ℝ) ≃ₗ[ℝ] ℝ × ℝ := by
|
|
||||||
sorry
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
universe u
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 8
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Eine Familie von Vektorräumen schreibt man erst einmal als Funktion einer Indexmenge `ι`.
|
|
||||||
-/
|
|
||||||
|
|
||||||
variables {ι : Type u} {V : ι → Type u}
|
|
||||||
|
|
||||||
/-
|
|
||||||
Für einen einzelnen Vektorraum würde man jetzt Instanzen `[add_comm_monoid V] [module K V]`
|
|
||||||
definieren. Lean-Instanzen-Manager versteht hier `∀`-Ausdrücke:
|
|
||||||
-/
|
|
||||||
|
|
||||||
variables [∀i, add_comm_monoid (V i)] [∀i, module K (V i)]
|
|
||||||
|
|
||||||
/-
|
|
||||||
Ein externes Produkt von Vektorräumen schreibt man einfach mit `\\Pi`, also `Π i, V i`.
|
|
||||||
|
|
||||||
Lean kann aus den Ausdrücken oben dann automatisch herausfinden, dass `Π i, V i`
|
|
||||||
ein `K`-Vektorraum ist:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"Sei `U` ein `K`-Vektorraum und `fᵢ : U → Vᵢ` eine Familie von `K`-lineare Abbildungen
|
|
||||||
in `K`-Vektorräume. Dann gibt es genau eine Abbildung `f : U → (Π i, V i)`, die mit
|
|
||||||
allen kommutiert."
|
|
||||||
{K U : Type u} [Field K] {ι : Type u} {V : ι → Type u}
|
|
||||||
[∀ i, AddCommMonoid (V i)] [∀ i, Module K (V i)]
|
|
||||||
[AddCommMonoid U] [Module K U]
|
|
||||||
(f : ∀ i, U →ₗ[K] (V i)) : U →ₗ[K] (∀ i, V i) := by
|
|
||||||
sorry
|
|
||||||
-- { to_fun := λv i, f i v,
|
|
||||||
-- map_add' :=
|
|
||||||
-- begin
|
|
||||||
-- intros,
|
|
||||||
-- funext,
|
|
||||||
-- simp,
|
|
||||||
-- end,
|
|
||||||
-- map_smul' :=
|
|
||||||
-- begin
|
|
||||||
-- intros,
|
|
||||||
-- funext,
|
|
||||||
-- simp,
|
|
||||||
-- end }
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Module2"
|
|
||||||
Level 9
|
|
||||||
|
|
||||||
Title "Lineare Abbildung"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
universe u
|
|
||||||
|
|
||||||
variable {K : Type u} [Field K]
|
|
||||||
variable {ι : Type u} {V : ι → Type u}
|
|
||||||
variable [∀i, AddCommMonoid (V i)] [∀i, Module K (V i)]
|
|
||||||
|
|
||||||
/-
|
|
||||||
Ein externes Summe von Vektorräumen schreibt man mit `\Pi\0`, also `Π₀ i, V i`.
|
|
||||||
Das Suffix `_₀` wird in Mathlib häufig dafür verwendet "endlichen Support" zu bezeichnen.
|
|
||||||
|
|
||||||
-/
|
|
||||||
example : Module K (Π₀ i, V i) := inferInstance
|
|
||||||
|
|
||||||
variable {U : Type u} [AddCommMonoid U] [Module K U]
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"" : True := by
|
|
||||||
sorry
|
|
||||||
|
|
||||||
-- -- :(
|
|
||||||
-- variable [decidable_eq ι]
|
|
||||||
-- variable [Π (i : ι) (x : V i), decidable (x ≠ 0)]
|
|
||||||
|
|
||||||
-- def my_sum_map (f : Π i, V i →ₗ[K] U) : (Π₀ i, V i) →ₗ[K] U :=
|
|
||||||
-- { to_fun := λ x, x.sum (λ i, (f i)),
|
|
||||||
-- map_add' :=
|
|
||||||
-- begin
|
|
||||||
-- intros,
|
|
||||||
-- funext,
|
|
||||||
-- sorry,
|
|
||||||
-- end,
|
|
||||||
-- map_smul' :=
|
|
||||||
-- begin
|
|
||||||
-- intros,
|
|
||||||
-- funext,
|
|
||||||
-- simp,
|
|
||||||
-- sorry
|
|
||||||
-- end }
|
|
||||||
|
|
||||||
-- Statement
|
|
||||||
-- "Sei `U` ein `K`-Vektorraum und `fᵢ : Vᵢ → U` eine Familie von `K`-lineare Abbildungen
|
|
||||||
-- in `K`-Vektorräume. Dann gibt es genau eine Abbildung `f : (Π₀ i, V i) → U`, die mit
|
|
||||||
-- allen kommutiert."
|
|
||||||
-- (f : ∀ i, V i →ₗ[K] U) :
|
|
||||||
-- ∃! (g : (Π₀ i, V i) →ₗ[K] U), (∀ i v, f i v = g (dfinsupp.single i v)) :=
|
|
||||||
-- by
|
|
||||||
-- let g := my_sum_map f,
|
|
||||||
-- use g,
|
|
||||||
-- constructor,
|
|
||||||
-- { simp,
|
|
||||||
-- intros,
|
|
||||||
-- sorry },
|
|
||||||
-- { intros g' h,
|
|
||||||
-- apply linear_map.ext,
|
|
||||||
-- intro x,
|
|
||||||
-- sorry
|
|
||||||
-- -- change (λ i, g' x i) = λ i, f i x, -- Wieso?
|
|
||||||
-- -- funext,
|
|
||||||
-- -- symmetry,
|
|
||||||
-- -- apply h,
|
|
||||||
-- }
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
- `trivial` uses a bunch of other tactics:
|
|
||||||
(contradiction, assumption, rfl, decide, True.intro, And.intro)
|
|
||||||
so it's maybe not a good candidate to introduce at the beginning of the level.
|
|
||||||
- Ringschluss (tfae) is not in mathlib4 yet.
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import Adam.Levels.Numbers.L01_PNat
|
|
||||||
import Adam.Levels.Numbers.L02_PNat
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Numbers"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title ""
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
-- Level name : Positive natürliche Zahlen
|
|
||||||
|
|
||||||
import data.pnat.basic
|
|
||||||
|
|
||||||
/-
|
|
||||||
In diesem Level lernst du neben `ℕ` weitere Arten von
|
|
||||||
Zahlen kennen: `ℕ+`,`ℤ`, `ℚ`, `ℝ`, `ℂ`.
|
|
||||||
|
|
||||||
Manchmal sieht man in der Literatur Diskussionen, ob die natürlichen Zahlen jetzt bei `0` oder `1`
|
|
||||||
anfangen, wobei zumindest in der formalisierten Mathematik (z.B. ZFC-Mengenlehre)
|
|
||||||
eigentlich immer `ℕ = {0, 1, 2, 3, …}` definiert wird.
|
|
||||||
|
|
||||||
So ist auch in Lean `1` als `0.succ` und `2 = 1.succ = 0.succ.succ` definiert und
|
|
||||||
Lean hat eine separate Notation `ℕ+` (oder `pnat`) für alle *positiven* natürlichen Zahlen.
|
|
||||||
|
|
||||||
Dies ist als Sub-Typ von `ℕ` definiert:
|
|
||||||
`def pnat := {n : ℕ // 0 < n}`
|
|
||||||
|
|
||||||
ein Element `(p : ℕ+)` besteht also aus einer natürlichen Zahl `(p.val : ℕ)`
|
|
||||||
(oder auch `p.1`, wobei `p.val` bevorzugt ist) sowie einem Beweis, dass diese positiv ist,
|
|
||||||
`p.property` (oder `p.2`).
|
|
||||||
|
|
||||||
Solche Strukturen mit mehr als einem Feld kann man in Lean mit dem anonymen Konstruktor `⟨_, _⟩`
|
|
||||||
erstellen, wie du schon einmal beim `∃` gesehen hast: `(⟨n, h⟩ : ℕ+)`
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
(a : ℕ+) : (a : ℕ) ≠ 0 := by
|
|
||||||
apply ne_of_gt
|
|
||||||
rcases a with ⟨a, ha⟩
|
|
||||||
assumption
|
|
||||||
|
|
||||||
|
|
||||||
-- -/
|
|
||||||
|
|
||||||
-- /- Hint : a.property
|
|
||||||
-- `have ha := a.property` speichert die `ℕ+`-Eigenschaft dass `0 < a.val`
|
|
||||||
-- gilt als neue Variable.
|
|
||||||
-- -/
|
|
||||||
|
|
||||||
-- /- Hint : ne_of_lt/ne_of_gt
|
|
||||||
-- `a < b → a ≠ b`
|
|
||||||
-- oder
|
|
||||||
-- `a < b → b ≠ a`
|
|
||||||
|
|
||||||
-- alternativ kannst du auch mit `symmetry` ein symmetrischen Goal drehen.
|
|
||||||
-- -/
|
|
||||||
|
|
||||||
-- /- Lemma : no-side-bar
|
|
||||||
-- Beweise.
|
|
||||||
-- -/
|
|
||||||
-- example (a : ℕ+) : (a : ℕ) ≠ 0 :=
|
|
||||||
-- begin
|
|
||||||
-- have ha := a.property,
|
|
||||||
-- symmetry,
|
|
||||||
-- apply ne_of_lt,
|
|
||||||
-- exact ha,
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- /- Axiom : ne_of_lt
|
|
||||||
-- `a < b → a ≠ b`.
|
|
||||||
-- -/
|
|
||||||
|
|
||||||
-- /- Axiom : ne_of_gt
|
|
||||||
-- `a < b → b ≠ a`.
|
|
||||||
-- -/
|
|
||||||
|
|
||||||
-- /- Tactic : symmetry
|
|
||||||
-- Dreht ein symmetrisches Goal wie `A = B`, `A ≠ B`, `A ↔ B`, ...
|
|
||||||
-- -/
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Numbers"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title ""
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Das Lemma, das du gerade bewiesen hast, findest du als `pnat.ne_zero`
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
""
|
|
||||||
(a b : ℕ+) : (a : ℕ) * b ≠ 0 := by
|
|
||||||
by_contra h
|
|
||||||
rw [Nat.mul_eq_zero] at h
|
|
||||||
cases h
|
|
||||||
have := PNat.ne_zero a
|
|
||||||
contradiction
|
|
||||||
have := PNat.ne_zero b
|
|
||||||
contradiction
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import Adam.Levels.Predicate.L01_Ring
|
|
||||||
import Adam.Levels.Predicate.L02_Rewrite
|
|
||||||
import Adam.Levels.Predicate.L03_Rewrite
|
|
||||||
import Adam.Levels.Predicate.L04_Ring
|
|
||||||
import Adam.Levels.Predicate.L05_Rfl
|
|
||||||
import Adam.Levels.Predicate.L06_Exists
|
|
||||||
import Adam.Levels.Predicate.L07_Exists
|
|
||||||
import Adam.Levels.Predicate.L08_Forall
|
|
||||||
import Adam.Levels.Predicate.L09_PushNeg
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Title "Quantus"
|
|
||||||
|
|
||||||
Introduction "Auf dem Schwestermond Quantus erwartet Euch bereits ein großer Ansammlung von Formalosopheninnen. Sie reden alle wild durcheinander und Ihr habt Probleme, Euch überhaupt Gehör zu verschaffen. Robo produziert schließlich ein lautes Gong-Geräusch, das sie kurzzeitig zur Ruhe bringt.
|
|
||||||
|
|
||||||
**Du**: Wir haben einen Brief für Eure Königin. Könntet Ihr uns zu Eurer Königin führen?
|
|
||||||
|
|
||||||
**Alle** *(im Chor)*: Wir sind schon alle hier!
|
|
||||||
|
|
||||||
**Du**: Ok. Und wer von Euch ist die Königin?
|
|
||||||
|
|
||||||
Nun herrscht betretenes Schweigen. Alle zucken mit den Schultern.
|
|
||||||
|
|
||||||
**Du**: Habt Ihr überhaupt eine Königin?
|
|
||||||
|
|
||||||
**Alle** *(im Chor)*: Ja, ja. Wir haben eine Königen, wir haben eine Königen.
|
|
||||||
|
|
||||||
**Robo** *(zu dir)*: Ich fasse mal zusammen. Es existiert eine Königen, aber keiner weiß, wer sie ist …
|
|
||||||
|
|
||||||
**Du**: Ist das nicht ein Widerspruch?
|
|
||||||
|
|
||||||
**Robo**: Fragst du, du als Mathematiker? Nein, das ist kein Widerspruch. Das ist einfach eine „reine Existenzaussage“.
|
|
||||||
|
|
||||||
Du bist dir nicht ganz sicher, wie ernst er das meint.
|
|
||||||
|
|
||||||
**Du**: Dann ich schlage vor, wir übergeben das Päckchen einfach an *alle* Bewohner. Dann haben wir es ja insbesondere der Königin übergeben.
|
|
||||||
|
|
||||||
**Du** *(in die Menge*): Wir haben Euch ein Päckchen von Implis gebracht. Hier, das ist für Euch.
|
|
||||||
|
|
||||||
Robo spuckt es aus, wirft es in die Menge, und die Formalosophinnen reißen es auf. Darin befinden sich ein paar loser Seiten, die sie sofort eingehend studieren.
|
|
||||||
|
|
||||||
Zwei Minuten später liegen die Seiten wieder bei Euch. Es sind wieder mathematische Probleme. Und die Formalosophinnen wollen sehen, wie Ihr sie löst.
|
|
||||||
"
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
--set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Natürliche Zahlen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"Du schaust dir die erste Seite an."
|
|
||||||
|
|
||||||
Statement (x y : ℕ) : (x + y) ^ 2 = x ^ 2 + 2 * x * y + y ^ 2 := by
|
|
||||||
Hint "**Du**: Das ist doch Schulmathematik! Man rechnet das einfach aus,
|
|
||||||
indem man die Terme umsortiert.
|
|
||||||
|
|
||||||
**Robo**: Wenn die Gleichung stimmt, kannst du auf Leansch sogar einfach mit `ring` beweisen, dass das so ist.
|
|
||||||
|
|
||||||
**Du**: Aber `ℕ` ist doch gar kein Ring?
|
|
||||||
|
|
||||||
**Robo**: `ring` funktioniert sogar für sogenannte Halbringe. Ich glaube, man sagt `ring`, weil es in (kommutativen) Ringen am besten funktioniert.
|
|
||||||
"
|
|
||||||
ring
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
""
|
|
||||||
|
|
||||||
-- TODO: Modifiy ring so it does not show info about using ring_nf.
|
|
||||||
NewTactic ring ring_nf
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Rewrite"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
""
|
|
||||||
|
|
||||||
Statement (a b c d : ℕ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c := by
|
|
||||||
Hint "**Du**: Schau mal, dieses Problem sieht so ähnlich aus wie eines, das wir auf *Implis* schon gelöst hatten.
|
|
||||||
Nur, das hier jetzt Gleichheiten von Zahlen statt Genau-Dann-Wenn-Aussagen stehen!
|
|
||||||
|
|
||||||
**Robo**: Richtig. Und im Grunde macht das gar keinen Unterscheid.
|
|
||||||
Du kannst `=` und `↔` praktisch mit `rw` praktisch gleich behandeln."
|
|
||||||
|
|
||||||
Hint (hidden := true) "**Du**: Also auch `rw [hₓ]` und `rw [← hₓ]`?
|
|
||||||
|
|
||||||
**Robo**: Probiers doch einfach."
|
|
||||||
rw [h₁]
|
|
||||||
Hint (hidden := true) "**Du**: Wie war das nochmals mit rückwärts umschreiben?
|
|
||||||
|
|
||||||
**Robo**: `←` ist `\\l`. Und dann `rw [← hₓ]`"
|
|
||||||
rw [←h₂]
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
""
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Rewrite"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
""
|
|
||||||
|
|
||||||
Statement
|
|
||||||
"
|
|
||||||
$$
|
|
||||||
\\begin{aligned}
|
|
||||||
a &= b \\\\
|
|
||||||
a + a ^ 2 &= b + 1 \\\\
|
|
||||||
\\vdash b + b ^ 2 &= b + 1
|
|
||||||
\\end{aligned}
|
|
||||||
$$
|
|
||||||
"
|
|
||||||
(a b : ℕ) (h : a = b) (g : a + a ^ 2 = b + 1) : b + b ^ 2 = b + 1 := by
|
|
||||||
Hint "**Du**: Hier muss man, glaube ich, einfach in Annahme `{g}` die Variable `{a}` durch `{b}` ersetzen.
|
|
||||||
|
|
||||||
**Robo**: Genau! Das machst du mit `rw [{h}] at {g}`."
|
|
||||||
rw [h] at g
|
|
||||||
Hint (hidden := true) "**Robo**: Schau mal durch die Annahmen."
|
|
||||||
assumption
|
|
||||||
|
|
||||||
Conclusion "
|
|
||||||
**Robo**: Noch ein Trick: Mit `rw [h] at *` kann man gleichzeitig mittels `h` **alle** Annahmen und das Goal umschreiben.
|
|
||||||
"
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 4
|
|
||||||
|
|
||||||
Title "Natürliche Zahlen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
""
|
|
||||||
|
|
||||||
Statement
|
|
||||||
(x y z : ℕ) (h : x = 2 * y + 1) (g : z = 3 * y + 1): x ^ 2 = 4 * y ^ 2 + z + y := by
|
|
||||||
Hint "**Du**: Ich vermute, wenn ich zuerst alles so umschreibe, dass
|
|
||||||
das Beweisziel nur noch rechnen und umsortieren zu beweisen ist, erledigt `ring` den Rest!
|
|
||||||
|
|
||||||
**Robo**: Genau. Und noch ein Trick: Zwei Schritte `rw [h₁]` und `rw [h₂]` kann man zu einem einzigen Schritt zusammenfassen: `rw [h₁, h₂]`."
|
|
||||||
rw [h, g]
|
|
||||||
ring
|
|
||||||
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
""
|
|
||||||
|
|
||||||
NewTactic ring rw
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 5
|
|
||||||
|
|
||||||
Title "Definitionally equal"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Beim nächsten Problem bekommt ihr ausnahmsweise Hilfe vom Publikum.
|
|
||||||
|
|
||||||
**Alle**: `rfl`, `rfl`, …
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement : 1 + 1 = 2 := by
|
|
||||||
Hint "**Du**: Wieso nicht `ring`?
|
|
||||||
|
|
||||||
**Robo**: Klar, `ring` würde normalerweise auch funktioneren. Aber ich würde mich hier dem Mehrheitswillen beugen …"
|
|
||||||
rfl
|
|
||||||
|
|
||||||
OnlyTactic rfl
|
|
||||||
|
|
||||||
Conclusion
|
|
||||||
"
|
|
||||||
**Robo**: Der Grund, warum hier ausnahmsweise auch mal `rfl` funktioniert hat, ist, dass auf beiden Seiten tatsächlich *per Definition* dasselbe steht. Das soll heißen, wenn man links in `1 + 1` die Definition von `1` und `+ 1` einsetzt, und rechts die Definition von `2`, dann erhält man *buchstäblich* dasselbe (nämlich `(0.succ).succ`).
|
|
||||||
|
|
||||||
**Du**: Na schön. Muss ich mir jetzt diese Definition von `2` merken?
|
|
||||||
|
|
||||||
**Robo**: Ich glaube eher nicht.
|
|
||||||
"
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 6
|
|
||||||
|
|
||||||
Title "Gerade/Ungerade"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Ihr habt nun alle Fragen aus dem königlichen Päckchen beantwortet, und die Formalosophinnen applaudieren. Dann wollen Sie aber auch noch ein paar Fragen stellen, aber sie können sich nicht einigen, welche.
|
|
||||||
Ihr heute abwechselnd die Rufe „Even“ und „Odd“ aus der Menge heraus. Deshalb zeigt dir Robo vorsichtshalber schon einmal die entsprechenden Definitionen an:
|
|
||||||
|
|
||||||
```
|
|
||||||
def Even (n : ℕ) : Prop := ∃ r, n = r + r
|
|
||||||
```
|
|
||||||
|
|
||||||
und
|
|
||||||
|
|
||||||
```
|
|
||||||
def Odd (n : ℕ) : Prop := ∃ r, n = 2 * r + 1
|
|
||||||
```
|
|
||||||
|
|
||||||
Schließlich taucht von irgendwo aus der Menge folgendes Papier auf:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement even_square (n : ℕ) (h : Even n) : Even (n ^ 2) := by
|
|
||||||
Hint "**Robo**: Wie du oben siehst, ist `Even n` dadurch definiert,
|
|
||||||
dass ein `r` existiert so dass `r + r = n` ist. Am besten
|
|
||||||
öffnest du diese Definition mit `unfold Even at *` einmal.
|
|
||||||
Dann siehst du besser, was los ist."
|
|
||||||
Branch
|
|
||||||
unfold Even
|
|
||||||
Hint "Robo**: Am besten machst du auch noch `unfold Even at h`, damit du verstehst, was los ist."
|
|
||||||
unfold Even at *
|
|
||||||
Hint "**Du**: Also von `{h}` weiß ich jetzt, dass ein `r` existiert, so dass `r + r = n` …
|
|
||||||
|
|
||||||
**Robo**: Mit `rcases h with ⟨r, hr⟩` kannst du dieses `r` tatsächlich einführen."
|
|
||||||
rcases h with ⟨r, hr⟩
|
|
||||||
Hint "**Du**: Und jetzt muss ich eine passende Zahl finden, so dass `x + x = n^2`?
|
|
||||||
|
|
||||||
**Robo**: Genau. Und mit `use _` gibst du diese Zahl an."
|
|
||||||
Hint (hidden := true) "**Robo**: Also sowas ähnliches wie `use 4 * r ^ 3`, aber ich kann
|
|
||||||
dir leider nicht sagen, welche Zahl passt.
|
|
||||||
"
|
|
||||||
Branch
|
|
||||||
rw [hr]
|
|
||||||
Hint "**Robo**: Das geht auch, jetzt musst du aber wirklich `use` verwenden."
|
|
||||||
use 2 * r ^ 2
|
|
||||||
Hint (hidden := true) "**Du**: Ah, und jetzt `ring`!"
|
|
||||||
ring
|
|
||||||
use 2 * r ^ 2
|
|
||||||
Hint "**Du**: Ah, und jetzt `ring`!
|
|
||||||
|
|
||||||
**Robo**: Aber zuerst musst du noch mit
|
|
||||||
`rw` `n` durch `r + r` ersetzen, da `ring` das sonst nicht weiß."
|
|
||||||
rw [hr]
|
|
||||||
ring
|
|
||||||
|
|
||||||
-- TODO: [Comment] For me the expected behaviour of `(strict := true)` would
|
|
||||||
-- be that it distinguishes between the defEq states while `(strict := false)`
|
|
||||||
-- would show the hint regardless of a `unfold Even`.
|
|
||||||
|
|
||||||
NewTactic unfold use
|
|
||||||
NewDefinition Even Odd
|
|
||||||
|
|
||||||
Conclusion "Applaus!"
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 7
|
|
||||||
|
|
||||||
Title "Gerade/Ungerade"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Sofort taucht das nächste Blatt auf. Anscheinend hatten sie sich auf einen Kompromiss geeinigt.
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (n : ℕ) (h : Odd n) : Odd (n ^ 2) := by
|
|
||||||
Hint (hidden := true) "**Robo**: mit `rcases h with ⟨r, hr⟩` kannst du wieder
|
|
||||||
das `r` nehmen, das laut Annahme existieren muss.
|
|
||||||
|
|
||||||
**Robo**: Oder aber, du fängst mit `unfold Odd at *` an."
|
|
||||||
Branch
|
|
||||||
unfold Odd
|
|
||||||
Hint "**Robo**: Mit `unfold Odd at *` öffnest du alle Definitionen von `Odd`."
|
|
||||||
unfold Odd at *
|
|
||||||
Branch
|
|
||||||
unfold Odd at *
|
|
||||||
Hint (hidden := true) "**Robo**: mit `rcases h with ⟨r, hr⟩` kannst du wieder
|
|
||||||
das `r` nehmen, das laut Annahme existieren muss."
|
|
||||||
rcases h with ⟨r, hr⟩
|
|
||||||
Hint "**Robo**: Ich hab noch einen Trick auf Lager:
|
|
||||||
Wenn du jetzt noch nicht weißt, welche Zahl du einsetzen musst, könntest
|
|
||||||
du schon jetzt mit `rw [{hr}]` weitermachen …"
|
|
||||||
Branch
|
|
||||||
rw [hr]
|
|
||||||
Hint "**Robo**: Wenn du jetzt `ring` brauchst, dann schreibt es einfach alles in
|
|
||||||
Normalform um, das hilft beim Vergleichen."
|
|
||||||
ring
|
|
||||||
Hint "**Du**: Was bedeutet `ring_nf`?
|
|
||||||
|
|
||||||
**Robo**: Wenn man `ring` nicht am Schluss benützt, sollte man stattdessen `ring_nf`
|
|
||||||
schreiben, aber die funktionieren praktisch gleich."
|
|
||||||
use 2 * (r + r ^ 2)
|
|
||||||
ring
|
|
||||||
rcases h with ⟨r, hr⟩
|
|
||||||
Hint "**Robo**: Ich hab noch einen Trick auf Lager:
|
|
||||||
Wenn du jetzt noch nicht weißt, welche Zahl du einsetzen musst, könntest
|
|
||||||
Du schon jetzt mit `rw [{hr}]` weitermachen…"
|
|
||||||
Branch
|
|
||||||
rw [hr]
|
|
||||||
Hint "**Robo**: Wenn du jetzt `ring` brauchst, dann schreibt es einfach alles in
|
|
||||||
Normalform um, das hilft beim Vergleichen."
|
|
||||||
ring
|
|
||||||
Hint "**Du**: Was bedeutet `ring_nf`?
|
|
||||||
|
|
||||||
**Robo**: Wenn man `ring` nicht am Schluss benützt, sollte man stattdessen `ring_nf`
|
|
||||||
schreiben, aber die funktionieren praktisch gleich."
|
|
||||||
use 2 * (r + r ^ 2)
|
|
||||||
rw [hr]
|
|
||||||
ring
|
|
||||||
-- TODO: Allow `ring_nf` as part of `ring`.
|
|
||||||
|
|
||||||
Conclusion "Applaus!"
|
|
||||||
|
|
||||||
-- TODO: THis level would be a good example where a `Hint (defeq := true)` would be desirable
|
|
||||||
-- in order to reduce the number of hints that are duplicated.
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
set_option tactic.hygienic false
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 8
|
|
||||||
|
|
||||||
Title "Für alle"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Nach längerem Durcheinander findet ein weiteres Blatt aus der Menge zu Euch.
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Zum `∃` gehört auch das \"für alle\" `∀` (`\\forall`).
|
|
||||||
|
|
||||||
-- Der Syntax ist `∀ (n : ℕ), 0 ≤ n` also wie beim `∃` trennt ein Komma die Annahmen von der Aussage.
|
|
||||||
|
|
||||||
-- Eine `∀`-Aussage in den Annahmen verhält sich so wie ein Lemma. Das heisst man kann
|
|
||||||
-- auch diese mit `apply` und `rw` anwenden, je nachdem was die Aussage nach dem Komma ist.
|
|
||||||
|
|
||||||
-- Also folgende Annahme und Lemma sind genau :
|
|
||||||
-- - `(le_square : ∀ (n : ℕ), n ≤ n^2)`
|
|
||||||
-- - `lemma le_square (n : ℕ) : n ≤ n^2`
|
|
||||||
|
|
||||||
-- Ein `∀` im Goal kann man mit `intro` angehen, genau wie bei einer Implikation `→`.
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: 1-2 Aufgaben mehr.
|
|
||||||
|
|
||||||
Statement : ∀ (x : ℕ), (Even x) → Odd (1 + x) := by
|
|
||||||
Hint "**Du**: Das `∀` heisst sicher \"für alle\".
|
|
||||||
|
|
||||||
**Robo**: Und man schreibt `\\forall`. Ein `∀ x, …` im Beweisziel kannst du wie eine
|
|
||||||
Implikation mit `intro x` angehen."
|
|
||||||
intro x h
|
|
||||||
unfold Even at h
|
|
||||||
unfold Odd
|
|
||||||
rcases h with ⟨y, hy⟩
|
|
||||||
use y
|
|
||||||
rw [hy]
|
|
||||||
ring
|
|
||||||
|
|
||||||
Conclusion "Wieder werdet Ihr mit einem Applaus belohnt, und die Formalosophinnen beratschlagen sich, was sie Euch noch vorlegen wollen."
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Predicate"
|
|
||||||
Level 9
|
|
||||||
|
|
||||||
Title "PushNeg"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Nach langem Hin und Her einigen sie sich schließlich auf folgende Frage:
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Zum Schluss, immer wenn man irgendwo eine Verneinung `¬∃` oder `¬∀` sieht (`\\not`), kann man
|
|
||||||
-- mit `push_neg` das `¬` durch den Quantor hindurchschieben.
|
|
||||||
|
|
||||||
-- Das braucht intern die Lemmas
|
|
||||||
|
|
||||||
-- - `not_exists (A : Prop) : ¬ (∃ x, A) ↔ ∀x, (¬A)`
|
|
||||||
-- - `not_forall (A : Prop) : ¬ (∀ x, A) ↔ ∃x, (¬A)`
|
|
||||||
|
|
||||||
-- (welche man auch mit `rw` explizit benutzen könnte.)
|
|
||||||
|
|
||||||
open Nat
|
|
||||||
|
|
||||||
Statement : ¬ ∃ (n : ℕ), ∀ (k : ℕ) , Odd (n + k) := by
|
|
||||||
Hint "**Du**: Ich würde gern diese Negation `¬` am Quantor vorbeischieben.
|
|
||||||
|
|
||||||
**Robo**: `push_neg` macht genau das! Oder du könntest `rw` mit den folgenden Lemmas verwenden:
|
|
||||||
|
|
||||||
```
|
|
||||||
not_exists (A : Prop) : ¬ (∃ x, A) ↔ ∀x, (¬A)
|
|
||||||
not_forall (A : Prop) : ¬ (∀ x, A) ↔ ∃x, (¬A)
|
|
||||||
```
|
|
||||||
"
|
|
||||||
Branch
|
|
||||||
unfold Odd
|
|
||||||
push_neg
|
|
||||||
Hint "**Robo**: Dieser Lösungsweg scheint mir etwas zu schwierig.
|
|
||||||
Ich würde nochmal zurückgehen und schauen,
|
|
||||||
dass du irgendwie `¬Odd` erhältst.
|
|
||||||
Das kannst du dann mit `rw [←even_iff_not_odd]`
|
|
||||||
zu `Even` umwandeln."
|
|
||||||
push_neg
|
|
||||||
intro n
|
|
||||||
Hint "**Robo**: Jetzt brauchst du eine Zahl mit `use`, und danach vermutlich das Lemma `←even_iff_not_odd` brauchen.
|
|
||||||
|
|
||||||
**Du**: Könnte ich jetzt schon `rw [←even_iff_not_odd]` anwenden?
|
|
||||||
|
|
||||||
**Robo**: Nee, `rw` kann nicht innerhalb von Quantoren umschreiben.
|
|
||||||
|
|
||||||
**Du**: Aber wie würde ich das machen?
|
|
||||||
|
|
||||||
**Robo**: Zeig ich dir später, nicht hier vor großem Publikum.
|
|
||||||
Ich würde jetzt lieber mit `use` eine richtige Zahl angeben, und danach umschreiben."
|
|
||||||
Branch
|
|
||||||
use n + 2
|
|
||||||
Hint "**Robo**: Gute Wahl! Jetzt kannst du `←even_iff_not_odd` verwenden."
|
|
||||||
Branch
|
|
||||||
use n + 4
|
|
||||||
Hint "**Robo**: Gute Wahl! Jetzt kannst du `←even_iff_not_odd` verwenden."
|
|
||||||
use n
|
|
||||||
Hint "**Robo**: Gute Wahl! Jetzt kannst du `←even_iff_not_odd` verwenden."
|
|
||||||
rw [←even_iff_not_odd]
|
|
||||||
-- TODO: if I write `tauto` here, I get a weird error
|
|
||||||
unfold Even
|
|
||||||
use n
|
|
||||||
--ring
|
|
||||||
|
|
||||||
NewTactic push_neg
|
|
||||||
NewLemma Nat.even_iff_not_odd Nat.odd_iff_not_even not_exists not_forall
|
|
||||||
|
|
||||||
Conclusion "Die Formalosophinnen sind ganz begeistert.
|
|
||||||
Nachdem sich der Beifall gelegt hat, hast du auch einmal eine Frage.
|
|
||||||
|
|
||||||
**Du**: Kann uns hier irgendjemand vielleicht ein bisschen Orientierung im Formaloversum geben?
|
|
||||||
|
|
||||||
**Alle**: Ja, ja.
|
|
||||||
|
|
||||||
**Du**: Wer denn?
|
|
||||||
|
|
||||||
Die Frage war wieder zu konkret. Betretenes Schweigen.
|
|
||||||
|
|
||||||
**Robo**: Lass nur. Ich schlage vor, wir machen als nächstes einen Ausflug auf den Asteroiden da
|
|
||||||
drüben. Und bevor du fragst – hier ist wieder ein Überblick, was du auf diesem Planeten
|
|
||||||
gelernt hast.
|
|
||||||
|
|
||||||
| | Beschreibung |
|
|
||||||
|:--------------|:----------------------------|
|
|
||||||
| `ℕ` | Die natürlichen Zahlen. |
|
|
||||||
| `∃` | Existential-Quantifier |
|
|
||||||
| `∀` | Forall-Quantifier |
|
|
||||||
| `Even n` | `n` ist gerade |
|
|
||||||
| `Odd n` | `n` ist ungerade |
|
|
||||||
|
|
||||||
| | Taktik | Beispiel |
|
|
||||||
|:------|:--------------------------|:-------------------------------------------------------|
|
|
||||||
| *12ᶜ* | `rw` | Umschreiben mit Gleichungen. |
|
|
||||||
| 13 | `ring` | Löst Gleichungen mit `+, -, *, ^`. |
|
|
||||||
| 14 | `unfold` | Setzt visuell die Bedeutung einer Definition ein. |
|
|
||||||
| 15 | `use` | Um ein `∃` im Goal anzugehen. |
|
|
||||||
| *7ᶜ* | `rcases h with ⟨x, hx⟩` | Um ein `∃` in den Annahmen zu zerlegen. |
|
|
||||||
| *8ᵇ* | `intro` | Um ein `∀` im Goal anzugehen. |
|
|
||||||
| 16 | `push_neg` | Für `¬∃` und `¬∀` im Goal. |
|
|
||||||
|
|
||||||
"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import Adam.Levels.Prime.L01_Dvd
|
|
||||||
-- import Adam.Levels.Prime.L04_Prime
|
|
||||||
-- import Adam.Levels.Prime.L05_Prime
|
|
||||||
-- import Adam.Levels.Prime.L06_ExistsUnique
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Prime"
|
|
||||||
Title "Teilbarkeit"
|
|
||||||
|
|
||||||
Introduction "Ihr schlendert durch die Befestigung ohne direktes Ziel. Und sprecht mit
|
|
||||||
verschiedenen Einwohnern."
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Prime"
|
|
||||||
Level 1
|
|
||||||
|
|
||||||
Title "Teilbarkeit"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Ihr begenet einer Frau, die mit Vorschlaghammer und Schaufel anscheinend an einer Erweiterung
|
|
||||||
ihres Hauses baut. Im gespräch erzählt sie euch wie die Dornenwände gezüchtet wurden vor ihrer
|
|
||||||
Zeit, und über's Wetter und so.
|
|
||||||
|
|
||||||
**Handwerkerin**: (*langer Monolog*) …, und dann gestern habe ich zwei Herren überhört,
|
|
||||||
wie sie an folgender Aufgabe gesessen sind, könnt ihr mir das erklären?
|
|
||||||
"
|
|
||||||
|
|
||||||
-- Die Aussage \"$m$ teilt $n$.\" wird in Lean als `m | n` (`\\|`) geschrieben.
|
|
||||||
|
|
||||||
-- **Wichtig:** `∣` (Teilbarkeit) ist ein spezielles Unicode Symbol, das nicht dem
|
|
||||||
-- senkrechten Strich auf der Tastatur (`|`) entspricht. Man erhält es mit `\\|`.
|
|
||||||
|
|
||||||
-- `m ∣ n` bedeutet `∃ c, n = m * c`, das heisst, man kann damit genau gleich umgehen
|
|
||||||
-- wie mit einem `∃`-Quantifier.
|
|
||||||
|
|
||||||
Statement dvd_add (n m k : ℕ) (h : m ∣ n) (g : m ∣ k) : m ∣ n + k := by
|
|
||||||
Hint "**Robo**: `n ∣ m` bedeutet \"$n$ teilt $m$\", der senkrechte Strich ist allerdings
|
|
||||||
ein spezieller, den man mit `\\|` schreibt.
|
|
||||||
Definiert ist dieses Symbol als `∃ c, n = m * c`.
|
|
||||||
|
|
||||||
**Du**: Dann kann ich direkt `rcases` und `use` verwenden, wie wenns ein `∃` wäre?
|
|
||||||
|
|
||||||
**Robo**: Genau!"
|
|
||||||
Hint (hidden := true) "**Robo**: Fang doch damit an, mit `rcases _ with ⟨x ,hx⟩`
|
|
||||||
alle Hyptothesen aufzuteilen."
|
|
||||||
rcases h with ⟨x, h⟩
|
|
||||||
rcases g with ⟨y, g⟩
|
|
||||||
Hint (hidden := true) "**Robo**: Jetzt musst du mit `use _` eine Zahl angeben so dass
|
|
||||||
`{n} + {k} = {m} * _` gilt."
|
|
||||||
use x + y
|
|
||||||
Hint (hidden := true) "**Du**: Mit ein bisschen umschreiben kann man sicer `ring` verwenden."
|
|
||||||
rw [h, g]
|
|
||||||
ring
|
|
||||||
|
|
||||||
DisabledLemma dvd_add
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Prime"
|
|
||||||
Level 2
|
|
||||||
|
|
||||||
Title "Primzahlen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Als nächstes Begnet ihr einem Lehrer, der nachdenkend an der Sonne sitzt.
|
|
||||||
|
|
||||||
**Lehrer**: Sagt mal, mich hat heute einer meiner Schüler was gefragt,
|
|
||||||
und ich glaube einfach, der ist in so jungen Jahren bereits schlauer als ich.
|
|
||||||
|
|
||||||
Hier etwas Kontext:
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement (p : ℕ) (h : Nat.Prime p) : ∀ (x : ℕ), (x ∣ p) → x = 1 ∨ x = p := by
|
|
||||||
Hint "**Du**: Die einzigen Teiler einer Primzahl sind `1` und `p`, ist das
|
|
||||||
nicht eine der möglichen Definitionen über `ℕ`?
|
|
||||||
|
|
||||||
**Robo**: Doch, oder zumindest fast.
|
|
||||||
Du kannst du mit `rw` und `Nat.prime_def_lt''` eine der Definitionen für `Nat.Prime` einsetzen
|
|
||||||
|
|
||||||
**Du** Könnte ich nicht einfach `unfold Nat.Prime` sagen um mir das anzuschauen.
|
|
||||||
|
|
||||||
**Robo**: Bloss nicht. Das ist so eine Definition, in die du besser nicht hineinschaust!
|
|
||||||
`Nat.Prime p` ist als `Irreducible p` definiert, was wiederum anhand von Einheiten
|
|
||||||
definiert ist… Da verlieren wir uns in Definition die wir im Moment gar nicht brauchen."
|
|
||||||
rw [Nat.prime_def_lt''] at h
|
|
||||||
rcases h with ⟨_, h₂⟩
|
|
||||||
assumption
|
|
||||||
|
|
||||||
NewLemma Nat.prime_def_lt''
|
|
||||||
|
|
||||||
Conclusion "**Du**: Ich sehe, meine \"Definition\" hätte auch `1` als Primzahl deklariert. Gut,
|
|
||||||
dass wir das überprüft haben.
|
|
||||||
|
|
||||||
**Lehrer**: Und jetzt kommen wir zu dem, was mir Kopfschmerzen bereitet."
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import Adam.Metadata
|
|
||||||
import Adam.Options.MathlibPart
|
|
||||||
|
|
||||||
import Adam.ToBePorted
|
|
||||||
|
|
||||||
Game "Adam"
|
|
||||||
World "Prime"
|
|
||||||
Level 3
|
|
||||||
|
|
||||||
Title "Primzahlen"
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
"
|
|
||||||
Der Lehrer erklärt sein Problem.
|
|
||||||
|
|
||||||
**Lehrer**: Und dann fragte der Schüler, wie man denn folgendes herleitet.
|
|
||||||
Und dabei ist das weit über seiner Altersstufe!
|
|
||||||
"
|
|
||||||
|
|
||||||
Statement
|
|
||||||
(p : ℕ) (h₂ : 2 ≤ p): Nat.Prime p ↔ ∀ (a b : ℕ), p ∣ a * b → p ∣ a ∨ p ∣ b := by
|
|
||||||
Hint "**Du**: Naja, mal schauen wie weit man mit `intro` und `constructor` kommt…"
|
|
||||||
constructor
|
|
||||||
intro h a b
|
|
||||||
Hint "**Robo**: Stop! Hier helfe ich dir etwas"
|
|
||||||
apply (Nat.Prime.dvd_mul h).mp
|
|
||||||
intro h
|
|
||||||
rw [Nat.prime_iff]
|
|
||||||
unfold Prime
|
|
||||||
rw [Nat.isUnit_iff, ←and_assoc]
|
|
||||||
constructor
|
|
||||||
constructor
|
|
||||||
linarith
|
|
||||||
linarith
|
|
||||||
assumption
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user