factor out adam game

pull/68/head
Jon Eugster 2 years ago
parent f9614b3bcd
commit 2097eddb2f

1
.gitignore vendored

@ -2,4 +2,5 @@ node_modules
client/dist
server/build
server/nng
server/adam
**/lake-packages/

@ -1 +0,0 @@
build

@ -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,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

Loading…
Cancel
Save