diff --git a/.gitignore b/.gitignore index 88be6e5..659fbd9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules client/dist server/build server/nng +server/adam **/lake-packages/ diff --git a/server/adam/.gitignore b/server/adam/.gitignore deleted file mode 100644 index c795b05..0000000 --- a/server/adam/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build \ No newline at end of file diff --git a/server/adam/.vscode/settings.json b/server/adam/.vscode/settings.json deleted file mode 100644 index 23325f1..0000000 --- a/server/adam/.vscode/settings.json +++ /dev/null @@ -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 -} diff --git a/server/adam/Adam.lean b/server/adam/Adam.lean deleted file mode 100644 index 8c38954..0000000 --- a/server/adam/Adam.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Doc/Definitions.lean b/server/adam/Adam/Doc/Definitions.lean deleted file mode 100644 index 3d4084c..0000000 --- a/server/adam/Adam/Doc/Definitions.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Doc/Lemmas.lean b/server/adam/Adam/Doc/Lemmas.lean deleted file mode 100644 index 71ae0df..0000000 --- a/server/adam/Adam/Doc/Lemmas.lean +++ /dev/null @@ -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" -" -`` -" diff --git a/server/adam/Adam/Doc/Tactics.lean b/server/adam/Adam/Doc/Tactics.lean deleted file mode 100644 index 5e1978a..0000000 --- a/server/adam/Adam/Doc/Tactics.lean +++ /dev/null @@ -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 -" -" diff --git a/server/adam/Adam/HelperTools.lean b/server/adam/Adam/HelperTools.lean deleted file mode 100644 index b61ca25..0000000 --- a/server/adam/Adam/HelperTools.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Contradiction.lean b/server/adam/Adam/Levels/Contradiction.lean deleted file mode 100644 index 127262c..0000000 --- a/server/adam/Adam/Levels/Contradiction.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Contradiction/L01_Have.lean b/server/adam/Adam/Levels/Contradiction/L01_Have.lean deleted file mode 100644 index 2543477..0000000 --- a/server/adam/Adam/Levels/Contradiction/L01_Have.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Contradiction/L02_Suffices.lean b/server/adam/Adam/Levels/Contradiction/L02_Suffices.lean deleted file mode 100644 index 9b1b902..0000000 --- a/server/adam/Adam/Levels/Contradiction/L02_Suffices.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Contradiction/L03_ByContra.lean b/server/adam/Adam/Levels/Contradiction/L03_ByContra.lean deleted file mode 100644 index 6111d61..0000000 --- a/server/adam/Adam/Levels/Contradiction/L03_ByContra.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Contradiction/L04_ByContra.lean b/server/adam/Adam/Levels/Contradiction/L04_ByContra.lean deleted file mode 100644 index 406a41c..0000000 --- a/server/adam/Adam/Levels/Contradiction/L04_ByContra.lean +++ /dev/null @@ -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 "" diff --git a/server/adam/Adam/Levels/Contradiction/L05_Contrapose.lean b/server/adam/Adam/Levels/Contradiction/L05_Contrapose.lean deleted file mode 100644 index ca0e523..0000000 --- a/server/adam/Adam/Levels/Contradiction/L05_Contrapose.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Contradiction/L06_Summary.lean b/server/adam/Adam/Levels/Contradiction/L06_Summary.lean deleted file mode 100644 index f22927c..0000000 --- a/server/adam/Adam/Levels/Contradiction/L06_Summary.lean +++ /dev/null @@ -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 | -" diff --git a/server/adam/Adam/Levels/Function.lean b/server/adam/Adam/Levels/Function.lean deleted file mode 100644 index 085d729..0000000 --- a/server/adam/Adam/Levels/Function.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Function/L01_Function.lean b/server/adam/Adam/Levels/Function/L01_Function.lean deleted file mode 100644 index 93774d5..0000000 --- a/server/adam/Adam/Levels/Function/L01_Function.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Function/L02_Let.lean b/server/adam/Adam/Levels/Function/L02_Let.lean deleted file mode 100644 index 8ce9817..0000000 --- a/server/adam/Adam/Levels/Function/L02_Let.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Function/L03_Piecewise.lean b/server/adam/Adam/Levels/Function/L03_Piecewise.lean deleted file mode 100644 index b330f21..0000000 --- a/server/adam/Adam/Levels/Function/L03_Piecewise.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Function/L04_Injective.lean b/server/adam/Adam/Levels/Function/L04_Injective.lean deleted file mode 100644 index a6243d9..0000000 --- a/server/adam/Adam/Levels/Function/L04_Injective.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Function/L05_Injective.lean b/server/adam/Adam/Levels/Function/L05_Injective.lean deleted file mode 100644 index 032c91f..0000000 --- a/server/adam/Adam/Levels/Function/L05_Injective.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Function/L06_Injective.lean b/server/adam/Adam/Levels/Function/L06_Injective.lean deleted file mode 100644 index 41122ef..0000000 --- a/server/adam/Adam/Levels/Function/L06_Injective.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Function/L07_Surjective.lean b/server/adam/Adam/Levels/Function/L07_Surjective.lean deleted file mode 100644 index 8cc739f..0000000 --- a/server/adam/Adam/Levels/Function/L07_Surjective.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Function/L08_Bijective.lean b/server/adam/Adam/Levels/Function/L08_Bijective.lean deleted file mode 100644 index e444faa..0000000 --- a/server/adam/Adam/Levels/Function/L08_Bijective.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Function/L09_Inverse.lean b/server/adam/Adam/Levels/Function/L09_Inverse.lean deleted file mode 100644 index 04c909f..0000000 --- a/server/adam/Adam/Levels/Function/L09_Inverse.lean +++ /dev/null @@ -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?" diff --git a/server/adam/Adam/Levels/Implication.lean b/server/adam/Adam/Levels/Implication.lean deleted file mode 100644 index ebdf64a..0000000 --- a/server/adam/Adam/Levels/Implication.lean +++ /dev/null @@ -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! - -" diff --git a/server/adam/Adam/Levels/Implication/L01_Intro.lean b/server/adam/Adam/Levels/Implication/L01_Intro.lean deleted file mode 100644 index f72c1ba..0000000 --- a/server/adam/Adam/Levels/Implication/L01_Intro.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L02_Revert.lean b/server/adam/Adam/Levels/Implication/L02_Revert.lean deleted file mode 100644 index 563cb7e..0000000 --- a/server/adam/Adam/Levels/Implication/L02_Revert.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L03_Apply.lean b/server/adam/Adam/Levels/Implication/L03_Apply.lean deleted file mode 100644 index bf6f44e..0000000 --- a/server/adam/Adam/Levels/Implication/L03_Apply.lean +++ /dev/null @@ -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}$$ diff --git a/server/adam/Adam/Levels/Implication/L04_Apply.lean b/server/adam/Adam/Levels/Implication/L04_Apply.lean deleted file mode 100644 index 5181ff7..0000000 --- a/server/adam/Adam/Levels/Implication/L04_Apply.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L05_Apply.lean b/server/adam/Adam/Levels/Implication/L05_Apply.lean deleted file mode 100644 index d4747a9..0000000 --- a/server/adam/Adam/Levels/Implication/L05_Apply.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L06_Iff.lean b/server/adam/Adam/Levels/Implication/L06_Iff.lean deleted file mode 100644 index c63948b..0000000 --- a/server/adam/Adam/Levels/Implication/L06_Iff.lean +++ /dev/null @@ -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. diff --git a/server/adam/Adam/Levels/Implication/L07_Rw.lean b/server/adam/Adam/Levels/Implication/L07_Rw.lean deleted file mode 100644 index 7551676..0000000 --- a/server/adam/Adam/Levels/Implication/L07_Rw.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L08_Iff.lean b/server/adam/Adam/Levels/Implication/L08_Iff.lean deleted file mode 100644 index ba0ba35..0000000 --- a/server/adam/Adam/Levels/Implication/L08_Iff.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L09_Iff.lean b/server/adam/Adam/Levels/Implication/L09_Iff.lean deleted file mode 100644 index 7e86e99..0000000 --- a/server/adam/Adam/Levels/Implication/L09_Iff.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L10_Apply.lean b/server/adam/Adam/Levels/Implication/L10_Apply.lean deleted file mode 100644 index 5223c4e..0000000 --- a/server/adam/Adam/Levels/Implication/L10_Apply.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L11_ByCases.lean b/server/adam/Adam/Levels/Implication/L11_ByCases.lean deleted file mode 100644 index 61f121c..0000000 --- a/server/adam/Adam/Levels/Implication/L11_ByCases.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Implication/L12_Rw.lean b/server/adam/Adam/Levels/Implication/L12_Rw.lean deleted file mode 100644 index 4ca425e..0000000 --- a/server/adam/Adam/Levels/Implication/L12_Rw.lean +++ /dev/null @@ -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" diff --git a/server/adam/Adam/Levels/Implication/L13_Summary.lean b/server/adam/Adam/Levels/Implication/L13_Summary.lean deleted file mode 100644 index b2d4d6f..0000000 --- a/server/adam/Adam/Levels/Implication/L13_Summary.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Induction.lean b/server/adam/Adam/Levels/Induction.lean deleted file mode 100644 index 5e77bb6..0000000 --- a/server/adam/Adam/Levels/Induction.lean +++ /dev/null @@ -1,5 +0,0 @@ -import Adam.Levels.Induction.L01_Induction - -Game "Adam" -World "Induction" -Title "Übungen Induktions" diff --git a/server/adam/Adam/Levels/Induction/L01_Induction.lean b/server/adam/Adam/Levels/Induction/L01_Induction.lean deleted file mode 100644 index b9c9c92..0000000 --- a/server/adam/Adam/Levels/Induction/L01_Induction.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Inequality.lean b/server/adam/Adam/Levels/Inequality.lean deleted file mode 100644 index 18eb423..0000000 --- a/server/adam/Adam/Levels/Inequality.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Inequality/L01_LE.lean b/server/adam/Adam/Levels/Inequality/L01_LE.lean deleted file mode 100644 index b41f27b..0000000 --- a/server/adam/Adam/Levels/Inequality/L01_LE.lean +++ /dev/null @@ -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?" diff --git a/server/adam/Adam/Levels/Inequality/L02_Pos.lean b/server/adam/Adam/Levels/Inequality/L02_Pos.lean deleted file mode 100644 index 1cb0a3d..0000000 --- a/server/adam/Adam/Levels/Inequality/L02_Pos.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Inequality/L03_Linarith.lean b/server/adam/Adam/Levels/Inequality/L03_Linarith.lean deleted file mode 100644 index 0cb4095..0000000 --- a/server/adam/Adam/Levels/Inequality/L03_Linarith.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Inequality/L04_Linarith.lean b/server/adam/Adam/Levels/Inequality/L04_Linarith.lean deleted file mode 100644 index c51e9c2..0000000 --- a/server/adam/Adam/Levels/Inequality/L04_Linarith.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Inequality/L05_DrinkersParadox.lean b/server/adam/Adam/Levels/Inequality/L05_DrinkersParadox.lean deleted file mode 100644 index 9089578..0000000 --- a/server/adam/Adam/Levels/Inequality/L05_DrinkersParadox.lean +++ /dev/null @@ -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…" diff --git a/server/adam/Adam/Levels/Inequality/T_Induction.lean b/server/adam/Adam/Levels/Inequality/T_Induction.lean deleted file mode 100644 index 1a4add5..0000000 --- a/server/adam/Adam/Levels/Inequality/T_Induction.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Lean.lean b/server/adam/Adam/Levels/Lean.lean deleted file mode 100644 index d60af11..0000000 --- a/server/adam/Adam/Levels/Lean.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Lean/L01_Type.lean b/server/adam/Adam/Levels/Lean/L01_Type.lean deleted file mode 100644 index 878296e..0000000 --- a/server/adam/Adam/Levels/Lean/L01_Type.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Lean/L02_Universe.lean b/server/adam/Adam/Levels/Lean/L02_Universe.lean deleted file mode 100644 index ee3dbdd..0000000 --- a/server/adam/Adam/Levels/Lean/L02_Universe.lean +++ /dev/null @@ -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 => --- "" diff --git a/server/adam/Adam/Levels/Lean/L03_ImplicitArguments.lean b/server/adam/Adam/Levels/Lean/L03_ImplicitArguments.lean deleted file mode 100644 index 6590917..0000000 --- a/server/adam/Adam/Levels/Lean/L03_ImplicitArguments.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Lean/L04_InstanceArguments.lean b/server/adam/Adam/Levels/Lean/L04_InstanceArguments.lean deleted file mode 100644 index a362bd4..0000000 --- a/server/adam/Adam/Levels/Lean/L04_InstanceArguments.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/LeftOvers/L09_Or.lean b/server/adam/Adam/Levels/LeftOvers/L09_Or.lean deleted file mode 100644 index 703fc5c..0000000 --- a/server/adam/Adam/Levels/LeftOvers/L09_Or.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LeftOvers/L33_Prime.lean b/server/adam/Adam/Levels/LeftOvers/L33_Prime.lean deleted file mode 100644 index 8d9ad9d..0000000 --- a/server/adam/Adam/Levels/LeftOvers/L33_Prime.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LeftOvers/L34_ExistsUnique.lean b/server/adam/Adam/Levels/LeftOvers/L34_ExistsUnique.lean deleted file mode 100644 index a16cebb..0000000 --- a/server/adam/Adam/Levels/LeftOvers/L34_ExistsUnique.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LeftOvers/Lxx_Prime.lean b/server/adam/Adam/Levels/LeftOvers/Lxx_Prime.lean deleted file mode 100644 index bf246d2..0000000 --- a/server/adam/Adam/Levels/LeftOvers/Lxx_Prime.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LeftOvers/Lxx_Tauto.lean b/server/adam/Adam/Levels/LeftOvers/Lxx_Tauto.lean deleted file mode 100644 index 10bedbb..0000000 --- a/server/adam/Adam/Levels/LeftOvers/Lxx_Tauto.lean +++ /dev/null @@ -1 +0,0 @@ --- tauto is not implemented yet... duper? diff --git a/server/adam/Adam/Levels/LeftOvers/Lxx_Tfae.lean b/server/adam/Adam/Levels/LeftOvers/Lxx_Tfae.lean deleted file mode 100644 index 0bd6a4d..0000000 --- a/server/adam/Adam/Levels/LeftOvers/Lxx_Tfae.lean +++ /dev/null @@ -1 +0,0 @@ --- not implemented yet diff --git a/server/adam/Adam/Levels/LeftOvers/Playground.lean b/server/adam/Adam/Levels/LeftOvers/Playground.lean deleted file mode 100644 index 8ccfefa..0000000 --- a/server/adam/Adam/Levels/LeftOvers/Playground.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LeftOvers/xx_Functions.lean b/server/adam/Adam/Levels/LeftOvers/xx_Functions.lean deleted file mode 100644 index 403a75b..0000000 --- a/server/adam/Adam/Levels/LeftOvers/xx_Functions.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra.lean b/server/adam/Adam/Levels/LinearAlgebra.lean deleted file mode 100644 index 0bb386d..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra.lean +++ /dev/null @@ -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" diff --git a/server/adam/Adam/Levels/LinearAlgebra/L01_Module.lean b/server/adam/Adam/Levels/LinearAlgebra/L01_Module.lean deleted file mode 100644 index 4e6eb93..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L01_Module.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L02_VectorNotation.lean b/server/adam/Adam/Levels/LinearAlgebra/L02_VectorNotation.lean deleted file mode 100644 index e322d11..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L02_VectorNotation.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L03_VectorNotation.lean b/server/adam/Adam/Levels/LinearAlgebra/L03_VectorNotation.lean deleted file mode 100644 index 53d2fe4..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L03_VectorNotation.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L04_Submodule.lean b/server/adam/Adam/Levels/LinearAlgebra/L04_Submodule.lean deleted file mode 100644 index 294f05a..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L04_Submodule.lean +++ /dev/null @@ -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] diff --git a/server/adam/Adam/Levels/LinearAlgebra/L05_Submodule.lean b/server/adam/Adam/Levels/LinearAlgebra/L05_Submodule.lean deleted file mode 100644 index 2884d6b..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L05_Submodule.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L06_Span.lean b/server/adam/Adam/Levels/LinearAlgebra/L06_Span.lean deleted file mode 100644 index 7d4b557..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L06_Span.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L07_Span.lean b/server/adam/Adam/Levels/LinearAlgebra/L07_Span.lean deleted file mode 100644 index e7854df..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L07_Span.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/L08_GeneratingSet.lean b/server/adam/Adam/Levels/LinearAlgebra/L08_GeneratingSet.lean deleted file mode 100644 index 271aa84..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/L08_GeneratingSet.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/M01_LinearMap.lean b/server/adam/Adam/Levels/LinearAlgebra/M01_LinearMap.lean deleted file mode 100644 index 1391df8..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/M01_LinearMap.lean +++ /dev/null @@ -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 - } diff --git a/server/adam/Adam/Levels/LinearAlgebra/M02_LinearIndep.lean b/server/adam/Adam/Levels/LinearAlgebra/M02_LinearIndep.lean deleted file mode 100644 index 200db01..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/M02_LinearIndep.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/M04_Basis.lean b/server/adam/Adam/Levels/LinearAlgebra/M04_Basis.lean deleted file mode 100644 index 887d7e9..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/M04_Basis.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N01_Span.lean b/server/adam/Adam/Levels/LinearAlgebra/N01_Span.lean deleted file mode 100644 index d824f0e..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N01_Span.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N02_Span.lean b/server/adam/Adam/Levels/LinearAlgebra/N02_Span.lean deleted file mode 100644 index 850491a..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N02_Span.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N03_Idempotent.lean b/server/adam/Adam/Levels/LinearAlgebra/N03_Idempotent.lean deleted file mode 100644 index 90400e1..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N03_Idempotent.lean +++ /dev/null @@ -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 } diff --git a/server/adam/Adam/Levels/LinearAlgebra/N04_Idempotent.lean b/server/adam/Adam/Levels/LinearAlgebra/N04_Idempotent.lean deleted file mode 100644 index 6c53e4f..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N04_Idempotent.lean +++ /dev/null @@ -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, diff --git a/server/adam/Adam/Levels/LinearAlgebra/N05_Sum.lean b/server/adam/Adam/Levels/LinearAlgebra/N05_Sum.lean deleted file mode 100644 index 401562e..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N05_Sum.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N06_Sum.lean b/server/adam/Adam/Levels/LinearAlgebra/N06_Sum.lean deleted file mode 100644 index 52c2e03..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N06_Sum.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N07_Prod.lean b/server/adam/Adam/Levels/LinearAlgebra/N07_Prod.lean deleted file mode 100644 index 09341f4..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N07_Prod.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/LinearAlgebra/N08_Prod.lean b/server/adam/Adam/Levels/LinearAlgebra/N08_Prod.lean deleted file mode 100644 index a800016..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N08_Prod.lean +++ /dev/null @@ -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 } diff --git a/server/adam/Adam/Levels/LinearAlgebra/N09_Prod.lean b/server/adam/Adam/Levels/LinearAlgebra/N09_Prod.lean deleted file mode 100644 index 672b5fa..0000000 --- a/server/adam/Adam/Levels/LinearAlgebra/N09_Prod.lean +++ /dev/null @@ -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, --- } diff --git a/server/adam/Adam/Levels/Notes.txt b/server/adam/Adam/Levels/Notes.txt deleted file mode 100644 index 9552ed2..0000000 --- a/server/adam/Adam/Levels/Notes.txt +++ /dev/null @@ -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. diff --git a/server/adam/Adam/Levels/Numbers.lean b/server/adam/Adam/Levels/Numbers.lean deleted file mode 100644 index 6a6f2fa..0000000 --- a/server/adam/Adam/Levels/Numbers.lean +++ /dev/null @@ -1,2 +0,0 @@ -import Adam.Levels.Numbers.L01_PNat -import Adam.Levels.Numbers.L02_PNat diff --git a/server/adam/Adam/Levels/Numbers/L01_PNat.lean b/server/adam/Adam/Levels/Numbers/L01_PNat.lean deleted file mode 100644 index 66cf131..0000000 --- a/server/adam/Adam/Levels/Numbers/L01_PNat.lean +++ /dev/null @@ -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`, ... --- -/ diff --git a/server/adam/Adam/Levels/Numbers/L02_PNat.lean b/server/adam/Adam/Levels/Numbers/L02_PNat.lean deleted file mode 100644 index f5fbc73..0000000 --- a/server/adam/Adam/Levels/Numbers/L02_PNat.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Predicate.lean b/server/adam/Adam/Levels/Predicate.lean deleted file mode 100644 index 4d7d0a1..0000000 --- a/server/adam/Adam/Levels/Predicate.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Predicate/L01_Ring.lean b/server/adam/Adam/Levels/Predicate/L01_Ring.lean deleted file mode 100644 index 39d000c..0000000 --- a/server/adam/Adam/Levels/Predicate/L01_Ring.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Predicate/L02_Rewrite.lean b/server/adam/Adam/Levels/Predicate/L02_Rewrite.lean deleted file mode 100644 index 4434f17..0000000 --- a/server/adam/Adam/Levels/Predicate/L02_Rewrite.lean +++ /dev/null @@ -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 -"" diff --git a/server/adam/Adam/Levels/Predicate/L03_Rewrite.lean b/server/adam/Adam/Levels/Predicate/L03_Rewrite.lean deleted file mode 100644 index eb5f3ef..0000000 --- a/server/adam/Adam/Levels/Predicate/L03_Rewrite.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Predicate/L04_Ring.lean b/server/adam/Adam/Levels/Predicate/L04_Ring.lean deleted file mode 100644 index 8a4e243..0000000 --- a/server/adam/Adam/Levels/Predicate/L04_Ring.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Predicate/L05_Rfl.lean b/server/adam/Adam/Levels/Predicate/L05_Rfl.lean deleted file mode 100644 index 1a45df8..0000000 --- a/server/adam/Adam/Levels/Predicate/L05_Rfl.lean +++ /dev/null @@ -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. -" diff --git a/server/adam/Adam/Levels/Predicate/L06_Exists.lean b/server/adam/Adam/Levels/Predicate/L06_Exists.lean deleted file mode 100644 index 5532d23..0000000 --- a/server/adam/Adam/Levels/Predicate/L06_Exists.lean +++ /dev/null @@ -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!" diff --git a/server/adam/Adam/Levels/Predicate/L07_Exists.lean b/server/adam/Adam/Levels/Predicate/L07_Exists.lean deleted file mode 100644 index e8736c4..0000000 --- a/server/adam/Adam/Levels/Predicate/L07_Exists.lean +++ /dev/null @@ -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. diff --git a/server/adam/Adam/Levels/Predicate/L08_Forall.lean b/server/adam/Adam/Levels/Predicate/L08_Forall.lean deleted file mode 100644 index c16b6b6..0000000 --- a/server/adam/Adam/Levels/Predicate/L08_Forall.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Predicate/L09_PushNeg.lean b/server/adam/Adam/Levels/Predicate/L09_PushNeg.lean deleted file mode 100644 index 773369b..0000000 --- a/server/adam/Adam/Levels/Predicate/L09_PushNeg.lean +++ /dev/null @@ -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. | - -" diff --git a/server/adam/Adam/Levels/Prime.lean b/server/adam/Adam/Levels/Prime.lean deleted file mode 100644 index 6f1e466..0000000 --- a/server/adam/Adam/Levels/Prime.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Prime/L01_Dvd.lean b/server/adam/Adam/Levels/Prime/L01_Dvd.lean deleted file mode 100644 index 91a5901..0000000 --- a/server/adam/Adam/Levels/Prime/L01_Dvd.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Prime/L02_Prime.lean b/server/adam/Adam/Levels/Prime/L02_Prime.lean deleted file mode 100644 index bbd083f..0000000 --- a/server/adam/Adam/Levels/Prime/L02_Prime.lean +++ /dev/null @@ -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." diff --git a/server/adam/Adam/Levels/Prime/L03_Prime.lean b/server/adam/Adam/Levels/Prime/L03_Prime.lean deleted file mode 100644 index ff5f64e..0000000 --- a/server/adam/Adam/Levels/Prime/L03_Prime.lean +++ /dev/null @@ -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 diff --git a/server/adam/Adam/Levels/Prime/L06_ExistsUnique.lean b/server/adam/Adam/Levels/Prime/L06_ExistsUnique.lean deleted file mode 100644 index e03c0a7..0000000 --- a/server/adam/Adam/Levels/Prime/L06_ExistsUnique.lean +++ /dev/null @@ -1,28 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -Game "Adam" -World "Prime" -Level 4 - -Title "Existiert eindeutig" - -Introduction -" -Hier lässt sich noch eine neue Notation einführen: `∃!` bedeutet -\"es existiert ein eindeutiges\" und ist definiert als - - -" - -Statement -"Zeige dass die einzige gerade Primzahl $2$ ist." - : ∃! p, Nat.Prime p ∧ Even p := by - use 2 - constructor - simp - rintro y ⟨hy, hy'⟩ - rw [←Nat.Prime.even_iff hy] - assumption diff --git a/server/adam/Adam/Levels/Proposition.lean b/server/adam/Adam/Levels/Proposition.lean deleted file mode 100644 index 79a7083..0000000 --- a/server/adam/Adam/Levels/Proposition.lean +++ /dev/null @@ -1,39 +0,0 @@ -import Adam.Levels.Proposition.L00_Tauto -import Adam.Levels.Proposition.L01_Rfl -import Adam.Levels.Proposition.L02_Assumption -import Adam.Levels.Proposition.L03_Assumption -import Adam.Levels.Proposition.L04_True -import Adam.Levels.Proposition.L05_Not -import Adam.Levels.Proposition.L06_False -import Adam.Levels.Proposition.L07_ContraNotEq -import Adam.Levels.Proposition.L08_Contra -import Adam.Levels.Proposition.L09_And -import Adam.Levels.Proposition.L10_And -import Adam.Levels.Proposition.L11_Or -import Adam.Levels.Proposition.L12_Or -import Adam.Levels.Proposition.L13_Summary - -Game "Adam" -World "Proposition" -Title "Logo" - -Introduction " -Durch eine unvorhergesehene und nicht-kanonische Singularität in der Raumzeit -bist du ausversehen in ein Paralleluniversum gestolpert. Wie es aussieht, gibt es kein zurück. -Richte dich besser darauf ein, hier bleiben und dich zurechtzufinden zu müssen. - -Wie es aussieht, gibt es hier viele nette kleine Planeten. Alle bewohnbar, und bis zu -sieben Sonnenuntergänge täglich inklusive. Nur werden sie allesamt von Formalosophen bewohnt, -seltsamen Wesen mit ausgefallenen mathematischen Obsessionen. Und dummerweise hat sich -herumgesprochen, dass du in deinem früheren Universum Mathematiker warst. du wirst hier -keine Ruhe finden, solange du nicht lernst, ihren unablässigen Wissensdurst zu stillen. - -Es gibt nur zwei Schwierigkeiten: Erstens haben die Formalosophen allem Anschein nach -überhaupt kein tieferes mathematisches Verständnis, und zweitens kommunizieren Sie über Mathematik -exklusiv in einem dir fremden Dialekt, den sie Leansch [liːnʃ] nennen. - -Zum Glück hat Robo mit dir das Universum gewechselt. -Robo, das ist dein kleiner SmartElf. Robo ist war auch nicht die mathematische Leuchte, die du Dir -in dieser Situation gewünscht hättest, aber es scheint, er hat irgendwo Leansch gelernt. -Und das ist Gold wert. -" diff --git a/server/adam/Adam/Levels/Proposition/L00_Tauto.lean b/server/adam/Adam/Levels/Proposition/L00_Tauto.lean deleted file mode 100644 index 6b13754..0000000 --- a/server/adam/Adam/Levels/Proposition/L00_Tauto.lean +++ /dev/null @@ -1,47 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "Proposition" -Level 1 - -Title "Automatisierung" - -Introduction -" -Gerade seid Ihr auf Königin *Logisindes* Planeten. Sie kommt ohne Umschweife zum Punkt: - -**Logisinde** Werte Wesen aus fremden Welten, gestatten Sie eine Frage. Warum gilt … - -Und sie kritzelt etwas auf ein Stück Papier: oben ein paar Annahmen, unten eine Schlussfolgerung. -Dazwischen sollst du offenbar einen Beweis eintragen. -Du siehst Robo hilflos an. -" - -Statement "" - (A B C : Prop) : - ¬((¬B ∨ ¬ C) ∨ (A → B)) → (¬A ∨ B) ∧ ¬ (B ∧ C) := by - Hint "**Robo** Das ist ganz einfach. Mit `{A} {B} {C} : Prop` meint sie: - `{A}`, `{B}` und `{C}` sind irgendwelche Aussagen (*propositions*). - Und mit `→` meint sie ⇒, also “impliziert”. Die anderen Symbole kennst du, oder? - - **Du** Ehhm, ja. Aber da muss ich jetzt trotzdem erst einmal überlegen. - - **Robo** (flüsternd) Behaupte doch einfach, dass sei eine Tautologie. - - **Du** Ernsthaft? - - **Robo** Ja. Schreib einfach `tauto`. - - **Robo** Mach schon …" - tauto - -Conclusion -" -**Logisinde** (etwas konsterniert) Ja, das ist streng genommen richtig. -Aber glaubt bloß nicht, dass Ihr damit auf *diesem* Planeten viel weiterkommt! -Meine Untertanen verstehen `tauto` nicht. Da müsst Ihr Euch schon etwas mehr anstrengen. -" - -LemmaTab "Logic" -NewTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L01_Rfl.lean b/server/adam/Adam/Levels/Proposition/L01_Rfl.lean deleted file mode 100644 index f15ccb2..0000000 --- a/server/adam/Adam/Levels/Proposition/L01_Rfl.lean +++ /dev/null @@ -1,32 +0,0 @@ -import Adam.Metadata - -Game "Adam" -World "Proposition" -Level 2 - -Title "Aller Anfang ist... ein Einzeiler?" - -Introduction -" -In der Zwischenzeit hat bereits sich eine lange Schlange Untertanen gebildet, die gern ihren -Fragen stellen würden. Logisinde winkt den ersten nach vorn. Er räuspert sich. - -**Untertan** Warum ist $42 = 42$? - -Du schaust ihn fassungslos an. -Er schreibt es dir wieder auf. -" - -Statement "" : - 42 = 42 := by - Hint " **Robo** Ist doch klar. Du musst ihn einfach daran erinnern, - dass Gleichheit *reflexiv* ist. Probier mal `rfl`." - rfl - -Conclusion -" -**Untertan** Ah, richtig. Ja, Sie haben ja so recht. Das vergesse ich immer. Rfl, rfl, rfl … -" - -NewTactic rfl -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L02_Assumption.lean b/server/adam/Adam/Levels/Proposition/L02_Assumption.lean deleted file mode 100644 index 8466041..0000000 --- a/server/adam/Adam/Levels/Proposition/L02_Assumption.lean +++ /dev/null @@ -1,43 +0,0 @@ -import Adam.Metadata - -Game "Adam" -World "Proposition" -Level 3 - -Title "Annahmen" - -Introduction -" -Während der erste Untertan noch rfl, rfl, rfl murmelt, tritt schon der nächste nach vorne. Es ist schüchtern und schreibt bloß. -" - -Statement "" - (n : ℕ) (h₁ : 10 > n) (h₂ : 1 < n) (h₃ : n ≠ 5) : 1 < n := by - Hint " -**Robo** `{n} : ℕ` bedeutet, `{n}` ist eine natürliche Zahl. - -**Du** Warum schreibt er dann nicht `{n} ∈ ℕ`?? - -**Robo** Weil das hier alles komische Typen sind … Ich kann dir das später mal in Ruhe erklären. -Jetzt will ich erst einmal die Frage entschlüsseln. - -**Robo** Also, `{h₁}`, `{h₂}`, `{h₃}` sind einfach nur Namen für verschiedene Annahmen, und zwar -für die Annahme `n < 10`, `1 < n` und `n ≠ 5`. Beweisen sollen wir: `1 < n`. - -**Du** Aber das war doch gerade eine der Annahmen. - -**Robo** Ja, stimmt. - -**Du** ??? - -**Robo** Du musst ihm das halt explizit sagen. Probiers mal mit `assumption`." - assumption - -Conclusion -" -**Untertan** Ja richtig! Wenn Ihr nur wüsstet, was ich mir an dieser Frage schon den Kopf -zerbrochen habe! -" - -NewTactic assumption -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L03_Assumption.lean b/server/adam/Adam/Levels/Proposition/L03_Assumption.lean deleted file mode 100644 index 91b0115..0000000 --- a/server/adam/Adam/Levels/Proposition/L03_Assumption.lean +++ /dev/null @@ -1,36 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "Proposition" -Level 4 - -Title "Logische Aussagen" - -Introduction -" -Ein dritter Untertan kommt mit folgendem Problem. -" - -Statement "" - (A : Prop) (hA : A) : A := by - Hint " -**Robo** Hier bedeutet `{A} : Prop` wieder, dass `{A}` irgendeine Aussage ist. - Und `{hA}` ist eine Name für die Annahme, dass `{A}` wahr ist. - -**Du** Und unter dieser Annahme sollen wir jetzt `{A}` beweisen? - -**Robo** Ja. Da kommst du jetzt selbst drauf, wie das geht, oder? -" - Hint (hidden := true) "**Robo**: Ist doch genau wie eben: -die Aussage, die zu beweisen ist, gehört selbst zu den Annahmen. -Also wird `assumption` auch wieder funktionieren." - assumption - -Conclusion -" -**Untertan** Das ging ja schnell. Super! Vielen Dank. -" - -NewTactic assumption -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L04_True.lean b/server/adam/Adam/Levels/Proposition/L04_True.lean deleted file mode 100644 index 9332c3c..0000000 --- a/server/adam/Adam/Levels/Proposition/L04_True.lean +++ /dev/null @@ -1,37 +0,0 @@ -import Adam.Metadata - -Game "Adam" -World "Proposition" -Level 5 - -Title "True/False" - -Introduction -" -Der nächste Untertan in der Reihe ist ein Schelm. -" - -Statement "" : True := by - Hint " -**Robo** Dieses `True` ist eine spezielle Aussage, nämlich die Aussage, die immer und -bedingungslos wahr ist. - -**Du** Und was genau ist dann zu beweisen? - -**Robo** Ich glaube, nichts. Ich glaube, du kannst einfach `trivial` schreiben. -" - trivial - -Conclusion -" -**Schelm** Wollte nur mal sehen, dass Ihr nicht auf den Kopf gefallen seid … - -**Du** *(zu Robo)* Können wir nicht einfach immer dieses `trivial` verwenden? -Wie in einer Mathe-Vorlesung? - -**Robo** Nein, das `trivial` hier hat eine ziemlich spezielle Bedeutung. -Das funktioniert nur in einer Handvoll Situationen. -" - -NewTactic trivial -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L05_Not.lean b/server/adam/Adam/Levels/Proposition/L05_Not.lean deleted file mode 100644 index 486072f..0000000 --- a/server/adam/Adam/Levels/Proposition/L05_Not.lean +++ /dev/null @@ -1,34 +0,0 @@ -import Adam.Metadata - -Game "Adam" -World "Proposition" -Level 6 - -Title "Not" - -Introduction -" -Der Schelm hat noch eine Schwester dabei. -" - -Statement "" : ¬False := by - Hint " -**Robo** Dieses Zeichen `¬` bedeutet Negation. Also wenn eine Aussage `(A : Prop)` -wahr ist, dann ist `¬A` falsch, und umgekehrt. - -**Du** Und `False` ist wahrscheinlich die Aussage, die immer falsch ist? - -**Robo** Ja, richtig. - -**Du** Ist das jetzt nicht doch wieder trivial? - -**Robo** Probier mal!" - trivial - -Conclusion -" -Die Schwester lacht und eilt ihrem Bruder hinterher. -" - -NewTactic trivial -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L06_False.lean b/server/adam/Adam/Levels/Proposition/L06_False.lean deleted file mode 100644 index 55e29b3..0000000 --- a/server/adam/Adam/Levels/Proposition/L06_False.lean +++ /dev/null @@ -1,45 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - -Game "Adam" -World "Proposition" -Level 7 - -Title "Aus Falschem folgt vieles." - -Introduction -" -Als nächstes kommen drei Querulanten. Der erste hat folgendes Problem: -" - -Statement "" - (A : Prop) (h : False) : A := by - Hint "**Du** Wenn ich das jetzt richtig lese, ist `{A}` eine Aussage, -und wir haben außerdem eine Annahme names `{h}`, die besagt … - -**Robo** … die besagt, dass `False` gilt. - -**Du** Ich dachte, `False` gilt nie? - -**Robo** Ja, genau. Die Annahme ist `False`, also falsch. -Und aus einer falschen Annahme kann man bekanntlich alles beweisen! -Insbesondere die gesuchte Aussage `{A}`. - -**Du** Und wie erkläre ich das jetzt diesem Formalosophen? - -**Robo** Ich glaube, du musst ihn darauf hinweisen, dass zwischen der allgemeingültigen -Annahme `True` und seiner Annahme `False` ein Widerspruch besteht. Probier mal `contradiction`." - contradiction - -Conclusion -"Der erste Querulant ist offenbar zufrieden. - -**Du** War das jetzt ein Widerspruchsbeweis? - -**Robo** Nein, nein, ein Widerspruchsbeweis sieht anders aus. Das Argument hier war: - wir haben eine `contradiction` in unserem Annahmen, also folgt jede beliebige Aussage. -" - -NewTactic contradiction -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L07_ContraNotEq.lean b/server/adam/Adam/Levels/Proposition/L07_ContraNotEq.lean deleted file mode 100644 index 7a64979..0000000 --- a/server/adam/Adam/Levels/Proposition/L07_ContraNotEq.lean +++ /dev/null @@ -1,39 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -Game "Adam" -World "Proposition" -Level 8 - -Title "Aus Falschem folgt vieles." - -Introduction -" -Auftritt zweiter Querulant. -" - -Statement "" - (n : ℕ) (h : n ≠ n) : n = 37 := by - Hint "**Du** Ist `{n} ≠ {n}` nicht auch ein Widerspruch? - -**Robo** Probiers mal!" - contradiction - -Conclusion -" -**Du** Ja, scheint funktioniert zu haben. - -**Du** Aber irgendwie kommt mir das immer noch ein wenig suspekt vor. -Jetzt habe ich bewiesen, dass eine beliebige natürliche Zahl gleich 37 ist? - -**Robo** Nein, nicht doch. Nur eine beliebige Zahl, die ungleich sich selbst ist, ist gleich 37. -Und gleich 38, und gleich 39, … - -**Du** Ok, ok, verstehe. -" - -NewTactic contradiction -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L08_Contra.lean b/server/adam/Adam/Levels/Proposition/L08_Contra.lean deleted file mode 100644 index 79244df..0000000 --- a/server/adam/Adam/Levels/Proposition/L08_Contra.lean +++ /dev/null @@ -1,35 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -Game "Adam" -World "Proposition" -Level 9 - -Title "Aus Falschem folgt vieles." - -Introduction -" -Auftritt dritter Querulant. -" - -Statement "" - (n : ℕ) (h : n = 10) (g : n ≠ 10) : n = 42 := by - Hint "**Du** Wieder ein Widerspruch in den Annahmen? - -**Robo** Ich sehe, du hast langsam den Dreh raus." - contradiction - - - -Conclusion -" -**Robo** Gut gemacht. Bei dieser Frage ist auch ein bisschen offensichtlicher, -worin der Widerspruch besteht: Die Annahme `n ≠ 10` ist genau die Negation von `n = 10`. -Man muss `≠` immer als `¬(· = ·)` lesen. -" - -NewTactic contradiction -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L09_And.lean b/server/adam/Adam/Levels/Proposition/L09_And.lean deleted file mode 100644 index 2c0096e..0000000 --- a/server/adam/Adam/Levels/Proposition/L09_And.lean +++ /dev/null @@ -1,70 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases - -set_option tactic.hygienic false - -Game "Adam" -World "Proposition" -Level 10 - -Title "Und" - -Introduction -" -Der nächste Formalosoph in der Reihe hat seine Frage bereìts mitgebracht. -Er legt sie uns vor, setzt sich hin und häkelt. -" -Statement "" (A B : Prop) (hA : A) (hB : B) : A ∧ B := by - Hint -" -**Du**: Also, wir haben zwei Annahmen: `{A}` gilt, und `{B}` gilt auch. Und beweisen sollen wir -dass `{A} und {B}` gilt. Ich glaube, diese Formalospinner treiben mich noch zur Verzweiflung. -Kann ich nicht wieder `trivial` sagen? - -**Robo**: Nee, diesmal wird das nicht funktionieren. -Du musst das Beweisziel einfach in zwei Teile zerlegen. Probier mal `constructor`. - -**Du**: Du meinst, `destructor`?? - -**Robo**: Nein, `constructor`. Ich weiß das ist verwirrend, -aber die nennen das hier so weil man die Aussage aus mehreren Teilen -konstruieren kann. -" - constructor - -- TODO: (BUG) Hier werden beide der folgenden Hints angezeigt. - -- Das logiste Verhalten wäre, wenn jeder nur am richtigen Ort - -- angezeigt würde. - -- Ein cooles Feature wäre, wenn man nur diesen ersten Hint schreiben könnte - -- und dieser dann automatisch auch beim zweiten Goal angezeigt wird, aber dann mit `B` statt `A`. - Hint (hidden := true) -" -**Robo**: Schau mal, das ist Zauberpapier. -Jetzt haben wir auf einmal zwei Beweisziele. -Hier ist dast Ziel `{A}`. -Ich glaube, du weißt schon, wie man die jeweils erreicht. -Die Ziele stehen ja jeweils in den *Annahmen*. -" - assumption - Hint (hidden := true) -" -**Robo**: Schau mal, das ist Zauberpapier. -Jetzt haben wir auf einmal zwei Beweisziele. -Hier ist dast Ziel `{B}`. -Ich glaube, du weißt schon, wie man die jeweils erreicht. -Die Ziele stehen ja jeweils in den *Annahmen*. -" - assumption - - -Conclusion -" -**Robo** Super! - -Ihm scheinen diese Fragen inzwischen Spaß zu machen. - -**Robo** Meinst du, dieser Hebel, an dem \"Editor mode\" steht, ist echt? -Oder ist der nur gemalt? Probier mal! -" - -NewTactic constructor -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L10_And.lean b/server/adam/Adam/Levels/Proposition/L10_And.lean deleted file mode 100644 index 5422d66..0000000 --- a/server/adam/Adam/Levels/Proposition/L10_And.lean +++ /dev/null @@ -1,44 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases - -set_option tactic.hygienic false - -Game "Adam" -World "Proposition" -Level 11 - -Title "Und" - -Introduction -" -Langsam wird die Schlange kürzer. Die nächste Formalosophin, ebenfalls häkelnd, hat folgendes Anliegen. -" - -Statement "" - (A B C : Prop) (h : A ∧ (B ∧ C)) : B := by - Hint " -**Du** Jetzt müssen wir wohl die Annahme de-konstruieren. - -**Robo** Ja, genau. Das geht am einfachsten mit `rcases {h} with ⟨h₁, h₂⟩`. - -**Du** Moment, wie schreib ich *das* denn hier auf? - -**Robo** Die bleiden Klammern schreibst du als `\\<` und `\\>`, oder gleichzeitig als `\\<>`. -Und h₁ schreibst du einfach als `h\\1`. Aber du kannst dir auch einfach andere Namen -für `h₁` und `h₂`, zum Beispiel `rcases {h} with ⟨hA, hBC⟩` -" - Branch - rcases h with ⟨h₁, h₂⟩ - Hint "**Robo** Das sieht doch schon besser aus! Gleich nochmal!" - rcases h with ⟨_, ⟨g , _⟩⟩ - Hint (hidden := true) "**Robo** Du hast einen Beweis dafür in den *Annahmen*." - assumption - -Conclusion -" -**Robo** Du hättest das übrigens auch direkt verschachtelt schreiben können: -`rcases h with ⟨h₁, ⟨h₂ , h₃⟩⟩`. -" - -NewTactic rcases -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L11_Or.lean b/server/adam/Adam/Levels/Proposition/L11_Or.lean deleted file mode 100644 index 97925e5..0000000 --- a/server/adam/Adam/Levels/Proposition/L11_Or.lean +++ /dev/null @@ -1,42 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - ---set_option tactic.hygienic false - -Game "Adam" -World "Proposition" -Level 12 - -Title "Oder" - -Introduction -" -Der nächste bitte … -" - -Statement -"" - (A B : Prop) (hA : A) : A ∨ (¬ B) := by - Hint "**Du** Muss ich jetzt wieder das Beweisziel de-konstruieren? - -**Robo** Nein, viel einfacher. Wenn du eine Oder-Aussage beweisen sollst, musst du dich -einfach entscheiden, ob du die linke oder rechte Seite beweisen willst. - -**Du** Und wie erkläre ich meinem Formalosophen, welche Seite ich gern beweisen würde? -Ich will natürlich `{A}` beweisen! - -**Robo** Mit `left` bzw. `right`. Ist doch logisch, oder?" - Branch - right - Hint "**Robo** Wusste gar nicht, dass du eine Links-Rechts-Schwäche hast. Probier's nochmal." - left - assumption - -Conclusion -" -Auch dieser Formalosoph zieht zufrieden von dannen. -" - -NewTactic left right assumption -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L12_Or.lean b/server/adam/Adam/Levels/Proposition/L12_Or.lean deleted file mode 100644 index d5128f3..0000000 --- a/server/adam/Adam/Levels/Proposition/L12_Or.lean +++ /dev/null @@ -1,112 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - ---set_option autoImplicit false - - -Game "Adam" -World "Proposition" -Level 13 - -Title "Oder" - -Introduction -" -Der nächste bitte … -" - -Statement "" - (A B : Prop) (h : (A ∧ B) ∨ A) : A := by - Hint "**Robo** Schau mal, wenn du mit dem Finger eine Annahme berührst, zeigt es dir, -wie die Klammern gesetzt sind. Irre… - -**Du** Ah ich sehe, also `({A} ∧ {B}) ∨ {A}`! - -**Du** Ich glaube den ganzen Zircus hier langsam nicht mehr: -Zuerst ein \"Und\" im Ziel, dann \"Und\" in der Annahme, dann \"Oder\" im Ziel und jetzt -\"Oder\" in der Annahme, die haben sich doch abgesprochen! - -**Robo** Lass ihnen doch ihren Spaß. -Wir sind ja gleich hier fertig, und können zu einem interessanteren Planeten weiterfliegen. - -**Du** Also, wieder `rcases …`? - -**Robo** Ja, aber diesmal nicht `rcases {h} with ⟨h₁, h₂⟩`, sondern `rcases {h} with h | h`." - rcases h with h | h - Hint "**Robo** -Jetzt musst du dein Ziel zweimal beweisen: -Einmal unter Annahme der linken Seite `{A} ∨ {B}`, -und einmal unter Annahme der rechten Seite `{A}`. -Hier haben nehmen wir an, die linke Seite -sei wahr." - Hint (hidden := true) " **Robo** Wie man mit einem Und in den Annahmen umgeht, -weißt du doch schon: -`rcases h with ⟨h₁, h₂⟩`. Zur Erinnerung: Für die Klammern schreibst du `\\<>`." - rcases h with ⟨h₁, h₂⟩ - Hint "**Robo** Jetzt musst du dein Ziel zweimal beweisen: -Einmal unter Annahme der linken Seite `{A}`, -und einmal unter Annahme der rechten Seite `{A} ∨ {B}`. Hier haben nehmen wir an, die linke Seite -sei wahr." - assumption - assumption - -Conclusion -"**Du** Ok, das scheint ihn zufriedenzustellen. Nur noch eine Seele… -Kannst du mir vorher noch einmal kurz alles Leansch zusammenfassen, -das du mir bis hierher beigebracht hast? - -Robo strahlt überglücklich. Noch *nie* warst du so auf ihn angewiesen. - -**Robo** Na klar, schau her! - -## Notationen / Begriffe - -| | Beschreibung | -|:--------------|:-------------------------------------------------------------------------| -| *Goal* | Was aktuell zu beweisen ist. | -| *Annahme* | Objekte & Resultate, die man zur Verfügung hat. | -| *Taktik* | Befehl im Beweis. Entspricht einem Beweisschritt. | -| `ℕ` | Typ aller natürlichen Zahlen. | -| `0, 1, 2, …` | Explizite natürliche Zahlen. | -| `=` | Gleichheit. | -| `≠` | Ungleichheit. Abkürzung für `¬(·=·)`. | -| `Prop` | Typ aller logischen Aussagen. | -| `True` | Die logische Aussage `(True : Prop)` ist bedingungslos wahr. | -| `False` | Die logische Aussage `(False : Prop)` ist bedingungslos falsch. | -| `¬` | Logische Negierung. | -| `∧` | Logisch UND. | -| `∨` | Logisch ODER. | -| `(n : ℕ)` | Eine natürliche Zahl. | -| `(A : Prop)` | Eine logische Aussage. | -| `(ha : A)` | Ein Beweis, dass die logische Aussage `(A : Prop)` wahr ist. | -| `(h : A ∧ B)` | Eine Annahme, die den Namen `h` bekommen hat. | -| `⟨·,·⟩` | Schreibweise für Struktur mit mehreren Feldern (kommt später im Detail). | -| `h.1, h.2, …` | Die einzelnen Felder der Stuktur. Auch `h.[Name des Feldes]` | - - -## Taktiken - -Die Worte, die du aktiv gebrauchen musst, heißen zusammengefasst `Taktiken`. Hier sind alle Taktiken, die wir auf diesem Planeten gebraucht haben: - -| | Taktik | Beispiel | -|:---|:--------------------------|:--------------------------------------------------| -| 1 | `rfl` | Beweist `A = A`. | -| 2 | `assumption` | Sucht das Goal in den Annahmen. | -| 3 | `contradiction` | Sucht einen Widerspruch. | -| 4 | `trivial` | Kombiniert die obigen drei Taktiken (und mehr). | -| 5 | `constructor` | Teilt ein UND im Goal auf. | -| 6 | `left`/`right` | Beweist eine Seite eines ODER im Goal. | -| 7ᵃ | `rcases h with ⟨h₁, h₂⟩` | Teilt ein UND in den Annahmen auf. | -| 7ᵇ | `rcases h with h \\| h` | Teilt ein ODER in den Annahmen in zwei Fälle auf. | - -**Du** Woher weißt du das eigentlich alles? - -**Robo** Keine Ahnung. War, glaube ich, vorinstalliert. -" - - -NewTactic assumption rcases -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/Proposition/L13_Summary.lean b/server/adam/Adam/Levels/Proposition/L13_Summary.lean deleted file mode 100644 index ec23431..0000000 --- a/server/adam/Adam/Levels/Proposition/L13_Summary.lean +++ /dev/null @@ -1,117 +0,0 @@ -import Adam.Metadata -import Std.Tactic.RCases -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "Proposition" -Level 14 - -Title "Zusammenfassung" - -Introduction -" -Der letzte Untertan tritt vor. Ihr Anliegen ist etwas komplizierter als die vorherigen. - -**Robo** Wirf einfach alles drauf, was du gelernt hast. -Hier, ich bin sogar so nett und zeig dir noch einmal die vier -wichtigsten Taktiken für diese Situation an. - -| (Übersicht) | Und (`∧`) | Oder (`∨`) | -|-------------|:-------------------------|:------------------------| -| Annahme | `rcases h with ⟨h₁, h₂⟩` | `rcases h with h \\| h` | -| Goal | `constructor` | `left`/`right` | -" - --- Note: The other direction would need arguing by cases. - -Statement "" - (A B C : Prop) (h : A ∨ (B ∧ C)) : (A ∨ B) ∧ (A ∨ C) := by - Hint (hidden := true) - "**Robo**: Ich würd zuerst die Annahme {h} mit `rcases {h}` aufteilen." - Branch - constructor - · rcases h with h' | h' - · left - assumption - · rcases h' with ⟨h₁, h₂⟩ - right - assumption - · rcases h with h' | h' - · left - assumption - · rcases h' with ⟨h₁, h₂⟩ - right - assumption - rcases h - Hint (hidden := true) "**Robo**: Jetzt kannst du das `∧` im Goal mit `constructor` angehen." - · constructor - · left - assumption - · left - assumption - · Hint (hidden := true) - "**Robo**: Hier würde ich die Annahme {h} nochmals mit `rcases` aufteilen." - Branch - constructor - · Hint "**Robo**: Der Nachteil an der Reihenfolge ist, dass du jetzt in jedem Untergoal -`rcases h` aufrufen musst." - Branch - right - rcases h with ⟨h₁, h₂⟩ - assumption - rcases h with ⟨h₁, h₂⟩ - right - assumption - · Branch - right - rcases h with ⟨h₁, h₂⟩ - assumption - rcases h with ⟨h₁, h₂⟩ - right - assumption - rcases h with ⟨h₁, h₂⟩ - constructor - · right - assumption - · right - assumption - - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : B ∧ C) : (A ∨ B) ∧ (A ∨ C) => --- "**Robo** Das `∧` in der Annahme kannst du mit `rcases {h} with ⟨h₁, h₂⟩` zerlegen." - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) : (A ∨ B) ∧ (A ∨ C) => --- "**Robo** Das `∧` im Goal kannst du mit `constructor` zerlegen." - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : A ∨ (B ∧ C)) : (A ∨ B) ∧ (A ∨ C) => --- "**Robo** Das `∨` in der Annahme kannst du mit `rcases h with h | h` zerlegen." - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : A ∨ (B ∧ C)) : (A ∨ B) => --- "**Robo** Das `∨` in der Annahme kannst du mit `rcases h with h | h` zerlegen." - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : A ∨ (B ∧ C)) : (A ∨ C) => --- "**Robo** Das `∨` in der Annahme kannst du mit `rcases h with h | h` zerlegen." - - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : B ∧ C) : (A ∨ B) => --- "**Robo** Das `∧` in der Annahme kannst du mit `rcases h with ⟨h₁, h₂⟩` zerlegen." - --- HiddenHint (A : Prop) (B : Prop) (C : Prop) (h : B ∧ C) : (A ∨ C) => --- "**Robo** Das `∧` in der Annahme kannst du mit `rcases {h} with ⟨h₁, h₂⟩` zerlegen." - --- -- TODO: Hint nur Anhand der Annahmen? - --- HiddenHint (A : Prop) (B : Prop) : A ∨ B => --- "**Robo** `left` oder `right`?" - -Conclusion -" -**Robo** Bravo! Jetzt aber nichts wie weg hier, bevor sich eine neue Schlange bildet! - -Königin *Logisinde* ist in der Zwischenzeit eingeschlafen, und ihr stehlt euch heimlich davon. -" - -NewTactic left right assumption constructor rcases rfl contradiction trivial -DisabledTactic tauto diff --git a/server/adam/Adam/Levels/SetFunction.lean b/server/adam/Adam/Levels/SetFunction.lean deleted file mode 100644 index a6f2b4b..0000000 --- a/server/adam/Adam/Levels/SetFunction.lean +++ /dev/null @@ -1,8 +0,0 @@ -import Adam.Levels.SetFunction.L01_Image -import Adam.Levels.SetFunction.L02_Preimage -import Adam.Levels.SetFunction.L03_Range -import Adam.Levels.SetFunction.L04_ImageUnion - -Game "Adam" -World "SetFunction" -Title "Abbildungen 2" diff --git a/server/adam/Adam/Levels/SetFunction/L01_Image.lean b/server/adam/Adam/Levels/SetFunction/L01_Image.lean deleted file mode 100644 index 2499c3a..0000000 --- a/server/adam/Adam/Levels/SetFunction/L01_Image.lean +++ /dev/null @@ -1,76 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetFunction" -Level 1 - -Title "" - -open Set - -set_option tactic.hygienic false - -Introduction -" -Das Bild einer Funktion ist eine Menge, die als `f '' S` geschrieben wird. -In der Mathe ist das normalerweise als $f(S)$ geschrieben. - -Mit `ext i` kann man Gleichheit von Mengen angehen. -" - - --- Wenn man mit Abildungen auf Mengen arbeitet, muss man in Lean etwas aufpassen, um --- die Typen (z.B. `(U : Type _)`) und Mengen von diesen Typen (z.B. `(S : Set U)`) --- zu unterscheiden. - --- Abbildungen sind prinzipiell immer auf Typen definiert. Wenn eine Funktion nicht --- auf dem ganzen Typen definiert ist, hat man prinzipiell zwei Optionen: - --- 1. Nach dem Motto \"Junk in, junk out\" werden in der Mathlib Funktionen --- oft einfach auf irgendwas gesetzt wenn sie nicht definiert sind, so gibt `1 / 0` in `ℕ` --- einfach `0`. Dies funktioniert, weil dann alle relevanten Theoreme, die von `x / n` --- handeln, dann Annahmen der Form `(h : n ≠ 0)` haben. --- 2. Man kann auch Funktionen auf *Subtypen* definieren, also z.B. auf `ℕ+`. - - --- /- Image of Union -/ --- lemma image_unionₓ - -Statement -"" - (S T : Set ℕ) (f : ℕ → ℕ) : (f '' S) ∪ (f '' T) = f '' (S ∪ T) := by - Hint "Fang mal mit `ext i` an." - ext i - rw [mem_union] - simp_rw [mem_image] - constructor - intro h - rcases h with ⟨x, hx, hx'⟩ | ⟨x, hx, hx'⟩ - use x - constructor - apply mem_union_left - assumption - assumption - use x - constructor - apply mem_union_right - assumption - assumption - rintro ⟨x, hx, hx'⟩ - rw [mem_union] at hx - rcases hx with hx | hx - left - use x - constructor - assumption - assumption - right - use x - constructor - assumption - assumption - -NewTactic ext -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetFunction/L02_Preimage.lean b/server/adam/Adam/Levels/SetFunction/L02_Preimage.lean deleted file mode 100644 index 26dbd23..0000000 --- a/server/adam/Adam/Levels/SetFunction/L02_Preimage.lean +++ /dev/null @@ -1,33 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "SetFunction" -Level 2 - -Title "" - -open Set - -Introduction -" -Das Urbild einer Menge `U` unter einer Funktion `f` ist mit `f ⁻¹' U` bezeichnet. - -Note: `f ⁻¹` ist das abstrakte, gruppentheoretische Inverse von `f`, was generell nicht existieren muss, -deshalb wurde die andere Notation hier gewählt - -" - -Statement - (U : Set ℕ) (f : ℕ → ℕ) : U ⊆ f ⁻¹' (f '' U) := by - Hint "Fang wieder mal mit `intro` an." - intro x hx - Hint "Mit `rw [preimage]` kannst du sehen, wie das Urbild definiert ist." - rw [preimage] - Hint "Also musst du jetzt ein Element `y` angeben sodass `f y` in `f '' U` liegt." - use x - constructor - assumption - rfl - -NewDefinition Set.preimage diff --git a/server/adam/Adam/Levels/SetFunction/L03_Range.lean b/server/adam/Adam/Levels/SetFunction/L03_Range.lean deleted file mode 100644 index e30baf6..0000000 --- a/server/adam/Adam/Levels/SetFunction/L03_Range.lean +++ /dev/null @@ -1,21 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "SetFunction" -Level 3 - -Title "" - -Introduction -" -" - -Statement -"" - (U : Set ℕ) (f : ℕ → ℕ) : U ⊆ f ⁻¹' (f '' U) := by - intro x hx - use x - constructor - assumption - rfl diff --git a/server/adam/Adam/Levels/SetFunction/L04_ImageUnion.lean b/server/adam/Adam/Levels/SetFunction/L04_ImageUnion.lean deleted file mode 100644 index 36090e2..0000000 --- a/server/adam/Adam/Levels/SetFunction/L04_ImageUnion.lean +++ /dev/null @@ -1,20 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "SetFunction" -Level 4 - -Title "" - -Introduction -" -Wenn man Aussagen über Familien von Mengen machen will, macht man das mit -`(N : I → Set V)`, also also Funktionen von einer Indexmenge. -" - -Statement -"" - (I U V : Type _) (f : U → V) (N : I → Set V) : - f ⁻¹' (⋃ (i : I), N i) = ⋃ i, f ⁻¹' (N i) := by - simp diff --git a/server/adam/Adam/Levels/SetTheory.lean b/server/adam/Adam/Levels/SetTheory.lean deleted file mode 100644 index f2e240c..0000000 --- a/server/adam/Adam/Levels/SetTheory.lean +++ /dev/null @@ -1,45 +0,0 @@ -import Adam.Levels.SetTheory.L01_Univ -import Adam.Levels.SetTheory.L02_Empty -import Adam.Levels.SetTheory.L03_Subset -import Adam.Levels.SetTheory.L04_SubsetEmpty -import Adam.Levels.SetTheory.L05_Empty -import Adam.Levels.SetTheory.L06_Nonempty -import Adam.Levels.SetTheory.L07_UnionInter -import Adam.Levels.SetTheory.L08_UnionInter -import Adam.Levels.SetTheory.L09_Complement -import Adam.Levels.SetTheory.L10_Morgan -import Adam.Levels.SetTheory.L11_SSubset -import Adam.Levels.SetTheory.L12_Insert -import Adam.Levels.SetTheory.L13_Insert --- import Adam.Levels.SetTheory.L14_SetOf --- import Adam.Levels.SetTheory.L15_Powerset --- import Adam.Levels.SetTheory.L16_Disjoint --- import Adam.Levels.SetTheory.L17_SetOf --- import Adam.Levels.SetTheory.L18_SetOf --- import Adam.Levels.SetTheory.L19_Subtype - -Game "Adam" -World "SetTheory" -Title "Mengenlehre" - -Introduction -"[Note: von hier an sind die Levels leider noch nicht vollständig. Evt. müsst ihr etwas ausprobieren oder -fragen, wenn ihr nicht weiterkommt.] - -Der größere der beiden Monde sieht dunkelrot und karg aus. Trotzdem sollen dort nomadische -Gesellschaften wohnen, die sich in der Einöde zurechtfinden. - -Ihr steuert einen der wenigen befestigten Standorte am Fusse eines Berges an. - -**Robo**: Die Bevölkerung hier lebt so abgekapselt vom Rest des Universums, dass sie sich -vermutlich noch viel besser mit alter Sprache und Schrift auskennt. - -**Du**: Hoffen wir, dass sie uns weiterhelfen können dieses Buch der Urbilder zu entschlüsseln. - -Sofort begrüßt euch eine ältere Frau, die sich als *Mengea*, die Beschützerin des Mondes, -vorstellt. -" - --- Game "Adam" --- World "SetTheory2" --- Title "Mehr Mengenlehre" diff --git a/server/adam/Adam/Levels/SetTheory/L01_Univ.lean b/server/adam/Adam/Levels/SetTheory/L01_Univ.lean deleted file mode 100644 index b6017b8..0000000 --- a/server/adam/Adam/Levels/SetTheory/L01_Univ.lean +++ /dev/null @@ -1,58 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false -set_option autoImplicit false - -Game "Adam" -World "SetTheory" -Level 1 - -Title "Mengen" - -Introduction -" -**Mengea**: Ich würde leider den Inhalt jenes Buches eh nicht verstehen. Aber der beste Weg für -euch, dieses zu entschlüsseln ist, euch ausgiebig mit der Bevölkerung hier zu unterhalten. -Lebt mit ihnen, redet mit ihnen und ihr werdet die Sprache automatisch lernen. - -**Mengea**: Seit aber vorgewarnt, die Leute hier denken ganz viel über Mengen nach, -womit sie immer *homogene Mengen* meinen. Eine Menge natürlicher Zahlen `{1, 4, 6}` ist -verständlich, aber sowas wie eine Menge `{(2 : ℕ), {3, 1}, \"e\", (1 : ℂ)}` gibt es hier -einfach nicht. Punkt. - -**Robo**: Als Kontext: Wenn `A` ein beliebiger `Type` ist, dann ist `(U : Set A)` eine Menge -mit Elementen aus `A` - -**Mengea**: Damit ich weiss, dass ihr euch grundsätzlich mit den Leuten austauschen könnt, -erklärt mir doch folgendes: -" - -open Set - -Statement Set.mem_univ "" {A : Type} (x : A) : x ∈ (univ : Set A) := by - Hint "**Du**: Also `A` ist ein `Type`, `x` ist ein Element in `A`… - - **Robo** … und `univ` ist die Menge aller Elemente in `A`. - - **Du** ist das nicht einfach `A` selber? - - **Robo** Fast, aber das eine ist ein `Type`, das andere eine Menge, also vom Typ `Set A`. - - **Du**: Unlogisch. - - **Mengites**: Naja, Typen und Mengen sind halt zwei unterschiedliche Sachen und wenn ihr - über Mengen sprechen wollt, müssen alles Mengen sein. - - **Du**: Na gut. Und wieso `x ∈ univ` und nicht `x : univ` wie bei Typen? - - **Robo**: Jedes Element `(x : A)` hat entweder die Eigenschaft `x ∈ U` oder `x ∉ U` für eine - Menge `(U : Set A)`. (`\\in`, `\\nin`) - - **Du**: Also das ist ja dann `trivial`. Hoffentlich sehen die das hier auch so…" - trivial - -LemmaTab "Set" - -Conclusion "**Mengea**: Ja das stimmt schon. Dann wünsche ich euch viel Erfolg auf eurer Reise!" diff --git a/server/adam/Adam/Levels/SetTheory/L02_Empty.lean b/server/adam/Adam/Levels/SetTheory/L02_Empty.lean deleted file mode 100644 index 3f45c6d..0000000 --- a/server/adam/Adam/Levels/SetTheory/L02_Empty.lean +++ /dev/null @@ -1,34 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 2 - -Title "leere Menge" - -Introduction -" -Ihr zieht also durch die Gegend und redet mit den Leuten. Ein Junge rennt zu euch und fragt: -" - -open Set - -Statement Set.not_mem_empty "" {A : Type} (x : A) : - x ∉ (∅ : Set A) := by - Hint "**Du**: Kein Element ist in der leeren Menge enthalten? Das ist ja alles - tautologisches Zeugs... - - **Robo**: Dann behaupte das doch." - tauto - -NewLemma Set.mem_univ -LemmaTab "Set" - -Conclusion "Der Junge rennt weiter. - -**Du**: So wird das ganze schon angenehmer. - -**Robo**: Die Leere Menge schreibst du mit `\\empty` falls du die nochmals brauchst." diff --git a/server/adam/Adam/Levels/SetTheory/L03_Subset.lean b/server/adam/Adam/Levels/SetTheory/L03_Subset.lean deleted file mode 100644 index eea45e1..0000000 --- a/server/adam/Adam/Levels/SetTheory/L03_Subset.lean +++ /dev/null @@ -1,49 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 3 - -Title "Teilmengen" - -Introduction -" -Ihr bemerkt, dass mit dem Jungen noch zwei andere -Kinder zuhörten. Eines der beiden Mädchen hat ebenfalls eine Frage. -" - --- Hat man zwei Mengen `(A B : Set ℕ)` kann man fragen, ob diese Teilmengen --- voneinander sind: `A ⊆ B` (`\\sub`/`\\ss`) ist die Notation für Teilmengen, die auch gleich --- sein können. - --- `A ⊆ B` ist als `∀ x, x ∈ A → x ∈ B` definiert, das heisst, ein `⊆` kann immer auch mit `intro x hx` --- angegangen werden. - --- Die Taktik `tauto` macht das automatisch, aber um dies zu lernen ist `tauto` hier deaktiviert. --- Benutze also `intro`: - -namespace MySet - -open Set - -Statement Set.subset_univ (A : Set ℕ) : A ⊆ univ := by - Hint "**Robo**: `A ⊆ B` ist als `∀ x, x ∈ A → x ∈ B` definiert. - - **Du**: Also kann ich mit `intro` anfangen, wie ich das bei einem `∀` funktioniert? - - **Robo**: Das ist korrekt." - intro h hA - Hint (hidden := true) "**Robo**: Das dürfte eine Trivialität sein." - trivial --apply mem_univ -- or `trivial`. - -DisabledTactic tauto simp -NewDefinition Symbol.Subset -LemmaTab "Set" - -Conclusion "Damit drehen sich die beiden Mädchen um und folgen dem Jungen." - -end MySet diff --git a/server/adam/Adam/Levels/SetTheory/L04_SubsetEmpty.lean b/server/adam/Adam/Levels/SetTheory/L04_SubsetEmpty.lean deleted file mode 100644 index 56a15af..0000000 --- a/server/adam/Adam/Levels/SetTheory/L04_SubsetEmpty.lean +++ /dev/null @@ -1,54 +0,0 @@ -import Adam.Metadata -import Adam.Levels.SetTheory.L03_Subset - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 4 - -Title "Teilmengen" - -Introduction -" -Etwas weiter kommt ihr an einem kleinen Gemüsestand vorbei. Da ihr nicht so -richtig einen Plan habt, fragt ihr den Verkäufer. - -**Verkäufer**: Hier ist was ganz wichtiges, was ihr noch oft brauchen werdet: -Ein zentrales Lemma ist `Subset.antisymm_iff` welches folgendes sagt: - -``` -lemma antisymm_iff {α : Type} {A B : Set α} : A = B ↔ A ⊆ B ∧ B ⊆ A -``` - -Fast immer wenn man Gleichheiten von Mengen zeigen muss, will man diese in zwei Ungleichungen -aufteilen. -" - -open Set Subset - -Statement Set.subset_empty_iff {A : Type _} (s : Set A) : - s ⊆ ∅ ↔ s = ∅ := by - Hint "**Du**: Ja, die einzige Teilmenge der leeren Menge ist die leere Menge. - Das ist doch eine Tautologie? - - **Robo**: Ja schon, aber zuerst einmal explizit." - Hint (hidden := true) "**Robo**: Fang doch einmal mit `constructor` an." - constructor - intro h - Hint "**Robo**: Gleichheit zwischen Mengen kann man zum Beispiel zeigen, - indem man `A ⊆ B` und `B ⊆ A` zeigt. - - Dieser Schritt ist `apply Subset.antisymm`" - apply Subset.antisymm - assumption - Hint "**Robo**: Hier ist das Lemma `empty_subset` hilfreich." - apply empty_subset - intro h - rw [h] - -DisabledTactic tauto -NewLemma Set.Subset.antisymm Set.Subset.antisymm_iff Set.empty_subset Set.subset_univ -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L05_Empty.lean b/server/adam/Adam/Levels/SetTheory/L05_Empty.lean deleted file mode 100644 index 5581575..0000000 --- a/server/adam/Adam/Levels/SetTheory/L05_Empty.lean +++ /dev/null @@ -1,32 +0,0 @@ -import Adam.Metadata -import Adam.Levels.SetTheory.L04_SubsetEmpty - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 5 - -Title "Empty" - -Introduction -" -Zeige folgendes Lemma, welches wir gleich brauchen werden: -" - -open Set - - -Statement Set.eq_empty_iff_forall_not_mem -"" - {A : Type _} (s : Set A) : - s = ∅ ↔ ∀ x, x ∉ s := by - Hint "Das Lemma `subset_empty_iff` von letzter Aufgabe könnte hilfreich sein." - rw [←subset_empty_iff] - rfl -- This is quite a miracle :) - -NewTactic constructor intro rw assumption rcases simp tauto trivial -NewLemma Set.subset_empty_iff -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L06_Nonempty.lean b/server/adam/Adam/Levels/SetTheory/L06_Nonempty.lean deleted file mode 100644 index ae0c905..0000000 --- a/server/adam/Adam/Levels/SetTheory/L06_Nonempty.lean +++ /dev/null @@ -1,37 +0,0 @@ -import Adam.Metadata -import Adam.Levels.SetTheory.L05_Empty - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 6 - -Title "Nonempty" - -Introduction -" -Das Gegenteil von `A = ∅` ist `A ≠ ∅`, aber in Lean wird der Ausdruck `A.Nonempty` bevorzugt. -Dieser ist dadurch existiert, dass in `A` ein Element existiert: `∃x, x ∈ A`. - -Zeige dass die beiden Ausdrücke äquivalent sind: -" - -open Set - -Statement Set.nonempty_iff_ne_empty - {A : Type _} (s : Set A) : - s.Nonempty ↔ s ≠ ∅ := by - Hint "Am besten fängst du mit `unfold Set.Nonempty` an." - unfold Set.Nonempty - Hint "Mit `ne_eq` und `eq_empty_iff_forall_not_mem` kannst du hier weiterkommen." - rw [ne_eq, eq_empty_iff_forall_not_mem] - Hint (hidden := true) "`push_neg` kann hier helfen." - push_neg - rfl - -NewLemma ne_eq Set.eq_empty_iff_forall_not_mem -NewDefinition Set.Nonempty -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L07_UnionInter.lean b/server/adam/Adam/Levels/SetTheory/L07_UnionInter.lean deleted file mode 100644 index 772a94e..0000000 --- a/server/adam/Adam/Levels/SetTheory/L07_UnionInter.lean +++ /dev/null @@ -1,30 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 7 - -Title "Schnittmenge und Vereinigung" - -Introduction -" -Die klassischen Mengenoperationen sind -Schnittmenge `∩` (`\\inter`), Vereinigung `∪` (`\\union`) und -Differenz `\\` (`\\\\`). - -Die Taktik `simp` kann triviale Aussagen with Vereinigung mit der -leeren Menge vereinfachen. -" - -open Set - -Statement -"" (A B : Set ℕ) : (A ∪ ∅) ∩ B = A ∩ (univ ∩ B) := by - simp - -NewTactic constructor intro rw assumption rcases simp tauto trivial -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L08_UnionInter.lean b/server/adam/Adam/Levels/SetTheory/L08_UnionInter.lean deleted file mode 100644 index 7b0076a..0000000 --- a/server/adam/Adam/Levels/SetTheory/L08_UnionInter.lean +++ /dev/null @@ -1,40 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false - -Game "Adam" -World "SetTheory" -Level 8 - -Title "Schnittmenge und Vereinigung" - -Introduction -" -Ansonsten gibt es jegliche Lemmas in der Mathlib -die beim Umgang mit diesen Operationen weiterhelfen. Schaue in der Bibliothek auf -der Seite nach Lemmas, die dir hier weiterhelfen! - -Denk daran, die lemma Namen sind blockweise aus der Aussage konstruiert. Ein lemma mit -der Aussage `C \\ (A ∩ B) + …` wird vermutlich mit `diff_inter_…` anfangen. -" - -open Set - -Statement -"" - (A B : Set ℕ) : univ \ (A ∩ B) = (univ \ A) ∪ (univ \ B) ∪ (A \ B) := by - rw [diff_inter] - Hint (hidden := true) "mit `union_assoc` und `union_diff_distrib` kannst du - auf der rechten Seite weiterkommen." - rw [union_assoc] - rw [←union_diff_distrib] - rw [univ_union] - -NewTactic constructor intro rw assumption rcases simp tauto trivial -DisabledTactic tauto -NewLemma Set.diff_inter Set.union_assoc Set.union_diff_distrib Set.univ_union -LemmaTab "Set" - -Conclusion "Wie du vielleicht bemerkt hast, könnte `tauto` sowas automatisch lösen." diff --git a/server/adam/Adam/Levels/SetTheory/L09_Complement.lean b/server/adam/Adam/Levels/SetTheory/L09_Complement.lean deleted file mode 100644 index a776fa2..0000000 --- a/server/adam/Adam/Levels/SetTheory/L09_Complement.lean +++ /dev/null @@ -1,40 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 9 - -Title "Komplement" - -Introduction -" -Das Komplement einer Menge wird als `Aᶜ` (`\\^c`) geschrieben. Wichtige Lemmas -sind `not_mem_compl_iff` und `compl_eq_univ_diff`. -" - -open Set - -Statement -"" - (A : Set ℕ) (h : Aᶜ ⊆ A) : A = univ := by - Hint "Start doch mit `apply Subset.antisymm`." - apply Subset.antisymm - simp only [subset_univ] - Hint "Da `⊆` als `∀x, x ∈ A → x ∈ B ` definiert ist, fängst du - am besten mit `intro` an." - intros x hx - Hint "Eine Möglichkeit ist, eine Fallunterscheidung zu machen: `by_cases g: {x} ∈ {A}ᶜ`." - by_cases h4 : x ∈ Aᶜ - Hint "Hier könnte `mem_of_subset_of_mem` hilfreich werden." - apply mem_of_subset_of_mem h - assumption - Hint "Diese Richtung geben wir als Lemma: `not_mem_compl_iff`." - rw [not_mem_compl_iff] at h4 - assumption - -NewTactic constructor intro rw assumption rcases simp tauto trivial -NewLemma Set.not_mem_compl_iff Set.mem_of_subset_of_mem Set.compl_eq_univ_diff -DisabledTactic tauto -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L10_Morgan.lean b/server/adam/Adam/Levels/SetTheory/L10_Morgan.lean deleted file mode 100644 index b9141a4..0000000 --- a/server/adam/Adam/Levels/SetTheory/L10_Morgan.lean +++ /dev/null @@ -1,61 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 10 - -Title "Morgansche Regeln" - -Introduction -" -Die De-Morgan'schen Regeln sagen `(A ∪ B)ᶜ = Aᶜ ∩ Bᶜ` -und `(A ∩ B)ᶜ = Aᶜ ∪ Bᶜ` sind in Lean als - -`compl_union` und `compl_inter`. - - -Zudem gibt es die Lemmas `mem_compl_iff : x ∈ Aᶜ ↔ x ∉ A` und -`not_mem_compl_iff`, mit welchen -man die de-Morganschen Regeln einfach selber beweisen könnten. - - -Die meisten Aufgaben über Mengen sind eine Kombination von `rw` und `simp_rw` verschiedenster -NewLemma in `import Mathlib.Data.Set`. - -Die Taktik `simp_rw` funktioniert ähnlich wie `rw`, aber sie versucht jedes Lemma so oft -wie möglich anzuwenden. Wir kennen also 4 etwas verwandte Optionen um Lemmas und Theoreme zu -brauchen: - -- `rw [lemma_A, lemma_B]`: führt jedes Lemma genau einmal aus in der Reihenfolge. -- `simp_rw [lemma_A, lemma_B]` : führt jedes Lemma in Reihenfolge so oft aus wie möglich. -- `simp only [lemma_A, lemma_B]` : sucht eine Kombination der beiden Lemmas, ohne bestimmte - Reihenfolge. -- `simp [lemma_A, lemma_B]` : Braucht die beiden Lemmas und alle simp-Lemmas. -" - -open Set - -#check compl_union -#check compl_inter -#check mem_compl_iff - -Statement - (A B C : Set ℕ) : (A \ B)ᶜ ∩ (C \ B)ᶜ = ((univ \ A) \ C) ∪ (univ \ Bᶜ) := by - Hint "Oft kann es auch nützlich sein, mit `rw [← …]` rückwärts umzuschreiben. - Der ganze Level ist mit `rw`/`simp_rw` und den Lemmas in deiner Bibliothek - lösbar." - rw [←compl_union] - rw [←union_diff_distrib] - rw [diff_diff] - simp_rw [←compl_eq_univ_diff] - rw [←compl_inter] - rw [diff_eq_compl_inter] - rw [inter_comm] - -OnlyTactic rw simp_rw tauto trivial assumption rfl «have» «suffices» -NewTactic simp_rw -LemmaTab "Set" -NewLemma Set.mem_compl_iff Set.compl_union Set.diff_diff Set.compl_inter - Set.diff_eq_compl_inter Set.inter_comm diff --git a/server/adam/Adam/Levels/SetTheory/L11_SSubset.lean b/server/adam/Adam/Levels/SetTheory/L11_SSubset.lean deleted file mode 100644 index 969d7d0..0000000 --- a/server/adam/Adam/Levels/SetTheory/L11_SSubset.lean +++ /dev/null @@ -1,38 +0,0 @@ -import Adam.Metadata -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 11 - -Title "Strikte Teilmenge" - -Introduction -" -Strikte Teilmengen sind in Lean eher selten, aber wir schauen sie hier -trotzdem kurz an : `A ⊂ B` (`\\ssub`) bedeutet `(A ⊆ B) ∧ (¬B ⊆ A)`. -Entsprechend, kann man die gleichen Methoden wie beim UND benützen -(`rcases`/`constructor`). - -Zudem kann man mit `rw [ssubset_def]` explizit die Definition einsetzen. - -Note: `rw [subset_def]` macht das gleiche für `⊆`. -" - -open Set - -Statement -"" - (A B : Set ℕ) (h : A ⊂ B) : ∃ x, x ∈ B \ A := by - cases' h with h₁ h₂ - rw [subset_def] at h₂ - rw [not_forall] at h₂ - cases' h₂ with x hx - use x - rw [not_imp] at hx - rw [mem_diff] - exact hx - -NewTactic constructor intro rw assumption rcases simp tauto trivial -NewLemma Set.subset_def Set.ssubset_def not_imp Set.mem_diff -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L12_Insert.lean b/server/adam/Adam/Levels/SetTheory/L12_Insert.lean deleted file mode 100644 index a1195c4..0000000 --- a/server/adam/Adam/Levels/SetTheory/L12_Insert.lean +++ /dev/null @@ -1,36 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 12 - -Title "Konkrete Mengen" - -Introduction -" -Nun schauen wir uns konkrete Mengen an. Man schreibt diese mit -geschweiften Klammern: `{0, 4, 117, 3}`. Meistens muss man -den Typ explizit angeben, weil Lean nicht weiss, ob man mit `Set` (Mengen) -oder `Finset` (endliche Mengen) arbeiten möchte: `({4, 9} : Set ℕ)`. - -`Finset` schauen wir uns später an. - -Um mit expliziten Mengen zu arbeiten, ist die Implementationsweise wichtig. - -Intern ist eine Menge `{0, 9, 5, 2}` iterativ als Vereinigung von -Singletons definiert: `{0} ∪ ( {9} ∪ ( {5} ∪ {2} ))`. - -Die folgende Aufgabe ist entsprechend mit `rfl` lösbar. -" - -open Set - -Statement -"Die Menge $\\{4, 9\\}$ ist per Definition $\\{4}\\cup\\{9\\}$." : - ({4, 9} : Set ℕ) = Set.insert 4 {9} := by - rfl - -OnlyTactic rfl -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L13_Insert.lean b/server/adam/Adam/Levels/SetTheory/L13_Insert.lean deleted file mode 100644 index 6dde7b9..0000000 --- a/server/adam/Adam/Levels/SetTheory/L13_Insert.lean +++ /dev/null @@ -1,39 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 13 - -Title "Konkrete Mengen" - -Introduction -" -Um zu überprüfen, dass gewisse Elemente in -konkreten Mengen enthalten sind, gibt es nicht direkt eine Taktik, aber ein -einfaches Rezept: - -``` -simp_rw [mem_insert_iff, mem_singleton_iff] at * -``` - -vereinfacht Aussagen der Form `6 ∈ {0, 6, 1}` zu `(6 = 0) ∨ (6 = 6) ∨ (6 = 1)`, -und dann kann `tauto` diese Aussage beweisen. - -Bei `⊆` kann man wie schon vorher zuerst mit `intro x hx` die Definition -auseinandernehmen und dann gleich vorgehen. - -" - -open Set - -Statement : - ({2, 3, 5} : Set ℕ) ⊆ {4, 2, 5, 7, 3} := by - Hint "Fang wieder mit `rw [subset_def]` oder direkt mit `intro` an." - intro x hx - simp_rw [mem_insert_iff, mem_singleton_iff] at * - tauto - -NewLemma Set.mem_insert_iff Set.mem_singleton_iff -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L14_SetOf.lean b/server/adam/Adam/Levels/SetTheory/L14_SetOf.lean deleted file mode 100644 index 88faf47..0000000 --- a/server/adam/Adam/Levels/SetTheory/L14_SetOf.lean +++ /dev/null @@ -1,36 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory2" -Level 1 - -Title "Mengen mit Konditionen" - -Introduction -" -Eine wichtige mathematische Notation ist Teilmengen zu erstellen, -die gewissen Bedingungen unterliegen. - -`{n : ℕ | Odd n}` ist die Menge aller natürlichen Zahlen, die ungerade sind. -Diese Konstruktion hat in Lean den Namen `setOf` - -Um zu beweisen, dass ein Element in einer Teilmenge mit Bedingungen ist, braucht -man `rw [mem_setOf]`. Danach muss man zeigen, dass die Bedinung für -dieses Element erfüllt ist. -" - -open Set - -Statement : 3 ∈ {n : ℕ | Odd n} := by - rw [mem_setOf] - Hint (hidden := true) "**Robo**: Zur Erinnerung, wenn du nicht mehr weisst, wie `Odd` definiert - ist, benutze `rw [Odd]`." - Branch - rw [Odd] - use 1 - ring - -NewLemma Set.mem_setOf -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L15_Powerset.lean b/server/adam/Adam/Levels/SetTheory/L15_Powerset.lean deleted file mode 100644 index 85ba280..0000000 --- a/server/adam/Adam/Levels/SetTheory/L15_Powerset.lean +++ /dev/null @@ -1,48 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -Game "Adam" -World "SetTheory2" -Level 2 - -Title "Potenzmenge" - -Introduction -" -Eine andere wichtige Menge ist die Potenzmenge einer Menge, welche als -`𝒫 A` geschrieben wird (`\\powerset`). Diese ist als `{S | S ⊆ A}` definiert, also -alle Mengen, die in $A$ enthalten sind. - -Eines der wichtigsten Lemmas ist `mem_powerset_iff: x ∈ 𝒫 s ↔ x ⊆ s` welches -im Grunde die Definition einsetzt. -" - -open Set - -Statement -"" (X Y : Set ℕ): - 𝒫 X ∪ 𝒫 Y ⊆ 𝒫 (X ∪ Y) := by - Hint "**Robo**: Fang mal mit `intro` an, wie das bei `⊆` fast immer der Fall ist." - intro A hA - Hint "**Robo**: Als nächstes must du noch die Annahme `{A} ∈ 𝒫 X ∪ 𝒫 Y` zu - `{A} ∈ (𝒫 X) ∨ {A} ∈ (𝒫 Y)` wechseln. Dafür kennst du schon ein Lemma." - rw [mem_union] at hA - Hint "**Robo**: Jetzt wär der Zeitpunkt um `mem_powerset_iff` mal überall anzuwenden." - simp_rw [mem_powerset_iff] at * - Hint "**Robo**: Jetzt kann `tauto` den rest übernehmen, vielleicht solltest du diese - Hilfe annehmen. - Wenn nicht, brauchst du vermutlich die Lemmas `Set.subset_union_of_subset_left` - und `Set.subset_union_of_subset_right`" - Branch - rcases hA with hA | hA - apply subset_union_of_subset_left - assumption - apply subset_union_of_subset_right - assumption - tauto - -NewLemma Set.mem_powerset_iff Set.subset_union_of_subset_left Set.subset_union_of_subset_right -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L16_Disjoint.lean b/server/adam/Adam/Levels/SetTheory/L16_Disjoint.lean deleted file mode 100644 index 5fc21eb..0000000 --- a/server/adam/Adam/Levels/SetTheory/L16_Disjoint.lean +++ /dev/null @@ -1,46 +0,0 @@ -import Adam.Metadata - - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory2" -Level 3 - -Title "" - -Introduction -" -Um anzunehmen, dass zwei Mengen disjunkt sind schreibt man -`Disjoint S T`, welches dadurch definiert ist das die -einzige gemeinsame Teilmenge die leere Menge ist, -also etwa `A ⊆ S → A ⊆ T → A ⊆ ∅`. - -Beachte, dass `Disjoint` in Lean genereller definiert ist als -für Mengen, deshalb siehst du die Symbole -`≤` anstatt `⊆` und `⊥` anstatt `∅`, aber diese bedeuten genau -das gleiche. -" - -open Set - -Statement : - ¬Disjoint ({n : ℤ | ∃ k, n = 2 * k} : Set ℤ) ({3, 5, 6, 9, 11} : Set ℤ) := by - Hint "**Robo**: Öffne als erstes mal `Disjoint`." - rw [Disjoint] - Branch - rw [not_forall] -- why not `push_neg`? - push_neg - Hint "**Robo**: Das sieht jetzt ein bisschen gefürchig aus, aber das ist einfach ein `∃`. - Was du jetzt angeben musst, ist eine Menge, die Teilmenge beider Mengen - `\{n : ℤ | ∃ k, n = 2 * k}` und `\{3, 5, 6, 9, 11}` ist. - " - Hint (hidden := true) "**Robo**: Versuch einmal `use \{6}`." - use {6} - Hint "**Robo**: Schau mal wie weit `simp` kommt." - simp - use 3 - ring - -NewDefinition Disjoint -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L17_SetOf.lean b/server/adam/Adam/Levels/SetTheory/L17_SetOf.lean deleted file mode 100644 index 8a0c62b..0000000 --- a/server/adam/Adam/Levels/SetTheory/L17_SetOf.lean +++ /dev/null @@ -1,36 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - - -Game "Adam" -World "SetTheory2" -Level 4 - -Title "" - -Introduction -" -" - -open Set - -Statement -"" : - {2, 7} ⊆ {n : ℕ | n = 2 ∨ (n ≤ 10 ∧ Odd n)} := by - rw [setOf_or, setOf_and] - intro x hx - rw [mem_union, mem_inter_iff] - simp_rw [mem_setOf, mem_insert_iff, mem_singleton_iff] at * - rcases hx with hx | hx - left - assumption - right - constructor - linarith - use 3 - rw [hx] - ring - -NewLemma Set.setOf_or Set.setOf_and Set.mem_inter_iff -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L18_SetOf.lean b/server/adam/Adam/Levels/SetTheory/L18_SetOf.lean deleted file mode 100644 index e183071..0000000 --- a/server/adam/Adam/Levels/SetTheory/L18_SetOf.lean +++ /dev/null @@ -1,30 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - - -Game "Adam" -World "SetTheory2" -Level 5 - -Title "" - -Introduction -" -Zu der Teilmengen-Schreibweise (`SetOf`) gibt es noch zwei spezielle -Syntax, die abundzu auftreten. - -Der erste ist `{ x ∈ S | 0 ≤ x}` ( für z.B `(S : Set ℤ)`), -welcher eine Abkürzung für `{ x : ℤ | x ∈ S ∧ 0 ≤ x}` ist. -Entsprechend hilft auch hier `setOf_and`. - -" - -open Set - -Statement -"" (S : Set ℤ) : - { x ∈ (S : Set ℤ) | 0 ≤ x} ⊆ S := by - simp - -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L19_Subtype.lean b/server/adam/Adam/Levels/SetTheory/L19_Subtype.lean deleted file mode 100644 index d0ce8da..0000000 --- a/server/adam/Adam/Levels/SetTheory/L19_Subtype.lean +++ /dev/null @@ -1,25 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory2" -Level 6 - -Title "" - -Introduction -" -" - -open Set - -Statement -"" : - 3 ∈ {n : ℕ | Odd n} := by - rw [mem_setOf] - use 1 - ring - -NewTactic constructor intro rw assumption rcases simp tauto trivial -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L20_UnionInter.lean b/server/adam/Adam/Levels/SetTheory/L20_UnionInter.lean deleted file mode 100644 index b149cb1..0000000 --- a/server/adam/Adam/Levels/SetTheory/L20_UnionInter.lean +++ /dev/null @@ -1,24 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory2" -Level 7 - -Title "" - -Introduction -" -Wir haben bereits `∪` und `∩` kennengelernt. Von beiden gibt es auch eine Version für Familien -von Mengen: $\\bigcup_i A_ i$ und $\\bigcap_j B_ j$. - -" - -open Set - -Statement -"" : True := sorry - -NewTactic constructor intro rw assumption rcases simp tauto trivial -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/L21_Summary.lean b/server/adam/Adam/Levels/SetTheory/L21_Summary.lean deleted file mode 100644 index bde2d22..0000000 --- a/server/adam/Adam/Levels/SetTheory/L21_Summary.lean +++ /dev/null @@ -1,25 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -Game "Adam" -World "SetTheory" -Level 21 - -Title "" - -Introduction -" -" - -open Set - -Statement -"" : - 3 ∈ {n : ℕ | Odd n} := by - rw [mem_setOf] - use 1 - ring - -NewTactic constructor intro rw assumption rcases simp tauto trivial -LemmaTab "Set" diff --git a/server/adam/Adam/Levels/SetTheory/PowersetPlayground.lean b/server/adam/Adam/Levels/SetTheory/PowersetPlayground.lean deleted file mode 100644 index ef09c7f..0000000 --- a/server/adam/Adam/Levels/SetTheory/PowersetPlayground.lean +++ /dev/null @@ -1,109 +0,0 @@ - - -open Set - -namespace Finset - -theorem powerset_singleton {U : Type _} [DecidableEq U] (x : U) : - Finset.powerset {x} = {∅, {x}} := by - ext y - rw [mem_powerset, subset_singleton_iff, mem_insert, mem_singleton] - -end Finset - -/- The powerset of a singleton contains only `∅` and the singleton. -/ -theorem powerset_singleton {U : Type _} (x : U) : - 𝒫 ({x} : Set U) = {∅, {x}} := by - ext y - rw [mem_powerset_iff, subset_singleton_iff_eq, mem_insert_iff, mem_singleton_iff] - -theorem subset_insert_iff_of_not_mem {U : Type _ } {s t : Set U} {a : U} (h : a ∉ s) - : s ⊆ insert a t ↔ s ⊆ t := by - constructor - · intro g y hy - specialize g hy - rw [mem_insert_iff] at g - rcases g with g | g - · rw [g] at hy - contradiction - · assumption - · intro g y hy - specialize g hy - exact mem_insert_of_mem _ g - -theorem subset_insert_iff_of_not_mem' {U : Type _ } {s t : Set U} {a : U} (h : a ∉ s) - (g : s ⊆ t) : s ⊆ insert a t := by - intro y hy - specialize g hy - exact mem_insert_of_mem _ g - -lemma mem_powerset_insert_iff {U : Type _} (A S : Set U) (x : U) : - S ∈ 𝒫 (insert x A) ↔ S ∈ 𝒫 A ∨ ∃ B ∈ 𝒫 A , insert x B = S := by - simp_rw [mem_powerset_iff] - constructor - · intro h - by_cases hs : x ∈ S - · right - use S \ {x} - rw [insert_diff_singleton, insert_eq_of_mem hs, diff_singleton_subset_iff] - exact ⟨h, rfl⟩ - · left - exact (subset_insert_iff_of_not_mem hs).mp h - · intro h - rcases h with h | ⟨B, h₁, h₂⟩ - · exact le_trans h (subset_insert x A) - · rw [←h₂] - exact insert_subset_insert h₁ - -lemma mem_powerset_insert_iff' {U : Type _} (A S : Set U) (x : U) : - S ∈ 𝒫 (insert x A) ↔ S \ {x} ∈ 𝒫 A := by - simp_rw [mem_powerset_iff, diff_singleton_subset_iff] - -lemma powerset_insert {U : Type _} (A : Set U) (x : U) : - 𝒫 (insert x A) = A.powerset ∪ A.powerset.image (insert x) := by - ext y - rw [mem_powerset_insert_iff, mem_union, mem_image] - - - - - -example : ({0} : Set ℕ) ∪ {1, 2} = {0, 2, 1} := by - rw [union_insert, singleton_union] - simp only [insert_comm, ←insert_emptyc_eq] - -example : powerset {0, 1} = {∅, {0}, {1}, {0, 1}} := by - simp_rw [powerset_insert, powerset_singleton] - simp only [image_insert_eq, union_insert, image_singleton, union_singleton] - simp only [insert_comm, ←insert_emptyc_eq] - --- This one is much slower, but it still works -example : powerset {0, 1, 2, 4} = - {∅, {0}, {1}, {0, 1}, {2}, {1, 2}, {0, 2}, {0, 1, 2}, - {4}, {0, 4}, {1, 4}, {0, 1, 4}, {2, 4}, {1, 2, 4}, {0, 2, 4}, {0, 1, 2, 4}} := by - simp_rw [powerset_insert, powerset_singleton] - simp only [image_insert_eq, union_insert, image_singleton, union_singleton] - simp only [insert_comm, ←insert_emptyc_eq] - -example : ({∅, {0}, {1}, {0, 1}} : Finset (Finset ℕ)) = {∅, {1}, {0}, {0, 1}} := by - simp only [] - -example : ({{0, 2}, {3, 5, 6}} : Set (Set ℕ)) = {{2, 0}, {5, 3, 6}} := by - rw [Subset.antisymm_iff] - constructor <;> - intro A hA <;> - simp_rw [mem_insert_iff, mem_singleton_iff] at * - · rw [pair_comm 2 0, insert_comm 5 3] - tauto - · rw [pair_comm 0 2, insert_comm 3 5] - tauto - --- A trick to compare two concrete sets. -example (A : Set ℕ) : ({{0, 2}, A, {3, 5, 6}} : Set (Set ℕ)) = {{2, 0}, {5, 3, 6}, A} := by - simp only [insert_comm, ←insert_emptyc_eq] - -example : ({{0, 2}, {3, 5, 6}} : Finset (Finset ℕ)) = {{2, 0}, {5, 3, 6}} := by - simp only - --- Trick: --- attribute [default_instance] Set.instSingletonSet diff --git a/server/adam/Adam/Levels/SetTheory/T01_Set.lean b/server/adam/Adam/Levels/SetTheory/T01_Set.lean deleted file mode 100644 index f781751..0000000 --- a/server/adam/Adam/Levels/SetTheory/T01_Set.lean +++ /dev/null @@ -1,286 +0,0 @@ --- import Adam.Metadata - --- import Adam.Options.MathlibPart - --- set_option tactic.hygienic false - --- Game "Adam" --- World "SetTheory" --- Level 1 - --- Title "Mengen" - --- Introduction --- " --- In diesem Kapitel schauen wir uns Mengen an. - --- Zuerst ein ganz wichtiger Punkt: Alle Mengen in Lean sind homogen. Das heisst, --- alle Elemente in einer Menge haben den gleichen Typ. - --- Zum Beispiel `{1, 4, 6}` ist eine Menge von natürlichen Zahlen. Aber man kann keine --- Menge `{(2 : ℕ), {3, 1}, \"e\", (1 : ℂ)}` definieren, da die Elemente unterschiedliche Typen haben. - --- Für einen Typen `{X : Type*}` definiert damit also `set X` der Type aller Mengen mit Elementen aus --- `X`. `set.univ` ist dann ganz `X` also Menge betrachtet, und es ist wichtig den Unterschied --- zu kennen: `(univ : set X)` und `(X : Typ*)` haben nicht den gleichen Typ und sind damit auch nicht --- austauschbar! - --- Am anderen Ende sitzt die leere Menge `(∅ : set X)` (`\\empty`). Bei `univ` und `∅` versucht Lean --- automatisch den Typ zu erraten, in exotischen Beispielen muss man wie oben diesen explizit angeben. - --- Als erste Operationen schauen wir uns `∪` (`\\union` oder `\\cup`), `∩` --- (`\\inter` oder `\\cap`) und `\\` (`\\\\` oder `\\ `) - --- " - --- open Set - --- Statement --- "Wenn $B$ wahr ist, dann ist die Implikation $A \\Rightarrow (A ∧ B)$ wahr." --- {X : Type _} {A B : Set X} : univ \ (A ∩ B) ∪ ∅ = (univ \ A) ∪ (univ \ B) ∪ (A \ B) := by --- rw [Set.diff_inter] --- rw [Set.union_empty] --- rw [Set.union_assoc] --- rw [←Set.union_diff_distrib] --- rw [Set.univ_union] - --- NewTactic rw - --- example : 4 ∈ (univ : Set ℕ) := by --- trivial - --- example (A : Set ℕ) : 4 ∉ (∅ : Set ℕ) := by --- trivial - --- example (A : Set ℕ) : A ⊆ univ := by --- intro x h --- trivial - --- -- -- subset_empty_iff --- -- example {s : Set α} : s ⊆ ∅ ↔ s = ∅ := by --- -- constructor --- -- intro h --- -- rw [Subset.antisymm_iff] --- -- constructor --- -- assumption --- -- simp only [empty_subset] --- -- intro a --- -- rw [Subset.antisymm_iff] at a --- -- rcases a with ⟨h₁, h₂⟩ --- -- assumption - --- -- -- eq_empty_iff_forall_not_mem --- -- example {s : Set α} : s = ∅ ↔ ∀ x, x ∉ s := by --- -- rw [←subset_empty_iff] --- -- rfl - --- -- -- nonempty_iff_ne_empty --- -- example (X : Type _) (s : Set X) : Set.Nonempty s ↔ s ≠ ∅ := by --- -- rw [Set.Nonempty] --- -- rw [ne_eq, eq_empty_iff_forall_not_mem] --- -- push_neg --- -- rfl - - --- -- example (A B : ℝ): A = B ↔ A ≤ B ∧ B ≤ A := by library_search - --- namespace Finset - --- theorem powerset_singleton {U : Type _} [DecidableEq U] (x : U) : --- Finset.powerset {x} = {∅, {x}} := by --- ext y --- rw [mem_powerset, subset_singleton_iff, mem_insert, mem_singleton] - --- end Finset - --- /- The powerset of a singleton contains only `∅` and the singleton. -/ --- theorem powerset_singleton {U : Type _} (x : U) : --- 𝒫 ({x} : Set U) = {∅, {x}} := by --- ext y --- rw [mem_powerset_iff, subset_singleton_iff_eq] --- rw [mem_insert_iff, mem_singleton_iff] - - --- lemma mem_powerset_insert_iff {U : Type _} (A S : Set U) (x : U) : --- S ∈ 𝒫 (insert x A) ↔ S \ {x} ∈ 𝒫 A := by --- rw [mem_powerset_iff, mem_powerset_iff, diff_singleton_subset_iff] - --- -- lemma powerset_insert {U : Type _} (A : Set U) (x : U) : --- -- 𝒫 (insert x A) = 𝒫 A ∪ ({B : Set U | B \ {x} ∈ 𝒫 A}) := by --- -- sorry - --- theorem subset_insert_iff_of_not_mem {U : Type _ }{s t : Set U} (h : a ∉ s) : s ⊆ insert a t ↔ s ⊆ t := by --- rw [subset_insert_iff, erase_eq_of_not_mem h] - --- lemma mem_powerset_insert_iff₂ {U : Type _} (A S : Set U) (x : U) : --- S ∈ 𝒫 (insert x A) ↔ S ∈ 𝒫 A ∨ ∃ B ∈ 𝒫 A , insert x B = S := by --- simp_rw [mem_powerset_iff] --- constructor --- · intro h --- by_cases hs : x ∈ S --- · sorry --- · left --- rw [Finset.subset_insert_iff_of_not_mem] --- · intro h --- rcases h with h | ⟨B, h₁, h₂⟩ --- · exact le_trans h (subset_insert x A) --- · rw [←h₂] --- exact insert_subset_insert h₁ - --- lemma powerset_insert {U : Type _} (A : Set U) (x : U) : --- 𝒫 (insert x A) = A.powerset ∪ A.powerset.image (insert x) := by --- rw [Subset.antisymm_iff] --- constructor <;> --- intro B hB <;> --- simp_rw [mem_powerset_insert_iff₂, mem_union, mem_image] at hB ⊢ <;> --- assumption - - --- example : powerset {0, 1} = {∅, {0}, {1}, {0, 1}} := by --- simp_rw [powerset_insert, powerset_singleton, Finset.powerset_insert, Finset.powerset_singleton] --- simp only [image_insert_eq, union_insert, image_singleton, union_singleton] --- simp only [insert_comm, ←insert_emptyc_eq] - --- example [DecidableEq ℕ] : Finset.powerset {0, 1} = {∅, {0}, {1}, {0, 1}} := by --- repeat' rw [@ Finset.powerset_insert ℕ] --- repeat' rw [@Finset.powerset_singleton ℕ] --- --simp only [image_insert_eq, union_insert, image_singleton, union_singleton] - - --- example : powerset {0, 1, 2, 4} = --- {∅, {0}, {1}, {0, 1}, {2}, {1, 2}, {0, 2}, {0, 1, 2}, --- {4}, {0, 4}, {1, 4}, {0, 1, 4}, {2, 4}, {1, 2, 4}, {0, 2, 4}, {0, 1, 2, 4}} := by --- simp_rw [powerset_insert, powerset_singleton] --- simp_rw [image_insert_eq, image_singleton] - - - --- example : Finset.powerset ({0, 1} : Finset ℕ) = {{0, 1}, ∅, {1}, {0}} := by --- have h : Finset.powerset ({0, 1} : Finset ℕ) = {∅, {0}, {1}, {0, 1}} --- rfl --- rw [h] --- simp only [] - - --- example : ({∅, {0}, {1}, {0, 1}} : Finset (Finset ℕ)) = {∅, {1}, {0}, {0, 1}} := by --- simp only [] - - - --- lemma subset_of_subset_diff {U : Type _} (A B C : Set U) (h : A ⊆ B \ C) : A ⊆ B := --- fun _ hx => mem_of_mem_diff (h hx) - --- lemma subset_of_subset_diff' {U : Type _} (A B C : Set U) (h : A ⊆ B) : A \ C ⊆ B := --- sorry - --- lemma mem_powerset' {U : Type _} {A B C : Set U} --- (h' : B ∈ 𝒫 C) (h : A ⊆ B) : --- A ∈ 𝒫 C := by --- rw [mem_powerset_iff] at h' ⊢ --- exact le_trans h h' - --- example (A B : Set ℕ) : A = B ↔ ∀ x, x ∈ A ↔ x ∈ B := by --- exact ext_iff - - - --- lemma NO.powerset_insert {U : Type _} (A : Set U) (x : U) : --- 𝒫 (insert x A) = 𝒫 A ∪ ({insert x B | B ∈ 𝒫 A}) := by --- ext y --- rw [mem_powerset_insert_iff] --- constructor --- · intro h --- rw [mem_union, mem_setOf] --- by_cases hx : x ∈ y --- · right --- use y \ {x} --- constructor --- · assumption --- · rw [insert_diff_singleton, insert_eq_of_mem hx] --- · left --- rw [diff_singleton_eq_self hx] at h --- assumption --- · intro h --- rw [mem_union, mem_setOf] at h --- rcases h with h | h --- · apply mem_powerset' h --- simp --- · rcases h with ⟨B, hB⟩ --- rw [←hB.2] --- apply mem_powerset' hB.1 --- simp - --- -- lemma xxx {U : Type _} (x y : U): --- -- ({insert x B | B ∈ {∅, }}) = {({x} : Set U), {x, y}} := by --- -- sorry - --- -- lemma hh {U : Type _} (A : Set U) (x : U) : --- -- A \ {x} ∈ - --- lemma diff_singleton_eq_iff {U : Type _} {A B : Set U} {x : U} : --- A \ {x} = B ↔ A = B ∨ A = insert x B := by sorry - --- lemma x1 {U : Type _} (x : U) : insert x (∅ : Set U) = {x} := by sorry - --- --set_option maxHeartbeats 20000 - - --- example {U : Type _} {x y : U} : ({x, y} : Set U) = {y, x} := by --- exact pair_comm x y - --- example {U : Type _} {A : Set U} {x y : U} : insert x (insert y A) = insert y (insert x A) := by --- exact insert_comm x y A - --- open Classical - --- #check decide - --- example : ({{0, 2}, {3, 5, 6}} : Set (Set ℕ)) = {{2, 0}, {5, 3, 6}} := by --- rw [Subset.antisymm_iff] --- constructor <;> --- intro A hA <;> --- simp_rw [mem_insert_iff, mem_singleton_iff] at * --- · rw [pair_comm 2 0, insert_comm 5 3] --- tauto --- · rw [pair_comm 0 2, insert_comm 3 5] --- tauto - --- example (A : Set ℕ) : ({{0, 2}, A, {3, 5, 6}} : Set (Set ℕ)) = {{2, 0}, {5, 3, 6}, A} := by --- simp only [insert_comm, ←insert_emptyc_eq] - - --- example : ({{0, 2}, {3, 5, 6}} : Finset (Finset ℕ)) = {{2, 0}, {5, 3, 6}} := by --- simp only - - --- -- -- This works but does not scale well --- -- ext x --- -- simp_rw [powerset_insert, powerset_singleton] --- -- simp_rw [mem_union, mem_setOf, mem_insert_iff, mem_singleton_iff] --- -- simp_rw [diff_singleton_eq_iff, x1] --- -- tauto - - - - --- -- rw [Subset.antisymm_iff] --- -- constructor --- -- intro A hA --- -- rw [mem_powerset_iff] at hA --- -- simp_rw [mem_insert_iff, mem_singleton_iff] at * - - --- example : ({2, 3, 5} : Set ℕ) ⊆ {4, 2, 5, 7, 3} := by --- intro a ha --- simp_rw [Set.mem_insert_iff, Set.mem_singleton_iff] at * --- tauto - --- example : ({0} : Set ℕ) ∪ {1, 2} = {0, 2, 1} := by --- rw [Subset.antisymm_iff] --- intro A hA --- --rw [Set.mem_insert_iff] - - - --- -- Trick: --- -- attribute [default_instance] Set.instSingletonSet diff --git a/server/adam/Adam/Levels/SetTheory/T04_xx.lean b/server/adam/Adam/Levels/SetTheory/T04_xx.lean deleted file mode 100644 index 106c3f9..0000000 --- a/server/adam/Adam/Levels/SetTheory/T04_xx.lean +++ /dev/null @@ -1,96 +0,0 @@ --- import Adam.Metadata - - --- import Duper.Tactic - - --- import Mathlib.Order.Disjoint - --- set_option tactic.hygienic false - --- Game "Adam" --- World "SetTheory" --- Level 4 - --- Title "Mengen" - --- Introduction --- " --- `∈ ∉ ⊆ ⊂ ⋃ ⋂` --- " - --- open Set - --- -- open_locale cardinal - --- variables {X : Type _} (x : X) (A B : Set X) - --- #check A.Nonempty --- #check Nonempty A --- #check insert x A -- {x} ∪ A --- -- #check disjoint A B -- needs Mathlib.Order.Disjoint --- #check A ∆ B --- #check Nontrivial A - --- #check ({2} : Set ℕ) - --- example : ({2} : Set ℕ) ⊆ {4, 2, 3} := by --- simp only [mem_singleton_iff, mem_insert_iff, or_self, singleton_subset_iff, or_false, or_true] - --- example : ({2, 3, 5} : Set ℕ) ⊆ {4, 2, 5, 7, 3} := by --- intro n hn --- simp only [mem_insert_iff, mem_singleton_iff] at * --- tauto - --- example : {2, 3, 5} ⊆ (univ : Set ℕ) := by --- tauto - --- example : 3 ∈ ({4, 2, 5, 7, 3} : Set ℕ) := by --- tauto - --- example : ({4, 9} : Set ℕ) = Set.insert 4 {9} := by --- rfl - - - - --- #check Finset.card - --- variable (A : Finset ℕ) - --- #check A.card - --- -- card_union_eq --- example (A B : Finset ℕ) (h : Disjoint A B) : (A ∪ B).card = A.card + B.card := by --- -- Not a suitable proof for the course. --- rw [← Finset.disjUnion_eq_union A B h, Finset.card_disjUnion _ _ _] - --- example : ¬Disjoint {n : ℤ | ∃ k, n = 2 * k} {3, 5, 6, 9, 11} := by --- rw [not_disjoint_iff] --- use 6 --- constructor --- rw [mem_setOf_eq] --- use 3 --- tauto - --- example : {n : ℕ | Even n ∨ Odd n} = univ := by --- rw [setOf_or] - - - - --- #check Set.eq_of_mem_singleton --- #check {n : ℤ | ∃ k, n = 2 * k} --- #check {n : ℤ // ∃ k, n = 2 * k} --- #check ℤ --- variables (C : Set ℤ) --- #check {n ∈ C | ∃ (k : ℤ), n = 2 * k} --- #check {n : ℤ | n ∈ C ∧ ∃ (k : ℤ), n = 2 * k} --- #check {x ∈ A | x = x} --- #check {y | y ∈ A} --- #check setOf_and --- #check setOf_or --- #check Disjoint C univ - --- example : {n ∈ C | ∃ (k : ℤ), n = 2 * k} = {n : ℤ | n ∈ C ∧ ∃ (k : ℤ), n = 2 * k} := by --- rfl diff --git a/server/adam/Adam/Levels/StatementTest.lean b/server/adam/Adam/Levels/StatementTest.lean deleted file mode 100644 index 8ea9990..0000000 --- a/server/adam/Adam/Levels/StatementTest.lean +++ /dev/null @@ -1,38 +0,0 @@ --- import Adam.Metadata --- import Mathlib - --- Game "Adam" --- World "TestWorld" --- Level 1 - --- Title "Annahmen" - --- Introduction "yadaa yadaa" - --- class MyClass (n : ℕ) where - --- Statement name --- "Beweise dieses Lemma." --- (n m : ℕ) : CommSemigroup ℕ where --- mul := fun i j => 0 --- mul_comm := sorry --- mul_assoc := sorry - --- --@[exercise] --- instance instTest (n m : ℕ) : CommSemigroup ℕ where --- mul := fun i j => 0 --- mul_comm := by --- sorry --- mul_assoc := by --- sorry - --- --@[exercise] --- lemma asdf (a b c d : ℕ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c := by --- rewrite [h₁] --- rw [←h₂] --- assumption - - --- Conclusion "" - --- NewTactic assumption diff --git a/server/adam/Adam/Levels/Sum.lean b/server/adam/Adam/Levels/Sum.lean deleted file mode 100644 index 529b8fa..0000000 --- a/server/adam/Adam/Levels/Sum.lean +++ /dev/null @@ -1,19 +0,0 @@ -import Adam.Levels.Sum.L01_Simp -import Adam.Levels.Sum.L02_Sum -import Adam.Levels.Sum.L03_ArithSum -import Adam.Levels.Sum.L04_SumOdd -import Adam.Levels.Sum.L05_SumComm -import Adam.Levels.Sum.L06_Summary - -Game "Adam" -World "Sum" -Title "Endliche Summe" - -Introduction "Ihr steigt in eurer Raumschiff und setzt eure Reise fort. - -Bald erreicht ihr einen neuen Planet. Die oberfläche scheint steinig zu sein, aber nicht etwa -geröll oder Chaos. Stattdessen, scheinen unzählige Steinplatten zu bizzaren hohen Türme -gestapelt und die ganze Landschaft wirkt wie ein grosses Puzzle in dem jede Platte -feinsäuberlich auf den darunterliegenden Platten aufbaut. - -Bald trefft ihr auch die Bewohner dieses Planeten an." diff --git a/server/adam/Adam/Levels/Sum/L01_Simp.lean b/server/adam/Adam/Levels/Sum/L01_Simp.lean deleted file mode 100644 index 66cfc86..0000000 --- a/server/adam/Adam/Levels/Sum/L01_Simp.lean +++ /dev/null @@ -1,67 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted - -set_option tactic.hygienic false - -Game "Adam" -World "Sum" -Level 1 - -Title "Simp" - -Introduction -" -**Unbekannte**: Willkommen auf *Indu*, unserem Planeten! Bevor ich euch herumzeigen will, -sagt mir, ob ihr unsere Lebensweise zu verstehen und schätzen wisst: -In diesem Kapitel lernen wir endliche Summen und mehr Übungen zur Induktion. - -" - --- Eine endliche Summe läuft erstmal immer über einen endlichen Index --- `Fin n`, welcher $n$ Elemente --- $\\{0, 1, \\ldots, n-1\\}$ beinhaltet. - --- Der Syntax für $\\sum_{i=0}^n a_i$ ist `∑ i : Fin n, _` (\\sum) - --- Als erstes kann die Taktik `simp` (für \"simplification\") ganz viel Triviales vereinfachen. --- `simp` ist eine der stärksten Taktiken in Lean und verwendet --- ganz viele markierte Lemmas um das Goal zu vereinfachen. - --- Zum Beispiel kennt es ein Lemma das ungefähr so aussieht: - --- ``` --- @[simp] --- lemma sum_const_add (n : ℕ) : (∑ i in Fin n, 0) = 0 := by --- sorry --- ``` - --- Die Taktik `simp` benützt alle Lemmas, die mit `@[simp]` markiert sind. - --- (Tipp: `simp?` zeigt an, welche Lemmas `simp` benutzen würde.) - -open BigOperators - -Statement (n : ℕ) : (∑ i : Fin n, (0 + 0)) = 0 := by - Hint " - **Du**: Oh das ist ganz schön viel neues… Mal sehen, das sagt wohl - $( \\sum_i 0 + 0 ) = 0$. Dann ist das vielleicht doch nicht so komplex. - - **Robo**: Genau! Man schreibt `\\sum`. Beachte den Index: - $( \\sum_\{i=0}^\{n-1} 0 + 0 ) = 0$, also `Fin n` ist ein Typ mit den Elementen - $(0, \\ldots, n-1)$. - - **Du**: Oke, also `Fin n` hat `n` Elemente. Und was mach ich jetzt? - - **Robo**: `simp` ist eine ganz starke Taktik, die viele Terme vereinfacht, wir - fangen besser an, diese zu benützen. - - Irgendwie hast du das Gefühl ein Déjà-vue zu haben…" - simp - -OnlyTactic simp -LemmaTab "Sum" - -Conclusion "**Unbekannte**: Sehr gut, folgt mir!" - --- TODO: Cannot write $\\{0\\}$ inside a hint. diff --git a/server/adam/Adam/Levels/Sum/L02_Sum.lean b/server/adam/Adam/Levels/Sum/L02_Sum.lean deleted file mode 100644 index 6ec0238..0000000 --- a/server/adam/Adam/Levels/Sum/L02_Sum.lean +++ /dev/null @@ -1,57 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted - -import Adam.Options.MathlibPart - -set_option tactic.hygienic false -open Finset - -Game "Adam" -World "Sum" -Level 2 - -Title "endliche Summe" - -Introduction -" -Während euch die Person zu einem besonders herausragenden Steinturm führt, löchert -sie euch noch weiter mit Fragen. -" - -open BigOperators - -Statement - "$\\sum_{i=0}^{n-1} (i + 1) = n + \\sum_{i=0}^{n-1} i$." - (n : ℕ) : ∑ i : Fin n, ((i : ℕ) + 1) = n + (∑ i : Fin n, (i : ℕ)) := by - Hint "**Du**: Hmm, wieder `simp`? - - **Robo**: Nicht ganz. `simp` benützt nur Lemmas, die klar eine Vereinfachung darstellen, - und in deiner Bibliothek mit `@[simp]` markiert wird. Hier brauchen wir eine andere - Umformung: - - $$ - \\sum_\{i = 0}^n a_i + b_i = \\sum_\{i = 0}^n a_i + \\sum_\{j = 0}^n b_j - $$ - - **Robo**: Da unklar ist, welche Seite \"einfacher\" ist, wird so ein Lemma nicht mit - `@[simp]` markiert. Das heisst du musst `sum_add_distrib` mit `rw` - explizit anwenden. - " - rw [sum_add_distrib] - Hint "**Robo**: Die zweite Summe `∑ x : Fin n, 1` kann jetzt aber mit - `simp` zu `n` vereinfacht werden." - simp - Hint "**Robo**: Bis auf Umordnung sind jetzt beide Seiten gleich! - - **Du**: Dann greift jetzt wohl `ring`! - - **Robo**: Genau! Und alternativ könntest du mit `rw [add_comm]` die Arbeit von `ring` - auch manuell machen." - ring - -NewLemma Finset.sum_add_distrib add_comm -LemmaTab "Sum" - -Conclusion "Eure Begleitung scheint mit der Antwort zu frieden zu sein und zeigt -freudig an dem Turm empor, den ihr soeben erreicht habt." diff --git a/server/adam/Adam/Levels/Sum/L03_ArithSum.lean b/server/adam/Adam/Levels/Sum/L03_ArithSum.lean deleted file mode 100644 index cd7fac1..0000000 --- a/server/adam/Adam/Levels/Sum/L03_ArithSum.lean +++ /dev/null @@ -1,95 +0,0 @@ -import Adam.Metadata - -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -set_option tactic.hygienic false - -Game "Adam" -World "Sum" -Level 3 - -Title "Arithmetische Summe" - -Introduction -" -**Du**: Wie werden solche Meisterwerke eigentlich gebaut? - -Da zeigt eure Begleitung auf eine kleine Steinplatte neben dem Eingang, -auf der eien Beschreibung gekritzelt ist. - -**Robo**: Das ist wohl der bekannte arithmetische Turm von Indu, über den hab ich schon -einmal Daten verarbeitet. Und die antwort auf deine Frage: Vermutlich ein Stein nach -dem anderen. -" - -open Fin - -open BigOperators - -Statement arithmetic_sum - "$2 \\cdot \\sum_{i = 0}^n i = n \\cdot (n + 1)$." - (n : ℕ) : 2 * (∑ i : Fin (n + 1), ↑i) = n * (n + 1) := by - Hint "**Du**: Klar, die werden ja nicht oben anfangen mit bauen. Sag mal, - wie zeige ich denn die arithmetische Summe, die hier gekritzelt steht? - Ich würde gerne Induktion über $n$ anwenden. - - **Robo**: Ja dann ist's einfach `induction n with d hd`! Der `with d hd` teil ist - Optional und hilft dir die Induktionsvariable und -hypothese zu benennen." - induction n with d hd - Hint "**Du**: Zuerst den Induktionsanfang… - - **Robo**: Diesen kannst du oft mit `simp` abkürzen!" - simp - Hint "**Robo**: Jetzt im Induktionsschritt: Bei Induktion über endlichen Summen willst du - immer mit `rw [sum_univ_castSucc]` anfangen" -- : - - -- $$\\sum_\{i=0}^n a_i = \\sum_{i=0}^\{n-1} a_i + a_n$$" - rw [sum_univ_castSucc] - -- TODO: Bug. Dieser Hint wird nicht angezeigt. - Hint "**Du**: Oh das sieht jetz aber kompliziert aus… - - **Robo**: Da musst du etwas drüber hinweg lesen. Am besten machst du kurz `simp`, - dann sieht's schon wieder besser aus." - simp - Hint "**Du**: Was bedeutet eigentlich der kleine Pfeil `↑`? - - **Robo**: Das ist eine *Coersion*. Sowas wie wenn man eine natürliche Zahl als Integer anschaut, - also die natürliche Abbildung `ℕ ↪ ℤ`. Oder hier, wenn ein Element `x : Fin n` stattdessen als - Element in `(↑x : ℕ)` angeschaut wird. - - **Robo**: Übrigens, um die Induktionshypothese anzuwenden brauchst du zuerst das Lemma - `mul_add`." - rw [mul_add] - Hint "**Du**: Und wie wende ich jetzt die Induktionshypothese an? - - **Robo mit `rw` wie jede andere Annahme auch." - rw [hd] - Hint "**Du**: Der Rest ist einfach Rechnerei. - - **Robo**: Dann wir `ring` wohl keine Probleme haben." - -- Hint "**Robo**: Jetzt musst du noch kurz `rw [Nat.succ_eq_add_one]` anwenden. - - -- **Du**: Aber wieso? - - -- **Robo**: Naja, `ring` ist jetzt auch noch nicht so stark, und erkennt nicht dass `n.succ` - -- und `n + 1` das gleiche sind. - - -- **Du**: Aber das könnte man doch ändern, oder? - - -- **Robo**: Vielleicht wenn wir einmal einem Techniker begegnen, der mir ein Update - -- einspielen kann…" - -- Branch - -- ring_nf - -- Hint "**Robo**: Wie gesagt, brauch doch `rw [Nat.succ_eq_add_one]` als Fix für meine - -- kleinen Maken." - -- rw [Nat.succ_eq_add_one] - ring - -NewTactic induction -NewLemma Fin.sum_univ_castSucc Nat.succ_eq_add_one mul_add add_mul Nat.zero_eq -LemmaTab "Sum" - -Conclusion "Du schaust dich um und bewunderst das Tal in dem hunderte, wenn nicht tausende, -Steintürme in allen Formen und Höhen stehen." diff --git a/server/adam/Adam/Levels/Sum/L04_SumOdd.lean b/server/adam/Adam/Levels/Sum/L04_SumOdd.lean deleted file mode 100644 index b2692bd..0000000 --- a/server/adam/Adam/Levels/Sum/L04_SumOdd.lean +++ /dev/null @@ -1,40 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted -import Adam.Options.MathlibPart - -import Adam.Levels.Sum.L03_ArithSum - -Game "Adam" -World "Sum" -Level 4 - -Title "Summe aller ungeraden Zahlen" - -Introduction -" -**Du**: Haben eigentlich alle Türme hier so kryptische Beschreibungen am Eingang? - -Du gehst zu einem etwas kleineren Nachbarsturm. -" -set_option tactic.hygienic false - -open Fin - -open BigOperators - -Statement - "$\\sum_{i = 0}^n (2n + 1) = n ^ 2$." - (n : ℕ) : (∑ i : Fin n, (2 * (i : ℕ) + 1)) = n ^ 2 := by - Hint "**Robo**: Das funktioniert genau gleich wie zuvor, viel Glück." - induction n - simp - Hint (hidden := true) "Den Induktionschritt mit Summen willst du - eigentlich immer mit `rw [sum_univ_castSucc]` beginnen." - rw [sum_univ_castSucc] - simp - rw [n_ih] - --rw [Nat.succ_eq_add_one] - ring - -LemmaTab "Sum" diff --git a/server/adam/Adam/Levels/Sum/L05_SumComm.lean b/server/adam/Adam/Levels/Sum/L05_SumComm.lean deleted file mode 100644 index eddf617..0000000 --- a/server/adam/Adam/Levels/Sum/L05_SumComm.lean +++ /dev/null @@ -1,50 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted -import Adam.Options.MathlibPart - -import Adam.Levels.Sum.L04_SumOdd - -set_option tactic.hygienic false - -open BigOperators -open Finset - -Game "Adam" -World "Sum" -Level 5 - -Title "Summe vertauschen" - -Introduction -" -Nun aber zeigt euch eure Begleiterin zwei weitere Türme mit einer kleinen Brücke, die -zwischen den beiden verläuft. Die Tafel am Eingang wurde von einem herunterfallenden Stein -zerstört. Auf der oberen Hälfte steht nur folgendes: - -$$\\sum_{i=0}^n\\sum_{j=0}^m a_{ij} = \\sum_{j=0}^m\\sum_{i=0}^n a_{ij}$$ - -**Du**: Ich glaube, ich kann das in eurem Dialekt formulieren und euch damit helfen! -" - - -Statement -(n m : ℕ) : ∑ i : Fin n, ∑ j : Fin m, ( 2^i * (1 + j) : ℕ) = - ∑ j : Fin m, ∑ i : Fin n, ( 2^i * (1 + j) : ℕ) := by - Hint "**Robo**: Das sieht gut aus, aber du solltest das kurz beweisen, um sicher zu sein. - - **Du**: Hast du nicht ein Lemma dafür? - - **Robo**: Doch, probier mal `sum_comm`." - rw [Finset.sum_comm] - -NewLemma Finset.sum_comm -LemmaTab "Sum" - -Conclusion " - Euer Begleiter ist ganz begeistert als er dir das Stück Papier aus den Händen nimmt, - auf dem du die Aussage gekritzelt hast. Gleich zückt sie einen Meißel und beginnt eine - neue Platte zu erstellen. - - Ihr winkt ihr noch zum Abschied und geht weiter. -" diff --git a/server/adam/Adam/Levels/Sum/L06_Summary.lean b/server/adam/Adam/Levels/Sum/L06_Summary.lean deleted file mode 100644 index 8bbd9c2..0000000 --- a/server/adam/Adam/Levels/Sum/L06_Summary.lean +++ /dev/null @@ -1,93 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted -import Adam.Options.MathlibPart - -import Adam.Levels.Sum.L05_SumComm - -Game "Adam" -World "Sum" -Level 6 - -set_option tactic.hygienic false - -Title "Zusammenfassung" - -Introduction -" -**Du**: Robo gib mir nochmals eine Übersicht, bitte. - -**Robo**: Aber klar: - -| | Beschreibung | -|:---------------------|:------------------------------------------| -| `Fin n` | Ist ein Typ mit Zahlen $0, \\ldots, n-1$. | -| `∑ (i : Fin n), a i` | $\\sum_{i=0}^{n-1} a_i$ | -| `↑i` | Eine Coersion, z.B. `Fin n → ℕ`. | - -und - -| | Taktik | Beispiel | -|:---|:--------------------------|:-------------------------------------| -| 21 | `simp` | Simplifikation. | -| 22 | `induction n` | Induktion über $n$ | - -Da löst sich aus der Steinlandschaft plötzlich ein grosser Steingolem. Er schaut euch -bedrohlich an und fragt in tiefer Stimme: -" - -open Fin - -open BigOperators - -Statement (m : ℕ) : (∑ i : Fin (m + 1), (i : ℕ)^3) = (∑ i : Fin (m + 1), (i : ℕ))^2 := by - Hint "**Du**: Gulp. Naja das wird schon klappen. Also man fängt wieder mit Induktion an…" - induction m - Hint "**Du**: Also den Induktionsanfang kann man einfach zeigen…" - simp - Hint (hidden := true) "**Robo**: Und jetzt wieder `rw [sum_univ_castSucc]` und `simp` um vorwärts zu - kommen!" - rw [Fin.sum_univ_castSucc] - simp - Hint "**Robo**: Siehst du die Induktionshypothese hier drin?" - rw [n_ih] - Hint "**Du**: Ok, damit habe ich die linke Seite der Gleichung ziemlich gut bearbeitet. - Aber, ehm, mit der Rechten komme ich nicht weiter… - - Der Golem schaut dich finster an. - - **Robo**: Du willst `sum_univ_castSucc` auf der rechten Seite anwenden, aber es - gibt mehrere Orte, wo das Lemma passen würde. - Deshalb musst du mit `rw [sum_univ_castSucc (n := {n} + 1)]` angeben, wo genau. - - **Du**: Was bedeutet das? - - **Robo** Das Lemma hat eine Annahme `n` und du sagst ihm explizit, was es für dieses `n` - einsetzen muss, nämlich `{n} + 1`" - Branch - rw [Fin.sum_univ_castSucc] - Hint "**Robo**: Das hat jetzt einfach `Fin.sum_univ_castSucc` am ersten Ort angewendet, - wo das möglich war. Das ist nicht so ideal, die like Seite war schon okay. - - **Robo**: Geh doch zurück und bring `rw` dazu am anderen Ort umzuschreiben." - rw [Fin.sum_univ_castSucc (n := n + 1)] - simp - Hint "**Robo**: `add_pow_two` ist auch noch nützlich!" - rw [add_pow_two] - Hint "**Du**: Ich glaube, ich sehe hier ne arithmetische Summe drin!! - - **Robo**: Ich habe dir das dies von vorhin temporär als `arithmetic_sum` gespeichert, - damit du diese brauchen kannst." - rw [arithmetic_sum] - Hint "**Du**: Jetzt sollten es eigentlich nur noch arithmetische Operationen sein." - ring - -NewLemma add_pow_two -LemmaTab "Sum" - -Conclusion "Der Golem denkt ganz lange nach, und ihr bekommt das Gefühl, dass er gar nie -aggressiv war, sondern nur eine sehr tiefe Stimme hat. - -Mit einem kleinen Erdbeben setzt er sich hin und winkt euch dankend zu. - -Damit zieht ihr weiter durch die karge Landschaft auf diesem Planet." diff --git a/server/adam/Adam/Levels/Sum/T01_Induction.lean b/server/adam/Adam/Levels/Sum/T01_Induction.lean deleted file mode 100644 index ec8dc5f..0000000 --- a/server/adam/Adam/Levels/Sum/T01_Induction.lean +++ /dev/null @@ -1,38 +0,0 @@ --- import Adam.Metadata - --- import Adam.ToBePorted --- import Adam.Options.MathlibPart - --- set_option tactic.hygienic false - --- open Nat - --- Game "Adam" --- World "Sum" --- Level 2 - --- Title "endliche Summe" - --- -- TODO: Tactics `mono` and `omega` are not ported yet. - --- Introduction --- " --- 2^n > n^2 für n ≥ 5 --- " - --- Statement --- "2^n > n^2 für n ≥ 5" --- (n : ℕ) : (n + 5)^2 < 2 ^ (n + 5) := by --- induction' n with n ih --- simp --- rw [succ_eq_add_one] --- simp_rw [add_pow_two] at * --- ring_nf at ih ⊢ --- sorry - - - --- example (n : ℕ) (h : 5 ≤ n) : n^2 < 2 ^ n --- | 0 | 1 | 2 | 3 | 4 => by --- sorry --- | n + 5 => by sorry diff --git a/server/adam/Adam/Levels/Sum/T02_Induction.lean b/server/adam/Adam/Levels/Sum/T02_Induction.lean deleted file mode 100644 index 1ce9f9e..0000000 --- a/server/adam/Adam/Levels/Sum/T02_Induction.lean +++ /dev/null @@ -1,34 +0,0 @@ --- import Adam.Metadata - --- import Adam.ToBePorted --- import Adam.Options.MathlibPart - --- set_option tactic.hygienic false - --- Game "Adam" --- World "Sum" --- Level 2 - --- Title "endliche Summe" - --- Introduction --- " --- n^3 + 2n ist durch 3 teilbar für alle ganzen Zahlen n --- " - --- Statement --- "n^3 + 2n ist durch 3 teilbar für alle ganzen Zahlen n" --- (n : ℤ) : 3 ∣ n^3 + 2*n := by --- induction n --- induction a --- norm_cast --- change 3 ∣ (Nat.succ n : ℤ) ^ 3 + 2 * (Nat.succ n : ℤ) --- rw [Int.ofNat_succ] --- sorry --- sorry - --- example (n : ℕ) : (n - 1) * (n + 1) = (n ^ 2 - 1) := by --- induction' n with n hn --- ring --- rw [Nat.succ_eq_one_add] --- rw [] diff --git a/server/adam/Adam/Levels/Sum/T03__Bernoulli.lean b/server/adam/Adam/Levels/Sum/T03__Bernoulli.lean deleted file mode 100644 index 7b4bb9b..0000000 --- a/server/adam/Adam/Levels/Sum/T03__Bernoulli.lean +++ /dev/null @@ -1,48 +0,0 @@ -import Adam.Metadata - -import Adam.ToBePorted -import Adam.Options.MathlibPart - -import Adam.ToBePorted - -Game "Adam" -World "Sum" -Level 5 - -Title "Bernoulli Ungleichung" - -Introduction -" -TODO: Induktion (& induktion vs rcases) - -" - -open BigOperators - -example (x : ℕ) (n : ℕ) : 1 + n * x ≤ (x + 1) ^ n := by - induction' n with n hn - simp - rw [Nat.succ_mul] - rw [Nat.pow_succ] - sorry - -example (n : ℕ) : (∑ i : Fin (n + 1), ↑(2 * i - 1)) = n ^ 2 := by - induction' n with n hn - simp - -#check Finset.sum_comm - -Statement -"Zeige $\\sum_{i = 0}^n i = \\frac{n ⬝ (n + 1)}{2}$." - (n : ℕ) : (∑ i : Fin (n + 1), ↑i) = n * (n + 1) / 2 := by - sorry - -- apply hh1 - -- induction' n with n hn - -- simp - -- sorry - -- rw [Fin.sum_univ_castSucc] - -- simp [nat_succ] - -- rw [mul_add, hn] - -- ring - -NewTactic ring diff --git a/server/adam/Adam/Metadata.lean b/server/adam/Adam/Metadata.lean deleted file mode 100644 index 240d0ea..0000000 --- a/server/adam/Adam/Metadata.lean +++ /dev/null @@ -1,6 +0,0 @@ -import GameServer.Commands -import Adam.Doc.Tactics -import Adam.Doc.Lemmas -import Adam.Doc.Definitions -import Mathlib.Init.Data.Nat.Basic -- Imports the notation ℕ. -import Adam.Modification.Tactic diff --git a/server/adam/Adam/Modification/Tactic.lean b/server/adam/Adam/Modification/Tactic.lean deleted file mode 100644 index 941fca3..0000000 --- a/server/adam/Adam/Modification/Tactic.lean +++ /dev/null @@ -1,83 +0,0 @@ -import Mathlib.Lean.Expr.Basic -import Lean.Elab.Tactic.Basic -import Mathlib.Init.Data.Nat.Notation - -open Lean.Meta Lean.Elab.Tactic Lean.Parser.Tactic - -/-! -# Modified `induction` tactic - -Modify `induction` tactic to use the cases `0` and `n + 1` (isnstead of `zero` and `succ n`) -and support the lean3-style `with` keyword. - -This is mainly copied and modified from the mathlib-tactic `induction'`. --/ - -/-- Custom induction principle that uses `0` and `n + 1` instead -of `Nat.zero` and `Nat.succ n`. -/ -def CustomTactic.rec' {P : ℕ → Prop} (zero : P 0) - (succ : (n : ℕ) → (n_ih : P n) → P (n + 1)) (t : ℕ) : P t := by - induction t with - | zero => assumption - | succ n => - apply succ - assumption - -namespace Lean.Parser.Tactic -open Meta Elab Elab.Tactic - -open private getAltNumFields in evalCases ElimApp.evalAlts.go in -def _root_.CustomTactic.ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg : Syntax) - (numEqs := 0) (numGeneralized := 0) (toClear : Array FVarId := #[]) : - Lean.Elab.Term.TermElabM (Array MVarId) := do - let mut names : List Syntax := withArg[1].getArgs |>.toList - let mut subgoals := #[] - for { name := altName, mvarId := g, .. } in alts do - let numFields ← getAltNumFields elimInfo altName - let (altVarNames, names') := names.splitAtD numFields (Unhygienic.run `(_)) - names := names' - let (fvars, g) ← g.introN numFields <| altVarNames.map (getNameOfIdent' ·[0]) - let some (g, subst) ← Cases.unifyEqs? numEqs g {} | pure () - let (_, g) ← g.introNP numGeneralized - let g ← liftM $ toClear.foldlM (·.tryClear) g - for fvar in fvars, stx in altVarNames do - g.withContext <| (subst.apply <| .fvar fvar).addLocalVarInfoForBinderIdent ⟨stx⟩ - subgoals := subgoals.push g - pure subgoals - -open private getElimNameInfo generalizeTargets generalizeVars in evalInduction in - -/-- -Modified `induction` tactic for this game. - -Usage: `induction n with d hd`. - -For this game, `induction n` uses the cases `0` and `n + 1` instead of `Nat.zero` and -`Nat.succ n`. These are defEq, but it's currently annoying that `ring` does not like the -latter forms. - -*(The actual `induction` tactic has a more complex `with`-argument that works differently)* --/ -elab (name := _root_.MyNat.induction) "induction " tgts:(casesTarget,+) - withArg:((" with " (colGt binderIdent)+)?) - : tactic => do - let targets ← elabCasesTargets tgts.1.getSepArgs - let g :: gs ← getUnsolvedGoals | throwNoGoalsToBeSolved - g.withContext do - let elimInfo ← getElimInfo `CustomTactic.rec' - let targets ← addImplicitTargets elimInfo targets - evalInduction.checkTargets targets - let targetFVarIds := targets.map (·.fvarId!) - g.withContext do - let forbidden ← mkGeneralizationForbiddenSet targets - let mut s ← getFVarSetToGeneralize targets forbidden - let (fvarIds, g) ← g.revert (← sortFVarIds s.toArray) - let result ← withRef tgts <| ElimApp.mkElimApp elimInfo targets (← g.getTag) - let elimArgs := result.elimApp.getAppArgs - ElimApp.setMotiveArg g elimArgs[elimInfo.motivePos]!.mvarId! targetFVarIds - g.assign result.elimApp - let subgoals ← CustomTactic.ElimApp.evalNames elimInfo result.alts withArg - (numGeneralized := fvarIds.size) (toClear := targetFVarIds) - setGoals <| (subgoals ++ result.others).toList ++ gs - -end Lean.Parser.Tactic diff --git a/server/adam/Adam/Options/MathlibPart.lean b/server/adam/Adam/Options/MathlibPart.lean deleted file mode 100644 index 55bf1da..0000000 --- a/server/adam/Adam/Options/MathlibPart.lean +++ /dev/null @@ -1,15 +0,0 @@ -import Std.Tactic.RCases -import Mathlib.Tactic.LeftRight -import Mathlib.Tactic.Contrapose -import Mathlib.Tactic.Use -import Mathlib.Tactic.Ring -import Mathlib.Tactic.Linarith -import Mathlib.Data.Nat.Parity -import Mathlib.Algebra.BigOperators.Fin -import Mathlib.LinearAlgebra.LinearIndependent -import Mathlib.Data.Real.Basic -- definiert `ℝ` -import Mathlib.LinearAlgebra.Basis -import Mathlib.Data.Real.Basic -- definiert `ℝ` -import Mathlib.Algebra.Module.Pi -- definiert `Module ℚ (fin 2 → ℚ)` -import Mathlib.Data.Fin.VecNotation -import Mathlib.Tactic.FinCases diff --git a/server/adam/Adam/Playground.lean b/server/adam/Adam/Playground.lean deleted file mode 100644 index 997447d..0000000 --- a/server/adam/Adam/Playground.lean +++ /dev/null @@ -1,97 +0,0 @@ --- import Mathlib.Data.Set.Basic --- import Mathlib - --- open Function Set - --- example {A B : Type _ } (f : A → B) : f.Injective ↔ ∃ g : B → A, g ∘ f = id := by --- constructor --- · intro h --- -- hard. --- sorry --- · intro h --- rcases h with ⟨g, h⟩ --- unfold Injective --- intro a b hab --- rw [←id_eq a, ←id_eq b] --- rw [← h] --- rw [comp_apply] --- rw [hab] --- simp - - --- lemma singleton_mem_powerset --- {U : Type _} {M : Set U} {x : U} (h : x ∈ M) : --- {x} ∈ 𝒫 M := by --- rw [mem_powerset_iff, singleton_subset_iff] --- assumption - --- example --- {U : Type _} (M : Set U) : --- {A : Set U // A ∈ 𝒫 M} = {A ∈ 𝒫 M | True} := by --- simp_rw [coe_setOf, and_true] - --- example --- {U : Type _} (M : Set U) : --- {A : Set U // A ∈ 𝒫 M} = 𝒫 M := by --- rfl - --- example --- {U : Type _} (M : Set U) : --- {x : U // x ∈ M} = M := by --- rfl - --- example --- {U : Type _} (M : Set U) : --- ∃ (f : M → 𝒫 M), Injective f := by --- use fun x ↦ ⟨ _, singleton_mem_powerset x.prop ⟩ --- intro a b hab --- simp at hab --- rw [Subtype.val_inj] at hab --- assumption - --- instance {U : Type _} {M : Set U} : Membership ↑M ↑(𝒫 M) := --- { mem := fun x A ↦ x.1 ∈ A.1 } - --- instance {U : Type _} {M : Set U} : Membership U (Set ↑M) := --- { mem := fun x A ↦ _ } - - --- example --- {U : Type _} {M : Set U} (h_empty : M.Nonempty) --- (f : {x : U // x ∈ M} → {A : Set U // A ∈ 𝒫 M}): --- ¬ Surjective f := by --- unfold Surjective --- push_neg --- --by_contra h_sur --- let B : Set M := {x : M | x ∉ (f x)} --- use ⟨B, sorry⟩ --- intro ⟨a, ha⟩ --- sorry --- -- Too hard? - --- #check singleton_mem_powerset --- #check Subtype.val_inj - - - --- -- These are fun exercises for prime. --- example (x : ℕ) : 0 < x ↔ 1 ≤ x := by --- rfl - --- lemma le_cancel_left (n x : ℕ) (h : x ≠ 0): n ≤ n * x := by --- induction n --- simp --- simp --- rw [← zero_lt_iff] at h --- assumption - - --- example (n m : ℕ) (g : m ≠ 0) (h : n ∣ m) : n ≤ m := by --- rcases h with ⟨x, hx⟩ --- rw [hx] --- apply le_cancel_left --- by_contra k --- rw [k] at hx --- simp at hx --- rw [hx] at g --- contradiction diff --git a/server/adam/Adam/StructInstWithHoles.lean b/server/adam/Adam/StructInstWithHoles.lean deleted file mode 100644 index 0921856..0000000 --- a/server/adam/Adam/StructInstWithHoles.lean +++ /dev/null @@ -1,1698 +0,0 @@ -/- Copied from `https://github.com/leanprover-community/mathlib4/tree/thorimur/refine_struct-via-StructInst` -/ - -/- -Copyright (c) 2020 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura --/ -import Lean.Util.FindExpr -import Lean.Parser.Term -import Lean.Meta.Structure -import Lean.Elab.App -import Lean.Elab.Binders - -set_option autoImplicit true - -/-! - # Structure Instances With (Variadic) Holes - This file defines a term elaborator for structure instance syntax that includes "variadic holes", - i.e. holes of "variable length", which are represented via via the syntax `?..`, `?..!`, etc., - e.g. `{ x := 0, ?.. }`. - This serves to port the functionality of mathlib3's `refine_struct { .. }`, but via `refine` - (e.g. `refine { ?.. }`). - Lean currently already supports one form of variadic hole in structure instances, namely `..`, - which fills all unspecified fields with natural metavariables and which is frequently used in - pattern matching. - Variadic holes that begin with a question mark are meant to parallel named holes (e.g. `?x`). - Therefore, syntax like `{ x := 0, ?.. }` will fill all remaining fields with metavariables named - by the field in question (e.g. `y := ?y`). Identifiers can optionally be provided to prefix the - name; see below. - Tests are performed in `Tests/StructInstWithHoles.lean`. - At the end of this file, we implement `haveFieldProj` in analogy to `have_field` with some - modifications. (This might be moved or eliminated.) - ## Current specifics - The following is subject to change. - Several variants are supported to enable the choice between synthetic holes (`?`) and natural - ones, and to enable the choice between filling all unspecified fields with holes (`!`) and - synthesizing defaults where possible. - Currently only three combinations are allowed, since I can't see a use for unnamed/natural goals - with synthesized defaults. More descriptive syntax might be used for indicating whether to - synthesize defaults or not (e.g. `?.. noDefaults`) - synthesize defaults - ┌──true──┬─false──┐ - named goals │ `?..` │ `?..!` │ - ├────────┼────────┤ - unnamed goals │ × │ `..` │ - └────────┴────────┘ - Identifiers can be provided after the variadic hole syntax in the `?` case, e.g. `?..foo` and - `?..!foo`. These will be prefixed to the goal name. For example, a field `y`'s goal will be named - `foo.y` instead of `y`. - # Overview of existing code - This document began as `StructInst.lean`, then was modified as needed. The modifications are done - in such a way as to (hopefully) make it easy for them to be absorbed into `StructInst.lean`, if - that's where it ends up. The following details how the original `StructInst.lean` works (which is - largely preserved). - ## Short version - The way this works is that we start with syntax, parse it into a bare-bones `Struct`, use - `expandStruct` to expand that struct into another struct that has intermediate indicators - (`FieldVal`s) holding raw syntax or accounting for its absence. We then `elabStruct` that struct - into an `ElabStructResult` which has the potential result expression (an application of the - structure's single constructor to its values, which may be metavariables if they weren't found in - the syntax) plus info on the original struct. We then synthesize defaults using `propagate` to - assign any metavariables standing in for default values, and then return the expression. - ## Long version - We start with turning the syntax into a struct. First we extract the sources (everything before - the `with` and any variadic holes (`..` or similar)), then we feed this to `elabStructInstAux` - along with the raw syntax and expected type. Inside `elabStructInstAux` we make the syntax into a - Struct (`mkStructView`), then `expandStruct`. - There's a "pre-expression scaffolding/framework/spine" set up early on in the process in the form - of FieldVal's, which hold raw information: `.term stx` where `stx` is syntax, if a term was - provided; a `.missing` value if it was missing; or a `.nested s` value where `s` is a `Struct` if - a subobject relation obtains. The `FieldVal`s for a field might be modified as elaboration - proceeds: for example, some might become `.nested`, or some defaults might turn into terms. This - all happens during `expandStruct`. - The `Struct` holds everything, and is updated throughout the process. - One of its fields is `field`, which holds a list of `Field Struct`'s. (The appearance of `Struct` - within `Field Struct` is to allow the `Struct`s to nest other `Struct`s when we have subobjects.) - The fields of each element of the `field` field (got that?) are - * `ref : Syntax`, which holds the `Syntax` found for that field - * `lhs : FieldLHS`, which describes the name of the field in question - * `val : FieldVal`, which holds the pre-expression `FieldVal`—either `.term stx` where `stx` is - the syntax of the field's value, `.default` (now `.missing`) if no syntax was found, or `.nested - s` if the field represents a subobject `s` of the structure (e.g. `toFoo`, produced by `extends`) - * `expr? : Option Expr`, which holds the elaborated expression when it becomes available (or a - metavariable, if the syntax is missing), and which begins at this stage as `none`. - `elacStructInstAux` then calls `elabStruct` on the skeletal `Struct` (which has appropriate - `FieldVal`s, but `none` for each field's `expr?`), which turns the `Struct` into an - `ElabStructResult`. - `elabStruct` elaborates everything but defaults, constructing the structure instance as an - expression given by the application of the structure's constructor to the values it finds by - elaborating the `stx` in any `.term stx` `FieldVal` while ensuring the appropriate type. (It's - not quite true that no defaults are taken care of here: `autoparam`s are turned into `.term`s.) - If the `FieldVal` is `.nested s`, it calls `elabStruct` on `s`; if it finds a `.default` (now - renamed to `.missing`) `FieldVal`, it uses a fresh metavariable in place of an elaborated - expression. As it does this, it stores any elaborated expressions in the `expr?` field of its - fields and builds this constructor application expression, which is, in the resulting - `ElabStructResult` structure, confusingly also named "val". Occasionally the `FieldVals` for each - field are updated as well. Also returned in `ElabStructResult` is the updated Struct with all its - new fields, and `instMVars`, an array of metavariables for dealing with typeclass instance - synthesis. - During `elabStruct`, defaults were inserted as metavariables into the constructed expression and - into `expr?`, but they were also annotated with ``structInstDefault` to indicate that they - represented a missing default value, and needed to be synthesized during the default loop. - Indeed, the function `isMissingDefault?` checks that this metavariable is unassigned when - deciding whether to return true or false. We finish our elaboration of the structure instance - with the `propagate` loop, which iteratively synthesizes the defaults, as sometimes the default - values of fields reference other fields which may also have a default value (etc.). - # Modifications - Changes from `StructInst.lean` are no longer marked with `!!` in a comment (or with `!!/`, `!!\` - surrounding a new or altered block). These are however visible in past commits. - Existing comments are left unchanged, and new comments begin with "~~". - ## Syntax - We use the parser from `Term.lean`, but change `optional ".."` to our parseer for variadic holes, - `variadicHole` - ## Logic - The original implementation of `..`, which creates a natural metavariable for each goal (and does - not synthesize defaults) affects things early on, at the stage of `FieldVal`s. Instead of using a - `.default` `FieldVal`, it makes a hole via syntax by providing a `.term (mkHole ref)` `FieldVal` - for each missing field value. - We preserve this behavior only for the `isSynthetic := false, useDefaults := false` case. - Otherwise, we use the `.default` `FieldVal`—now renamed to `.missing` to reflect its changed - function—and intervene mostly within the `ImplicitFields` namespace (previously the - `DefaultFields` namespace), where defaults are synthesized. If the variadic hole syntax says not - to, we don't propagate the default-synthesizing loop and therefore don't synthesize any defaults. - Typically, when the default loop ends with some fields still annotated as missing, an error is - thrown (`fields missing: ...`). However, if there's a variadic hole, we simply return from the - loop without error; next (whether the loop has run or not) we assign those remaining annotated - fields to *new* metavariables, which, in the `isSynthetic := true` case, are well-named and hold - all of the metadata we want them to. These are ripe to be used in a `refine` statement. - The only exception to this flow is how we handle `autoparam`s: autoparams are handled in - `elabStruct`, so that's where we intervene as well. - ## Style - New code is often written in a "lookahead" fashion, to make it as easy as possible to move this - to core, in case it would better belong there. Therefore some cases that don't occur in this - elaboration are nonetheless accounted for—for example, the case where variadic hole syntax is - absent (where the value of struct.source.implicit is none), and the case where `isSynthetic := - false, useDefaults := false`, which is already accounted for by existing `..` syntax. We use a - different token (`...`) only to show that this works. - This modification of `StructInst.lean` also attempts to be "minimally invasive" by intervening in - as few places as possible and leaving the existing flow of computation intact. - ## Locations of changes - The changes to existing definitions are localized to the following: - ### Necessary parsing and syntax processing changes - * The `structInst` term parser was modified to allow variadic hole syntax. - * `expandStructInstFieldAbbrev` - * update `$[..%$ell]?` syntax match to accommodate variadic holes - * type of `implicit` in `Source` structure: `Option Syntax` ⇒ `Option VariadicHoleConfig` - * originally this held the syntax `..` if present; now it holds information derived from the - variadic hole syntax (if present) as opposed to the raw syntax - * `getStructSource` - * inserted `getVariadicHoleConfig?` in front of the raw `implicitSource` syntax to process it - into a `VariadicHoleConfig` - * `formatStruct` - * instead of using a literal `".."` whenever `implicit.isSome`, use the syntax we encountered - (stored as one of the fields of `VariadicHoleConfig`) - ### Logic - **Simple renamings** - * The `.default` `FieldVal`, which was used to indicate that fields would be synthesized by the - default loop, is renamed to `.missing` for clarity. Likewise `Struct.allDefault` is renamed to - `Struct.allMissing` (since it simply checks these `FieldVal`s), and `formatField` formats - `.missing` fields via `""` instead of via `""`. - * We rename the `DefaultFields` namespace to `ImplicitFields`, since this is now where we - intervene to handle holes as well. - **Setup changes** - * `addMissingFields`, which is responsible for attaching `.missing` to unspecified fields, - previously attached a `.term (mkHole stx)` to any missing field whenever `..` was present. Here, - we only do so in the `isSynthetic := false, useDefaults := false` case, attaching `.missing` in - all other cases (both when we exepct them to be synthesized as defaults and not). - * `elabStruct` – this function uses `FieldVal`s to 1) generate `expr?`s for each field when - possible and 2) apply the structure's constructor to the arguments it finds to build the instance - expression. It stops short of synthesizing defaults, inserting a metavariable in both places when - it encounters a `.missing` field. However, autoparams for `.missing` values are handled here. We - therefore modify that section of the code so that - * if the variadic hole says to use holes instead of defaults, we don't try the autoparam - * if it says to use defaults, we try the autoparam in such a way that if it fails we use a hole - instead - * we also need to introduce a new optional `Bool` argument to the internal `cont` function - that, when modified from its default, takes a different branch. Otherwise `cont` is - untouched, and the original behavior is used when this argument is not specified. - * if there's no variadic hole, use the original behavior - **Default loop changes** - * `propagateLoop` – this is a pass of the loop used for synthesizing defaults, and is responsible - for throwing an error when too few fields are specified. If there is a variadic hole, it does not - throw that error and simply returns. - * `propagate` – this sets things up for the loop and executes it. - * We check the variadic hole config and don't run `propagateLoop` if it says not to. (We start - with a `do` to accommodate this.) - * At the end, if there is a variadic hole, we run `assignRemainingDefaultsToFieldHoles` (a new - function which does what you expect) - ## New Code - The new functionality is in the `ImplicitFields` section to attach metadata to the goals - produced. Currently, we attach the metadata as a `KVMap` to the type of the goal, but this may - change. We use this metadata to resolve name conflicts, appending an appropriate index if any - existing metavariable is from a structure that shares a field name. This is meant to improve - clarity: for example, if `Foo` and `Bar` both have fields `x` and `y`, - `refine ({ y := 0, ?.. : Foo}, { x := 1, ?.. : Bar})` will produce goals `x` and `y_1` to show - that these are not from the same structure. (This may change if we decide to prefix each goal - name with the name of the structure.) - # Questions - * Should `trySynthStructInstance?` be run even when `useDefaults` is `false`? - * what about `bi == .instImplicit`? Should default synthesis be avoided in that case too? - * Dhould metadata be on the type, or somewhere else? - * Is the best way to get a unique id for a syntax instance via getPos? Do we need to do so anyway? - * Should utility-like functions be refactored into other files? - * Can the docstrings of the original structure instance and `refine` be modified from "within - mathlib" somehow? - * Do I need to add to "authors" at the top or worry about the copyright? - * Check for unreachable code after design decisions have been made. --/ -namespace Lean.Elab.Term.StructInstWithHoles - -open Meta -open TSyntax.Compat - -/-- - A synthetic variadic hole. When used in structure instance syntax, it fills the unspecified - fields with metavariables named by the field. It synthesizes defaults when possible. - It can be followed by an identifier to specify a prefix for the names of the holes. - -/ -def vH?dd := leading_parser "?.." >> Parser.optional Parser.ident -/-- - A synthetic variadic hole that does not synthesize any defaults. When used in structure instance - syntax, it fills the unspecified fields with metavariables named by the field. It synthesizes - defaults when possible. It can be followed by an identifier to specify a prefix for the names of - the holes. - -/ -def vH?dd! := leading_parser "?..!" >> Parser.optional Parser.ident -/-~~! Removed for now. -/-- A natural variadic hole that does not synthesize defaults. -/ -def vHdd! := leading_parser "..!" -/-- A natural variadic hole that synthesizes defaults when possible. -/ -def vHdd := leading_parser "..." --/ -/-- A variadic hole that fills multiple spots with holes. -/ -def variadicHole := leading_parser (vH?dd <|> vH?dd! /-~~! <|> vHdd! <|> vHdd-/) - -open Lean.Parser Lean.Parser.Term in -/-- -Structure instance. `{ x := e, ... }` assigns `e` to field `x`, which may be -inherited. If `e` is itself a variable called `x`, it can be elided: -`fun x => { x , y := 1 }`. -A *structure update* of an existing value can be given via `with`: -`{ point with x := 1 }`. -The structure type can be specified if not inferable: -`{ x := 1, y := 2 : Point }`. -`..` can be used in pattern-matching to fill all unspecified fields with `_`: -`match s with | { x := 1, .. } => ...` -`?..` fills all unspecified fields with automatically-named goals: -if a `Foo` has fields `x`, `y`, `z`, `{ x := 1, ?.. } : Foo` creates `?y`, `?z`. --/ -@[term_parser] def structInstWithHoles := leading_parser "{" >> ppHardSpace >> Lean.Parser.optional -(atomic (sepBy1 termParser ", " >> " with ")) - >> sepByIndent (structInstFieldAbbrev <|> structInstField) ", " (allowTrailingSep := true) - >> variadicHole -- Only apply this elaboration to syntax that has one of these holes - >> Lean.Parser.optional (" : " >> termParser) >> " }" - -/-- - Syntactically move any type specification outside of the structure instance syntax: - `{ x := 0 : Foo }` becomes `{ x := 0 } : Foo`. --/ -@[macro structInstWithHoles] def expandStructInstWithHolesExpectedType : Macro := fun stx => - let expectedArg := stx[4] - if expectedArg.isNone then - Macro.throwUnsupported - else - let expected := expectedArg[1] - let stxNew := stx.setArg 4 mkNullNode - `(($stxNew : $expected)) - -/-- Expand field abbreviations. Example: `{ x, y := 0 }` expands to `{ x := x, y := 0 }` -/ -@[macro structInstWithHoles] def expandStructInstWithHolesFieldAbbrev : Macro - | `({ $[$srcs,* with]? $fields,* $ell:variadicHole $[: $ty]? }) => - if fields.getElems.raw.any (·.getKind == ``Lean.Parser.Term.structInstFieldAbbrev) then do - let fieldsNew ← fields.getElems.mapM fun - | `(Parser.Term.structInstFieldAbbrev| $id:ident) => - `(Parser.Term.structInstField| $id:ident := $id:ident) - | field => return field - `({ $[$srcs,* with]? $fieldsNew,* $ell $[: $ty]? }) - else - Macro.throwUnsupported - | _ => Macro.throwUnsupported - -/-- - If `stx` is of the form `{ s₁, ..., sₙ with ... }` and `sᵢ` is not a local variable, expand into - `let src := sᵢ; { ..., src, ... with ... }`. - Note that this one is not a `Macro` because we need to access the local context. --/ -private def expandNonAtomicExplicitSources (stx : Syntax) : TermElabM (Option Syntax) := do - let sourcesOpt := stx[1] - if sourcesOpt.isNone then - return none - else - let sources := sourcesOpt[0] - if sources.isMissing then - throwAbortTerm - let sources := sources.getSepArgs - if (← sources.allM fun source => return (← isLocalIdent? source).isSome) then - return none - if sources.any (·.isMissing) then - throwAbortTerm - return some (← go sources.toList #[]) -where - go (sources : List Syntax) (sourcesNew : Array Syntax) : TermElabM Syntax := do - match sources with - | [] => - let sources := Syntax.mkSep sourcesNew (mkAtomFrom stx ", ") - return stx.setArg 1 (stx[1].setArg 0 sources) - | source :: sources => - if (← isLocalIdent? source).isSome then - go sources (sourcesNew.push source) - else - withFreshMacroScope do - let sourceNew ← `(src) - let r ← go sources (sourcesNew.push sourceNew) - `(let src := $source; $r) - -/-- Information for any explicit sources encountered (i.e. some `sᵢ` in `s₁, ..., sₙ with`) -/ -structure ExplicitSourceInfo where - /-- The syntax of some `sᵢ` in `s₁, ..., sₙ with` -/ - stx : Syntax - /-- The name of some structure `sᵢ` in `s₁, ..., sₙ with` -/ - structName : Name - deriving Inhabited - -/-- - Information deduced from variadic hole syntax, as well as the raw - syntax itself and any identifiers that were found. --/ -structure VariadicHoleConfig where - /-- The raw variadic hole syntax encountered (`?..`, `..`, etc.)-/ - stx : TSyntax ``variadicHole - /-- An optional name `x` found in `?..x` or `?..!x`, to be used as a prefix. -/ - name : Option Name := none - /-- Whether the holes should be synthetic and automatically named. -/ - isSynthetic : Bool - /-- Whether defaults should attempt to be synthesized before filling fields with holes. -/ - useDefaults : Bool - deriving Inhabited, Repr - -/-- - Information on other sources of field values via structure update syntax or variadic holes. - Collects of explicit source info (preceding `with` in structure updates) and implicit source - info (for specification of holes, e.g. `..` or `?..`). --/ -structure Source where - /-- info for all `sᵢ` in `s₁, ..., sₙ with` -/ - explicit : Array ExplicitSourceInfo - /-- info for any variadic hole syntax encountered (`?..`, `..`, etc.) -/ - implicit : Option VariadicHoleConfig - deriving Inhabited - -/-- Check if neither an explicit nor an implicit source has been specified. -/ -def Source.isNone : Source → Bool - | { explicit := #[], implicit := none } => true - | _ => false - -/-- Process variadic hole syntax into a VariadicHoleConfig. -/ -def getVariadicHoleConfig? : TSyntax ``variadicHole → Option VariadicHoleConfig -| stx => match stx with - | `(variadicHole|?..$[$x:ident]?) => some - {stx, isSynthetic := true, useDefaults := true, name := x.map Syntax.getId} - | `(variadicHole|?..!$[$x:ident]?) => some - {stx, isSynthetic := true, useDefaults := false, name := x.map Syntax.getId} - | _ => none - -/-- - Put an array of source syntax into a form which matches - `optional (atomic (sepBy1 termParser ", " >> " with ")`, e.g. `s₁, s₂, s₃ with`. - Should only be called when `sources` is a nonempty `Array`. - -/ -private def mkSourcesWithSyntax (sources : Array Syntax) : Syntax := - let ref := sources[0]! - let stx := Syntax.mkSep sources (mkAtomFrom ref ", ") - mkNullNode #[stx, mkAtomFrom ref "with "] - -/-- - Extract and process both explicit (`s₁, ..., sₙ with`) and implicit (`..`, `?..`, etc.) source - syntax from structure syntax. --/ -private def getStructSource (structStx : Syntax) : TermElabM Source := - withRef structStx do - let explicitSource := structStx[1] - let implicitSource := structStx[3] - let explicit ← if explicitSource.isNone then - pure #[] - else - explicitSource[0].getSepArgs.mapM fun stx => do - let some src ← isLocalIdent? stx | unreachable! - addTermInfo' stx src - let srcType ← whnf (← inferType src) - tryPostponeIfMVar srcType - let structName ← getStructureName srcType - return { stx, structName } - let implicit := - if implicitSource[0].isNone - then none - else getVariadicHoleConfig? implicitSource - return { explicit, implicit } - -/-- - We say a `{ ... }` notation is a `modifyOp` if it contains only one - ``` - def structInstArrayRef := leading_parser "[" >> termParser >>"]" - ``` --/ -private def isModifyOp? (stx : Syntax) : TermElabM (Option Syntax) := do - let s? ← stx[2].getSepArgs.foldlM (init := none) fun s? arg => do - /- arg is of the form `structInstFieldAbbrev <|> structInstField` -/ - if arg.getKind == ``Lean.Parser.Term.structInstField then - /- Remark: the syntax for `structInstField` is - ``` - def structInstLVal := leading_parser (ident <|> numLit <|> structInstArrayRef) >> many - (group ("." >> (ident <|> numLit)) <|> structInstArrayRef) - def structInstField := leading_parser structInstLVal >> " := " >> termParser - ``` - -/ - let lval := arg[0] - let k := lval[0].getKind - if k == ``Lean.Parser.Term.structInstArrayRef then - match s? with - | none => return some arg - | some s => - if s.getKind == ``Lean.Parser.Term.structInstArrayRef then - throwErrorAt arg "invalid \{...} notation, at most one `[..]` at a given level" - else - throwErrorAt arg "invalid \{...} notation, can't mix field and `[..]` at a given level" - else - match s? with - | none => return some arg - | some s => - if s.getKind == ``Lean.Parser.Term.structInstArrayRef then - throwErrorAt arg "invalid \{...} notation, can't mix field and `[..]` at a given level" - else - return s? - else - return s? - match s? with - | none => return none - | some s => if s[0][0].getKind == ``Lean.Parser.Term.structInstArrayRef then return s? else - return none - -/-- Elaborate `modifyOp`s given a single explicit source. -/ -private def elabModifyOp (stx modifyOp : Syntax) (sources : Array ExplicitSourceInfo) -(expectedType? : Option Expr) : TermElabM Expr := do - if sources.size > 1 then - throwError "invalid \{...} notation, multiple sources and array update is not supported." - let cont (val : Syntax) : TermElabM Expr := do - let lval := modifyOp[0][0] - let idx := lval[1] - let self := sources[0]!.stx - let stxNew ← `($(self).modifyOp (idx := $idx) (fun s => $val)) - trace[Elab.struct.modifyOp] "{stx}\n===>\n{stxNew}" - withMacroExpansion stx stxNew <| elabTerm stxNew expectedType? - let rest := modifyOp[0][1] - if rest.isNone then - cont modifyOp[2] - else - let s ← `(s) - let valFirst := rest[0] - let valFirst := if valFirst.getKind == ``Lean.Parser.Term.structInstArrayRef then valFirst - else valFirst[1] - let restArgs := rest.getArgs - let valRest := mkNullNode restArgs[1:restArgs.size] - let valField := modifyOp.setArg 0 <| mkNode ``Parser.Term.structInstLVal #[valFirst, valRest] - let valSource := mkSourcesWithSyntax #[s] - let val := stx.setArg 1 valSource - let val := val.setArg 2 <| mkNullNode #[valField] - trace[Elab.struct.modifyOp] "{stx}\nval: {val}" - cont val - -/-- - Get structure name. - This method tries to postpone execution if the expected type is not available. - If the expected type is available and it is a structure, then we use it. - Otherwise, we use the type of the first source. --/ -private def getStructName (expectedType? : Option Expr) (sourceView : Source) : TermElabM Name := do - tryPostponeIfNoneOrMVar expectedType? - let useSource : Unit → TermElabM Name := fun _ => do - unless sourceView.explicit.isEmpty do - return sourceView.explicit[0]!.structName - match expectedType? with - | some expectedType => throwUnexpectedExpectedType expectedType - | none => throwUnknownExpectedType - match expectedType? with - | none => useSource () - | some expectedType => - let expectedType ← whnf expectedType - match expectedType.getAppFn with - | Expr.const constName _ => - unless isStructure (← getEnv) constName do - throwError "invalid \{...} notation, structure type expected{indentExpr expectedType}" - return constName - | _ => useSource () -where - throwUnknownExpectedType := - throwError "invalid \{...} notation, expected type is not known" - throwUnexpectedExpectedType type (kind := "expected") := do - let type ← instantiateMVars type - if type.getAppFn.isMVar then - throwUnknownExpectedType - else - throwError "invalid \{...} notation, {kind} type is not of the form (C ...){indentExpr type}" - -/-- Information on the left hand side of a binding encountered in structure syntax. -/ -inductive FieldLHS where - /-- A representation of the name of a field as encountered in binding syntax (e.g. `x` in - `x := ...`). -/ - | fieldName (ref : Syntax) (name : Name) - /-- A representation of the index of a field as encountered in binding syntax (e.g. `3` in - `3 := ...`). -/ - | fieldIndex (ref : Syntax) (idx : Nat) - /-- A representation of a modifyOp as encountered in binding syntax. -/ - | modifyOp (ref : Syntax) (index : Syntax) - deriving Inhabited - -instance : ToFormat FieldLHS := ⟨fun lhs => - match lhs with - | .fieldName _ n => format n - | .fieldIndex _ i => format i - | .modifyOp _ i => "[" ++ i.prettyPrint ++ "]"⟩ - -/-- - A limited, pre-expression description of the values of fields. Only terms given by raw syntax, - nested values (for subobjects), and missing values are can be specified. - The polymorphism via its `Type` argument is only used for nested `FieldVal`s, which need to - know what type their argument should be. In practice, we only ever take this argument to be - `Struct`. - -/ -inductive FieldVal (σ : Type) where - /-- Term syntax encountered on the RHS of a binding, e.g. `1+1` in `x := 1+1`. -/ - | term (stx : Syntax) : FieldVal σ - /-- A nested `FieldVal`, which in practice is used to hold subobjects as `Struct`s. -/ - | nested (s : σ) : FieldVal σ - /-- An indication that this field was missing, i.e. not specified explicitly in the syntax. -/ - | missing : FieldVal σ - deriving Inhabited - -/-- - A representation of a field in a structure. This contains the original syntax of the field - (`ref`), a representation of the LHS of the `:=` binding (`lhs`), the pre-expression `FieldVal` - (`val`), and the actual expression that we take to be the value of the field (`expr?`). - `expr?` begins as `none`, and is modified over the course of this code as we figure out whether - we need to elaborate some syntax encountered (e.g. if `.term stx` is in `val`) or if the field - value is `.missing` (in which case we make a metavariable). --/ -structure Field (σ : Type) where - /-- The syntax of the binding used to specify this field. -/ - ref : Syntax - /-- Information on the LHS of the binding used to specify this field. -/ - lhs : List FieldLHS - /-- The basic content of the field value, prior to elaboration. -/ - val : FieldVal σ - /-- The elaborated value of the field in question as it becomes available, which starts - out as `none` and is updated during `elabStruct` with either elaborated terms or - metavariables which may get assigned to synthesized defaults. -/ - expr? : Option Expr := none - deriving Inhabited - -/-- Check if the LHS of the binding specifying a field is a single `FieldLHS`. -/ -def Field.isSimple {σ} : Field σ → Bool - | { lhs := [_], .. } => true - | _ => false - -/-- - The organized content of the structure instance. - The field `params` is used for `.missing` value propagation. It is initially empty, and - then set at `elabStruct`. -/ -inductive Struct where - | mk (ref : Syntax) (structName : Name) (params : Array (Name × Expr)) - (fields : List (Field Struct)) (source : Source) - deriving Inhabited - -/-- Abbreviation for `List (Field Struct)`: A list of representations of the structure's fields. -/ -abbrev Fields := List (Field Struct) - -/-- The original syntax of the structure instance. -/ -def Struct.ref : Struct → Syntax - | ⟨ref, _, _, _, _⟩ => ref - -/-- The name of the structure. -/ -def Struct.structName : Struct → Name - | ⟨_, structName, _, _, _⟩ => structName - -/-- Parameters used during the initial processing of `.missing` fields. Initially `none`, and set - at `elabStruct`. -/ -def Struct.params : Struct → Array (Name × Expr) - | ⟨_, _, params, _, _⟩ => params - -/-- The list of `fields` in the structure instance as `Field Struct`s. Updated over the course of - the elaboration to include computed values. -/ -def Struct.fields : Struct → Fields - | ⟨_, _, _, fields, _⟩ => fields - -/-- Information on other sources of values for the structure. Namely, any structures preceding - `with` in structure update syntax and any variadic holes (`..`, `?..`) following the field - bindings. -/ -def Struct.source : Struct → Source - | ⟨_, _, _, _, s⟩ => s - -/-- `true` iff all fields of the given structure are marked as `.missing`. -/ -partial def Struct.allMissing (s : Struct) : Bool := - s.fields.all fun { val := val, .. } => match val with - | .term _ => false - | .missing => true - | .nested s => allMissing s - -/-- Pretty-prints a field (`Field Struct`). Uses the field LHS's and its `val : FieldVal Struct`. -/ -def formatField (formatStruct : Struct → Format) (field : Field Struct) : Format := - Format.joinSep field.lhs " . " ++ " := " ++ - match field.val with - | .term v => v.prettyPrint - | .nested s => formatStruct s - | .missing => "" - -/-- Pretty-prints a `Struct`. -/ -partial def formatStruct : Struct → Format - | ⟨_, _, _, fields, source⟩ => - let fieldsFmt := Format.joinSep (fields.map (formatField formatStruct)) ", " - let implicitFmt := match source.implicit with - | some v => format v.stx - | none => "" - if source.explicit.isEmpty then - "{" ++ fieldsFmt ++ implicitFmt ++ "}" - else - "{" ++ format (source.explicit.map (·.stx)) ++ " with " ++ fieldsFmt ++ implicitFmt ++ "}" - -instance : ToFormat Struct := ⟨formatStruct⟩ -instance : ToString Struct := ⟨toString ∘ format⟩ - -instance : ToFormat (Field Struct) := ⟨formatField formatStruct⟩ -instance : ToString (Field Struct) := ⟨toString ∘ format⟩ - -/-- -Turns a `FieldLHS` into syntax. The first argument specifies whether this is the first in a list of -`FieldLHS`'s or not. -Recall that `structInstField` elements have the form -``` - def structInstField := leading_parser structInstLVal >> " := " >> termParser - def structInstLVal := leading_parser (ident <|> numLit <|> structInstArrayRef) - >> many (("." >> (ident <|> numLit)) <|> structInstArrayRef) - def structInstArrayRef := leading_parser "[" >> termParser >>"]" -``` -Remark: this code relies on the fact that `expandStruct` only transforms `fieldLHS.fieldName` --/ -def FieldLHS.toSyntax (first : Bool) : FieldLHS → Syntax - | .modifyOp stx _ => stx - | .fieldName stx name => if first then mkIdentFrom stx name - else mkGroupNode #[mkAtomFrom stx ".", mkIdentFrom stx name] - | .fieldIndex stx _ => if first then stx else mkGroupNode #[mkAtomFrom stx ".", stx] - -/-- Extracts the `stx` from a `.term stx : FieldVal Struct`. Panics when called on any other - constructor of `FieldVal Struct`. -/ -def FieldVal.toSyntax : FieldVal Struct → Syntax - | .term stx => stx - | _ => unreachable! - -/-- Turns a field (as a `Field Struct`) into syntax if has a `val` of the form `.term stx`; panics - otherwise. Panics if the `lhs` is an empty list. -/ -def Field.toSyntax : Field Struct → Syntax - | field => - let stx := field.ref - let stx := stx.setArg 2 field.val.toSyntax - match field.lhs with - | first::rest => stx.setArg 0 <| mkNullNode - #[first.toSyntax true, mkNullNode <| rest.toArray.map (FieldLHS.toSyntax false) ] - | _ => unreachable! - -/-- Processes syntax into a `FieldLHS`. -/ -private def toFieldLHS (stx : Syntax) : MacroM FieldLHS := - if stx.getKind == ``Lean.Parser.Term.structInstArrayRef then - return FieldLHS.modifyOp stx stx[1] - else - -- Note that the representation of the first field is different. - let stx := if stx.getKind == groupKind then stx[1] else stx - if stx.isIdent then - return FieldLHS.fieldName stx stx.getId.eraseMacroScopes - else match stx.isFieldIdx? with - | some idx => return FieldLHS.fieldIndex stx idx - | none => Macro.throwError "unexpected structure syntax" - -/-- Processes structure instance syntax into a `Struct` given the `structName` and its `source`s. -/ -private def mkStructView (stx : Syntax) (structName : Name) (source : Source) : MacroM Struct := do - /- Recall that `stx` is of the form - ``` - leading_parser "{" >> optional (atomic (sepBy1 termParser ", " >> " with ")) - >> sepByIndent (structInstFieldAbbrev <|> structInstField) ... - >> variadicHole - >> optional (" : " >> termParser) - >> " }" - ``` - This method assumes that `structInstFieldAbbrev` had already been expanded. - -/ - let fields ← stx[2].getSepArgs.toList.mapM fun fieldStx => do - let val := fieldStx[2] - let first ← toFieldLHS fieldStx[0][0] - let rest ← fieldStx[0][1].getArgs.toList.mapM toFieldLHS - return { ref := fieldStx, lhs := first :: rest, val := FieldVal.term val : Field Struct } - return ⟨stx, structName, #[], fields, source⟩ - -/-- (Monadic) Modifies a `Struct`'s fields with a monadic function. -/ -def Struct.modifyFieldsM {m : Type → Type} [Monad m] (s : Struct) (f : Fields → m Fields) : -m Struct := - match s with - | ⟨ref, structName, params, fields, source⟩ => - return ⟨ref, structName, params, (← f fields), source⟩ - -/-- Modify a `Struct`'s `Fields` with a function. -/ -def Struct.modifyFields (s : Struct) (f : Fields → Fields) : Struct := - Id.run <| s.modifyFieldsM f - -/-- Overwrite a `Struct`'s fields. -/ -def Struct.setFields (s : Struct) (fields : Fields) : Struct := - s.modifyFields fun _ => fields - -/-- Overwrite a `Struct`'s params. -/ -def Struct.setParams (s : Struct) (ps : Array (Name × Expr)) : Struct := - match s with - | ⟨ref, structName, _, fields, source⟩ => ⟨ref, structName, ps, fields, source⟩ - -/-- Breaks down non-anonymous names in the lhs of fields into lists of their components. -/ -private def expandCompositeFields (s : Struct) : Struct := - s.modifyFields fun fields => fields.map fun field => match field with - | { lhs := .fieldName _ (.str Name.anonymous ..) :: _, .. } => field - | { lhs := .fieldName ref n@(.str ..) :: rest, .. } => - let newEntries := n.components.map <| FieldLHS.fieldName ref - { field with lhs := newEntries ++ rest } - | _ => field - -/-- Replaces field lhs's that are specified by index with the name of the field (as registered in - the structure). -/ -private def expandNumLitFields (s : Struct) : TermElabM Struct := - s.modifyFieldsM fun fields => do - let env ← getEnv - let fieldNames := getStructureFields env s.structName - fields.mapM fun field => match field with - | { lhs := .fieldIndex ref idx :: rest, .. } => - if idx == 0 then throwErrorAt ref "invalid field index, index must be greater than 0" - else if idx > fieldNames.size - then throwErrorAt ref "invalid field index, structure has only #{fieldNames.size} fields" - else return { field with lhs := .fieldName ref fieldNames[idx - 1]! :: rest } - | _ => return field - -/-- For example, consider the following structures: - ``` - structure A where - x : Nat - structure B extends A where - y : Nat - structure C extends B where - z : Bool - ``` - This method expands parent structure fields using the path to the parent structure. - For example, - ``` - { x := 0, y := 0, z := true : C } - ``` - is expanded into - ``` - { toB.toA.x := 0, toB.y := 0, z := true : C } - ``` --/ -private def expandParentFields (s : Struct) : TermElabM Struct := do - let env ← getEnv - s.modifyFieldsM fun fields => fields.mapM fun field => do match field with - | { lhs := .fieldName ref fieldName :: _, .. } => - addCompletionInfo <| CompletionInfo.fieldId ref fieldName (← getLCtx) s.structName - match findField? env s.structName fieldName with - | none => throwErrorAt ref "'{fieldName}' is not a field of structure '{s.structName}'" - | some baseStructName => - if baseStructName == s.structName then pure field - else match getPathToBaseStructure? env baseStructName s.structName with - | some path => - let path := path.map fun funName => match funName with - | .str _ s => .fieldName ref (Name.mkSimple s) - | _ => unreachable! - return { field with lhs := path ++ field.lhs } - | _ => throwErrorAt ref "failed to access field '{fieldName}' in parent structure" - | _ => return field - -/-- Abbreviation for `HashMap Name Fields`: A hash map from field names to lists of representations - of fields. -/ -private abbrev FieldMap := HashMap Name Fields - -/-- Creates a hash map from field names to lists of representations of fields. The length of the - list can be greater than one if the field is not simple. Panics if the lhs of a field is empty. - -/ -private def mkFieldMap (fields : Fields) : TermElabM FieldMap := - fields.foldlM (init := {}) fun fieldMap field => - match field.lhs with - | .fieldName _ fieldName :: _ => - match fieldMap.find? fieldName with - | some (prevField::restFields) => - if field.isSimple || prevField.isSimple then - throwErrorAt field.ref "field '{fieldName}' has already been specified" - else - return fieldMap.insert fieldName (field::prevField::restFields) - | _ => return fieldMap.insert fieldName [field] - | _ => unreachable! - -/-- Unwraps a `Field Struct` from a list of length one, and otherwise returns `none`. -/ -private def isSimpleField? : Fields → Option (Field Struct) - | [field] => if field.isSimple then some field else none - | _ => none - -/-- Finds the index of the field name in its third argument in the list of field names in its - second. The first argument, the name of the structure, is used only for descriptive error - messages. -/ -private def getFieldIdx (structName : Name) (fieldNames : Array Name) (fieldName : Name) : -TermElabM Nat := do - match fieldNames.findIdx? fun n => n == fieldName with - | some idx => return idx - | none => throwError "field '{fieldName}' is not a valid field of '{structName}'" - -/-- Constructs the syntax for a field projection. Only does so if the given field name is in fact a - field of the given structure name; returns `none` otherwise. -/ -def mkProjStx? (s : Syntax) (structName : Name) (fieldName : Name) : TermElabM (Option Syntax) := do - if (findField? (← getEnv) structName fieldName).isNone then - return none - return some <| mkNode ``Parser.Term.proj #[s, mkAtomFrom s ".", mkIdentFrom s fieldName] - -/-- Gets a field from a list of fields by name. If not found, returns `none`. -/ -def findField? (fields : Fields) (fieldName : Name) : Option (Field Struct) := - fields.find? fun field => - match field.lhs with - | [.fieldName _ n] => n == fieldName - | _ => false - -mutual - - /-- Group fields that belong to a subobject as a `Struct` under that subobject field via a - `.nested s` `FieldVal`. For example, a `Struct` representing - `{ toFoo.x := 1, toFoo.y := 2, z := 3 }` will become one representing - `{ toFoo := { x := 1, y := 2 }, z := 3 }`. - -/ - private partial def groupFields (s : Struct) : TermElabM Struct := do - let env ← getEnv - withRef s.ref do - s.modifyFieldsM fun fields => do - let fieldMap ← mkFieldMap fields - fieldMap.toList.mapM fun ⟨fieldName, fields⟩ => do - match isSimpleField? fields with - | some field => pure field - | none => - let substructFields := fields.map fun field => { field with lhs := field.lhs.tail! } - let field := fields.head! - match Lean.isSubobjectField? env s.structName fieldName with - | some substructName => - let substruct := Struct.mk s.ref substructName #[] substructFields s.source - let substruct ← expandStruct substruct - pure { field with lhs := [field.lhs.head!], val := FieldVal.nested substruct } - | none => - let updateSource (structStx : Syntax) : TermElabM Syntax := do - let sourcesNew ← s.source.explicit.filterMapM - fun source => mkProjStx? source.stx source.structName fieldName - let explicitSourceStx := if sourcesNew.isEmpty then mkNullNode - else mkSourcesWithSyntax sourcesNew - let implicitSourceStx := s.source.implicit.map (·.stx) |>.getD mkNullNode - return (structStx.setArg 1 explicitSourceStx).setArg 3 implicitSourceStx - let valStx := s.ref -- construct substructure syntax using s.ref as template - let valStx := valStx.setArg 4 mkNullNode -- erase optional expected type - let args := substructFields.toArray.map (·.toSyntax) - let valStx := valStx.setArg 2 (mkNullNode <| mkSepArray args (mkAtom ",")) - let valStx ← updateSource valStx - return { field with lhs := [field.lhs.head!], val := FieldVal.term valStx } - - /-- - Add `val : FieldVal`s to fields as specified by the sources. - If a value is found in the explicit sources (prior to `with`), add it as a `.term` or a - `.nested` `FieldVal`, as appropriate. If not, check for `..`, and make a hole via syntax as a - `.term`. Otherwise, mark the field as as `.missing`. - -/ - private partial def addMissingFields (s : Struct) : TermElabM Struct := do - let env ← getEnv - let fieldNames := getStructureFields env s.structName - let ref := s.ref.mkSynthetic - withRef ref do - let fields ← fieldNames.foldlM (init := []) fun fields fieldName => do - match findField? s.fields fieldName with - | some field => return field::fields - | none => - let addField (val : FieldVal Struct) : TermElabM Fields := do - return { ref, lhs := [FieldLHS.fieldName ref fieldName], val := val } :: fields - match Lean.isSubobjectField? env s.structName fieldName with - | some substructName => - -- If one of the sources has the subobject field, use it - if let some val ← s.source.explicit.findSomeM? - fun source => mkProjStx? source.stx source.structName fieldName - then - addField (FieldVal.term val) - else - let substruct := Struct.mk ref substructName #[] [] s.source - let substruct ← expandStruct substruct - addField (FieldVal.nested substruct) - | none => - if let some val ← s.source.explicit.findSomeM? - fun source => mkProjStx? source.stx source.structName fieldName - then - addField (FieldVal.term val) - else - -- Use hole syntax as a term in the natural, no-defaults (`..`) case; - -- otherwise mark it as a missing field. - match s.source.implicit with - | some { isSynthetic := false, useDefaults := false, .. } => - addField (FieldVal.term (mkHole ref)) - | _ => addField FieldVal.missing - return s.setFields fields.reverse - - /-- Put the `Struct` into canonical form by expanding different ways of specifying fields - (composite, by index, subobject); group fields by subobject; and incorporate values (or - holes) sources. -/ - private partial def expandStruct (s : Struct) : TermElabM Struct := do - let s := expandCompositeFields s - let s ← expandNumLitFields s - let s ← expandParentFields s - let s ← groupFields s - addMissingFields s - -end - -/-- Information about the constructor. -/ -structure CtorHeaderResult where - /-- The constructor function itself as an `Expr`. -/ - ctorFn : Expr - /-- The type of the constructor as an `Expr`. -/ - ctorFnType : Expr - /-- Metavariables for instances. -/ - instMVars : Array MVarId - /-- Named parameters encountered in bindings of the type and the expressions used for them. -/ - params : Array (Name × Expr) - -/-- Helper function that processes the constructor and its type until its first parameter reaches 0. --/ -private def mkCtorHeaderAux : -Nat → Expr → Expr → Array MVarId → Array (Name × Expr) → TermElabM CtorHeaderResult - | 0, type, ctorFn, instMVars, params => - return { ctorFn , ctorFnType := type, instMVars, params } - | n+1, type, ctorFn, instMVars, params => do - match (← whnfForall type) with - | .forallE paramName d b c => - match c with - | .instImplicit => - let a ← mkFreshExprMVar d .synthetic - mkCtorHeaderAux n (b.instantiate1 a) (mkApp ctorFn a) (instMVars.push a.mvarId!) - (params.push (paramName, a)) - | _ => - let a ← mkFreshExprMVar d - mkCtorHeaderAux n (b.instantiate1 a) (mkApp ctorFn a) instMVars (params.push (paramName, a)) - | _ => throwError "unexpected constructor type" - -/-- Burrows into the body of a `.forallE` expression `n` times if possible, and returns the result. - If an expression not of the form `.forallE` is encountered along the way, return `none`. -/ -private partial def getForallBody : Nat → Expr → Option Expr - | i+1, .forallE _ _ b _ => getForallBody i b - | _+1, _ => none - | 0, type => type - -/-- When the expected type is known, attempt to get the type of the constructor by stripping `n` - `.forallE`'s off of the expression and then assigning metavariables by `isDefEq`'ing with - the expected type. -/ -private def propagateExpectedType (type : Expr) (numFields : Nat) (expectedType? : Option Expr) : -TermElabM Unit := do - match expectedType? with - | none => return () - | some expectedType => - match getForallBody numFields type with - | none => pure () - | some typeBody => - unless typeBody.hasLooseBVars do - discard <| isDefEq expectedType typeBody - -/-- Process information about a given `ConstructorVal`. -/ -private def mkCtorHeader (ctorVal : ConstructorVal) (expectedType? : Option Expr) : -TermElabM CtorHeaderResult := do - let us ← mkFreshLevelMVars ctorVal.levelParams.length - let val := Lean.mkConst ctorVal.name us - let type ← instantiateTypeLevelParams (ConstantInfo.ctorInfo ctorVal) us - let r ← mkCtorHeaderAux ctorVal.numParams type val #[] #[] - propagateExpectedType r.ctorFnType ctorVal.numFields expectedType? - synthesizeAppInstMVars r.instMVars r.ctorFn - return r - -/-- Annotate an expression to indicate that it must be synthesized as a default value. - In practice, the expression is a metavariable. -/ -def markDefaultMissing (e : Expr) : Expr := - mkAnnotation `structInstDefault e - -/-- Check if an expression has been annotated in a way that indicates it should be synthesized - during the default loop. -/ -def defaultMissing? (e : Expr) : Option Expr := - annotation? `structInstDefault e - -/-- Provide a descriptive error message if the structure instance elaboration fails. -/ -def throwFailedToElabField {α} (fieldName : Name) (structName : Name) (msgData : MessageData) : -TermElabM α := - throwError "failed to elaborate field '{fieldName}' of '{structName}, {msgData}" - -/-- Attempt to synthesize an -/ -def trySynthStructInstance? (s : Struct) (expectedType : Expr) : TermElabM (Option Expr) := do - if !s.allMissing then - return none - else - try synthInstance? expectedType catch _ => return none - --- By Mario Carneiro -/-- Use an expression in syntax. Example: ``(foo $(← toSyntax e))`. - This works by creating syntax for a metavariable, then elaborating that syntax and assigning - the metavariable to the expression in question. - -/ -def toSyntax (e : Expr) (type? : Option Expr := none) : TermElabM Syntax := withFreshMacroScope do - let stx ← `(?a) - let mvar ← elabTerm stx type? - mvar.mvarId!.assign e - pure stx - -/-- - The result of running `elabStruct` on a `Struct`, containing: - * `struct : Struct`, now with updated `expr?` values in its fields, representing the values for - those fields. - * `val : Expr`, the constructor applied to the field values (`expr?`s). This is the actual - expression that the structure instance elaborates to. (Note that this is distinct from the - `val` of each field, which is a `FieldVal`.) - * `instMVars : Array MVarId`, used forkeeping track of instances. - -/ -structure ElabStructResult where - /-- The structure's constructor applied to the field values (`expr?`s). This is the actual - expression that the structure instance elaborates to. -/ - val : Expr - /-- The `struct` that was fed to `elabStruct`, but now with updated `expr?` values for all of its - fields containing their values as expressions. -/ - struct : Struct - /-- Used for keeping track of instances. -/ - instMVars : Array MVarId - -/-- - Elaborates a `Struct` into an `ElabStructResult`. - This computes expressions for all fields of a structure (in `expr?`) on the basis of `FieldVal`s - while simultaneously building the elaboration of the structure instance itself, in the form of - its constructor applied to the expressions for each of its fields in turn. - `.term stx` `FieldVals` are elaborated while ensuring the type (as given by the constructor's - type), `.nested s` `FieldVals` are recursed into. `.missing` `FieldVals` are replaced with - metavariables and annotated to indicate that they will get assigned during the default synthesis - loop. Note that in this case the same metavariable is used both in the `expr?` field and the - final constructed expression (`val`), so that assigning it gives access to the value in both - places. The one exception is if an `autoParam` is encountered in the type, in which case the - tactic is elaborated. --/ -private partial def elabStruct (s : Struct) (expectedType? : Option Expr) : -TermElabM ElabStructResult := withRef s.ref do - let env ← getEnv - let vhc? := s.source.implicit - let ctorVal := getStructureCtor env s.structName - if isPrivateNameFromImportedModule env ctorVal.name then - throwError "invalid \{...} notation, constructor for `{s.structName}` is marked as private" - -- We store the parameters at the resulting `Struct`. - -- We use this information during default value propagation. - let { ctorFn, ctorFnType, params, .. } ← mkCtorHeader ctorVal expectedType? - let (e, _, fields, instMVars) ← s.fields.foldlM - (init := (ctorFn, ctorFnType, [], #[])) - fun (e, type, fields, instMVars) field => do - match field.lhs with - | [.fieldName ref fieldName] => - let type ← whnfForall type - trace[Elab.struct] "elabStruct {field}, {type}" - match type with - | .forallE _ d b bi => - let cont (val : Expr) (field : Field Struct) (instMVars := instMVars) - (updateField := true) : TermElabM (Expr × Expr × Fields × Array MVarId) := do - pushInfoTree <| InfoTree.node (children := {}) <| Info.ofFieldInfo { - projName := s.structName.append fieldName, - fieldName, - lctx := (← getLCtx), - val, - stx := ref } - let e := mkApp e val - let type := b.instantiate1 val - let field := if updateField then { field with expr? := some val } else field - return (e, type, field::fields, instMVars) - match field.val with - | .term stx => - cont (← elabTermEnsuringType stx d.consumeTypeAnnotations) field - | .nested s => - let inst? := if vhc?.all (·.useDefaults) then - (← trySynthStructInstance? s d) else none - match inst? with - | some val => - cont val { field with val := FieldVal.term (mkHole field.ref) } - | none => - let { val, struct := sNew, instMVars := instMVarsNew } ← elabStruct s (some d) - let val ← ensureHasType d val - cont val { field with val := FieldVal.nested sNew } (instMVars ++ instMVarsNew) - | .missing => - match d.getAutoParamTactic? with - | some (.const tacticDecl ..) => - let d := (d.getArg! 0).consumeTypeAnnotations - if vhc?.all (·.useDefaults) then - match evalSyntaxConstant env (← getOptions) tacticDecl with - | .error err => throwError err - | .ok tacticSyntax => - if vhc?.isSome then - let val := (← mkFreshExprMVar (some d) .synthetic) - let stx ← `(by first | $tacticSyntax | exact $(← toSyntax val)) - cont (← elabTermEnsuringType stx d) - {field with expr? := some (markDefaultMissing val)} - (updateField := false) - else - let stx ← `(by $tacticSyntax) - cont (← elabTermEnsuringType stx d) field - else - let val ← withRef field.ref <| mkFreshExprMVar (some d) - cont (markDefaultMissing val) field - | _ => - if bi == .instImplicit then - let val ← withRef field.ref <| mkFreshExprMVar d .synthetic - trace[Elab.struct] ".instImplicit ({val})" - cont val field (instMVars.push val.mvarId!) - else - let val ← withRef field.ref <| mkFreshExprMVar (some d) - cont (markDefaultMissing val) field - | _ => withRef field.ref (throwFailedToElabField - fieldName s.structName m!"unexpected constructor type{indentExpr type}") - | _ => throwErrorAt field.ref "unexpected unexpanded structure field" - return { val := e, struct := s.setFields fields.reverse |>.setParams params, instMVars } - -namespace ImplicitFields - -/-- Updated as we search for default values. We must search for default values overriden in derived - structures. -/ -structure Context where - /-- `Struct`s in the context which might supply default values. -/ - structs : Array Struct := #[] - /-- The names of structures in the context which might supply default values. -/ - allStructNames : Array Name := #[] - /-- - Consider the following example: - ``` - structure A where - x : Nat := 1 - structure B extends A where - y : Nat := x + 1 - x := y + 1 - structure C extends B where - z : Nat := 2*y - x := z + 3 - ``` - And we are trying to elaborate a structure instance for `C`. - There are default values for `x` at `A`, `B`, and `C`. - We say the default value at `C` has distance 0, the one at `B` distance 1, and the one at `A` - distance 2. - The field `maxDistance` specifies the maximum distance considered in a round of Default field - computation. - Remark: since `C` does not set a default value of `y`, the default value at `B` is at distance 0. - The fixpoint for setting default values works in the following way. - - Keep computing default values using `maxDistance == 0`. - - We increase `maxDistance` whenever we failed to compute a new default value in a round. - - If `maxDistance > 0`, then we interrupt a round as soon as we compute some default value. - We use depth-first search. - - We sign an error if no progress is made when `maxDistance` == structure hierarchy depth (2 in - the example above). - -/ - maxDistance : Nat := 0 - -/-- Stores an indicator of whether progress has been made during a round in the default loop. -/ -structure State where - /-- Indicates whether progress has been made during a round in the default loop. -/ - progress : Bool := false - -/-- Collects the names of all nested structures in a `Struct` (at any depth), including the name of - the structure itself. -/ -partial def collectStructNames (struct : Struct) (names : Array Name) : Array Name := - let names := names.push struct.structName - struct.fields.foldl (init := names) fun names field => - match field.val with - | .nested struct => collectStructNames struct names - | _ => names - -/-- Gets the maximum depth at which any structure is nested within the given structure, i.e. the - height of its subobject poset. -/ -partial def getHierarchyDepth (struct : Struct) : Nat := - struct.fields.foldl (init := 0) fun max field => - match field.val with - | .nested struct => Nat.max max (getHierarchyDepth struct + 1) - | _ => max - -/-- (Monadic) Checks if the value of a field (`expr?`) is an unassigned metavariable that is - annotated to indicate that it should be synthesized during the default loop. -/ -def isDefaultMissing? [Monad m] [MonadMCtx m] (field : Field Struct) : m Bool := do - if let some expr := field.expr? then - if let some (.mvar mvarId) := defaultMissing? expr then - unless (← mvarId.isAssigned) do - return true - return false - -/-- (Monadic) Gets the first encountered field in a `Struct` whose value (`expr?`) is an unassigned - metavariable that is annotated to indicate that it should be synthesized during the default - loop. -/ -partial def findDefaultMissing? [Monad m] [MonadMCtx m] (struct : Struct) : -m (Option (Field Struct)) := - struct.fields.findSomeM? fun field => do - match field.val with - | .nested struct => findDefaultMissing? struct - | _ => return if (← isDefaultMissing? field) then field else none - -/-- (Monadic) Gets an array containing all fields in the `Struct` whose value (`expr?`) is an - unassigned metavariable that is annotated to indicate that it should be synthesized during the - default loop. -/ -partial def allDefaultMissing [Monad m] [MonadMCtx m] (struct : Struct) : -m (Array (Field Struct)) := - go struct *> get |>.run' #[] -where - /-- Loop through all fields in the `Struct`, recursing if a `.nested` one is found, and storing - the field in a mutable array if it `isDefaultMissing?` -/ - go (struct : Struct) : StateT (Array (Field Struct)) m Unit := - for field in struct.fields do - if let .nested struct := field.val then - go struct - else if (← isDefaultMissing? field) then - modify (·.push field) - -/-- Gets the name of a field, assuming that its `lhs` is of the form `[.fieldName _ fieldName]`. - Panics otherwise. -/ -def getFieldName (field : Field Struct) : Name := - match field.lhs with - | [.fieldName _ fieldName] => fieldName - | _ => unreachable! - -/-- Abbreviation for `ReaderT Context (StateRefT State TermElabM)`: A monad transformation of - `TermElabM` that lets us access the `Context` (relevant for checking if default values are - overridden) and keeping track of whether progress has been made during a round of the default - loop (`State`). -/ -abbrev M := ReaderT Context (StateRefT State TermElabM) - -/-- Checks if the round has completed by checking that progress has been made and that the - `maxDistance > 0`. -/ -def isRoundDone : M Bool := do - return (← get).progress && (← read).maxDistance > 0 - -/-- Gets the value (`expr?`) of a field in a `Struct` given the name of the field. -/ -def getFieldValue? (struct : Struct) (fieldName : Name) : Option Expr := - struct.fields.findSome? fun field => - if getFieldName field == fieldName then - field.expr? - else - none - -section NamedGoalsWithMetadata -/-- A convenient representation of the metadata attached to named goals produced by `?..` syntax. -/ -structure FieldHoleMData where - /-- The index of the named goal used for name conflict resolution when dealing with multiple - occcurrences of `?..`. Each conflicting use of `?..` should generate field holes with - different indices. An index of `0` indicates that no name conflicts were found with any - existing goals. -/ - index : Nat - /-- The syntax of the structure instance that contained the `?..` syntax. -/ - structRef : Syntax - /-- The name of the structure that contained the `?..` syntax. -/ - structName : Name - /-- The name of the field this goal represents. -/ - fieldName : Name - /-- The name to be prefixed to the name of this goal. `Name.anonymous` indicates that no name is - to be prefixed. -/ - prefixName : Name - -/-- Creates the metadata for a field's named goal given the field, the `Struct`, and the - conflict-resolution index. -/ -def mkFieldHoleMData (index : Nat) (field : Field Struct) (struct : Struct) : FieldHoleMData := - { - index, - structRef := struct.ref - structName := struct.structName - fieldName := getFieldName field - prefixName := match struct.source.implicit with - | some {name := some prefixName, ..} => prefixName - | _ => Name.anonymous - } - -open KVMap in -/-- Gets the field hole metadata from a metavariable if present. -/ -def getFieldHoleMDataFromMVar? (decl : MetavarDecl) : Option FieldHoleMData := - match decl.type with - | .mdata md _ => - if getBool md `fieldHole then - some - { - index := getNat md `index - structRef := getSyntax md `structRef - structName := getName md `structName - fieldName := getName md `fieldName - prefixName := getName md `prefixName - } - else none - | _ => none - -/-- Checks if a metavariable decl is a named field hole created by `?..` syntax. -/ -def isFieldHole (decl : MetavarDecl) : Bool := - match decl.type with - | .mdata md _ => KVMap.getBool md `fieldHole - | _ => false - -section KVMap -/-- Merges two `KVMap`s, overwriting the values of any shared keys with those in the second `KVMap` - -/ -def mergeKVMap : KVMap → KVMap → KVMap := - fun m₀ m₁ => Id.run do - let mut m := m₀ - for (name, data) in m₁ do - m := KVMap.insert m name data - return m - -/-- Turns a list of key-value pairs (e.g. ``[(`a, ofBool true), (`b, ofNat 2), ...]``) into a - `KVMap`. -/ -def toKVMap : List (Name × DataValue) → KVMap -| l => l.foldl (fun m (n, d) => KVMap.insert m n d) {} - -end KVMap - -open DataValue in -/-- Turns a representation of field hole metadata into actual metadata (a `KVMap`). -/ -def mkFieldHoleMDataKVMap (f : FieldHoleMData) : KVMap := - toKVMap [ - (`fieldHole , ofBool true ), - (`index , ofNat f.index ), - (`structRef , ofSyntax f.structRef ), - (`structName , ofName f.structName), - (`fieldName , ofName f.fieldName ), - (`prefixName , ofName f.prefixName) - ] - -/-- - Create a metavariable with `metadata` attached to its `type`. - If there's any existing metadata on `type`, `metadata` is preferentially merged into it. - -/ -def mkFreshExprMVarWithMData (type : Expr) (metadata : KVMap) (kind : MetavarKind := default) -(userName := Name.anonymous) : MetaM Expr := - let annotatedType := - match type with - | .mdata m e => - let merge := mergeKVMap m metadata - Expr.mdata merge e - | _ => - Expr.mdata metadata type - mkFreshExprMVar annotatedType (kind := kind) (userName := userName) - -/-- Make a fresh expression metavariable for a field, named accordingly, and with metadata - attached. -/ -def mkFreshFieldNamedMVar (type : Expr) (index : Nat) (prefixName : Option Name) -(field : Field Struct) (struct : Struct) : MetaM Expr := - let fieldHoleMData := mkFieldHoleMDataKVMap <| mkFieldHoleMData index field struct - let name := - match prefixName with - | some x => x ++ (getFieldName field) - | none => getFieldName field - let name := if index == 0 then name else name.appendIndexAfter index - mkFreshExprMVarWithMData type fieldHoleMData (kind := .syntheticOpaque) (userName := name) - -/-- Given the names of two structures, check if they have any field names in common. -/ -def fieldsOverlap (env : Environment) (structName₀ : Name) (structName₁ : Name) : Bool := - let fields₀ := getStructureFieldsFlattened env structName₀ false - let fields₁ := getStructureFieldsFlattened env structName₁ false - fields₀.any (fun field => fields₁.contains field) - --- Monadic to enable tracing. -/-- If the provided metavariable decl is a named field hole created by `?..` syntax, check if it - conflicts with the current structure and prefix name. If so, return its index. Otherwise, - return `none`. -/ -def getConflictingIndex? (env : Environment) (s : Struct) (prefixName : Name) (decl : MetavarDecl) -: TermElabM (Option Nat) := do - let fieldHoleMData? := getFieldHoleMDataFromMVar? decl - match fieldHoleMData? with - | some fieldHoleMData => - let cond2 := prefixName == fieldHoleMData.prefixName - let cond3 := fieldsOverlap env s.structName (fieldHoleMData.structName) - trace[Elab.struct] - "goal name conflict for {fieldHoleMData.structName}: {cond2} && {cond3}" - if cond2 && cond3 - then return some fieldHoleMData.index - else return none - | none => return none - -/-- Get the next non-conflicting index among all metavariable conflicts. - A metavariable conflicts iff all of the following are true: - * it is a named field hole created by `?..` syntax - * it is not from the same occurrence of `?..` - * it has the same prefix name (possibly `Name.anonymous` if it does not have a prefix) - * it belongs to a structure that has field names in common with the current structure - Note that this gets the index one greater than the maximum conflicting index, not the next - "available" index. We take a "wide berth" approach to avoid situations where it might appear - like two goals are from the same occurrence of `?..` despite this not being the case. -/ -def nextIndexGivenCollisions (env : Environment) (mctx : MetavarContext) (s : Struct) -: TermElabM Nat := do - let prefixName := match s.source.implicit with - | some { name := some prefixName, .. } => prefixName - | _ => Name.anonymous - let conflictingIndex : (Option Nat) ← mctx.decls.foldl - (fun i? _ decl => do - let i'? ← getConflictingIndex? env s prefixName decl - return (Option.merge max (← i?) i'?)) (pure none) - match conflictingIndex with - | some i => return i+1 - | none => return 0 - -/-- Assign all fields which did not get synthesized during the default loop (but which were marked - as such) to appropriately-named field holes with metadata in the case of `?..` syntax (and to - natural holes when the `?` is absent). -/ -def assignRemainingDefaultsToFieldHoles (struct : Struct) : TermElabM Unit := - withRef struct.ref do - match struct.source.implicit with - | some vhc => - let index ← nextIndexGivenCollisions (← getEnv) (← getMCtx) struct - for field in (← allDefaultMissing struct) do - match field.expr? with - | some expr => - match defaultMissing? expr with - | some (.mvar mvarId) => - let type := (← getMVarDecl mvarId).type - if vhc.isSynthetic then - mvarId.assign (← withRef field.ref <| - mkFreshFieldNamedMVar type index vhc.name field struct) - else - let newHole ← withRef field.ref <| mkFreshExprMVar type (kind := .natural) - mvarId.assign newHole - registerMVarErrorHoleInfo newHole.mvarId! struct.ref - | _ => unreachable! - | none => unreachable! - | none => return () - -end NamedGoalsWithMetadata -/-- A helper function that applies lambdas whose parameters are field names to the corresponding - field values until it finds a non-lambda, using propagated parameters instead of field names if - necessary along the way. Returns `none` if it finds a lambda that's not of this form. -/ -partial def mkDefaultValueAux? (struct : Struct) : Expr → TermElabM (Option Expr) - | .lam n d b c => withRef struct.ref do - if c.isExplicit then - let fieldName := n - match getFieldValue? struct fieldName with - | none => return none - | some val => - let valType ← inferType val - if (← isDefEq valType d) then - mkDefaultValueAux? struct (b.instantiate1 val) - else - return none - else - if let some (_, param) := struct.params.find? fun (paramName, _) => paramName == n then - -- Recall that we did not use to have support for parameter propagation here. - if (← isDefEq (← inferType param) d) then - mkDefaultValueAux? struct (b.instantiate1 param) - else - return none - else - let arg ← mkFreshExprMVar d - mkDefaultValueAux? struct (b.instantiate1 arg) - | e => - if e.isAppOfArity ``id 2 then - return some e.appArg! - else - return some e - -/-- If possible, make a default value by applying lambdas in the given constant to the appropriate - field values or propagated parameter values. -/ -def mkDefaultValue? (struct : Struct) (cinfo : ConstantInfo) : TermElabM (Option Expr) := - withRef struct.ref do - let us ← mkFreshLevelMVarsFor cinfo - mkDefaultValueAux? struct (← instantiateValueLevelParams cinfo us) - -/-- Reduce default value. It performs beta reduction and projections of the given structures. -/ -partial def reduce (structNames : Array Name) (e : Expr) : MetaM Expr := do - match e with - | .lam .. => lambdaLetTelescope e fun xs b => do mkLambdaFVars xs (← reduce structNames b) - | .forallE .. => forallTelescope e fun xs b => do mkForallFVars xs (← reduce structNames b) - | .letE .. => lambdaLetTelescope e fun xs b => do mkLetFVars xs (← reduce structNames b) - | .proj _ i b => - match (← Meta.project? b i) with - | some r => reduce structNames r - | none => return e.updateProj! (← reduce structNames b) - | .app f .. => - match (← reduceProjOf? e structNames.contains) with - | some r => reduce structNames r - | none => - let f := f.getAppFn - let f' ← reduce structNames f - if f'.isLambda then - let revArgs := e.getAppRevArgs - reduce structNames (f'.betaRev revArgs) - else - let args ← e.getAppArgs.mapM (reduce structNames) - return mkAppN f' args - | .mdata _ b => - let b ← reduce structNames b - if (defaultMissing? e).isSome && !b.isMVar then - return b - else - return e.updateMData! b - | .mvar mvarId => - match (← getExprMVarAssignment? mvarId) with - | some val => if val.isMVar then pure val else reduce structNames val - | none => return e - | e => return e - -/-- - Attempt to synthesize the default value for a field, looping through nested structures if - necessary. If a default value is found, assign it to the metavariable that we created for the - field's value back in `elabStruct`, and return `true`. Otherwise return `false`. --/ -partial def tryToSynthesizeDefault (structs : Array Struct) (allStructNames : Array Name) -(maxDistance : Nat) (fieldName : Name) (mvarId : MVarId) : TermElabM Bool := - let rec loop (i : Nat) (dist : Nat) := do - if dist > maxDistance then - return false - else if h : i < structs.size then - let struct := structs.get ⟨i, h⟩ - match getDefaultFnForField? (← getEnv) struct.structName fieldName with - | some defFn => - let cinfo ← getConstInfo defFn - let mctx ← getMCtx - match (← mkDefaultValue? struct cinfo) with - | none => setMCtx mctx; loop (i+1) (dist+1) - | some val => - let val ← reduce allStructNames val - match val.find? fun e => (defaultMissing? e).isSome with - | some _ => setMCtx mctx; loop (i+1) (dist+1) - | none => - let mvarDecl ← getMVarDecl mvarId - let val ← ensureHasType mvarDecl.type val - mvarId.assign val - return true - | _ => loop (i+1) dist - else - return false - loop 0 0 - -/-- The main loop of `tryToSynthesizeDefault`, which keeps track of which struct out of an array of - all nested structs is being considered, as well as the distance to make sure it doesn't exceed - the `maxDistance` (see the documentation for `Context.maxDistance`). -/ -add_decl_doc tryToSynthesizeDefault.loop - -/-- - A step within the default synthesis loop. We proceed only if the round is not done. We loop - through all fields in the structure, attempting to synthesize a default via - `tryToSynthesizeDefault` when possible. If we succeed, we set `progress := true` in the `State`. - Note: by now, all `expr?`s should be `some expr` from `elabStruct`, even if that `expr` is a - metavariable; as such, we panic if one of them is `none`. --/ -partial def step (struct : Struct) : M Unit := - unless (← isRoundDone) do - withReader (fun ctx => { ctx with structs := ctx.structs.push struct }) do - for field in struct.fields do - match field.val with - | .nested struct => step struct - | _ => match field.expr? with - | none => unreachable! - | some expr => - match defaultMissing? expr with - | some (.mvar mvarId) => - unless (← mvarId.isAssigned) do - let ctx ← read - if (← withRef field.ref (tryToSynthesizeDefault - ctx.structs ctx.allStructNames ctx.maxDistance (getFieldName field) mvarId)) - then - modify fun _ => { progress := true } - | _ => pure () - -/-- - The workhorse of the default synthesis loop. - If there are no fields left that need to be synthesized during the default loop, we return from - the loop. - Otherwise, when we find a field that ought to be synthesized during the default loop, we take a - `step`. If we've made `progress`, we call `propagateLoop` again and reset the depth to `0`. If we - haven't, we call `propagateLoop` again with a higher depth. - If the depth ever exceeds the hierarchy depth, we know that we've searched all nested structures, - but no default values were to be found. In this case, we either throw an error with the missing - fields, or, if a variadic hole is present (e.g. `?..`), simply return from the loop (at which - point the remaining holes will be assigned by `assignRemainingDefaultsToFieldHoles` ). --/ -partial def propagateLoop (hierarchyDepth : Nat) (d : Nat) (struct : Struct) : M Unit := do - match (← findDefaultMissing? struct) with - | none => return () -- Done - | some field => - trace[Elab.struct] "propagate [{d}] [field := {field}]: {struct}" - if d > hierarchyDepth then - let missingFields := (← allDefaultMissing struct).map getFieldName - if struct.source.implicit.isSome then - return () - else - let missingFieldsWithoutDefault := - let env := (← getEnv) - let structs := (← read).allStructNames - missingFields.filter fun fieldName => structs.all fun struct => - (getDefaultFnForField? env struct fieldName).isNone - let fieldsToReport := - if missingFieldsWithoutDefault.isEmpty then missingFields else missingFieldsWithoutDefault - throwErrorAt field.ref - "fields missing: {fieldsToReport.toList.map (s!"'{·}'") |> ", ".intercalate}" - else withReader (fun ctx => { ctx with maxDistance := d }) do - modify fun _ => { progress := false } - step struct - if (← get).progress then - propagateLoop hierarchyDepth 0 struct - else - propagateLoop hierarchyDepth (d+1) struct - -/-- - The default synthesis loop. - We call our workhorse function `propagateLoop` with appropriate initial values, which implements - the loop itself (unless there is a variadic hole that specifies defaults are not to be used). - Then, if there is a variadic hole, we assign the remaining metavariables that couldn't be - synthesized into default values to (named) field holes. --/ -def propagate (struct : Struct) : TermElabM Unit := do - let hierarchyDepth := getHierarchyDepth struct - let structNames := collectStructNames struct #[] - let vhc? := struct.source.implicit - if vhc?.all (·.useDefaults) then - propagateLoop hierarchyDepth 0 struct { allStructNames := structNames } |>.run' {} - if vhc?.isSome then - assignRemainingDefaultsToFieldHoles struct - -end ImplicitFields - -/-- - The main content of the elaboration, during which we normalize the `Struct`'s form, call - `elabStruct` to compute field values and construct the elaborated expression, run the default - synthesis loop (and provide named field holes if warranted), and synthesize instances. -/ -private def elabStructInstAux (stx : Syntax) (expectedType? : Option Expr) (source : Source) -: TermElabM Expr := do - let structName ← getStructName expectedType? source - let struct ← liftMacroM <| mkStructView stx structName source - let struct ← expandStruct struct - trace[Elab.struct] "{struct}" - /- We try to synthesize pending problems with `withSynthesize` combinator before trying to use - default values. - This is important in examples such as - ``` - structure MyStruct where - {α : Type u} - {β : Type v} - a : α - b : β - #check { a := 10, b := true : MyStruct } - ``` - were the `α` will remain "unknown" until the default instance for `OfNat` is used to ensure - that `10` is a `Nat`. - TODO: investigate whether this design decision may have unintended side effects or produce - confusing behavior. - -/ - let { val := r, struct, instMVars } ← withSynthesize (mayPostpone := true) <| - elabStruct struct expectedType? - trace[Elab.struct] "before propagate {r}" - ImplicitFields.propagate struct - synthesizeAppInstMVars instMVars r - return r - -/-- The term elaborator for structure instance syntax that includes variadic holes (`?..`). -/ -@[term_elab structInstWithHoles] def elabStructInstWithHoles : TermElab := fun stx expectedType? => -do - match (← expandNonAtomicExplicitSources stx) with - | some stxNew => withMacroExpansion stx stxNew <| elabTerm stxNew expectedType? - | none => - let sourceView ← getStructSource stx - if let some modifyOp ← isModifyOp? stx then - if sourceView.explicit.isEmpty then - throwError - "invalid \{...} notation, explicit source is required when using '[] := '" - elabModifyOp stx modifyOp sourceView.explicit expectedType? - else - elabStructInstAux stx expectedType? sourceView - -section haveFieldProj - -/-- `as foo` names the field projection `foo`. -/ -declare_syntax_cat asname -/-- `as foo` names the field projection `foo`. -/ -syntax "as" ident : asname - --- couldn't write elab "haveFieldProj" f:(ident)? x:("as" n:ident)? : tactic -/-- - Once a goal has been created for a structure's field via `?..` syntax, `haveFieldProj` can be - used equivalently to `have .proj := `. - `haveFieldProj f as a` gets the field projection for the field `f` and names it `a`; - `f` and `as a` can both be individually omitted. --/ -elab "haveFieldProj" f:(ident)? x:(asname)? : tactic => do - let fieldHoleMData? := ImplicitFields.getFieldHoleMDataFromMVar? (← Tactic.getMainDecl) - match fieldHoleMData? with - | some fieldHoleMData => - let fieldName := match f with | some f' => f'.getId | none => fieldHoleMData.fieldName - let structName := fieldHoleMData.structName -- so the error fits on one line - let some projname := - (getProjFnForField? (← getEnv) fieldHoleMData.structName fieldName) | throwError - "couldn't find projection function for field {fieldName} of structure {structName}" - let name := match x with - | some stx => match stx with - | `(asname|as $n:ident) => n - | _ => mkIdent (fieldName ++ `proj) - | none => mkIdent (fieldName ++ `proj) - Tactic.evalTactic (←`(tactic|have $name := $(mkIdent projname))) - | none => throwError "no field metadata found on the main goal" - -end haveFieldProj diff --git a/server/adam/Adam/StructInstWithHolesTest.lean b/server/adam/Adam/StructInstWithHolesTest.lean deleted file mode 100644 index 743e991..0000000 --- a/server/adam/Adam/StructInstWithHolesTest.lean +++ /dev/null @@ -1,117 +0,0 @@ --- import Adam.StructInstWithHoles --- import Mathlib - - --- example : Module ℚ ℝ := by --- refine { ?..! } --- exact fun a r => a * r --- intro b --- sorry --- sorry --- sorry --- sorry --- sorry --- sorry --- sorry - --- structure Foo where --- x : Nat := 0 --- y : Nat - --- structure Bar extends Foo where --- z : Nat := x - --- example := by refine { ?.. : Foo }; case y => exact 0 --- example := by refine { ?.. : Bar }; case y => exact 0 --- example := by refine { ?..a : Bar }; case a.y => exact 0 --- example := by refine { ?..! : Bar }; case x | y | z => exact 0; --- example := by refine { ?..!a : Bar }; case a.x | a.y | a.z => exact 0; --- -- example := by refine' { ... : Bar }; exact 0 --- example := by refine' { .. : Bar }; exact 0; exact 0; exact 0 --- -- example := by refine' { ..! : Bar }; exact 0; exact 0; exact 0 - --- structure rflFoo where --- x : Nat --- y : Nat --- xy : x = y := by rfl - --- example := by refine { ?.. : rflFoo }; (case x | y => exact 0); case xy => rfl --- example := by refine { ?..! : rflFoo }; (case x | y => exact 0); case xy => rfl - --- structure autoFoo where --- x : Nat := 0 --- y : Nat := 0 --- xy : x = y := by rfl - --- example := { ?.. : autoFoo } --- example := by refine { ?..! : autoFoo }; (case x | y => exact 0); case xy => rfl - --- def f : Foo → Nat := fun _ => 0 --- def ff : Foo → Foo → Unit := fun _ _ => () --- def ffb : Foo → Bar → Unit := fun _ _ => () --- def ffa : Foo → autoFoo → Unit := fun _ _ => () - --- example := by refine { x := f { ?.. }, ?.. : Foo }; case y | y_1 => exact 0 --- example := by refine { x := f { ?..x }, ?.. : Foo }; case x.y | y => exact 0 --- example := by refine { x := f { ?.. }, ?..x : Foo }; case y | x.y => exact 0 --- example := by refine { x := f { ?..x }, ?..x : Foo }; case x.y | x.y_1 => exact 0 - --- example := by refine ff { ?.. } { ?.. }; case y | y_1 => exact 0 --- example := by refine ff { ?..! } { ?.. }; case x | y | y_1 => exact 0 --- example := by refine ffb { ?..! } { ?..! }; case x | y | x_1 | y_1 | z_1 => exact 0 --- example := by refine ffa { ?..! } { ?..! }; (case x | y | x_1 | y_1 => exact 0); rfl - --- structure Foo' where --- x : Nat - --- structure dFoo' where --- x : Nat := 0 - --- def ff' : Foo → Foo' → Unit := fun _ _ => () --- def fdf' : Foo → dFoo' → Unit := fun _ _ => () - --- example := by refine ff' { ?.. } { ?.. }; case y | x_1 => exact 0 --- example := by refine fdf' { ?.. } { ?.. }; case y => exact 0 - --- structure Fooα (α : Type) where --- x : α - --- example := by refine { ?.. : Fooα Nat}; case x => exact 0 - --- structure Fooαi where --- {α : Type} --- x : α - --- example := by refine { ?.. : Fooαi }; (case α => exact Nat); case x => exact 0 - --- /- haveFieldProj tests (subject to be moved)-/ --- section haveFieldProj - --- structure Foo'' where --- x : Bool --- y : Nat - --- def foo'': Foo'' := { x := true, y := 0 } - --- example := by --- refine { ?.. : Foo''}; --- haveFieldProj; --- case x => exact x.proj foo''; --- case y => exact 0 --- example := by --- refine { ?.. : Foo''}; --- haveFieldProj as a; --- case x => exact a foo''; --- case y => exact 0 --- example := by --- refine { ?.. : Foo''}; --- haveFieldProj y; --- case x => exact 0 == y.proj foo''; --- case y => exact 0 --- example := by --- refine { ?.. : Foo''}; --- haveFieldProj y as a; --- case x => exact 0 == a foo''; --- case y => exact 0 - --- end haveFieldProj diff --git a/server/adam/Adam/Tactics.lean b/server/adam/Adam/Tactics.lean deleted file mode 100644 index d5dfd4b..0000000 --- a/server/adam/Adam/Tactics.lean +++ /dev/null @@ -1,12 +0,0 @@ -import Lean --- import Adam.MyNat - -open Lean Elab Tactic - -elab "swap" : tactic => do - match ← getGoals with - | g₁::g₂::t => setGoals (g₂::g₁::t) - | _ => pure () - --- macro "induction_on" n:ident : tactic => --- `(tactic| refine myInduction $n ?base ?inductive_step; swap; clear $n; intro $n $(mkIdent `ind_hyp); swap) diff --git a/server/adam/Adam/ToBePorted.lean b/server/adam/Adam/ToBePorted.lean deleted file mode 100644 index 5e6ef93..0000000 --- a/server/adam/Adam/ToBePorted.lean +++ /dev/null @@ -1,87 +0,0 @@ -import Adam.Options.MathlibPart - -open BigOperators - -/-! # Delab Problems -/ - -open Lean PrettyPrinter Delaborator SubExpr - -@[delab app.Finset.sum] -def delabFinsetSum : Delab := do - guard $ (← getExpr).getAppNumArgs == 5 - guard $ ((← getExpr).getArg! 3).isAppOf' ``Finset.univ - guard $ ((← getExpr).getArg! 4).isLambda - withNaryArg 4 do - let α ← withBindingDomain delab - withBindingBodyUnusedName fun n => do - let n : TSyntax `ident := ⟨n⟩ - let b ← delab - `(∑ $n:ident : $α, $b) - - - - -/-! # Other Stuff -/ - --- lemma not_odd {n : ℕ} : ¬ Odd n ↔ Even n := by --- sorry - --- lemma not_even {n : ℕ} : ¬ Even n ↔ Odd n := by --- sorry - - --- section powerset - --- open Set - --- namespace Finset - --- theorem powerset_singleton {U : Type _} [DecidableEq U] (x : U) : --- Finset.powerset {x} = {∅, {x}} := by --- ext y --- rw [mem_powerset, subset_singleton_iff, mem_insert, mem_singleton] - --- end Finset - --- /- The powerset of a singleton contains only `∅` and the singleton. -/ --- theorem powerset_singleton {U : Type _} (x : U) : --- 𝒫 ({x} : Set U) = {∅, {x}} := by --- ext y --- rw [mem_powerset_iff, subset_singleton_iff_eq, mem_insert_iff, mem_singleton_iff] - --- theorem subset_insert_iff_of_not_mem' {U : Type _ } {s t : Set U} {a : U} (h : a ∉ s) --- (g : s ⊆ t) : s ⊆ insert a t := by --- intro y hy --- specialize g hy --- exact mem_insert_of_mem _ g - --- lemma mem_powerset_insert_iff {U : Type _} (A S : Set U) (x : U) : --- S ∈ 𝒫 (insert x A) ↔ S ∈ 𝒫 A ∨ ∃ B ∈ 𝒫 A , insert x B = S := by --- simp_rw [mem_powerset_iff] --- constructor --- · intro h --- by_cases hs : x ∈ S --- · right --- use S \ {x} --- rw [insert_diff_singleton, insert_eq_of_mem hs, diff_singleton_subset_iff] --- exact ⟨h, rfl⟩ --- · left --- exact (subset_insert_iff_of_not_mem hs).mp h --- · intro h --- rcases h with h | ⟨B, h₁, h₂⟩ --- · exact le_trans h (subset_insert x A) --- · rw [←h₂] --- exact insert_subset_insert h₁ - --- lemma mem_powerset_insert_iff' {U : Type _} (A S : Set U) (x : U) : --- S ∈ 𝒫 (insert x A) ↔ S \ {x} ∈ 𝒫 A := by --- rw [mem_powerset_iff, mem_powerset_iff, diff_singleton_subset_iff] - --- lemma powerset_insert {U : Type _} (A : Set U) (x : U) : --- 𝒫 (insert x A) = A.powerset ∪ A.powerset.image (insert x) := by --- ext y --- rw [mem_powerset_insert_iff, mem_union, mem_image] - - - --- end powerset diff --git a/server/adam/gameserver b/server/adam/gameserver deleted file mode 100644 index 21de520..0000000 Binary files a/server/adam/gameserver and /dev/null differ diff --git a/server/adam/lake-manifest.json b/server/adam/lake-manifest.json deleted file mode 100644 index 0856666..0000000 --- a/server/adam/lake-manifest.json +++ /dev/null @@ -1,28 +0,0 @@ -{"version": 4, - "packagesDir": "lake-packages", - "packages": - [{"git": - {"url": "https://github.com/leanprover-community/mathlib4.git", - "subDir?": null, - "rev": "fc4a489c2af75f687338fe85c8901335360f8541", - "name": "mathlib", - "inputRev?": "master"}}, - {"git": - {"url": "https://github.com/gebner/quote4", - "subDir?": null, - "rev": "cc915afc9526e904a7b61f660d330170f9d60dd7", - "name": "Qq", - "inputRev?": "master"}}, - {"git": - {"url": "https://github.com/JLimperg/aesop", - "subDir?": null, - "rev": "071464ac36e339afb7a87640aa1f8121f707a59a", - "name": "aesop", - "inputRev?": "master"}}, - {"path": {"name": "GameServer", "dir": "./../leanserver"}}, - {"git": - {"url": "https://github.com/leanprover/std4", - "subDir?": null, - "rev": "44a92d84c31a88b9af9329a441890ad449d8cd5f", - "name": "std", - "inputRev?": "main"}}]} diff --git a/server/adam/lakefile.lean b/server/adam/lakefile.lean deleted file mode 100644 index a075148..0000000 --- a/server/adam/lakefile.lean +++ /dev/null @@ -1,14 +0,0 @@ -import Lake -open Lake DSL - -require GameServer from ".."/"leanserver" - -require mathlib from git - "https://github.com/leanprover-community/mathlib4.git"@"master" - -package Adam where - moreLeanArgs := #["-DautoImplicit=false", "-Dtactic.hygienic=false"] - moreServerArgs := #["-DautoImplicit=false", "-Dtactic.hygienic=false"] - -@[default_target] -lean_lib Adam diff --git a/server/adam/lean-toolchain b/server/adam/lean-toolchain deleted file mode 100644 index 7f0fd43..0000000 --- a/server/adam/lean-toolchain +++ /dev/null @@ -1 +0,0 @@ -leanprover/lean4:nightly-2023-03-09 diff --git a/server/build.sh b/server/build.sh index 9051276..b1a2afd 100755 --- a/server/build.sh +++ b/server/build.sh @@ -6,17 +6,24 @@ cd $(dirname $0) # Build elan image if not already present docker build --pull --rm -f elan.Dockerfile -t elan:latest . -# Build adam -(cd adam && lake exe cache get && lake build) +# Build Adam +( if [ ! -d adam ] + then + git clone https://github.com/hhu-adam/Robo adam/ + cd adam + else + cd adam + git pull + fi + lake exe cache get + lake build) docker rmi adam:latest || true docker build \ --build-arg GAME_DIR=adam \ --rm -f server.Dockerfile -t adam:latest . # Build NNG - -( - if [ ! -d nng ] +( if [ ! -d nng ] then git clone https://github.com/hhu-adam/NNG4 nng/ cd nng @@ -25,8 +32,7 @@ docker build \ git pull fi lake exe cache get - lake build -) + lake build) docker rmi nng:latest || true docker build \