NNG progress

This commit is contained in:
Jon Eugster
2023-04-25 14:06:17 +02:00
parent f8ae5795cb
commit b1a53aba05
95 changed files with 1818 additions and 1136 deletions
+19 -27
View File
@@ -1,5 +1,6 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.Addition
Game "NNG"
World "AdvAddition"
@@ -10,44 +11,35 @@ open MyNat
Introduction
"
Peano's original collection of axioms for the natural numbers contained two further
assumptions, which have not yet been mentioned in the game:
Let's finally learn how to use `succ_inj`:
```
succ_inj {a b : mynat} :
succ(a) = succ(b) → a = b
zero_ne_succ (a : mynat) :
zero ≠ succ(a)
```
The reason they have not been used yet is that they are both implications,
that is,
of the form $P\\implies Q$. This is clear for `succ_inj a b`, which
says that for all $a$ and $b$ we have $succ(a)=succ(b)\\implies a=b$.
For `zero_ne_succ` the trick is that $X\ne Y$ is *defined to mean*
$X = Y\\implies{\\tt false}$. If you have played through Proposition world,
you now have the required Lean skills (i.e., you know the required
tactics) to work with these implications.
Let's finally learn how to use `succ_inj`. You should know a couple
of ways to prove the below -- one directly using an `exact`,
and one which uses an `apply` first. But either way you'll need to use `succ_inj`.
succ_inj (a b : ℕ) :
succ a = succ b → a = b
```
"
Statement -- MyNat.succ_inj'
"For all naturals $a$ and $b$, if we assume $succ(a)=succ(b)$, then we can
deduce $a=b$."
"For all naturals $a$ and $b$, if we assume $\\operatorname{succ}(a)=\\operatorname{succ}(b)$,
then we can deduce $a=b$."
{a b : ℕ} (hs : succ a = succ b) : a = b := by
exact succ_inj hs
Hint "You should know a couple
of ways to prove the below -- one directly using an `exact`,
and one which uses an `apply` first. But either way you'll need to use `succ_inj`."
Branch
apply succ_inj
exact hs
exact succ_inj hs
NewLemma MyNat.succ_inj MyNat.zero_ne_succ
NewLemma MyNat.succ_inj
LemmaTab "Nat"
Conclusion
"
## Important thing.
**Important thing**:
You can rewrite proofs of *equalities*. If `h : A = B` then `rw h` changes `A`s to `B`s.
But you *cannot rewrite proofs of implications*. `rw succ_inj` will *never work*
You can rewrite proofs of *equalities*. If `h : A = B` then `rw [h]` changes `A`s to `B`s.
But you *cannot rewrite proofs of implications*. `rw [succ_inj]` will *never work*
because `succ_inj` isn't of the form $A = B$, it's of the form $A\\implies B$. This is one
of the most common mistakes I see from beginners. $\\implies$ and $=$ are *two different things*
and you need to be clear about which one you are using.
+54 -53
View File
@@ -1,6 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.MyNat.Multiplication
import NNG.Levels.AdvAddition.Level_9
import Std.Tactic.RCases
Game "NNG"
World "AdvAddition"
@@ -11,64 +10,66 @@ open MyNat
Introduction
"
In Lean, `a ≠ b` is *defined to mean* `(a = b) → false`.
In Lean, `a ≠ b` is *defined to mean* `(a = b) → False`.
This means that if you see `a ≠ b` you can *literally treat
it as saying* `(a = b) → false`. Computer scientists would
say that these two terms are *definitionally equal*.
it as saying* `(a = b) → False`. Computer scientists would
say that these two terms are *definitionally equal*.
The following lemma, $a+b=0\\implies b=0$, will be useful in inequality world.
Let me go through the proof, because it introduces several new
concepts:
* `cases b`, where `b : mynat`
* `exfalso`
* `apply succ_ne_zero`
We're going to prove $a+b=0\\implies b=0$. Here is the
strategy. Each natural number is either `0` or `succ(d)` for
some other natural number `d`. So we can start the proof
with
`cases b with d,`
and then we have two goals, the case `b = 0` (which you can solve easily)
and the case `b = succ(d)`, which looks like this:
```
a d : mynat,
H : a + succ d = 0
⊢ succ d = 0
```
Our goal is impossible to prove. However our hypothesis `H`
is also impossible, meaning that we still have a chance!
First let's see why `H` is impossible. We can
`rw add_succ at H,`
to turn `H` into `H : succ (a + d) = 0`. Because
`succ_ne_zero (a + d)` is a proof that `succ (a + d) ≠ 0`,
it is also a proof of the implication `succ (a + d) = 0 → false`.
Hence `succ_ne_zero (a + d) H` is a proof of `false`!
Unfortunately our goal is not `false`, it's a generic
false statement.
Recall however that the `exfalso` command turns any goal into `false`
(it's logically OK because `false` implies every proposition, true or false).
You can probably take it from here.
"
Statement -- add_left_eq_zero
"If $a$ and $b$ are natural numbers such that
Statement MyNat.add_left_eq_zero
"If $a$ and $b$ are natural numbers such that
$$ a + b = 0, $$
then $b = 0$."
{{a b : ℕ}} (H : a + b = 0) : b = 0 := by
{a b : ℕ} (h : a + b = 0) : b = 0 := by
Hint "
You want to start of by making a distinction `b = 0` or `b = succ d` for some
`d`. You can do this with
```
induction b
```
even if you are never going to use the induction hypothesis.
"
-- TODO: induction vs rcases
Branch
rcases b
-- TODO: `⊢ zero = 0` :(
induction b with d
rfl
rw [add_succ] at H
exfalso
apply succ_ne_zero (a + d)
exact H
· rfl
· Hint "This goal seems impossible! However, our hypothesis `h` is also impossible,
meaning that we still have a chance!
First let's see why `h` is impossible. We can
```
rw [add_succ] at h
```
"
rw [add_succ] at h
Hint "
Because `succ_ne_zero (a + {d})` is a proof that `succ (a + {d}) ≠ 0`,
it is also a proof of the implication `succ (a + {d}) = 0 → False`.
Hence `succ_ne_zero (a + {d}) h` is a proof of `False`!
Unfortunately our goal is not `False`, it's a generic
false statement.
Recall however that the `exfalso` command turns any goal into `False`
(it's logically OK because `False` implies every proposition, true or false).
You can probably take it from here.
"
Branch
have j := succ_ne_zero (a + d) h
exfalso
exact j
exfalso
apply succ_ne_zero (a + d)
exact h
LemmaTab "Add"
Conclusion
"
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_10
Game "NNG"
World "AdvAddition"
@@ -8,22 +7,22 @@ Title "add_right_eq_zero"
open MyNat
theorem MyNat.add_left_eq_zero {{a b : ℕ}} (H : a + b = 0) : b = 0 := by sorry
Introduction
"
We just proved `add_left_eq_zero (a b : mynat) : a + b = 0 → b = 0`.
We just proved `add_left_eq_zero (a b : ℕ) : a + b = 0 → b = 0`.
Hopefully `add_right_eq_zero` shouldn't be too hard now.
"
Statement
"If $a$ and $b$ are natural numbers such that
Statement MyNat.add_right_eq_zero
"If $a$ and $b$ are natural numbers such that
$$ a + b = 0, $$
then $a = 0$."
{a b : ℕ} : a + b = 0 → a = 0 := by
intro H
rw [add_comm] at H
exact add_left_eq_zero H
intro h
rw [add_comm] at h
exact add_left_eq_zero h
LemmaTab "Add"
Conclusion
"
@@ -1,5 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_11
Game "NNG"
World "AdvAddition"
@@ -12,20 +12,22 @@ Introduction
"
We have
* `succ_eq_add_one (n : mynat) : succ n = n + 1`
```
succ_eq_add_one (n : ℕ) : succ n = n + 1
```
but sometimes the other way is also convenient.
"
theorem succ_eq_add_one (d : ℕ) : succ d = d + 1 := by sorry
Statement
Statement MyNat.add_one_eq_succ
"For any natural number $d$, we have
$$ d+1 = \\operatorname{succ}(d). $$"
(d : ℕ) : d + 1 = succ d := by
rw [succ_eq_add_one]
rfl
LemmaTab "Add"
Conclusion
"
+16 -12
View File
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_12
Game "NNG"
World "AdvAddition"
@@ -11,24 +10,29 @@ open MyNat
Introduction
"
The last level in Advanced Addition World is the statement
that $n\\not=\\operatorname{succ}(n)$. When you've done this
you've completed Advanced Addition World and can move on
to Advanced Multiplication World (after first doing
Multiplication World, if you didn't do it already).
that $n\\not=\\operatorname{succ}(n)$.
"
Statement --ne_succ_self
"For any natural number $n$, we have
$$ n \\neq \\operatorname{succ}(n). $$"
(n : ℕ) : n ≠ succ n := by
Hint (hidden := true) "I would start a proof by induction on `n`."
induction n with d hd
apply zero_ne_succ
intro hs
apply hd
apply succ_inj
assumption
· apply zero_ne_succ
· Hint (hidden := true) "If you have no clue, you could start with `rw [Ne, Not]`."
Branch
rw [Ne, Not]
intro hs
apply hd
apply succ_inj
exact hs
LemmaTab "Nat"
Conclusion
"
Congratulations. You've completed Advanced Addition World and can move on
to Advanced Multiplication World (after first doing
Multiplication World, if you didn't do it already).
"
+25 -22
View File
@@ -1,5 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_1
Game "NNG"
World "AdvAddition"
@@ -11,43 +11,46 @@ open MyNat
Introduction
"
In the below theorem, we need to apply `succ_inj` twice. Once to prove
$succ(succ(a))=succ(succ(b))\\implies succ(a)=succ(b)$, and then again
to prove $succ(a)=succ(b)\\implies a=b$. However `succ(a)=succ(b)` is
$\\operatorname{succ}(\\operatorname{succ}(a))=\\operatorname{succ}(\\operatorname{succ}(b))
\\implies \\operatorname{succ}(a)=\\operatorname{succ}(b)$, and then again
to prove $\\operatorname{succ}(a)=\\operatorname{succ}(b)\\implies a=b$.
However `succ a = succ b` is
nowhere to be found, it's neither an assumption or a goal when we start
this level. You can make it with `have` or you can use `apply`.
"
Statement
"For all naturals $a$ and $b$, if we assume $succ(succ(a))=succ(succ(b))$, then we can
deduce $a=b$. "
{a b : ℕ} (h : succ (succ a) = succ ( succ b )) : a = b := by
"For all naturals $a$ and $b$, if we assume
$\\operatorname{succ}(\\operatorname{succ}(a))=\\operatorname{succ}(\\operatorname{succ}(b))$,
then we can deduce $a=b$. "
{a b : ℕ} (h : succ (succ a) = succ (succ b)) : a = b := by
Branch
exact succ_inj (succ_inj h)
apply succ_inj
apply succ_inj
assumption
LemmaTab "Nat"
Conclusion
"
## Sample solutions to this level.
## Sample solutions to this level.
Make sure you understand them all. And remember that `rw` should not be used
with `succ_inj` -- `rw` works only with equalities or `↔` statements,
not implications or functions.
example {a b : mynat} (h : succ(succ(a)) = succ(succ(b))) : a = b :=
begin
apply succ_inj,
apply succ_inj,
```
example {a b : ℕ} (h : succ (succ a) = succ (succ b)) : a = b := by
apply succ_inj
apply succ_inj
exact h
end
example {a b : mynat} (h : succ(succ(a)) = succ(succ(b))) : a = b :=
begin
apply succ_inj,
exact succ_inj(h),
end
example {a b : ℕ} (h : succ (succ a) = succ (succ b)) : a = b := by
apply succ_inj
exact succ_inj h
example {a b : mynat} (h : succ(succ(a)) = succ(succ(b))) : a = b :=
begin
exact succ_inj(succ_inj(h)),
end
example {a b : ℕ} (h : succ (succ a) = succ (succ b)) : a = b := by
exact succ_inj (succ_inj h)
```
"
+10 -12
View File
@@ -1,5 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_2
Game "NNG"
World "AdvAddition"
@@ -11,20 +11,18 @@ open MyNat
Introduction
"
We are going to prove something completely obvious: if $a=b$ then
$succ(a)=succ(b)$. This is *not* `succ_inj`!
This is trivial -- we can just rewrite our proof of `a=b`.
But how do we get to that proof? Use the `intro` tactic.
$\\operatorname{succ}(a)=\\operatorname{succ}(b)$. This is *not* `succ_inj`!
"
Statement
"For all naturals $a$ and $b$, $a=b\\implies succ(a)=succ(b)$.
"
Statement MyNat.succ_eq_succ_of_eq
"For all naturals $a$ and $b$, $a=b\\implies \\operatorname{succ}(a)=\\operatorname{succ}(b)$."
{a b : ℕ} : a = b → succ a = succ b := by
Hint "This is trivial -- we can just rewrite our proof of `a=b`.
But how do we get to that proof? Use the `intro` tactic."
intro h
Hint "Now we can indeed just `rw` `a` to `b`."
rw [h]
Hint (hidden := true) "Recall that `rfl` closes these goals."
rfl
Conclusion
"
"
LemmaTab "Nat"
+20 -18
View File
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_3
Game "NNG"
World "AdvAddition"
@@ -11,19 +10,7 @@ open MyNat
Introduction
"
Here is an `iff` goal. You can split it into two goals (the implications in both
directions) using the `split` tactic, which is how you're going to have to start.
`split,`
Now you have two goals. The first is exactly `succ_inj` so you can close
it with
`exact succ_inj,`
and the second one you could solve by looking up the name of the theorem
you proved in the last level and doing `exact <that name>`, or alternatively
you could get some more `intro` practice and seeing if you can prove it
using `intro`, `rw` and `refl`.
directions) using the `constructor` tactic, which is how you're going to have to start.
"
Statement
@@ -31,10 +18,25 @@ Statement
"
(a b : ℕ) : succ a = succ b ↔ a = b := by
constructor
Hint "Now you have two goals. The first is exactly `succ_inj` so you can close
it with
```
exact succ_inj
intro H
rw [H]
rfl
```
"
· exact succ_inj
· Hint "The second one you could solve by looking up the name of the theorem
you proved in the last level and doing `exact <that name>`, or alternatively
you could get some more `intro` practice and seeing if you can prove it
using `intro`, `rw` and `rfl`."
Branch
exact succ_eq_succ_of_eq
intro h
rw [h]
rfl
LemmaTab "Nat"
Conclusion
"
+12 -6
View File
@@ -1,5 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_4
Game "NNG"
World "AdvAddition"
@@ -11,18 +11,19 @@ open MyNat
Introduction
"
The theorem `add_right_cancel` is the theorem that you can cancel on the right
when you're doing addition -- if `a + t = b + t` then `a = b`. After `intro h`
I'd recommend induction on `t`. Don't forget that `rw add_zero at h` can be used
to do rewriting of hypotheses rather than the goal.
when you're doing addition -- if `a + t = b + t` then `a = b`.
"
Statement
Statement MyNat.add_right_cancel
"On the set of natural numbers, addition has the right cancellation property.
In other words, if there are natural numbers $a, b$ and $c$ such that
$$ a + t = b + t, $$
then we have $a = b$."
(a t b : ℕ) : a + t = b + t → a = b := by
Hint (hidden := true) "You should start with `intro`."
intro h
Hint "I'd recommend now induction on `t`. Don't forget that `rw [add_zero] at h` can be used
to do rewriting of hypotheses rather than the goal."
induction t with d hd
rw [add_zero] at h
rw [add_zero] at h
@@ -30,8 +31,13 @@ then we have $a = b$."
apply hd
rw [add_succ] at h
rw [add_succ] at h
Hint (hidden := true) "At this point `succ_inj` might be useful."
exact succ_inj h
-- TODO: Display at this level after induction is confusing: old assumption floating in context
LemmaTab "Add"
Conclusion
"
+11 -8
View File
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_5
Game "NNG"
World "AdvAddition"
@@ -11,23 +10,27 @@ open MyNat
Introduction
"
The theorem `add_left_cancel` is the theorem that you can cancel on the left
when you're doing addition -- if `t + a = t + b` then `a = b`.
There is a three-line proof which ends in `exact add_right_cancel a t b` (or even
`exact add_right_cancel _ _ _`); this
strategy involves changing the goal to the statement of `add_right_cancel` somehow.
when you're doing addition -- if `t + a = t + b` then `a = b`.
"
Statement
Statement MyNat.add_left_cancel
"On the set of natural numbers, addition has the left cancellation property.
In other words, if there are natural numbers $a, b$ and $t$ such that
$$ t + a = t + b, $$
then we have $a = b$."
(t a b : ℕ) : t + a = t + b → a = b := by
Hint "There is a three-line proof which ends in `exact add_right_cancel a t b` (or even
`exact add_right_cancel _ _ _`); this
strategy involves changing the goal to the statement of `add_right_cancel` somehow."
rw [add_comm]
rw [add_comm t]
Hint "Now that looks like `add_right_cancel`!"
Hint (hidden := true) "`exact add_right_cancel` does not work. You need
`exact add_right_cancel a t b` or `exact add_right_cancel _ _ _`."
exact add_right_cancel a t b
LemmaTab "Add"
Conclusion
"
+11 -16
View File
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_6
Game "NNG"
World "AdvAddition"
@@ -11,25 +10,21 @@ open MyNat
Introduction
"
It's sometimes convenient to have the \"if and only if\" version
of theorems like `add_right_cancel`. Remember that you can use `split`
of theorems like `add_right_cancel`. Remember that you can use `constructor`
to split an `↔` goal into the `→` goal and the `←` goal.
## Pro tip:
`exact add_right_cancel _ _ _` means \"let Lean figure out the missing inputs\"
"
Statement --add_right_cancel_iff
"For all naturals $a$, $b$ and $t$,
Statement MyNat.add_right_cancel_iff
"For all naturals $a$, $b$ and $t$,
$$ a + t = b + t\\iff a=b. $$
"
(t a b : ℕ) : a + t = b + t ↔ a = b := by
constructor
exact add_right_cancel _ _ _ -- done that way already,
intro H -- H : a = b,
rw [H]
rfl
Conclusion
"
· Hint "Pro tip: `exact add_right_cancel _ _ _` means \"let Lean figure out the missing inputs\"."
exact add_right_cancel _ _ _
· intro H
rw [H]
rfl
LemmaTab "Add"
"
@@ -1,5 +1,5 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_7
Game "NNG"
World "AdvAddition"
@@ -14,17 +14,20 @@ The lemma you're about to prove will be useful when we want to prove that $\\leq
There are some wrong paths that you can take with this one.
"
Statement --eq_zero_of_add_right_eq_self
"If $a$ and $b$ are natural numbers such that
Statement MyNat.eq_zero_of_add_right_eq_self
"If $a$ and $b$ are natural numbers such that
$$ a + b = a, $$
then $b = 0$."
{a b : ℕ} : a + b = a → b = 0 := by
intro h
Hint (hidden := true) "Look at `add_left_cancel`."
apply add_left_cancel a
rw [h]
rw [add_zero]
rfl
LemmaTab "Add"
Conclusion
"
+28 -9
View File
@@ -1,5 +1,4 @@
import NNG.Metadata
import NNG.MyNat.AdvAddition
import NNG.Levels.AdvAddition.Level_8
Game "NNG"
World "AdvAddition"
@@ -11,23 +10,43 @@ open MyNat
Introduction
"
Levels 9 to 13 introduce the last axiom of Peano, namely
that $0\\not=\\operatorname{succ}(a)$. The proof of this is called `zero_ne_succ a`.
that $0\\not=\\operatorname{succ}(a)$. The proof of this is called `zero_ne_succ a`.
`zero_ne_succ (a : mynat) : 0 ≠ succ(a)`
```
zero_ne_succ (a : ¬) : 0 ≠ succ a
```
The `symmetry` tactic will turn any goal of the form `R x y` into `R y x`,
if `R` is a symmetric binary relation (for example `=` or `≠`).
In particular, you can prove `succ_ne_zero` below by first using
`symmetry` and then `exact zero_ne_succ a`.
$X\\ne Y$ is *defined to mean* $X = Y\\implies{\\tt False}$, similar to how `¬A` was defined.
"
-- TODO: I dont think there is a `symmetry` tactic anymore.
-- The `symmetry` tactic will turn any goal of the form `R x y` into `R y x`,
-- if `R` is a symmetric binary relation (for example `=` or `≠`).
-- In particular, you can prove `succ_ne_zero` below by first using
-- `symmetry` and then `exact zero_ne_succ a`.
Statement -- succ_ne_zero
Statement MyNat.succ_ne_zero
"Zero is not the successor of any natural number."
(a : ℕ) : succ a ≠ 0 := by
Hint "You have several options how to start. One would be to recall that `≠` is defined as
`(· = ·) → False` and start with `intro`. Or do `rw [Ne, Not]` to explicitely remove the
`≠`. Or you could use the lemma `Ne.symm (a b : ℕ) : a ≠ b → b ≠ a` which I just added to your
inventory."
Branch
rw [Ne, Not]
intro h
apply zero_ne_succ a
rw [h]
rfl
Branch
exact (zero_ne_succ a).symm
apply Ne.symm
exact zero_ne_succ a
NewLemma MyNat.zero_ne_succ Ne.symm Eq.symm Iff.symm
NewDefinition Ne
LemmaTab "Nat"
Conclusion
"