Mercurial > cpdt > repo
comparison src/Match.v @ 370:549d604c3d16
Move exercises out of mainline book
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Fri, 02 Mar 2012 09:58:00 -0500 |
parents | 50e1d338728c |
children | b911d0df5eee |
comparison
equal
deleted
inserted
replaced
369:4550dedad73a | 370:549d604c3d16 |
---|---|
998 Theorem t9 : exists p : nat * nat, fst p = 3. | 998 Theorem t9 : exists p : nat * nat, fst p = 3. |
999 econstructor; match goal with | 999 econstructor; match goal with |
1000 | [ |- fst ?x = 3 ] => equate x (3, 2) | 1000 | [ |- fst ?x = 3 ] => equate x (3, 2) |
1001 end; reflexivity. | 1001 end; reflexivity. |
1002 Qed. | 1002 Qed. |
1003 | |
1004 | |
1005 (* begin thide *) | |
1006 (** * Exercises *) | |
1007 | |
1008 (** %\begin{enumerate}%#<ol># | |
1009 | |
1010 %\item%#<li># An anonymous Coq fan from the Internet was excited to come up with this tactic definition shortly after getting started learning Ltac: *) | |
1011 | |
1012 Ltac deSome := | |
1013 match goal with | |
1014 | [ H : Some _ = Some _ |- _ ] => injection H; clear H; intros; subst; deSome | |
1015 | _ => reflexivity | |
1016 end. | |
1017 | |
1018 (** Without lifting a finger, exciting theorems can be proved: *) | |
1019 | |
1020 Theorem test : forall (a b c d e f g : nat), | |
1021 Some a = Some b | |
1022 -> Some b = Some c | |
1023 -> Some e = Some c | |
1024 -> Some f = Some g | |
1025 -> c = a. | |
1026 intros; deSome. | |
1027 Qed. | |
1028 | |
1029 (** Unfortunately, this tactic exhibits some degenerate behavior. Consider the following example: *) | |
1030 | |
1031 Theorem test2 : forall (a x1 y1 x2 y2 x3 y3 x4 y4 x5 y5 x6 y6 : nat), | |
1032 Some x1 = Some y1 | |
1033 -> Some x2 = Some y2 | |
1034 -> Some x3 = Some y3 | |
1035 -> Some x4 = Some y4 | |
1036 -> Some x5 = Some y5 | |
1037 -> Some x6 = Some y6 | |
1038 -> Some a = Some a | |
1039 -> x1 = x2. | |
1040 intros. | |
1041 Time try deSome. | |
1042 Abort. | |
1043 | |
1044 (* begin hide *) | |
1045 Reset test. | |
1046 (* end hide *) | |
1047 | |
1048 (** This (failed) proof already takes about one second on my workstation. I hope a pattern in the theorem statement is clear; this is a representative of a class of theorems, where we may add more matched pairs of [x] and [y] variables, with equality hypotheses between them. The running time of [deSome] is exponential in the number of such hypotheses. | |
1049 | |
1050 The task in this exercise is twofold. First, figure out why [deSome] exhibits exponential behavior for this class of examples and record your explanation in a comment. Second, write an improved version of [deSome] that runs in polynomial time.#</li># | |
1051 | |
1052 %\item%#<li># Sometimes it can be convenient to know that a proof attempt is doomed because the theorem is false. For instance, here are three non-theorems about lists: *) | |
1053 | |
1054 Theorem test1 : forall A (ls1 ls2 : list A), ls1 ++ ls2 = ls2 ++ ls1. | |
1055 (* begin hide *) | |
1056 Abort. | |
1057 (* end hide *) | |
1058 | |
1059 Theorem test2 : forall A (ls1 ls2 : list A), length (ls1 ++ ls2) = length ls1 - length ls2. | |
1060 (* begin hide *) | |
1061 Abort. | |
1062 (* end hide *) | |
1063 | |
1064 Theorem test3 : forall A (ls : list A), length (rev ls) - 3 = 0. | |
1065 (* begin hide *) | |
1066 Abort. | |
1067 (* end hide *) | |
1068 | |
1069 (** The task in this exercise is to write a tactic that disproves these and many other related %``%#"#theorems#"#%''% about lists. Your tactic should follow a simple brute-force enumeration strategy, considering all [list bool] values with length up to some bound given by the user, as a [nat] argument to the tactic. A successful invocation should add a new hypothesis of the negation of the theorem (guaranteeing that the tactic has made a sound decision about falsehood). | |
1070 | |
1071 A few hints: A good starting point is to pattern-match the conclusion formula and use the [assert] tactic on its negation. An [assert] invocation may include a [by] clause to specify a tactic to use to prove the assertion. | |
1072 | |
1073 The idea in this exercise is to disprove a quantified formula by finding instantiations for the quantifiers that make it manifestly false. Recall the [specialize] tactic for specializing a hypothesis to particular quantifier instantiations. When you have instantiated quantifiers fully, [discriminate] is a good choice to derive a contradiction. (It at least works for the three examples above and is smart enough for this exercise's purposes.) The [type of] Ltac construct may be useful to analyze the type of a hypothesis to choose how to instantiate its quantifiers. | |
1074 | |
1075 To enumerate all boolean lists up to a certain length, it will be helpful to write a recursive tactic in continuation-passing style, where the continuation is meant to be called on each candidate list. | |
1076 | |
1077 Remember that arguments to Ltac functions may not be type-checked in contexts large enough to allow usual implicit argument inference, so instead of [nil] it will be useful to write [@][nil bool], which specifies the usually implicit argument explicitly. | |
1078 | |
1079 %\item%#<li># Some theorems involving existential quantifiers are easy to prove with [eauto]. *) | |
1080 | |
1081 Theorem test1 : exists x, x = 0. | |
1082 eauto. | |
1083 Qed. | |
1084 | |
1085 (** Others are harder. The problem with the next theorem is that the existentially quantified variable does not appear in the rest of the theorem, so [eauto] has no way to deduce its value. However, we know that we had might as well instantiate that variable to [tt], the only value of type [unit]. *) | |
1086 | |
1087 Theorem test2 : exists x : unit, 0 = 0. | |
1088 (* begin hide *) | |
1089 eauto. | |
1090 Abort. | |
1091 (* end hide *) | |
1092 | |
1093 (** We also run into trouble in the next theorem, because [eauto] does not understand the [fst] and [snd] projection functions for pairs. *) | |
1094 | |
1095 Theorem test3 : exists x : nat * nat, fst x = 7 /\ snd x = 2 + fst x. | |
1096 (* begin hide *) | |
1097 eauto. | |
1098 Abort. | |
1099 (* end hide *) | |
1100 | |
1101 (** Both problems show up in this monster example. *) | |
1102 | |
1103 Theorem test4 : exists x : (unit * nat) * (nat * bool), | |
1104 snd (fst x) = 7 /\ fst (snd x) = 2 + snd (fst x) /\ snd (snd x) = true. | |
1105 (* begin hide *) | |
1106 eauto. | |
1107 Abort. | |
1108 (* end hide *) | |
1109 | |
1110 (** The task in this problem is to write a tactic that preprocesses such goals so that [eauto] can finish them. Your tactic should serve as a complete proof of each of the above examples, along with the wide class of similar examples. The key smarts that your tactic will bring are: first, it introduces separate unification variables for all the %``%#"#leaf types#"#%''% of compound types built out of pairs; and second, leaf unification variables of type [unit] are simply replaced by [tt]. | |
1111 | |
1112 A few hints: The following tactic is more convenient than direct use of the built-in tactic [evar], for generation of new unification variables: *) | |
1113 | |
1114 Ltac makeEvar T k := let x := fresh in | |
1115 evar (x : T); let y := eval unfold x in x in clear x; k y. | |
1116 | |
1117 (** remove printing exists *) | |
1118 | |
1119 (** This is a continuation-passing style tactic. For instance, when the goal begins with existential quantification over a type [T], the following tactic invocation will create a new unification variable to use as the quantifier instantiation: | |
1120 | |
1121 [makeEvar T ltac:(][fun x => exists x)] *) | |
1122 | |
1123 (** printing exists $\exists$ *) | |
1124 | |
1125 (** Recall that [exists] formulas are desugared to uses of the [ex] inductive family. In particular, a pattern like the following can be used to extract the domain of an [exists] quantifier into variable [T]: | |
1126 | |
1127 [| ]#[#%[%[ |- ex (][A := ?][T) _ ]#]#%]%[ => ...] | |
1128 | |
1129 The [equate] tactic used as an example in this chapter will probably be useful, to unify two terms, for instance if the first is a unification variable whose value you want to set. | |
1130 [[ | |
1131 Ltac equate E1 E2 := let H := fresh in | |
1132 assert (H : E1 = E2) by reflexivity; clear H. | |
1133 ]] | |
1134 | |
1135 Finally, there are some minor complications surrounding overloading of the [*] operator for both numeric multiplication and Cartesian product for sets (i.e., pair types). To ensure that an Ltac pattern is using the type version, write it like this: | |
1136 | |
1137 [| (?T1 * ?T2)%][type => ...]#</li># | |
1138 | |
1139 %\item%#<li># An exercise in the last chapter dealt with automating proofs about rings using [eauto], where we must prove some odd-looking theorems to push proof search in a direction where unification does all the work. Algebraic proofs consist mostly of rewriting in equations, so we might hope that the [autorewrite] tactic would yield more natural automated proofs. Indeed, consider this example within the same formulation of ring theory that we dealt with last chapter, where each of the three axioms has been added to the rewrite hint database [cpdt] using [Hint Rewrite]: | |
1140 [[ | |
1141 Theorem test1 : forall a b, a * b * i b = a. | |
1142 intros; autorewrite with cpdt; reflexivity. | |
1143 Qed. | |
1144 ]] | |
1145 | |
1146 So far so good. However, consider this further example: | |
1147 [[ | |
1148 Theorem test2 : forall a, a * e * i a * i e = e. | |
1149 intros; autorewrite with cpdt. | |
1150 ]] | |
1151 | |
1152 The goal is merely reduced to [a * (][i a * i e) = e], which of course [reflexivity] cannot prove. The essential problem is that [autorewrite] does not do backtracking search. Instead, it follows a %``%#"#greedy#"#%''% approach, at each stage choosing a rewrite to perform and then never allowing that rewrite to be undone. An early mistake can doom the whole process. | |
1153 | |
1154 The task in this problem is to use Ltac to implement a backtracking version of [autorewrite] that works much like [eauto], in that its inputs are a database of hint lemmas and a bound on search depth. Here our search trees will have uses of [rewrite] at their nodes, rather than uses of [eapply] as in the case of [eauto], and proofs must be finished by [reflexivity]. | |
1155 | |
1156 An invocation to the tactic to prove [test2] might look like this: | |
1157 [[ | |
1158 rewriter (right_identity, (right_inverse, tt)) 3. | |
1159 ]] | |
1160 | |
1161 The first argument gives the set of lemmas to consider, as a kind of list encoded with pair types. Such a format cannot be analyzed directly by Gallina programs, but Ltac allows us much more freedom to deconstruct syntax. For example, to case analyze such a list found in a variable [x], we need only write: | |
1162 [[ | |
1163 match x with | |
1164 | (?lemma, ?more) => ... | |
1165 end | |
1166 ]] | |
1167 | |
1168 In the body of the case analysis, [lemma] will be bound to the first lemma, and [more] will be bound to the remaining lemmas. There is no need to consider a case for [tt], our stand-in for [nil]. This is because lack of any matching pattern will trigger failure, which is exactly the outcome we would like upon reaching the end of the lemma list without finding one that applies. The tactic will fail, triggering backtracking to some previous [match]. | |
1169 | |
1170 There are different kinds of backtracking, corresponding to different sorts of decisions to be made. The examples considered above can be handled with backtracking that only reconsiders decisions about the order in which to apply rewriting lemmas. A full-credit solution need only handle that kind of backtracking, considering all rewriting sequences up to the length bound passed to your tactic. A good test of this level of applicability is to prove both [test1] and [test2] above. However, some theorems could only be proved using a smarter tactic that considers not only order of rewriting lemma uses, but also choice of arguments to the lemmas. That is, at some points in a proof, the same lemma may apply at multiple places within the goal formula, and some choices may lead to stuck proof states while others lead to success. For an extra challenge (without any impact on the grade for the problem), you might try beefing up your tactic to do backtracking on argument choice, too.#</li># | |
1171 | |
1172 #</ol>#%\end{enumerate}% *) | |
1173 (* end thide *) |