merge necessary as upstream developed while storyline slept
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
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 "Widerspruch"
|
||||
|
||||
Introduction "
|
||||
Ihr begebt euch auf die Suche nach *Oddeus*. Nach etwas rumfragen, kommt ihr tatsächlich an
|
||||
eine Dornenfestung und nachdem ihr erklärt habt, wer ihr seit, werdet ihr auf eine Audienz
|
||||
gebeten.
|
||||
"
|
||||
@@ -0,0 +1,60 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 1
|
||||
|
||||
Title "Have"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Oddeus**: Willkommen Reisende! Ich muss eingestehen ich bin in Gedanken noch
|
||||
an etwas, könnt ihr mir bei diesem widersprüchlichen Problem helfen?
|
||||
"
|
||||
|
||||
-- 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**: Aber jetzt…
|
||||
|
||||
**Robo**: Du könntest dir ein passendes Zwischenresultat zurechtlegen, das dir hilft:
|
||||
Mach mal `have g : ¬ B`!"
|
||||
have g : ¬ B
|
||||
· Hint "**Du**: Was und jetzt hab ich einfach angenommen das sei richtig?
|
||||
|
||||
**Robo**: Ne, jetzt musst du das zuerst beweisen bevor du es dann benützen kannst."
|
||||
Hint (hidden := true) "**Robo**: `apply` scheint passend zu sein."
|
||||
apply h
|
||||
assumption
|
||||
· Hint (hidden := true) "**Du**: Und wie war das nochmals wenn zwei Annahmen sich widersprechen?
|
||||
|
||||
**Robo**: `contradiction`."
|
||||
contradiction
|
||||
|
||||
NewTactic «have»
|
||||
DisabledTactic «suffices»
|
||||
|
||||
Conclusion "*Oddeus*: Das stimmt wohl."
|
||||
@@ -0,0 +1,63 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 2
|
||||
|
||||
Title "Suffices"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*Oddeus*' Partner meldet sich.
|
||||
|
||||
**Partner**: Ich habe letzthin was änliches gesehen, aber irgendwie verdreht.
|
||||
"
|
||||
|
||||
-- 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:
|
||||
|
||||
Statement
|
||||
"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."
|
||||
(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`
|
||||
brauchen. Das funktioniert genau gleich, aussert dass dann die beiden Goals 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! Verwendende `have` und `suffices` einfach nach gutdünken."
|
||||
suffices g : ¬ B
|
||||
Hint "**Robo**: Also hier beendest du den Beweis angenommen {g} sei wahr."
|
||||
contradiction
|
||||
Hint "**Robo**: Und hier beweist du das Zwischenresultat."
|
||||
apply h
|
||||
assumption
|
||||
|
||||
NewTactic «suffices»
|
||||
DisabledTactic «have»
|
||||
|
||||
Conclusion "*Oddeus* nimmt den Brief, schaut ihn an und, rollt ihn zusammen.
|
||||
|
||||
**Oddeus**: Ich verstehe meine Schwester nie. Kommt, vielleicht könnt ihr mir helfen.
|
||||
|
||||
Und er führt euch durch seinen Rosengarten."
|
||||
@@ -0,0 +1,65 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
import Mathlib
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 3
|
||||
|
||||
Title "Per Widerspruch"
|
||||
|
||||
Introduction
|
||||
"**Oddeus**: Ich verstehe *Evenine* einfach nicht. Ich will euch auch gleich zeigen,
|
||||
was sie mir letzthin geschrieben hat, aber zuerst schaut einmal unseren
|
||||
wunderschönen Absurda-Tempel an!
|
||||
|
||||
Damit kommt ihr vor einen sehr hohen Turm, der ausschliesslich aus Dornenranken gewachsen
|
||||
scheint.
|
||||
|
||||
**Oddeus**: Versteht ihr, was hier über dem Eingang steht?
|
||||
"
|
||||
|
||||
-- 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 heisst häufig, dass du einen Widerspruchsbeweis führen
|
||||
möchtest.
|
||||
|
||||
**Du**: Und wie mach ich das? Mit `contradiction`?
|
||||
|
||||
**Robo**: Mit `by_contra h` fängst du einen an. Mit `contradiction` schliesst du ihn dann
|
||||
später ab."
|
||||
by_contra h
|
||||
Hint "**Robo**: Jetzt hast du also eine Annahme `{h} : ¬ {A}`, und damit musst du einen
|
||||
Widerspruch herbeileiten.
|
||||
|
||||
Ein Methode ist, dass du jetzt mit `suffices` sagts, zu was du denn gerne den Widerspruch
|
||||
haben möchtest, zum Beispiel `suffices k : B`
|
||||
"
|
||||
suffices k : B
|
||||
Hint "**Du**: Ah und jetzt kann ich einfach sagen dass sich die Anahmen `{B}` und `¬{B}`
|
||||
widersprechen."
|
||||
contradiction
|
||||
Hint "**Robo**: Und jetzt kannst du noch das Ergebnis zeigen, das zu einem Widerspruch
|
||||
geführt hat."
|
||||
apply g
|
||||
assumption
|
||||
|
||||
NewTactic by_contra
|
||||
|
||||
Conclusion "**Oddeus**: Sehr gut, kommt mit hinein!"
|
||||
@@ -0,0 +1,51 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
import Mathlib
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 4
|
||||
|
||||
Title "Per Widerspruch"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*Oddeus* Geht zu einem Regal mit vielen Dokumenten und beginnt zu suchen.
|
||||
|
||||
**Oddeus**: Ich hab's gleich. Hier ist eine Notiz meiner Gelehrter, die mir
|
||||
mit solchen kryptischen Nachrichten helfen wollten.
|
||||
|
||||
Auf dem Pergament steht das ein Lemma mit dem Namen `not_imp_not`:
|
||||
"
|
||||
|
||||
Statement not_imp_not (A B : Prop) : A → B ↔ (¬ B → ¬ A) := by
|
||||
Hint "**Du**: Ich glaube, dafür kenn ich das meiste schon."
|
||||
Hint (hidden := true) "**Robo**: Fang doch mal mit `constructor` an."
|
||||
constructor
|
||||
intro h b
|
||||
by_contra a
|
||||
Hint "**Robo**: Zur Erinnerung, hier würde ich 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 Widerspruch 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
|
||||
|
||||
Conclusion "**Du**: Und wie hilft uns das jetzt, was steht denn in dem Brief?"
|
||||
@@ -0,0 +1,70 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 5
|
||||
|
||||
Title "Kontraposition"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*Oddeus* reicht euch das Papier.
|
||||
|
||||
**Du**: Da steht etwas über `contrapose` hier…
|
||||
|
||||
**Oddeus**: Das ist doch klar eine Aggression uns gegenüber!
|
||||
|
||||
**Robo**: Wartet mal, vielleicht wollte euch eure Schwester einfach von ihren neuen
|
||||
Endeckungen zeigen. Schaut, darunter ist eine Aufgabe.
|
||||
"
|
||||
|
||||
-- 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 "**Oddeus**: Wie soll das den gehen?
|
||||
|
||||
**Robo**: `contrapose` benutzt das Lemma eurer Gelehrter, `not_imp_not`. Also es wandelt
|
||||
ein Goal `A → B` zu `¬B → ¬A ` um.
|
||||
|
||||
**Du**: Aber das Goal ist doch gar keine Implikation?
|
||||
|
||||
**Robo**: Mit `revert {h}` kannst du die Annahme `{h}` als Implikationsannahme ins Goal
|
||||
schieben."
|
||||
revert h
|
||||
Hint "*Oddeus*: Ob man jetzt wohl dieses `contrapose` benutzen kann?"
|
||||
contrapose
|
||||
Hint (hidden := true) "**Du**: Warte mal, jetzt kann man wohl `even_iff_not_odd` verwenden…"
|
||||
rw [← even_iff_not_odd]
|
||||
rw [← even_iff_not_odd]
|
||||
Hint "**Robo**: Und den Rest hast du bei *Evenine* als Lemma gezeigt!"
|
||||
apply even_square
|
||||
|
||||
NewTactic contrapose
|
||||
DisabledTactic by_contra
|
||||
|
||||
Conclusion "**Oddeus**: Ah ich sehe, die Aussage ist, dass wir das nur zusammen lösen konnten.
|
||||
Ich danke euch, darauf wäre ich nie gekommen."
|
||||
@@ -0,0 +1,56 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Contradiction"
|
||||
Level 6
|
||||
|
||||
Title "Contradiction"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du**: Sag mal Robo, das hätte ich aber auch als Widerspruch anstatt Kontraposition
|
||||
beweisen können?
|
||||
|
||||
**Robo**: Klar. `contrapose` ist eine Kontraposition, `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 "**Robo**: Fang diesmal mit `by_contra g` an!"
|
||||
by_contra g
|
||||
Hint "**Robo**: Jetzt würde ich einen Widerspruch zu `Odd (n ^ 2)` führen."
|
||||
Hint "**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 nochmals ein Überblick, was wir jetzt alles auf diesem
|
||||
Mond gelernt haben:
|
||||
|
||||
| | Taktik | Beispiel |
|
||||
|:------|:----------------|:-------------------------------------------------------|
|
||||
| 177 | `have` | Zwischenresultat annehmen. |
|
||||
| 18 | `suffices` | Zwischenresultat annehmen. |
|
||||
| 19 | `by_contra` | Widerspruch. (startet einen Widerspruch) |
|
||||
| *3* | `contradiction` | *(Schliesst einen Widerspruchsbeweis)* |
|
||||
| 20 | `contrapose` | Kontraposition. |
|
||||
| *9* | `revert` | Nützlich um danach `contrapose` anzuwenden. |
|
||||
"
|
||||
@@ -0,0 +1,24 @@
|
||||
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
|
||||
import Adam.Levels.Function.L11_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.
|
||||
"
|
||||
@@ -0,0 +1,63 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
use (fun x ↦ x - 1)
|
||||
simp
|
||||
|
||||
Hint : ∃ f : ℤ → ℤ, ∀ x, f x < x =>
|
||||
"
|
||||
**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.
|
||||
"
|
||||
|
||||
HiddenHint : ∃ f : ℕ → ℤ, ∀ x, f x < x =>
|
||||
"
|
||||
**Du**: Ja aber was mach ich damit?
|
||||
|
||||
**Robo**: Wie immer gehst du ein `∃` mit `use …` an.
|
||||
"
|
||||
|
||||
-- TODO: Why does this not show?
|
||||
HiddenHint : ∀ (x : ℤ), (fun (y : ℤ) => y - 1) x < x =>
|
||||
"**Du**: Zu was sich das wohl vereinfacht?"
|
||||
|
||||
HiddenHint (x : ℤ) : (fun y => y - 1) x < x =>
|
||||
"**Du**: Zu was sich das wohl vereinfacht?"
|
||||
|
||||
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.
|
||||
"
|
||||
@@ -0,0 +1,82 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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:
|
||||
"
|
||||
|
||||
def f (x : ℤ) : ℤ := (x + 4)
|
||||
|
||||
Statement "" (x : ℤ) : ∃ (g : ℤ → ℤ), (g ∘ f) x = x + 1 := by
|
||||
let g := fun (x : ℤ) ↦ x - 3
|
||||
use g
|
||||
simp
|
||||
unfold f
|
||||
ring
|
||||
|
||||
NewTactic «let»
|
||||
NewLemma Function.comp_apply
|
||||
|
||||
Hint (x : ℤ) : ∃ g, (g ∘ f) x = x + 1 =>
|
||||
"**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.
|
||||
"
|
||||
|
||||
-- TODO: Make some hints work here
|
||||
Hint (x : ℤ) : ((fun (x : ℤ) ↦ x - 3) ∘ f) x = x + 1 =>
|
||||
"**Robo**: Manchmal must du nachhelfen und Funktionen mit `unfold f` öffnen, manchmal nicht.
|
||||
Um erlich zu sein, sagt mein Programm nicht genau wann man das machen muss…"
|
||||
|
||||
-- TODO : Make this work
|
||||
Hint (x : ℤ) (g := (fun (x : ℤ) ↦ x - 3)) : (g ∘ f) x = x + 1 =>
|
||||
"**Robo**: `(g ∘ f) x` ist per Definition `g (f x)`, aber mit
|
||||
`rw [Function.comp_apply]` kann man das explizit umschreiben, aber `simp` kennt das
|
||||
Lemma auch."
|
||||
|
||||
Hint (x : ℤ) : f x - 3 = x + 1 =>
|
||||
"**Robo**: Manchmal must du nachhelfen und Definitionen mit `unfold f` öffnen, mamchmal klappts
|
||||
ohne.
|
||||
Um erlich zu sein, sagt mein Programm nicht genau wann man das machen muss…"
|
||||
|
||||
-- TODO: Block simp-Lemma
|
||||
|
||||
Conclusion "**Du**: Dann verstehst du etwas Mathe?
|
||||
|
||||
**Robo**: Ich hatte ja keine Ahnung ob die generierte Aufgabe beweisbar ist…
|
||||
|
||||
Und damit erreicht ihr den Hügel mit der Bibliothek."
|
||||
@@ -0,0 +1,177 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
funext x
|
||||
simp_rw [Function.comp_apply]
|
||||
unfold g
|
||||
by_cases 0 ≤ x
|
||||
have h' : 0 ≤ f x
|
||||
unfold f
|
||||
linarith
|
||||
rw [if_pos h', if_pos h]
|
||||
unfold f
|
||||
ring
|
||||
have h' : ¬ (0 ≤ f x)
|
||||
unfold f
|
||||
linarith
|
||||
rw [if_neg h, if_neg h']
|
||||
unfold f
|
||||
ring
|
||||
|
||||
NewTactic funext by_cases simp_rw linarith
|
||||
|
||||
NewLemma not_le if_pos if_neg
|
||||
|
||||
|
||||
Hint : f ∘ g = g ∘ f =>
|
||||
"
|
||||
**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.
|
||||
"
|
||||
|
||||
-- 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 =>
|
||||
"
|
||||
**Du**: Ah und jetzt kann ich erst einmal `(g ∘ f) {x}` zu `g (f {x})` umschreiben?
|
||||
|
||||
**Robo**: Mit `simp_rw` geht das übrigens schneller.
|
||||
|
||||
**Robo**: Und danach willst du eien 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.
|
||||
"
|
||||
|
||||
Hint (x : ℚ) (h : 0 ≤ x) : f (g x) = g (f x) =>
|
||||
"
|
||||
**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₂ : _`?
|
||||
"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,38 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
intro a b
|
||||
simp
|
||||
|
||||
NewDefinition Injective
|
||||
|
||||
Hint : Injective (fun (n : ℤ) ↦ n + 3) =>
|
||||
"**Robo**: `Injective` ist als `∀ \{a b : U}, f a = f b → a = b`
|
||||
definiert, also kannst du mit `intro` anfangen.
|
||||
"
|
||||
|
||||
Hint (a b : ℤ) : (fun n => n + 3) a = (fun n => n + 3) b → a = b =>
|
||||
"**Du**: Kann man das wohl vereinfachen?"
|
||||
|
||||
Hint (a b : ℤ) (hab : (fun n => n + 3) a = (fun n => n + 3) b) : a = b =>
|
||||
"**Robot**: Jetzt musst du wohl `{hab}` vereinfachen."
|
||||
|
||||
Conclusion "**Du** Woa das war ja einfach!"
|
||||
@@ -0,0 +1,79 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
apply StrictMono.injective
|
||||
apply StrictMono.add
|
||||
apply Odd.strictMono_pow
|
||||
trivial
|
||||
intro a b
|
||||
simp
|
||||
|
||||
NewDefinition Injective
|
||||
NewLemma StrictMono.injective StrictMono.add Odd.strictMono_pow
|
||||
|
||||
|
||||
Hint : Injective fun (n : ℤ) => n ^ 3 + (n + 3) =>
|
||||
"**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."
|
||||
|
||||
HiddenHint : Injective fun (n : ℤ) => n ^ 3 + (n + 3) =>
|
||||
"**Robo**: `apply` ist wonach du suchst."
|
||||
|
||||
Hint : StrictMono fun (n : ℤ) => n ^ 3 + (n + 3) =>
|
||||
"**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!"
|
||||
|
||||
Hint : StrictMono fun (x : ℤ) => x ^ 3 =>
|
||||
"**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…"
|
||||
|
||||
HiddenHint : Odd 3 =>
|
||||
"**Du**: Ist das nicht ne Trivialität? Warte mal!"
|
||||
|
||||
Hint : StrictMono fun (x : ℤ) => x + 3 =>
|
||||
"**Du**: Ha! Und dieser Teil funktioniert sicher gleich wie Injektivität vorhin!"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hint (a b : ℤ) : a ^ 3 + (a + 3) = b ^ 3 + (b + 3) → a = b =>
|
||||
"**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!
|
||||
"
|
||||
|
||||
Hint (a b : ℤ) (h : a ^ 3 + (a + 3) = b ^ 3 + (b + 3)) : a = b =>
|
||||
"**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!
|
||||
"
|
||||
|
||||
Conclusion "**Du**: Danke vielmals!
|
||||
|
||||
Und damit lässt das Wesen mitten im Gang stehen, wo es weiter über Injektivität nachdenkt."
|
||||
@@ -0,0 +1,76 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
push_neg
|
||||
use 2
|
||||
use 3
|
||||
simp
|
||||
|
||||
Hint : ¬ (Injective (f + f)) =>
|
||||
"
|
||||
**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…
|
||||
"
|
||||
|
||||
HiddenHint : ¬ (Injective (f + f)) =>
|
||||
"
|
||||
**Robo**: Das war `push_neg`.
|
||||
"
|
||||
|
||||
Hint : ∃ a b, (f + f) a = (f + f) b ∧ a ≠ b =>
|
||||
"**Du** Jetzt muss ich einfach ein Gegenbeispiel nennen, oder?
|
||||
|
||||
**Robo** Genau! Welche beiden Zahlen möchtest du denn verwenden?"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,37 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
intro y
|
||||
use y-1
|
||||
simp
|
||||
|
||||
NewDefinition Surjective
|
||||
|
||||
Hint : Surjective (fun (n : ℤ) ↦ n + 1) =>
|
||||
"**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!"
|
||||
|
||||
Conclusion
|
||||
"Der Gelehrte händigt euch schmunzelnd das Buch aus."
|
||||
@@ -0,0 +1,38 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
unfold Bijective
|
||||
constructor
|
||||
intro a b
|
||||
simp
|
||||
intro y
|
||||
use y-1
|
||||
simp
|
||||
|
||||
Hint : Bijective (fun (n : ℤ) ↦ n + 1) =>
|
||||
"**Robo** *(flüsternd)*: `Bijectve f` ist als `Injective f ∧ Surjective f` definiert.
|
||||
|
||||
**Du**: Dann ist das ja ganz simpel!
|
||||
"
|
||||
|
||||
Conclusion
|
||||
"Zufrieden drückt euch der Gelehrte eine neue Fackel in die Hand und
|
||||
zeigt euch den Weg nach draußen."
|
||||
|
||||
NewDefinition Bijective
|
||||
@@ -0,0 +1,61 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 9
|
||||
|
||||
Title "Inverse"
|
||||
|
||||
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 bijective_iff_has_inverse "" {A B : Type} (f : A → B) :
|
||||
Bijective f ↔ ∃ g, LeftInverse g f ∧ RightInverse g f := by
|
||||
constructor
|
||||
intro h
|
||||
use fun x => (h.2 x).choose
|
||||
constructor
|
||||
· intro x
|
||||
simp
|
||||
apply h.1
|
||||
apply Exists.choose_spec (h.2 (f x))
|
||||
· intro x
|
||||
simp
|
||||
apply Exists.choose_spec (h.2 x)
|
||||
intro ⟨g, h₁, h₂⟩
|
||||
constructor
|
||||
· intro a b hab
|
||||
have h : g (f a) = g (f b)
|
||||
· apply congrArg
|
||||
assumption
|
||||
rw [h₁, h₁] at h
|
||||
assumption
|
||||
· intro x
|
||||
use g x
|
||||
rw [h₂]
|
||||
|
||||
NewDefinition LeftInverse RightInverse
|
||||
NewLemma Exists.choose Exists.choose_spec congrArg congrFun
|
||||
DisabledLemma Function.bijective_iff_has_inverse
|
||||
|
||||
Hint {A B : Type} (f : A → B) : Bijective f ↔ ∃ g, LeftInverse g f ∧ RightInverse g f =>
|
||||
"**Du**: Nah da sagt mir so manches nichts, aber ich kann ja mal mit dem `↔` anfangen, das kenn
|
||||
ich ja schon."
|
||||
|
||||
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?"
|
||||
@@ -0,0 +1,93 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Function"
|
||||
Level 10
|
||||
|
||||
Title "Inverse"
|
||||
|
||||
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
|
||||
set_option pp.rawOnError true
|
||||
Statement bijective_iff_has_inverse "" {A B : Type} (f : A → B) :
|
||||
Bijective f ↔ ∃ g, LeftInverse g f ∧ RightInverse g f := by
|
||||
Branch
|
||||
exfalso
|
||||
Hint "Das war eine blöde Idee
|
||||
dd
|
||||
|
||||
ddds
|
||||
"
|
||||
Hint (hidden := true) "constructor"
|
||||
constructor
|
||||
Hint "intro h" -- does not show
|
||||
intro h
|
||||
Hint "rcases h with ⟨h₁, h₂⟩" -- shows too late: 1, 2 after
|
||||
rcases h with ⟨h₁, h₂⟩
|
||||
Hint (strict := true) "let g := fun x => (h₂ x).choose" -- shows correct + 1 after
|
||||
let g := fun x => (h₂ x).choose
|
||||
Hint "use g"
|
||||
use g
|
||||
Hint "constructor" -- does not show
|
||||
constructor
|
||||
Hint "intro x" -- does not show
|
||||
intro x
|
||||
Hint "simp" -- Error updating: Error fetching goals: Rpc error: InternalError: unknown universe metavariable '?_uniq.286465'. Try again.
|
||||
simp
|
||||
Hint "apply h₁"
|
||||
apply h₁
|
||||
Hint "apply Exists.choose_spec (h₂ (f x))"
|
||||
apply Exists.choose_spec (h₂ (f x))
|
||||
Hint "intro y" -- Error updating: Error fetching goals: Rpc error: InternalError: unknown universe metavariable '?_uniq.286465'. Try again.
|
||||
intro y
|
||||
Hint "simp"
|
||||
simp
|
||||
Hint "apply Exists.choose_spec (h₂ y)"
|
||||
apply Exists.choose_spec (h₂ y)
|
||||
Hint "intro ⟨g, h₁, h₂⟩"
|
||||
intro ⟨g, h₁, h₂⟩
|
||||
Hint "constructor"
|
||||
constructor
|
||||
Hint "intro a b hab"
|
||||
intro a b hab
|
||||
Hint (strict := true) "have h : g (f a) = g (f b)"
|
||||
have h : g (f a) = g (f b)
|
||||
Hint "apply congrArg"
|
||||
apply congrArg
|
||||
Hint "assumption"
|
||||
assumption
|
||||
Hint "rw [h₁, h₁] at h"
|
||||
rw [h₁, h₁] at h
|
||||
Hint "assumption"
|
||||
assumption
|
||||
Hint "intro x"
|
||||
intro x
|
||||
Hint "use g x"
|
||||
use g x
|
||||
Hint "rw [h₂]"
|
||||
rw [h₂]
|
||||
|
||||
-- NewDefinition LeftInverse RightInverse
|
||||
-- NewLemma Exists.choose Exists.choose_spec congrArg congrFun
|
||||
-- DisabledLemma Function.bijective_iff_has_inverse
|
||||
|
||||
Hint (A B: Type) (f : A → B) (h : Bijective f) :
|
||||
(∃ g, LeftInverse g f ∧ RightInverse g f) → Bijective f =>
|
||||
"Test"
|
||||
|
||||
Conclusion
|
||||
"Endlich entkommt ihr dem Tempel.
|
||||
|
||||
**Robo**: Da würden mich keine zehn Pferde nochmals hineinbringen!
|
||||
|
||||
**Du**: Von wegen Pferden, wie viele PS hat eigentlich unser Raumschiff?"
|
||||
@@ -0,0 +1,34 @@
|
||||
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 "Aussagenlogik 2"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Zurück im Raumschiff macht ihr euch auf den Weg zum einem der beiden Monde, die ebenfalls
|
||||
beide bewohnt zu sein scheinen.
|
||||
|
||||
**Du**: Sag mal Robo, Königin *Logisindes* hat under anderem von Implikationen gesprochen,
|
||||
aber niemand von den Einwohnern wusste was davon...
|
||||
|
||||
**Robo**: Auf dem Mond *Implis* den wir gerade ansteuern können sie uns vielleicht mehr
|
||||
erzählen…
|
||||
|
||||
Und damit leitet Robo den Landeanflug ein. Implis scheint ein riesiger Tagbau zu sein auf
|
||||
dem nach allem möglichen gegraben wird. Überall seht ihr Förderbänder kreuz und quer.
|
||||
|
||||
Das Operationsteam begrüsst euch freundlich und lädt zum Essen im Kommandoturm.
|
||||
"
|
||||
@@ -0,0 +1,34 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Tauto
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 1
|
||||
|
||||
Title "Intro"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Operationsleiter**: Sagt mal, könnt ihr mir hier weiterhelfen?
|
||||
"
|
||||
|
||||
Statement (A B : Prop) (hb : B) : A → (A ∧ B) := by
|
||||
Hint "**Du**: Einen Moment, das ist eine Implikation (`\\to`),
|
||||
also `A` impliziert `A und B`, soweit so gut, also eine Tautologie.
|
||||
|
||||
**Robo**: Du hast recht, eigentlich könnte man `tauto` sagen,
|
||||
aber das scheinen die hier tauto nicht zu verstehen.
|
||||
Implikationen kannst du aber mit `intro h` angehen."
|
||||
intro hA
|
||||
Hint "**Du**: Jetzt habe ich also angenommen, dass `A` wahr ist und muss `A ∧ B` zeigen,
|
||||
das kennen wir ja schon."
|
||||
constructor
|
||||
assumption
|
||||
assumption
|
||||
|
||||
Conclusion "Der Operationsleiter nickt bedacht."
|
||||
|
||||
NewTactic intro
|
||||
DisabledTactic tauto
|
||||
@@ -0,0 +1,30 @@
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 2
|
||||
|
||||
Title "Revert"
|
||||
|
||||
Introduction
|
||||
"Jemand aus der Gruppe gibt dir ein Blatt Papier mit einer Zeile Text:"
|
||||
|
||||
Statement (A B : Prop) (ha : A) (h : A → B) : B := by
|
||||
Hint "**Robo**: Mit `revert {ha}` kann man die Annahme `ha` als
|
||||
Implikationsprämisse vorne ans Goal anhängen, dann ist das Goal `{A} → {B}`.
|
||||
|
||||
**Du**: Das wirkt etwas unnatürlich.
|
||||
|
||||
**Robo**: Schon, ja. Aber als Tool kann das manchmal nützlich sein."
|
||||
revert ha
|
||||
assumption
|
||||
|
||||
Conclusion "**Du**: Aber das müsste doch auch anders gehen, ich hätte jetzt intuitiv
|
||||
die Implikation $A \\Rightarrow B$ angewendet und behauptet, dass es genügt $A$ zu zeigen…
|
||||
|
||||
Daraufhin lächelt der Fragende nur vorahnend."
|
||||
|
||||
NewTactic revert
|
||||
DisabledTactic tauto
|
||||
@@ -0,0 +1,35 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 3
|
||||
|
||||
Title "Apply"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Sein Kollege zieht eine Linie unter deinen Beweis, schreibt ein durchgestrichenes ~`revert`~
|
||||
hin und gibt dir das Blatt wieder.
|
||||
"
|
||||
|
||||
Statement (A B : Prop) (hA : A) (h : A → B) : B := by
|
||||
Hint "**Robo**: Da hat er natürlich recht, normalerweise ist es viel schöner mit
|
||||
`apply {h}` die Implikation anzuwenden."
|
||||
apply h
|
||||
Hint "**Du**: Und jetzt genügt es also `A` zu zeigen."
|
||||
assumption
|
||||
|
||||
Conclusion "**Robo** Übrigens mit `apply LEMMA` kannst auch jedes Lemma anwenden, dessen
|
||||
Aussage mit dem Goal übereinstimmt.
|
||||
|
||||
Die beiden Fragenden schauen das Blatt an und murmeln zustimmend."
|
||||
|
||||
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}$$
|
||||
@@ -0,0 +1,38 @@
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 4
|
||||
|
||||
Title "Implikation"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du** *(zu Robo)*: Testen die uns eigentlich hier?
|
||||
|
||||
Ein älteres Gruppenmitglied schiebt ein Tablet über den Tisch und beginnt in leiser
|
||||
Stimme zu erklären.
|
||||
|
||||
**Mitarbeiterin**: Eines unserer Kontrollelemente ist kaputt und ist verwirrt, wo Sachen hinkommen.
|
||||
Gesteuert werden diese über Panels, und hier hab ich das Übungspanel, mit dem wir neue
|
||||
Ingeneure ausbilden:
|
||||
"
|
||||
|
||||
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 "**Du**: Ich hab das Konzept verstanden.
|
||||
|
||||
Die Mitarbeiterin ist zufrieden und wünscht euch Glück auf der Mission."
|
||||
|
||||
DisabledTactic tauto
|
||||
@@ -0,0 +1,53 @@
|
||||
import Adam.Metadata
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 5
|
||||
|
||||
Title "Implikation"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Selbstsicher folgt ihr den Anweisungen und geht nach draußen zum
|
||||
defekten Kontrollelement. Dieses zeigt ein kompliziertes Diagram:
|
||||
$$
|
||||
\\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**: Und 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
|
||||
"Mit einem lauten Ratteln springen die Förderbänder wieder an.
|
||||
|
||||
**Operationsleiter**: Vielen Dank euch! Kommt ich geb euch eine Führung und stell euch den
|
||||
Technikern hier vor."
|
||||
|
||||
DisabledTactic tauto
|
||||
|
||||
-- https://www.jmilne.org/not/Mamscd.pdf
|
||||
@@ -0,0 +1,46 @@
|
||||
import Adam.Metadata
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 6
|
||||
|
||||
Title "Genau dann wenn"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Als erstes kommt ihr in einen kleinen Raum mit ganz vielen Bildschirmen.
|
||||
|
||||
Ein junges Wesen dreht sich auf dem Stuhl um, und sagt:
|
||||
|
||||
**Mitarbeiter**: Oh hallo! Schaut euch mal das hier an!
|
||||
"
|
||||
|
||||
Statement (A B : Prop) (mp : A → B) (mpr : B → A) : A ↔ B := by
|
||||
Hint "**Robo**: Das ist ein genau-dann-wenn Pfeil: `\\iff`. Er besteht aus zwei Teilen:
|
||||
`A ↔ B` ist als `⟨A → B, B → A⟩` definiert.
|
||||
|
||||
**Du**: Also ganz ähnlich wie das UND, `A ∧ B`?
|
||||
|
||||
**Robo**: Genau. Entsprechend kannst du hier auch mit `constructor` anfangen."
|
||||
constructor
|
||||
Hint "**Du**: Ah und die beiden hab ich schon in den Annahmen."
|
||||
assumption
|
||||
assumption
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Robo**: Übrigens, bei `(h : A ∧ B)` haben die beiden Teile `h.left` und `h.right` geheissen,
|
||||
hier bei `(h : A ↔ B)` heissen sie `h.mp` und `h.mpr`.
|
||||
|
||||
**Du**: Also `h.mp` ist `A → B`? Wieso `mp`?
|
||||
|
||||
**Operationsleiter**: \"Modulo Ponens\" ist ein lokaler Begriff hier,
|
||||
aber das ist doch nicht wichtig.
|
||||
|
||||
**Robo**: Und das \"r\" in `mpr` stünde für \"reverse\" weil's die Rückrichtung ist.
|
||||
"
|
||||
|
||||
NewTactic constructor
|
||||
DisabledTactic tauto rw
|
||||
|
||||
-- TODO : `case mpr =>` ist mathematisch noch sinnvoll.
|
||||
@@ -0,0 +1,47 @@
|
||||
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
|
||||
"
|
||||
Als nächstes begenet ihr jemandem im Flur.
|
||||
|
||||
Dieser hat schon von euch gehört und will sofort wissen, ob ihr ihm helfen könnt:
|
||||
"
|
||||
|
||||
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 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 `←` vor den Namen, also `rw [← hₓ]`."
|
||||
Branch
|
||||
rw [← h₃]
|
||||
Hint "**Du**: Ehm, das ist verkehrt.
|
||||
|
||||
**Robo**: Andersrum wär's besser gewesen, aber wenn du jetzt einfach weitermachst bis du
|
||||
sowas wie `A ↔ A` kriegst, kann `rfl` das beweisen.
|
||||
|
||||
**Robo: Da fällt mir ein, `rw` versucht automatisch `rfl` am Ende. Das heisst, du musst
|
||||
das nicht einmal mehr schreiben."
|
||||
rw [h₂]
|
||||
rw [←h₂]
|
||||
assumption
|
||||
|
||||
Conclusion "Ihr geht weiter und der Operationsleiter zeigt euch die Küche."
|
||||
|
||||
NewTactic rw assumption
|
||||
DisabledTactic tauto
|
||||
-- NewLemma Iff.symm
|
||||
@@ -0,0 +1,44 @@
|
||||
import Adam.Metadata
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 8
|
||||
|
||||
Title "Genau dann wenn"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Der Koch kommt erfreut hinter einem grossen Topf hervor.
|
||||
|
||||
**Koch**: Sagt mal, gestern hat mir jemand was erzählt und es will einfach nicht aus
|
||||
meinem Kopf…
|
||||
"
|
||||
|
||||
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**: Weiss ich ja!"
|
||||
apply g
|
||||
Hint "**Robo**: …und du kannst die Implikation `{A} → {B}` genau gleich mit
|
||||
`apply {h}.mp` anwenden.
|
||||
|
||||
**Du**: Aber ich könnte hier auch `rw [← h]` sagen, oder?
|
||||
|
||||
**Robo**: Klar, aber offenbar versteht der Koch das `rw` nicht.
|
||||
"
|
||||
apply h.mp
|
||||
assumption
|
||||
|
||||
Conclusion "**Koch**: Danke vielmals! Jetzt muss ich aber schauen dass die Suppe nicht verkocht!
|
||||
|
||||
Und er eilt davon."
|
||||
|
||||
NewTactic apply assumption
|
||||
DisabledTactic tauto rw
|
||||
@@ -0,0 +1,53 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 9
|
||||
|
||||
Title "Genau dann wenn"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Noch während der Koch wieder zu seiner Suppe geht, kommt sein erster Gehilfe hervor.
|
||||
|
||||
**Gehilfe**: Ich hab gestern noch was anderes gehört, könnt ihr mir da auch helfen?
|
||||
Aber ich versteh nicht ganz was ihr meinem Chef erklärt habt.
|
||||
"
|
||||
|
||||
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 kenn `rw [h]` und `apply h.mp`, aber das will er wohl nicht hören.
|
||||
|
||||
**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` benützen, aber der
|
||||
Gehilfe will, dass du zwingend eine dritte Variante benützt. Geh doch einen
|
||||
Schritt zurück so dass das Goal `A → B` ist."
|
||||
rcases h with ⟨mp, mpr⟩
|
||||
Hint (hidden := true) "**Du**: Ah und jetzt ist das Resultat in den Annahmen."
|
||||
assumption
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Gehilfe**: Ah danke! Und jetzt versteh ich auch die Zusammenhänge!
|
||||
"
|
||||
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
|
||||
@@ -0,0 +1,49 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 10
|
||||
|
||||
Title "Lemmas"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Ihr setzt euch hin und der Gehilfe bringt euch allen Suppe. Neben euch sitzt eine Mechanikerin
|
||||
über ihre Suppe geneigt.
|
||||
|
||||
**Mechanikerin**: Sagt mal, ich hab unten über folgendes tiefgründiges Problem nachgedacht:
|
||||
"
|
||||
|
||||
Statement (A : Prop) : ¬A ∨ A := by
|
||||
Hint "**Du**: Das scheint ziemlich offensichtlich.
|
||||
|
||||
**Robo**: Ich glaube, sie will eine detailierte Antwort. Ich kenne ein Lemma
|
||||
`not_or_of_imp`, was sagt `(A → B) → ¬ A ∨ B`. Da das Resultat des Lemmas mit
|
||||
deinem Goal übreinstimmt, kannst du es mit `apply not_or_of_imp` anwenden."
|
||||
Branch
|
||||
right
|
||||
Hint "**Du**: Und jetzt?
|
||||
|
||||
**Robo**: `right/left` funktioniert hier nicht, da du nicht weisst ob `A` wahr oder falsch
|
||||
ist."
|
||||
Branch
|
||||
left
|
||||
Hint "**Du**: Und jetzt?
|
||||
|
||||
**Robo**: `right/left` funktioniert hier nicht, da du nicht weisst ob `A` wahr oder falsch
|
||||
ist."
|
||||
apply not_or_of_imp
|
||||
Hint (hidden := true) "**Robo**: Ich würd wieder mit `intro` weitermachen."
|
||||
intro
|
||||
assumption
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Mechanikerin**: Danke vielmals, jetzt bin ich schon viel ruhiger.
|
||||
"
|
||||
|
||||
NewLemma not_or_of_imp
|
||||
DisabledTactic tauto
|
||||
@@ -0,0 +1,38 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 11
|
||||
|
||||
Title "by_cases"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du**: Sagt mal, hätte ich da nicht auch einfach zwei Fälle anschauen können:
|
||||
Wenn `A` wahr ist, beweis ich die rechte Seite, sonst die Linke.
|
||||
|
||||
**Robo**: Tatsächlich, `by_cases h : A` würde genau das machen!
|
||||
"
|
||||
|
||||
Statement (A : Prop) : ¬A ∨ A := by
|
||||
Hint (hidden := true) "**Du**: Wie?
|
||||
|
||||
**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
|
||||
Hint "**Du**: "
|
||||
right
|
||||
assumption
|
||||
left
|
||||
assumption
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Du**: Das kann noch ganz nützlich sein.
|
||||
"
|
||||
|
||||
NewTactic by_cases
|
||||
DisabledTactic tauto
|
||||
@@ -0,0 +1,50 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Cases
|
||||
import Mathlib.Logic.Basic
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 12
|
||||
|
||||
Title "Lemmas"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Der Arbeitskollegin der Mechanikerin, der die ganze Zeit gespannt zugehört hat, dreht sich zu
|
||||
euch.
|
||||
|
||||
Er ist offensichtlich interessiert and existierenden Resultaten zu sein, aber offenbar
|
||||
kann er nicht viel mit `apply` anfangen.
|
||||
|
||||
Er hat aber folgendes Resultat bereit:
|
||||
|
||||
```
|
||||
lemma not_not (A : Prop) : ¬¬A ↔ A
|
||||
```
|
||||
|
||||
und stellt euch folgende Frage:
|
||||
"
|
||||
|
||||
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 was anderes, also brauch ich das Lemma nochmals."
|
||||
rw [not_not]
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Du**: Ah und wir sind fertig…?
|
||||
|
||||
**Robo**: Ja, `rw` versucht immer anschliessend `rfl` aufzurufen, und das hat hier
|
||||
funktioniert.
|
||||
"
|
||||
|
||||
DisabledTactic tauto apply
|
||||
NewLemma not_not
|
||||
@@ -0,0 +1,77 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Implication"
|
||||
Level 13
|
||||
|
||||
Title "Zusammenfassung"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Operationsleiter**: Damit endet unsere Führung langsam. Bevor ihr weitergeht
|
||||
habe ich noch ein Problem, an dem ich mir die Zähne ausbeisse. Wir haben die
|
||||
Herleitung eines unserer Programme `imp_iff_not_or` verloren, und wissen nicht mehr
|
||||
ob es einwandfrei funktioniert.
|
||||
|
||||
**Du**: Nah gut, mal sehen. Robo, was hab ich denn alles hier gelernt?
|
||||
|
||||
**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**: Das sieht kompliziert aus…
|
||||
|
||||
**Robo** *(flüsternd)*: Ja, aber die Richtung kennst du ja schon also Lemma,
|
||||
wend doch einfach das 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 fangst du immer mit `intro` an."
|
||||
intro h
|
||||
intro ha
|
||||
Hint (hidden := true) "**Robo**: Ich wür mal die Annahme `h` mit `rcases` aufteilen."
|
||||
rcases h with h | h
|
||||
contradiction
|
||||
assumption
|
||||
|
||||
DisabledTactic tauto
|
||||
|
||||
Conclusion "**Operationsleiter**: Damit gehen unsere Wege auseinander. Da fällt mir ein, seit
|
||||
ihr auf dem Weg zu unserem Schwestermond?
|
||||
|
||||
**Du**: Könnten wir sein…
|
||||
|
||||
**Operationsleiter**: Ich hab hier einen Brief für *Evenine*, könntet ihr diesen mit euch führen?
|
||||
|
||||
**Du**: Klar! Robo, halt den mal.
|
||||
|
||||
Robo nimmt den Brief und lässt ihn irgendwo in seinem Innern verschwinden. Dabei bemerkt er
|
||||
den besorgten Blick des Operationsleiters.
|
||||
|
||||
**Robo**: Keine Angst, ich verdaue nichts!"
|
||||
@@ -0,0 +1,5 @@
|
||||
import Adam.Levels.Induction.L01_Induction
|
||||
|
||||
Game "Adam"
|
||||
World "Induction"
|
||||
Title "Übungen Induktions"
|
||||
@@ -0,0 +1,37 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,16 @@
|
||||
import Adam.Levels.Inequality.L01_LE
|
||||
import Adam.Levels.Inequality.L02_Pos
|
||||
import Adam.Levels.Inequality.L03_Linarith
|
||||
import Adam.Levels.Inequality.L04_Linarith
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Title "Ungleichung"
|
||||
|
||||
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.
|
||||
"
|
||||
@@ -0,0 +1,34 @@
|
||||
import Adam.Metadata
|
||||
|
||||
Game "Adam"
|
||||
World "Inequality"
|
||||
Level 1
|
||||
|
||||
Title "Kleinergleich"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*(Gesrpä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?"
|
||||
@@ -0,0 +1,53 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
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**: Und hier fang ich wohl am besten an wie ich das schon kenne."
|
||||
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
|
||||
|
||||
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."
|
||||
@@ -0,0 +1,26 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Linarith
|
||||
|
||||
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
|
||||
|
||||
Conclusion "**Du**: Naja so beeindruckend war das jetzt auch noch nicht."
|
||||
@@ -0,0 +1,29 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Linarith
|
||||
|
||||
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.
|
||||
|
||||
Und damit endet auch Deine Erinnerung und wer weiss was du anschließend gemacht hast…"
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,26 @@
|
||||
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!"
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
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."
|
||||
@@ -0,0 +1,44 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
|
||||
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."
|
||||
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 =>
|
||||
-- ""
|
||||
@@ -0,0 +1,71 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
import Adam.ToBePorted
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Lean"
|
||||
Level 3
|
||||
|
||||
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)]
|
||||
rfl
|
||||
|
||||
OnlyTactic rw rfl
|
||||
|
||||
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."
|
||||
@@ -0,0 +1,57 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib
|
||||
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
|
||||
|
||||
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.
|
||||
"
|
||||
@@ -0,0 +1,70 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
|
||||
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
|
||||
@@ -0,0 +1,23 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "Adam"
|
||||
World "Nat2"
|
||||
Level 3
|
||||
|
||||
Title "Primzahlen"
|
||||
|
||||
Introduction
|
||||
"
|
||||
TODO: Primzahl
|
||||
|
||||
"
|
||||
|
||||
Statement "" : True := by
|
||||
trivial
|
||||
|
||||
Conclusion
|
||||
"
|
||||
"
|
||||
|
||||
NewTactic ring
|
||||
@@ -0,0 +1,23 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "Adam"
|
||||
World "Nat2"
|
||||
Level 5
|
||||
|
||||
Title "Exists unique"
|
||||
|
||||
Introduction
|
||||
"
|
||||
TODO: Es existiert genau eine gerade Primzahl.
|
||||
|
||||
"
|
||||
|
||||
Statement "" : True := by
|
||||
trivial
|
||||
|
||||
Conclusion
|
||||
"
|
||||
"
|
||||
|
||||
NewTactic ring
|
||||
@@ -0,0 +1,61 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
-- 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
|
||||
@@ -0,0 +1 @@
|
||||
-- tauto is not implemented yet... duper?
|
||||
@@ -0,0 +1 @@
|
||||
-- not implemented yet
|
||||
@@ -0,0 +1,18 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
-- -- 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
|
||||
@@ -0,0 +1,25 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
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
|
||||
@@ -0,0 +1,41 @@
|
||||
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"
|
||||
@@ -0,0 +1,106 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Basic -- definiert `module`
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
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
|
||||
@@ -0,0 +1,59 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Pi -- definiert `Module ℚ (fin 2 → ℚ)`
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
import Mathlib.Tactic.FinCases
|
||||
|
||||
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
|
||||
@@ -0,0 +1,25 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.Pi -- definiert `Module ℚ (fin 2 → ℚ)`
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
import Mathlib.Tactic.FinCases
|
||||
|
||||
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
|
||||
@@ -0,0 +1,46 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
|
||||
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]
|
||||
@@ -0,0 +1,23 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
|
||||
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
|
||||
@@ -0,0 +1,39 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Data.Fin.VecNotation -- Importiert Matrix/Vektor-Notation
|
||||
--import Mathlib.LinearAlgebra.FinSupp -- contains `top_le_span_range_iff_forall_exists_fun`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
|
||||
Statement mem_span_of_mem
|
||||
"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
|
||||
@@ -0,0 +1,48 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Data.Fin.VecNotation -- Importiert Matrix/Vektor-Notation
|
||||
--import Mathlib.LinearAlgebra.FinSupp -- contains `top_le_span_range_iff_forall_exists_fun`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
import Mathlib.Tactic.LibrarySearch
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,43 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Data.Fin.VecNotation -- Importiert Matrix/Vektor-Notation
|
||||
--import Mathlib.LinearAlgebra.FinSupp -- contains `top_le_span_range_iff_forall_exists_fun`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
@@ -0,0 +1,91 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.LinearMap -- definiert `→ₗ`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Algebra.Module.LinearMap -- definiert `→ₗ`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Data.Fin.VecNotation
|
||||
-- import Mathlib.LinearAlgebra.Finsupp
|
||||
import Mathlib.Algebra.BigOperators.Basic -- default
|
||||
-- import Mathlib.LinearAlgebra.LinearIndependent
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,32 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,30 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Data.Fin.VecNotation -- Importiert Matrix/Vektor-Notation
|
||||
--import Mathlib.LinearAlgebra.FinSupp -- contains `top_le_span_range_iff_forall_exists_fun`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
@@ -0,0 +1,45 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic -- definiert `ℝ`
|
||||
import Mathlib.Data.Fin.VecNotation -- Importiert Matrix/Vektor-Notation
|
||||
--import Mathlib.LinearAlgebra.FinSupp -- contains `top_le_span_range_iff_forall_exists_fun`
|
||||
import Mathlib.Tactic.FinCases
|
||||
import Mathlib.Algebra.BigOperators.Finsupp -- default?
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Basic
|
||||
|
||||
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 }
|
||||
@@ -0,0 +1,33 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Basic
|
||||
|
||||
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,
|
||||
@@ -0,0 +1,26 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
@@ -0,0 +1,25 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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 }
|
||||
@@ -0,0 +1,78 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Algebra.Module.Submodule.Lattice
|
||||
import Mathlib.Data.Real.Basic
|
||||
import Mathlib.LinearAlgebra.Span
|
||||
|
||||
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,
|
||||
-- }
|
||||
@@ -0,0 +1,4 @@
|
||||
- `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.
|
||||
@@ -0,0 +1,2 @@
|
||||
import Adam.Levels.Numbers.L01_PNat
|
||||
import Adam.Levels.Numbers.L02_PNat
|
||||
@@ -0,0 +1,82 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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`, ...
|
||||
-- -/
|
||||
@@ -0,0 +1,24 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,27 @@
|
||||
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 "Prädikate"
|
||||
|
||||
Introduction "Eure Reise geht weiter zum zweiten Mond. Dieser ist etwas grösser und
|
||||
komplett mit buschartigen Pflanzen überwachsen. Der Landeanflug sit etwas kniffliger,
|
||||
aber offenbar kann Robo nicht nur Lean übersetzen, sondern auch mit maschineller Genauigkeit
|
||||
navigieren.
|
||||
|
||||
Ihr werdet sofort empfangen und man führt euch zur lokalen Machthaberin.
|
||||
Ihr kommt an verschiedensten riesigen Büschen vorbei, die offensichtlich innen Ausgehöhlt sind
|
||||
und so als Wände für Behausungen der Wesen hier dienen.
|
||||
|
||||
Man führt euch in einen der Büsche. Nun entdecksts du dass das Blätterdach künstlich verstärkt ist,
|
||||
offensichtlich um Regen abzuweisen.
|
||||
|
||||
Vor euch steht eine Frau, die euch als Machthabering *Evenine* vorgestellt wird."
|
||||
@@ -0,0 +1,36 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
--set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 1
|
||||
|
||||
Title "Natürliche Zahlen"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Evenine**: Willkommen Reisende! Wir leben hier in Einklang mit der Natur und allem natürlichen,
|
||||
so sagt mir, könnt ihr mit natürlichen Zahlen umgehen?
|
||||
"
|
||||
|
||||
Statement (x y : ℕ) : (x + y) ^ 2 = x ^ 2 + 2 * x * y + y ^ 2 := by
|
||||
Hint "**Du**: Das hab ich in der Schule gelernt, man rechnet das einfach aus,
|
||||
indem man die Terme umsortiert.
|
||||
|
||||
**Robo**: Behaupte doch mit `ring`, dass das so ist.
|
||||
|
||||
**Du**: Aber `ℕ` ist doch gar kein Ring?
|
||||
|
||||
**Robo**: `ring` funktioniert schon für Halbringe, aber sie heisst ring, weil sie auf
|
||||
(kommutativen) Ringen am besten funktioniert.
|
||||
"
|
||||
ring
|
||||
|
||||
Conclusion
|
||||
"
|
||||
*Evenine: Ja das stimmt schon. Und das genügt uns auf diesem Planet auch als Antwort.*
|
||||
"
|
||||
|
||||
NewTactic ring
|
||||
@@ -0,0 +1,39 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 2
|
||||
|
||||
Title "Rewrite"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Robo spuckt den Brief aus, den er dabei hatte, und gibt ihn *Evenine*.
|
||||
|
||||
**Evenine**: Das verstehe ich nicht, wisst ihr was damit gemeint ist?
|
||||
|
||||
Und sie händigt Dir den Brief:
|
||||
"
|
||||
|
||||
Statement (a b c d : ℕ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c := by
|
||||
Hint "**Du**: Schau mal, das ist ja fast genau, was wir auf *Implis* gemacht haben,
|
||||
nur jetzt mit Gleichheiten von Zahlen anstatt Genau-Dann-Wenn-Aussagen!
|
||||
|
||||
**Robo**: `=` und `↔` kannst du praktisch gleich behandeln wenns um `rw` geht."
|
||||
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
|
||||
"
|
||||
**Evenine**: Danke viemals, das hilft uns vermutlich, jetzt Frage ich mich aber…
|
||||
"
|
||||
|
||||
NewTactic assumption rw
|
||||
@@ -0,0 +1,36 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 3
|
||||
|
||||
Title "Rewrite"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Evenine**: Mit diesem neuen Wissen, könnt ihr mir bei folgendem helfen:
|
||||
"
|
||||
|
||||
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**: Ah da ersetzt man ja einfach `{a}` durch `{b}` in der anderen Annahme!
|
||||
|
||||
**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 im weiteren `h` in **allen** Annahmen und
|
||||
dem Goal umschreiben.
|
||||
"
|
||||
@@ -0,0 +1,35 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 4
|
||||
|
||||
Title "Natürliche Zahlen"
|
||||
|
||||
Introduction
|
||||
"
|
||||
*Evenines* Berater meldet sich.
|
||||
|
||||
**Berater**: Das stimmt wohl, aber das Problem, das uns eigentlich beschäftigt hat, eure
|
||||
Natürlichkeit, war folgendes:
|
||||
"
|
||||
|
||||
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 versteh das Pattern. Wenn ich zuerst alles so umschreibe, dass
|
||||
das Goal nur noch rechnen und umsortieren ist, dann kann `ring` den Rest machen!
|
||||
|
||||
**Robo**: Noch ein Trick: Entweder kannst du zwei Befehle `rw [h₁]` und `rw [h₂]` schreiben,
|
||||
oder du kannst das gleich in einem machen : rw [h₁, h₂]."
|
||||
rw [h, g]
|
||||
ring
|
||||
|
||||
|
||||
Conclusion
|
||||
"
|
||||
*Evenine* bedankt sich nochmals für die Botschaft und ihr werdet zu einem kleineren Busch geführt,
|
||||
der ein gemütlich warmes Innenleben an den Tag legt.
|
||||
"
|
||||
|
||||
NewTactic ring rw
|
||||
@@ -0,0 +1,36 @@
|
||||
import Adam.Metadata
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 5
|
||||
|
||||
Title "Definitionally equal"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Müde ruht ihr euch in eurer Bleibe aus. Du schaust doch eine Lücke in den Blättern vielen
|
||||
kleinen Vögeln bei der Nahrungssuche zu.
|
||||
|
||||
**Du**: Sag mal Robo, ich hab vorhin ein Kind überhört, dass seinem Spielgefährten erklärt hat,
|
||||
folgendes sei mit `rfl` zu beweisen:
|
||||
"
|
||||
|
||||
Statement : 1 + 1 = 2 := by
|
||||
Hint "**Du**: Wieso nicht `ring`?
|
||||
|
||||
**Robo**: Klar, `ring` geht auch und ist intuitiver.
|
||||
Für `rfl` kommt es darauf an, wie die Sachen genau definiert sind: `1 + 1` ist als
|
||||
`(0.succ).succ` definiert und `2` halt ebenfalls.
|
||||
"
|
||||
rfl
|
||||
|
||||
OnlyTactic rfl
|
||||
|
||||
Conclusion
|
||||
"
|
||||
**Du**: Dann war das mehr Glück?
|
||||
|
||||
**Robo**: Das ist eine Art die Welt zu sehen…
|
||||
|
||||
Damit fällst du in einen ruhigen Schlaf.
|
||||
"
|
||||
@@ -0,0 +1,73 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Mathlib.Algebra.Parity
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 6
|
||||
|
||||
Title "Gerade/Ungerade"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Am nächsten Tag erklärt euch *Evenine*, dass es auf dem Mond zwei Gruppierungen gibt,
|
||||
ihre und die ihres Halbbruders *Oddeus*. Die Mottos sind
|
||||
|
||||
```
|
||||
def Even (n : ℕ) : Prop := ∃ r, n = r + r
|
||||
```
|
||||
|
||||
und
|
||||
|
||||
```
|
||||
def Odd (n : ℕ) : Prop := ∃ r, n = 2 * r + 1
|
||||
```
|
||||
|
||||
**Evenine**: Hier, ich zeige euch mal etwas was man bei uns machen kann:
|
||||
"
|
||||
|
||||
Statement even_square (n : ℕ) (h : Even n) : Even (n ^ 2) := by
|
||||
Branch
|
||||
unfold Even
|
||||
Hint "Rob**: Am besten machst du auch noch `unfold Even at h`, damit du verstehst was los ist."
|
||||
Hint "**Robo**: Wie du oben siehst, ist `Even n` dadurch definiert,
|
||||
dass ein `r` existiert so dass `r + r = n`. Am besten
|
||||
öffnest du diese Definition mit `unfold Even at *` einmal, dann siehst du besser, was los ist. "
|
||||
unfold Even at *
|
||||
Hint "**Du**: Also von `{h}` weiss 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
|
||||
ring
|
||||
use 2 * r ^ 2
|
||||
Hint "**Du**: Ah und jetzt `ring`!
|
||||
|
||||
**Robo**: Aber zuerst must du noch mit
|
||||
`rw` `n` durch `r + r` ersetzen, da `ring` das sonst nicht weiss."
|
||||
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 "**Evenine**: Seht ihr?"
|
||||
@@ -0,0 +1,43 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Mathlib.Algebra.Parity
|
||||
|
||||
set_option tactic.hygienic false
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 7
|
||||
|
||||
Title "Gerade/Ungerade"
|
||||
|
||||
Introduction
|
||||
"
|
||||
**Du**: Aber, das sagt doch gar nichts aus, genau das gleiche könnte ich für `Odd`
|
||||
auch sagen. Hier seht!
|
||||
"
|
||||
|
||||
Statement odd_square (n : ℕ) (h : Odd n) : Odd (n ^ 2) := by
|
||||
unfold Odd at *
|
||||
rcases h with ⟨r, hr⟩
|
||||
Hint "**Robo**: Ich hab noch einen Trick auf Lager:
|
||||
Wenn du jetzt herausfinden willst, welche Zahl du einsetzen musst, könntest
|
||||
du schon jetzt mit `rw [{hr}]` weitermachen…"
|
||||
rw [hr]
|
||||
Hint "**Robo**: Wenn du jetzt `ring` benötigst, 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
|
||||
|
||||
-- TODO: Allow `ring_nf` as part of `ring`.
|
||||
|
||||
Conclusion "**Evenine**: Tatsächlich. Vielleicht sind wir gar nich tso unterschiedlich. Könntet
|
||||
ihr mal mit ihm reden gehen?"
|
||||
@@ -0,0 +1,53 @@
|
||||
import Adam.Metadata
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
import Mathlib.Algebra.Parity
|
||||
import Mathlib
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 8
|
||||
|
||||
Title "Für alle"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Ihr macht euch also auf den Weg. Unterwegs trefft ihr einen Händler und ihr lässt euch von
|
||||
ihm den Weg zeigen, sowie einige Tipps zu den beiden Geschwistern geben.
|
||||
|
||||
**Händler**: Also seht, die beiden sind gar nicht so verschieden. Ein altes Sprichwort sagt:
|
||||
"
|
||||
|
||||
-- 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 Goal 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 "**Händler**: Sichere Reise!"
|
||||
@@ -0,0 +1,109 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.PushNeg
|
||||
import Mathlib
|
||||
|
||||
import Mathlib.Algebra.Parity
|
||||
|
||||
import Adam.ToBePorted
|
||||
|
||||
Game "Adam"
|
||||
World "Predicate"
|
||||
Level 9
|
||||
|
||||
Title "PushNeg"
|
||||
|
||||
Introduction
|
||||
"
|
||||
Das Dorf von *Oddeus* scheint stärker befestigt zu sein, all jenes von *Evenine*. Ihr kommt
|
||||
and eine Wand aus Dornenranken. Beim Eingang steht eine Wache, die auch zuruft:
|
||||
|
||||
"
|
||||
|
||||
-- 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**: Also ich kann mal das `¬` durch die Quantifier hindurchschieben.
|
||||
|
||||
**Robo**: `push_neg` macht genau das!
|
||||
|
||||
**Robo**: Intern braucht das zwei Lemmas
|
||||
|
||||
```
|
||||
not_exists (A : Prop) : ¬ (∃ x, A) ↔ ∀x, (¬A)
|
||||
not_forall (A : Prop) : ¬ (∀ x, A) ↔ ∃x, (¬A)
|
||||
```
|
||||
die du natürlich auch mit `rw` gebrauchen könntest."
|
||||
Branch
|
||||
unfold Odd
|
||||
push_neg
|
||||
Hint "**Robo**: Der Weg ist etwas schwieriger. Ich würde nochmals zurück und schauen,
|
||||
dass du irgendwann `¬Odd` kriegst, was du dann mit `rw [←even_iff_not_odd]`
|
||||
zu `Even` umwandeln.
|
||||
kannst."
|
||||
push_neg
|
||||
intro n
|
||||
Hint "**Robo**: Welche Zahl du jetzt mit `use` brauchst, danach wirst du vermutlich das
|
||||
Lemma `←even_iff_not_odd` brauchen.
|
||||
|
||||
**Du**: Könnte ich jetzt schon `rw [←even_iff_not_odd]` machen?
|
||||
|
||||
**Robo**: Ne, `rw` kann nicht innerhalb von Quantifiern umschreiben.
|
||||
|
||||
**Du**: Aber wie würde ich das machen?
|
||||
|
||||
**Robo**: Zeig ich dir später, die Wache wird schon ganz ungeduldig!
|
||||
Im Moment würde ich zuerst 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]
|
||||
unfold Even
|
||||
use n
|
||||
--ring
|
||||
|
||||
Conclusion "Damit werdet ihr eingelassen.
|
||||
|
||||
**Robo**: Entweder wir suchen direkt diesen *Oddeus*, oder wir schauen uns einmal um. Die Wahl
|
||||
ist deine!
|
||||
|
||||
**Du**: Kannst du mir nochmals einen Überblick geben, was wir gelernt haben?
|
||||
|
||||
**Robo**:
|
||||
|
||||
| | 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. |
|
||||
|
||||
"
|
||||
|
||||
NewTactic push_neg
|
||||
NewLemma Nat.even_iff_not_odd Nat.odd_iff_not_even not_exists not_forall
|
||||
@@ -0,0 +1,11 @@
|
||||
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."
|
||||
@@ -0,0 +1,49 @@
|
||||
import Adam.Metadata
|
||||
|
||||
import Mathlib.Tactic.Ring
|
||||
import Mathlib
|
||||
|
||||
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
|
||||
@@ -0,0 +1,51 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Data.Nat.Prime
|
||||
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
-- import Data.Nat.Prime
|
||||
|
||||
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."
|
||||
@@ -0,0 +1,41 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Data.Nat.Prime
|
||||
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Data.Nat.Prime
|
||||
|
||||
import Std.Tactic.RCases
|
||||
import Mathlib.Tactic.LeftRight
|
||||
import Mathlib.Tactic.Contrapose
|
||||
import Mathlib.Tactic.Use
|
||||
import Mathlib.Tactic.Ring
|
||||
|
||||
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
|
||||
@@ -0,0 +1,39 @@
|
||||
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 "Aussagenlogik 1"
|
||||
|
||||
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.
|
||||
"
|
||||
@@ -0,0 +1,46 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Tactic.Tauto
|
||||
|
||||
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.
|
||||
"
|
||||
|
||||
NewTactic tauto
|
||||
@@ -0,0 +1,32 @@
|
||||
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
|
||||
@@ -0,0 +1,43 @@
|
||||
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
|
||||
@@ -0,0 +1,36 @@
|
||||
import Adam.Metadata
|
||||
import Mathlib.Data.Nat.Basic -- TODO
|
||||
|
||||
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
|
||||
@@ -0,0 +1,37 @@
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user