generated from siddhartha-gadgil/algebraic-topology-2022
-
Notifications
You must be signed in to change notification settings - Fork 4
/
NatLe.lean
224 lines (170 loc) · 5.25 KB
/
NatLe.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import Mathlib
/-!
# Examples of Proofs
We see our next proofs, most of which involve the `≤` relation on natural numbers.
We will see that the natural numbers are "defined" in terms of the `zero` and `succ` constructors.
* `Nat.zero : ℕ`
* `Nat.succ : ℕ → ℕ`
Analogous to this, (modulo renaming) the `≤` relation is defined in terms of the `le_refl` and `le_step` constructors.
* `Nat.le : ℕ → ℕ → Prop`
* `Nat.le_refl : ∀ n : ℕ, n ≤ n`
* `Nat.le_step : ∀ {n m : ℕ}, n ≤ m → n ≤ Nat.succ m`
-/
#check Nat.zero -- Nat.zero : ℕ
#check Nat.succ -- Nat.succ : ℕ → ℕ
#check Nat.le -- Nat.le : ℕ → ℕ → Prop
#check Nat.le_step -- Nat.le_step : ∀ {n m : ℕ}, n ≤ m → n ≤ Nat.succ m
#check Nat.le_refl -- Nat.le_refl : ∀ n : ℕ, n ≤ n
/-!
The first proof we see is of `3 ≤ 3`. This is a direct application of `Nat.le_refl`. This is analogous to applying `Nat.le_refl` as a function to the argument `3`.
```lean
theorem three_le_three : 3 ≤ 3 :=
Nat.le_refl 3
```
Our second result is similar and has a similar proof.
However in the proof we did not specify the argument `4`
and instead used the *placeholder* `_`. Lean deduced that
the unique way to get types correct is to fill in `4`.
```lean
/-- The result `4 ≤ 4`. -/
def four_le_four : 4 ≤ 4 :=
Nat.le_refl _
```
-/
/-- The result `3 ≤ 3`. -/
theorem three_le_three : 3 ≤ 3 :=
Nat.le_refl 3
/-- The result `4 ≤ 4`. -/
def four_le_four : 4 ≤ 4 :=
Nat.le_refl _
#eval Nat.succ 0
-- #eval succ 0
open Nat in
#eval succ 0
#check le_refl
/-!
Some more complex proofs. In the first case the proof is given fully while in the second we allow a parameter to be inferred
```lean
theorem three_le_five : 3 ≤ 5 :=
Nat.le_step (Nat.le_step (Nat.le_refl 3))
theorem three_le_six : 3 ≤ 6 :=
Nat.le_step (
Nat.le_step
(Nat.le_step (Nat.le_refl _)))
```
-/
theorem three_le_five : 3 ≤ 5 :=
Nat.le_step (Nat.le_step (Nat.le_refl 3))
theorem three_le_six : 3 ≤ 6 :=
Nat.le_step (
Nat.le_step
(Nat.le_step (Nat.le_refl _)))
/-!
In the next proof we use tactics, specifically the `apply`
tactic. We also see a case where it fails.
```lean
theorem four_le_seven : 4 ≤ 7 := by
apply Nat.le_step
-- apply Nat.le_refl
/-tactic 'apply' failed, failed to unify
?n ≤ ?n
with
4 ≤ 6-/
apply Nat.le_step
apply Nat.le_step
apply Nat.le_refl
```
-/
theorem four_le_seven : 4 ≤ 7 := by
apply Nat.le_step
-- apply Nat.le_refl
/-tactic 'apply' failed, failed to unify
?n ≤ ?n
with
4 ≤ 6-/
apply Nat.le_step
apply Nat.le_step
apply Nat.le_refl
/-!
Note that the proofs produced by tactics are proofs in the usual sense.
```lean
#print four_le_seven /- theorem four_le_seven : 4 ≤ 7 :=
Nat.le_step (Nat.le_step (Nat.le_step (Nat.le_refl 4))) -/
```
-/
#print four_le_seven -- theorem four_le_seven : 4 ≤ 7 :=
-- Nat.le_step (Nat.le_step (Nat.le_step (Nat.le_refl 4)))
/-!
Lean has many powerful tactics. The `decide` tactic can prove propositions that (are true and) can be decided by
an algorithm corresponding to the `Decidable` typeclass (which we see later).
```lean
theorem four_le_ten : 4 ≤ 10 :=
by decide
```
The proof produced by the `decide` tacic is similar to the above proofs.
```lean
def four_le_ten' : 4 ≤ 10 :=
by decide
#reduce four_le_ten' /- Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step Nat.le.refl)))))
-/
```
-/
theorem four_le_ten : 4 ≤ 10 :=
by decide
def four_le_ten' : 4 ≤ 10 :=
by decide
#reduce four_le_ten' /- Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step (Nat.le.step Nat.le.refl)))))
-/
/-!
We can combine tactics. `repeat` applies a tactic as long as it is valid; `first` applies the first applicable tactic.
```lean
example : 4 ≤ 10 :=
by
-- repeat (apply Nat.le_step) -- goal: 4 ≤ 0
repeat (first |
apply Nat.le_refl |
apply Nat.le_step)
done
```
-/
example : 4 ≤ 10 :=
by
-- repeat (apply Nat.le_step) -- goal: 4 ≤ 0
repeat (first |
apply Nat.le_refl |
apply Nat.le_step)
done
example : 3 ≤ 6 := by
apply Nat.le_step
apply three_le_five
/-! We will write some basic tactics
-/
/-- A tactic for proving `≤` for natural numbers -/
macro "nat_le" : tactic =>
`(tactic| repeat (first |
apply Nat.le_refl |
apply Nat.le_step))
example : 3 ≤ 33 := by nat_le
/-- A tactic where we try repeatedly to finish with a theorem or take a step with another. -/
macro "finish_with" x:term
"steps" y:term : tactic => do
`(tactic| repeat (first |
apply ($x:term) |
apply $y))
/-!
We can use our more general tactic in different ways.
```lean
example : 4 ≤ 44 := by
finish_with Nat.le_refl steps Nat.le_step
#check Nat.succ_le_succ -- ∀ {n m : ℕ}, n ≤ m → Nat.succ n ≤ Nat.succ m
#check Nat.zero_le -- ∀ (n : ℕ), 0 ≤ n
example : 4 ≤ 44 := by
finish_with Nat.zero_le steps Nat.succ_le_succ
```
-/
example : 4 ≤ 44 := by
finish_with Nat.le_refl steps Nat.le_step
#check Nat.succ_le_succ -- ∀ {n m : ℕ}, n ≤ m → Nat.succ n ≤ Nat.succ m
#check Nat.zero_le -- ∀ (n : ℕ), 0 ≤ n
example : 4 ≤ 44 := by
finish_with Nat.zero_le steps Nat.succ_le_succ