comparison src/Predicates.v @ 52:ce0c9d481ee3

What could go wrong; some exercises
author Adam Chlipala <adamc@hcoop.net>
date Sun, 28 Sep 2008 12:42:59 -0400
parents a21eb02cc7c6
children 422865e240b1
comparison
equal deleted inserted replaced
50:a21eb02cc7c6 52:ce0c9d481ee3
209 209
210 (* begin hide *) 210 (* begin hide *)
211 (* In-class exercises *) 211 (* In-class exercises *)
212 212
213 Theorem contra : P -> ~P -> R. 213 Theorem contra : P -> ~P -> R.
214 (* begin thide *)
215 unfold not.
216 intros.
217 elimtype False.
218 apply H0.
219 assumption.
220 (* end thide *)
214 Admitted. 221 Admitted.
215 222
216 Theorem and_assoc : (P /\ Q) /\ R -> P /\ (Q /\ R). 223 Theorem and_assoc : (P /\ Q) /\ R -> P /\ (Q /\ R).
224 (* begin thide *)
225 intros.
226 destruct H.
227 destruct H.
228 split.
229 assumption.
230 split.
231 assumption.
232 assumption.
233 (* end thide *)
217 Admitted. 234 Admitted.
218 235
219 Theorem or_assoc : (P \/ Q) \/ R -> P \/ (Q \/ R). 236 Theorem or_assoc : (P \/ Q) \/ R -> P \/ (Q \/ R).
237 (* begin thide *)
238 intros.
239 destruct H.
240 destruct H.
241 left.
242 assumption.
243 right.
244 left.
245 assumption.
246 right.
247 right.
248 assumption.
249 (* end thide *)
220 Admitted. 250 Admitted.
221 251
222 (* end hide *) 252 (* end hide *)
223 253
224 254
346 (* begin hide *) 376 (* begin hide *)
347 (* In-class exercises *) 377 (* In-class exercises *)
348 378
349 Theorem forall_exists_commute : forall (A B : Type) (P : A -> B -> Prop), 379 Theorem forall_exists_commute : forall (A B : Type) (P : A -> B -> Prop),
350 (exists x : A, forall y : B, P x y) -> (forall y : B, exists x : A, P x y). 380 (exists x : A, forall y : B, P x y) -> (forall y : B, exists x : A, P x y).
381 (* begin thide *)
382 intros.
383 destruct H.
384 exists x.
385 apply H.
386 (* end thide *)
351 Admitted. 387 Admitted.
352 388
353 (* end hide *) 389 (* end hide *)
354 390
355 391
435 471
436 (* begin hide *) 472 (* begin hide *)
437 (* In-class exercises *) 473 (* In-class exercises *)
438 474
439 (* EX: Define an inductive type capturing when a list has exactly two elements. Prove that your predicate does not hold of the empty list, and prove that, whenever it holds of a list, the length of that list is two. *) 475 (* EX: Define an inductive type capturing when a list has exactly two elements. Prove that your predicate does not hold of the empty list, and prove that, whenever it holds of a list, the length of that list is two. *)
476
477 (* begin thide *)
478 Section twoEls.
479 Variable A : Type.
480
481 Inductive twoEls : list A -> Prop :=
482 | TwoEls : forall x y, twoEls (x :: y :: nil).
483
484 Theorem twoEls_nil : twoEls nil -> False.
485 inversion 1.
486 Qed.
487
488 Theorem twoEls_two : forall ls, twoEls ls -> length ls = 2.
489 inversion 1.
490 reflexivity.
491 Qed.
492 End twoEls.
493 (* end thide *)
440 494
441 (* end hide *) 495 (* end hide *)
442 496
443 497
444 (** * Recursive Predicates *) 498 (** * Recursive Predicates *)
658 [crush] uses the tactic [intuition], which, when it runs out of tricks to try using only propositional logic, by default tries the tactic [auto], which we saw in an earlier example. [auto] attempts Prolog-style logic programming, searching through all proof trees up to a certain depth that are built only out of hints that have been registered with [Hint] commands. Compared to Prolog, [auto] places an important restriction: it never introduces new unification variables during search. That is, every time a rule is applied during proof search, all of its arguments must be deducible by studying the form of the goal. [eauto] relaxes this restriction, at the cost of possibly exponentially greater running time. In this particular case, we know that [eauto] has only a small space of proofs to search, so it makes sense to run it. It is common in effectively-automated Coq proofs to see a bag of standard tactics applied to pick off the "easy" subgoals, finishing off with [eauto] to handle the tricky parts that can benefit from ad-hoc exhaustive search. 712 [crush] uses the tactic [intuition], which, when it runs out of tricks to try using only propositional logic, by default tries the tactic [auto], which we saw in an earlier example. [auto] attempts Prolog-style logic programming, searching through all proof trees up to a certain depth that are built only out of hints that have been registered with [Hint] commands. Compared to Prolog, [auto] places an important restriction: it never introduces new unification variables during search. That is, every time a rule is applied during proof search, all of its arguments must be deducible by studying the form of the goal. [eauto] relaxes this restriction, at the cost of possibly exponentially greater running time. In this particular case, we know that [eauto] has only a small space of proofs to search, so it makes sense to run it. It is common in effectively-automated Coq proofs to see a bag of standard tactics applied to pick off the "easy" subgoals, finishing off with [eauto] to handle the tricky parts that can benefit from ad-hoc exhaustive search.
659 713
660 The original theorem now follows trivially from our lemma. *) 714 The original theorem now follows trivially from our lemma. *)
661 715
662 Theorem even_contra : forall n, even (S (n + n)) -> False. 716 Theorem even_contra : forall n, even (S (n + n)) -> False.
663 intros; apply even_contra' with (S (n + n)) n; trivial. 717 intros; eapply even_contra'; eauto.
664 Qed. 718 Qed.
719
720 (** We use a variant [eapply] of [apply] which has the same relationship to [apply] as [eauto] has to [auto]. [apply] only succeeds if all arguments to the rule being used can be determined from the form of the goal, whereas [eapply] will introduce unification variables for undetermined arguments. [eauto] is able to determine the right values for those unification variables.
721
722 By considering an alternate attempt at proving the lemma, we can see another common pitfall of inductive proofs in Coq. Imagine that we had tried to prove [even_contra'] with all of the [forall] quantifiers moved to the front of the lemma statement. *)
723
724 Lemma even_contra'' : forall n' n, even n' -> n' = S (n + n) -> False.
725 induction 1; crush;
726 match goal with
727 | [ H : S ?N = ?N0 + ?N0 |- _ ] => destruct N; destruct N0
728 end; crush; eauto.
729
730 (** One subgoal remains: *)
731
732 (** [[
733
734 n : nat
735 H : even (S (n + n))
736 IHeven : S (n + n) = S (S (S (n + n))) -> False
737 ============================
738 False
739 ]] *)
740
741 (** We are out of luck here. The inductive hypothesis is trivially true, since its assumption is false. In the version of this proof that succeeded, [IHeven] had an explicit quantification over [n]. This is because the quantification of [n] %\textit{%#<i>#appeared after the thing we are inducting on#</i>#%}% in the theorem statement. In general, quantified variables and hypotheses that appear before the induction object in the theorem statement stay fixed throughout the inductive proof. Variables and hypotheses that are quantified after the induction object may be varied explicitly in uses of inductive hypotheses.
742
743 Why should Coq implement [induction] this way? One answer is that it avoids burdening this basic tactic with additional heuristic smarts, but that is not the whole picture. Imagine that [induction] analyzed dependencies among variables and reordered quantifiers to preserve as much freedom as possible in later uses of inductive hypotheses. This could make the inductive hypotheses more complex, which could in turn cause particular automation machinery to fail when it would have succeeded before. In general, we want to avoid quantifiers in our proofs whenever we can, and that goal is furthered by the refactoring that the [induction] tactic forces us to do. *)
744
745
746 (* begin hide *)
747 (* In-class exercises *)
748
749 (* EX: Define a type [prop] of simple boolean formulas made up only of truth, falsehood, binary conjunction, and binary disjunction. Define an inductive predicate [holds] that captures when [prop]s are valid, and define a predicate [falseFree] that captures when a [prop] does not contain the "false" formula. Prove that every false-free [prop] is valid. *)
750
751 (* begin thide *)
752 Inductive prop : Set :=
753 | Tru : prop
754 | Fals : prop
755 | And : prop -> prop -> prop
756 | Or : prop -> prop -> prop.
757
758 Inductive holds : prop -> Prop :=
759 | HTru : holds Tru
760 | HAnd : forall p1 p2, holds p1 -> holds p2 -> holds (And p1 p2)
761 | HOr1 : forall p1 p2, holds p1 -> holds (Or p1 p2)
762 | HOr2 : forall p1 p2, holds p2 -> holds (Or p1 p2).
763
764 Inductive falseFree : prop -> Prop :=
765 | FFTru : falseFree Tru
766 | FFAnd : forall p1 p2, falseFree p1 -> falseFree p2 -> falseFree (And p1 p2)
767 | FFNot : forall p1 p2, falseFree p1 -> falseFree p2 -> falseFree (Or p1 p2).
768
769 Hint Constructors holds.
770
771 Theorem falseFree_holds : forall p, falseFree p -> holds p.
772 induction 1; crush.
773 Qed.
774 (* end thide *)
775
776
777 (* EX: Define an inductive type [prop'] that is the same as [prop] but omits the possibility for falsehood. Define a proposition [holds'] for [prop'] that is analogous to [holds]. Define a function [propify] for translating [prop']s to [prop]s. Prove that, for any [prop'] [p], if [propify p] is valid, then so is [p]. *)
778
779 (* begin thide *)
780 Inductive prop' : Set :=
781 | Tru' : prop'
782 | And' : prop' -> prop' -> prop'
783 | Or' : prop' -> prop' -> prop'.
784
785 Inductive holds' : prop' -> Prop :=
786 | HTru' : holds' Tru'
787 | HAnd' : forall p1 p2, holds' p1 -> holds' p2 -> holds' (And' p1 p2)
788 | HOr1' : forall p1 p2, holds' p1 -> holds' (Or' p1 p2)
789 | HOr2' : forall p1 p2, holds' p2 -> holds' (Or' p1 p2).
790
791 Fixpoint propify (p : prop') : prop :=
792 match p with
793 | Tru' => Tru
794 | And' p1 p2 => And (propify p1) (propify p2)
795 | Or' p1 p2 => Or (propify p1) (propify p2)
796 end.
797
798 Hint Constructors holds'.
799
800 Lemma propify_holds' : forall p', holds p' -> forall p, p' = propify p -> holds' p.
801 induction 1; crush; destruct p; crush.
802 Qed.
803
804 Theorem propify_holds : forall p, holds (propify p) -> holds' p.
805 intros; eapply propify_holds'; eauto.
806 Qed.
807 (* end thide *)
808
809 (* end hide *)