This commit is contained in:
Jon Eugster
2023-04-03 19:51:27 +02:00
parent f636a8d833
commit 68606aab99
41 changed files with 579 additions and 407 deletions
@@ -15,47 +15,45 @@ dass sie euch gar nicht sagt, wo dieser zu finden sei.
"
Statement "" : ∃ f : ℤ → ℤ, ∀ x, f x < x := by
Hint
"
**Robo**: `f : ℤ → ℤ` ist die Notation für eine Funktion und `f x` ist diese Funktion
angewendet auf ein Element `(x : ℤ)`.
**Du**: War `→` nicht eben noch eine Implikation?
**Robo**: Doch, die brauchen das gleiche Zeichen für beides.
**Du**: Dann ist `f : ℤ → ℤ` also einfach abstrakt irgendeine Funktion,
wie definier ich aber jetzt konkret eine Abbildungsvorschrift?
**Robo**: Man kennt hier eine Notation für eine anonyme Funktion:
`fun (x : ℤ) ↦ x ^ 2` ist
$$
\\begin\{aligned}
f : \\mathbb\{ℤ} &\\to \\mathbb\{ℤ} \\\\
x &\\mapsto x ^ 2
\\end\{aligned}
$$
**Robo**: PS, `↦` ist `\\mapsto`. Aber man kann auch stattdessen `=>` benützen.
"
Hint (hidden := true)
"
**Du**: Ja aber was mach ich damit?
**Robo**: Wie immer gehst du ein `∃` mit `use …` an.
"
use (fun x ↦ x - 1)
Hint (hidden := true) "**Du**: Zu was sich das wohl vereinfacht?"
Branch
intro x
Hint (hidden := true) "**Du**: Zu was sich das wohl vereinfacht?"
simp
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?"
NewDefinition Symbol.function
LemmaTab "Function"
Conclusion "Das Mädchen wird kurz ruhig, dann beginnt es zu lächeln und zeigt strahlend
in eine Richtung. Ihr folgt ihrem Finger und euch fällt in weiter ferne eine pompöse Struktur
+25 -31
View File
@@ -33,12 +33,35 @@ def f (x : ℤ) : ℤ := (x + 4)
und:
"
open Function
def f (x : ℤ) : ℤ := (x + 4)
Statement "" (x : ℤ) : ∃ (g : ℤ → ℤ), (g ∘ f) x = x + 1 := by
Hint
"**Du**: Ist `g ∘ f` Komposition von Funktionen?
**Robo**: Richtig! Das schreibt man mit `\\comp`.
**Du** Und hier könnte ich also zuerst
`let g := fun (x : ℤ) ↦ _` definieren, anstatt direkt
`use fun (x : ℤ) ↦ _`?
**Robo**: Genau! Das ist zwar praktisch das gleiche, aber kann manchmal nützlich sein."
Branch
use fun (x : ℤ) ↦ x - 3
Hint "**Robo**: `((fun (x : ℤ) ↦ x - 3) ∘ f) x` ist per Definition `(fun (x : ℤ) ↦ x - 3) (f x)`, aber mit
`rw [comp_apply]` kann man das explizit umschreiben, aber `simp` kennt das
Lemma auch."
let g := fun (x : ℤ) ↦ x - 3
Hint "**Robo**: gute Wahl! Jetzt kannst du diese mit `use g` benützen."
use g
Hint "**Robo**: `({g} ∘ f) x` ist per Definition `{g} (f x)`, aber mit
`rw [comp_apply]` kann man das explizit umschreiben, aber `simp` kennt das
Lemma auch."
simp
Hint "**Robo**: Wie schon gehabt hat `ring` Schwierigkeiten, Definitionen zu öffnen.
Du kannst mit `unfold f` oder `rw [f]` nachhelfen."
unfold f
ring
@@ -46,38 +69,9 @@ NewTactic «let»
NewLemma Function.comp_apply
LemmaTab "Function"
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…
**Robo**: Ich hatte ja keine Ahnung ob die generierte Aufgabe beweisbar ist… aber offenbar
hatte ich Glück.
Und damit erreicht ihr den Hügel mit der Bibliothek."
@@ -25,7 +25,7 @@ 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
open Set Function
namespace LevelFunction4
@@ -34,62 +34,64 @@ def g : ℚ → ℚ := fun x ↦ if 0 ≤ x then 2*x else 0
Statement ""
: f ∘ g = g ∘ f := by
Hint "
**Robo**: Schau mal, die beiden haben zwei Funktionen, eine davon mit stückweiser Definition.
**Du**: Und ich soll zeigen, dass die beiden vertauschbar sind?
**Robo**: Genau, am besten wählst du mit `funext x` ein beliebiges Element aus, und zeigst das
dann für dieses.
"
funext x
simp_rw [Function.comp_apply]
Hint "
**Du**: Ah und jetzt kann ich erst einmal `(g ∘ f) {x}` zu `g (f {x})` umschreiben?
**Robo**: Mit `simp` klappt das.
"
simp
Hint "**Robo**: Jetzt würde ich einmal mit `unfold g` die Definition von `g` öffnen."
unfold g
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
Hint "**Robo**: Jetzt kannst du nämlich eine Fallunterscheidung
machen, `by_cases h : 0 ≤ {x}`.
**Du**: Damit krieg ich die Fälle `0 ≤ {x}` und `{x} < 0`?
**Robo**: Genau! Oder präziser `0 ≤ {x}` und `¬(0 ≤ {x})`. Das ist nicht ganz das gleiche, und man
könnte mit dem Lemma `not_le` zwischen `¬(0 ≤ {x})` und `0 < {x}` wechseln."
by_cases h : 0 ≤ x
· Hint "**Robo**: Um das ausrechnen zu können, brauchst du nicht nur `0 ≤ x` sondern auch noch
eine neue Annahme `0 ≤ f x`.
**Du**: Also `have h₂ : _`?"
have h' : 0 ≤ f x
· unfold f
linarith
rw [if_pos h]
rw [if_pos h']
unfold f
ring
· have h' : ¬ (0 ≤ f x)
unfold f
linarith
rw [if_neg h]
rw [if_neg h']
unfold f
ring
NewTactic funext by_cases simp_rw linarith
NewLemma not_le if_pos if_neg
LemmaTab "Logic"
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?
Hint (x : ℚ) : (f ∘ g) x = (g ∘ f) x => ""
**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) =>
@@ -19,20 +19,16 @@ Plötzlich begegnet ihr einem älteren Wesen mit Fakel. Auf die Frage antwortet
open Set Function
Statement "" : Injective (fun (n : ℤ) ↦ n + 3) := by
Hint "**Robo**: `Injective` ist als `∀ \{a b : U}, f a = f b → a = b`
definiert, also kannst du mit `intro` anfangen."
intro a b
Branch
intro h
Hint "**Robot**: Jetzt musst du wohl `{h}` vereinfachen."
Hint (hidden := true) "**Du**: Kann man das wohl vereinfachen?"
simp
NewDefinition Injective
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."
LemmaTab "Function"
Conclusion "**Du** Woa das war ja einfach!"
@@ -22,10 +22,31 @@ example (f : ℤ → ℤ) (h : StrictMono f) : Injective f := by
-- Odd.strictMono_pow
Statement "" : Injective (fun (n : ℤ) ↦ n^3 + (n + 3)) := by
Hint "**Du**: Hmm, das ist etwas schwieriger…
**Robo**: Aber ich hab einen Trick auf Lager:
Das Lemma `StrictMono.injective` sagt, dass jede strikt monotone Funktion injektive ist,
und ich habe das Gefühl Monotonie ist hier einfacher zu zeigen."
Hint (hidden := true) "**Robo**: `apply` ist wonach du suchst."
Branch
intro a b
Hint "**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!"
intro ha
Hint "**Robo**: Ich glaube, dieser Weg ist zu steinig. Fang doch nochmals von vorne an!"
apply StrictMono.injective
Hint "**Du**: Jetzt möchte ich strikte Monotonie von `n ^ 3` und `n + 3` separat zeigen,
schliesslich scheint es mir als wär das zweite wieder einfach.
**Robo**: Dafür hab ich `StrictMono.add` bereit!"
apply StrictMono.add
Hint "**Du**: Hmm, darauf hab ich jetzt wenig Lust. Gibt's dafür auch was? Das gilt ja nur
wenn der Exponent ungerade ist.
**Robo**: Du könntest mal `Odd.strictMono_pow` versuchen…"
apply Odd.strictMono_pow
Hint (hidden := true) "**Du**: Ist das nicht ne Trivialität? Warte mal!"
trivial
Hint "**Du**: Ha! Und dieser Teil funktioniert sicher gleich wie Injektivität vorhin!"
intro a b
simp
@@ -33,47 +54,6 @@ NewDefinition Injective
NewLemma StrictMono.injective StrictMono.add Odd.strictMono_pow
LemmaTab "Function"
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."
@@ -40,31 +40,23 @@ def f : ℕ → ℕ := fun n ↦ if Even n then n^2 else n+1
Statement "" : ¬ (f + f).Injective := by
unfold Injective
Hint "**Robo**: Das ist sicher ein Hinweis.
**Du**: Aber `¬ Injective` sagt mir nichts…
**Robo**: Könntest du etwas mit `¬ ∀` anfangen? Dann könntest du ja `Injektive` zuerst öffnen.
**Du**: Darüber haben wir doch mal was gelernt…"
Hint (hidden := true) "**Robo**: Das war `push_neg`."
push_neg
Hint "**Du** Jetzt muss ich einfach ein Gegenbeispiel nennen, oder?
**Robo** Genau! Welche beiden Zahlen möchtest du denn verwenden?"
use 2
use 3
simp
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?"
LemmaTab "Function"
Conclusion
"
@@ -20,18 +20,17 @@ Bevor er dieses aushändigt, will er aber folgendes wissen:
open Function
Statement "" : Surjective (fun (n : ℤ) ↦ n + 1) := by
Hint "**Robo**: Die Definition von `Surjective f` ist `∀ y, (∃ x, f x = y)`.
**Du**: Dann kann ich das auch einfach wie Quantifier behandeln?
**Robo**: Schieß drauf los!"
intro y
use y-1
simp
NewDefinition Surjective
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!"
LemmaTab "Function"
Conclusion
"Der Gelehrte händigt euch schmunzelnd das Buch aus."
@@ -17,6 +17,10 @@ Introduction
open Function
Statement "" : Bijective (fun (n : ℤ) ↦ n + 1) := by
Hint "
**Robo** *(flüsternd)*: `Bijectve f` ist als `Injective f ∧ Surjective f` definiert.
**Du**: Dann ist das ja ganz simpel!"
unfold Bijective
constructor
intro a b
@@ -25,14 +29,9 @@ Statement "" : Bijective (fun (n : ℤ) ↦ n + 1) := by
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!
"
NewDefinition Bijective
LemmaTab "Function"
Conclusion
"Zufrieden drückt euch der Gelehrte eine neue Fackel in die Hand und
zeigt euch den Weg nach draußen."
NewDefinition Bijective
@@ -7,6 +7,8 @@ Level 9
Title "Inverse"
set_option tactic.hygienic false
Introduction
"
Eigentlich hast du nur beiläufig Robo gefragt, ob bijektiv nicht auch bedeute, dass
@@ -20,39 +22,86 @@ 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
-- bijective_iff_has_inverse
Statement "" {A B : Type} (f : A → B) :
Statement Function.bijective_iff_has_inverse "" {A B : Type} (f : A → B) :
Bijective f ↔ ∃ g, LeftInverse g f ∧ RightInverse g f := by
Hint "**Du**: Nah da sagt mir so manches nichts, aber ich kann ja mal mit dem `↔` anfangen,
das kenn ich ja schon."
constructor
intro h
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
· intro h
Hint "**Robo**: Tipp. Teil doch `Bijective` mit `rcases {h} with ⟨hI, hS⟩` in
`Injective` und `Surjective` auf!"
rcases h with ⟨hI, hS⟩
Hint "**Du**: Ja was ist eigentlich die Inverse von `f`…?
**Robo**: Hast du eine Idee?
**Du**: Also von der Surjektivität weiss ich, dass für alle `y` ein Urbild existiert
und mit der Injektivität könnte ich dann zeigen, dass dieses eindeutig ist.
**Robo**: Also Schritt für Schritt: Mit `fun y ↦ ({hS} y).choose ` kannst du eine Funktion
definieren, die `y` irgendein Urbild zuweist.
**Du**: Die ist aber nicht wohldefiniert, oder?
**Robo**: In der Mathe nicht. In Lean geht das ganz gut, aber es ist dann unmöglich etwas
darüber zu beweisen, wenn es mehrere Möglichkeiten gäbe."
use fun x => (hS x).choose
constructor
· Hint "**Robo**: fang mal mit `intro` an."
intro x
Hint "**Du**: kompliziert.
**Robo**: Aber mit `simp` kannst du es ja etwas vereinfachen."
simp
Hint "**Du**: Das kann ich jetzt nicht zeigen solange ich nicht weiss, dass nur genau ein
Urbild besteht.
**Robo**: Dann wende doch mit `apply {hI}` die Injektivität an!"
apply hI
Hint "**Robo**: Dies ist jetzt eine etwas tautologische Aussage. In Lean ist das
`Exists.choose_spec`. Konkret `apply Exists.choose_spec (hS (f x))`."
apply Exists.choose_spec (hS (f x))
· Hint "**Robo**: Gut! Auf zum Rechtsinversen! Fang auch hier wieder mit `intro` an."
intro x
Hint "**Du**: Kann ich das vereinfachen?"
simp
Hint "**Du**: Also wieder `Exists.choose_spec`?
**Robo**: Genau! Diesmal mit dem Argument `(hS x)`."
apply Exists.choose_spec (hS x)
· Hint "**Robo**: Die eine Richtung ist gezeigt. Jetzt auf zur Rückrichtung!"
intro h
Hint "**Robo**: Zerlege {h} noch soweit du kannst!"
rcases h with ⟨g, h⟩
Hint "**Robo**: Das UND auch noch!"
rcases h with ⟨hL, hR⟩
Hint "**Robo**: Das `Bijective` kannst du auch aufteilen."
constructor
· Hint "**Robo**: Injektivität ist der schwierige Teil. Fang mal an mit `intro`."
intro a b hab
Hint "**Robo**: Im nächsten Schritt must du `LeftInverse` brauchen um das Goal
zu `g (f a) = g (f b)` zu wechseln: benutze `rw [←{hL} {a}, …]`."
rw [← hL a, ← hL b]
Hint "**Du**: Wenn die Argumente `f a = f b` gleich sind, ist dann auch `g (f a) = g (f b)`,
wie sag ich das?
**Robo**: Das heisst `apply congrArg`."
apply congrArg
assumption
rw [h₁, h₁] at h
assumption
· intro x
use g x
rw [h₂]
· Hint "Die Surjektivität sollte einfacher sein."
intro x
Hint (hidden := true) "**Robo**: Psst, mit `RightInverse g f` weisst du, dass `f (g x) = x`.
Hilft das rauszufinden was du hier brauchen musst?"
use g x
Hint (hidden := true) "**Robo**: Du kannst die `RightInverse`-Annahme einfach mit `rw`
benützen."
rw [hR]
NewDefinition LeftInverse RightInverse
NewLemma Exists.choose Exists.choose_spec congrArg congrFun
DisabledLemma Function.bijective_iff_has_inverse
LemmaTab "Logic"
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.
@@ -1,95 +0,0 @@
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
-- bijective_iff_has_inverse
Statement {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?"