adam@324
|
1 (* Copyright (c) 2011, Adam Chlipala
|
adam@324
|
2 *
|
adam@324
|
3 * This work is licensed under a
|
adam@324
|
4 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
|
adam@324
|
5 * Unported License.
|
adam@324
|
6 * The license text is available at:
|
adam@324
|
7 * http://creativecommons.org/licenses/by-nc-nd/3.0/
|
adam@324
|
8 *)
|
adam@324
|
9
|
adam@324
|
10 (* begin hide *)
|
adam@324
|
11
|
adam@324
|
12 Require Import List.
|
adam@324
|
13
|
adam@324
|
14 Require Import CpdtTactics.
|
adam@324
|
15
|
adam@324
|
16 Set Implicit Arguments.
|
adam@324
|
17
|
adam@324
|
18 (* end hide *)
|
adam@324
|
19
|
adam@324
|
20 (** %\part{Proof Engineering}
|
adam@324
|
21
|
adam@324
|
22 \chapter{Proof Search by Logic Programming}% *)
|
adam@324
|
23
|
adam@324
|
24 (** Exciting new chapter that is missing prose for the new content! Some content was moved from the next chapter, and it may not seem entirely to fit here yet. *)
|
adam@324
|
25
|
adam@324
|
26
|
adam@324
|
27 (** * Introducing Logic Programming *)
|
adam@324
|
28
|
adam@324
|
29 Print plus.
|
adam@324
|
30
|
adam@324
|
31 Inductive plusR : nat -> nat -> nat -> Prop :=
|
adam@324
|
32 | PlusO : forall m, plusR O m m
|
adam@324
|
33 | PlusS : forall n m r, plusR n m r
|
adam@324
|
34 -> plusR (S n) m (S r).
|
adam@324
|
35
|
adam@324
|
36 (* begin thide *)
|
adam@324
|
37 Hint Constructors plusR.
|
adam@324
|
38 (* end thide *)
|
adam@324
|
39
|
adam@324
|
40 Theorem plus_plusR : forall n m,
|
adam@324
|
41 plusR n m (n + m).
|
adam@324
|
42 (* begin thide *)
|
adam@324
|
43 induction n; crush.
|
adam@324
|
44 Qed.
|
adam@324
|
45 (* end thide *)
|
adam@324
|
46
|
adam@324
|
47 Theorem plusR_plus : forall n m r,
|
adam@324
|
48 plusR n m r
|
adam@324
|
49 -> r = n + m.
|
adam@324
|
50 (* begin thide *)
|
adam@324
|
51 induction 1; crush.
|
adam@324
|
52 Qed.
|
adam@324
|
53 (* end thide *)
|
adam@324
|
54
|
adam@324
|
55 Example four_plus_three : 4 + 3 = 7.
|
adam@324
|
56 (* begin thide *)
|
adam@324
|
57 reflexivity.
|
adam@324
|
58 Qed.
|
adam@324
|
59 (* end thide *)
|
adam@324
|
60
|
adam@324
|
61 Example four_plus_three' : plusR 4 3 7.
|
adam@324
|
62 (* begin thide *)
|
adam@324
|
63 auto.
|
adam@324
|
64 Qed.
|
adam@324
|
65 (* end thide *)
|
adam@324
|
66
|
adam@324
|
67 Example five_plus_three' : plusR 5 3 8.
|
adam@324
|
68 (* begin thide *)
|
adam@324
|
69 auto 6.
|
adam@324
|
70 Restart.
|
adam@324
|
71 info auto 6.
|
adam@324
|
72 Qed.
|
adam@324
|
73 (* end thide *)
|
adam@324
|
74
|
adam@324
|
75 (* begin thide *)
|
adam@324
|
76 Hint Constructors ex.
|
adam@324
|
77 (* end thide *)
|
adam@324
|
78
|
adam@324
|
79 Example seven_minus_three : exists x, x + 3 = 7.
|
adam@324
|
80 (* begin thide *)
|
adam@324
|
81 eauto 6.
|
adam@324
|
82 Abort.
|
adam@324
|
83 (* end thide *)
|
adam@324
|
84
|
adam@324
|
85 Example seven_minus_three' : exists x, plusR x 3 7.
|
adam@324
|
86 (* begin thide *)
|
adam@324
|
87 info eauto 6.
|
adam@324
|
88 Qed.
|
adam@324
|
89 (* end thide *)
|
adam@324
|
90
|
adam@324
|
91 Example seven_minus_four' : exists x, plusR 4 x 7.
|
adam@324
|
92 (* begin thide *)
|
adam@324
|
93 info eauto 6.
|
adam@324
|
94 Qed.
|
adam@324
|
95 (* end thide *)
|
adam@324
|
96
|
adam@324
|
97 (* begin thide *)
|
adam@324
|
98 SearchRewrite (O + _).
|
adam@324
|
99
|
adam@324
|
100 Hint Immediate plus_O_n.
|
adam@324
|
101
|
adam@324
|
102 Lemma plusS : forall n m r,
|
adam@324
|
103 n + m = r
|
adam@324
|
104 -> S n + m = S r.
|
adam@324
|
105 crush.
|
adam@324
|
106 Qed.
|
adam@324
|
107
|
adam@324
|
108 Hint Resolve plusS.
|
adam@324
|
109 (* end thide *)
|
adam@324
|
110
|
adam@324
|
111 Example seven_minus_three : exists x, x + 3 = 7.
|
adam@324
|
112 (* begin thide *)
|
adam@324
|
113 info eauto 6.
|
adam@324
|
114 Qed.
|
adam@324
|
115 (* end thide *)
|
adam@324
|
116
|
adam@324
|
117 Example seven_minus_four : exists x, 4 + x = 7.
|
adam@324
|
118 (* begin thide *)
|
adam@324
|
119 info eauto 6.
|
adam@324
|
120 Qed.
|
adam@324
|
121 (* end thide *)
|
adam@324
|
122
|
adam@324
|
123 Example hundred_minus_hundred : exists x, 4 + x + 0 = 7.
|
adam@324
|
124 (* begin thide *)
|
adam@324
|
125 eauto 6.
|
adam@324
|
126 Abort.
|
adam@324
|
127 (* end thide *)
|
adam@324
|
128
|
adam@324
|
129 (* begin thide *)
|
adam@324
|
130 Lemma plusO : forall n m,
|
adam@324
|
131 n = m
|
adam@324
|
132 -> n + 0 = m.
|
adam@324
|
133 crush.
|
adam@324
|
134 Qed.
|
adam@324
|
135
|
adam@324
|
136 Hint Resolve plusO.
|
adam@324
|
137 (* end thide *)
|
adam@324
|
138
|
adam@324
|
139 Example seven_minus_four_zero : exists x, 4 + x + 0 = 7.
|
adam@324
|
140 (* begin thide *)
|
adam@324
|
141 info eauto 7.
|
adam@324
|
142 Qed.
|
adam@324
|
143 (* end thide *)
|
adam@324
|
144
|
adam@324
|
145 Check eq_trans.
|
adam@324
|
146
|
adam@324
|
147 Section slow.
|
adam@324
|
148 Hint Resolve eq_trans.
|
adam@324
|
149
|
adam@324
|
150 Example three_minus_four_zero : exists x, 1 + x = 0.
|
adam@324
|
151 Time eauto 1.
|
adam@324
|
152 Time eauto 2.
|
adam@324
|
153 Time eauto 3.
|
adam@324
|
154 Time eauto 4.
|
adam@324
|
155 Time eauto 5.
|
adam@324
|
156 debug eauto 3.
|
adam@324
|
157 Abort.
|
adam@324
|
158 End slow.
|
adam@324
|
159
|
adam@324
|
160 (* begin thide *)
|
adam@324
|
161 Hint Resolve eq_trans : slow.
|
adam@324
|
162 (* end thide *)
|
adam@324
|
163
|
adam@324
|
164 Example three_minus_four_zero : exists x, 1 + x = 0.
|
adam@324
|
165 (* begin thide *)
|
adam@324
|
166 eauto.
|
adam@324
|
167 Abort.
|
adam@324
|
168 (* end thide *)
|
adam@324
|
169
|
adam@324
|
170 Example seven_minus_three_again : exists x, x + 3 = 7.
|
adam@324
|
171 (* begin thide *)
|
adam@324
|
172 eauto 6.
|
adam@324
|
173 Qed.
|
adam@324
|
174 (* end thide *)
|
adam@324
|
175
|
adam@324
|
176 Example needs_trans : forall x y, 1 + x = y
|
adam@324
|
177 -> y = 2
|
adam@324
|
178 -> exists z, z + x = 3.
|
adam@324
|
179 (* begin thide *)
|
adam@324
|
180 info eauto with slow.
|
adam@324
|
181 Qed.
|
adam@324
|
182 (* end thide *)
|
adam@324
|
183
|
adam@324
|
184
|
adam@324
|
185 (** * Searching for Underconstrained Values *)
|
adam@324
|
186
|
adam@324
|
187 Print length.
|
adam@324
|
188
|
adam@324
|
189 Example length_1_2 : length (1 :: 2 :: nil) = 2.
|
adam@324
|
190 auto.
|
adam@324
|
191 Qed.
|
adam@324
|
192
|
adam@324
|
193 Print length_1_2.
|
adam@324
|
194
|
adam@324
|
195 (* begin thide *)
|
adam@324
|
196 Theorem length_O : forall A, length (nil (A := A)) = O.
|
adam@324
|
197 crush.
|
adam@324
|
198 Qed.
|
adam@324
|
199
|
adam@324
|
200 Theorem length_S : forall A (h : A) t n,
|
adam@324
|
201 length t = n
|
adam@324
|
202 -> length (h :: t) = S n.
|
adam@324
|
203 crush.
|
adam@324
|
204 Qed.
|
adam@324
|
205
|
adam@324
|
206 Hint Resolve length_O length_S.
|
adam@324
|
207 (* end thide *)
|
adam@324
|
208
|
adam@324
|
209 Example length_is_2 : exists ls : list nat, length ls = 2.
|
adam@324
|
210 (* begin thide *)
|
adam@324
|
211 eauto.
|
adam@324
|
212
|
adam@324
|
213 Show Proof.
|
adam@324
|
214 Abort.
|
adam@324
|
215 (* end thide *)
|
adam@324
|
216
|
adam@324
|
217 Print Forall.
|
adam@324
|
218
|
adam@324
|
219 Example length_is_2 : exists ls : list nat, length ls = 2
|
adam@324
|
220 /\ Forall (fun n => n >= 1) ls.
|
adam@324
|
221 (* begin thide *)
|
adam@324
|
222 eauto 9.
|
adam@324
|
223 Qed.
|
adam@324
|
224 (* end thide *)
|
adam@324
|
225
|
adam@324
|
226 Definition sum := fold_right plus O.
|
adam@324
|
227
|
adam@324
|
228 (* begin thide *)
|
adam@324
|
229 Lemma plusO' : forall n m,
|
adam@324
|
230 n = m
|
adam@324
|
231 -> 0 + n = m.
|
adam@324
|
232 crush.
|
adam@324
|
233 Qed.
|
adam@324
|
234
|
adam@324
|
235 Hint Resolve plusO'.
|
adam@324
|
236
|
adam@324
|
237 Hint Extern 1 (sum _ = _) => simpl.
|
adam@324
|
238 (* end thide *)
|
adam@324
|
239
|
adam@324
|
240 Example length_and_sum : exists ls : list nat, length ls = 2
|
adam@324
|
241 /\ sum ls = O.
|
adam@324
|
242 (* begin thide *)
|
adam@324
|
243 eauto 7.
|
adam@324
|
244 Qed.
|
adam@324
|
245 (* end thide *)
|
adam@324
|
246
|
adam@324
|
247 Print length_and_sum.
|
adam@324
|
248
|
adam@324
|
249 Example length_and_sum' : exists ls : list nat, length ls = 5
|
adam@324
|
250 /\ sum ls = 42.
|
adam@324
|
251 (* begin thide *)
|
adam@324
|
252 eauto 15.
|
adam@324
|
253 Qed.
|
adam@324
|
254 (* end thide *)
|
adam@324
|
255
|
adam@324
|
256 Print length_and_sum'.
|
adam@324
|
257
|
adam@324
|
258 Example length_and_sum'' : exists ls : list nat, length ls = 2
|
adam@324
|
259 /\ sum ls = 3
|
adam@324
|
260 /\ Forall (fun n => n <> 0) ls.
|
adam@324
|
261 (* begin thide *)
|
adam@324
|
262 eauto 11.
|
adam@324
|
263 Qed.
|
adam@324
|
264 (* end thide *)
|
adam@324
|
265
|
adam@324
|
266 Print length_and_sum''.
|
adam@324
|
267
|
adam@324
|
268
|
adam@324
|
269 (** * Synthesizing Programs *)
|
adam@324
|
270
|
adam@324
|
271 Inductive exp : Set :=
|
adam@324
|
272 | Const : nat -> exp
|
adam@324
|
273 | Var : exp
|
adam@324
|
274 | Plus : exp -> exp -> exp.
|
adam@324
|
275
|
adam@324
|
276 Inductive eval (var : nat) : exp -> nat -> Prop :=
|
adam@324
|
277 | EvalConst : forall n, eval var (Const n) n
|
adam@324
|
278 | EvalVar : eval var Var var
|
adam@324
|
279 | EvalPlus : forall e1 e2 n1 n2, eval var e1 n1
|
adam@324
|
280 -> eval var e2 n2
|
adam@324
|
281 -> eval var (Plus e1 e2) (n1 + n2).
|
adam@324
|
282
|
adam@324
|
283 (* begin thide *)
|
adam@324
|
284 Hint Constructors eval.
|
adam@324
|
285 (* end thide *)
|
adam@324
|
286
|
adam@324
|
287 Example eval1 : forall var, eval var (Plus Var (Plus (Const 8) Var)) (var + (8 + var)).
|
adam@324
|
288 (* begin thide *)
|
adam@324
|
289 auto.
|
adam@324
|
290 Qed.
|
adam@324
|
291 (* end thide *)
|
adam@324
|
292
|
adam@324
|
293 Example eval1' : forall var, eval var (Plus Var (Plus (Const 8) Var)) (2 * var + 8).
|
adam@324
|
294 (* begin thide *)
|
adam@324
|
295 eauto.
|
adam@324
|
296 Abort.
|
adam@324
|
297 (* end thide *)
|
adam@324
|
298
|
adam@324
|
299 (* begin thide *)
|
adam@324
|
300 Theorem EvalPlus' : forall var e1 e2 n1 n2 n, eval var e1 n1
|
adam@324
|
301 -> eval var e2 n2
|
adam@324
|
302 -> n1 + n2 = n
|
adam@324
|
303 -> eval var (Plus e1 e2) n.
|
adam@324
|
304 crush.
|
adam@324
|
305 Qed.
|
adam@324
|
306
|
adam@324
|
307 Hint Resolve EvalPlus'.
|
adam@324
|
308
|
adam@324
|
309 Hint Extern 1 (_ = _) => abstract omega.
|
adam@324
|
310 (* end thide *)
|
adam@324
|
311
|
adam@324
|
312 Example eval1' : forall var, eval var (Plus Var (Plus (Const 8) Var)) (2 * var + 8).
|
adam@324
|
313 (* begin thide *)
|
adam@324
|
314 eauto.
|
adam@324
|
315 Qed.
|
adam@324
|
316 (* end thide *)
|
adam@324
|
317
|
adam@324
|
318 Print eval1'.
|
adam@324
|
319
|
adam@324
|
320 Example synthesize1 : exists e, forall var, eval var e (var + 7).
|
adam@324
|
321 (* begin thide *)
|
adam@324
|
322 eauto.
|
adam@324
|
323 Qed.
|
adam@324
|
324 (* end thide *)
|
adam@324
|
325
|
adam@324
|
326 Print synthesize1.
|
adam@324
|
327
|
adam@324
|
328 Example synthesize2 : exists e, forall var, eval var e (2 * var + 8).
|
adam@324
|
329 (* begin thide *)
|
adam@324
|
330 eauto.
|
adam@324
|
331 Qed.
|
adam@324
|
332 (* end thide *)
|
adam@324
|
333
|
adam@324
|
334 Print synthesize2.
|
adam@324
|
335
|
adam@324
|
336 Example synthesize3 : exists e, forall var, eval var e (3 * var + 42).
|
adam@324
|
337 (* begin thide *)
|
adam@324
|
338 eauto.
|
adam@324
|
339 Qed.
|
adam@324
|
340 (* end thide *)
|
adam@324
|
341
|
adam@324
|
342 Print synthesize3.
|
adam@324
|
343
|
adam@324
|
344 (* begin thide *)
|
adam@324
|
345 Theorem EvalConst' : forall var n m, n = m
|
adam@324
|
346 -> eval var (Const n) m.
|
adam@324
|
347 crush.
|
adam@324
|
348 Qed.
|
adam@324
|
349
|
adam@324
|
350 Hint Resolve EvalConst'.
|
adam@324
|
351
|
adam@324
|
352 Theorem zero_times : forall n m r,
|
adam@324
|
353 r = m
|
adam@324
|
354 -> r = 0 * n + m.
|
adam@324
|
355 crush.
|
adam@324
|
356 Qed.
|
adam@324
|
357
|
adam@324
|
358 Hint Resolve zero_times.
|
adam@324
|
359
|
adam@324
|
360 Theorem EvalVar' : forall var n,
|
adam@324
|
361 var = n
|
adam@324
|
362 -> eval var Var n.
|
adam@324
|
363 crush.
|
adam@324
|
364 Qed.
|
adam@324
|
365
|
adam@324
|
366 Hint Resolve EvalVar'.
|
adam@324
|
367
|
adam@324
|
368 Theorem plus_0 : forall n r,
|
adam@324
|
369 r = n
|
adam@324
|
370 -> r = n + 0.
|
adam@324
|
371 crush.
|
adam@324
|
372 Qed.
|
adam@324
|
373
|
adam@324
|
374 Theorem times_1 : forall n, n = 1 * n.
|
adam@324
|
375 crush.
|
adam@324
|
376 Qed.
|
adam@324
|
377
|
adam@324
|
378 Hint Resolve plus_0 times_1.
|
adam@324
|
379
|
adam@324
|
380 Require Import Arith Ring.
|
adam@324
|
381
|
adam@324
|
382 Theorem combine : forall x k1 k2 n1 n2,
|
adam@324
|
383 (k1 * x + n1) + (k2 * x + n2) = (k1 + k2) * x + (n1 + n2).
|
adam@324
|
384 intros; ring.
|
adam@324
|
385 Qed.
|
adam@324
|
386
|
adam@324
|
387 Hint Resolve combine.
|
adam@324
|
388
|
adam@324
|
389 Theorem linear : forall e, exists k, exists n,
|
adam@324
|
390 forall var, eval var e (k * var + n).
|
adam@324
|
391 induction e; crush; eauto.
|
adam@324
|
392 Qed.
|
adam@324
|
393
|
adam@324
|
394 Print linear.
|
adam@324
|
395 (* end thide *)
|
adam@324
|
396
|
adam@324
|
397
|
adam@324
|
398 (** * More on [auto] Hints *)
|
adam@324
|
399
|
adam@324
|
400 (** Another class of built-in tactics includes [auto], [eauto], and [autorewrite]. These are based on %\textit{%#<i>#hint databases#</i>#%}%, which we have seen extended in many examples so far. These tactics are important, because, in Ltac programming, we cannot create %``%#"#global variables#"#%''% whose values can be extended seamlessly by different modules in different source files. We have seen the advantages of hints so far, where [crush] can be defined once and for all, while still automatically applying the hints we add throughout developments.
|
adam@324
|
401
|
adam@324
|
402 The basic hints for [auto] and [eauto] are [Hint Immediate lemma], asking to try solving a goal immediately by applying a lemma and discharging any hypotheses with a single proof step each; [Resolve lemma], which does the same but may add new premises that are themselves to be subjects of nested proof search; [Constructors type], which acts like [Resolve] applied to every constructor of an inductive type; and [Unfold ident], which tries unfolding [ident] when it appears at the head of a proof goal. Each of these [Hint] commands may be used with a suffix, as in [Hint Resolve lemma : my_db]. This adds the hint only to the specified database, so that it would only be used by, for instance, [auto with my_db]. An additional argument to [auto] specifies the maximum depth of proof trees to search in depth-first order, as in [auto 8] or [auto 8 with my_db]. The default depth is 5.
|
adam@324
|
403
|
adam@324
|
404 All of these [Hint] commands can be issued alternatively with a more primitive hint kind, [Extern]. A few examples should do best to explain how [Hint Extern] works. *)
|
adam@324
|
405
|
adam@324
|
406 Theorem bool_neq : true <> false.
|
adam@324
|
407 (* begin thide *)
|
adam@324
|
408 auto.
|
adam@324
|
409
|
adam@324
|
410 (** [crush] would have discharged this goal, but the default hint database for [auto] contains no hint that applies. *)
|
adam@324
|
411
|
adam@324
|
412 Abort.
|
adam@324
|
413
|
adam@324
|
414 (** It is hard to come up with a [bool]-specific hint that is not just a restatement of the theorem we mean to prove. Luckily, a simpler form suffices. *)
|
adam@324
|
415
|
adam@324
|
416 Hint Extern 1 (_ <> _) => congruence.
|
adam@324
|
417
|
adam@324
|
418 Theorem bool_neq : true <> false.
|
adam@324
|
419 auto.
|
adam@324
|
420 Qed.
|
adam@324
|
421 (* end thide *)
|
adam@324
|
422
|
adam@324
|
423 (** Our hint says: %``%#"#whenever the conclusion matches the pattern [_ <> _], try applying [congruence].#"#%''% The [1] is a cost for this rule. During proof search, whenever multiple rules apply, rules are tried in increasing cost order, so it pays to assign high costs to relatively expensive [Extern] hints.
|
adam@324
|
424
|
adam@324
|
425 [Extern] hints may be implemented with the full Ltac language. This example shows a case where a hint uses a [match]. *)
|
adam@324
|
426
|
adam@324
|
427 Section forall_and.
|
adam@324
|
428 Variable A : Set.
|
adam@324
|
429 Variables P Q : A -> Prop.
|
adam@324
|
430
|
adam@324
|
431 Hypothesis both : forall x, P x /\ Q x.
|
adam@324
|
432
|
adam@324
|
433 Theorem forall_and : forall z, P z.
|
adam@324
|
434 (* begin thide *)
|
adam@324
|
435 crush.
|
adam@324
|
436
|
adam@324
|
437 (** [crush] makes no progress beyond what [intros] would have accomplished. [auto] will not apply the hypothesis [both] to prove the goal, because the conclusion of [both] does not unify with the conclusion of the goal. However, we can teach [auto] to handle this kind of goal. *)
|
adam@324
|
438
|
adam@324
|
439 Hint Extern 1 (P ?X) =>
|
adam@324
|
440 match goal with
|
adam@324
|
441 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X))
|
adam@324
|
442 end.
|
adam@324
|
443
|
adam@324
|
444 auto.
|
adam@324
|
445 Qed.
|
adam@324
|
446 (* end thide *)
|
adam@324
|
447
|
adam@324
|
448 (** We see that an [Extern] pattern may bind unification variables that we use in the associated tactic. [proj1] is a function from the standard library for extracting a proof of [R] from a proof of [R /\ S]. *)
|
adam@324
|
449
|
adam@324
|
450 End forall_and.
|
adam@324
|
451
|
adam@324
|
452 (** After our success on this example, we might get more ambitious and seek to generalize the hint to all possible predicates [P].
|
adam@324
|
453
|
adam@324
|
454 [[
|
adam@324
|
455 Hint Extern 1 (?P ?X) =>
|
adam@324
|
456 match goal with
|
adam@324
|
457 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X))
|
adam@324
|
458 end.
|
adam@324
|
459
|
adam@324
|
460 User error: Bound head variable
|
adam@324
|
461
|
adam@324
|
462 ]]
|
adam@324
|
463
|
adam@324
|
464 Coq's [auto] hint databases work as tables mapping %\textit{%#<i>#head symbols#</i>#%}% to lists of tactics to try. Because of this, the constant head of an [Extern] pattern must be determinable statically. In our first [Extern] hint, the head symbol was [not], since [x <> y] desugars to [not (eq x y)]; and, in the second example, the head symbol was [P].
|
adam@324
|
465
|
adam@324
|
466 This restriction on [Extern] hints is the main limitation of the [auto] mechanism, preventing us from using it for general context simplifications that are not keyed off of the form of the conclusion. This is perhaps just as well, since we can often code more efficient tactics with specialized Ltac programs, and we will see how in the next chapter. *)
|
adam@324
|
467
|
adam@324
|
468
|
adam@324
|
469 (** * Rewrite Hints *)
|
adam@324
|
470
|
adam@324
|
471 (** We have used [Hint Rewrite] in many examples so far. [crush] uses these hints by calling [autorewrite]. Our rewrite hints have taken the form [Hint Rewrite lemma : cpdt], adding them to the [cpdt] rewrite database. This is because, in contrast to [auto], [autorewrite] has no default database. Thus, we set the convention that [crush] uses the [cpdt] database.
|
adam@324
|
472
|
adam@324
|
473 This example shows a direct use of [autorewrite]. *)
|
adam@324
|
474
|
adam@324
|
475 Section autorewrite.
|
adam@324
|
476 Variable A : Set.
|
adam@324
|
477 Variable f : A -> A.
|
adam@324
|
478
|
adam@324
|
479 Hypothesis f_f : forall x, f (f x) = f x.
|
adam@324
|
480
|
adam@324
|
481 Hint Rewrite f_f : my_db.
|
adam@324
|
482
|
adam@324
|
483 Lemma f_f_f : forall x, f (f (f x)) = f x.
|
adam@324
|
484 intros; autorewrite with my_db; reflexivity.
|
adam@324
|
485 Qed.
|
adam@324
|
486
|
adam@324
|
487 (** There are a few ways in which [autorewrite] can lead to trouble when insufficient care is taken in choosing hints. First, the set of hints may define a nonterminating rewrite system, in which case invocations to [autorewrite] may not terminate. Second, we may add hints that %``%#"#lead [autorewrite] down the wrong path.#"#%''% For instance: *)
|
adam@324
|
488
|
adam@324
|
489 Section garden_path.
|
adam@324
|
490 Variable g : A -> A.
|
adam@324
|
491 Hypothesis f_g : forall x, f x = g x.
|
adam@324
|
492 Hint Rewrite f_g : my_db.
|
adam@324
|
493
|
adam@324
|
494 Lemma f_f_f' : forall x, f (f (f x)) = f x.
|
adam@324
|
495 intros; autorewrite with my_db.
|
adam@324
|
496 (** [[
|
adam@324
|
497 ============================
|
adam@324
|
498 g (g (g x)) = g x
|
adam@324
|
499 ]]
|
adam@324
|
500 *)
|
adam@324
|
501
|
adam@324
|
502 Abort.
|
adam@324
|
503
|
adam@324
|
504 (** Our new hint was used to rewrite the goal into a form where the old hint could no longer be applied. This %``%#"#non-monotonicity#"#%''% of rewrite hints contrasts with the situation for [auto], where new hints may slow down proof search but can never %``%#"#break#"#%''% old proofs. The key difference is that [auto] either solves a goal or makes no changes to it, while [autorewrite] may change goals without solving them. The situation for [eauto] is slightly more complicated, as changes to hint databases may change the proof found for a particular goal, and that proof may influence the settings of unification variables that appear elsewhere in the proof state. *)
|
adam@324
|
505
|
adam@324
|
506 Reset garden_path.
|
adam@324
|
507
|
adam@324
|
508 (** [autorewrite] also works with quantified equalities that include additional premises, but we must be careful to avoid similar incorrect rewritings. *)
|
adam@324
|
509
|
adam@324
|
510 Section garden_path.
|
adam@324
|
511 Variable P : A -> Prop.
|
adam@324
|
512 Variable g : A -> A.
|
adam@324
|
513 Hypothesis f_g : forall x, P x -> f x = g x.
|
adam@324
|
514 Hint Rewrite f_g : my_db.
|
adam@324
|
515
|
adam@324
|
516 Lemma f_f_f' : forall x, f (f (f x)) = f x.
|
adam@324
|
517 intros; autorewrite with my_db.
|
adam@324
|
518 (** [[
|
adam@324
|
519
|
adam@324
|
520 ============================
|
adam@324
|
521 g (g (g x)) = g x
|
adam@324
|
522
|
adam@324
|
523 subgoal 2 is:
|
adam@324
|
524 P x
|
adam@324
|
525 subgoal 3 is:
|
adam@324
|
526 P (f x)
|
adam@324
|
527 subgoal 4 is:
|
adam@324
|
528 P (f x)
|
adam@324
|
529 ]]
|
adam@324
|
530 *)
|
adam@324
|
531
|
adam@324
|
532 Abort.
|
adam@324
|
533
|
adam@324
|
534 (** The inappropriate rule fired the same three times as before, even though we know we will not be able to prove the premises. *)
|
adam@324
|
535
|
adam@324
|
536 Reset garden_path.
|
adam@324
|
537
|
adam@324
|
538 (** Our final, successful, attempt uses an extra argument to [Hint Rewrite] that specifies a tactic to apply to generated premises. Such a hint is only used when the tactic succeeds for all premises, possibly leaving further subgoals for some premises. *)
|
adam@324
|
539
|
adam@324
|
540 Section garden_path.
|
adam@324
|
541 Variable P : A -> Prop.
|
adam@324
|
542 Variable g : A -> A.
|
adam@324
|
543 Hypothesis f_g : forall x, P x -> f x = g x.
|
adam@324
|
544 (* begin thide *)
|
adam@324
|
545 Hint Rewrite f_g using assumption : my_db.
|
adam@324
|
546 (* end thide *)
|
adam@324
|
547
|
adam@324
|
548 Lemma f_f_f' : forall x, f (f (f x)) = f x.
|
adam@324
|
549 (* begin thide *)
|
adam@324
|
550 intros; autorewrite with my_db; reflexivity.
|
adam@324
|
551 Qed.
|
adam@324
|
552 (* end thide *)
|
adam@324
|
553
|
adam@324
|
554 (** [autorewrite] will still use [f_g] when the generated premise is among our assumptions. *)
|
adam@324
|
555
|
adam@324
|
556 Lemma f_f_f_g : forall x, P x -> f (f x) = g x.
|
adam@324
|
557 (* begin thide *)
|
adam@324
|
558 intros; autorewrite with my_db; reflexivity.
|
adam@324
|
559 (* end thide *)
|
adam@324
|
560 Qed.
|
adam@324
|
561 End garden_path.
|
adam@324
|
562
|
adam@324
|
563 (** remove printing * *)
|
adam@324
|
564
|
adam@324
|
565 (** It can also be useful to use the [autorewrite with db in *] form, which does rewriting in hypotheses, as well as in the conclusion. *)
|
adam@324
|
566
|
adam@324
|
567 (** printing * $*$ *)
|
adam@324
|
568
|
adam@324
|
569 Lemma in_star : forall x y, f (f (f (f x))) = f (f y)
|
adam@324
|
570 -> f x = f (f (f y)).
|
adam@324
|
571 (* begin thide *)
|
adam@324
|
572 intros; autorewrite with my_db in *; assumption.
|
adam@324
|
573 (* end thide *)
|
adam@324
|
574 Qed.
|
adam@324
|
575
|
adam@324
|
576 End autorewrite.
|
adam@325
|
577
|
adam@325
|
578
|
adam@325
|
579 (** * Exercises *)
|
adam@325
|
580
|
adam@325
|
581 (** printing * $\cdot$ *)
|
adam@325
|
582
|
adam@325
|
583 (** %\begin{enumerate}%#<ol>#
|
adam@325
|
584
|
adam@325
|
585 %\item%#<li># I did a Google search for group theory and found #<a href="http://dogschool.tripod.com/housekeeping.html">#a page that proves some standard theorems#</a>#%\footnote{\url{http://dogschool.tripod.com/housekeeping.html}}%. This exercise is about proving all of the theorems on that page automatically.
|
adam@325
|
586
|
adam@325
|
587 For the purposes of this exercise, a group is a set [G], a binary function [f] over [G], an identity element [e] of [G], and a unary inverse function [i] for [G]. The following laws define correct choices of these parameters. We follow standard practice in algebra, where all variables that we mention are quantified universally implicitly at the start of a fact. We write infix [*] for [f], and you can set up the same sort of notation in your code with a command like [Infix "*" := f.].
|
adam@325
|
588
|
adam@325
|
589 %\begin{itemize}%#<ul>#
|
adam@325
|
590 %\item%#<li># %\textbf{%#<b>#Associativity#</b>#%}%: [(a * b) * c = a * (b * c)]#</li>#
|
adam@325
|
591 %\item%#<li># %\textbf{%#<b>#Right Identity#</b>#%}%: [a * e = a]#</li>#
|
adam@325
|
592 %\item%#<li># %\textbf{%#<b>#Right Inverse#</b>#%}%: [a * i a = e]#</li>#
|
adam@325
|
593 #</ul> </li>#%\end{itemize}%
|
adam@325
|
594
|
adam@325
|
595 The task in this exercise is to prove each of the following theorems for all groups, where we define a group exactly as above. There is a wrinkle: every theorem or lemma must be proved by either a single call to [crush] or a single call to [eauto]! It is allowed to pass numeric arguments to [eauto], where appropriate. Recall that a numeric argument sets the depth of proof search, where 5 is the default. Lower values can speed up execution when a proof exists within the bound. Higher values may be necessary to find more involved proofs.
|
adam@325
|
596
|
adam@325
|
597 %\begin{itemize}%#<ul>#
|
adam@325
|
598 %\item%#<li># %\textbf{%#<b>#Characterizing Identity#</b>#%}%: [a * a = a -> a = e]#</li>#
|
adam@325
|
599 %\item%#<li># %\textbf{%#<b>#Left Inverse#</b>#%}%: [i a * a = e]#</li>#
|
adam@325
|
600 %\item%#<li># %\textbf{%#<b>#Left Identity#</b>#%}%: [e * a = a]#</li>#
|
adam@325
|
601 %\item%#<li># %\textbf{%#<b>#Uniqueness of Left Identity#</b>#%}%: [p * a = a -> p = e]#</li>#
|
adam@325
|
602 %\item%#<li># %\textbf{%#<b>#Uniqueness of Right Inverse#</b>#%}%: [a * b = e -> b = i a]#</li>#
|
adam@325
|
603 %\item%#<li># %\textbf{%#<b>#Uniqueness of Left Inverse#</b>#%}%: [a * b = e -> a = i b]#</li>#
|
adam@325
|
604 %\item%#<li># %\textbf{%#<b>#Right Cancellation#</b>#%}%: [a * x = b * x -> a = b]#</li>#
|
adam@325
|
605 %\item%#<li># %\textbf{%#<b>#Left Cancellation#</b>#%}%: [x * a = x * b -> a = b]#</li>#
|
adam@325
|
606 %\item%#<li># %\textbf{%#<b>#Distributivity of Inverse#</b>#%}%: [i (a * b) = i b * i a]#</li>#
|
adam@327
|
607 %\item%#<li># %\textbf{%#<b>#Double Inverse#</b>#%}%: [i (][i a) = a]#</li>#
|
adam@325
|
608 %\item%#<li># %\textbf{%#<b>#Identity Inverse#</b>#%}%: [i e = e]#</li>#
|
adam@325
|
609 #</ul> </li>#%\end{itemize}%
|
adam@325
|
610
|
adam@325
|
611 One more use of tactics is allowed in this problem. The following lemma captures one common pattern of reasoning in algebra proofs: *)
|
adam@325
|
612
|
adam@325
|
613 (* begin hide *)
|
adam@325
|
614 Variable G : Set.
|
adam@325
|
615 Variable f : G -> G -> G.
|
adam@325
|
616 Infix "*" := f.
|
adam@325
|
617 (* end hide *)
|
adam@325
|
618
|
adam@325
|
619 Lemma mult_both : forall a b c d1 d2,
|
adam@325
|
620 a * c = d1
|
adam@325
|
621 -> b * c = d2
|
adam@325
|
622 -> a = b
|
adam@325
|
623 -> d1 = d2.
|
adam@325
|
624 crush.
|
adam@325
|
625 Qed.
|
adam@325
|
626
|
adam@325
|
627 (** That is, we know some equality [a = b], which is the third hypothesis above. We derive a further equality by multiplying both sides by [c], to yield [a * c = b * c]. Next, we do algebraic simplification on both sides of this new equality, represented by the first two hypotheses above. The final result is a new theorem of algebra.
|
adam@325
|
628
|
adam@325
|
629 The next chapter introduces more details of programming in Ltac, but here is a quick teaser that will be useful in this problem. Include the following hint command before you start proving the main theorems of this exercise: *)
|
adam@325
|
630
|
adam@325
|
631 Hint Extern 100 (_ = _) =>
|
adam@325
|
632 match goal with
|
adam@325
|
633 | [ _ : True |- _ ] => fail 1
|
adam@325
|
634 | _ => assert True by constructor; eapply mult_both
|
adam@325
|
635 end.
|
adam@325
|
636
|
adam@325
|
637 (** This hint has the effect of applying [mult_both] %\emph{%#<i>#at most once#</i>#%}% during a proof. After the next chapter, it should be clear why the hint has that effect, but for now treat it as a useful black box. Simply using [Hint Resolve mult_both] would increase proof search time unacceptably, because there are just too many ways to use [mult_both] repeatedly within a proof.
|
adam@325
|
638
|
adam@325
|
639 The order of the theorems above is itself a meta-level hint, since I found that order to work well for allowing the use of earlier theorems as hints in the proofs of later theorems.
|
adam@325
|
640
|
adam@325
|
641 The key to this problem is coming up with further lemmas like [mult_both] that formalize common patterns of reasoning in algebraic proofs. These lemmas need to be more than sound: they must also fit well with the way that [eauto] does proof search. For instance, if we had given [mult_both] a traditional statement, we probably would have avoided %``%#"#pointless#"#%''% equalities like [a = b], which could be avoided simply by replacing all occurrences of [b] with [a]. However, the resulting theorem would not work as well with automated proof search! Every additional hint you come up with should be registered with [Hint Resolve], so that the lemma statement needs to be in a form that [eauto] understands %``%#"#natively.#"#%''%
|
adam@325
|
642
|
adam@325
|
643 I recommend testing a few simple rules corresponding to common steps in algebraic proofs. You can apply them manually with any tactics you like (e.g., [apply] or [eapply]) to figure out what approaches work, and then switch to [eauto] once you have the full set of hints.
|
adam@325
|
644
|
adam@325
|
645 I also proved a few hint lemmas tailored to particular theorems, but which do not give common algebraic simplification rules. You will probably want to use some, too, in cases where [eauto] does not find a proof within a reasonable amount of time. In total, beside the main theorems to be proved, my sample solution includes 6 lemmas, with a mix of the two kinds of lemmas. You may use more in your solution, but I suggest trying to minimize the number.
|
adam@325
|
646
|
adam@325
|
647 #</ol>#%\end{enumerate}% *)
|