(** * Software Foundations, Formally Benjamin C. Pierce Version of 10/1/2007 Before handing in this file with your homework solutions, please fill in the names of all members of your group: FILL IN HERE Also, please tell us roughly how many person-hours you spent on this assignment (i.e., if you worked in a group, give us the SUM of the number of hours spent by each person individually). FILL IN HERE *) (* ====================================================================== *) (* LECTURE 8 *) (* Technical note: This proof script has finally gotten too big and unwieldy to keep in a single file. This file contains just this week's lectures. Material from all previous lectures is contained in the file [lec07.v] that was distributed last week. You should COMPILE this file (so that it can be loaded quickly) by typing the following command to your shell: coqc lec07.v This generates a file [lec07.vo], which can now be loaded into the working environment using the following command: *) Require Export lec07. (* ---------------------------------------------------------------------- *) (* A little more on induction principles *) (* The relation between [Inductive] definitions and the corresponding induction principles generated for them by Coq is somewhat complex to describe in full generality. It is not necessary to understand every detail, but let's discuss a few important points... The most typical example of an inductive definition is, of course, natural numbers: Inductive nat : Set := | O : nat | S : nat -> nat. The corresponding induction principle that is generated by Coq... nat_ind : forall P : nat -> Prop, P O -> (forall n : nat, P n -> P (S n)) -> forall n : nat, P n ... can be read as follows: - The induction principle can be used to prove assertions about numbers; the type [nat->Prop] of its first argument [P] captures this. - When the induction principle is applied, the result will be a proof that [P] holds of all numbers; the last line says this. - When the induction principle is applied to some [P], two subgoals are generated (one for each of the constructors of [nat]); these are the second and third lines. The inductive definition of polymorphic lists Inductive list (X:Set) : Set := | nil : list X | cons : X -> list X -> list X. is very similar. The main difference is that, here, the whole definition is PARAMTERIZED on a set [X] -- i.e., we are defining a FAMILY of inductive types [list X], one for each [X]. Note that, wherever [list] appears in the body of the declaration, it is always applied to the parameter [X]. The induction principle is likewise parameterized on [X]: list_ind : forall (X : Set) (P : list X -> Prop), P (nil X) -> (forall (x : X) (l : list X), P l -> P (x :: l)) -> forall l : list X, P l Note the wording here (and, accordingly, the form of [list_ind]): The WHOLE induction principle is parameterized on [X]. That is, [list_ind] can be thought of as a polymorphic function that, when applied to a set [X], gives us back an induction principle specialized to [list X]. *) (* THOUGHT EXERCISE (not to be handed in): Write out the induction principles that Coq will generate for the following definitions of inductive sets. Compare your answers with what Coq prints. *) Inductive rgb : Set := | red : rgb | green : rgb | blue : rgb. Check rgb_ind. Inductive tree (X:Set) : Set := | leaf : nat -> tree X | node : tree X -> tree X -> tree X. Check tree_ind. (* THOUGHT EXERCISE (not to be handed in): Find an inductive definition that gives rise to the following induction principle: mytype_ind : forall (X : Set) (P : mytype X -> Prop), (forall x : X, P (constr1 X x)) -> (forall n : nat, P (constr2 X n)) -> (forall m : mytype X, P m -> forall n : nat, P (constr3 X m n)) -> forall m : mytype X, P m *) (* THOUGHT EXERCISE (not to be handed in): Find an inductive definition that gives rise to the following induction principle: foo_ind : forall (X Y : Set) (P : foo X Y -> Prop), (forall x : X, P (bar X Y x)) -> (forall y : Y, P (baz X Y y)) -> (forall f1 : nat -> foo X Y, (forall n : nat, P (f1 n)) -> P (quux X Y f1)) -> forall f2 : foo X Y, P f2 *) (* Here is a more interesting inductively defined family of sets: Inductive vector (X:Set) : nat->Set := | Vnil : vector X zero | Vcons : forall n:nat, X -> vector X n -> vector X (S n). Given a set [X] and a natural number [n], the set [vector X n] describes lists of length [n] whose elements are drawn from the set [X]. Note that the numeric argument to [vector] is NOT a general parameter: it plays different roles in the two clauses (it is [zero] in the type of the constructor [Vnil] and [S n] in the type of [Vcons]). We call such an argument an INDEX of the inductive definition. Since it is not used uniformly, it cannot be written as a parameter to the whole inductive definition (as [X] is). Instead, it becomes part of the declared "result type" of the inductive definition (i.e., the result type is [nat->Set], not just [Set]). Thus, the first line of the declaration, [Inductive vector (X:Set) : nat->Set], can be read as, "For every set [X], declare a family of inductively defined sets (indexed by a [nat]) as follows..." Terminological note: Like [list], the type [vector] is parameterized -- it can be thought of as a function that, when applied to appropriate arguments, yields a set. Unlike [list], however, one of [vector]'s parameters is a VALUE, not just another set. Types like this -- i.e., families of types indexed by values -- are generally called DEPENDENT TYPES. Here is the induction principle that is generated for [vector]: vector_ind : forall (X : Set) (P : forall n : nat, vector X n -> Prop), P zero (Vnil X) -> (forall (n : nat) (x : X) (v : vector X n), P n v -> P (S n) (Vcons X n x v)) -> forall (n : nat) (v : vector X n), P n v. Note that the parameter [X] and the index [n] are treated differently: [X] becomes a parameter to the whole induction principle, while [n] becomes an argument to the proposition [P]. *) (* THOUGHT EXERCISE (not to be handed in): Here is a variant of the set [tree] defined above. For each natural number [n], the type [htree n] describes balanced trees of height exactly [n]. Write out the induction principle for [htree] and compare it with what Coq generates. *) Inductive htree (X:Set) : nat->Set := | hleaf : nat -> htree X zero | hnode : forall n:nat, htree X n -> htree X n -> htree X (S n). Check htree_ind. (* So far, the whole discussion applies to inductively defined SETS. Inductively defined PROPOSITIONS are handled a little differently. For example, from what we've said so far, you might expect the inductive definition of [evenI] Inductive evenI : nat -> Prop := | even_zero : evenI O | even_SS : forall n:nat, evenI n -> evenI (S (S n)). to give rise to an induction principle that looks like this... evenI_ind_max : forall P : (forall n : nat, evenI n -> Prop), P O even_zero -> (forall (n : nat) (e : evenI n), P n e -> P (S (S n)) (even_SS n e)) -> forall (n : nat) (e : evenI n), P n e ... because: - Since [evenI] is indexed by a number [n] (every [evenI] object [e] is a piece of evidence that some particular number [n] is even), the proposition [P] is parameterized by both [n] and [e] -- that is, the induction principle can be used to prove assertions involving both an even number and the evidence that it is even. - Since there are two ways of giving evidence of evenness ([evenI] has two constructors), applying the induction principle generates two subgoals: - We must prove that [P] holds for [O] and [even_zero]. - We must prove that, whenever [n] is an even number and [e] is evidence of its evenness, if [P] holds of [n] and [e], then it also holds of [S (S n)] and [even_SS n e]. - If these subgoals can be proved, then the induction principle tells us that [P] is true for ALL even numbers [n] and evidence [e] of their evenness. But this is a little more flexibility than we actually need or want: it is giving us a way to prove logical assertions about EVIDENCE of evenness, while all we really care about is proving properties of numbers that are even -- we interested in assertions about numbers, not about evidence. It would therefore be more convenient to have an induction principle for proving propositions [P] that are parameterized just by [n] and whose conclusion establishes [P] for all even numbers [n]: forall P : nat -> Prop, ... -> forall n : nat, evenI n -> P n For this reason, Coq actually generates the following simplified induction principle for [evenI]: evenI_ind : forall P : nat -> Prop, P O -> (forall n : nat, evenI n -> P n -> P (S (S n))) -> forall n : nat, evenI n -> P n Similarly, from the inductive definition of the proposition [and A B] Inductive and (A B : Prop) : Prop := conj : A -> B -> (and A B). we might expect Coq to generate this induction principle and_ind_max : forall (A B : Prop) (P : A /\ B -> Prop), (forall (a : A) (b : B), P (conj A B a b)) -> forall a : A /\ B, P a but actually it generates this simpler and more useful one: and_ind : forall A B P : Prop, (A -> B -> P) -> A /\ B -> P In the same way, when given the inductive definition of [or A B] Inductive or (A B : Prop) : Prop := | or_introl : A -> or A B | or_intror : B -> or A B. instead of the "maximal induction principle" or_ind_max : forall (A B : Prop) (P : A \/ B -> Prop), (forall a : A, P (or_introl A B a)) -> (forall b : B, P (or_intror A B b)) -> forall o : A \/ B, P o what Coq actually generates is this: or_ind : forall A B P : Prop, (A -> P) -> (B -> P) -> A \/ B -> P *) (* ---------------------------------------------------------------------- *) (* Relations as propositions *) (* A proposition parameterized over a number (like [evenI]) can be thought of as a PREDICATE -- i.e., the subset of [nat] for which the proposition is provable. A two-argument proposition can be thought of as a RELATION -- i.e., the set of pairs for which the proposition is provable. *) (* For example, here is the "less than or equal" relation on numbers. *) Inductive le (n:nat) : nat -> Prop := | le_n : le n n | le_S : forall m:nat, (le n m) -> (le n (S m)). Notation "m <= n" := (le m n). (* Note that the left-hand argument [n] to [le] is the same everywhere in the definition, so we've made it a general parameter. This leads to a simpler induction principle. *) (* THOUGHT EXERCISE: Print out the induction principle for [le] and check that you understand it. Then try redefining [le] with [n] as an index rather than a general parameter (i.e., write the first line as [Inductive le : nat -> nat -> Prop]) and check how the generated induction principle changes. *) (* Some sanity checks on the definition. (Notice that, although these are the same kind of simple "unit tests" as we gave for the testing functions we wrote in the first few lectures, we must construct their proofs explicitly -- [simpl] doesn't do the job for us. *) Lemma check_le1 : three <= three. Proof. apply le_n. Qed. Lemma check_le2 : three <= six. Proof. apply le_S. apply le_S. apply le_S. apply le_n. Qed. Lemma check_le3 : ~ (two <= one). Proof. intros H. inversion H. inversion H1. Qed. (* The "strictly less than" relation [n < m] can now be defined on top of [le]. *) Definition lt (n m:nat) := le (S n) m. Notation "m < n" := (lt m n). (* Here are a few more simple relations on numbers *) Inductive square_of : nat -> nat -> Prop := sq : forall n:nat, square_of n (times n n). Inductive next_nat (n:nat) : nat -> Prop := | nn : next_nat n (S n). Inductive next_even (n:nat) : nat -> Prop := | ne_1 : evenI (S n) -> next_even n (S n) | ne_2 : evenI (S (S n)) -> next_even n (S (S n)). (* EXERCISE: define an inductive relation [total_relation] that holds between every pair of natural numbers. *) (* FILL IN HERE *) (* EXERCISE: define an inductive relation [empty_relation] (on numbers) that never holds. *) (* FILL IN HERE *) (* ---------------------------------------------------------------------- *) (* Relations, in general *) (* We've now defined a few particular relations. As you may remember from an undergraduate discrete math course, there are a lot of ways of discussing and describing relations *in general* -- ways of classifying relations (are they reflexive, transitive, etc.), theorems that can be proved generically about classes of relations, constructions that build one relation from another, etc. Let us pause here to review a few of these that will be useful in what follows. *) (* A RELATION on a set [X] is a proposition parameterized by two [X]s -- i.e., it is a logical assertion involving two values from the set [X]. *) Definition relation (X: Set) := X->X->Prop. (* A relation [R] on a set [X] is a PARTIAL FUNCTION if, for every [x : X], there is at most one [y] such that [R x y] -- or, to put it differently, if [R x y1] and [R x y2] together imply [y1 = y2]. *) Definition partial_function (X: Set) (R: relation X) := forall x y1 y2 : X, R x y1 -> R x y2 -> y1 = y2. Lemma le_not_a_partial_function : ~ (partial_function _ le). Proof. unfold not. unfold partial_function. intros H. assert (zero <= one) as A01. Case "Proof of assertion". apply le_S. apply le_n. assert (zero <= two) as A02. Case "Proof of assertion". apply le_S. apply le_S. apply le_n. assert (one = two) as Nonsense. Case "Proof of assertion". apply H with (x:=zero) (y1:=one) (y2:=two). apply A01. apply A02. inversion Nonsense. Qed. (* EXERCISE: Show that the [total_relation] you defined above is not a partial function, but that [empty_relation] is. *) (* FILL IN HERE *) Definition reflexive (X: Set) (R: relation X) := forall a : X, R a a. Lemma le_reflexive : reflexive _ le. Proof. unfold reflexive. intros n. apply le_n. Qed. Definition symmetric (X: Set) (R: relation X) := forall a b : X, (R a b) -> (R b a). Lemma le_not_symmetric : ~ (symmetric _ le). Proof. (* FILL IN HERE (and delete "Admitted") *) Admitted. Definition antisymmetric (X: Set) (R: relation X) := forall a b : X, (R a b) -> (R b a) -> a = b. Lemma le_antisymmetric : antisymmetric _ le. Proof. (* FILL IN HERE (and delete "Admitted") *) Admitted. Definition transitive (X: Set) (R: relation X) := forall a b c : X, (R a b) -> (R b c) -> (R a c). Lemma le_transitive : transitive _ le. Proof. intros m n o Hmn Hno. induction Hno. apply Hmn. apply le_S. apply IHHno. Qed. Lemma lt_transitive : transitive _ lt. Proof. (* Prove this by induction on evidence that [n] is less than [o] *) unfold lt. unfold transitive. intros m n o Hmn Hno. induction Hno. (* FILL IN HERE (and delete "Admitted") *) Admitted. Lemma lt_transitive' : transitive _ lt. Proof. (* Prove the same thing again by induction on [o] *) unfold lt. unfold transitive. intros m n o Hmn Hno. induction o. (* FILL IN HERE (and delete "Admitted") *) Admitted. Definition equivalence (X:Set) (R: relation X) := (reflexive _ R) /\ (symmetric _ R) /\ (transitive _ R). Definition partial_order (X:Set) (R: relation X) := (reflexive _ R) /\ (antisymmetric _ R) /\ (transitive _ R). Definition preorder (X:Set) (R: relation X) := (reflexive _ R) /\ (transitive _ R). Lemma le_preorder : preorder _ le. Proof. unfold preorder. apply conj. Case "refl". apply le_reflexive. Case "trans". apply le_transitive. Qed. Inductive refl_trans_closure (X:Set) (R: relation X) : X -> X -> Prop := | rtc_R : forall (x y : X), R x y -> refl_trans_closure X R x y | rtc_refl : forall (x : X), refl_trans_closure X R x x | rtc_trans : forall (x y z : X), refl_trans_closure X R x y -> refl_trans_closure X R y z -> refl_trans_closure X R x z. Definition preserves (X: Set) (R: relation X) (P: X->Prop) := forall (x y : X), P x -> R x y -> P y. Lemma rtc_preserves : forall (X: Set) (R: relation X) (P: X->Prop), preserves _ R P -> preserves _ (refl_trans_closure _ R) P. Proof. (* FILL IN HERE (and delete "Admitted") *) Admitted. (* ---------------------------------------------------------------------- *) (* Operational semantics *) Module SimpleArithEval. Import SimpleArith. Export SimpleArith. Inductive eval : tm -> tm -> Prop := | E_PlusConstConst : forall n1 n2, eval (tm_plus (tm_const n1) (tm_const n2)) (tm_const (plus n1 n2)) | E_Plus1 : forall t1 t1' t2, (eval t1 t1') -> eval (tm_plus t1 t2) (tm_plus t1' t2) | E_Plus2 : forall n1 t2 t2', (eval t2 t2') -> eval (tm_plus (tm_const n1) t2) (tm_plus (tm_const n1) t2'). (* THOUGHT EXERCISE: What induction principle is generated for [eval]? *) (* Formally, [Theorem] means the same as [Lemma]. Calling something a [Theorem] is a signal to the reader that the assertion being proved is a particularly important or interesting one. *) Theorem eval_preserves_interp : forall t t', eval t t' -> interp t = interp t'. Proof. intros t t' E. induction E. Case "E_PlusConstConst". reflexivity. Case "EPlus1". simpl. rewrite -> IHE. reflexivity. Case "E_Plus2". simpl. rewrite -> IHE. reflexivity. Qed. (* OPTIONAL EXERCISE: Is the word "preserves" in the name of this lemma being used in precisely the same sense as we did earlier? That is, can the statement of the lemma be written using the formal term [preserves] that we defined above? If yes, do so and provide a proof. If no, explain why not. *) Definition deterministic (X: Set) (R: relation X) := partial_function X R. Theorem eval_deterministic : deterministic _ eval. Proof. unfold deterministic. unfold partial_function. intros x y1 y2 Hy1 Hy2. generalize dependent y2. induction Hy1. Case "E_PlusConstConst". intros y2 Hy2. inversion Hy2. Case "E_PlusConstConst". reflexivity. Case "E_Plus1". inversion H2. Case "E_Plus2". inversion H2. Case "E_Plus1". intros y2 Hy2. inversion Hy2. Case "E_PlusConstConst". rewrite <- H0 in Hy1. inversion Hy1. Case "E_Plus1". assert (t1' = t1'0) as eq. Case "Proof of assertion". apply IHHy1. apply H2. rewrite <- eq. reflexivity. Case "E_Plus2". rewrite <- H in Hy1. inversion Hy1. Case "E_Plus2". intros y2 Hy2. inversion Hy2. Case "E_PlusConstConst". rewrite <- H1 in Hy1. inversion Hy1. Case "E_Plus1". inversion H2. Case "E_Plus2". assert (t2' = t2'0) as eq. Case "Proof of assertion". apply IHHy1. apply H2. rewrite <- eq. reflexivity. Qed. End SimpleArithEval.