Skip to content

Commit 2a5448d

Browse files
committed
Add more Induction exercises
N.B. destruct_induction is absent, as it seems irrelevant to Idris.
1 parent 26ad099 commit 2a5448d

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed

docs/pdf/sf-idris-2016.pdf

16.2 KB
Binary file not shown.

src/Induction.lidr

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,240 @@ Prove the following using induction. You might need previously proven results.
9696
> plus_comm : (n, m : Nat) -> n + m = m + n
9797
> plus_comm n m = ?plus_comm_rhs
9898

99+
> plus_assoc : (n, m, p : Nat) -> n + (m + p) = (n + m) + p
100+
> plus_assoc n m p = ?plus_assoc_rhs
101+
102+
$\square$
103+
104+
105+
=== Exercise: 2 stars, (double_plus)
106+
107+
Consider the following function, which doubles its argument:
108+
109+
> double : (n : Nat) -> Nat
110+
> double Z = Z
111+
> double (S k) = S (S (double k))
112+
113+
Use induction to prove this simple fact about `double`:
114+
115+
> double_plus : (n : Nat) -> double n = n + n
116+
> double_plus n = ?double_plus_rhs
117+
118+
$\square$
119+
120+
121+
=== Exercise: 2 stars, optional (evenb_S)
122+
123+
One inconveninent aspect of our definition of `evenb n` is that it may need to
124+
perform a recursive call on `n - 2`. This makes proofs about `evenb n` harder
125+
when done by induction on `n`, since we may need an induction hypothesis about
126+
`n - 2`. The following lemma gives a better characterization of `evenb (S n)`:
127+
128+
> evenb_S : (n : Nat) -> evenb (S n) = negb (evenb n)
129+
> evenb_S n = ?evenb_S_rhs
130+
131+
$\square$
132+
133+
134+
== Proofs Within Proofs
135+
136+
In Coq, as in informal mathematics, large proofs are often broken into a
137+
sequence of theorems, with later proofs referring to earlier theorems. But
138+
sometimes a proof will require some miscellaneous fact that is too trivial and
139+
of too little general interest to bother giving it its own top-level name. In
140+
such cases, it is convenient to be able to simply state and prove the needed
141+
"sub-theorem" right at the point where it is used. The `assert` tactic allows us
142+
to do this. For example, our earlier proof of the `mult_0_plus` theorem referred
143+
to a previous theorem named `plus_Z_n`. We could instead use `assert` to state
144+
and prove `plus_Z_n` in-line:
145+
146+
> mult_0_plus' : (n, m : Nat) -> (0 + n) * m = n * m
147+
> mult_0_plus' n m = Refl
148+
149+
The `assert` tactic introduces two sub-goals. The first is the assertion itself;
150+
by prefixing it with `H:` we name the assertion `H`. (We can also name the
151+
assertion with `as` just as we did above with `destruct` and `induction`, i.e.,
152+
`assert (0 + n = n) as H`.) Note that we surround the proof of this assertion
153+
with curly braces `{ ... }`, both for readability and so that, when using Coq
154+
interactively, we can see more easily when we have finished this sub-proof. The
155+
second goal is the same as the one at the point where we invoke `assert` except
156+
that, in the context, we now have the assumption `H` that `0 + n = n`. That is,
157+
`assert` generates one subgoal where we must prove the asserted fact and a
158+
second subgoal where we can use the asserted fact to make progress on whatever
159+
we were trying to prove in the first place.
160+
161+
The `assert` tactic is handy in many sorts of situations. For example, suppose
162+
we want to prove that `(n + m) + (p + q) = (m + n) + (p + q)`. The only
163+
difference between the two sides of the `=` is that the arguments `m` and `n` to
164+
the first inner `+` are swapped, so it seems we should be able to use the
165+
commutativity of addition (`plus_comm`) to rewrite one into the other. However,
166+
the `rewrite` tactic is a little stupid about _where_ it applies the rewrite.
167+
There are three uses of `+` here, and it turns out that doing `rewrite ->
168+
plus_comm` will affect only the _outer_ one...
169+
170+
```idris
171+
plus_rearrange_firsttry : (n, m, p, q : Nat) ->
172+
(n + m) + (p + q) = (m + n) + (p + q)
173+
plus_rearrange_firsttry n m p q = rewrite plus_comm in Refl
174+
```
175+
```
176+
When checking right hand side of plus_rearrange_firsttry with expected type
177+
n + m + (p + q) = m + n + (p + q)
178+
179+
_ does not have an equality type ((n1 : Nat) ->
180+
(n1 : Nat) -> plus n1 m1 = plus m1 n1)
181+
```
182+
183+
To get `plus_comm` to apply at the point where we want it to, we can introduce a
184+
local lemma stating that `n + m = m + n` (for the particular `m` and `n` that we
185+
are talking about here), prove this lemma using `plus_comm`, and then use it to
186+
do the desired rewrite.
187+
188+
> plus_rearrange_lemma : (n, m : Nat) -> n + m = m + n
189+
> plus_rearrange_lemma = plus_comm
190+
191+
> plus_rearrange : (n, m, p, q : Nat) ->
192+
> (n + m) + (p + q) = (m + n) + (p + q)
193+
> plus_rearrange n m p q = rewrite plus_rearrange_lemma n m in Refl
194+
195+
196+
== More Exercises
197+
198+
=== Exercise: 3 stars, recommended (mult_comm)
199+
200+
Use `rewrite` to help prove this theorem. You shouldn't need to use induction on
201+
`plus_swap`.
202+
203+
> plus_swap : (n, m, p : Nat) -> n + (m + p) = m + (n + p)
204+
> plus_swap n m p = ?plus_swap_rhs
205+
206+
Now prove commutativity of multiplication. (You will probably need to define and
207+
prove a separate subsidiary theorem to be used in the proof of this one. You may
208+
find that `plus_swap` comes in handy.)
209+
210+
> mult_comm : (m, n : Nat) -> m * n = n * m
211+
> mult_comm m n = ?mult_comm_rhs
212+
213+
$\square$
214+
215+
216+
=== Exercise: 3 stars, optional (more_exercises)
217+
218+
Take a piece of paper. For each of the following theorems, first _think_ about
219+
whether (a) it can be proved using only simplification and rewriting, (b) it
220+
also requires case analysis (`destruct`), or (c) it also requires induction.
221+
Write down your prediction. Then fill in the proof. (There is no need to turn in
222+
your piece of paper; this is just to encourage you to reflect before you hack!)
223+
224+
> leb_refl : (n : Nat) -> True = leb n n
225+
> leb_refl n = ?leb_refl_rhs
226+
227+
> zero_nbeq_S : (n : Nat) -> beq_nat 0 (S n) = False
228+
> zero_nbeq_S n = ?zero_nbeq_S_rhs
229+
230+
> andb_false_r : (b : Bool) -> andb b False = False
231+
> andb_false_r b = ?andb_false_r_rhs
232+
233+
> plus_ble_compat_l : (n, m, p : Nat) ->
234+
> leb n m = True -> leb (p + n) (p + m) = True
235+
> plus_ble_compat_l n m p prf = ?plus_ble_compat_l_rhs
236+
237+
> S_nbeq_0 : (n : Nat) -> beq_nat (S n) 0 = False
238+
> S_nbeq_0 n = ?S_nbeq_0_rhs
239+
240+
> mult_1_l : (n : Nat) -> 1 * n = n
241+
> mult_1_l n = ?mult_1_l_rhs
242+
243+
> all3_spec : (b, c : Bool) ->
244+
> orb (andb b c)
245+
> (orb (negb b)
246+
> (negb c))
247+
> = True
248+
> all3_spec b c = ?all3_spec_rhs
249+
250+
> mult_plus_distr_r : (n, m, p : Nat) -> (n + m) * p = (n * p) + (m * p)
251+
> mult_plus_distr_r n m p = ?mult_plus_distr_r_rhs
252+
253+
> mult_assoc : (n, m, p : Nat) -> n * (m * p) = (n * m) * p
254+
> mult_assoc n m p = ?mult_assoc_rhs
255+
256+
$\square$
257+
258+
259+
=== Exercise: 2 stars, optional (beq_nat_refl)
260+
261+
Prove the following theorem. (Putting the `True` on the left-hand side of the
262+
equality may look odd, but this is how the theorem is stated in the Coq standard
263+
library, so we follow suit. Rewriting works equally well in either direction, so
264+
we will have no problem using the theorem no matter which way we state it.)
265+
266+
> beq_nat_refl : (n : Nat) -> True = beq_nat n n
267+
> beq_nat_refl n = ?beq_nat_refl_rhs
268+
269+
$\square$
270+
271+
272+
=== Exercise: 2 stars, optional (plus_swap')
273+
274+
The `replace` tactic allows you to specify a particular subterm to rewrite and
275+
what you want it rewritten to: `replace (t) with (u)` replaces (all copies of)
276+
expression `t` in the goal by expression `u`, and generates `t = u` as an
277+
additional subgoal. This is often useful when a plain `rewrite` acts on the
278+
wrong part of the goal.
279+
280+
Use the `replace` tactic to do a proof of `plus_swap'`, just like `plus_swap`
281+
but without needing `assert (n + m = m + n)`.
282+
283+
> plus_swap' : (n, m, p : Nat) -> n + (m + p) = m + (n + p)
284+
> plus_swap' n m p = ?plus_swap'_rhs
285+
286+
$\square$
287+
288+
289+
=== Exercise: 3 stars, recommended (binary_commute)
290+
291+
Recall the `incr` and `bin_to_nat` functions that you wrote for the `binary`
292+
exercise in the `Basics` chapter. Prove that the following diagram commutes:
293+
294+
bin --------- incr -------> bin
295+
| |
296+
bin_to_nat bin_to_nat
297+
| |
298+
v v
299+
nat ---------- S ---------> nat
300+
301+
That is, incrementing a binary number and then converting it to a (unary)
302+
natural number yields the same result as first converting it to a natural number
303+
and then incrementing. Name your theorem `bin_to_nat_pres_incr` ("pres" for
304+
"preserves").
305+
306+
Before you start working on this exercise, please copy the definitions from your
307+
solution to the `binary` exercise here so that this file can be graded on its
308+
own. If you find yourself wanting to change your original definitions to make
309+
the property easier to prove, feel free to do so!
310+
311+
$\square$
312+
313+
314+
=== Exercise: 5 stars, advanced (binary_inverse)
315+
316+
This exercise is a continuation of the previous exercise about binary numbers.
317+
You will need your definitions and theorems from there to complete this one.
318+
319+
(a) First, write a function to convert natural numbers to binary numbers. Then
320+
prove that starting with any natural number, converting to binary, then
321+
converting back yields the same natural number you started with.
322+
323+
(b) You might naturally think that we should also prove the opposite direction:
324+
that starting with a binary number, converting to a natural, and then back
325+
to binary yields the same number we started with. However, this is not true!
326+
Explain what the problem is.
327+
328+
(c) Define a "direct" normalization function -- i.e., a function `normalize`
329+
from binary numbers to binary numbers such that, for any binary number b,
330+
converting to a natural and then back to binary yields `(normalize b)`.
331+
Prove it. (Warning: This part is tricky!)
332+
333+
Again, feel free to change your earlier definitions if this helps here.
334+
99335
$\square$

0 commit comments

Comments
 (0)