Add introductory levels
commit
7091f8adac
@ -1,3 +1,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
client/dist
|
client/dist
|
||||||
server/build
|
server/build
|
||||||
|
**/lean_packages/
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"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,6 +1,16 @@
|
|||||||
import TestGame.Metadata
|
import TestGame.Metadata
|
||||||
import TestGame.Levels.Level1
|
import TestGame.Levels.Logic.L01_Rfl
|
||||||
import TestGame.Levels.Level2
|
import TestGame.Levels.Logic.L02_Rfl
|
||||||
import TestGame.Levels.Level3
|
import TestGame.Levels.Logic.L03_Assumption
|
||||||
import TestGame.Levels.Level4
|
import TestGame.Levels.Logic.L03b_Assumption
|
||||||
import TestGame.Levels.Level5
|
import TestGame.Levels.Logic.L04_Rewrite
|
||||||
|
import TestGame.Levels.Logic.L05_Apply
|
||||||
|
import TestGame.Levels.Logic.L05b_Apply
|
||||||
|
import TestGame.Levels.Logic.L05c_Apply
|
||||||
|
import TestGame.Levels.Logic.L06_Iff
|
||||||
|
import TestGame.Levels.Logic.L06b_Iff
|
||||||
|
import TestGame.Levels.Logic.L06c_Iff
|
||||||
|
import TestGame.Levels.Logic.L06d_Iff
|
||||||
|
import TestGame.Levels.Logic.L07_And
|
||||||
|
import TestGame.Levels.Logic.L08_Or
|
||||||
|
import TestGame.Levels.Logic.L08b_Or
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 1
|
||||||
|
|
||||||
|
Title "Aller Anfang ist... ein Einzeiler?"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Willkommen zum Lean-Crashkurs wo du lernst wie man mathematische Beweise vom Computer
|
||||||
|
unterstützt und verifiziert schreiben kann.
|
||||||
|
|
||||||
|
Ein Beweis besteht in Lean aus verschiedenen **Taktiken**, welche ungefähr einem
|
||||||
|
logischen Schritt entsprechen, den man auf Papier aufschreiben würde.
|
||||||
|
|
||||||
|
Rechts im **Infoview** siehst den Status des aktuellen Beweis.
|
||||||
|
Du siehst ein oder mehrere offene **Goals** (mit einem `⊢` davor), die du noch zeigen musst.
|
||||||
|
Wenn du eine Taktik hinschreibst, dann versucht Lean diesen Schritt beim
|
||||||
|
ersten offenen Goal zu machen.
|
||||||
|
Wenn der Beweis komplett ist, erscheint \"goals accomplished\".
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement "Zeige `42 = 42`." : 42 = 42 := by
|
||||||
|
rfl
|
||||||
|
|
||||||
|
Message : 42 = 42 =>
|
||||||
|
"Die erste Taktik ist `rfl`, die ein Goal von der Form `A = A` beweist."
|
||||||
|
|
||||||
|
Hint : 42 = 42 =>
|
||||||
|
"Man schreibt eine Taktik pro Zeile, also gib 'rfl' ein gefolgt von ENTER."
|
||||||
|
|
||||||
|
Conclusion "Bravo!"
|
||||||
|
|
||||||
|
Tactics rfl
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 2
|
||||||
|
|
||||||
|
Title "Definitionally equal"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Achtung: `rfl` kann auch Gleichungen beweisen, wenn die beiden Terme Lean-intern gleich
|
||||||
|
definiert sind, auch wenn diese unterschiedlich dargestellt werden.
|
||||||
|
So sind `1 + 1` und `2` per Definition das Gleiche, da sie beide von Lean als `0.succ.succ`
|
||||||
|
gelesen werden.
|
||||||
|
|
||||||
|
Das kann anfänglich verwirrend sein und das Verhalten hängt von der Lean-Implementation ab.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement "Zeige dass eins plus eins zwei ist." : 1 + 1 = 2 := by
|
||||||
|
rfl
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
"
|
||||||
|
Im weiteren führen die meisten anderen Taktiken `refl` automatisch am Ende aus,
|
||||||
|
deshalb musst du dieses häufig gar nicht mehr schreiben.
|
||||||
|
"
|
||||||
|
|
||||||
|
Tactics rfl
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
import Mathlib.Data.Nat.Basic -- TODO
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 4
|
||||||
|
|
||||||
|
Title "Logische Aussagen: `Prop`"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Eine allgemeine logische Aussage definiert man mit `(A : Prop)`. Damit sagt man noch nicht,
|
||||||
|
ob die Aussage `A` wahr oder falsch ist. Mit einer Annahme `(hA : A)` nimmt man an, dass
|
||||||
|
`A` wahr ist: `hA` ist ein Beweis der Aussage `A`.
|
||||||
|
"
|
||||||
|
|
||||||
|
-- TODO: Macht es Sinn mehrere Aufgaben auf einer Seite zu haben?
|
||||||
|
Statement mehr_triviales
|
||||||
|
"
|
||||||
|
Sei `A` eine logische Aussage und angenommen man hat einen Beweis für `A`.
|
||||||
|
Zeige, dass `A` wahr ist.
|
||||||
|
"
|
||||||
|
(A : Prop) (hA : A) : A := by
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Conclusion ""
|
||||||
|
|
||||||
|
Tactics assumption
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
import Mathlib
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 6
|
||||||
|
|
||||||
|
Title "Implikation"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Wie wir schon gesehen haben, wir eine logische Aussage als `(A : Prop)` geschrieben, und
|
||||||
|
die Annahme, dass `A` wahr ist als `(hA : A)`, also `hA` ist sozusagens ein Beweis der
|
||||||
|
Aussage `A`.
|
||||||
|
|
||||||
|
Logische Aussagen können einander implizieren. Wir kennen hauptsächlich zwei Zeichen dafür:
|
||||||
|
`A ↔ B` (`\\iff`) bedeutet \"Genau dann wenn\" und `A → B` (`\\to`) bedeutet \"`A` impliziert `B`\".
|
||||||
|
|
||||||
|
Wenn man Aussage `B` beweisen will und eine Implikationsannahme `(h : A → B)` hat, dann kann man
|
||||||
|
diese mit `apply h` anwenden.
|
||||||
|
Auf Papier würde man schreiben, \"es genügt zu zeigen, dass `A` stimmt, denn `A` impliziert `B`\".
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
"
|
||||||
|
Seien `A`, `B` logische Aussagen, wobei `A` wahr ist und `A` impliziert `B`.
|
||||||
|
Zeige, dass `B` wahr ist.
|
||||||
|
"
|
||||||
|
(A B : Prop) (hA : A) (g : A → B) : B := by
|
||||||
|
apply g
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (hA : A) (g : A → B) : A =>
|
||||||
|
"Nachdem du die Implikation `A → B` angewendet hast, musst du nur noch `A` zeigen,
|
||||||
|
dafür hast du bereits einen Beweis in den Annahmen."
|
||||||
|
|
||||||
|
Tactics apply
|
||||||
|
Tactics assumption
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 7
|
||||||
|
|
||||||
|
Title "Implikation"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Angenommen man hat folgende Implikationen und weiss dass Aussage `A` wahr ist.
|
||||||
|
```
|
||||||
|
A → B ← C
|
||||||
|
↓ ↓
|
||||||
|
D → E → F
|
||||||
|
```
|
||||||
|
Beweise Aussage `F`.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
"
|
||||||
|
Seien `A`, `B` logische Aussagen, wobei `A` wahr ist und `A` impliziert `B`.
|
||||||
|
Zeige, dass `B` wahr ist.
|
||||||
|
"
|
||||||
|
(A B C D E F : Prop) (hA : A) (f : A → B) (g : C → B) (h : B → E)
|
||||||
|
(i : D → E) (k : E → F) (m : C → F) : F := by
|
||||||
|
apply k
|
||||||
|
apply h
|
||||||
|
apply f
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (C : Prop) (D : Prop) (E : Prop) (F : Prop)
|
||||||
|
(hA : A) (f : A → B) (g : C → B) (h : B → E)
|
||||||
|
(i : D → E) (k : E → F) (m : C → F) : C =>
|
||||||
|
"Sackgasse. Probier doch einen anderen Weg."
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (C : Prop) (D : Prop) (E : Prop) (F : Prop)
|
||||||
|
(hA : A) (f : A → B) (g : C → B) (h : B → E)
|
||||||
|
(i : D → E) (k : E → F) (m : C → F) : D =>
|
||||||
|
"Sackgasse. Probier doch einen anderen Weg."
|
||||||
|
|
||||||
|
Tactics apply
|
||||||
|
Tactics assumption
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 8
|
||||||
|
|
||||||
|
Title "Implikation"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Wenn das Goal von der Form `A → B` ist, kann man mit `intro` annehmen, dass `A` wahr ist
|
||||||
|
und das Goal wird zu `B`.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
(A B C : Prop) (f : A → B) (g : B → C) : A → C := by
|
||||||
|
intro hA
|
||||||
|
apply g
|
||||||
|
apply f
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Tactics intro apply assumption
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 9
|
||||||
|
|
||||||
|
Title "Genau dann wenn"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Genau-dann-wenn `A ↔ B` (`\\iff`) besteht aus zwei Implikationen `A → B` und `B → A`.
|
||||||
|
|
||||||
|
Als erstes kann man mit `rw` Annahmen der Form `(h : A ↔ B)` genau gleich wie Gleichungen
|
||||||
|
`(h : a = b)` benützen, um das Goal umzuschreiben.
|
||||||
|
|
||||||
|
Hier also nochmals die Gleiche Aufgabe, aber diesmal mit Iff-Statements von Aussagen anstatt
|
||||||
|
Gleichungen von natürlichen Zahlen.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
"
|
||||||
|
Zeige dass `B ↔ C`.
|
||||||
|
"
|
||||||
|
(A B C D : Prop) (h₁ : C ↔ D) (h₂ : A ↔ B) (h₃ : A ↔ D) : B ↔ C := by
|
||||||
|
rw [h₁]
|
||||||
|
rw [←h₂]
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Tactics rw
|
||||||
|
Tactics assumption
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 10
|
||||||
|
|
||||||
|
Title "Genau dann wenn"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Als nächstes will man oft ein Iff-Statement `A ↔ B` wie zwei einzelne Implikationen
|
||||||
|
`A → B` und `B → A` behandeln.
|
||||||
|
|
||||||
|
Wenn das Goal `A ↔ B` ist, kann man mit der `constructor` Taktik, dieses in die Einzelteile
|
||||||
|
`A → B` und `B → A` zerlegen.
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
"
|
||||||
|
Zeige dass `B ↔ C`.
|
||||||
|
"
|
||||||
|
(A B : Prop) (mp : A → B) (mpr : B → A) : A ↔ B := by
|
||||||
|
constructor
|
||||||
|
assumption
|
||||||
|
assumption
|
||||||
|
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
"
|
||||||
|
Die Taktik `constructor` heisst so, weil `↔` als \"Struktur\" definiert ist, die
|
||||||
|
aus mehreren Einzelteilen besteht: `⟨A → B, B → A⟩`. Man sagt also Lean, es soll versuchen,
|
||||||
|
ob das Goal aus solchen Einzelteilen \"konstruiert\" werden kann.
|
||||||
|
"
|
||||||
|
|
||||||
|
Tactics constructor
|
||||||
|
Tactics assumption
|
||||||
|
|
||||||
|
-- TODO : `case mpr =>` ist mathematisch noch sinnvoll.
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
import Std.Tactic.RCases
|
||||||
|
import Mathlib.Tactic.Cases
|
||||||
|
|
||||||
|
set_option tactic.hygienic false
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 11
|
||||||
|
|
||||||
|
Title "Genau dann wenn"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Umgekehrt, wenn man eine Annahme `(h : A ↔ B)` hat, kann man auf verschiedene
|
||||||
|
Arten die Einzelteile `A → B` und `B → A` extrahieren.
|
||||||
|
|
||||||
|
- mit `rcases h` oder `rcases h with ⟨h₁, h₂⟩` teilt man die Annahme `h` auf. (Im zweiten Fall gibt
|
||||||
|
man explizit an, wie die neuen Annahmen heissen sollen, die Klammern sind `\\<` und `\\>`).
|
||||||
|
|
||||||
|
"
|
||||||
|
Statement
|
||||||
|
(A B : Prop) : (A ↔ B) → (A → B) := by
|
||||||
|
intro h
|
||||||
|
rcases h
|
||||||
|
exact mp
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) : (A ↔ B) → A → B =>
|
||||||
|
"Angefangen mit `intro h` kannst du annehmen, dass `(h : A ↔ B)` wahr ist."
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
"
|
||||||
|
Anstatt
|
||||||
|
```
|
||||||
|
intro h
|
||||||
|
rcases h with ⟨h₁, h₂⟩
|
||||||
|
```
|
||||||
|
kann man direkt `intro ⟨h₁, h₂⟩` schreiben.
|
||||||
|
Wie du schon gesehen hast, sind diese Klammern `⟨⟩` Lean's Syntax für eine Struktur aus
|
||||||
|
mehreren Teilen.
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
|
Tactics intro apply rcases assumption
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 12
|
||||||
|
|
||||||
|
Title "Genau dann wenn"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Man kann auch die einzelnen Richtungen benützen, ohne `h` selber zu verändern:
|
||||||
|
|
||||||
|
- `h.1` und `h.2` sind direkt die einzelnen Richtungen. Man kann also z.B. mit `apply h.1` die
|
||||||
|
Implikation `A → B` auf ein Goal `B` anwenden.
|
||||||
|
- `h.mp` und `h.mpr` sind die bevorzugten Namen anstatt `.1` und `.2`. \"mp\" kommt von
|
||||||
|
\"Modus Ponens\", aber das ist hier irrelevant.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
"
|
||||||
|
Benütze nur `apply` und `assumption` um das gleiche Resultat zu zeigen.
|
||||||
|
"
|
||||||
|
(A B C : Prop) (h : A ↔ B) (g : B → C) : A → C := by
|
||||||
|
intro hA
|
||||||
|
apply g
|
||||||
|
apply h.mp
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (C : Prop) (h : A ↔ B) (g : B → C) (hA : A) : B =>
|
||||||
|
"Mit `apply h.mp` kannst du nun die Implikation `A → B` anwenden."
|
||||||
|
|
||||||
|
Tactics apply
|
||||||
|
Tactics assumption
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
import TestGame.Metadata
|
||||||
|
import Std.Tactic.RCases
|
||||||
|
|
||||||
|
set_option tactic.hygienic false
|
||||||
|
|
||||||
|
Game "TestGame"
|
||||||
|
World "TestWorld"
|
||||||
|
Level 13
|
||||||
|
|
||||||
|
Title "Und"
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
"
|
||||||
|
Das logische UND `A ∧ B` (`\\and`) funktioniert sehr ähnlich zum Iff (`↔`).
|
||||||
|
Grund dafür ist, dass `A ∧ B` auch eine Struktur aus zwei Teilen `⟨A, B⟩` ist.
|
||||||
|
|
||||||
|
Man can also genau gleich `constructor` und `rcases` anwenden, ebenso kann man
|
||||||
|
`.1` und `.2` für die Einzelteile brauchen, diese heissen lediglich
|
||||||
|
`h.left` und `h.right` anstatt `.mp` und `.mpr`.
|
||||||
|
"
|
||||||
|
|
||||||
|
Statement
|
||||||
|
(A B : Prop) : (A ∧ (A → B)) ↔ (A ∧ B) := by
|
||||||
|
constructor
|
||||||
|
intro h
|
||||||
|
rcases h with ⟨h₁, h₂⟩
|
||||||
|
constructor
|
||||||
|
assumption
|
||||||
|
apply h₂
|
||||||
|
assumption
|
||||||
|
intro h
|
||||||
|
rcases h with ⟨h₁, h₂⟩
|
||||||
|
constructor
|
||||||
|
assumption
|
||||||
|
intro
|
||||||
|
assumption
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) : A ∧ (A → B) ↔ A ∧ B =>
|
||||||
|
"`↔` oder `∧` im Goal kann man mit `constructor` aufteilen."
|
||||||
|
|
||||||
|
-- if they don't use `intro ⟨_, _⟩`.
|
||||||
|
Message (A : Prop) (B : Prop) (h : A ∧ (A → B)) : A ∧ B =>
|
||||||
|
"Jetzt erst mal noch schnell die Annahme `A ∧ (A → B)` mit `rcases` aufteilen."
|
||||||
|
|
||||||
|
-- if they don't use `intro ⟨_, _⟩`.
|
||||||
|
Message (A : Prop) (B : Prop) (h : A ∧ B) : A ∧ (A → B) =>
|
||||||
|
"Jetzt erst mal noch schnell die Annahme `A ∧ B` mit `rcases` aufteilen."
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (hA : A) (h : A → B) : A ∧ B =>
|
||||||
|
"Wieder in Einzelteile aufteilen..."
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) : A ∧ (A → B) =>
|
||||||
|
"Immer das gleiche ... noch mehr aufteilen."
|
||||||
|
|
||||||
|
Message (A : Prop) (B : Prop) (h₁: A) (h₂: B) : A → B =>
|
||||||
|
"Das ist jetzt vielleicht etwas verwirrend: Wir wollen die Implikation `A → B` zeigen,
|
||||||
|
wissen aber, dass `B` immer wahr ist (habe eine Annahme der Form `(hB : B)`).
|
||||||
|
|
||||||
|
Mit intro können wir einfach nochmal annehmen, dass `A` wahr ist. Es stört uns nicht,
|
||||||
|
dass wir das schon wissen und auch gar nicht brauchen. Damit müssen wir nur noch zeigen,
|
||||||
|
dass `B` wahr ist."
|
||||||
|
|
||||||
|
Hint (A : Prop) (B : Prop) (hA : A) (h : A → B) : B =>
|
||||||
|
"Sieht nach einem Fall für `apply` aus."
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
|
||||||
|
|
||||||
|
Tactics apply rcases
|
||||||
|
Tactics assumption
|
||||||
Loading…
Reference in New Issue