comparison src/Large.v @ 240:b28c6e6eca0c

New-rewrite-hint-breaks-old-script example
author Adam Chlipala <adamc@hcoop.net>
date Wed, 09 Dec 2009 11:06:39 -0500
parents a3f0cdcb09c3
children cb3f3ef9d5bb
comparison
equal deleted inserted replaced
239:a3f0cdcb09c3 240:b28c6e6eca0c
399 | None => _ end] ] => 399 | None => _ end] ] =>
400 dep_destruct E 400 dep_destruct E
401 end; crush). 401 end; crush).
402 Qed. 402 Qed.
403 403
404 (** Even after we put together nice automated proofs, we must deal with specification changes that can invalidate them. It is not generally possible to step through single-tactic proofs interactively. There is a command [Debug On] that lets us step through points in tactic execution, but the debugger tends to make counterintuitive choices of which points we would like to stop at, and per-point output is quite verbose, so most Coq users do not find this debugging mode very helpful. How are we to understand what has broken in a script that used to work?
405
406 An example helps demonstrate a useful approach. Consider what would have happened in our proof of [reassoc_correct] if we had first added an unfortunate rewriting hint. *)
407
408 Reset reassoc_correct.
409
410 Theorem confounder : forall e1 e2 e3,
411 eval e1 * eval e2 * eval e3 = eval e1 * (eval e2 + 1 - 1) * eval e3.
412 crush.
413 Qed.
414
415 Hint Rewrite confounder : cpdt.
416
417 Theorem reassoc_correct : forall e, eval (reassoc e) = eval e.
418 induction e; crush;
419 match goal with
420 | [ |- context[match ?E with Const _ => _ | Plus _ _ => _ | Mult _ _ => _ end] ] =>
421 destruct E; crush
422 end.
423
424 (** One subgoal remains:
425
426 [[
427 ============================
428 eval e1 * (eval e3 + 1 - 1) * eval e4 = eval e1 * eval e2
429
430 ]]
431
432 The poorly-chosen rewrite rule fired, changing the goal to a form where another hint no longer applies. Imagine that we are in the middle of a large development with many hints. How would we diagnose the problem? First, we might not be sure which case of the inductive proof has gone wrong. It is useful to separate out our automation procedure and apply it manually. *)
433
434 Restart.
435
436 Ltac t := crush; match goal with
437 | [ |- context[match ?E with Const _ => _ | Plus _ _ => _
438 | Mult _ _ => _ end] ] =>
439 destruct E; crush
440 end.
441
442 induction e.
443
444 (** Since we see the subgoals before any simplification occurs, it is clear that this is the case for constants. [t] makes short work of it. *)
445
446 t.
447
448 (** The next subgoal, for addition, is also discharged without trouble. *)
449
450 t.
451
452 (** The final subgoal is for multiplication, and it is here that we get stuck in the proof state summarized above. *)
453
454 t.
455
456 (** What is [t] doing to get us to this point? The [info] command can help us answer this kind of question. *)
457
458 (** remove printing * *)
459 Undo.
460 info t.
461 (** [[
462 == simpl in *; intuition; subst; autorewrite with cpdt in *;
463 simpl in *; intuition; subst; autorewrite with cpdt in *;
464 simpl in *; intuition; subst; destruct (reassoc e2).
465 simpl in *; intuition.
466
467 simpl in *; intuition.
468
469 simpl in *; intuition; subst; autorewrite with cpdt in *;
470 refine (eq_ind_r
471 (fun n : nat =>
472 n * (eval e3 + 1 - 1) * eval e4 = eval e1 * eval e2) _ IHe1);
473 autorewrite with cpdt in *; simpl in *; intuition;
474 subst; autorewrite with cpdt in *; simpl in *;
475 intuition; subst.
476
477 ]]
478
479 A detailed trace of [t]'s execution appears. Since we are using the very general [crush] tactic, many of these steps have no effect and only occur as instances of a more general strategy. We can copy-and-paste the details to see where things go wrong. *)
480
481 Undo.
482
483 (** We arbitrarily split the script into chunks. The first few seem not to do any harm. *)
484
485 simpl in *; intuition; subst; autorewrite with cpdt in *.
486 simpl in *; intuition; subst; autorewrite with cpdt in *.
487 simpl in *; intuition; subst; destruct (reassoc e2).
488 simpl in *; intuition.
489 simpl in *; intuition.
490
491 (** The next step is revealed as the culprit, bringing us to the final unproved subgoal. *)
492
493 simpl in *; intuition; subst; autorewrite with cpdt in *.
494
495 (** We can split the steps further to assign blame. *)
496
497 Undo.
498
499 simpl in *.
500 intuition.
501 subst.
502 autorewrite with cpdt in *.
503
504 (** It was the final of these four tactics that made the rewrite. We can find out exactly what happened. The [info] command presents hierarchical views of proof steps, and we can zoom down to a lower level of detail by applying [info] to one of the steps that appeared in the original trace. *)
505
506 Undo.
507
508 info autorewrite with cpdt in *.
509 (** [[
510 == refine (eq_ind_r (fun n : nat => n = eval e1 * eval e2) _
511 (confounder (reassoc e1) e3 e4)).
512
513 ]]
514
515 The way a rewrite is displayed is somewhat baroque, but we can see that theorem [confounder] is the final culprit. At this point, we could remove that hint, prove an alternate version of the key lemma [rewr], or come up with some other remedy. Fixing this kind of problem tends to be relatively easy once the problem is revealed. *)
516
517 Abort.
518
519 (** printing * $\times$ *)
520
404 Section slow. 521 Section slow.
405 Hint Resolve trans_eq. 522 Hint Resolve trans_eq.
406 523
407 Variable A : Set. 524 Variable A : Set.
408 Variables P Q R S : A -> A -> Prop. 525 Variables P Q R S : A -> A -> Prop.