├── .gitignore ├── AbstractInterpret.v ├── AbstractInterpretation.v ├── BasicSyntax.v ├── BasicSyntax_template.v ├── CompilerCorrectness.v ├── CompilerCorrectness_template.v ├── ConcurrentSeparationLogic.v ├── ConcurrentSeparationLogic_template.v ├── Connecting.v ├── DataAbstraction.v ├── DataAbstraction_template.v ├── DeepAndShallowEmbeddings.v ├── DeepAndShallowEmbeddings_template.v ├── DeepInterp.ml ├── DeeperInterp.ml ├── DeeperWithFailInterp.ml ├── DependentInductiveTypes.v ├── DependentInductiveTypes_template.v ├── EvaluationContexts.v ├── EvaluationContexts_template.v ├── FirstClassFunctions.v ├── FirstClassFunctions_template.v ├── Frap.v ├── FrapWithoutSets.v ├── HoareLogic.v ├── HoareLogic_template.v ├── Imp.v ├── Interpreters.v ├── Interpreters_template.v ├── IntroToProofScripting.v ├── IntroToProofScripting_template.v ├── Invariant.v ├── LICENSE ├── LambdaCalculusAndTypeSoundness.v ├── LambdaCalculusAndTypeSoundness_template.v ├── LogicProgramming.v ├── LogicProgramming_template.v ├── Makefile ├── Makefile.fraplib ├── Map.v ├── MessagesAndRefinement.v ├── ModelCheck.v ├── ModelChecking.v ├── ModelChecking_sol.v ├── ModelChecking_template.v ├── OperationalSemantics.v ├── OperationalSemantics_template.v ├── Polymorphism.v ├── Polymorphism_template.v ├── ProgramDerivation.v ├── ProgramDerivation_template.v ├── ProofByReflection.v ├── ProofByReflection_template.v ├── README.md ├── Relations.v ├── RuleInduction.v ├── RuleInduction_template.v ├── SepCancel.v ├── SeparationLogic.v ├── SeparationLogic_template.v ├── SessionTypes.v ├── Sets.v ├── SharedMemory.v ├── SubsetTypes.v ├── SubsetTypes_template.v ├── TransitionSystems.v ├── TransitionSystems_template.v ├── TypesAndMutation.v ├── Var.v ├── _CoqProject ├── _CoqProject.fraplib ├── frap_book.tex └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.aux 3 | *.idx 4 | *.log 5 | *.out 6 | *.pdf 7 | *.toc 8 | *.bbl 9 | *.blg 10 | *.ilg 11 | *.ind 12 | Makefile.coq 13 | Makefile.coq.conf 14 | *.glob 15 | *.d 16 | *.vo 17 | *.vok 18 | *.vos 19 | frap.tgz 20 | .coq-native 21 | Deep.ml* 22 | Deeper.ml* 23 | DeeperWithFail.ml* 24 | *.dir-locals.el 25 | *.cache 26 | fraplib 27 | fraplib.tgz 28 | -------------------------------------------------------------------------------- /BasicSyntax_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | (* The following definition closely mirrors a standard BNF grammar for expressions. 4 | * It defines abstract syntax trees of arithmetic expressions. *) 5 | Inductive arith : Set := 6 | | Const (n : nat) 7 | | Plus (e1 e2 : arith) 8 | | Times (e1 e2 : arith). 9 | 10 | (* Here are a few examples of specific expressions. *) 11 | Example ex1 := Const 42. 12 | Example ex2 := Plus (Const 1) (Times (Const 2) (Const 3)). 13 | 14 | (* How many nodes appear in the tree for an expression? *) 15 | Fixpoint size (e : arith) : nat := 16 | match e with 17 | | Const _ => 1 18 | | Plus e1 e2 => 1 + size e1 + size e2 19 | | Times e1 e2 => 1 + size e1 + size e2 20 | end. 21 | 22 | (* Here's how to run a program (evaluate a term) in Coq. *) 23 | Compute size ex1. 24 | Compute size ex2. 25 | 26 | (* What's the longest path from the root of a syntax tree to a leaf? *) 27 | Fixpoint depth (e : arith) : nat := 28 | match e with 29 | | Const _ => 1 30 | | Plus e1 e2 => 1 + max (depth e1) (depth e2) 31 | | Times e1 e2 => 1 + max (depth e1) (depth e2) 32 | end. 33 | 34 | Compute depth ex1. 35 | Compute depth ex2. 36 | 37 | (* Our first proof! 38 | * Size is an upper bound on depth. *) 39 | Theorem depth_le_size : forall e, depth e <= size e. 40 | Proof. 41 | Admitted. 42 | 43 | (* A silly recursive function: swap the operand orders of all binary operators. *) 44 | Fixpoint commuter (e : arith) : arith := 45 | match e with 46 | | Const _ => e 47 | | Plus e1 e2 => Plus (commuter e2) (commuter e1) 48 | | Times e1 e2 => Times (commuter e2) (commuter e1) 49 | end. 50 | 51 | Compute commuter ex1. 52 | Compute commuter ex2. 53 | 54 | (* [commuter] has all the appropriate interactions with other functions (and itself). *) 55 | 56 | Theorem size_commuter : forall e, size (commuter e) = size e. 57 | Proof. 58 | Admitted. 59 | 60 | Theorem depth_commuter : forall e, depth (commuter e) = depth e. 61 | Proof. 62 | Admitted. 63 | 64 | Theorem commuter_inverse : forall e, commuter (commuter e) = e. 65 | Proof. 66 | Admitted. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | (* Now we go back and add this constructor to [arith]: 86 | << 87 | | Var (x : var) 88 | >> 89 | 90 | (* Now that we have variables, we can consider new operations, 91 | * like substituting an expression for a variable. *) 92 | Fixpoint substitute (inThis : arith) (replaceThis : var) (withThis : arith) : arith := 93 | match inThis with 94 | | Const _ => inThis 95 | | Var x => if x ==v replaceThis then withThis else inThis 96 | | Plus e1 e2 => Plus (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 97 | | Times e1 e2 => Times (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 98 | end. 99 | 100 | (* An intuitive property about how much [substitute] might increase depth. *) 101 | Theorem substitute_depth : forall replaceThis withThis inThis, 102 | depth (substitute inThis replaceThis withThis) <= depth inThis + depth withThis. 103 | Proof. 104 | admit. 105 | Qed. 106 | 107 | (* A silly self-substitution has no effect. *) 108 | Theorem substitute_self : forall replaceThis inThis, 109 | substitute inThis replaceThis (Var replaceThis) = inThis. 110 | Proof. 111 | admit. 112 | Qed. 113 | 114 | (* We can do substitution and commuting in either order. *) 115 | Theorem substitute_commuter : forall replaceThis withThis inThis, 116 | commuter (substitute inThis replaceThis withThis) 117 | = substitute (commuter inThis) replaceThis (commuter withThis). 118 | Proof. 119 | admit. 120 | Qed. 121 | 122 | (* *Constant folding* is one of the classic compiler optimizations. 123 | * We repeatedly find opportunities to replace fancier expressions 124 | * with known constant values. *) 125 | Fixpoint constantFold (e : arith) : arith := 126 | match e with 127 | | Const _ => e 128 | | Var _ => e 129 | | Plus e1 e2 => 130 | let e1' := constantFold e1 in 131 | let e2' := constantFold e2 in 132 | match e1', e2' with 133 | | Const n1, Const n2 => Const (n1 + n2) 134 | | Const 0, _ => e2' 135 | | _, Const 0 => e1' 136 | | _, _ => Plus e1' e2' 137 | end 138 | | Times e1 e2 => 139 | let e1' := constantFold e1 in 140 | let e2' := constantFold e2 in 141 | match e1', e2' with 142 | | Const n1, Const n2 => Const (n1 * n2) 143 | | Const 1, _ => e2' 144 | | _, Const 1 => e1' 145 | | Const 0, _ => Const 0 146 | | _, Const 0 => Const 0 147 | | _, _ => Times e1' e2' 148 | end 149 | end. 150 | 151 | (* This is supposed to be an *optimization*, so it had better not *increase* 152 | * the size of an expression! *) 153 | Theorem size_constantFold : forall e, size (constantFold e) <= size e. 154 | Proof. 155 | admit. 156 | Qed. 157 | 158 | (* Business as usual, with another commuting law *) 159 | Theorem commuter_constantFold : forall e, commuter (constantFold e) = constantFold (commuter e). 160 | Proof. 161 | admit. 162 | Qed. 163 | 164 | (* To define a further transformation, we first write a roundabout way of 165 | * testing whether an expression is a constant. *) 166 | Definition isConst (e : arith) : option nat := 167 | match e with 168 | | Const n => Some n 169 | | _ => None 170 | end. 171 | 172 | (* Our next target is a function that finds multiplications by constants 173 | * and pushes the multiplications to the leaves of syntax trees. 174 | * This helper function takes a coefficient [multiplyBy] that should be 175 | * applied to an expression. *) 176 | Fixpoint pushMultiplicationInside' (multiplyBy : nat) (e : arith) : arith := 177 | match e with 178 | | Const n => Const (multiplyBy * n) 179 | | Var _ => Times (Const multiplyBy) e 180 | | Plus e1 e2 => Plus (pushMultiplicationInside' multiplyBy e1) 181 | (pushMultiplicationInside' multiplyBy e2) 182 | | Times e1 e2 => 183 | match isConst e1 with 184 | | Some k => pushMultiplicationInside' (k * multiplyBy) e2 185 | | None => Times (pushMultiplicationInside' multiplyBy e1) e2 186 | end 187 | end. 188 | 189 | (* The overall transformation just fixes the initial coefficient as [1]. *) 190 | Definition pushMultiplicationInside (e : arith) : arith := 191 | pushMultiplicationInside' 1 e. 192 | 193 | (* Let's prove this boring arithmetic property, so that we may use it below. *) 194 | Lemma n_times_0 : forall n, n * 0 = 0. 195 | Proof. 196 | linear_arithmetic. 197 | Qed. 198 | 199 | (* A fun fact about pushing multiplication inside: 200 | * the coefficient has no effect on depth! 201 | * Let's show that any coefficient is equivalent to coefficient 0. *) 202 | Lemma depth_pushMultiplicationInside'_irrelevance0 : forall e multiplyBy, 203 | depth (pushMultiplicationInside' multiplyBy e) 204 | = depth (pushMultiplicationInside' 0 e). 205 | Proof. 206 | admit. 207 | Qed. 208 | 209 | (* Let's prove that pushing-inside has only a small effect on depth, 210 | * considering for now only coefficient 0. *) 211 | Lemma depth_pushMultiplicationInside' : forall e, 212 | depth (pushMultiplicationInside' 0 e) <= S (depth e). 213 | Proof. 214 | admit. 215 | Qed. 216 | 217 | Theorem depth_pushMultiplicationInside : forall e, 218 | depth (pushMultiplicationInside e) <= S (depth e). 219 | Proof. 220 | admit. 221 | Qed. 222 | *) 223 | -------------------------------------------------------------------------------- /DeepInterp.ml: -------------------------------------------------------------------------------- 1 | open Deep 2 | 3 | let rec i2n n = 4 | match n with 5 | | 0 -> O 6 | | _ -> S (i2n (n - 1)) 7 | 8 | let interp c = 9 | let h : (nat, nat) Hashtbl.t = Hashtbl.create 0 in 10 | Hashtbl.add h (i2n 0) (i2n 2); 11 | Hashtbl.add h (i2n 1) (i2n 1); 12 | Hashtbl.add h (i2n 2) (i2n 8); 13 | Hashtbl.add h (i2n 3) (i2n 6); 14 | 15 | let rec interp' (c : 'a cmd) : 'a = 16 | match c with 17 | | Return v -> v 18 | | Bind (c1, c2) -> interp' (c2 (interp' c1)) 19 | | Read a -> 20 | Obj.magic (try 21 | Hashtbl.find h a 22 | with Not_found -> O) 23 | | Write (a, v) -> Obj.magic (Hashtbl.replace h a v) 24 | 25 | in h, interp' c 26 | -------------------------------------------------------------------------------- /DeeperInterp.ml: -------------------------------------------------------------------------------- 1 | open Deeper 2 | 3 | let rec i2n n = 4 | match n with 5 | | 0 -> O 6 | | _ -> S (i2n (n - 1)) 7 | 8 | let interp c = 9 | let h : (nat, nat) Hashtbl.t = Hashtbl.create 0 in 10 | Hashtbl.add h (i2n 0) (i2n 2); 11 | Hashtbl.add h (i2n 1) (i2n 1); 12 | Hashtbl.add h (i2n 2) (i2n 8); 13 | Hashtbl.add h (i2n 3) (i2n 6); 14 | 15 | let rec interp' (c : 'a cmd) : 'a = 16 | match c with 17 | | Return v -> v 18 | | Bind (c1, c2) -> interp' (c2 (interp' c1)) 19 | | Read a -> 20 | Obj.magic (try 21 | Hashtbl.find h a 22 | with Not_found -> O) 23 | | Write (a, v) -> Obj.magic (Hashtbl.replace h a v) 24 | | Loop (i, b) -> 25 | match Obj.magic (interp' (Obj.magic (b i))) with 26 | | Done r -> r 27 | | Again r -> interp' (Loop (r, b)) 28 | 29 | in h, interp' c 30 | -------------------------------------------------------------------------------- /DeeperWithFailInterp.ml: -------------------------------------------------------------------------------- 1 | open DeeperWithFail 2 | 3 | let rec i2n n = 4 | match n with 5 | | 0 -> O 6 | | _ -> S (i2n (n - 1)) 7 | 8 | let interp c = 9 | let h : (nat, nat) Hashtbl.t = Hashtbl.create 0 in 10 | Hashtbl.add h (i2n 0) (i2n 2); 11 | Hashtbl.add h (i2n 1) (i2n 1); 12 | Hashtbl.add h (i2n 2) (i2n 8); 13 | Hashtbl.add h (i2n 3) (i2n 6); 14 | 15 | let rec interp' (c : 'a cmd) : 'a = 16 | match c with 17 | | Return v -> v 18 | | Bind (c1, c2) -> interp' (c2 (interp' c1)) 19 | | Read a -> 20 | Obj.magic (try 21 | Hashtbl.find h a 22 | with Not_found -> O) 23 | | Write (a, v) -> Obj.magic (Hashtbl.replace h a v) 24 | | Loop (i, b) -> 25 | begin match Obj.magic (interp' (Obj.magic (b i))) with 26 | | Done r -> r 27 | | Again r -> interp' (Loop (r, b)) 28 | end 29 | | Fail -> failwith "Fail" 30 | 31 | in h, interp' c 32 | -------------------------------------------------------------------------------- /Frap.v: -------------------------------------------------------------------------------- 1 | Require Export FrapWithoutSets. 2 | 3 | Module Export SN := SetNotations(FrapWithoutSets). 4 | -------------------------------------------------------------------------------- /FrapWithoutSets.v: -------------------------------------------------------------------------------- 1 | Require Import Eqdep String NArith Arith Lia Program Sets Relations Map Var Invariant Bool ModelCheck. 2 | Export Ascii String Arith Sets Relations Map Var Invariant Bool ModelCheck. 3 | Require Import List. 4 | Export List ListNotations. 5 | Open Scope string_scope. 6 | Open Scope list_scope. 7 | 8 | Ltac inductN n := 9 | match goal with 10 | | [ |- forall x : ?E, _ ] => 11 | match type of E with 12 | | Prop => 13 | let H := fresh in intro H; 14 | match n with 15 | | 1 => dependent induction H 16 | | S ?n' => inductN n' 17 | end 18 | | _ => intro; inductN n 19 | end 20 | end. 21 | 22 | Ltac same_structure x y := 23 | match x with 24 | | ?f ?a1 ?b1 ?c1 ?d1 => 25 | match y with 26 | | f ?a2 ?b2 ?c2 ?d2 => same_structure a1 a2; same_structure b1 b2; same_structure c1 c2; same_structure d1 d2 27 | | _ => fail 2 28 | end 29 | | ?f ?a1 ?b1 ?c1 => 30 | match y with 31 | | f ?a2 ?b2 ?c2 => same_structure a1 a2; same_structure b1 b2; same_structure c1 c2 32 | | _ => fail 2 33 | end 34 | | ?f ?a1 ?b1 => 35 | match y with 36 | | f ?a2 ?b2 => same_structure a1 a2; same_structure b1 b2 37 | | _ => fail 2 38 | end 39 | | ?f ?a1 => 40 | match y with 41 | | f ?a2 => same_structure a1 a2 42 | | _ => fail 2 43 | end 44 | | _ => 45 | match y with 46 | | ?f ?a1 ?b1 ?c1 ?d1 => 47 | match x with 48 | | f ?a2 ?b2 ?c2 ?d2 => same_structure a1 a2; same_structure b1 b2; same_structure c1 c2; same_structure d1 d2 49 | | _ => fail 2 50 | end 51 | | ?f ?a1 ?b1 ?c1 => 52 | match x with 53 | | f ?a2 ?b2 ?c2 => same_structure a1 a2; same_structure b1 b2; same_structure c1 c2 54 | | _ => fail 2 55 | end 56 | | ?f ?a1 ?b1 => 57 | match x with 58 | | f ?a2 ?b2 => same_structure a1 a2; same_structure b1 b2 59 | | _ => fail 2 60 | end 61 | | ?f ?a1 => 62 | match x with 63 | | f ?a2 => same_structure a1 a2 64 | | _ => fail 2 65 | end 66 | | _ => idtac 67 | end 68 | end. 69 | 70 | Ltac instantiate_obvious1 H := 71 | match type of H with 72 | | _ ++ _ = _ ++ _ -> _ => fail 1 73 | | ?x = ?y -> _ => 74 | (same_structure x y; specialize (H eq_refl)) 75 | || (has_evar (x, y); fail 3) 76 | | JMeq.JMeq ?x ?y -> _ => 77 | (same_structure x y; specialize (H JMeq.JMeq_refl)) 78 | || (has_evar (x, y); fail 3) 79 | | forall x : ?T, _ => 80 | match type of T with 81 | | Prop => fail 1 82 | | _ => 83 | let x' := fresh x in 84 | evar (x' : T); 85 | let x'' := eval unfold x' in x' in specialize (H x''); clear x'; 86 | instantiate_obvious1 H 87 | end 88 | end. 89 | 90 | Ltac instantiate_obvious H := 91 | match type of H with 92 | | context[@eq string _ _] => idtac 93 | | _ => repeat instantiate_obvious1 H 94 | end. 95 | 96 | Ltac instantiate_obviouses := 97 | repeat match goal with 98 | | [ H : _ |- _ ] => instantiate_obvious H 99 | end. 100 | 101 | (** * Interlude: special notations and induction principle for [N] *) 102 | 103 | (* Note: recurse is an identifier, but we will always use the name "recurse" by convention *) 104 | (*Declare Scope N_recursion_scope.*) 105 | Notation "recurse 'by' 'cases' | 0 => A | n + 1 => B 'end'" := 106 | (N.recursion A (fun n recurse => B)) 107 | (at level 11, A at level 200, n at level 0, B at level 200, 108 | format "'[hv' recurse 'by' 'cases' '//' '|' 0 => A '//' '|' n + 1 => B '//' 'end' ']'") 109 | : N_recursion_scope. 110 | 111 | Open Scope N_recursion_scope. 112 | 113 | Lemma indN: forall (P: N -> Prop), 114 | P 0%N -> (* base case to prove *) 115 | (forall n: N, P n -> P (n + 1)%N) -> (* inductive case to prove *) 116 | forall n, P n. (* conclusion to enjoy *) 117 | Proof. setoid_rewrite N.add_1_r. exact N.peano_ind. Qed. 118 | 119 | Ltac induct e := (induction e using indN || inductN e || dependent induction e); instantiate_obviouses. 120 | 121 | Ltac invert' H := inversion H; clear H; subst. 122 | 123 | Ltac invertN n := 124 | match goal with 125 | | [ |- forall x : ?E, _ ] => 126 | match type of E with 127 | | Prop => 128 | let H := fresh in intro H; 129 | match n with 130 | | 1 => invert' H 131 | | S ?n' => invertN n' 132 | end 133 | | _ => intro; invertN n 134 | end 135 | end. 136 | 137 | Ltac invert e := invertN e || invert' e. 138 | 139 | Ltac invert0 e := invert e; fail. 140 | Ltac invert1 e := invert0 e || (invert e; []). 141 | Ltac invert2 e := invert1 e || (invert e; [|]). 142 | 143 | Ltac maps_neq := 144 | match goal with 145 | | [ H : ?m1 = ?m2 |- _ ] => 146 | let rec recur E := 147 | match E with 148 | | ?E' $+ (?k, _) => 149 | (apply (f_equal (fun m => m $? k)) in H; simpl in *; autorewrite with core in *; simpl in *; congruence) 150 | || recur E' 151 | end in 152 | recur m1 || recur m2 153 | end. 154 | 155 | Ltac fancy_neq := 156 | repeat match goal with 157 | | _ => maps_neq 158 | | [ H : @eq (nat -> _) _ _ |- _ ] => apply (f_equal (fun f => f 0)) in H 159 | | [ H : @eq ?T _ _ |- _ ] => 160 | match eval compute in T with 161 | | fmap _ _ => fail 1 162 | | _ => invert H 163 | end 164 | end. 165 | 166 | Ltac maps_equal' := progress Frap.Map.M.maps_equal; autorewrite with core; simpl. 167 | 168 | Ltac removeDups := 169 | match goal with 170 | | [ |- context[constant ?ls] ] => 171 | someMatch ls; 172 | erewrite (@removeDups_ok _ ls) 173 | by repeat (apply RdNil 174 | || (apply RdNew; [ simpl; intuition (congruence || solve [ fancy_neq ]) | ]) 175 | || (apply RdDup; [ simpl; intuition (congruence || (repeat (maps_equal' || f_equal))) | ])) 176 | end. 177 | 178 | Ltac doSubtract := 179 | match goal with 180 | | [ |- context[@minus ?A (@constant ?A1 ?ls) (@constant ?A2 ?ls0)] ] => 181 | match A with 182 | | A1 => idtac 183 | | _ => change (@constant A1 ls) with (@constant A ls) 184 | end; 185 | match A with 186 | | A2 => idtac 187 | | _ => change (@constant A2 ls0) with (@constant A ls0) 188 | end; 189 | erewrite (@doSubtract_ok A ls ls0) 190 | by repeat (apply DsNil 191 | || (apply DsKeep; [ simpl; intuition (congruence || solve [ fancy_neq ]) | ]) 192 | || (apply DsDrop; [ simpl; intuition (congruence || (repeat (maps_equal' || f_equal))) | ])) 193 | end. 194 | 195 | Ltac simpl_maps := 196 | repeat match goal with 197 | | [ |- context[add ?m ?k1 ?v $? ?k2] ] => 198 | (rewrite (@lookup_add_ne _ _ m k1 k2 v) by (congruence || lia)) 199 | || (rewrite (@lookup_add_eq _ _ m k1 k2 v) by (congruence || lia)) 200 | end. 201 | 202 | Ltac simplify := repeat (unifyTails; pose proof I); 203 | repeat match goal with 204 | | [ H : True |- _ ] => clear H 205 | end; 206 | repeat progress (simpl in *; intros; try autorewrite with core in *; simpl_maps); 207 | repeat (normalize_set || doSubtract). 208 | Ltac propositional := intuition idtac. 209 | 210 | Ltac linear_arithmetic := intros; 211 | repeat match goal with 212 | | [ |- context[max ?a ?b] ] => 213 | let Heq := fresh "Heq" in destruct (Max.max_spec a b) as [[? Heq] | [? Heq]]; 214 | rewrite Heq in *; clear Heq 215 | | [ _ : context[max ?a ?b] |- _ ] => 216 | let Heq := fresh "Heq" in destruct (Max.max_spec a b) as [[? Heq] | [? Heq]]; 217 | rewrite Heq in *; clear Heq 218 | | [ |- context[min ?a ?b] ] => 219 | let Heq := fresh "Heq" in destruct (Min.min_spec a b) as [[? Heq] | [? Heq]]; 220 | rewrite Heq in *; clear Heq 221 | | [ _ : context[min ?a ?b] |- _ ] => 222 | let Heq := fresh "Heq" in destruct (Min.min_spec a b) as [[? Heq] | [? Heq]]; 223 | rewrite Heq in *; clear Heq 224 | end; lia. 225 | 226 | Ltac equality := intuition congruence. 227 | 228 | Ltac cases E := 229 | ((repeat match type of E with 230 | | _ \/ _ => destruct E as [E | E] 231 | end) 232 | || (match type of E with 233 | | N => destruct E using indN 234 | end) 235 | || (is_var E; destruct E) 236 | || match type of E with 237 | | {_} + {_} => destruct E 238 | | _ => let Heq := fresh "Heq" in destruct E eqn:Heq 239 | end); 240 | repeat match goal with 241 | | [ H : _ = left _ |- _ ] => clear H 242 | | [ H : _ = right _ |- _ ] => clear H 243 | end. 244 | 245 | Global Opaque max min. 246 | 247 | Infix "==n" := eq_nat_dec (no associativity, at level 50). 248 | Infix "<=?" := le_lt_dec. 249 | 250 | Export Frap.Map. 251 | 252 | Ltac maps_equal := Frap.Map.M.maps_equal; simplify. 253 | 254 | Ltac first_order := firstorder idtac. 255 | 256 | 257 | (** * Model checking *) 258 | 259 | Lemma eq_iff : forall P Q, 260 | P = Q 261 | -> (P <-> Q). 262 | Proof. 263 | equality. 264 | Qed. 265 | 266 | Ltac sets0 := Sets.sets ltac:(simpl in *; intuition (subst; auto; try equality; try linear_arithmetic)). 267 | 268 | Ltac sets := propositional; 269 | try match goal with 270 | | [ |- @eq (?T -> Prop) _ _ ] => 271 | change (T -> Prop) with (set T) 272 | end; 273 | try match goal with 274 | | [ |- @eq (set _) _ _ ] => 275 | let x := fresh "x" in 276 | apply sets_equal; intro x; 277 | repeat match goal with 278 | | [ H : @eq (set _) _ _ |- _ ] => apply (f_equal (fun f => f x)) in H; 279 | apply eq_iff in H 280 | end 281 | end; sets0; 282 | try match goal with 283 | | [ H : @eq (set ?T) _ _, x : ?T |- _ ] => 284 | repeat match goal with 285 | | [ H : @eq (set T) _ _ |- _ ] => apply (f_equal (fun f => f x)) in H; 286 | apply eq_iff in H 287 | end; 288 | solve [ sets0 ] 289 | end. 290 | 291 | Ltac model_check_invert1 := 292 | match goal with 293 | | [ H : ?P |- _ ] => 294 | match type of P with 295 | | Prop => invert H; 296 | repeat match goal with 297 | | [ H : existT _ ?x _ = existT _ ?x _ |- _ ] => 298 | apply inj_pair2 in H; subst 299 | end; simplify 300 | end 301 | end. 302 | 303 | Ltac model_check_invert := simplify; subst; repeat model_check_invert1. 304 | 305 | Lemma oneStepClosure_solve : forall A (sys : trsys A) I I', 306 | oneStepClosure sys I I' 307 | -> I = I' 308 | -> oneStepClosure sys I I. 309 | Proof. 310 | equality. 311 | Qed. 312 | 313 | Ltac singletoner := try (exfalso; solve [ sets ]); 314 | repeat match goal with 315 | (* | _ => apply singleton_in *) 316 | | [ |- _ ?S ] => idtac S; apply singleton_in 317 | | [ |- (_ \cup _) _ ] => apply singleton_in_other 318 | end. 319 | 320 | Ltac closure := 321 | repeat (apply oneStepClosure_empty 322 | || (apply oneStepClosure_split; [ model_check_invert; try equality; solve [ singletoner ] | ])). 323 | 324 | Ltac model_check_done := apply MscDone. 325 | Ltac model_check_step := eapply MscStep; [ closure | simplify ]. 326 | 327 | Ltac model_check_steps1 := model_check_step || model_check_done. 328 | Ltac model_check_steps := repeat model_check_steps1. 329 | 330 | Ltac model_check_finish := simplify; propositional; subst; simplify; try equality; try linear_arithmetic. 331 | 332 | Ltac model_check_infer := 333 | apply multiStepClosure_ok; simplify; model_check_steps. 334 | 335 | Ltac model_check_find_invariant := 336 | simplify; eapply invariant_weaken; [ model_check_infer | ]; cbv beta in *. 337 | 338 | Ltac model_check := model_check_find_invariant; model_check_finish. 339 | 340 | Inductive ordering (n m : nat) := 341 | | Lt (_ : n < m) 342 | | Eq (_ : n = m) 343 | | Gt (_ : n > m). 344 | 345 | Local Hint Constructors ordering : core. 346 | Local Hint Extern 1 (_ < _) => lia : core. 347 | Local Hint Extern 1 (_ > _) => lia : core. 348 | 349 | Theorem totally_ordered : forall n m, ordering n m. 350 | Proof. 351 | induction n; destruct m; simpl; eauto. 352 | destruct (IHn m); eauto. 353 | Qed. 354 | 355 | Ltac total_ordering N M := destruct (totally_ordered N M). 356 | 357 | Ltac inList x xs := 358 | match xs with 359 | | (x, _) => true 360 | | (_, ?xs') => inList x xs' 361 | | _ => false 362 | end. 363 | 364 | Ltac maybe_simplify_map m found kont := 365 | match m with 366 | | @empty ?A ?B => kont (@empty A B) 367 | | ?m' $+ (?k, ?v) => 368 | let iL := inList k found in 369 | match iL with 370 | | true => maybe_simplify_map m' found kont 371 | | false => 372 | maybe_simplify_map m' (k, found) ltac:(fun m' => kont (m' $+ (k, v))) 373 | end 374 | end. 375 | 376 | Ltac simplify_map' m found kont := 377 | match m with 378 | | ?m' $+ (?k, ?v) => 379 | let iL := inList k found in 380 | match iL with 381 | | true => maybe_simplify_map m' found kont 382 | | false => 383 | simplify_map' m' (k, found) ltac:(fun m' => kont (m' $+ (k, v))) 384 | end 385 | end. 386 | 387 | Ltac simplify_map := 388 | match goal with 389 | | [ |- context[@add ?A ?B ?m ?k ?v] ] => 390 | simplify_map' (m $+ (k, v)) tt ltac:(fun m' => 391 | replace (@add A B m k v) with m' by maps_equal) 392 | end. 393 | 394 | Require Import Classical. 395 | Ltac excluded_middle P := destruct (classic P). 396 | 397 | Lemma join_idempotent: forall (A B : Type) (m : fmap A B), (m $++ m) = m. 398 | Proof. 399 | simplify; apply fmap_ext; simplify. 400 | cases (m $? k). 401 | - rewrite lookup_join1; auto. 402 | eauto using lookup_Some_dom. 403 | - rewrite lookup_join2; auto. 404 | eauto using lookup_None_dom. 405 | Qed. 406 | 407 | Lemma includes_refl: forall (A B : Type) (m : fmap A B), m $<= m. 408 | Proof. 409 | simplify. 410 | apply includes_intro; auto. 411 | Qed. 412 | 413 | Ltac dep_cases E := 414 | let x := fresh "x" in 415 | remember E as x; simpl in x; dependent destruction x; 416 | try match goal with 417 | | [ H : _ = E |- _ ] => try rewrite <- H in *; clear H 418 | end. 419 | 420 | (** * More with [N] *) 421 | 422 | Lemma recursion_step: forall {A: Type} (a: A) (f: N -> A -> A) (n: N), 423 | N.recursion a f (n + 1)%N = f n (N.recursion a f n). 424 | Proof. 425 | intros until f. setoid_rewrite N.add_1_r. 426 | eapply N.recursion_succ; cbv; intuition congruence. 427 | Qed. 428 | 429 | Ltac head f := 430 | match f with 431 | | ?g _ => head g 432 | | _ => constr:(f) 433 | end. 434 | 435 | (* If a function f is defined as 436 | 437 | recurse by cases 438 | | 0 => base 439 | | k + 1 => step recurse k 440 | end. 441 | 442 | and we have an occurrence of (f (k + 1)) in our goal, we can use 443 | "unfold_recurse f k" to replace (f (k + 1)) by (step (f k) k), 444 | ie it allows us to unfold one recursive step. *) 445 | Ltac unfold_recurse f k := 446 | let h := head f in 447 | let rhs := eval unfold h in f in 448 | lazymatch rhs with 449 | | N.recursion ?base ?step => 450 | let g := eval cbv beta in (step k (f k)) in 451 | rewrite (recursion_step base step k : f (k + 1)%N = g) in * 452 | | _ => let expected := open_constr:(N.recursion _ _) in 453 | fail "The provided term" f "expands to" rhs "which is not of the expected form" expected 454 | end. 455 | 456 | (* This will make "simplify" a bit less nice in some cases (but these are easily worked around using 457 | linear_arithmetic). *) 458 | Arguments N.mul: simpl never. 459 | Arguments N.add: simpl never. 460 | 461 | Definition IF_then_else (p q1 q2 : Prop) := 462 | (p /\ q1) \/ (~p /\ q2). 463 | 464 | Notation "'IFF' p 'then' q1 'else' q2" := (IF_then_else p q1 q2) (at level 95). 465 | -------------------------------------------------------------------------------- /HoareLogic_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | 4 | (** * Syntax and semantics of a simple imperative language *) 5 | 6 | Inductive exp := 7 | | Const (n : nat) 8 | | Var (x : string) 9 | | Read (e1 : exp) 10 | | Plus (e1 e2 : exp) 11 | | Minus (e1 e2 : exp) 12 | | Mult (e1 e2 : exp). 13 | 14 | Inductive bexp := 15 | | Equal (e1 e2 : exp) 16 | | Less (e1 e2 : exp). 17 | 18 | Definition heap := fmap nat nat. 19 | Definition valuation := fmap var nat. 20 | Definition assertion := heap -> valuation -> Prop. 21 | 22 | Inductive cmd := 23 | | Skip 24 | | Assign (x : var) (e : exp) 25 | | Write (e1 e2 : exp) 26 | | Seq (c1 c2 : cmd) 27 | | If_ (be : bexp) (then_ else_ : cmd) 28 | | While_ (inv : assertion) (be : bexp) (body : cmd) 29 | 30 | | Assert (a : assertion). 31 | 32 | (* Shorthand notation for looking up in a finite map, returning zero if the key 33 | * is not found *) 34 | Notation "m $! k" := (match m $? k with Some n => n | None => O end) (at level 30). 35 | 36 | (* Start of expression semantics: meaning of expressions *) 37 | Fixpoint eval (e : exp) (h : heap) (v : valuation) : nat := 38 | match e with 39 | | Const n => n 40 | | Var x => v $! x 41 | | Read e1 => h $! eval e1 h v 42 | | Plus e1 e2 => eval e1 h v + eval e2 h v 43 | | Minus e1 e2 => eval e1 h v - eval e2 h v 44 | | Mult e1 e2 => eval e1 h v * eval e2 h v 45 | end. 46 | 47 | (* Meaning of Boolean expressions *) 48 | Fixpoint beval (b : bexp) (h : heap) (v : valuation) : bool := 49 | match b with 50 | | Equal e1 e2 => if eval e1 h v ==n eval e2 h v then true else false 51 | | Less e1 e2 => if eval e2 h v <=? eval e1 h v then false else true 52 | end. 53 | 54 | (* A big-step operational semantics for commands *) 55 | Inductive exec : heap -> valuation -> cmd -> heap -> valuation -> Prop := 56 | | ExSkip : forall h v, 57 | exec h v Skip h v 58 | | ExAssign : forall h v x e, 59 | exec h v (Assign x e) h (v $+ (x, eval e h v)) 60 | | ExWrite : forall h v e1 e2, 61 | exec h v (Write e1 e2) (h $+ (eval e1 h v, eval e2 h v)) v 62 | | ExSeq : forall h1 v1 c1 h2 v2 c2 h3 v3, 63 | exec h1 v1 c1 h2 v2 64 | -> exec h2 v2 c2 h3 v3 65 | -> exec h1 v1 (Seq c1 c2) h3 v3 66 | | ExIfTrue : forall h1 v1 b c1 c2 h2 v2, 67 | beval b h1 v1 = true 68 | -> exec h1 v1 c1 h2 v2 69 | -> exec h1 v1 (If_ b c1 c2) h2 v2 70 | | ExIfFalse : forall h1 v1 b c1 c2 h2 v2, 71 | beval b h1 v1 = false 72 | -> exec h1 v1 c2 h2 v2 73 | -> exec h1 v1 (If_ b c1 c2) h2 v2 74 | | ExWhileFalse : forall I h v b c, 75 | beval b h v = false 76 | -> exec h v (While_ I b c) h v 77 | | ExWhileTrue : forall I h1 v1 b c h2 v2 h3 v3, 78 | beval b h1 v1 = true 79 | -> exec h1 v1 c h2 v2 80 | -> exec h2 v2 (While_ I b c) h3 v3 81 | -> exec h1 v1 (While_ I b c) h3 v3 82 | 83 | (* Assertions execute only when they are true. They provide a way to embed 84 | * proof obligations within programs. *) 85 | | ExAssert : forall h v (a : assertion), 86 | a h v 87 | -> exec h v (Assert a) h v. 88 | 89 | 90 | (** * Hoare logic *) 91 | 92 | Inductive hoare_triple : assertion -> cmd -> assertion -> Prop := 93 | | HtSkip : forall P, hoare_triple P Skip P 94 | | HtAssign : forall (P : assertion) x e, 95 | hoare_triple P (Assign x e) (fun h v => exists v', P h v' /\ v = v' $+ (x, eval e h v')) 96 | | HtWrite : forall (P : assertion) (e1 e2 : exp), 97 | hoare_triple P (Write e1 e2) (fun h v => exists h', P h' v /\ h = h' $+ (eval e1 h' v, eval e2 h' v)) 98 | | HtSeq : forall (P Q R : assertion) c1 c2, 99 | hoare_triple P c1 Q 100 | -> hoare_triple Q c2 R 101 | -> hoare_triple P (Seq c1 c2) R 102 | | HtIf : forall (P Q1 Q2 : assertion) b c1 c2, 103 | hoare_triple (fun h v => P h v /\ beval b h v = true) c1 Q1 104 | -> hoare_triple (fun h v => P h v /\ beval b h v = false) c2 Q2 105 | -> hoare_triple P (If_ b c1 c2) (fun h v => Q1 h v \/ Q2 h v) 106 | | HtWhile : forall (I P : assertion) b c, 107 | (forall h v, P h v -> I h v) 108 | -> hoare_triple (fun h v => I h v /\ beval b h v = true) c I 109 | -> hoare_triple P (While_ I b c) (fun h v => I h v /\ beval b h v = false) 110 | | HtAssert : forall P I : assertion, 111 | (forall h v, P h v -> I h v) 112 | -> hoare_triple P (Assert I) P 113 | | HtConsequence : forall (P Q P' Q' : assertion) c, 114 | hoare_triple P c Q 115 | -> (forall h v, P' h v -> P h v) 116 | -> (forall h v, Q h v -> Q' h v) 117 | -> hoare_triple P' c Q'. 118 | 119 | Lemma hoare_triple_big_step_while: forall (I : assertion) b c, 120 | (forall h v h' v', exec h v c h' v' 121 | -> I h v 122 | -> beval b h v = true 123 | -> I h' v') 124 | -> forall h v h' v', exec h v (While_ I b c) h' v' 125 | -> I h v 126 | -> I h' v' /\ beval b h' v' = false. 127 | Proof. 128 | induct 2; eauto. 129 | Qed. 130 | 131 | Theorem hoare_triple_big_step : forall pre c post, 132 | hoare_triple pre c post 133 | -> forall h v h' v', exec h v c h' v' 134 | -> pre h v 135 | -> post h' v'. 136 | Proof. 137 | induct 1; eauto; invert 1; eauto. 138 | 139 | simplify. 140 | eapply hoare_triple_big_step_while; eauto. 141 | Qed. 142 | 143 | 144 | (* BEGIN syntax macros that won't be explained *) 145 | Coercion Const : nat >-> exp. 146 | Coercion Var : string >-> exp. 147 | Notation "*[ e ]" := (Read e) : cmd_scope. 148 | Infix "+" := Plus : cmd_scope. 149 | Infix "-" := Minus : cmd_scope. 150 | Infix "*" := Mult : cmd_scope. 151 | Infix "=" := Equal : cmd_scope. 152 | Infix "<" := Less : cmd_scope. 153 | Definition set (dst src : exp) : cmd := 154 | match dst with 155 | | Read dst' => Write dst' src 156 | | Var dst' => Assign dst' src 157 | | _ => Assign "Bad LHS" 0 158 | end. 159 | Infix "<-" := set (no associativity, at level 70) : cmd_scope. 160 | Infix ";;" := Seq (right associativity, at level 75) : cmd_scope. 161 | Notation "'when' b 'then' then_ 'else' else_ 'done'" := (If_ b then_ else_) (at level 75, b at level 0). 162 | Notation "{{ I }} 'while' b 'loop' body 'done'" := (While_ I b body) (at level 75). 163 | Notation "'assert' {{ I }}" := (Assert I) (at level 75). 164 | Delimit Scope cmd_scope with cmd. 165 | (* END macros *) 166 | 167 | (* We should draw some attention to the next notation, which defines special 168 | * lambdas for writing assertions. *) 169 | Notation "h & v ~> e" := (fun h v => e%nat%type) (at level 85, v at level 0). 170 | 171 | (* And here's the classic notation for Hoare triples. *) 172 | Notation "{{ P }} c {{ Q }}" := (hoare_triple P c%cmd Q) (at level 90, c at next level). 173 | 174 | (* Special case of consequence: keeping the precondition; only changing the 175 | * postcondition. *) 176 | Lemma HtStrengthenPost : forall (P Q Q' : assertion) c, 177 | hoare_triple P c Q 178 | -> (forall h v, Q h v -> Q' h v) 179 | -> hoare_triple P c Q'. 180 | Proof. 181 | simplify; eapply HtConsequence; eauto. 182 | Qed. 183 | 184 | (* Finally, three tactic definitions that we won't explain. The overall tactic 185 | * [ht] tries to prove Hoare triples, essentially by rote application of the 186 | * rules. Some other obligations are generated, generally of implications 187 | * between assertions, and [ht] also makes a best effort to solve those. *) 188 | 189 | Ltac ht1 := 190 | match goal with 191 | | [ |- {{ _ }} _ {{ ?P }} ] => 192 | tryif is_evar P then 193 | apply HtSkip || apply HtAssign || apply HtWrite || eapply HtSeq 194 | || eapply HtIf || eapply HtWhile || eapply HtAssert 195 | else 196 | eapply HtStrengthenPost 197 | end. 198 | 199 | Ltac t := cbv beta; propositional; subst; 200 | repeat match goal with 201 | | [ H : ex _ |- _ ] => invert H; propositional; subst 202 | end; 203 | simplify; 204 | repeat match goal with 205 | | [ _ : context[?a <=? ?b] |- _ ] => destruct (a <=? b); try discriminate 206 | | [ H : ?E = ?E |- _ ] => clear H 207 | end; simplify; propositional; auto; try equality; try linear_arithmetic. 208 | 209 | Ltac ht := simplify; repeat ht1; t. 210 | 211 | 212 | (** * Some examples of verified programs *) 213 | 214 | (** ** Swapping the values in two variables *) 215 | 216 | Theorem swap_ok : forall a b, 217 | {{_&v ~> v $! "x" = a /\ v $! "y" = b}} 218 | "tmp" <- "x";; 219 | "x" <- "y";; 220 | "y" <- "tmp" 221 | {{_&v ~> v $! "x" = b /\ v $! "y" = a}}. 222 | Proof. 223 | Admitted. 224 | 225 | (** ** Computing the maximum of two variables *) 226 | 227 | Theorem max_ok : forall a b, 228 | {{_&v ~> v $! "x" = a /\ v $! "y" = b}} 229 | when "x" < "y" then 230 | "m" <- "y" 231 | else 232 | "m" <- "x" 233 | done 234 | {{_&v ~> v $! "m" = max a b}}. 235 | Proof. 236 | Admitted. 237 | 238 | (** ** Iterative factorial *) 239 | 240 | Theorem fact_ok : forall n, 241 | {{_&v ~> v $! "n" = n}} 242 | "acc" <- 1;; 243 | {{_&v ~> True}} 244 | while 0 < "n" loop 245 | "acc" <- "acc" * "n";; 246 | "n" <- "n" - 1 247 | done 248 | {{_&v ~> v $! "acc" = fact n}}. 249 | Proof. 250 | Admitted. 251 | 252 | (** ** Selection sort *) 253 | 254 | (* This is our one example of a program reading/writing memory, which holds the 255 | * representation of an array that we want to sort in-place. *) 256 | 257 | (* One simple lemma turns out to be helpful to guide [eauto] properly. *) 258 | Lemma leq_f : forall A (m : fmap A nat) x y, 259 | x = y 260 | -> m $! x <= m $! y. 261 | Proof. 262 | ht. 263 | Qed. 264 | 265 | Local Hint Resolve leq_f : core. 266 | Local Hint Extern 1 (@eq nat _ _) => linear_arithmetic : core. 267 | Local Hint Extern 1 (_ < _) => linear_arithmetic : core. 268 | Local Hint Extern 1 (_ <= _) => linear_arithmetic : core. 269 | (* We also register [linear_arithmetic] as a step to try during proof search. *) 270 | 271 | Theorem selectionSort_ok : 272 | {{_&_ ~> True}} 273 | "i" <- 0;; 274 | {{h&v ~> True}} 275 | while "i" < "n" loop 276 | "j" <- "i"+1;; 277 | "best" <- "i";; 278 | {{h&v ~> True}} 279 | while "j" < "n" loop 280 | when *["a" + "j"] < *["a" + "best"] then 281 | "best" <- "j" 282 | else 283 | Skip 284 | done;; 285 | "j" <- "j" + 1 286 | done;; 287 | "tmp" <- *["a" + "best"];; 288 | *["a" + "best"] <- *["a" + "i"];; 289 | *["a" + "i"] <- "tmp";; 290 | "i" <- "i" + 1 291 | done 292 | {{h&v ~> forall i j, i < j < v $! "n" -> h $! (v $! "a" + i) <= h $! (v $! "a" + j)}}. 293 | Proof. 294 | Admitted. 295 | 296 | 297 | (** * An alternative correctness theorem for Hoare logic, with small-step semantics *) 298 | 299 | Inductive step : heap * valuation * cmd -> heap * valuation * cmd -> Prop := 300 | | StAssign : forall h v x e, 301 | step (h, v, Assign x e) (h, v $+ (x, eval e h v), Skip) 302 | | StWrite : forall h v e1 e2, 303 | step (h, v, Write e1 e2) (h $+ (eval e1 h v, eval e2 h v), v, Skip) 304 | | StStepSkip : forall h v c, 305 | step (h, v, Seq Skip c) (h, v, c) 306 | | StStepRec : forall h1 v1 c1 h2 v2 c1' c2, 307 | step (h1, v1, c1) (h2, v2, c1') 308 | -> step (h1, v1, Seq c1 c2) (h2, v2, Seq c1' c2) 309 | | StIfTrue : forall h v b c1 c2, 310 | beval b h v = true 311 | -> step (h, v, If_ b c1 c2) (h, v, c1) 312 | | StIfFalse : forall h v b c1 c2, 313 | beval b h v = false 314 | -> step (h, v, If_ b c1 c2) (h, v, c2) 315 | | StWhileFalse : forall I h v b c, 316 | beval b h v = false 317 | -> step (h, v, While_ I b c) (h, v, Skip) 318 | | StWhileTrue : forall I h v b c, 319 | beval b h v = true 320 | -> step (h, v, While_ I b c) (h, v, Seq c (While_ I b c)) 321 | | StAssert : forall h v (a : assertion), 322 | a h v 323 | -> step (h, v, Assert a) (h, v, Skip). 324 | 325 | Local Hint Constructors step : core. 326 | 327 | Definition trsys_of (st : heap * valuation * cmd) := {| 328 | Initial := {st}; 329 | Step := step 330 | |}. 331 | 332 | Definition unstuck (st : heap * valuation * cmd) := 333 | snd st = Skip 334 | \/ exists st', step st st'. 335 | 336 | Lemma hoare_triple_unstuck : forall P c Q, 337 | {{P}} c {{Q}} 338 | -> forall h v, P h v 339 | -> unstuck (h, v, c). 340 | Proof. 341 | induct 1; unfold unstuck; simplify; propositional; eauto. 342 | 343 | apply IHhoare_triple1 in H1. 344 | unfold unstuck in H1; simplify; first_order; subst; eauto. 345 | cases x. 346 | cases p. 347 | eauto. 348 | 349 | cases (beval b h v); eauto. 350 | 351 | cases (beval b h v); eauto. 352 | 353 | apply H0 in H2. 354 | apply IHhoare_triple in H2. 355 | unfold unstuck in H2; simplify; first_order. 356 | Qed. 357 | 358 | Lemma hoare_triple_Skip : forall P Q, 359 | {{P}} Skip {{Q}} 360 | -> forall h v, P h v -> Q h v. 361 | Proof. 362 | induct 1; auto. 363 | Qed. 364 | 365 | Lemma hoare_triple_step : forall P c Q, 366 | {{P}} c {{Q}} 367 | -> forall h v h' v' c', 368 | step (h, v, c) (h', v', c') 369 | -> P h v 370 | -> {{h''&v'' ~> h'' = h' /\ v'' = v'}} c' {{Q}}. 371 | Proof. 372 | induct 1. 373 | 374 | invert 1. 375 | 376 | invert 1; ht; eauto. 377 | 378 | invert 1; ht; eauto. 379 | 380 | invert 1; simplify. 381 | 382 | eapply HtConsequence; eauto. 383 | propositional; subst. 384 | eapply hoare_triple_Skip; eauto. 385 | 386 | econstructor; eauto. 387 | 388 | invert 1; simplify. 389 | eapply HtConsequence; eauto; equality. 390 | eapply HtConsequence; eauto; equality. 391 | 392 | invert 1; simplify. 393 | eapply HtConsequence with (P := h'' & v'' ~> h'' = h' /\ v'' = v'). 394 | apply HtSkip. 395 | auto. 396 | simplify; propositional; subst; eauto. 397 | 398 | econstructor. 399 | eapply HtConsequence; eauto. 400 | simplify; propositional; subst; eauto. 401 | econstructor; eauto. 402 | 403 | invert 1; simplify. 404 | eapply HtConsequence; eauto. 405 | econstructor. 406 | simplify; propositional; subst; eauto. 407 | 408 | simplify. 409 | eapply HtConsequence. 410 | eapply IHhoare_triple; eauto. 411 | simplify; propositional; subst; eauto. 412 | auto. 413 | Qed. 414 | 415 | Theorem hoare_triple_invariant : forall P c Q h v, 416 | {{P}} c {{Q}} 417 | -> P h v 418 | -> invariantFor (trsys_of (h, v, c)) unstuck. 419 | Proof. 420 | simplify. 421 | apply invariant_weaken with (invariant1 := fun st => {{h&v ~> h = fst (fst st) 422 | /\ v = snd (fst st)}} 423 | snd st 424 | {{_&_ ~> True}}). 425 | 426 | apply invariant_induction; simplify. 427 | 428 | propositional; subst; simplify. 429 | eapply HtConsequence; eauto. 430 | equality. 431 | 432 | cases s. 433 | cases s'. 434 | cases p. 435 | cases p0. 436 | simplify. 437 | eapply hoare_triple_step; eauto. 438 | simplify; auto. 439 | 440 | simplify. 441 | cases s. 442 | cases p. 443 | simplify. 444 | eapply hoare_triple_unstuck; eauto. 445 | simplify; auto. 446 | Qed. 447 | 448 | (* A very simple example, just to show all this in action *) 449 | Definition forever := ( 450 | "i" <- 1;; 451 | "n" <- 1;; 452 | {{h&v ~> v $! "i" > 0}} 453 | while 0 < "i" loop 454 | "i" <- "i" * 2;; 455 | "n" <- "n" + "i";; 456 | assert {{h&v ~> v $! "n" >= 1}} 457 | done;; 458 | 459 | assert {{_&_ ~> False}} 460 | (* Note that this last assertion implies that the program never terminates! *) 461 | )%cmd. 462 | 463 | Theorem forever_ok : {{_&_ ~> True}} forever {{_&_ ~> False}}. 464 | Proof. 465 | ht. 466 | Qed. 467 | 468 | Theorem forever_invariant : invariantFor (trsys_of ($0, $0, forever)) unstuck. 469 | Proof. 470 | eapply hoare_triple_invariant. 471 | apply forever_ok. 472 | simplify; trivial. 473 | Qed. 474 | -------------------------------------------------------------------------------- /Imp.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | Set Implicit Arguments. 4 | 5 | 6 | Inductive arith : Set := 7 | | Const (n : nat) 8 | | Var (x : var) 9 | | Plus (e1 e2 : arith) 10 | | Minus (e1 e2 : arith) 11 | | Times (e1 e2 : arith). 12 | 13 | Inductive cmd := 14 | | Skip 15 | | Assign (x : var) (e : arith) 16 | | Sequence (c1 c2 : cmd) 17 | | If (e : arith) (then_ else_ : cmd) 18 | | While (e : arith) (body : cmd). 19 | 20 | Coercion Const : nat >-> arith. 21 | Coercion Var : var >-> arith. 22 | (*Declare Scope arith_scope.*) 23 | Infix "+" := Plus : arith_scope. 24 | Infix "-" := Minus : arith_scope. 25 | Infix "*" := Times : arith_scope. 26 | Delimit Scope arith_scope with arith. 27 | Notation "x <- e" := (Assign x e%arith) (at level 75). 28 | Infix ";;" := Sequence (at level 76). (* This one changed slightly, to avoid parsing clashes. *) 29 | Notation "'when' e 'then' then_ 'else' else_ 'done'" := (If e%arith then_ else_) (at level 75, e at level 0). 30 | Notation "'while' e 'loop' body 'done'" := (While e%arith body) (at level 75). 31 | 32 | Definition valuation := fmap var nat. 33 | Fixpoint interp (e : arith) (v : valuation) : nat := 34 | match e with 35 | | Const n => n 36 | | Var x => 37 | match v $? x with 38 | | None => 0 39 | | Some n => n 40 | end 41 | | Plus e1 e2 => interp e1 v + interp e2 v 42 | | Minus e1 e2 => interp e1 v - interp e2 v 43 | | Times e1 e2 => interp e1 v * interp e2 v 44 | end. 45 | 46 | Inductive eval : valuation -> cmd -> valuation -> Prop := 47 | | EvalSkip : forall v, 48 | eval v Skip v 49 | | EvalAssign : forall v x e, 50 | eval v (Assign x e) (v $+ (x, interp e v)) 51 | | EvalSeq : forall v c1 v1 c2 v2, 52 | eval v c1 v1 53 | -> eval v1 c2 v2 54 | -> eval v (Sequence c1 c2) v2 55 | | EvalIfTrue : forall v e then_ else_ v', 56 | interp e v <> 0 57 | -> eval v then_ v' 58 | -> eval v (If e then_ else_) v' 59 | | EvalIfFalse : forall v e then_ else_ v', 60 | interp e v = 0 61 | -> eval v else_ v' 62 | -> eval v (If e then_ else_) v' 63 | | EvalWhileTrue : forall v e body v' v'', 64 | interp e v <> 0 65 | -> eval v body v' 66 | -> eval v' (While e body) v'' 67 | -> eval v (While e body) v'' 68 | | EvalWhileFalse : forall v e body, 69 | interp e v = 0 70 | -> eval v (While e body) v. 71 | 72 | Inductive step : valuation * cmd -> valuation * cmd -> Prop := 73 | | StepAssign : forall v x e, 74 | step (v, Assign x e) (v $+ (x, interp e v), Skip) 75 | | StepSeq1 : forall v c1 c2 v' c1', 76 | step (v, c1) (v', c1') 77 | -> step (v, Sequence c1 c2) (v', Sequence c1' c2) 78 | | StepSeq2 : forall v c2, 79 | step (v, Sequence Skip c2) (v, c2) 80 | | StepIfTrue : forall v e then_ else_, 81 | interp e v <> 0 82 | -> step (v, If e then_ else_) (v, then_) 83 | | StepIfFalse : forall v e then_ else_, 84 | interp e v = 0 85 | -> step (v, If e then_ else_) (v, else_) 86 | | StepWhileTrue : forall v e body, 87 | interp e v <> 0 88 | -> step (v, While e body) (v, Sequence body (While e body)) 89 | | StepWhileFalse : forall v e body, 90 | interp e v = 0 91 | -> step (v, While e body) (v, Skip). 92 | 93 | Global Hint Constructors trc step eval : core. 94 | 95 | Lemma step_star_Seq : forall v c1 c2 v' c1', 96 | step^* (v, c1) (v', c1') 97 | -> step^* (v, Sequence c1 c2) (v', Sequence c1' c2). 98 | Proof. 99 | induct 1; eauto. 100 | cases y; eauto. 101 | Qed. 102 | 103 | Global Hint Resolve step_star_Seq : core. 104 | 105 | Theorem big_small : forall v c v', eval v c v' 106 | -> step^* (v, c) (v', Skip). 107 | Proof. 108 | induct 1; eauto 6 using trc_trans. 109 | Qed. 110 | 111 | Lemma small_big'' : forall v c v' c', step (v, c) (v', c') 112 | -> forall v'', eval v' c' v'' 113 | -> eval v c v''. 114 | Proof. 115 | induct 1; simplify; 116 | repeat match goal with 117 | | [ H : eval _ _ _ |- _ ] => invert1 H 118 | end; eauto. 119 | Qed. 120 | 121 | Global Hint Resolve small_big'' : core. 122 | 123 | Lemma small_big' : forall v c v' c', step^* (v, c) (v', c') 124 | -> forall v'', eval v' c' v'' 125 | -> eval v c v''. 126 | Proof. 127 | induct 1; eauto. 128 | cases y; eauto. 129 | Qed. 130 | 131 | Global Hint Resolve small_big' : core. 132 | 133 | Theorem small_big : forall v c v', step^* (v, c) (v', Skip) 134 | -> eval v c v'. 135 | Proof. 136 | eauto. 137 | Qed. 138 | 139 | Definition trsys_of (v : valuation) (c : cmd) : trsys (valuation * cmd) := {| 140 | Initial := {(v, c)}; 141 | Step := step 142 | |}. 143 | 144 | Inductive context := 145 | | Hole 146 | | CSeq (C : context) (c : cmd). 147 | 148 | Inductive plug : context -> cmd -> cmd -> Prop := 149 | | PlugHole : forall c, plug Hole c c 150 | | PlugSeq : forall c C c' c2, 151 | plug C c c' 152 | -> plug (CSeq C c2) c (Sequence c' c2). 153 | 154 | Inductive step0 : valuation * cmd -> valuation * cmd -> Prop := 155 | | Step0Assign : forall v x e, 156 | step0 (v, Assign x e) (v $+ (x, interp e v), Skip) 157 | | Step0Seq : forall v c2, 158 | step0 (v, Sequence Skip c2) (v, c2) 159 | | Step0IfTrue : forall v e then_ else_, 160 | interp e v <> 0 161 | -> step0 (v, If e then_ else_) (v, then_) 162 | | Step0IfFalse : forall v e then_ else_, 163 | interp e v = 0 164 | -> step0 (v, If e then_ else_) (v, else_) 165 | | Step0WhileTrue : forall v e body, 166 | interp e v <> 0 167 | -> step0 (v, While e body) (v, Sequence body (While e body)) 168 | | Step0WhileFalse : forall v e body, 169 | interp e v = 0 170 | -> step0 (v, While e body) (v, Skip). 171 | 172 | Inductive cstep : valuation * cmd -> valuation * cmd -> Prop := 173 | | CStep : forall C v c v' c' c1 c2, 174 | plug C c c1 175 | -> step0 (v, c) (v', c') 176 | -> plug C c' c2 177 | -> cstep (v, c1) (v', c2). 178 | 179 | Global Hint Constructors plug step0 cstep : core. 180 | 181 | Theorem step_cstep : forall v c v' c', 182 | step (v, c) (v', c') 183 | -> cstep (v, c) (v', c'). 184 | Proof. 185 | induct 1; repeat match goal with 186 | | [ H : cstep _ _ |- _ ] => invert H 187 | end; eauto. 188 | Qed. 189 | 190 | Global Hint Resolve step_cstep : core. 191 | 192 | Lemma step0_step : forall v c v' c', 193 | step0 (v, c) (v', c') 194 | -> step (v, c) (v', c'). 195 | Proof. 196 | invert 1; eauto. 197 | Qed. 198 | 199 | Global Hint Resolve step0_step : core. 200 | 201 | Lemma cstep_step' : forall C c0 c, 202 | plug C c0 c 203 | -> forall v' c'0 v c', step0 (v, c0) (v', c'0) 204 | -> plug C c'0 c' 205 | -> step (v, c) (v', c'). 206 | Proof. 207 | induct 1; simplify; repeat match goal with 208 | | [ H : plug _ _ _ |- _ ] => invert1 H 209 | end; eauto. 210 | Qed. 211 | 212 | Global Hint Resolve cstep_step' : core. 213 | 214 | Theorem cstep_step : forall v c v' c', 215 | cstep (v, c) (v', c') 216 | -> step (v, c) (v', c'). 217 | Proof. 218 | invert 1; eauto. 219 | Qed. 220 | -------------------------------------------------------------------------------- /Interpreters.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * Chapter 4: Semantics via Interpreters 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *) 5 | 6 | Require Import Frap. 7 | 8 | 9 | (* We begin with a return to our arithmetic language from BasicSyntax, 10 | * adding subtraction*, which will come in handy later. 11 | * *: good pun, right? *) 12 | Inductive arith : Set := 13 | | Const (n : nat) 14 | | Var (x : var) 15 | | Plus (e1 e2 : arith) 16 | | Minus (e1 e2 : arith) 17 | | Times (e1 e2 : arith). 18 | 19 | Example ex1 := Const 42. 20 | Example ex2 := Plus (Var "y") (Times (Var "x") (Const 3)). 21 | 22 | (* The above definition only explains what programs *look like*. 23 | * We also care about what they *mean*. 24 | * The natural meaning of an expression is the number it evaluates to. 25 | * Actually, it's not quite that simple. 26 | * We need to consider the meaning to be a function over a valuation 27 | * to the variables, which in turn is itself a finite map from variable 28 | * names to numbers. We use the book library's [fmap] type family. *) 29 | Definition valuation := fmap var nat. 30 | (* That is, the domain is [var] (a synonym for [string]) and the codomain/range 31 | * is [nat]. *) 32 | 33 | (* The interpreter is a fairly innocuous-looking recursive function. *) 34 | Fixpoint interp (e : arith) (v : valuation) : nat := 35 | match e with 36 | | Const n => n 37 | | Var x => 38 | (* Note use of infix operator to look up a key in a finite map. *) 39 | match v $? x with 40 | | None => 0 (* goofy default value! *) 41 | | Some n => n 42 | end 43 | | Plus e1 e2 => interp e1 v + interp e2 v 44 | | Minus e1 e2 => interp e1 v - interp e2 v 45 | (* For anyone who's wondering: this [-] sticks at 0, 46 | * if we would otherwise underflow. *) 47 | | Times e1 e2 => interp e1 v * interp e2 v 48 | end. 49 | 50 | (* Here's an example valuation, using an infix operator for map extension. *) 51 | Definition valuation0 : valuation := 52 | $0 $+ ("x", 17) $+ ("y", 3). 53 | 54 | (* Unfortunately, we can't execute code based on finite maps, since, for 55 | * convenience, they use uncomputable features. The reason is that we need a 56 | * comparison function, a hash function, etc., to do computable finite-map 57 | * implementation, and such things are impossible to compute automatically for 58 | * all types in Coq. However, we can still prove theorems about execution of 59 | * finite-map programs, and the [simplify] tactic knows how to reduce the 60 | * key constructions. *) 61 | Theorem interp_ex1 : interp ex1 valuation0 = 42. 62 | Proof. 63 | simplify. 64 | equality. 65 | Qed. 66 | 67 | Theorem interp_ex2 : interp ex2 valuation0 = 54. 68 | Proof. 69 | unfold valuation0. 70 | simplify. 71 | equality. 72 | Qed. 73 | 74 | (* Here's the silly transformation we defined last time. *) 75 | Fixpoint commuter (e : arith) : arith := 76 | match e with 77 | | Const _ => e 78 | | Var _ => e 79 | | Plus e1 e2 => Plus (commuter e2) (commuter e1) 80 | | Minus e1 e2 => Minus (commuter e1) (commuter e2) 81 | (* ^-- NB: didn't change the operand order here! *) 82 | | Times e1 e2 => Times (commuter e2) (commuter e1) 83 | end. 84 | 85 | (* Instead of proving various odds-and-ends properties about it, 86 | * let's show what we *really* care about: it preserves the 87 | * *meanings* of expressions! *) 88 | Theorem commuter_ok : forall v e, interp (commuter e) v = interp e v. 89 | Proof. 90 | induct e; simplify. 91 | 92 | equality. 93 | 94 | equality. 95 | 96 | linear_arithmetic. 97 | 98 | equality. 99 | 100 | rewrite IHe1, IHe2. 101 | ring. 102 | Qed. 103 | (* Well, that's a relief! ;-) *) 104 | 105 | (* Let's also revisit substitution. *) 106 | Fixpoint substitute (inThis : arith) (replaceThis : var) (withThis : arith) : arith := 107 | match inThis with 108 | | Const _ => inThis 109 | | Var x => if x ==v replaceThis then withThis else inThis 110 | | Plus e1 e2 => Plus (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 111 | | Minus e1 e2 => Minus (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 112 | | Times e1 e2 => Times (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 113 | end. 114 | 115 | Theorem substitute_ok : forall v replaceThis withThis inThis, 116 | interp (substitute inThis replaceThis withThis) v 117 | = interp inThis (v $+ (replaceThis, interp withThis v)). 118 | Proof. 119 | induct inThis; simplify; try equality. 120 | 121 | (* One case left after our basic heuristic: 122 | * the variable case, naturally! *) 123 | cases (x ==v replaceThis); simplify; equality. 124 | Qed. 125 | (* Great; we seem to have gotten that one right, too. *) 126 | 127 | (* Let's also define a pared-down version of the expression-simplification 128 | * functions from last chapter. *) 129 | Fixpoint doSomeArithmetic (e : arith) : arith := 130 | match e with 131 | | Const _ => e 132 | | Var _ => e 133 | | Plus (Const n1) (Const n2) => Const (n1 + n2) 134 | | Plus e1 e2 => Plus (doSomeArithmetic e1) (doSomeArithmetic e2) 135 | | Minus e1 e2 => Minus (doSomeArithmetic e1) (doSomeArithmetic e2) 136 | | Times (Const n1) (Const n2) => Const (n1 * n2) 137 | | Times e1 e2 => Times (doSomeArithmetic e1) (doSomeArithmetic e2) 138 | end. 139 | 140 | Theorem doSomeArithmetic_ok : forall e v, interp (doSomeArithmetic e) v = interp e v. 141 | Proof. 142 | induct e; simplify; try equality. 143 | 144 | cases e1; simplify; try equality. 145 | cases e2; simplify; equality. 146 | 147 | cases e1; simplify; try equality. 148 | cases e2; simplify; equality. 149 | Qed. 150 | 151 | (* Of course, we're going to get bored if we confine ourselves to arithmetic 152 | * expressions for the rest of our journey. Let's get a bit fancier and define 153 | * a *stack machine*, related to postfix calculators that some of you may have 154 | * experienced. *) 155 | Inductive instruction := 156 | | PushConst (n : nat) 157 | | PushVar (x : var) 158 | | Add 159 | | Subtract 160 | | Multiply. 161 | 162 | (* What does it all mean? An interpreter tells us unambiguously! *) 163 | Definition run1 (i : instruction) (v : valuation) (stack : list nat) : list nat := 164 | match i with 165 | | PushConst n => n :: stack 166 | | PushVar x => (match v $? x with 167 | | None => 0 168 | | Some n => n 169 | end) :: stack 170 | | Add => 171 | match stack with 172 | | arg2 :: arg1 :: stack' => arg1 + arg2 :: stack' 173 | | _ => stack (* arbitrary behavior in erroneous case (stack underflow) *) 174 | end 175 | | Subtract => 176 | match stack with 177 | | arg2 :: arg1 :: stack' => arg1 - arg2 :: stack' 178 | | _ => stack (* arbitrary behavior in erroneous case *) 179 | end 180 | | Multiply => 181 | match stack with 182 | | arg2 :: arg1 :: stack' => arg1 * arg2 :: stack' 183 | | _ => stack (* arbitrary behavior in erroneous case *) 184 | end 185 | end. 186 | 187 | (* That function explained how to run one instruction. 188 | * Here's how to run several of them. *) 189 | Fixpoint run (is : list instruction) (v : valuation) (stack : list nat) : list nat := 190 | match is with 191 | | nil => stack 192 | | i :: is' => run is' v (run1 i v stack) 193 | end. 194 | 195 | (* Instead of writing fiddly stack programs ourselves, let's *compile* 196 | * arithmetic expressions into equivalent stack programs. *) 197 | Fixpoint compile (e : arith) : list instruction := 198 | match e with 199 | | Const n => PushConst n :: nil 200 | | Var x => PushVar x :: nil 201 | | Plus e1 e2 => compile e1 ++ compile e2 ++ Add :: nil 202 | | Minus e1 e2 => compile e1 ++ compile e2 ++ Subtract :: nil 203 | | Times e1 e2 => compile e1 ++ compile e2 ++ Multiply :: nil 204 | end. 205 | 206 | (* Now, of course, we should prove our compiler correct. 207 | * Skip down to the next theorem to see the overall correctness statement. 208 | * It turns out that we need to strengthen the induction hypothesis with a 209 | * lemma, to push the proof through. *) 210 | Lemma compile_ok' : forall e v is stack, 211 | run (compile e ++ is) v stack = run is v (interp e v :: stack). 212 | Proof. 213 | induct e; simplify. 214 | 215 | equality. 216 | 217 | equality. 218 | 219 | (* Here we want to use associativity of [++], to get the conclusion to match 220 | * an induction hypothesis. Let's ask Coq to search its library for lemmas 221 | * that would justify such a rewrite, giving a pattern with wildcards, to 222 | * specify the essential structure that the rewrite should match. *) 223 | Search ((_ ++ _) ++ _). 224 | (* Ah, we see just the one! *) 225 | rewrite app_assoc_reverse. 226 | rewrite IHe1. 227 | rewrite app_assoc_reverse. 228 | rewrite IHe2. 229 | simplify. 230 | equality. 231 | 232 | rewrite app_assoc_reverse. 233 | rewrite IHe1. 234 | rewrite app_assoc_reverse. 235 | rewrite IHe2. 236 | simplify. 237 | equality. 238 | 239 | rewrite app_assoc_reverse. 240 | rewrite IHe1. 241 | rewrite app_assoc_reverse. 242 | rewrite IHe2. 243 | simplify. 244 | equality. 245 | Qed. 246 | 247 | (* The overall theorem follows as a simple corollary. *) 248 | Theorem compile_ok : forall e v, run (compile e) v nil = interp e v :: nil. 249 | Proof. 250 | simplify. 251 | 252 | (* To match the form of our lemma, we need to replace [compile e] with 253 | * [compile e ++ nil], adding a "pointless" concatenation of the empty list. 254 | * [Search] again helps us find a library lemma. *) 255 | Search (_ ++ nil). 256 | rewrite (app_nil_end (compile e)). 257 | (* Note that we can use [rewrite] with explicit values of the first few 258 | * quantified variables of a lemma. Otherwise, [rewrite] picks an 259 | * unhelpful place to rewrite. (Try it and see!) *) 260 | 261 | apply compile_ok'. 262 | (* Direct appeal to a previously proved lemma *) 263 | Qed. 264 | 265 | 266 | (* Let's get a bit fancier, moving toward the level of general-purpose 267 | * imperative languages. Here's a language of commands, building on the 268 | * language of expressions we have defined. *) 269 | Inductive cmd := 270 | | Skip 271 | | Assign (x : var) (e : arith) 272 | | Sequence (c1 c2 : cmd) 273 | | Repeat (e : arith) (body : cmd). 274 | 275 | (* That last constructor is for repeating a body command some number of 276 | * times. Note that we sneakily avoid constructs that could introduce 277 | * nontermination, since Coq only accepts terminating programs, and we want to 278 | * write an interpreter for commands. 279 | * In contrast to our last one, this interpreter *transforms valuations*. 280 | * We use a helper function for self-composing a function some number of 281 | * times. *) 282 | 283 | Fixpoint selfCompose {A} (f : A -> A) (n : nat) : A -> A := 284 | match n with 285 | | O => fun x => x 286 | | S n' => fun x => selfCompose f n' (f x) 287 | end. 288 | 289 | Fixpoint exec (c : cmd) (v : valuation) : valuation := 290 | match c with 291 | | Skip => v 292 | | Assign x e => v $+ (x, interp e v) 293 | | Sequence c1 c2 => exec c2 (exec c1 v) 294 | | Repeat e body => selfCompose (exec body) (interp e v) v 295 | end. 296 | 297 | (* Let's define some programs and prove that they operate in certain ways. *) 298 | 299 | Example factorial_ugly := 300 | Sequence 301 | (Assign "output" (Const 1)) 302 | (Repeat (Var "input") 303 | (Sequence 304 | (Assign "output" (Times (Var "output") (Var "input"))) 305 | (Assign "input" (Minus (Var "input") (Const 1))))). 306 | 307 | (* Ouch; that code is hard to read. Let's introduce some notations to make the 308 | * concrete syntax more palatable. We won't explain the general mechanisms on 309 | * display here, but see the Coq manual for details, or try to reverse-engineer 310 | * them from our examples. *) 311 | Coercion Const : nat >-> arith. 312 | Coercion Var : var >-> arith. 313 | (*Declare Scope arith_scope.*) 314 | Infix "+" := Plus : arith_scope. 315 | Infix "-" := Minus : arith_scope. 316 | Infix "*" := Times : arith_scope. 317 | Delimit Scope arith_scope with arith. 318 | Notation "x <- e" := (Assign x e%arith) (at level 75). 319 | Infix ";" := Sequence (at level 76). 320 | Notation "'repeat' e 'doing' body 'done'" := (Repeat e%arith body) (at level 75). 321 | 322 | (* OK, let's try that program again. *) 323 | Example factorial := 324 | "output" <- 1; 325 | repeat "input" doing 326 | "output" <- "output" * "input"; 327 | "input" <- "input" - 1 328 | done. 329 | 330 | (* Now we prove that it really computes factorial. 331 | * First, a reference implementation as a functional program. *) 332 | Fixpoint fact (n : nat) : nat := 333 | match n with 334 | | O => 1 335 | | S n' => n * fact n' 336 | end. 337 | 338 | (* To prove that [factorial] is correct, the real action is in a lemma, to be 339 | * proved by induction, showing that the loop works correctly. So, let's first 340 | * assign a name to the loop body alone. *) 341 | Definition factorial_body := 342 | "output" <- "output" * "input"; 343 | "input" <- "input" - 1. 344 | 345 | (* Now for that lemma: self-composition of the body's semantics produces the 346 | * expected changes in the valuation. 347 | * Note that here we're careful to put the quantified variable [input] *first*, 348 | * because the variables coming after it will need to *change* in the course of 349 | * the induction. Try switching the order to see what goes wrong if we put 350 | * [input] later. *) 351 | Lemma factorial_ok' : forall input output v, 352 | v $? "input" = Some input 353 | -> v $? "output" = Some output 354 | -> selfCompose (exec factorial_body) input v 355 | = v $+ ("input", 0) $+ ("output", output * fact input). 356 | Proof. 357 | induct input; simplify. 358 | 359 | maps_equal. 360 | (* [maps_equal]: prove that two finite maps are equal by considering all 361 | * the relevant cases for mappings of different keys. *) 362 | 363 | rewrite H0. 364 | f_equal. 365 | linear_arithmetic. 366 | 367 | trivial. 368 | (* [trivial]: Coq maintains a database of simple proof steps, such as proving 369 | * a fact by direct appeal to a matching hypothesis. [trivial] asks to try 370 | * all such simple steps. *) 371 | 372 | rewrite H, H0. 373 | (* Note the two arguments to one [rewrite]! *) 374 | rewrite (IHinput (output * S input)). 375 | (* Note the careful choice of a quantifier instantiation for the IH! *) 376 | maps_equal. 377 | f_equal; ring. 378 | simplify; f_equal; linear_arithmetic. 379 | simplify; equality. 380 | Qed. 381 | 382 | (* Finally, we have the natural correctness condition for factorial as a whole 383 | * program. *) 384 | Theorem factorial_ok : forall v input, 385 | v $? "input" = Some input 386 | -> exec factorial v $? "output" = Some (fact input). 387 | Proof. 388 | simplify. 389 | rewrite H. 390 | rewrite (factorial_ok' input 1); simplify. 391 | f_equal; linear_arithmetic. 392 | trivial. 393 | trivial. 394 | Qed. 395 | 396 | 397 | (* One last example: let's try to do loop unrolling, for constant iteration 398 | * counts. That is, we can duplicate the loop body instead of using an explicit 399 | * loop. *) 400 | 401 | Fixpoint seqself (c : cmd) (n : nat) : cmd := 402 | match n with 403 | | O => Skip 404 | | S n' => Sequence c (seqself c n') 405 | end. 406 | 407 | Fixpoint unroll (c : cmd) : cmd := 408 | match c with 409 | | Skip => c 410 | | Assign _ _ => c 411 | | Sequence c1 c2 => Sequence (unroll c1) (unroll c2) 412 | | Repeat (Const n) c1 => seqself (unroll c1) n 413 | (* ^-- the crucial case! *) 414 | | Repeat e c1 => Repeat e (unroll c1) 415 | end. 416 | 417 | (* This obvious-sounding fact will come in handy: self-composition gives the 418 | * same result, when passed two functions that map equal inputs to equal 419 | * outputs. *) 420 | Lemma selfCompose_extensional : forall {A} (f g : A -> A) n x, 421 | (forall y, f y = g y) 422 | -> selfCompose f n x = selfCompose g n x. 423 | Proof. 424 | induct n; simplify; try equality. 425 | 426 | rewrite H. 427 | apply IHn. 428 | trivial. 429 | Qed. 430 | 431 | (* Crucial lemma: [seqself] is acting just like [selfCompose], in a suitable 432 | * sense. *) 433 | Lemma seqself_ok : forall c n v, 434 | exec (seqself c n) v = selfCompose (exec c) n v. 435 | Proof. 436 | induct n; simplify; equality. 437 | Qed. 438 | 439 | (* The two lemmas we just proved are the main ingredients to prove the natural 440 | * correctness condition for [unroll]. *) 441 | Theorem unroll_ok : forall c v, exec (unroll c) v = exec c v. 442 | Proof. 443 | induct c; simplify; try equality. 444 | 445 | cases e; simplify; try equality. 446 | 447 | rewrite seqself_ok. 448 | apply selfCompose_extensional. 449 | trivial. 450 | 451 | apply selfCompose_extensional. 452 | trivial. 453 | 454 | apply selfCompose_extensional. 455 | trivial. 456 | 457 | apply selfCompose_extensional. 458 | trivial. 459 | 460 | apply selfCompose_extensional. 461 | trivial. 462 | Qed. 463 | -------------------------------------------------------------------------------- /Interpreters_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | 4 | (* We begin with a return to our arithmetic language from the last chapter, 5 | * adding subtraction*, which will come in handy later. 6 | * *: good pun, right? *) 7 | Inductive arith : Set := 8 | | Const (n : nat) 9 | | Var (x : var) 10 | | Plus (e1 e2 : arith) 11 | | Minus (e1 e2 : arith) 12 | | Times (e1 e2 : arith). 13 | 14 | Example ex1 := Const 42. 15 | Example ex2 := Plus (Var "y") (Times (Var "x") (Const 3)). 16 | 17 | Definition valuation := fmap var nat. 18 | (* A valuation is a finite map from [var] to [nat]. *) 19 | 20 | (* The interpreter is a fairly innocuous-looking recursive function. *) 21 | Fixpoint interp (e : arith) (v : valuation) : nat := 22 | match e with 23 | | Const n => n 24 | | Var x => 25 | (* Note use of infix operator to look up a key in a finite map. *) 26 | match v $? x with 27 | | None => 0 (* goofy default value! *) 28 | | Some n => n 29 | end 30 | | Plus e1 e2 => interp e1 v + interp e2 v 31 | | Minus e1 e2 => interp e1 v - interp e2 v 32 | (* For anyone who's wondering: this [-] sticks at 0, 33 | * if we would otherwise underflow. *) 34 | | Times e1 e2 => interp e1 v * interp e2 v 35 | end. 36 | 37 | (* Here's an example valuation, using an infix operator for map extension. *) 38 | Definition valuation0 : valuation := 39 | $0 $+ ("x", 17) $+ ("y", 3). 40 | 41 | Theorem interp_ex1 : interp ex1 valuation0 = 42. 42 | Proof. 43 | simplify. 44 | equality. 45 | Qed. 46 | 47 | Theorem interp_ex2 : interp ex2 valuation0 = 54. 48 | Proof. 49 | unfold valuation0. 50 | simplify. 51 | equality. 52 | Qed. 53 | 54 | (* Here's the silly transformation we defined last time. *) 55 | Fixpoint commuter (e : arith) : arith := 56 | match e with 57 | | Const _ => e 58 | | Var _ => e 59 | | Plus e1 e2 => Plus (commuter e2) (commuter e1) 60 | | Minus e1 e2 => Minus (commuter e1) (commuter e2) 61 | (* ^-- NB: didn't change the operand order here! *) 62 | | Times e1 e2 => Times (commuter e2) (commuter e1) 63 | end. 64 | 65 | (* Instead of proving various odds-and-ends properties about it, 66 | * let's show what we *really* care about: it preserves the 67 | * *meanings* of expressions! *) 68 | Theorem commuter_ok : forall v e, interp (commuter e) v = interp e v. 69 | Proof. 70 | Admitted. 71 | 72 | (* Let's also revisit substitution. *) 73 | Fixpoint substitute (inThis : arith) (replaceThis : var) (withThis : arith) : arith := 74 | match inThis with 75 | | Const _ => inThis 76 | | Var x => if x ==v replaceThis then withThis else inThis 77 | | Plus e1 e2 => Plus (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 78 | | Minus e1 e2 => Minus (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 79 | | Times e1 e2 => Times (substitute e1 replaceThis withThis) (substitute e2 replaceThis withThis) 80 | end. 81 | 82 | (* How should we state a correctness property for [substitute]? 83 | Theorem substitute_ok : forall v replaceThis withThis inThis, 84 | ... 85 | Proof. 86 | 87 | Qed.*) 88 | 89 | (* Let's also defined a pared-down version of the expression-simplificaton 90 | * functions from last chapter. *) 91 | Fixpoint doSomeArithmetic (e : arith) : arith := 92 | match e with 93 | | Const _ => e 94 | | Var _ => e 95 | | Plus (Const n1) (Const n2) => Const (n1 + n2) 96 | | Plus e1 e2 => Plus (doSomeArithmetic e1) (doSomeArithmetic e2) 97 | | Minus e1 e2 => Minus (doSomeArithmetic e1) (doSomeArithmetic e2) 98 | | Times (Const n1) (Const n2) => Const (n1 * n2) 99 | | Times e1 e2 => Times (doSomeArithmetic e1) (doSomeArithmetic e2) 100 | end. 101 | 102 | Theorem doSomeArithmetic_ok : forall e v, interp (doSomeArithmetic e) v = interp e v. 103 | Proof. 104 | Admitted. 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | (* Of course, we're going to get bored if we confine ourselves to arithmetic 128 | * expressions for the rest of our journey. Let's get a bit fancier and define 129 | * a *stack machine*, related to postfix calculators that some of you may have 130 | * experienced. *) 131 | Inductive instruction := 132 | | PushConst (n : nat) 133 | | PushVar (x : var) 134 | | Add 135 | | Subtract 136 | | Multiply. 137 | 138 | (* What does it all mean? An interpreter tells us unambiguously! *) 139 | Definition run1 (i : instruction) (v : valuation) (stack : list nat) : list nat := 140 | match i with 141 | | PushConst n => n :: stack 142 | | PushVar x => (match v $? x with 143 | | None => 0 144 | | Some n => n 145 | end) :: stack 146 | | Add => 147 | match stack with 148 | | arg2 :: arg1 :: stack' => arg1 + arg2 :: stack' 149 | | _ => stack (* arbitrary behavior in erroneous case (stack underflow) *) 150 | end 151 | | Subtract => 152 | match stack with 153 | | arg2 :: arg1 :: stack' => arg1 - arg2 :: stack' 154 | | _ => stack (* arbitrary behavior in erroneous case *) 155 | end 156 | | Multiply => 157 | match stack with 158 | | arg2 :: arg1 :: stack' => arg1 * arg2 :: stack' 159 | | _ => stack (* arbitrary behavior in erroneous case *) 160 | end 161 | end. 162 | 163 | (* That function explained how to run one instruction. 164 | * Here's how to run several of them. *) 165 | Fixpoint run (is : list instruction) (v : valuation) (stack : list nat) : list nat := 166 | match is with 167 | | nil => stack 168 | | i :: is' => run is' v (run1 i v stack) 169 | end. 170 | 171 | (* Instead of writing fiddly stack programs ourselves, let's *compile* 172 | * arithmetic expressions into equivalent stack programs. *) 173 | Fixpoint compile (e : arith) : list instruction := 174 | match e with 175 | | Const n => PushConst n :: nil 176 | | Var x => PushVar x :: nil 177 | | Plus e1 e2 => compile e1 ++ compile e2 ++ Add :: nil 178 | | Minus e1 e2 => compile e1 ++ compile e2 ++ Subtract :: nil 179 | | Times e1 e2 => compile e1 ++ compile e2 ++ Multiply :: nil 180 | end. 181 | 182 | Theorem compile_ok : forall e v, run (compile e) v nil = interp e v :: nil. 183 | Proof. 184 | Admitted. 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | (* Let's get a bit fancier, moving toward the level of general-purpose 214 | * imperative languages. Here's a language of commands, building on the 215 | * language of expressions we have defined. *) 216 | Inductive cmd := 217 | | Skip 218 | | Assign (x : var) (e : arith) 219 | | Sequence (c1 c2 : cmd) 220 | | Repeat (e : arith) (body : cmd). 221 | 222 | Fixpoint selfCompose {A} (f : A -> A) (n : nat) : A -> A := 223 | match n with 224 | | O => fun x => x 225 | | S n' => fun x => selfCompose f n' (f x) 226 | end. 227 | 228 | Fixpoint exec (c : cmd) (v : valuation) : valuation := 229 | match c with 230 | | Skip => v 231 | | Assign x e => v $+ (x, interp e v) 232 | | Sequence c1 c2 => exec c2 (exec c1 v) 233 | | Repeat e body => selfCompose (exec body) (interp e v) v 234 | end. 235 | 236 | (* Let's define some programs and prove that they operate in certain ways. *) 237 | 238 | Example factorial_ugly := 239 | Sequence 240 | (Assign "output" (Const 1)) 241 | (Repeat (Var "input") 242 | (Sequence 243 | (Assign "output" (Times (Var "output") (Var "input"))) 244 | (Assign "input" (Minus (Var "input") (Const 1))))). 245 | 246 | (* Ouch; that code is hard to read. Let's introduce some notations to make the 247 | * concrete syntax more palatable. We won't explain the general mechanisms on 248 | * display here, but see the Coq manual for details, or try to reverse-engineer 249 | * them from our examples. *) 250 | Coercion Const : nat >-> arith. 251 | Coercion Var : var >-> arith. 252 | (*Declare Scope arith_scope.*) 253 | Infix "+" := Plus : arith_scope. 254 | Infix "-" := Minus : arith_scope. 255 | Infix "*" := Times : arith_scope. 256 | Delimit Scope arith_scope with arith. 257 | Notation "x <- e" := (Assign x e%arith) (at level 75). 258 | Infix ";" := Sequence (at level 76). 259 | Notation "'repeat' e 'doing' body 'done'" := (Repeat e%arith body) (at level 75). 260 | 261 | (* OK, let's try that program again. *) 262 | Example factorial := 263 | "output" <- 1; 264 | repeat "input" doing 265 | "output" <- "output" * "input"; 266 | "input" <- "input" - 1 267 | done. 268 | 269 | (* Now we prove that it really computes factorial. 270 | * First, a reference implementation as a functional program. *) 271 | Fixpoint fact (n : nat) : nat := 272 | match n with 273 | | O => 1 274 | | S n' => n * fact n' 275 | end. 276 | 277 | Theorem factorial_ok : forall v input, 278 | v $? "input" = Some input 279 | -> exec factorial v $? "output" = Some (fact input). 280 | Proof. 281 | Admitted. 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | (* One last example: let's try to do loop unrolling, for constant iteration 302 | * counts. That is, we can duplicate the loop body instead of using an explicit 303 | * loop. *) 304 | 305 | (* This obvious-sounding fact will come in handy: self-composition gives the 306 | * same result, when passed two functions that map equal inputs to equal 307 | * outputs. *) 308 | Lemma selfCompose_extensional : forall {A} (f g : A -> A) n x, 309 | (forall y, f y = g y) 310 | -> selfCompose f n x = selfCompose g n x. 311 | Proof. 312 | induct n; simplify; try equality. 313 | 314 | rewrite H. 315 | apply IHn. 316 | trivial. 317 | Qed. 318 | 319 | (*Theorem unroll_ok : forall c v, exec (unroll c) v = exec c v. 320 | Proof. 321 | 322 | Qed.*) 323 | -------------------------------------------------------------------------------- /IntroToProofScripting_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | Set Implicit Arguments. 4 | 5 | 6 | (** * Ltac Programming Basics *) 7 | 8 | Theorem hmm : forall (a b c : bool), 9 | if a 10 | then if b 11 | then True 12 | else True 13 | else if c 14 | then True 15 | else True. 16 | Proof. 17 | Admitted. 18 | 19 | Theorem hmm2 : forall (a b : bool), 20 | (if a then 42 else 42) = (if b then 42 else 42). 21 | Proof. 22 | Admitted. 23 | 24 | 25 | (** * Automating the two-thread locked-increment example from TransitionSystems *) 26 | 27 | (* Let's experience the process of gradually automating the proof we finished 28 | * the last lecture with. Here's the system-definition code, stripped of 29 | * comments. *) 30 | 31 | Inductive increment_program := 32 | | Lock 33 | | Read 34 | | Write (local : nat) 35 | | Unlock 36 | | Done. 37 | 38 | Record inc_state := { 39 | Locked : bool; 40 | Global : nat 41 | }. 42 | 43 | Record threaded_state shared private := { 44 | Shared : shared; 45 | Private : private 46 | }. 47 | 48 | Definition increment_state := threaded_state inc_state increment_program. 49 | 50 | Inductive increment_init : increment_state -> Prop := 51 | | IncInit : 52 | increment_init {| Shared := {| Locked := false; Global := O |}; 53 | Private := Lock |}. 54 | 55 | Inductive increment_step : increment_state -> increment_state -> Prop := 56 | | IncLock : forall g, 57 | increment_step {| Shared := {| Locked := false; Global := g |}; 58 | Private := Lock |} 59 | {| Shared := {| Locked := true; Global := g |}; 60 | Private := Read |} 61 | | IncRead : forall l g, 62 | increment_step {| Shared := {| Locked := l; Global := g |}; 63 | Private := Read |} 64 | {| Shared := {| Locked := l; Global := g |}; 65 | Private := Write g |} 66 | | IncWrite : forall l g v, 67 | increment_step {| Shared := {| Locked := l; Global := g |}; 68 | Private := Write v |} 69 | {| Shared := {| Locked := l; Global := S v |}; 70 | Private := Unlock |} 71 | | IncUnlock : forall l g, 72 | increment_step {| Shared := {| Locked := l; Global := g |}; 73 | Private := Unlock |} 74 | {| Shared := {| Locked := false; Global := g |}; 75 | Private := Done |}. 76 | 77 | Definition increment_sys := {| 78 | Initial := increment_init; 79 | Step := increment_step 80 | |}. 81 | 82 | Inductive parallel1 shared private1 private2 83 | (init1 : threaded_state shared private1 -> Prop) 84 | (init2 : threaded_state shared private2 -> Prop) 85 | : threaded_state shared (private1 * private2) -> Prop := 86 | | Pinit : forall sh pr1 pr2, 87 | init1 {| Shared := sh; Private := pr1 |} 88 | -> init2 {| Shared := sh; Private := pr2 |} 89 | -> parallel1 init1 init2 {| Shared := sh; Private := (pr1, pr2) |}. 90 | 91 | Inductive parallel2 shared private1 private2 92 | (step1 : threaded_state shared private1 -> threaded_state shared private1 -> Prop) 93 | (step2 : threaded_state shared private2 -> threaded_state shared private2 -> Prop) 94 | : threaded_state shared (private1 * private2) 95 | -> threaded_state shared (private1 * private2) -> Prop := 96 | | Pstep1 : forall sh pr1 pr2 sh' pr1', 97 | step1 {| Shared := sh; Private := pr1 |} {| Shared := sh'; Private := pr1' |} 98 | -> parallel2 step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 99 | {| Shared := sh'; Private := (pr1', pr2) |} 100 | | Pstep2 : forall sh pr1 pr2 sh' pr2', 101 | step2 {| Shared := sh; Private := pr2 |} {| Shared := sh'; Private := pr2' |} 102 | -> parallel2 step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 103 | {| Shared := sh'; Private := (pr1, pr2') |}. 104 | 105 | Definition parallel shared private1 private2 106 | (sys1 : trsys (threaded_state shared private1)) 107 | (sys2 : trsys (threaded_state shared private2)) := {| 108 | Initial := parallel1 sys1.(Initial) sys2.(Initial); 109 | Step := parallel2 sys1.(Step) sys2.(Step) 110 | |}. 111 | 112 | Definition increment2_sys := parallel increment_sys increment_sys. 113 | 114 | Definition contribution_from (pr : increment_program) : nat := 115 | match pr with 116 | | Unlock => 1 117 | | Done => 1 118 | | _ => 0 119 | end. 120 | 121 | Definition has_lock (pr : increment_program) : bool := 122 | match pr with 123 | | Read => true 124 | | Write _ => true 125 | | Unlock => true 126 | | _ => false 127 | end. 128 | 129 | Definition shared_from_private (pr1 pr2 : increment_program) := 130 | {| Locked := has_lock pr1 || has_lock pr2; 131 | Global := contribution_from pr1 + contribution_from pr2 |}. 132 | 133 | Definition instruction_ok (self other : increment_program) := 134 | match self with 135 | | Lock => True 136 | | Read => has_lock other = false 137 | | Write n => has_lock other = false /\ n = contribution_from other 138 | | Unlock => has_lock other = false 139 | | Done => True 140 | end. 141 | 142 | Inductive increment2_invariant : 143 | threaded_state inc_state (increment_program * increment_program) -> Prop := 144 | | Inc2Inv : forall pr1 pr2, 145 | instruction_ok pr1 pr2 146 | -> instruction_ok pr2 pr1 147 | -> increment2_invariant {| Shared := shared_from_private pr1 pr2; Private := (pr1, pr2) |}. 148 | 149 | Lemma Inc2Inv' : forall sh pr1 pr2, 150 | sh = shared_from_private pr1 pr2 151 | -> instruction_ok pr1 pr2 152 | -> instruction_ok pr2 pr1 153 | -> increment2_invariant {| Shared := sh; Private := (pr1, pr2) |}. 154 | Proof. 155 | simplify. 156 | rewrite H. 157 | apply Inc2Inv; assumption. 158 | Qed. 159 | 160 | (* OK, HERE is where we prove the main theorem. *) 161 | 162 | Theorem increment2_invariant_ok : invariantFor increment2_sys increment2_invariant. 163 | Proof. 164 | Admitted. 165 | 166 | 167 | (** * Implementing some of [propositional] ourselves *) 168 | 169 | Print True. 170 | Print False. 171 | Locate "/\". 172 | Print and. 173 | Locate "\/". 174 | Print or. 175 | (* Implication ([->]) is built into Coq, so nothing to look up there. *) 176 | 177 | Section propositional. 178 | Variables P Q R : Prop. 179 | 180 | Theorem propositional : (P \/ Q \/ False) /\ (P -> Q) -> True /\ Q. 181 | Proof. 182 | Admitted. 183 | End propositional. 184 | 185 | (* Backtracking example #1 *) 186 | 187 | Theorem m1 : True. 188 | Proof. 189 | match goal with 190 | | [ |- _ ] => intro 191 | | [ |- True ] => constructor 192 | end. 193 | Qed. 194 | 195 | (* Backtracking example #2 *) 196 | 197 | Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q. 198 | Proof. 199 | intros; match goal with 200 | | [ H : _ |- _ ] => idtac H 201 | end. 202 | Admitted. 203 | 204 | (* Let's try some more ambitious reasoning, with quantifiers. We'll be 205 | * instantiating quantified facts heuristically. If we're not careful, we get 206 | * in a loop repeating the same instantiation forever. *) 207 | 208 | (* Spec: ensure that [P] doesn't follow trivially from hypotheses. *) 209 | Ltac notHyp P := idtac. 210 | 211 | (* Spec: add [pf] as hypothesis only if it doesn't already follow trivially. *) 212 | Ltac extend pf := idtac. 213 | 214 | (* Spec: add all simple consequences of known facts, including 215 | * [forall]-quantified. *) 216 | Ltac completer := idtac. 217 | 218 | Section firstorder. 219 | Variable A : Set. 220 | Variables P Q R S : A -> Prop. 221 | 222 | Hypothesis H1 : forall x, P x -> Q x /\ R x. 223 | Hypothesis H2 : forall x, R x -> S x. 224 | 225 | Theorem fo : forall (y x : A), P x -> S x. 226 | Proof. 227 | Admitted. 228 | End firstorder. 229 | 230 | 231 | (** * Functional Programming in Ltac *) 232 | 233 | (* Spec: return length of list. *) 234 | Ltac length ls := constr:(0). 235 | 236 | Goal False. 237 | let n := length (1 :: 2 :: 3 :: nil) in 238 | pose n. 239 | Abort. 240 | 241 | (* Spec: map Ltac function over list. *) 242 | Ltac map f ls := constr:(0). 243 | 244 | Goal False. 245 | (*let ls := map (nat * nat)%type ltac:(fun x => constr:((x, x))) (1 :: 2 :: 3 :: nil) in 246 | pose ls.*) 247 | Abort. 248 | 249 | (* Now let's revisit [length] and see how we might implement "printf debugging" 250 | * for it. *) 251 | 252 | 253 | (** * Recursive Proof Search *) 254 | 255 | (* Let's work on a tactic to try all possible instantiations of quantified 256 | * hypotheses, attempting to find out where the goal becomes obvious. *) 257 | 258 | Ltac inster n := idtac. 259 | 260 | Section test_inster. 261 | Variable A : Set. 262 | Variables P Q : A -> Prop. 263 | Variable f : A -> A. 264 | Variable g : A -> A -> A. 265 | 266 | Hypothesis H1 : forall x y, P (g x y) -> Q (f x). 267 | 268 | Theorem test_inster : forall x, P (g x x) -> Q (f x). 269 | Proof. 270 | inster 2. 271 | Admitted. 272 | 273 | Hypothesis H3 : forall u v, P u /\ P v /\ u <> v -> P (g u v). 274 | Hypothesis H4 : forall u, Q (f u) -> P u /\ P (f u). 275 | 276 | Theorem test_inster2 : forall x y, x <> y -> P x -> Q (f y) -> Q (f x). 277 | Proof. 278 | inster 3. 279 | Admitted. 280 | End test_inster. 281 | 282 | (** ** A fancier example of proof search (probably skipped on first 283 | reading/run-through) *) 284 | 285 | Definition imp (P1 P2 : Prop) := P1 -> P2. 286 | Infix "-->" := imp (no associativity, at level 95). 287 | Ltac imp := unfold imp; firstorder. 288 | 289 | (** These lemmas about [imp] will be useful in the tactic that we will write. *) 290 | 291 | Theorem and_True_prem : forall P Q, 292 | (P /\ True --> Q) 293 | -> (P --> Q). 294 | Proof. 295 | imp. 296 | Qed. 297 | 298 | Theorem and_True_conc : forall P Q, 299 | (P --> Q /\ True) 300 | -> (P --> Q). 301 | Proof. 302 | imp. 303 | Qed. 304 | 305 | Theorem pick_prem1 : forall P Q R S, 306 | (P /\ (Q /\ R) --> S) 307 | -> ((P /\ Q) /\ R --> S). 308 | Proof. 309 | imp. 310 | Qed. 311 | 312 | Theorem pick_prem2 : forall P Q R S, 313 | (Q /\ (P /\ R) --> S) 314 | -> ((P /\ Q) /\ R --> S). 315 | Proof. 316 | imp. 317 | Qed. 318 | 319 | Theorem comm_prem : forall P Q R, 320 | (P /\ Q --> R) 321 | -> (Q /\ P --> R). 322 | Proof. 323 | imp. 324 | Qed. 325 | 326 | Theorem pick_conc1 : forall P Q R S, 327 | (S --> P /\ (Q /\ R)) 328 | -> (S --> (P /\ Q) /\ R). 329 | Proof. 330 | imp. 331 | Qed. 332 | 333 | Theorem pick_conc2 : forall P Q R S, 334 | (S --> Q /\ (P /\ R)) 335 | -> (S --> (P /\ Q) /\ R). 336 | Proof. 337 | imp. 338 | Qed. 339 | 340 | Theorem comm_conc : forall P Q R, 341 | (R --> P /\ Q) 342 | -> (R --> Q /\ P). 343 | Proof. 344 | imp. 345 | Qed. 346 | 347 | Ltac search_prem tac := 348 | let rec search P := 349 | tac 350 | || (apply and_True_prem; tac) 351 | || match P with 352 | | ?P1 /\ ?P2 => 353 | (apply pick_prem1; search P1) 354 | || (apply pick_prem2; search P2) 355 | end 356 | in match goal with 357 | | [ |- ?P /\ _ --> _ ] => search P 358 | | [ |- _ /\ ?P --> _ ] => apply comm_prem; search P 359 | | [ |- _ --> _ ] => progress (tac || (apply and_True_prem; tac)) 360 | end. 361 | 362 | Ltac search_conc tac := 363 | let rec search P := 364 | tac 365 | || (apply and_True_conc; tac) 366 | || match P with 367 | | ?P1 /\ ?P2 => 368 | (apply pick_conc1; search P1) 369 | || (apply pick_conc2; search P2) 370 | end 371 | in match goal with 372 | | [ |- _ --> ?P /\ _ ] => search P 373 | | [ |- _ --> _ /\ ?P ] => apply comm_conc; search P 374 | | [ |- _ --> _ ] => progress (tac || (apply and_True_conc; tac)) 375 | end. 376 | 377 | Theorem False_prem : forall P Q, 378 | False /\ P --> Q. 379 | Proof. 380 | imp. 381 | Qed. 382 | 383 | Theorem True_conc : forall P Q : Prop, 384 | (P --> Q) 385 | -> (P --> True /\ Q). 386 | Proof. 387 | imp. 388 | Qed. 389 | 390 | Theorem Match : forall P Q R : Prop, 391 | (Q --> R) 392 | -> (P /\ Q --> P /\ R). 393 | Proof. 394 | imp. 395 | Qed. 396 | 397 | Theorem ex_prem : forall (T : Type) (P : T -> Prop) (Q R : Prop), 398 | (forall x, P x /\ Q --> R) 399 | -> (ex P /\ Q --> R). 400 | Proof. 401 | imp. 402 | Qed. 403 | 404 | Theorem ex_conc : forall (T : Type) (P : T -> Prop) (Q R : Prop) x, 405 | (Q --> P x /\ R) 406 | -> (Q --> ex P /\ R). 407 | Proof. 408 | imp. 409 | Qed. 410 | 411 | Theorem imp_True : forall P, 412 | P --> True. 413 | Proof. 414 | imp. 415 | Qed. 416 | 417 | Ltac matcher := 418 | intros; 419 | repeat search_prem ltac:(simple apply False_prem || (simple apply ex_prem; intro)); 420 | repeat search_conc ltac:(simple apply True_conc || simple eapply ex_conc 421 | || search_prem ltac:(simple apply Match)); 422 | try simple apply imp_True. 423 | 424 | (* Our tactic succeeds at proving a simple example. *) 425 | 426 | Theorem t2 : forall P Q : Prop, 427 | Q /\ (P /\ False) /\ P --> P /\ Q. 428 | Proof. 429 | matcher. 430 | Qed. 431 | 432 | (* In the generated proof, we find a trace of the workings of the search tactics. *) 433 | 434 | Print t2. 435 | 436 | (* We can also see that [matcher] is well-suited for cases where some human 437 | * intervention is needed after the automation finishes. *) 438 | 439 | Theorem t3 : forall P Q R : Prop, 440 | P /\ Q --> Q /\ R /\ P. 441 | Proof. 442 | matcher. 443 | Abort. 444 | 445 | (* The [matcher] tactic even succeeds at guessing quantifier instantiations. It 446 | * is the unification that occurs in uses of the [Match] lemma that does the 447 | * real work here. *) 448 | 449 | Theorem t4 : forall (P : nat -> Prop) Q, (exists x, P x /\ Q) --> Q /\ (exists x, P x). 450 | Proof. 451 | matcher. 452 | Qed. 453 | 454 | Print t4. 455 | 456 | 457 | (** * Creating Unification Variables *) 458 | 459 | (* A final useful ingredient in tactic crafting is the ability to allocate new 460 | * unification variables explicitly. Before we are ready to write a tactic, we 461 | * can try out its ingredients one at a time. *) 462 | 463 | Theorem t5 : (forall x : nat, S x > x) -> 2 > 1. 464 | Proof. 465 | intros. 466 | 467 | evar (y : nat). 468 | 469 | let y' := eval unfold y in y in 470 | clear y; specialize (H y'). 471 | 472 | apply H. 473 | Qed. 474 | 475 | (* Spec: create new evar of type [T] and pass to [k]. *) 476 | Ltac newEvar T k := idtac. 477 | 478 | (* Spec: instantiate initial [forall]s of [H] with new evars. *) 479 | Ltac insterU H := idtac. 480 | 481 | Theorem t5' : (forall x : nat, S x > x) -> 2 > 1. 482 | Proof. 483 | Admitted. 484 | 485 | (* This particular example is somewhat silly, since [apply] by itself would have 486 | * solved the goal originally. Separate forward reasoning is more useful on 487 | * hypotheses that end in existential quantifications. Before we go through an 488 | * example, it is useful to define a variant of [insterU] that does not clear 489 | * the base hypothesis we pass to it. *) 490 | 491 | Ltac insterKeep H := idtac. 492 | 493 | Section t6. 494 | Variables A B : Type. 495 | Variable P : A -> B -> Prop. 496 | Variable f : A -> A -> A. 497 | Variable g : B -> B -> B. 498 | 499 | Hypothesis H1 : forall v, exists u, P v u. 500 | Hypothesis H2 : forall v1 u1 v2 u2, 501 | P v1 u1 502 | -> P v2 u2 503 | -> P (f v1 v2) (g u1 u2). 504 | 505 | Theorem t6 : forall v1 v2, exists u1, exists u2, P (f v1 v2) (g u1 u2). 506 | Proof. 507 | Admitted. 508 | End t6. 509 | 510 | (* Here's an example where something bad happens. *) 511 | 512 | Section t7. 513 | Variables A B : Type. 514 | Variable Q : A -> Prop. 515 | Variable P : A -> B -> Prop. 516 | Variable f : A -> A -> A. 517 | Variable g : B -> B -> B. 518 | 519 | Hypothesis H1 : forall v, Q v -> exists u, P v u. 520 | Hypothesis H2 : forall v1 u1 v2 u2, 521 | P v1 u1 522 | -> P v2 u2 523 | -> P (f v1 v2) (g u1 u2). 524 | 525 | Theorem t7 : forall v1 v2, Q v1 -> Q v2 -> exists u1, exists u2, P (f v1 v2) (g u1 u2). 526 | Proof. 527 | (*intros; do 2 insterKeep H1; 528 | repeat match goal with 529 | | [ H : ex _ |- _ ] => destruct H 530 | end; eauto. 531 | 532 | (* Oh, two trivial goals remain. *) 533 | Unshelve. 534 | assumption. 535 | assumption.*) 536 | Admitted. 537 | End t7. 538 | 539 | Theorem t8 : exists p : nat * nat, fst p = 3. 540 | Proof. 541 | econstructor. 542 | instantiate (1 := (3, 2)). 543 | equality. 544 | Qed. 545 | 546 | (* A way that plays better with automation: *) 547 | 548 | Theorem t9 : exists p : nat * nat, fst p = 3. 549 | Proof. 550 | econstructor; match goal with 551 | | [ |- fst ?x = 3 ] => unify x (3, 2) 552 | end; equality. 553 | Qed. 554 | -------------------------------------------------------------------------------- /Invariant.v: -------------------------------------------------------------------------------- 1 | Require Import Relations. 2 | 3 | Set Implicit Arguments. 4 | 5 | 6 | Record trsys state := { 7 | Initial : state -> Prop; 8 | Step : state -> state -> Prop 9 | }. 10 | 11 | Definition invariantFor {state} (sys : trsys state) (invariant : state -> Prop) := 12 | forall s, sys.(Initial) s 13 | -> forall s', sys.(Step)^* s s' 14 | -> invariant s'. 15 | 16 | Theorem use_invariant : forall {state} (sys : trsys state) (invariant : state -> Prop) s s', 17 | invariantFor sys invariant 18 | -> sys.(Step)^* s s' 19 | -> sys.(Initial) s 20 | -> invariant s'. 21 | Proof. 22 | firstorder. 23 | Qed. 24 | 25 | Theorem invariant_weaken : forall {state} (sys : trsys state) 26 | (invariant1 invariant2 : state -> Prop), 27 | invariantFor sys invariant1 28 | -> (forall s, invariant1 s -> invariant2 s) 29 | -> invariantFor sys invariant2. 30 | Proof. 31 | unfold invariantFor; intuition eauto. 32 | Qed. 33 | 34 | Theorem invariant_induction : forall {state} (sys : trsys state) 35 | (invariant : state -> Prop), 36 | (forall s, sys.(Initial) s -> invariant s) 37 | -> (forall s, invariant s -> forall s', sys.(Step) s s' -> invariant s') 38 | -> invariantFor sys invariant. 39 | Proof. 40 | unfold invariantFor; intros. 41 | assert (invariant s) by eauto. 42 | clear H1. 43 | induction H2; eauto. 44 | Qed. 45 | 46 | 47 | (** * General parallel composition *) 48 | 49 | Record threaded_state shared private := { 50 | Shared : shared; 51 | Private : private 52 | }. 53 | 54 | Inductive parallel1 shared private1 private2 55 | (init1 : threaded_state shared private1 -> Prop) 56 | (init2 : threaded_state shared private2 -> Prop) 57 | : threaded_state shared (private1 * private2) -> Prop := 58 | | Pinit : forall sh pr1 pr2, 59 | init1 {| Shared := sh; Private := pr1 |} 60 | -> init2 {| Shared := sh; Private := pr2 |} 61 | -> parallel1 init1 init2 {| Shared := sh; Private := (pr1, pr2) |}. 62 | 63 | Inductive parallel2 shared private1 private2 64 | (step1 : threaded_state shared private1 -> threaded_state shared private1 -> Prop) 65 | (step2 : threaded_state shared private2 -> threaded_state shared private2 -> Prop) 66 | : threaded_state shared (private1 * private2) 67 | -> threaded_state shared (private1 * private2) -> Prop := 68 | | Pstep1 : forall sh pr1 pr2 sh' pr1', 69 | step1 {| Shared := sh; Private := pr1 |} {| Shared := sh'; Private := pr1' |} 70 | -> parallel2 step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 71 | {| Shared := sh'; Private := (pr1', pr2) |} 72 | | Pstep2 : forall sh pr1 pr2 sh' pr2', 73 | step2 {| Shared := sh; Private := pr2 |} {| Shared := sh'; Private := pr2' |} 74 | -> parallel2 step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 75 | {| Shared := sh'; Private := (pr1, pr2') |}. 76 | 77 | Definition parallel shared private1 private2 78 | (sys1 : trsys (threaded_state shared private1)) 79 | (sys2 : trsys (threaded_state shared private2)) := {| 80 | Initial := parallel1 sys1.(Initial) sys2.(Initial); 81 | Step := parallel2 sys1.(Step) sys2.(Step) 82 | |}. 83 | 84 | 85 | (** * Switching to multistep versions of systems *) 86 | 87 | Lemma trc_idem : forall A (R : A -> A -> Prop) x1 x2, 88 | R^*^* x1 x2 89 | -> R^* x1 x2. 90 | Proof. 91 | induction 1; eauto using trc_trans. 92 | Qed. 93 | 94 | Theorem invariant_multistepify : forall {state} (sys : trsys state) 95 | (invariant : state -> Prop), 96 | invariantFor sys invariant 97 | -> invariantFor {| Initial := Initial sys; Step := (Step sys)^* |} invariant. 98 | Proof. 99 | unfold invariantFor; simpl; intuition eauto using trc_idem. 100 | Qed. 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | "Formal Reasoning About Programs" code license information 2 | 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | CAUTION: Most of the source files in this distribution are NOT 6 | open-source in the usual sense. See the comment at the beginning of 7 | each source file for its license, which is Creative Commons, oriented 8 | more toward free distribution of books than the usual collaborative 9 | model of open-source software. The author really is trying to keep 10 | you from remixing your own versions of the book. 11 | 12 | However, a few of the library modules used here are sufficiently 13 | useful that they are released separately under a BSD license, included 14 | below. However, the author's advice is: please don't use these 15 | library modules in real projects. They are not designed for any use 16 | beside getting the reader up and running quickly in reading the book, 17 | sacrificing practicality (and minimal use of axioms) for simplicity. 18 | 19 | The following license applies ONLY to the source files: 20 | Relations.v 21 | Map.v 22 | Var.v 23 | Invariant.v 24 | ModelCheck.v 25 | FrapWithoutSets.v 26 | Sets.v 27 | Frap.v 28 | AbstractInterpret.v 29 | SepCancel.v 30 | 31 | ~~~~~~~~~~~ 32 | BSD LICENSE 33 | ~~~~~~~~~~~ 34 | 35 | Copyright (c) 2016-2020, Adam Chlipala 36 | All rights reserved. 37 | 38 | Redistribution and use in source and binary forms, with or without 39 | modification, are permitted provided that the following conditions are met: 40 | 41 | - Redistributions of source code must retain the above copyright notice, 42 | this list of conditions and the following disclaimer. 43 | - Redistributions in binary form must reproduce the above copyright notice, 44 | this list of conditions and the following disclaimer in the documentation 45 | and/or other materials provided with the distribution. 46 | - The names of contributors may not be used to endorse or promote products 47 | derived from this software without specific prior written permission. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 53 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 | POSSIBILITY OF SUCH DAMAGE. 60 | -------------------------------------------------------------------------------- /LambdaCalculusAndTypeSoundness_template.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * Chapter 11: Lambda Calculus and Simple Type Soundness 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *) 5 | 6 | Require Import Frap. 7 | 8 | (* The last few chapters have focused on small programming languages that are 9 | * representative of the essence of the imperative languages. We now turn to 10 | * lambda-calculus, the usual representative of functional languages. *) 11 | 12 | Module Ulc. 13 | Inductive exp : Set := 14 | | Var (x : var) 15 | | Abs (x : var) (body : exp) 16 | | App (e1 e2 : exp). 17 | 18 | Fixpoint subst (rep : exp) (x : var) (e : exp) : exp := 19 | match e with 20 | | Var y => if y ==v x then rep else Var y 21 | | Abs y e1 => Abs y (if y ==v x then e1 else subst rep x e1) 22 | | App e1 e2 => App (subst rep x e1) (subst rep x e2) 23 | end. 24 | 25 | 26 | (** * Big-step semantics *) 27 | 28 | Inductive eval : exp -> exp -> Prop := 29 | | BigAbs : forall x e, 30 | eval (Abs x e) (Abs x e) 31 | | BigApp : forall e1 x e1' e2 v2 v, 32 | eval e1 (Abs x e1') 33 | -> eval e2 v2 34 | -> eval (subst v2 x e1') v 35 | -> eval (App e1 e2) v. 36 | 37 | Inductive value : exp -> Prop := 38 | | Value : forall x e, value (Abs x e). 39 | 40 | Local Hint Constructors eval value : core. 41 | 42 | Theorem value_eval : forall v, 43 | value v 44 | -> eval v v. 45 | Proof. 46 | invert 1; eauto. 47 | Qed. 48 | 49 | Local Hint Resolve value_eval : core. 50 | 51 | Theorem eval_value : forall e v, 52 | eval e v 53 | -> value v. 54 | Proof. 55 | induct 1; eauto. 56 | Qed. 57 | 58 | Local Hint Resolve eval_value : core. 59 | 60 | (* Some notations, to let us write more normal-looking lambda terms *) 61 | Coercion Var : var >-> exp. 62 | Notation "\ x , e" := (Abs x e) (at level 50). 63 | Infix "@" := App (at level 49, left associativity). 64 | 65 | (* Believe it or not, this is a Turing-complete language! Here's an example 66 | * nonterminating program. *) 67 | Example omega := (\"x", "x" @ "x") @ (\"x", "x" @ "x"). 68 | 69 | 70 | (** * Church Numerals, everyone's favorite example of lambda terms in 71 | * action *) 72 | 73 | (* Here are two curious definitions. *) 74 | Definition zero := \"f", \"x", "x". 75 | Definition plus1 := \"n", \"f", \"x", "f" @ ("n" @ "f" @ "x"). 76 | 77 | (* We can build up any natural number [n] as [plus1^n @ zero]. Let's prove 78 | * that, in fact, these definitions constitute a workable embedding of the 79 | * natural numbers in lambda-calculus. *) 80 | 81 | (* A term [plus^n @ zero] evaluates to something very close to what this 82 | * function returns. *) 83 | Fixpoint canonical' (n : nat) : exp := 84 | match n with 85 | | O => "x" 86 | | S n' => "f" @ ((\"f", \"x", canonical' n') @ "f" @ "x") 87 | end. 88 | 89 | (* This missing piece is this wrapper. *) 90 | Definition canonical n := \"f", \"x", canonical' n. 91 | 92 | (* Let's formalize our definition of what it means to represent a number. *) 93 | Definition represents (e : exp) (n : nat) := 94 | eval e (canonical n). 95 | 96 | (* Zero passes the test. *) 97 | Theorem zero_ok : represents zero 0. 98 | Proof. 99 | unfold zero, represents, canonical. 100 | simplify. 101 | econstructor. 102 | Qed. 103 | 104 | (* So does our successor operation. *) 105 | Theorem plus1_ok : forall e n, represents e n 106 | -> represents (plus1 @ e) (S n). 107 | Proof. 108 | unfold plus1, represents, canonical; simplify. 109 | econstructor. 110 | econstructor. 111 | eassumption. 112 | simplify. 113 | econstructor. 114 | Qed. 115 | 116 | (* What's basically going on here? The representation of number [n] is [N] 117 | * such that, for any function [f]: 118 | * N(f) = f^n 119 | * That is, we represent a number as its repeated-composition operator. 120 | * So, given a number, we can use it to repeat any operation. In particular, 121 | * to implement addition, we can just repeat [plus1]! *) 122 | Definition add := \"n", \"m", "n" @ plus1 @ "m". 123 | 124 | (* Our addition works properly on this test case. *) 125 | Example add_1_2 : exists v, 126 | eval (add @ (plus1 @ zero) @ (plus1 @ (plus1 @ zero))) v 127 | /\ eval (plus1 @ (plus1 @ (plus1 @ zero))) v. 128 | Proof. 129 | eexists; propositional. 130 | repeat (econstructor; simplify). 131 | repeat econstructor. 132 | Qed. 133 | 134 | (* By the way: since [canonical'] doesn't mention variable "m", substituting 135 | * for "m" has no effect. This fact will come in handy shortly. *) 136 | Lemma subst_m_canonical' : forall m n, 137 | subst m "m" (canonical' n) = canonical' n. 138 | Proof. 139 | induct n; simplify; equality. 140 | Qed. 141 | 142 | (* This inductive proof is the workhorse for the next result, so let's skip 143 | * ahead there. *) 144 | Lemma add_ok' : forall m n, 145 | eval 146 | (subst (\ "f", (\ "x", canonical' m)) "x" 147 | (subst (\ "n", (\ "f", (\ "x", "f" @ (("n" @ "f") @ "x")))) "f" 148 | (canonical' n))) (canonical (n + m)). 149 | Proof. 150 | induct n; simplify. 151 | 152 | econstructor. 153 | 154 | econstructor. 155 | econstructor. 156 | econstructor. 157 | econstructor. 158 | econstructor. 159 | econstructor. 160 | simplify. 161 | econstructor. 162 | econstructor. 163 | simplify. 164 | eassumption. 165 | 166 | simplify. 167 | econstructor. 168 | Qed. 169 | 170 | (* [add] properly encodes the usual addition. *) 171 | Theorem add_ok : forall n ne m me, 172 | represents ne n 173 | -> represents me m 174 | -> represents (add @ ne @ me) (n + m). 175 | Proof. 176 | unfold represents; simplify. 177 | 178 | econstructor. 179 | econstructor. 180 | econstructor. 181 | eassumption. 182 | simplify. 183 | econstructor. 184 | eassumption. 185 | simplify. 186 | econstructor. 187 | econstructor. 188 | econstructor. 189 | econstructor. 190 | simplify. 191 | econstructor. 192 | econstructor. 193 | rewrite subst_m_canonical'. 194 | apply add_ok'. 195 | Qed. 196 | 197 | (* Let's repeat the same exercise for multiplication. *) 198 | 199 | Definition mult := \"n", \"m", "n" @ (add @ "m") @ zero. 200 | 201 | Example mult_1_2 : exists v, 202 | eval (mult @ (plus1 @ zero) @ (plus1 @ (plus1 @ zero))) v 203 | /\ eval (plus1 @ (plus1 @ zero)) v. 204 | Proof. 205 | eexists; propositional. 206 | repeat (econstructor; simplify). 207 | repeat econstructor. 208 | Qed. 209 | 210 | Lemma mult_ok' : forall m n, 211 | eval 212 | (subst (\ "f", (\ "x", "x")) "x" 213 | (subst 214 | (\ "m", 215 | ((\ "f", (\ "x", canonical' m)) @ 216 | (\ "n", (\ "f", (\ "x", "f" @ (("n" @ "f") @ "x"))))) @ "m") 217 | "f" (canonical' n))) (canonical (n * m)). 218 | Proof. 219 | induct n; simplify. 220 | 221 | econstructor. 222 | 223 | econstructor. 224 | econstructor. 225 | econstructor. 226 | econstructor. 227 | econstructor. 228 | econstructor. 229 | simplify. 230 | econstructor. 231 | econstructor. 232 | simplify. 233 | eassumption. 234 | 235 | simplify. 236 | econstructor. 237 | econstructor. 238 | econstructor. 239 | econstructor. 240 | simplify. 241 | econstructor. 242 | econstructor. 243 | rewrite subst_m_canonical'. 244 | apply add_ok'. (* Note the recursive appeal to correctness of [add]. *) 245 | Qed. 246 | 247 | Theorem mult_ok : forall n ne m me, 248 | represents ne n 249 | -> represents me m 250 | -> represents (mult @ ne @ me) (n * m). 251 | Proof. 252 | unfold represents; simplify. 253 | 254 | econstructor. 255 | econstructor. 256 | econstructor. 257 | eassumption. 258 | simplify. 259 | econstructor. 260 | eassumption. 261 | simplify. 262 | econstructor. 263 | econstructor. 264 | econstructor. 265 | econstructor. 266 | econstructor. 267 | econstructor. 268 | simplify. 269 | econstructor. 270 | simplify. 271 | econstructor. 272 | econstructor. 273 | simplify. 274 | rewrite subst_m_canonical'. 275 | apply mult_ok'. 276 | Qed. 277 | 278 | 279 | (** * Small-step semantics *) 280 | 281 | Inductive step : exp -> exp -> Prop := 282 | | Beta : forall x e v, 283 | value v 284 | -> step (App (Abs x e) v) (subst v x e) 285 | 286 | (* However, we also need bureaucractic rules for pushing evaluation inside 287 | * applications. *) 288 | | App1 : forall e1 e1' e2, 289 | step e1 e1' 290 | -> step (App e1 e2) (App e1' e2) 291 | | App2 : forall v e2 e2', 292 | value v 293 | -> step e2 e2' 294 | -> step (App v e2) (App v e2'). 295 | 296 | Local Hint Constructors step : core. 297 | 298 | (* Here we now go through a proof of equivalence between big- and small-step 299 | * semantics, though we won't spend any further commentary on it. *) 300 | 301 | Lemma step_eval' : forall e1 e2, 302 | step e1 e2 303 | -> forall v, eval e2 v 304 | -> eval e1 v. 305 | Proof. 306 | induct 1; simplify; eauto. 307 | 308 | invert H0. 309 | econstructor. 310 | apply IHstep. 311 | eassumption. 312 | eassumption. 313 | assumption. 314 | 315 | invert H1. 316 | econstructor. 317 | eassumption. 318 | apply IHstep. 319 | eassumption. 320 | assumption. 321 | Qed. 322 | 323 | Local Hint Resolve step_eval' : core. 324 | 325 | Theorem step_eval : forall e v, 326 | step^* e v 327 | -> value v 328 | -> eval e v. 329 | Proof. 330 | induct 1; eauto. 331 | Qed. 332 | 333 | Local Hint Resolve eval_value : core. 334 | 335 | Theorem step_app1 : forall e1 e1' e2, 336 | step^* e1 e1' 337 | -> step^* (App e1 e2) (App e1' e2). 338 | Proof. 339 | induct 1; eauto. 340 | Qed. 341 | 342 | Theorem step_app2 : forall e2 e2' v, 343 | value v 344 | -> step^* e2 e2' 345 | -> step^* (App v e2) (App v e2'). 346 | Proof. 347 | induct 2; eauto. 348 | Qed. 349 | 350 | Theorem eval_step : forall e v, 351 | eval e v 352 | -> step^* e v. 353 | Proof. 354 | induct 1; eauto. 355 | 356 | eapply trc_trans. 357 | apply step_app1. 358 | eassumption. 359 | eapply trc_trans. 360 | eapply step_app2. 361 | constructor. 362 | eassumption. 363 | econstructor. 364 | constructor. 365 | eauto. 366 | assumption. 367 | Qed. 368 | End Ulc. 369 | 370 | 371 | Module Stlc. 372 | Inductive exp : Set := 373 | | Var (x : var) 374 | | Const (n : nat) 375 | | Plus (e1 e2 : exp) 376 | | Abs (x : var) (e1 : exp) 377 | | App (e1 e2 : exp). 378 | 379 | Inductive value : exp -> Prop := 380 | | VConst : forall n, value (Const n) 381 | | VAbs : forall x e1, value (Abs x e1). 382 | 383 | Fixpoint subst (e1 : exp) (x : string) (e2 : exp) : exp := 384 | match e2 with 385 | | Var y => if y ==v x then e1 else Var y 386 | | Const n => Const n 387 | | Plus e2' e2'' => Plus (subst e1 x e2') (subst e1 x e2'') 388 | | Abs y e2' => Abs y (if y ==v x then e2' else subst e1 x e2') 389 | | App e2' e2'' => App (subst e1 x e2') (subst e1 x e2'') 390 | end. 391 | 392 | Inductive step : exp -> exp -> Prop := 393 | | Beta : forall x e v, 394 | value v 395 | -> step (App (Abs x e) v) (subst v x e) 396 | | Add : forall n1 n2, 397 | step (Plus (Const n1) (Const n2)) (Const (n1 + n2)) 398 | | App1 : forall e1 e1' e2, 399 | step e1 e1' 400 | -> step (App e1 e2) (App e1' e2) 401 | | App2 : forall v e2 e2', 402 | value v 403 | -> step e2 e2' 404 | -> step (App v e2) (App v e2') 405 | | Plus1 : forall e1 e1' e2, 406 | step e1 e1' 407 | -> step (Plus e1 e2) (Plus e1' e2) 408 | | Plus2 : forall v e2 e2', 409 | value v 410 | -> step e2 e2' 411 | -> step (Plus v e2) (Plus v e2'). 412 | 413 | Definition trsys_of (e : exp) := {| 414 | Initial := {e}; 415 | Step := step 416 | |}. 417 | 418 | Inductive type := 419 | | Nat (* Numbers *) 420 | | Fun (dom ran : type) (* Functions *). 421 | 422 | Inductive has_ty : fmap var type -> exp -> type -> Prop := 423 | | HtVar : forall G x t, 424 | G $? x = Some t 425 | -> has_ty G (Var x) t 426 | | HtConst : forall G n, 427 | has_ty G (Const n) Nat 428 | | HtPlus : forall G e1 e2, 429 | has_ty G e1 Nat 430 | -> has_ty G e2 Nat 431 | -> has_ty G (Plus e1 e2) Nat 432 | | HtAbs : forall G x e1 t1 t2, 433 | has_ty (G $+ (x, t1)) e1 t2 434 | -> has_ty G (Abs x e1) (Fun t1 t2) 435 | | HtApp : forall G e1 e2 t1 t2, 436 | has_ty G e1 (Fun t1 t2) 437 | -> has_ty G e2 t1 438 | -> has_ty G (App e1 e2) t2. 439 | 440 | Local Hint Constructors value step has_ty : core. 441 | 442 | (* Some notation to make it more pleasant to write programs *) 443 | Infix "-->" := Fun (at level 60, right associativity). 444 | Coercion Const : nat >-> exp. 445 | Infix "^+^" := Plus (at level 50). 446 | Coercion Var : var >-> exp. 447 | Notation "\ x , e" := (Abs x e) (at level 51). 448 | Infix "@" := App (at level 49, left associativity). 449 | 450 | (* Some examples of typed programs *) 451 | 452 | Example one_plus_one : has_ty $0 (1 ^+^ 1) Nat. 453 | Proof. 454 | repeat (econstructor; simplify). 455 | Qed. 456 | 457 | Example add : has_ty $0 (\"n", \"m", "n" ^+^ "m") (Nat --> Nat --> Nat). 458 | Proof. 459 | repeat (econstructor; simplify). 460 | Qed. 461 | 462 | Example eleven : has_ty $0 ((\"n", \"m", "n" ^+^ "m") @ 7 @ 4) Nat. 463 | Proof. 464 | repeat (econstructor; simplify). 465 | Qed. 466 | 467 | Example seven_the_long_way : has_ty $0 ((\"x", "x") @ (\"x", "x") @ 7) Nat. 468 | Proof. 469 | repeat (econstructor; simplify). 470 | Qed. 471 | 472 | 473 | (** * Let's prove type soundness. *) 474 | 475 | Definition unstuck e := value e 476 | \/ (exists e' : exp, step e e'). 477 | 478 | Lemma progress : forall e t, 479 | has_ty $0 e t 480 | -> value e 481 | \/ (exists e' : exp, step e e'). 482 | Proof. 483 | Admitted. 484 | 485 | (* Replacing a typing context with an equal one has no effect (useful to guide 486 | * proof search as a hint). *) 487 | Lemma has_ty_change : forall G e t, 488 | has_ty G e t 489 | -> forall G', G' = G 490 | -> has_ty G' e t. 491 | Proof. 492 | Admitted. 493 | 494 | Local Hint Resolve has_ty_change : core. 495 | 496 | Lemma preservation : forall e1 e2, 497 | step e1 e2 498 | -> forall t, has_ty $0 e1 t 499 | -> has_ty $0 e2 t. 500 | Proof. 501 | Admitted. 502 | 503 | Theorem safety : forall e t, has_ty $0 e t 504 | -> invariantFor (trsys_of e) unstuck. 505 | Proof. 506 | simplify. 507 | 508 | (* Step 1: strengthen the invariant. In particular, the typing relation is 509 | * exactly the right stronger invariant! Our progress theorem proves the 510 | * required invariant inclusion. *) 511 | apply invariant_weaken with (invariant1 := fun e' => has_ty $0 e' t). 512 | 513 | (* Step 2: apply invariant induction, whose induction step turns out to match 514 | * our preservation theorem exactly! *) 515 | apply invariant_induction; simplify. 516 | equality. 517 | 518 | eapply preservation. 519 | eassumption. 520 | assumption. 521 | 522 | simplify. 523 | eapply progress. 524 | eassumption. 525 | Qed. 526 | End Stlc. 527 | -------------------------------------------------------------------------------- /LogicProgramming_template.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * Supplementary Coq material: unification and logic programming 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ 5 | * Much of the material comes from CPDT by the same author. *) 6 | 7 | Require Import Frap. 8 | 9 | Set Implicit Arguments. 10 | 11 | 12 | (** * Introducing Logic Programming *) 13 | 14 | (* Recall the definition of addition from the standard library. *) 15 | 16 | Definition real_plus := Eval compute in plus. 17 | Print real_plus. 18 | 19 | (* Alternatively, we can define it as a relation. *) 20 | 21 | Inductive plusR : nat -> nat -> nat -> Prop := 22 | | PlusO : forall m, plusR O m m 23 | | PlusS : forall n m r, plusR n m r 24 | -> plusR (S n) m (S r). 25 | 26 | (* Let's prove the correspondence. *) 27 | 28 | Theorem plusR_plus : forall n m r, 29 | plusR n m r 30 | -> r = n + m. 31 | Proof. 32 | Admitted. 33 | 34 | Theorem plus_plusR : forall n m, 35 | plusR n m (n + m). 36 | Proof. 37 | Admitted. 38 | 39 | Example four_plus_three : 4 + 3 = 7. 40 | Proof. 41 | reflexivity. 42 | Qed. 43 | 44 | Print four_plus_three. 45 | 46 | Example four_plus_three' : plusR 4 3 7. 47 | Proof. 48 | Admitted. 49 | 50 | Print four_plus_three'. 51 | 52 | Example five_plus_three : plusR 5 3 8. 53 | Proof. 54 | Admitted. 55 | 56 | (* Demonstrating _backtracking_ *) 57 | Example seven_minus_three : exists x, x + 3 = 7. 58 | Proof. 59 | apply ex_intro with 0. 60 | Abort. 61 | 62 | Example seven_minus_three' : exists x, plusR x 3 7. 63 | Proof. 64 | Admitted. 65 | 66 | (* Backwards! *) 67 | Example seven_minus_four' : exists x, plusR 4 x 7. 68 | Proof. 69 | Admitted. 70 | 71 | Example seven_minus_three'' : exists x, x + 3 = 7. 72 | Proof. 73 | Admitted. 74 | 75 | Example seven_minus_four : exists x, 4 + x = 7. 76 | Proof. 77 | Admitted. 78 | 79 | Example seven_minus_four_zero : exists x, 4 + x + 0 = 7. 80 | Proof. 81 | Admitted. 82 | 83 | Check eq_trans. 84 | 85 | Section slow. 86 | Hint Resolve eq_trans : core. 87 | 88 | Example zero_minus_one : exists x, 1 + x = 0. 89 | Time eauto 1. 90 | Time eauto 2. 91 | Time eauto 3. 92 | Time eauto 4. 93 | Time eauto 5. 94 | 95 | debug eauto 3. 96 | Abort. 97 | End slow. 98 | 99 | Example from_one_to_zero : exists x, 1 + x = 0. 100 | Proof. 101 | Admitted. 102 | 103 | Example seven_minus_three_again : exists x, x + 3 = 7. 104 | Proof. 105 | Admitted. 106 | 107 | Example needs_trans : forall x y, 1 + x = y 108 | -> y = 2 109 | -> exists z, z + x = 3. 110 | Proof. 111 | Admitted. 112 | 113 | 114 | (** * Searching for Underconstrained Values *) 115 | 116 | Print Datatypes.length. 117 | 118 | Example length_1_2 : length (1 :: 2 :: nil) = 2. 119 | Proof. 120 | Admitted. 121 | 122 | Print length_1_2. 123 | 124 | Example length_is_2 : exists ls : list nat, length ls = 2. 125 | Proof. 126 | Abort. 127 | 128 | Print Forall. 129 | 130 | Example length_is_2 : exists ls : list nat, length ls = 2 131 | /\ Forall (fun n => n >= 1) ls. 132 | Proof. 133 | Admitted. 134 | 135 | Print length_is_2. 136 | 137 | Definition sum := fold_right plus O. 138 | 139 | Example length_and_sum : exists ls : list nat, length ls = 2 140 | /\ sum ls = O. 141 | Proof. 142 | Admitted. 143 | 144 | Print length_and_sum. 145 | 146 | Example length_and_sum' : exists ls : list nat, length ls = 5 147 | /\ sum ls = 42. 148 | Proof. 149 | Admitted. 150 | 151 | Print length_and_sum'. 152 | 153 | Example length_and_sum'' : exists ls : list nat, length ls = 2 154 | /\ sum ls = 3 155 | /\ Forall (fun n => n <> 0) ls. 156 | Proof. 157 | Admitted. 158 | 159 | Print length_and_sum''. 160 | 161 | 162 | (** * Synthesizing Programs *) 163 | 164 | Inductive exp : Set := 165 | | Const (n : nat) 166 | | Var 167 | | Plus (e1 e2 : exp). 168 | 169 | Inductive eval (var : nat) : exp -> nat -> Prop := 170 | | EvalConst : forall n, eval var (Const n) n 171 | | EvalVar : eval var Var var 172 | | EvalPlus : forall e1 e2 n1 n2, eval var e1 n1 173 | -> eval var e2 n2 174 | -> eval var (Plus e1 e2) (n1 + n2). 175 | 176 | Local Hint Constructors eval : core. 177 | 178 | Example eval1 : forall var, eval var (Plus Var (Plus (Const 8) Var)) (var + (8 + var)). 179 | Proof. 180 | auto. 181 | Qed. 182 | 183 | Example eval1' : forall var, eval var (Plus Var (Plus (Const 8) Var)) (2 * var + 8). 184 | Proof. 185 | eauto. 186 | Abort. 187 | 188 | Example eval1' : forall var, eval var (Plus Var (Plus (Const 8) Var)) (2 * var + 8). 189 | Proof. 190 | Admitted. 191 | 192 | Example synthesize1 : exists e, forall var, eval var e (var + 7). 193 | Proof. 194 | Admitted. 195 | 196 | Print synthesize1. 197 | 198 | (* Here are two more examples showing off our program-synthesis abilities. *) 199 | 200 | Example synthesize2 : exists e, forall var, eval var e (2 * var + 8). 201 | Proof. 202 | Admitted. 203 | 204 | Print synthesize2. 205 | 206 | Example synthesize3 : exists e, forall var, eval var e (3 * var + 42). 207 | Proof. 208 | Admitted. 209 | 210 | Print synthesize3. 211 | 212 | Theorem linear : forall e, exists k n, 213 | forall var, eval var e (k * var + n). 214 | Proof. 215 | Admitted. 216 | 217 | Section side_effect_sideshow. 218 | Variable A : Set. 219 | Variables P Q : A -> Prop. 220 | Variable x : A. 221 | 222 | Hypothesis Px : P x. 223 | Hypothesis Qx : Q x. 224 | 225 | Theorem double_threat : exists y, P y /\ Q y. 226 | Proof. 227 | eexists; propositional. 228 | eauto. 229 | eauto. 230 | Qed. 231 | End side_effect_sideshow. 232 | 233 | 234 | (** * More on [auto] Hints *) 235 | 236 | Theorem bool_neq : true <> false. 237 | Proof. 238 | Admitted. 239 | 240 | Section forall_and. 241 | Variable A : Set. 242 | Variables P Q : A -> Prop. 243 | 244 | Hypothesis both : forall x, P x /\ Q x. 245 | 246 | Theorem forall_and : forall z, P z. 247 | Proof. 248 | Admitted. 249 | End forall_and. 250 | 251 | 252 | (** * Rewrite Hints *) 253 | 254 | Section autorewrite. 255 | Variable A : Set. 256 | Variable f : A -> A. 257 | 258 | Hypothesis f_f : forall x, f (f x) = f x. 259 | 260 | Hint Rewrite f_f. 261 | 262 | Lemma f_f_f : forall x, f (f (f x)) = f x. 263 | Proof. 264 | intros; autorewrite with core; reflexivity. 265 | Qed. 266 | 267 | Section garden_path. 268 | Variable g : A -> A. 269 | Hypothesis f_g : forall x, f x = g x. 270 | Hint Rewrite f_g. 271 | 272 | Lemma f_f_f' : forall x, f (f (f x)) = f x. 273 | Proof. 274 | Admitted. 275 | End garden_path. 276 | 277 | Lemma in_star : forall x y, f (f (f (f x))) = f (f y) 278 | -> f x = f (f (f y)). 279 | Proof. 280 | Admitted. 281 | 282 | End autorewrite. 283 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all lib coq install 2 | 3 | all: frap_book.pdf coq 4 | 5 | frap_book.pdf: frap_book.tex Makefile 6 | pdflatex frap_book 7 | pdflatex frap_book 8 | makeindex frap_book 9 | pdflatex frap_book 10 | pdflatex frap_book 11 | 12 | coq: Makefile.coq 13 | $(MAKE) -f Makefile.coq 14 | 15 | lib: Makefile.coq 16 | $(MAKE) -f Makefile.coq Frap.vo AbstractInterpret.vo SepCancel.vo 17 | 18 | Makefile.coq: Makefile _CoqProject *.v 19 | coq_makefile -f _CoqProject -o Makefile.coq 20 | 21 | clean:: Makefile.coq 22 | $(MAKE) -f Makefile.coq clean 23 | rm -f Makefile.coq 24 | 25 | frap.tgz: Makefile _CoqProject *.v *.tex *.html 26 | git archive --format=tar.gz HEAD >frap.tgz 27 | 28 | fraplib.tgz: Makefile 29 | rm -rf fraplib 30 | mkdir fraplib 31 | cp LICENSE fraplib/ 32 | cp Makefile.fraplib fraplib/Makefile 33 | cp _CoqProject.fraplib fraplib/_CoqProject 34 | cp Relations.v fraplib/ 35 | cp Map.v fraplib/ 36 | cp Var.v fraplib/ 37 | cp Invariant.v fraplib/ 38 | cp ModelCheck.v fraplib/ 39 | cp FrapWithoutSets.v fraplib/ 40 | cp Sets.v fraplib/ 41 | cp Frap.v fraplib/ 42 | cp Imp.v fraplib/ 43 | cp AbstractInterpret.v fraplib/ 44 | cp SepCancel.v fraplib/ 45 | tar cf fraplib.tgz fraplib/* 46 | 47 | WHERE=chlipala.net:sites/chlipala/adam/frap/ 48 | 49 | install: index.html frap_book.pdf frap.tgz fraplib.tgz 50 | rsync frap_book.pdf $(WHERE) 51 | rsync frap.tgz $(WHERE) 52 | rsync fraplib.tgz $(WHERE) 53 | rsync index.html $(WHERE) 54 | -------------------------------------------------------------------------------- /Makefile.fraplib: -------------------------------------------------------------------------------- 1 | .PHONY: coq 2 | 3 | coq: Makefile.coq 4 | $(MAKE) -f Makefile.coq 5 | 6 | Makefile.coq: Makefile _CoqProject *.v 7 | coq_makefile -f _CoqProject -o Makefile.coq 8 | 9 | clean:: Makefile.coq 10 | $(MAKE) -f Makefile.coq clean 11 | rm -f Makefile.coq 12 | -------------------------------------------------------------------------------- /ModelCheck.v: -------------------------------------------------------------------------------- 1 | Require Import Invariant Relations Sets Classical. 2 | 3 | Set Implicit Arguments. 4 | 5 | 6 | Definition oneStepClosure_current {state} (sys : trsys state) 7 | (invariant1 invariant2 : state -> Prop) := 8 | forall st, invariant1 st 9 | -> invariant2 st. 10 | 11 | Definition oneStepClosure_new {state} (sys : trsys state) 12 | (invariant1 invariant2 : state -> Prop) := 13 | forall st st', invariant1 st 14 | -> sys.(Step) st st' 15 | -> invariant2 st'. 16 | 17 | Definition oneStepClosure {state} (sys : trsys state) 18 | (invariant1 invariant2 : state -> Prop) := 19 | oneStepClosure_current sys invariant1 invariant2 20 | /\ oneStepClosure_new sys invariant1 invariant2. 21 | 22 | Theorem prove_oneStepClosure : forall state (sys : trsys state) (inv1 inv2 : state -> Prop), 23 | (forall st, inv1 st -> inv2 st) 24 | -> (forall st st', inv1 st -> sys.(Step) st st' -> inv2 st') 25 | -> oneStepClosure sys inv1 inv2. 26 | Proof. 27 | unfold oneStepClosure; tauto. 28 | Qed. 29 | 30 | Inductive multiStepClosure {state} (sys : trsys state) 31 | : (state -> Prop) -> (state -> Prop) -> (state -> Prop) -> Prop := 32 | | MscDone : forall inv, 33 | multiStepClosure sys inv (constant nil) inv 34 | | MscStep : forall inv worklist inv' inv'', 35 | oneStepClosure sys worklist inv' 36 | -> multiStepClosure sys (inv \cup inv') (inv' \setminus inv) inv'' 37 | -> multiStepClosure sys inv worklist inv''. 38 | 39 | Lemma adding_irrelevant : forall A (s : A) inv inv', 40 | s \in (inv \cup inv') \setminus (inv' \setminus inv) 41 | -> s \in inv. 42 | Proof. 43 | sets idtac. 44 | destruct (classic (inv s)); tauto. 45 | Qed. 46 | 47 | Lemma multiStepClosure_ok' : forall state (sys : trsys state) (inv worklist inv' : state -> Prop), 48 | multiStepClosure sys inv worklist inv' 49 | -> (forall st, sys.(Initial) st -> inv st) 50 | -> worklist \subseteq inv 51 | -> (forall s, s \in inv \setminus worklist 52 | -> forall s', sys.(Step) s s' 53 | -> s' \in inv) 54 | -> invariantFor sys inv'. 55 | Proof. 56 | induction 1; simpl; intuition. 57 | 58 | apply invariant_induction; simpl; intuition. 59 | eapply H1. 60 | red. 61 | unfold minus. 62 | split; eauto. 63 | assumption. 64 | 65 | apply IHmultiStepClosure; clear IHmultiStepClosure. 66 | intuition. 67 | apply H1 in H4. 68 | sets idtac. 69 | sets idtac. 70 | intuition. 71 | apply adding_irrelevant in H4. 72 | destruct (classic (s \in worklist)). 73 | destruct H. 74 | red in H7. 75 | eapply H7 in H6. 76 | right; eassumption. 77 | assumption. 78 | left. 79 | eapply H3. 80 | 2: eassumption. 81 | sets idtac. 82 | Qed. 83 | 84 | Theorem multiStepClosure_ok : forall state (sys : trsys state) (inv : state -> Prop), 85 | multiStepClosure sys sys.(Initial) sys.(Initial) inv 86 | -> invariantFor sys inv. 87 | Proof. 88 | intros; eapply multiStepClosure_ok'; eauto; sets idtac. 89 | Qed. 90 | 91 | Theorem oneStepClosure_empty : forall state (sys : trsys state), 92 | oneStepClosure sys (constant nil) (constant nil). 93 | Proof. 94 | unfold oneStepClosure, oneStepClosure_current, oneStepClosure_new; intuition. 95 | Qed. 96 | 97 | Theorem oneStepClosure_split : forall state (sys : trsys state) st sts (inv1 inv2 : state -> Prop), 98 | (forall st', sys.(Step) st st' -> inv1 st') 99 | -> oneStepClosure sys (constant sts) inv2 100 | -> oneStepClosure sys (constant (st :: sts)) (constant (st :: nil) \cup inv1 \cup inv2). 101 | Proof. 102 | unfold oneStepClosure, oneStepClosure_current, oneStepClosure_new; intuition. 103 | 104 | inversion H0; subst. 105 | unfold union; simpl; tauto. 106 | 107 | unfold union; simpl; eauto. 108 | 109 | unfold union in *; simpl in *. 110 | intuition (subst; eauto). 111 | Qed. 112 | 113 | Theorem singleton_in : forall {A} (x : A) rest, 114 | (constant (x :: nil) \cup rest) x. 115 | Proof. 116 | unfold union; simpl; auto. 117 | Qed. 118 | 119 | Theorem singleton_in_other : forall {A} (x : A) (s1 s2 : set A), 120 | s2 x 121 | -> (s1 \cup s2) x. 122 | Proof. 123 | unfold union; simpl; auto. 124 | Qed. 125 | 126 | 127 | (** * Abstraction *) 128 | 129 | Inductive simulates state1 state2 (R : state1 -> state2 -> Prop) 130 | (sys1 : trsys state1) (sys2 : trsys state2) : Prop := 131 | | Simulates : 132 | (forall st1, sys1.(Initial) st1 133 | -> exists st2, R st1 st2 134 | /\ sys2.(Initial) st2) 135 | -> (forall st1 st2, R st1 st2 136 | -> forall st1', sys1.(Step) st1 st1' 137 | -> exists st2', R st1' st2' 138 | /\ sys2.(Step) st2 st2') 139 | -> simulates R sys1 sys2. 140 | 141 | Inductive invariantViaSimulation state1 state2 (R : state1 -> state2 -> Prop) 142 | (inv2 : state2 -> Prop) 143 | : state1 -> Prop := 144 | | InvariantViaSimulation : forall st1 st2, R st1 st2 145 | -> inv2 st2 146 | -> invariantViaSimulation R inv2 st1. 147 | 148 | Lemma invariant_simulates' : forall state1 state2 (R : state1 -> state2 -> Prop) 149 | (sys1 : trsys state1) (sys2 : trsys state2), 150 | (forall st1 st2, R st1 st2 151 | -> forall st1', sys1.(Step) st1 st1' 152 | -> exists st2', R st1' st2' 153 | /\ sys2.(Step) st2 st2') 154 | -> forall st1 st1', sys1.(Step)^* st1 st1' 155 | -> forall st2, R st1 st2 156 | -> exists st2', R st1' st2' 157 | /\ sys2.(Step)^* st2 st2'. 158 | Proof. 159 | induction 2; simpl; intuition eauto. 160 | 161 | eapply H in H2. 162 | firstorder. 163 | apply IHtrc in H2. 164 | firstorder; eauto. 165 | eauto. 166 | Qed. 167 | 168 | Local Hint Constructors invariantViaSimulation : core. 169 | 170 | Theorem invariant_simulates : forall state1 state2 (R : state1 -> state2 -> Prop) 171 | (sys1 : trsys state1) (sys2 : trsys state2) (inv2 : state2 -> Prop), 172 | simulates R sys1 sys2 173 | -> invariantFor sys2 inv2 174 | -> invariantFor sys1 (invariantViaSimulation R inv2). 175 | Proof. 176 | inversion_clear 1; intros. 177 | unfold invariantFor; intros. 178 | apply H0 in H2. 179 | firstorder. 180 | apply invariant_simulates' with (sys2 := sys2) (R := R) (st2 := x) in H3; auto. 181 | firstorder; eauto. 182 | Qed. 183 | -------------------------------------------------------------------------------- /ModelChecking_sol.v: -------------------------------------------------------------------------------- 1 | Theorem factorial_ok_2 : 2 | invariantFor (factorial_sys 2) (fact_correct 2). 3 | Proof. 4 | simplify. 5 | eapply invariant_weaken. 6 | (* We begin like in last chapter, by strengthening to an inductive 7 | * invariant. *) 8 | 9 | apply multiStepClosure_ok. 10 | (* The difference is that we will use multi-step closure to find the invariant 11 | * automatically. Note that the invariant appears as an existential variable, 12 | * whose name begins with a question mark. *) 13 | simplify. 14 | rewrite fact_init_is. 15 | (* It's important to phrase the current candidate invariant explicitly as a 16 | * finite set, before continuing. Otherwise, it won't be obvious how to take 17 | * the one-step closure. *) 18 | 19 | (* Compute which states are reachable after one step. *) 20 | eapply MscStep. 21 | apply oneStepClosure_split; simplify. 22 | invert H; simplify. 23 | apply singleton_in. 24 | apply oneStepClosure_empty. 25 | simplify. 26 | 27 | (* Compute which states are reachable after two steps. *) 28 | eapply MscStep. 29 | apply oneStepClosure_split; simplify. 30 | invert H; simplify. 31 | apply singleton_in. 32 | apply oneStepClosure_split; simplify. 33 | invert H; simplify. 34 | apply singleton_in. 35 | apply oneStepClosure_empty. 36 | simplify. 37 | 38 | (* Compute which states are reachable after three steps. *) 39 | eapply MscStep. 40 | apply oneStepClosure_split; simplify. 41 | invert H; simplify. 42 | apply singleton_in. 43 | apply oneStepClosure_split; simplify. 44 | invert H; simplify. 45 | apply singleton_in. 46 | apply oneStepClosure_split; simplify. 47 | invert H; simplify. 48 | apply singleton_in. 49 | apply oneStepClosure_empty. 50 | simplify. 51 | 52 | (* Now the candidate invariatn is closed under single steps. Let's prove 53 | * it. *) 54 | apply MscDone. 55 | apply prove_oneStepClosure; simplify. 56 | propositional. 57 | propositional; invert H0; try equality. 58 | invert H; equality. 59 | invert H1; equality. 60 | 61 | (* Finally, we prove that our new invariant implies the simpler, noninductive 62 | * one that we started with. *) 63 | simplify. 64 | propositional; subst; simplify; propositional. 65 | (* [subst]: remove all hypotheses like [x = e] for variables [x], simply 66 | * replacing all uses of [x] by [e]. *) 67 | Qed. 68 | 69 | Theorem twoadd2_ok : 70 | invariantFor (parallel twoadd_sys twoadd_sys) (twoadd_correct (private := _)). 71 | Proof. 72 | eapply invariant_weaken. 73 | eapply invariant_simulates. 74 | apply withInterference_abstracts. 75 | apply withInterference_parallel. 76 | apply twoadd_ok. 77 | apply twoadd_ok. 78 | 79 | unfold twoadd_correct. 80 | invert 1. 81 | assumption. 82 | Qed. 83 | -------------------------------------------------------------------------------- /Polymorphism_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | Set Implicit Arguments. 4 | (* This command sets up automatic inference of tedious arguments. *) 5 | 6 | 7 | (* Our first example: the [option] type family. While Java and friends force 8 | * all sorts of different types to include the special value [null], in Coq we 9 | * request that option explicitly by wrapping a type in [option]. Specifically, 10 | * any value of type [option A], for some type [A], is either [None] (sort of 11 | * like [null]) or [Some v] for a [v] of type [A]. *) 12 | Inductive option (A : Set) : Set := 13 | | None 14 | | Some (v : A). 15 | 16 | Arguments None {A}. 17 | (* This command asks Coq to *infer* the [A] type for each specific use of 18 | * [None]. *) 19 | 20 | (* Here are a few example terms using [option]. *) 21 | Example no_number : option nat := None. 22 | Example a_number : option nat := Some 42. 23 | Example no_number_squared : option (option nat) := None. 24 | Example no_number_squared_inside : option (option nat) := Some None. 25 | Example a_number_squared : option (option nat) := Some (Some 42). 26 | 27 | (* Pattern matching is the key ingredient for working with inductive definitions 28 | * of all sorts. Here are some examples matching on [option]s. *) 29 | 30 | Definition increment_optional (no : option nat) : option nat := 31 | match no with 32 | | None => None 33 | | Some n => Some (n + 1) 34 | end. 35 | 36 | (* Here we use type [A * B] of *pairs*, inhabited by values [(a, b)], with 37 | * [a : A] and [b : B]. *) 38 | Definition add_optional (po : option (nat * nat)) : option nat := 39 | match po with 40 | | None => None 41 | | Some (n, m) => Some (n + m) 42 | end. 43 | 44 | 45 | (** * Lists *) 46 | 47 | (* For functional programming (as in Coq), the king of all generic data 48 | * structures is the *list*. *) 49 | Inductive list (A : Set) : Set := 50 | | nil 51 | | cons (hd : A) (tl : list A). 52 | 53 | Arguments nil {A}. 54 | 55 | (* [nil] is the empty list, while [cons], standing for "construct," extends a 56 | * list of length [n] into one of length [n+1]. *) 57 | 58 | (* Here are some simple lists. *) 59 | 60 | Example nats0 : list nat := nil. 61 | Example nats1 : list nat := cons 1 nil. 62 | Example nats2 : list nat := cons 1 (cons 2 nil). 63 | 64 | (* Coq features a wonderful notation system, to help us write more concise and 65 | * readable code after introducing new syntactic forms. We will not give a 66 | * systematic presentation of the notation system, but we will show many 67 | * examples, from which it is possible to infer generality by scientific 68 | * induction. And, of course, the interested reader can always check the 69 | * notations chapter of the Coq reference manual. *) 70 | 71 | (* First, our examples can get more readable with an infix operator for [cons]. *) 72 | 73 | Infix "::" := cons. 74 | 75 | Example nats1' : list nat := 1 :: nil. 76 | Example nats2' : list nat := 1 :: 2 :: nil. 77 | 78 | (* Getting even more fancy, we declare a notation for list literals. *) 79 | 80 | Notation "[ ]" := nil. 81 | Notation "[ x1 ; .. ; xN ]" := (cons x1 (.. (cons xN nil) ..)). 82 | 83 | Example nats0'' : list nat := []. 84 | Example nats1'' : list nat := [1]. 85 | Example nats2'' : list nat := [1; 2]. 86 | Example nats3'' : list nat := [1; 2; 3]. 87 | 88 | (* Here are some classic recursive functions that operate over lists. 89 | * First, here is how to compute the length of a list. Recall that we put 90 | * *implicit* function arguments in curly braces, asking Coq to infer them at 91 | * call sites. *) 92 | 93 | Fixpoint length {A} (ls : list A) : nat := 94 | match ls with 95 | | nil => 0 96 | | _ :: ls' => 1 + length ls' 97 | end. 98 | 99 | (* Concatenation: *) 100 | Fixpoint app {A} (ls1 ls2 : list A) : list A := 101 | match ls1 with 102 | | nil => ls2 103 | | x :: ls1' => x :: app ls1' ls2 104 | end. 105 | 106 | Infix "++" := app. 107 | 108 | (* Reversal: *) 109 | Fixpoint rev {A} (ls : list A) : list A := 110 | match ls with 111 | | nil => nil 112 | | x :: ls' => rev ls' ++ [x] 113 | end. 114 | 115 | Theorem length_app : forall A (ls1 ls2 : list A), 116 | length (ls1 ++ ls2) = length ls1 + length ls2. 117 | Proof. 118 | Admitted. 119 | 120 | (* One of the classic gotchas in functional-programming class is how slow this 121 | * naive [rev] is. Each [app] operation requires linear time, so running 122 | * linearly many [app]s brings us to quadratic time for [rev]. Using a helper 123 | * function, we can bring [rev] to its optimal linear time. *) 124 | 125 | Fixpoint rev_append {A} (ls acc : list A) : list A := 126 | match ls with 127 | | nil => acc 128 | | x :: ls' => rev_append ls' (x :: acc) 129 | end. 130 | 131 | (* This function [rev_append] takes an extra *accumulator* argument, in which we 132 | * gradually build up the original input in reversed order. The base case just 133 | * returns the accumulator. Now reversal just needs to do a [rev_append] with 134 | * an empty initial accumulator. *) 135 | 136 | Definition rev' {A} (ls : list A) : list A := 137 | rev_append ls []. 138 | 139 | (* A few test cases can help convince us that this seems to work. *) 140 | 141 | Compute rev [1; 2; 3; 4]. 142 | Compute rev' [1; 2; 3; 4]. 143 | Compute rev ["hi"; "bye"; "sky"]. 144 | Compute rev' ["hi"; "bye"; "sky"]. 145 | 146 | (* OK, great. Now it seems worth investing in a correctness proof. *) 147 | 148 | Theorem rev'_ok : forall A (ls : list A), 149 | rev' ls = rev ls. 150 | Proof. 151 | Admitted. 152 | 153 | (** ** Zipping and unzipping *) 154 | 155 | (* Another classic pair of list operations is zipping and unzipping. 156 | * These functions convert between pairs of lists and lists of pairs. *) 157 | 158 | Fixpoint zip {A1 A2} (ls1 : list A1) (ls2 : list A2) : list (A1 * A2) := 159 | match ls1, ls2 with 160 | | x1 :: ls1', x2 :: ls2' => (x1, x2) :: zip ls1' ls2' 161 | | _, _ => [] 162 | end. 163 | (* Note how, when passed two lengths of different lists, [zip] drops the 164 | * mismatched suffix of the longer list. *) 165 | 166 | (* An explicit [Set] annotation is needed here, for obscure type-inference 167 | * reasons. *) 168 | Fixpoint unzip {A1 A2 : Set} (ls : list (A1 * A2)) : list A1 * list A2 := 169 | match ls with 170 | | [] => ([], []) 171 | | (x1, x2) :: ls' => 172 | let (ls1, ls2) := unzip ls' in 173 | (x1 :: ls1, x2 :: ls2) 174 | end. 175 | 176 | (* A few common-sense properties hold of these definitions. *) 177 | 178 | Theorem length_zip : forall A1 A2 (ls1 : list A1) (ls2 : list A2), 179 | length (zip ls1 ls2) = 7. 180 | Proof. 181 | Admitted. 182 | 183 | (* We write [fst] and [snd] for the first and second projection operators on 184 | * pairs, respectively. *) 185 | 186 | Theorem length_unzip1 : forall (A1 A2 : Set) (ls : list (A1 * A2)), 187 | length (fst (unzip ls)) = length ls. 188 | Proof. 189 | Admitted. 190 | 191 | Theorem length_unzip2 : forall (A1 A2 : Set) (ls : list (A1 * A2)), 192 | length (snd (unzip ls)) = length ls. 193 | Proof. 194 | Admitted. 195 | 196 | Theorem zip_unzip : forall (A1 A2 : Set) (ls : list (A1 * A2)), 197 | (let (ls1, ls2) := unzip ls in zip ls1 ls2) = ls. 198 | Proof. 199 | Admitted. 200 | 201 | (* There are also interesting interactions with [app] and [rev]. *) 202 | 203 | Theorem unzip_app : forall (A1 A2 : Set) (x y : list (A1 * A2)), 204 | unzip (x ++ y) 205 | = (let (x1, x2) := unzip x in 206 | let (y1, y2) := unzip y in 207 | (x1 ++ y1, x2 ++ y2)). 208 | Proof. 209 | Admitted. 210 | 211 | Theorem unzip_rev : forall (A1 A2 : Set) (ls : list (A1 * A2)), 212 | unzip (rev ls) = (let (ls1, ls2) := unzip ls in 213 | (rev ls1, rev ls2)). 214 | Proof. 215 | Admitted. 216 | 217 | 218 | (** * Binary trees *) 219 | 220 | (* Another classic datatype is binary trees, which we can define like so. *) 221 | Inductive tree (A : Set) : Set := 222 | | Leaf 223 | | Node (l : tree A) (d : A) (r : tree A). 224 | 225 | Arguments Leaf {A}. 226 | 227 | Example tr1 : tree nat := Node (Node Leaf 7 Leaf) 8 (Node Leaf 9 (Node Leaf 10 Leaf)). 228 | 229 | (* There is a natural notion of size of a tree. *) 230 | Fixpoint size {A} (t : tree A) : nat := 231 | match t with 232 | | Leaf => 0 233 | | Node l _ r => 1 + size l + size r 234 | end. 235 | 236 | (* There is also a natural sense of reversing a tree, flipping it around its 237 | * vertical axis. *) 238 | Fixpoint reverse {A} (t : tree A) : tree A := 239 | match t with 240 | | Leaf => Leaf 241 | | Node l d r => Node (reverse r) d (reverse l) 242 | end. 243 | 244 | (* There is a natural relationship between the two. *) 245 | Theorem size_reverse : forall A (t : tree A), 246 | size (reverse t) = size t. 247 | Proof. 248 | Admitted. 249 | 250 | (* Another classic tree operation is flattening into lists. *) 251 | Fixpoint flatten {A} (t : tree A) : list A := 252 | match t with 253 | | Leaf => [] 254 | | Node l d r => flatten l ++ d :: flatten r 255 | end. 256 | (* Note here that operators [++] and [::] are right-associative. *) 257 | 258 | Theorem length_flatten : forall A (t : tree A), 259 | length (flatten t) = size t. 260 | Proof. 261 | Admitted. 262 | 263 | Theorem rev_flatten : forall A (t : tree A), 264 | rev (flatten t) = flatten (reverse t). 265 | Proof. 266 | Admitted. 267 | 268 | 269 | (** * Syntax trees *) 270 | 271 | (* Trees are particularly important to us in studying program proof, since it is 272 | * natural to represent programs as *syntax trees*. Here's a quick example, for 273 | * a tiny imperative language. *) 274 | 275 | Inductive expression : Set := 276 | | Const (n : nat) 277 | | Var (x : var) 278 | | Plus (e1 e2 : expression) 279 | | Minus (e1 e2 : expression) 280 | | Times (e1 e2 : expression) 281 | | GreaterThan (e1 e2 : expression) 282 | | Not (e : expression). 283 | 284 | Inductive statement : Set := 285 | | Assign (x : var) (e : expression) 286 | | Sequence (s1 s2 : statement) 287 | | IfThenElse (e : expression) (s1 s2 : statement) 288 | | WhileLoop (e : expression) (s : statement). 289 | 290 | (* First, here's a quick sample of nifty notations to write 291 | * almost-natural-looking embedded programs in Coq. *) 292 | Coercion Const : nat >-> expression. 293 | Coercion Var : string >-> expression. 294 | (*Declare Scope embedded_scope.*) 295 | Infix "+" := Plus : embedded_scope. 296 | Infix "-" := Minus : embedded_scope. 297 | Infix "*" := Times : embedded_scope. 298 | Infix ">" := GreaterThan : embedded_scope. 299 | Infix "<-" := Assign (at level 75) : embedded_scope. 300 | Infix ";" := Sequence (at level 76) : embedded_scope. 301 | Notation "'If' e {{ s1 }} 'else' {{ s2 }}" := (IfThenElse e s1 s2) (at level 75) : embedded_scope. 302 | Notation "'While' e {{ s }}" := (WhileLoop e s) (at level 75) : embedded_scope. 303 | Delimit Scope embedded_scope with embedded. 304 | 305 | Example factorial := 306 | ("answer" <- 1; 307 | While ("input" > 0) {{ 308 | "answer" <- "answer" * "input"; 309 | "input" <- "input" - 1 310 | }})%embedded. 311 | 312 | (* A variety of compiler-style operations can be coded on top of this type. 313 | * Here's one to count total variable occurrences. *) 314 | 315 | Fixpoint varsInExpression (e : expression) : nat := 316 | match e with 317 | | Const _ => 0 318 | | Var _ => 1 319 | | Plus e1 e2 320 | | Minus e1 e2 321 | | Times e1 e2 322 | | GreaterThan e1 e2 => varsInExpression e1 + varsInExpression e2 323 | | Not e1 => varsInExpression e1 324 | end. 325 | 326 | Fixpoint varsInStatement (s : statement) : nat := 327 | match s with 328 | | Assign _ e => 1 + varsInExpression e 329 | | Sequence s1 s2 => varsInStatement s1 + varsInStatement s2 330 | | IfThenElse e s1 s2 => varsInExpression e + varsInStatement s1 + varsInStatement s2 331 | | WhileLoop e s1 => varsInExpression e + varsInStatement s1 332 | end. 333 | 334 | (* We will need to wait for a few more lectures' worth of conceptual progress 335 | * before we can prove that transformations on programs preserve meaning, but we 336 | * do already have enough tools that prove that transformations preserve more 337 | * basic properties, like number of variables. Here's one such transformation, 338 | * which flips "then" and "else" cases while also negating "if" conditions. *) 339 | Fixpoint flipper (s : statement) : statement := 340 | match s with 341 | | Assign _ _ => s 342 | | Sequence s1 s2 => Sequence (flipper s1) (flipper s2) 343 | | IfThenElse e s1 s2 => IfThenElse (Not e) (flipper s2) (flipper s1) 344 | | WhileLoop e s1 => WhileLoop e (flipper s1) 345 | end. 346 | 347 | Theorem varsIn_flipper : forall s, 348 | varsInStatement (flipper s) = varsInStatement s. 349 | Proof. 350 | Admitted. 351 | 352 | (* Just for the sheer madcap fun of it, let's write some translations of 353 | * programs into our lists from before, with variables as data values. *) 354 | 355 | Fixpoint listifyExpression (e : expression) : list var := 356 | match e with 357 | | Const _ => [] 358 | | Var x => [x] 359 | | Plus e1 e2 360 | | Minus e1 e2 361 | | Times e1 e2 362 | | GreaterThan e1 e2 => listifyExpression e1 ++ listifyExpression e2 363 | | Not e1 => listifyExpression e1 364 | end. 365 | 366 | Fixpoint listifyStatement (s : statement) : list var := 367 | match s with 368 | | Assign x e => x :: listifyExpression e 369 | | Sequence s1 s2 => listifyStatement s1 ++ listifyStatement s2 370 | | IfThenElse e s1 s2 => listifyExpression e ++ listifyStatement s1 ++ listifyStatement s2 371 | | WhileLoop e s1 => listifyExpression e ++ listifyStatement s1 372 | end. 373 | 374 | Compute listifyStatement factorial. 375 | 376 | Theorem length_listifyStatement : forall s, 377 | length (listifyStatement s) = varsInStatement s. 378 | Proof. 379 | Admitted. 380 | 381 | (* Other transformations are also possible, like the Swedish-Chef optimization, 382 | * which turns every variable into "bork". It saves many bits when most variable 383 | * names are longer than 4 characters. *) 384 | 385 | Fixpoint swedishExpression (e : expression) : expression := 386 | match e with 387 | | Const _ => e 388 | | Var _ => Var "bork" 389 | | Plus e1 e2 => Plus (swedishExpression e1) (swedishExpression e2) 390 | | Minus e1 e2 => Minus (swedishExpression e1) (swedishExpression e2) 391 | | Times e1 e2 => Times (swedishExpression e1) (swedishExpression e2) 392 | | GreaterThan e1 e2 => GreaterThan (swedishExpression e1) (swedishExpression e2) 393 | | Not e1 => Not (swedishExpression e1) 394 | end. 395 | 396 | Fixpoint swedishStatement (s : statement) : statement := 397 | match s with 398 | | Assign _ e => Assign "bork" (swedishExpression e) 399 | | Sequence s1 s2 => Sequence (swedishStatement s1) (swedishStatement s2) 400 | | IfThenElse e s1 s2 => IfThenElse (swedishExpression e) (swedishStatement s1) (swedishStatement s2) 401 | | WhileLoop e s1 => WhileLoop (swedishExpression e) (swedishStatement s1) 402 | end. 403 | 404 | Compute swedishStatement factorial. 405 | 406 | Fixpoint swedishList (ls : list var) : list var := 407 | match ls with 408 | | [] => [] 409 | | _ :: ls => "bork" :: swedishList ls 410 | end. 411 | 412 | Lemma listifyStatement_swedishStatement : forall s, 413 | listifyStatement (swedishStatement s) = swedishList (listifyStatement s). 414 | Proof. 415 | Admitted. 416 | -------------------------------------------------------------------------------- /ProofByReflection_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | Set Implicit Arguments. 4 | Set Asymmetric Patterns. 5 | Set Universe Polymorphism. 6 | 7 | 8 | (** * Proving Evenness *) 9 | 10 | Inductive isEven : nat -> Prop := 11 | | Even_O : isEven O 12 | | Even_SS : forall n, isEven n -> isEven (S (S n)). 13 | 14 | Theorem even_256 : isEven 256. 15 | Proof. 16 | Admitted. 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | (** * Reifying the Syntax of a Trivial Tautology Language *) 37 | 38 | Theorem true_galore : (True /\ True) -> (True \/ (True /\ (True -> True))). 39 | Proof. 40 | tauto. 41 | Qed. 42 | 43 | Print true_galore. 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | (** * A Monoid Expression Simplifier *) 67 | 68 | Section monoid. 69 | Variable A : Set. 70 | Variable e : A. 71 | Variable f : A -> A -> A. 72 | 73 | Infix "+" := f. 74 | 75 | Hypothesis assoc : forall a b c, (a + b) + c = a + (b + c). 76 | Hypothesis identl : forall a, e + a = a. 77 | Hypothesis identr : forall a, a + e = a. 78 | 79 | Inductive mexp : Set := 80 | | Ident : mexp 81 | | Var : A -> mexp 82 | | Op : mexp -> mexp -> mexp. 83 | 84 | (* Next, we write an interpretation function. *) 85 | 86 | Fixpoint mdenote (me : mexp) : A := 87 | match me with 88 | | Ident => e 89 | | Var v => v 90 | | Op me1 me2 => mdenote me1 + mdenote me2 91 | end. 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | Ltac reify me := 124 | match me with 125 | | e => Ident 126 | | ?me1 + ?me2 => 127 | let r1 := reify me1 in 128 | let r2 := reify me2 in 129 | constr:(Op r1 r2) 130 | | _ => constr:(Var me) 131 | end. 132 | 133 | (*Ltac monoid := 134 | match goal with 135 | | [ |- ?me1 = ?me2 ] => 136 | let r1 := reify me1 in 137 | let r2 := reify me2 in 138 | change (mdenote r1 = mdenote r2); 139 | apply monoid_reflect; simplify 140 | end. 141 | 142 | Theorem t1 : forall a b c d, a + b + c + d = a + (b + c) + d. 143 | simplify; monoid. 144 | reflexivity. 145 | Qed.*) 146 | End monoid. 147 | 148 | 149 | 150 | (** * Set Simplification for Model Checking *) 151 | 152 | (* Let's take a closer look at model-checking proofs like from last class. *) 153 | 154 | (* Here's a simple transition system, where state is just a [nat], and where 155 | * each step subtracts 1 or 2. *) 156 | 157 | Inductive subtract_step : nat -> nat -> Prop := 158 | | Subtract1 : forall n, subtract_step (S n) n 159 | | Subtract2 : forall n, subtract_step (S (S n)) n. 160 | 161 | Definition subtract_sys (n : nat) : trsys nat := {| 162 | Initial := {n}; 163 | Step := subtract_step 164 | |}. 165 | 166 | Lemma subtract_ok : 167 | invariantFor (subtract_sys 5) 168 | (fun n => n <= 5). 169 | Proof. 170 | eapply invariant_weaken. 171 | 172 | apply multiStepClosure_ok. 173 | simplify. 174 | (* Here we'll see that the Frap library uses slightly different, optimized 175 | * versions of the model-checking relations. For instance, [multiStepClosure] 176 | * takes an extra set argument, the _worklist_ recording newly discovered 177 | * states. There is no point in following edges out of states that were 178 | * already known at previous steps. *) 179 | 180 | (* Now, some more manual iterations: *) 181 | eapply MscStep. 182 | closure. 183 | (* Ew. What a big, ugly set expression. Let's shrink it down to something 184 | * more readable, with duplicates removed, etc. *) 185 | simplify. 186 | (* How does the Frap library do that? Proof by reflection is a big part of 187 | * it! Let's develop a baby version of that automation. The full-scale 188 | * version is in file Sets.v. *) 189 | Abort. 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | (* Back to our example, which we can now finish without calling [simplify] to 207 | * reduces trees of union operations. *) 208 | (*Lemma subtract_ok : 209 | invariantFor (subtract_sys 5) 210 | (fun n => n <= 5). 211 | Proof. 212 | eapply invariant_weaken. 213 | 214 | apply multiStepClosure_ok. 215 | simplify. 216 | 217 | (* Now, some more manual iterations: *) 218 | eapply MscStep. 219 | closure. 220 | simplify_set. 221 | (* Success! One subexpression shrunk. Now for the other. *) 222 | simplify_set. 223 | (* Our automation doesn't handle set difference, so we finish up calling the 224 | * library tactic. *) 225 | simplify. 226 | 227 | eapply MscStep. 228 | closure. 229 | simplify_set. 230 | simplify_set. 231 | simplify. 232 | 233 | eapply MscStep. 234 | closure. 235 | simplify_set. 236 | simplify_set. 237 | simplify. 238 | 239 | eapply MscStep. 240 | closure. 241 | simplify_set. 242 | simplify_set. 243 | simplify. 244 | 245 | model_check_done. 246 | 247 | simplify. 248 | linear_arithmetic. 249 | Qed.*) 250 | 251 | 252 | (** * A Smarter Tautology Solver *) 253 | 254 | Definition propvar := nat. 255 | 256 | Inductive formula : Set := 257 | | Atomic : propvar -> formula 258 | | Truth : formula 259 | | Falsehood : formula 260 | | And : formula -> formula -> formula 261 | | Or : formula -> formula -> formula 262 | | Imp : formula -> formula -> formula. 263 | 264 | Definition asgn := nat -> Prop. 265 | 266 | Fixpoint formulaDenote (atomics : asgn) (f : formula) : Prop := 267 | match f with 268 | | Atomic v => atomics v 269 | | Truth => True 270 | | Falsehood => False 271 | | And f1 f2 => formulaDenote atomics f1 /\ formulaDenote atomics f2 272 | | Or f1 f2 => formulaDenote atomics f1 \/ formulaDenote atomics f2 273 | | Imp f1 f2 => formulaDenote atomics f1 -> formulaDenote atomics f2 274 | end. 275 | 276 | Require Import ListSet. 277 | 278 | Section my_tauto. 279 | Variable atomics : asgn. 280 | 281 | Definition add (s : set propvar) (v : propvar) := set_add eq_nat_dec v s. 282 | 283 | Fixpoint allTrue (s : set propvar) : Prop := 284 | match s with 285 | | nil => True 286 | | v :: s' => atomics v /\ allTrue s' 287 | end. 288 | 289 | Theorem allTrue_add : forall v s, 290 | allTrue s 291 | -> atomics v 292 | -> allTrue (add s v). 293 | Proof. 294 | induct s; simplify; propositional; 295 | match goal with 296 | | [ |- context[if ?E then _ else _] ] => destruct E 297 | end; simplify; propositional. 298 | Qed. 299 | 300 | Theorem allTrue_In : forall v s, 301 | allTrue s 302 | -> set_In v s 303 | -> atomics v. 304 | Proof. 305 | induct s; simplify; equality. 306 | Qed. 307 | 308 | Fixpoint forward (known : set propvar) (hyp : formula) 309 | (cont : set propvar -> bool) : bool := 310 | match hyp with 311 | | Atomic v => cont (add known v) 312 | | Truth => cont known 313 | | Falsehood => true 314 | | And h1 h2 => forward known h1 (fun known' => 315 | forward known' h2 cont) 316 | | Or h1 h2 => forward known h1 cont && forward known h2 cont 317 | | Imp _ _ => cont known 318 | end. 319 | 320 | Compute fun cont => forward [] (Atomic 0) cont. 321 | Compute fun cont => forward [] (Or (Atomic 0) (Atomic 1)) cont. 322 | Compute fun cont => forward [] (Or (Atomic 0) (And (Atomic 1) (Atomic 2))) cont. 323 | 324 | Fixpoint backward (known : set propvar) (f : formula) : bool := 325 | match f with 326 | | Atomic v => if In_dec eq_nat_dec v known then true else false 327 | | Truth => true 328 | | Falsehood => false 329 | | And f1 f2 => backward known f1 && backward known f2 330 | | Or f1 f2 => backward known f1 || backward known f2 331 | | Imp f1 f2 => forward known f1 (fun known' => backward known' f2) 332 | end. 333 | 334 | Compute backward [] (Atomic 0). 335 | Compute backward [0] (Atomic 0). 336 | Compute backward [0; 2] (Or (Atomic 0) (Atomic 1)). 337 | Compute backward [2] (Or (Atomic 0) (Atomic 1)). 338 | Compute backward [2] (Imp (Atomic 0) (Or (Atomic 0) (Atomic 1))). 339 | Compute backward [2] (Imp (Or (Atomic 0) (Atomic 3)) (Or (Atomic 0) (Atomic 1))). 340 | Compute backward [2] (Imp (Or (Atomic 1) (Atomic 0)) (Or (Atomic 0) (Atomic 1))). 341 | End my_tauto. 342 | 343 | Lemma forward_ok : forall atomics hyp f known cont, 344 | forward known hyp cont = true 345 | -> (forall known', allTrue atomics known' 346 | -> cont known' = true 347 | -> formulaDenote atomics f) 348 | -> allTrue atomics known 349 | -> formulaDenote atomics hyp 350 | -> formulaDenote atomics f. 351 | Proof. 352 | induct hyp; simplify; propositional. 353 | 354 | apply H0 with (known' := add known p). 355 | apply allTrue_add. 356 | assumption. 357 | assumption. 358 | assumption. 359 | 360 | eapply H0. 361 | eassumption. 362 | assumption. 363 | 364 | eapply IHhyp1. 365 | eassumption. 366 | simplify. 367 | eauto. 368 | assumption. 369 | assumption. 370 | 371 | apply andb_true_iff in H; propositional. 372 | eapply IHhyp1. 373 | eassumption. 374 | assumption. 375 | assumption. 376 | assumption. 377 | 378 | apply andb_true_iff in H; propositional. 379 | eapply IHhyp2. 380 | eassumption. 381 | assumption. 382 | assumption. 383 | assumption. 384 | 385 | eapply H0. 386 | eassumption. 387 | assumption. 388 | Qed. 389 | 390 | Lemma backward_ok' : forall atomics f known, 391 | backward known f = true 392 | -> allTrue atomics known 393 | -> formulaDenote atomics f. 394 | Proof. 395 | induct f; simplify; propositional. 396 | 397 | cases (in_dec Nat.eq_dec p known); propositional. 398 | eapply allTrue_In. 399 | eassumption. 400 | unfold set_In. 401 | assumption. 402 | equality. 403 | 404 | equality. 405 | 406 | apply andb_true_iff in H; propositional. 407 | eapply IHf1. 408 | eassumption. 409 | assumption. 410 | 411 | apply andb_true_iff in H; propositional. 412 | eapply IHf2. 413 | eassumption. 414 | assumption. 415 | 416 | apply orb_true_iff in H; propositional. 417 | left. 418 | eapply IHf1. 419 | eassumption. 420 | assumption. 421 | right. 422 | eapply IHf2. 423 | eassumption. 424 | assumption. 425 | 426 | eapply forward_ok. 427 | eassumption. 428 | simplify. 429 | eapply IHf2. 430 | eassumption. 431 | assumption. 432 | assumption. 433 | assumption. 434 | Qed. 435 | 436 | Theorem backward_ok : forall f, 437 | backward [] f = true 438 | -> forall atomics, formulaDenote atomics f. 439 | Proof. 440 | simplify. 441 | apply backward_ok' with (known := []). 442 | assumption. 443 | simplify. 444 | propositional. 445 | Qed. 446 | 447 | (* Find the position of an element in a list. *) 448 | Ltac position x ls := 449 | match ls with 450 | | [] => constr:(@None nat) 451 | | x :: _ => constr:(Some 0) 452 | | _ :: ?ls' => 453 | let p := position x ls' in 454 | match p with 455 | | None => p 456 | | Some ?n => constr:(Some (S n)) 457 | end 458 | end. 459 | 460 | (* Compute a duplicate-free list of all variables in [P], combining it with 461 | * [acc]. *) 462 | Ltac vars_in P acc := 463 | match P with 464 | | True => acc 465 | | False => acc 466 | | ?Q1 /\ ?Q2 => 467 | let acc' := vars_in Q1 acc in 468 | vars_in Q2 acc' 469 | | ?Q1 \/ ?Q2 => 470 | let acc' := vars_in Q1 acc in 471 | vars_in Q2 acc' 472 | | ?Q1 -> ?Q2 => 473 | let acc' := vars_in Q1 acc in 474 | vars_in Q2 acc' 475 | | _ => 476 | let pos := position P acc in 477 | match pos with 478 | | Some _ => acc 479 | | None => constr:(P :: acc) 480 | end 481 | end. 482 | 483 | (* Reification of formula [P], with a pregenerated list [vars] of variables it 484 | * may mention *) 485 | Ltac reify_tauto' P vars := 486 | match P with 487 | | True => Truth 488 | | False => Falsehood 489 | | ?Q1 /\ ?Q2 => 490 | let q1 := reify_tauto' Q1 vars in 491 | let q2 := reify_tauto' Q2 vars in 492 | constr:(And q1 q2) 493 | | ?Q1 \/ ?Q2 => 494 | let q1 := reify_tauto' Q1 vars in 495 | let q2 := reify_tauto' Q2 vars in 496 | constr:(Or q1 q2) 497 | | ?Q1 -> ?Q2 => 498 | let q1 := reify_tauto' Q1 vars in 499 | let q2 := reify_tauto' Q2 vars in 500 | constr:(Imp q1 q2) 501 | | _ => 502 | let pos := position P vars in 503 | match pos with 504 | | Some ?pos' => constr:(Atomic pos') 505 | end 506 | end. 507 | 508 | (* Our final tactic implementation is now fairly straightforward. First, we 509 | * [intro] all quantifiers that do not bind [Prop]s. Then we reify. Finally, 510 | * we call the verified procedure through a lemma. *) 511 | 512 | Ltac my_tauto := 513 | repeat match goal with 514 | | [ |- forall x : ?P, _ ] => 515 | match type of P with 516 | | Prop => fail 1 517 | | _ => intro 518 | end 519 | end; 520 | match goal with 521 | | [ |- ?P ] => 522 | let vars := vars_in P (@nil Prop) in 523 | let p := reify_tauto' P vars in 524 | change (formulaDenote (nth_default False vars) p) 525 | end; 526 | apply backward_ok; reflexivity. 527 | 528 | (* A few examples demonstrate how the tactic works: *) 529 | 530 | Theorem mt1 : True. 531 | Proof. 532 | my_tauto. 533 | Qed. 534 | 535 | Print mt1. 536 | 537 | Theorem mt2 : forall x y : nat, x = y -> x = y. 538 | Proof. 539 | my_tauto. 540 | Qed. 541 | 542 | Print mt2. 543 | 544 | Theorem mt3 : forall x y z, 545 | (x < y /\ y > z) \/ (y > z /\ x < S y) 546 | -> y > z /\ (x < y \/ x < S y). 547 | Proof. 548 | my_tauto. 549 | Qed. 550 | 551 | Print mt3. 552 | 553 | Theorem mt4 : True /\ True /\ True /\ True /\ True /\ True /\ False -> False. 554 | Proof. 555 | my_tauto. 556 | Qed. 557 | 558 | Print mt4. 559 | 560 | Theorem mt4' : True /\ True /\ True /\ True /\ True /\ True /\ False -> False. 561 | Proof. 562 | tauto. 563 | Qed. 564 | 565 | Print mt4'. 566 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Formal Reasoning About Programs 2 | 3 | This is an in-progress, open-source book by [Adam Chlipala](http://adam.chlipala.net/) simultaneously introducing [the Coq proof assistant](http://coq.inria.fr/) and techniques for proving correctness of programs. That is, the game is doing completely rigorous, machine-checked mathematical proofs, showing that programs meet their specifications. 4 | 5 | Just run `make` here to build everything, including the book `frap_book.pdf` and the accompanying Coq source modules. Alternatively, run `make lib` to build just the book library, not the chapter example files or PDF. 6 | 7 | # Code associated with the different chapters 8 | 9 | The main narrative, also present in the book PDF, presents standard program-proof ideas, without rigorous proofs. Matching Coq files here show how to make it rigorous. Interleaved with that narrative, there are also other lectures' worth of material, for building up more practical background on Coq itself. That secondary track appears in this list, too, at a higher level of indentation. 10 | 11 | * Chapter 2: `BasicSyntax.v` 12 | * `Polymorphism.v`: polymorphism and generic data structures 13 | * Chapter 3: `DataAbstraction.v` 14 | * Chapter 4: `Interpreters.v` 15 | * `FirstClassFunctions.v`: functions as data; continuations and continuation-passing style 16 | * Chapter 5: `RuleInduction.v` 17 | * Chapter 6: `TransitionSystems.v` 18 | * `IntroToProofScripting.v`: writing scripts to find proofs in Coq 19 | * Chapter 7: `ModelChecking.v` 20 | * `ProofByReflection.v`: writing verified proof procedures in Coq 21 | * Chapter 8: `OperationalSemantics.v` 22 | * `LogicProgramming.v`: 'eauto' and friends, to automate proofs via logic programming 23 | * Chapter 9: `AbstractInterpretation.v` 24 | * Chapter 10: `CompilerCorrectness.v` 25 | * Chapter 11: `LambdaCalculusAndTypeSoundness.v` 26 | * Chapter 12: `EvaluationContexts.v` 27 | * Chapter 13: `TypesAndMutation.v` 28 | * Chapter 14: `HoareLogic.v` 29 | * Chapter 15: `DeepAndShallowEmbeddings.v` 30 | * Chapter 16: `SeparationLogic.v` 31 | * Chapter 17: `Connecting.v` 32 | * Chapter 18: `ProgramDerivation.v` 33 | * Chapter 19: `SharedMemory.v` 34 | * Chapter 20: `ConcurrentSeparationLogic.v` 35 | * Chapter 21: `MessagesAndRefinement.v` 36 | * Chapter 22: `SessionTypes.v` 37 | 38 | There are also two supplementary files that are independent of the main narrative, for introducing programming with dependent types, a distinctive Coq feature that we neither use nor recommend for the problem sets, but which many students find interesting (and useful in other contexts). 39 | * `SubsetTypes.v`: a first introduction to dependent types by attaching predicates to normal types (used after `CompilerCorrectness.v` in the last course offering) 40 | * `DependentInductiveTypes.v`: building type dependency into datatype definitions (used after `LambdaCalculusAndTypeSoundness.v` in the last course offering) 41 | -------------------------------------------------------------------------------- /Relations.v: -------------------------------------------------------------------------------- 1 | Set Implicit Arguments. 2 | 3 | 4 | Section trc. 5 | Variable A : Type. 6 | Variable R : A -> A -> Prop. 7 | 8 | Inductive trc : A -> A -> Prop := 9 | | TrcRefl : forall x, trc x x 10 | | TrcFront : forall x y z, 11 | R x y 12 | -> trc y z 13 | -> trc x z. 14 | 15 | Hint Constructors trc : core. 16 | 17 | Theorem trc_one : forall x y, R x y 18 | -> trc x y. 19 | Proof. 20 | eauto. 21 | Qed. 22 | 23 | Hint Resolve trc_one : core. 24 | 25 | Theorem trc_trans : forall x y, trc x y 26 | -> forall z, trc y z 27 | -> trc x z. 28 | Proof. 29 | induction 1; eauto. 30 | Qed. 31 | 32 | Hint Resolve trc_trans : core. 33 | 34 | Inductive trcEnd : A -> A -> Prop := 35 | | TrcEndRefl : forall x, trcEnd x x 36 | | TrcBack : forall x y z, 37 | trcEnd x y 38 | -> R y z 39 | -> trcEnd x z. 40 | 41 | Hint Constructors trcEnd : core. 42 | 43 | Lemma TrcFront' : forall x y z, 44 | R x y 45 | -> trcEnd y z 46 | -> trcEnd x z. 47 | Proof. 48 | induction 2; eauto. 49 | Qed. 50 | 51 | Hint Resolve TrcFront' : core. 52 | 53 | Theorem trc_trcEnd : forall x y, trc x y 54 | -> trcEnd x y. 55 | Proof. 56 | induction 1; eauto. 57 | Qed. 58 | 59 | Hint Resolve trc_trcEnd : core. 60 | 61 | Lemma TrcBack' : forall x y z, 62 | trc x y 63 | -> R y z 64 | -> trc x z. 65 | Proof. 66 | induction 1; eauto. 67 | Qed. 68 | 69 | Hint Resolve TrcBack' : core. 70 | 71 | Theorem trcEnd_trans : forall x y, trcEnd x y 72 | -> forall z, trcEnd y z 73 | -> trcEnd x z. 74 | Proof. 75 | induction 1; eauto. 76 | Qed. 77 | 78 | Hint Resolve trcEnd_trans : core. 79 | 80 | Theorem trcEnd_trc : forall x y, trcEnd x y 81 | -> trc x y. 82 | Proof. 83 | induction 1; eauto. 84 | Qed. 85 | 86 | Hint Resolve trcEnd_trc : core. 87 | 88 | Inductive trcLiteral : A -> A -> Prop := 89 | | TrcLiteralRefl : forall x, trcLiteral x x 90 | | TrcTrans : forall x y z, trcLiteral x y 91 | -> trcLiteral y z 92 | -> trcLiteral x z 93 | | TrcInclude : forall x y, R x y 94 | -> trcLiteral x y. 95 | 96 | Hint Constructors trcLiteral : core. 97 | 98 | Theorem trc_trcLiteral : forall x y, trc x y 99 | -> trcLiteral x y. 100 | Proof. 101 | induction 1; eauto. 102 | Qed. 103 | 104 | Theorem trcLiteral_trc : forall x y, trcLiteral x y 105 | -> trc x y. 106 | Proof. 107 | induction 1; eauto. 108 | Qed. 109 | 110 | Hint Resolve trc_trcLiteral trcLiteral_trc : core. 111 | 112 | Theorem trcEnd_trcLiteral : forall x y, trcEnd x y 113 | -> trcLiteral x y. 114 | Proof. 115 | induction 1; eauto. 116 | Qed. 117 | 118 | Theorem trcLiteral_trcEnd : forall x y, trcLiteral x y 119 | -> trcEnd x y. 120 | Proof. 121 | induction 1; eauto. 122 | Qed. 123 | 124 | Hint Resolve trcEnd_trcLiteral trcLiteral_trcEnd : core. 125 | End trc. 126 | 127 | Notation "R ^*" := (trc R) (at level 0). 128 | Notation "*^ R" := (trcEnd R) (at level 0). 129 | 130 | Hint Constructors trc : core. 131 | -------------------------------------------------------------------------------- /RuleInduction_template.v: -------------------------------------------------------------------------------- 1 | Require Import Frap. 2 | 3 | 4 | (** * Finite sets as inductive predicates *) 5 | 6 | Inductive my_favorite_numbers : nat -> Prop := 7 | | ILike17 : my_favorite_numbers 17 8 | | ILike23 : my_favorite_numbers 23 9 | | ILike42 : my_favorite_numbers 42. 10 | 11 | Check my_favorite_numbers_ind. 12 | 13 | Theorem favorites_below_50 : forall n, my_favorite_numbers n -> n < 50. 14 | Proof. 15 | Admitted. 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | (** * Transitive closure of relations *) 40 | 41 | Inductive tc {A} (R : A -> A -> Prop) : A -> A -> Prop := 42 | | TcBase : forall x y, R x y -> tc R x y 43 | | TcTrans : forall x y z, tc R x y -> tc R y z -> tc R x z. 44 | 45 | (** ** Less-than reimagined *) 46 | 47 | Definition oneApart (n m : nat) : Prop := 48 | n + 1 = m. 49 | 50 | Definition lt' : nat -> nat -> Prop := tc oneApart. 51 | 52 | Theorem lt'_lt : forall n m, lt' n m -> n < m. 53 | Proof. 54 | Admitted. 55 | 56 | Theorem lt_lt' : forall n m, n < m -> lt' n m. 57 | Proof. 58 | Admitted. 59 | 60 | (** ** Transitive closure is idempotent. *) 61 | 62 | Theorem tc_tc2 : forall A (R : A -> A -> Prop) x y, tc R x y -> tc (tc R) x y. 63 | Proof. 64 | Admitted. 65 | 66 | Theorem tc2_tc : forall A (R : A -> A -> Prop) x y, tc (tc R) x y -> tc R x y. 67 | Proof. 68 | Admitted. 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | (** * Permutation *) 92 | 93 | (* Lifted from the Coq standard library: *) 94 | Inductive Permutation {A} : list A -> list A -> Prop := 95 | | perm_nil : 96 | Permutation [] [] 97 | | perm_skip : forall x l l', 98 | Permutation l l' -> Permutation (x::l) (x::l') 99 | | perm_swap : forall x y l, 100 | Permutation (y::x::l) (x::y::l) 101 | | perm_trans : forall l l' l'', 102 | Permutation l l' -> Permutation l' l'' -> Permutation l l''. 103 | 104 | Theorem Permutation_rev : forall A (ls : list A), 105 | Permutation ls (rev ls). 106 | Proof. 107 | Admitted. 108 | 109 | Theorem Permutation_length : forall A (ls1 ls2 : list A), 110 | Permutation ls1 ls2 -> length ls1 = length ls2. 111 | Proof. 112 | Admitted. 113 | 114 | Theorem Permutation_app : forall A (ls1 ls1' ls2 ls2' : list A), 115 | Permutation ls1 ls1' 116 | -> Permutation ls2 ls2' 117 | -> Permutation (ls1 ++ ls2) (ls1' ++ ls2'). 118 | Proof. 119 | Admitted. 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | (** * Simple propositional logic *) 146 | 147 | Inductive prop := 148 | | Truth 149 | | Falsehood 150 | | And (p1 p2 : prop) 151 | | Or (p1 p2 : prop). 152 | 153 | Inductive valid : prop -> Prop := 154 | | ValidTruth : 155 | valid Truth 156 | | ValidAnd : forall p1 p2, 157 | valid p1 158 | -> valid p2 159 | -> valid (And p1 p2) 160 | | ValidOr1 : forall p1 p2, 161 | valid p1 162 | -> valid (Or p1 p2) 163 | | ValidOr2 : forall p1 p2, 164 | valid p2 165 | -> valid (Or p1 p2). 166 | 167 | Fixpoint interp (p : prop) : Prop := 168 | match p with 169 | | Truth => True 170 | | Falsehood => False 171 | | And p1 p2 => interp p1 /\ interp p2 172 | | Or p1 p2 => interp p1 \/ interp p2 173 | end. 174 | 175 | Theorem interp_valid : forall p, interp p -> valid p. 176 | Proof. 177 | Admitted. 178 | 179 | Theorem valid_interp : forall p, valid p -> interp p. 180 | Proof. 181 | Admitted. 182 | 183 | Fixpoint commuter (p : prop) : prop := 184 | match p with 185 | | Truth => Truth 186 | | Falsehood => Falsehood 187 | | And p1 p2 => And (commuter p2) (commuter p1) 188 | | Or p1 p2 => Or (commuter p2) (commuter p1) 189 | end. 190 | 191 | Theorem valid_commuter_fwd : forall p, valid p -> valid (commuter p). 192 | Proof. 193 | Admitted. 194 | 195 | Theorem valid_commuter_bwd : forall p, valid (commuter p) -> valid p. 196 | Proof. 197 | Admitted. 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | (* Proofs for an extension I hope we'll get to: 236 | 237 | Fixpoint interp (vars : var -> Prop) (p : prop) : Prop := 238 | match p with 239 | | Truth => True 240 | | Falsehood => False 241 | | Var x => vars x 242 | | And p1 p2 => interp vars p1 /\ interp vars p2 243 | | Or p1 p2 => interp vars p1 \/ interp vars p2 244 | | Imply p1 p2 => interp vars p1 -> interp vars p2 245 | end. 246 | 247 | Theorem valid_interp : forall vars hyps p, 248 | valid hyps p 249 | -> (forall h, hyps h -> interp vars h) 250 | -> interp vars p. 251 | Proof. 252 | induct 1; simplify. 253 | 254 | apply H0. 255 | assumption. 256 | 257 | propositional. 258 | 259 | propositional. 260 | 261 | propositional. 262 | 263 | propositional. 264 | 265 | propositional. 266 | 267 | propositional. 268 | 269 | propositional. 270 | 271 | propositional. 272 | apply IHvalid2. 273 | propositional. 274 | equality. 275 | apply H2. 276 | assumption. 277 | apply IHvalid3. 278 | propositional. 279 | equality. 280 | apply H2. 281 | assumption. 282 | 283 | apply IHvalid. 284 | propositional. 285 | equality. 286 | apply H0. 287 | assumption. 288 | 289 | propositional. 290 | 291 | excluded_middle (interp vars p); propositional. 292 | (* Note that use of excluded middle is a bit controversial in Coq, 293 | * and we'll generally be trying to avoid it, 294 | * but it helps enough with this example that we don't sweat the details. *) 295 | Qed. 296 | 297 | Lemma valid_weaken : forall hyps1 p, 298 | valid hyps1 p 299 | -> forall hyps2 : prop -> Prop, 300 | (forall h, hyps1 h -> hyps2 h) 301 | -> valid hyps2 p. 302 | Proof. 303 | induct 1; simplify. 304 | 305 | apply ValidHyp. 306 | apply H0. 307 | assumption. 308 | 309 | apply ValidTruthIntro. 310 | 311 | apply ValidFalsehoodElim. 312 | apply IHvalid. 313 | assumption. 314 | 315 | apply ValidAndIntro. 316 | apply IHvalid1. 317 | assumption. 318 | apply IHvalid2. 319 | assumption. 320 | 321 | apply ValidAndElim1 with p2. 322 | apply IHvalid. 323 | assumption. 324 | 325 | apply ValidAndElim2 with p1. 326 | apply IHvalid. 327 | assumption. 328 | 329 | apply ValidOrIntro1. 330 | apply IHvalid. 331 | assumption. 332 | 333 | apply ValidOrIntro2. 334 | apply IHvalid. 335 | assumption. 336 | 337 | apply ValidOrElim with p1 p2. 338 | apply IHvalid1. 339 | assumption. 340 | apply IHvalid2. 341 | first_order. 342 | apply IHvalid3. 343 | first_order. 344 | 345 | apply ValidImplyIntro. 346 | apply IHvalid. 347 | propositional. 348 | right. 349 | apply H0. 350 | assumption. 351 | 352 | apply ValidImplyElim with p1. 353 | apply IHvalid1. 354 | assumption. 355 | apply IHvalid2. 356 | assumption. 357 | 358 | apply ValidExcludedMiddle. 359 | Qed. 360 | 361 | Lemma valid_cut : forall hyps1 p p', 362 | valid hyps1 p 363 | -> forall hyps2, valid hyps2 p' 364 | -> (forall h, hyps1 h -> hyps2 h \/ h = p') 365 | -> valid hyps2 p. 366 | Proof. 367 | induct 1; simplify. 368 | 369 | apply H1 in H. 370 | propositional. 371 | apply ValidHyp. 372 | assumption. 373 | equality. 374 | 375 | apply ValidTruthIntro. 376 | 377 | apply ValidFalsehoodElim. 378 | apply IHvalid; assumption. 379 | 380 | apply ValidAndIntro. 381 | apply IHvalid1; assumption. 382 | apply IHvalid2; assumption. 383 | 384 | apply ValidAndElim1 with p2. 385 | apply IHvalid; assumption. 386 | 387 | apply ValidAndElim2 with p1. 388 | apply IHvalid; assumption. 389 | 390 | apply ValidOrIntro1. 391 | apply IHvalid; assumption. 392 | 393 | apply ValidOrIntro2. 394 | apply IHvalid; assumption. 395 | 396 | apply ValidOrElim with p1 p2. 397 | apply IHvalid1; assumption. 398 | apply IHvalid2. 399 | apply valid_weaken with hyps2. 400 | assumption. 401 | propositional. 402 | first_order. 403 | apply IHvalid3. 404 | apply valid_weaken with hyps2. 405 | assumption. 406 | propositional. 407 | first_order. 408 | 409 | apply ValidImplyIntro. 410 | apply IHvalid. 411 | apply valid_weaken with hyps2. 412 | assumption. 413 | propositional. 414 | first_order. 415 | 416 | apply ValidImplyElim with p1. 417 | apply IHvalid1; assumption. 418 | apply IHvalid2; assumption. 419 | 420 | apply ValidExcludedMiddle. 421 | Qed. 422 | 423 | Fixpoint varsOf (p : prop) : list var := 424 | match p with 425 | | Truth 426 | | Falsehood => [] 427 | | Var x => [x] 428 | | And p1 p2 429 | | Or p1 p2 430 | | Imply p1 p2 => varsOf p1 ++ varsOf p2 431 | end. 432 | 433 | Lemma interp_valid'' : forall p hyps, 434 | (forall x, In x (varsOf p) -> hyps (Var x) \/ hyps (Not (Var x))) 435 | -> (forall x, hyps (Var x) -> ~hyps (Not (Var x))) 436 | -> IFF interp (fun x => hyps (Var x)) p 437 | then valid hyps p 438 | else valid hyps (Not p). 439 | Proof. 440 | induct p; unfold IF_then_else; simplify. 441 | 442 | left; propositional. 443 | apply ValidTruthIntro. 444 | 445 | right; propositional. 446 | apply ValidImplyIntro. 447 | apply ValidHyp. 448 | propositional. 449 | 450 | specialize (H x); propositional. 451 | left; propositional. 452 | apply ValidHyp. 453 | assumption. 454 | right; first_order. 455 | apply ValidHyp. 456 | assumption. 457 | 458 | excluded_middle (interp (fun x => hyps (Var x)) p1). 459 | excluded_middle (interp (fun x => hyps (Var x)) p2). 460 | left; propositional. 461 | apply ValidAndIntro. 462 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 463 | apply IHp1; propositional. 464 | apply H. 465 | apply in_or_app; propositional. 466 | unfold IF_then_else in H3; propositional. 467 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 468 | apply IHp2; propositional. 469 | apply H. 470 | apply in_or_app; propositional. 471 | unfold IF_then_else in H3; propositional. 472 | right; propositional. 473 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 474 | apply IHp2; propositional. 475 | apply H. 476 | apply in_or_app; propositional. 477 | unfold IF_then_else in H3; propositional. 478 | apply ValidImplyIntro. 479 | apply ValidImplyElim with p2. 480 | apply valid_weaken with hyps. 481 | assumption. 482 | propositional. 483 | apply ValidAndElim2 with p1. 484 | apply ValidHyp. 485 | propositional. 486 | right; propositional. 487 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 488 | apply IHp1; propositional. 489 | apply H. 490 | apply in_or_app; propositional. 491 | unfold IF_then_else in H2; propositional. 492 | apply ValidImplyIntro. 493 | apply ValidImplyElim with p1. 494 | apply valid_weaken with hyps. 495 | assumption. 496 | propositional. 497 | apply ValidAndElim1 with p2. 498 | apply ValidHyp. 499 | propositional. 500 | 501 | excluded_middle (interp (fun x => hyps (Var x)) p1). 502 | left; propositional. 503 | apply ValidOrIntro1. 504 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 505 | apply IHp1; propositional. 506 | apply H. 507 | apply in_or_app; propositional. 508 | unfold IF_then_else in H2; propositional. 509 | excluded_middle (interp (fun x => hyps (Var x)) p2). 510 | left; propositional. 511 | apply ValidOrIntro2. 512 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 513 | apply IHp2; propositional. 514 | apply H. 515 | apply in_or_app; propositional. 516 | unfold IF_then_else in H3; propositional. 517 | right; propositional. 518 | apply ValidImplyIntro. 519 | apply ValidOrElim with p1 p2. 520 | apply ValidHyp. 521 | propositional. 522 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 523 | apply IHp1; propositional. 524 | apply H. 525 | apply in_or_app; propositional. 526 | unfold IF_then_else in H3; propositional. 527 | apply ValidImplyElim with p1. 528 | apply valid_weaken with hyps. 529 | assumption. 530 | propositional. 531 | apply ValidHyp. 532 | propositional. 533 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 534 | apply IHp2; propositional. 535 | apply H. 536 | apply in_or_app; propositional. 537 | unfold IF_then_else in H3; propositional. 538 | apply ValidImplyElim with p2. 539 | apply valid_weaken with hyps. 540 | assumption. 541 | propositional. 542 | apply ValidHyp. 543 | propositional. 544 | 545 | excluded_middle (interp (fun x => hyps (Var x)) p1). 546 | excluded_middle (interp (fun x => hyps (Var x)) p2). 547 | left; propositional. 548 | apply ValidImplyIntro. 549 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 550 | apply IHp2; propositional. 551 | apply H. 552 | apply in_or_app; propositional. 553 | unfold IF_then_else in H3; propositional. 554 | apply valid_weaken with hyps. 555 | assumption. 556 | propositional. 557 | right; propositional. 558 | apply ValidImplyIntro. 559 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 560 | apply IHp1; propositional. 561 | apply H. 562 | apply in_or_app; propositional. 563 | unfold IF_then_else in H3; propositional. 564 | assert (IFF interp (fun x : var => hyps (Var x)) p2 then valid hyps p2 else valid hyps (Not p2)). 565 | apply IHp2; propositional. 566 | apply H. 567 | apply in_or_app; propositional. 568 | unfold IF_then_else in H4; propositional. 569 | apply ValidImplyElim with p2. 570 | apply valid_weaken with hyps. 571 | assumption. 572 | propositional. 573 | apply ValidImplyElim with p1. 574 | apply ValidHyp. 575 | propositional. 576 | apply valid_weaken with hyps. 577 | assumption. 578 | propositional. 579 | left; propositional. 580 | apply ValidImplyIntro. 581 | assert (IFF interp (fun x : var => hyps (Var x)) p1 then valid hyps p1 else valid hyps (Not p1)). 582 | apply IHp1; propositional. 583 | apply H. 584 | apply in_or_app; propositional. 585 | unfold IF_then_else in H2; propositional. 586 | apply ValidFalsehoodElim. 587 | apply ValidImplyElim with p1. 588 | apply valid_weaken with hyps. 589 | assumption. 590 | propositional. 591 | apply ValidHyp. 592 | propositional. 593 | Qed. 594 | 595 | Lemma interp_valid' : forall p leftToDo alreadySplit, 596 | (forall x, In x (varsOf p) -> In x (alreadySplit ++ leftToDo)) 597 | -> forall hyps, (forall x, In x alreadySplit -> hyps (Var x) \/ hyps (Not (Var x))) 598 | -> (forall x, hyps (Var x) \/ hyps (Not (Var x)) -> In x alreadySplit) 599 | -> (forall x, hyps (Var x) -> ~hyps (Not (Var x))) 600 | -> (forall vars : var -> Prop, 601 | (forall x, hyps (Var x) -> vars x) 602 | -> (forall x, hyps (Not (Var x)) -> ~vars x) 603 | -> interp vars p) 604 | -> valid hyps p. 605 | Proof. 606 | induct leftToDo; simplify. 607 | 608 | rewrite app_nil_r in H. 609 | assert (IFF interp (fun x : var => hyps (Var x)) p then valid hyps p else valid hyps (Not p)). 610 | apply interp_valid''; first_order. 611 | unfold IF_then_else in H4; propositional. 612 | exfalso. 613 | apply H4. 614 | apply H3. 615 | propositional. 616 | first_order. 617 | 618 | excluded_middle (In a alreadySplit). 619 | 620 | apply IHleftToDo with alreadySplit; simplify. 621 | apply H in H5. 622 | apply in_app_or in H5. 623 | simplify. 624 | apply in_or_app. 625 | propositional; subst. 626 | propositional. 627 | first_order. 628 | first_order. 629 | first_order. 630 | first_order. 631 | 632 | apply ValidOrElim with (Var a) (Not (Var a)). 633 | apply ValidExcludedMiddle. 634 | 635 | apply IHleftToDo with (alreadySplit ++ [a]); simplify. 636 | apply H in H5. 637 | apply in_app_or in H5. 638 | simplify. 639 | apply in_or_app. 640 | propositional; subst. 641 | left; apply in_or_app; propositional. 642 | left; apply in_or_app; simplify; propositional. 643 | apply in_app_or in H5. 644 | simplify. 645 | propositional; subst. 646 | apply H0 in H6. 647 | propositional. 648 | propositional. 649 | propositional. 650 | invert H5. 651 | apply in_or_app. 652 | simplify. 653 | propositional. 654 | apply in_or_app. 655 | simplify. 656 | first_order. 657 | invert H5. 658 | apply in_or_app. 659 | simplify. 660 | first_order. 661 | propositional. 662 | invert H5. 663 | invert H7. 664 | first_order. 665 | invert H5. 666 | first_order. 667 | apply H3. 668 | first_order. 669 | first_order. 670 | 671 | apply IHleftToDo with (alreadySplit ++ [a]); simplify. 672 | apply H in H5. 673 | apply in_app_or in H5. 674 | simplify. 675 | apply in_or_app. 676 | propositional; subst. 677 | left; apply in_or_app; propositional. 678 | left; apply in_or_app; simplify; propositional. 679 | apply in_app_or in H5. 680 | simplify. 681 | propositional; subst. 682 | apply H0 in H6. 683 | propositional. 684 | propositional. 685 | propositional. 686 | invert H5. 687 | apply in_or_app. 688 | simplify. 689 | first_order. 690 | invert H5. 691 | apply in_or_app. 692 | simplify. 693 | propositional. 694 | apply in_or_app. 695 | simplify. 696 | first_order. 697 | propositional. 698 | invert H7. 699 | invert H7. 700 | invert H5. 701 | first_order. 702 | first_order. 703 | apply H3. 704 | first_order. 705 | first_order. 706 | Qed. 707 | 708 | Theorem interp_valid : forall p, 709 | (forall vars, interp vars p) 710 | -> valid (fun _ => False) p. 711 | Proof. 712 | simplify. 713 | apply interp_valid' with (varsOf p) []; simplify; first_order. 714 | Qed. 715 | *) 716 | -------------------------------------------------------------------------------- /SepCancel.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * An entailment procedure for separation logic's assertion language 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *) 5 | 6 | Require Import Frap Setoid Classes.Morphisms. 7 | 8 | Set Implicit Arguments. 9 | 10 | Module Type SEP. 11 | Parameter hprop : Type. 12 | Parameter lift : Prop -> hprop. 13 | Parameter star : hprop -> hprop -> hprop. 14 | Parameter exis : forall A, (A -> hprop) -> hprop. 15 | 16 | Notation "[| P |]" := (lift P). 17 | Infix "*" := star. 18 | Notation "'exists' x .. y , p" := (exis (fun x => .. (exis (fun y => p)) ..)). 19 | 20 | Parameters himp heq : hprop -> hprop -> Prop. 21 | 22 | Infix "===" := heq (no associativity, at level 70). 23 | Infix "===>" := himp (no associativity, at level 70). 24 | 25 | Axiom himp_heq : forall p q, p === q 26 | <-> (p ===> q /\ q ===> p). 27 | Axiom himp_refl : forall p, p ===> p. 28 | Axiom himp_trans : forall p q r, p ===> q -> q ===> r -> p ===> r. 29 | 30 | Axiom lift_left : forall p (Q : Prop) r, 31 | (Q -> p ===> r) 32 | -> p * [| Q |] ===> r. 33 | Axiom lift_right : forall p q (R : Prop), 34 | p ===> q 35 | -> R 36 | -> p ===> q * [| R |]. 37 | Axiom extra_lift : forall (P : Prop) p, 38 | P 39 | -> p === [| P |] * p. 40 | 41 | Axiom star_comm : forall p q, p * q === q * p. 42 | Axiom star_assoc : forall p q r, p * (q * r) === (p * q) * r. 43 | Axiom star_cancel : forall p1 p2 q1 q2, p1 ===> p2 44 | -> q1 ===> q2 45 | -> p1 * q1 ===> p2 * q2. 46 | 47 | Axiom exis_gulp : forall A p (q : A -> _), 48 | p * exis q === exis (fun x => p * q x). 49 | Axiom exis_left : forall A (p : A -> _) q, 50 | (forall x, p x ===> q) 51 | -> exis p ===> q. 52 | Axiom exis_right : forall A p (q : A -> _) x, 53 | p ===> q x 54 | -> p ===> exis q. 55 | End SEP. 56 | 57 | Module Make(Import S : SEP). 58 | Add Parametric Relation : hprop himp 59 | reflexivity proved by himp_refl 60 | transitivity proved by himp_trans 61 | as himp_rel. 62 | 63 | Lemma heq_refl : forall p, p === p. 64 | Proof. 65 | intros; apply himp_heq; intuition (apply himp_refl). 66 | Qed. 67 | 68 | Lemma heq_sym : forall p q, p === q -> q === p. 69 | Proof. 70 | intros; apply himp_heq; apply himp_heq in H; intuition. 71 | Qed. 72 | 73 | Lemma heq_trans : forall p q r, p === q -> q === r -> p === r. 74 | Proof. 75 | intros; apply himp_heq; apply himp_heq in H; apply himp_heq in H0; 76 | intuition (eauto using himp_trans). 77 | Qed. 78 | 79 | Add Parametric Relation : hprop heq 80 | reflexivity proved by heq_refl 81 | symmetry proved by heq_sym 82 | transitivity proved by heq_trans 83 | as heq_rel. 84 | 85 | Global Instance himp_heq_mor : Proper (heq ==> heq ==> iff) himp. 86 | Proof. 87 | hnf; intros; hnf; intros. 88 | apply himp_heq in H; apply himp_heq in H0. 89 | intuition eauto using himp_trans. 90 | Qed. 91 | 92 | Add Parametric Morphism : star 93 | with signature heq ==> heq ==> heq 94 | as star_mor. 95 | Proof. 96 | intros; apply himp_heq; apply himp_heq in H; apply himp_heq in H0; 97 | intuition (auto using star_cancel). 98 | Qed. 99 | 100 | Add Parametric Morphism : star 101 | with signature himp ==> himp ==> himp 102 | as star_mor'. 103 | Proof. 104 | auto using star_cancel. 105 | Qed. 106 | 107 | Global Instance exis_iff_morphism (A : Type) : 108 | Proper (pointwise_relation A heq ==> heq) (@exis A). 109 | Proof. 110 | hnf; intros; apply himp_heq; intuition. 111 | hnf in H. 112 | apply exis_left; intro. 113 | eapply exis_right. 114 | assert (x x0 === y x0) by eauto. 115 | apply himp_heq in H0; intuition eauto. 116 | hnf in H. 117 | apply exis_left; intro. 118 | eapply exis_right. 119 | assert (x x0 === y x0) by eauto. 120 | apply himp_heq in H0; intuition eauto. 121 | Qed. 122 | 123 | Global Instance exis_imp_morphism (A : Type) : 124 | Proper (pointwise_relation A himp ==> himp) (@exis A). 125 | Proof. 126 | hnf; intros. 127 | apply exis_left; intro. 128 | eapply exis_right. 129 | unfold pointwise_relation in H. 130 | eauto. 131 | Qed. 132 | 133 | Lemma star_combine_lift1 : forall P Q, [| P |] * [| Q |] ===> [| P /\ Q |]. 134 | Proof. 135 | intros. 136 | apply lift_left; intro. 137 | rewrite extra_lift with (P := True); auto. 138 | apply lift_left; intro. 139 | rewrite extra_lift with (P := True) (p := [| P /\ Q |]); auto. 140 | apply lift_right. 141 | reflexivity. 142 | tauto. 143 | Qed. 144 | 145 | Lemma star_combine_lift2 : forall P Q, [| P /\ Q |] ===> [| P |] * [| Q |]. 146 | Proof. 147 | intros. 148 | rewrite extra_lift with (P := True); auto. 149 | apply lift_left; intro. 150 | apply lift_right; try tauto. 151 | rewrite extra_lift with (P := True) (p := [| P |]); auto. 152 | apply lift_right; try tauto. 153 | reflexivity. 154 | Qed. 155 | 156 | Lemma star_combine_lift : forall P Q, [| P |] * [| Q |] === [| P /\ Q |]. 157 | Proof. 158 | intros. 159 | apply himp_heq; auto using star_combine_lift1, star_combine_lift2. 160 | Qed. 161 | 162 | Lemma star_comm_lift : forall P q, [| P |] * q === q * [| P |]. 163 | Proof. 164 | intros; apply star_comm. 165 | Qed. 166 | 167 | Lemma star_assoc_lift : forall p Q r, 168 | (p * [| Q |]) * r === p * r * [| Q |]. 169 | Proof. 170 | intros. 171 | rewrite <- star_assoc. 172 | rewrite (star_comm [| Q |]). 173 | apply star_assoc. 174 | Qed. 175 | 176 | Lemma star_comm_exis : forall A (p : A -> _) q, exis p * q === q * exis p. 177 | Proof. 178 | intros; apply star_comm. 179 | Qed. 180 | 181 | Ltac lift := 182 | intros; apply himp_heq; split; 183 | repeat (apply lift_left; intro); 184 | repeat (apply lift_right; intuition). 185 | 186 | Lemma lift_combine : forall p Q R, 187 | p * [| Q |] * [| R |] === p * [| Q /\ R |]. 188 | Proof. 189 | intros; apply himp_heq; split; 190 | repeat (apply lift_left; intro); 191 | repeat (apply lift_right; intuition). 192 | Qed. 193 | 194 | Lemma lift1_left : forall (P : Prop) q, 195 | (P -> [| True |] ===> q) 196 | -> [| P |] ===> q. 197 | Proof. 198 | intros. 199 | rewrite (@extra_lift True [| P |]); auto. 200 | apply lift_left; auto. 201 | Qed. 202 | 203 | Lemma lift1_right : forall p (Q : Prop), 204 | Q 205 | -> p ===> [| True |] 206 | -> p ===> [| Q |]. 207 | Proof. 208 | intros. 209 | rewrite (@extra_lift True [| Q |]); auto. 210 | apply lift_right; auto. 211 | Qed. 212 | 213 | Ltac normalize0 := 214 | match goal with 215 | | [ |- context[star ?p (exis ?q)] ] => rewrite (exis_gulp p q) 216 | | [ |- context[star (star ?p (lift ?q)) (lift ?r)] ] => rewrite (lift_combine p q r) 217 | | [ |- context[star ?p (star ?q ?r)] ] => rewrite (star_assoc p q r) 218 | | [ |- context[star (lift ?p) (lift ?q)] ] => rewrite (star_combine_lift p q) 219 | | [ |- context[star (lift ?p) ?q ] ] => rewrite (star_comm_lift p q) 220 | | [ |- context[star (star ?p (lift ?q)) ?r] ] => rewrite (star_assoc_lift p q r) 221 | | [ |- context[star (exis ?p) ?q] ] => rewrite (star_comm_exis p q) 222 | end. 223 | 224 | Ltac normalizeL := 225 | (apply exis_left || apply lift_left; intro; try congruence) 226 | || match goal with 227 | | [ |- lift ?P ===> _ ] => 228 | match P with 229 | | True => fail 1 230 | | _ => apply lift1_left; intro; try congruence 231 | end 232 | end. 233 | 234 | Ltac normalizeR := 235 | match goal with 236 | | [ |- _ ===> exis _ ] => eapply exis_right 237 | | [ |- _ ===> _ * lift _ ] => apply lift_right 238 | | [ |- _ ===> lift ?Q ] => 239 | match Q with 240 | | True => fail 1 241 | | _ => apply lift1_right 242 | end 243 | end. 244 | 245 | Ltac normalize1 := normalize0 || normalizeL || normalizeR. 246 | 247 | Lemma lift_uncombine : forall p P Q, 248 | p * [| P /\ Q |] === p * [| P |] * [| Q |]. 249 | Proof. 250 | lift. 251 | Qed. 252 | 253 | Ltac normalize2 := 254 | match goal with 255 | | [ |- context[star ?p (lift (?P /\ ?Q))] ] => rewrite (lift_uncombine p P Q) 256 | | [ |- context[star ?p (star ?q ?r)] ] => rewrite (star_assoc p q r) 257 | end. 258 | 259 | Ltac normalizeLeft := 260 | let s := fresh "s" in intro s; 261 | let rhs := fresh "rhs" in 262 | match goal with 263 | | [ |- _ ===> ?Q ] => set (rhs := Q) 264 | end; 265 | simpl; intros; repeat (normalize0 || normalizeL); 266 | repeat match goal with 267 | | [ H : ex _ |- _ ===> _ ] => destruct H 268 | | [ H : _ /\ _ |- _ ] => destruct H 269 | | [ H : _ = _ |- _ ] => rewrite H 270 | end; subst rhs. 271 | 272 | Ltac normalize := 273 | simpl; intros; repeat normalize1; repeat normalize2; 274 | repeat (match goal with 275 | | [ H : ex _ |- _ ===> _ ] => destruct H 276 | end; intuition idtac). 277 | 278 | Ltac forAllAtoms p k := 279 | match p with 280 | | ?q * ?r => forAllAtoms q k || forAllAtoms r k 281 | | _ => k p 282 | end. 283 | 284 | Lemma stb1 : forall p q r, 285 | (q * p) * r === q * r * p. 286 | Proof. 287 | intros; rewrite <- star_assoc; rewrite (star_comm p r); apply star_assoc. 288 | Qed. 289 | 290 | Ltac sendToBack part := repeat (rewrite (stb1 part) || rewrite (star_comm part)). 291 | 292 | Theorem star_cancel' : forall p1 p2 q, p1 ===> p2 293 | -> p1 * q ===> p2 * q. 294 | Proof. 295 | intros; apply star_cancel; auto using himp_refl. 296 | Qed. 297 | 298 | Theorem star_cancel'' : forall p q, lift True ===> q 299 | -> p ===> p * q. 300 | Proof. 301 | intros. 302 | eapply himp_trans. 303 | rewrite extra_lift with (P := True); auto. 304 | instantiate (1 := p * q). 305 | rewrite star_comm. 306 | apply star_cancel; auto. 307 | reflexivity. 308 | reflexivity. 309 | Qed. 310 | 311 | Module Type TRY_ME_FIRST. 312 | Parameter try_me_first : hprop -> Prop. 313 | 314 | Axiom try_me_first_easy : forall p, try_me_first p. 315 | End TRY_ME_FIRST. 316 | 317 | Module TMF : TRY_ME_FIRST. 318 | Definition try_me_first (_ : hprop) := True. 319 | 320 | Theorem try_me_first_easy : forall p, try_me_first p. 321 | Proof. 322 | constructor. 323 | Qed. 324 | End TMF. 325 | 326 | Import TMF. 327 | Export TMF. 328 | 329 | Ltac cancel1 := 330 | match goal with 331 | | [ |- ?p ===> ?q ] => 332 | (is_var q; fail 2) 333 | || forAllAtoms p ltac:(fun p0 => 334 | (let H := fresh in assert (H : try_me_first p0) by eauto; clear H); 335 | sendToBack p0; 336 | forAllAtoms q ltac:(fun q0 => 337 | (let H := fresh in assert (H : try_me_first q0) by eauto; clear H); 338 | sendToBack q0; 339 | apply star_cancel')) 340 | end || 341 | match goal with 342 | | [ |- _ ===> ?Q ] => 343 | match Q with 344 | | _ => is_evar Q; fail 1 345 | | ?Q _ => is_evar Q; fail 1 346 | | _ => apply himp_refl 347 | end 348 | | [ |- ?p ===> ?q ] => 349 | (is_var q; fail 2) 350 | || forAllAtoms p ltac:(fun p0 => 351 | sendToBack p0; 352 | forAllAtoms q ltac:(fun q0 => 353 | sendToBack q0; 354 | apply star_cancel')) 355 | | _ => progress autorewrite with core 356 | end. 357 | 358 | Ltac hide_evars := 359 | repeat match goal with 360 | | [ |- ?P ===> _ ] => is_evar P; set P 361 | | [ |- _ ===> ?Q ] => is_evar Q; set Q 362 | | [ |- context[star ?P _] ] => is_evar P; set P 363 | | [ |- context[star _ ?Q] ] => is_evar Q; set Q 364 | | [ |- _ ===> exists v, _ * ?R v ] => is_evar R; set R 365 | end. 366 | 367 | Ltac restore_evars := 368 | repeat match goal with 369 | | [ x := _ |- _ ] => subst x 370 | end. 371 | 372 | Fixpoint flattenAnds (Ps : list Prop) : Prop := 373 | match Ps with 374 | | nil => True 375 | | [P] => P 376 | | P :: Ps => P /\ flattenAnds Ps 377 | end. 378 | 379 | Ltac allPuresFrom k := 380 | match goal with 381 | | [ H : ?P |- _ ] => 382 | match type of P with 383 | | Prop => generalize dependent H; allPuresFrom ltac:(fun Ps => k (P :: Ps)) 384 | end 385 | | _ => intros; k (@nil Prop) 386 | end. 387 | 388 | Ltac whichToQuantify skip foundAlready k := 389 | match goal with 390 | | [ x : ?T |- _ ] => 391 | match type of T with 392 | | Prop => fail 1 393 | | _ => 394 | match skip with 395 | | context[x] => fail 1 396 | | _ => 397 | match foundAlready with 398 | | context[x] => fail 1 399 | | _ => (instantiate (1 := lift (x = x)); fail 2) 400 | || (instantiate (1 := fun _ => lift (x = x)); fail 2) 401 | || (whichToQuantify skip (x, foundAlready) k) 402 | end 403 | end 404 | end 405 | | _ => k foundAlready 406 | end. 407 | 408 | Ltac quantifyOverThem vars e k := 409 | match vars with 410 | | tt => k e 411 | | (?x, ?vars') => 412 | match e with 413 | | context[x] => 414 | match eval pattern x in e with 415 | | ?f _ => quantifyOverThem vars' (exis f) k 416 | end 417 | | _ => quantifyOverThem vars' e k 418 | end 419 | end. 420 | 421 | Ltac addQuantifiers P k := 422 | whichToQuantify tt tt ltac:(fun vars => 423 | quantifyOverThem vars P k). 424 | 425 | Ltac addQuantifiersSkipping x P k := 426 | whichToQuantify x tt ltac:(fun vars => 427 | quantifyOverThem vars P k). 428 | 429 | Ltac basic_cancel := 430 | normalize; repeat cancel1; repeat match goal with 431 | | [ H : _ /\ _ |- _ ] => destruct H 432 | | [ |- _ /\ _ ] => split 433 | end; eassumption || apply I. 434 | 435 | Ltac beautify := repeat match goal with 436 | | [ H : True |- _ ] => clear H 437 | | [ H : ?P, H' : ?P |- _ ] => 438 | match type of P with 439 | | Prop => clear H' 440 | end 441 | | [ H : _ /\ _ |- _ ] => destruct H 442 | end. 443 | 444 | Ltac cancel := hide_evars; normalize; repeat cancel1; restore_evars; beautify; 445 | try match goal with 446 | | [ |- _ ===> ?p * ?q ] => 447 | ((is_evar p; fail 1) || apply star_cancel'') 448 | || ((is_evar q; fail 1) || (rewrite (star_comm p q); apply star_cancel'')) 449 | end; 450 | try match goal with 451 | | [ |- ?P ===> _ ] => sendToBack P; 452 | match goal with 453 | | [ |- ?P ===> ?Q * ?P ] => is_evar Q; 454 | rewrite (star_comm Q P); 455 | allPuresFrom ltac:(fun Ps => 456 | match Ps with 457 | | nil => instantiate (1 := lift True) 458 | | _ => 459 | let Ps' := eval simpl in (flattenAnds Ps) in 460 | addQuantifiers (lift Ps') ltac:(fun e => instantiate (1 := e)) 461 | end; 462 | basic_cancel) 463 | end 464 | | [ |- ?P ===> ?Q ] => is_evar Q; 465 | allPuresFrom ltac:(fun Ps => 466 | match Ps with 467 | | nil => reflexivity 468 | | _ => 469 | let Ps' := eval simpl in (flattenAnds Ps) in 470 | addQuantifiers (star P (lift Ps')) ltac:(fun e => instantiate (1 := e)); 471 | basic_cancel 472 | end) 473 | | [ |- ?P ===> ?Q ?x ] => is_evar Q; 474 | allPuresFrom ltac:(fun Ps => 475 | match Ps with 476 | | nil => reflexivity 477 | | _ => 478 | let Ps' := eval simpl in (flattenAnds Ps) in 479 | addQuantifiersSkipping x (star P (lift Ps')) 480 | ltac:(fun e => match eval pattern x in e with 481 | | ?f _ => instantiate (1 := f) 482 | end); 483 | basic_cancel 484 | end) 485 | | [ |- _ ===> _ ] => intuition (try congruence) 486 | end; intuition idtac; beautify. 487 | End Make. 488 | -------------------------------------------------------------------------------- /SubsetTypes_template.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * Supplementary Coq material: subset types 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ 5 | * Much of the material comes from CPDT by the same author. *) 6 | 7 | Require Import FrapWithoutSets. 8 | (* We import a pared-down version of the book library, to avoid notations that 9 | * clash with some we want to use here. *) 10 | 11 | Set Implicit Arguments. 12 | Set Asymmetric Patterns. 13 | 14 | 15 | (** * Introducing Subset Types *) 16 | 17 | Definition pred (n : nat) : nat := 18 | match n with 19 | | O => O 20 | | S n' => n' 21 | end. 22 | 23 | Extraction pred. 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | (** * Decidable Proposition Types *) 39 | 40 | Print sumbool. 41 | 42 | Notation "'Yes'" := (left _ _). 43 | Notation "'No'" := (right _ _). 44 | Notation "'Reduce' x" := (if x then Yes else No) (at level 50). 45 | 46 | Definition eq_nat_dec : forall n m : nat, {n = m} + {n <> m}. 47 | Admitted. 48 | 49 | Compute eq_nat_dec 2 2. 50 | Compute eq_nat_dec 2 3. 51 | 52 | Extraction eq_nat_dec. 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Section In_dec. 63 | Variable A : Set. 64 | Variable A_eq_dec : forall x y : A, {x = y} + {x <> y}. 65 | 66 | (* The final function is easy to write using the techniques we have developed 67 | * so far. *) 68 | 69 | Definition In_dec : forall (x : A) (ls : list A), {In x ls} + {~ In x ls}. 70 | Admitted. 71 | End In_dec. 72 | 73 | Compute In_dec eq_nat_dec 2 (1 :: 2 :: nil). 74 | Compute In_dec eq_nat_dec 3 (1 :: 2 :: nil). 75 | 76 | Extraction In_dec. 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | (** * Partial Subset Types *) 91 | 92 | Inductive maybe (A : Set) (P : A -> Prop) : Set := 93 | | Unknown : maybe P 94 | | Found : forall x : A, P x -> maybe P. 95 | 96 | Notation "{{ x | P }}" := (maybe (fun x => P)). 97 | Notation "??" := (Unknown _). 98 | Notation "[| x |]" := (Found _ x _). 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Print sumor. 111 | 112 | Notation "!!" := (inright _ _). 113 | Notation "[|| x ||]" := (inleft _ [x]). 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | (** * Monadic Notations *) 125 | 126 | Notation "x <- e1 ; e2" := (match e1 with 127 | | Unknown => ?? 128 | | Found x _ => e2 129 | end) 130 | (right associativity, at level 60). 131 | 132 | Definition doublePred : forall n1 n2 : nat, {{p | n1 = S (fst p) /\ n2 = S (snd p)}}. 133 | Admitted. 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | Notation "x <-- e1 ; e2" := (match e1 with 148 | | inright _ => !! 149 | | inleft (exist x _) => e2 150 | end) 151 | (right associativity, at level 60). 152 | 153 | Definition doublePred' : forall n1 n2 : nat, 154 | {p : nat * nat | n1 = S (fst p) /\ n2 = S (snd p)}. 155 | Admitted. 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | (** * A Type-Checking Example *) 173 | 174 | Inductive exp := 175 | | Nat (n : nat) 176 | | Plus (e1 e2 : exp) 177 | | Bool (b : bool) 178 | | And (e1 e2 : exp). 179 | 180 | Inductive type := TNat | TBool. 181 | 182 | Inductive hasType : exp -> type -> Prop := 183 | | HtNat : forall n, 184 | hasType (Nat n) TNat 185 | | HtPlus : forall e1 e2, 186 | hasType e1 TNat 187 | -> hasType e2 TNat 188 | -> hasType (Plus e1 e2) TNat 189 | | HtBool : forall b, 190 | hasType (Bool b) TBool 191 | | HtAnd : forall e1 e2, 192 | hasType e1 TBool 193 | -> hasType e2 TBool 194 | -> hasType (And e1 e2) TBool. 195 | 196 | Definition typeCheck : forall e : exp, {{t | hasType e t}}. 197 | Admitted. 198 | 199 | Compute typeCheck (Nat 0). 200 | Compute typeCheck (Plus (Nat 1) (Nat 2)). 201 | Compute typeCheck (Plus (Nat 1) (Bool false)). 202 | 203 | Extraction typeCheck. 204 | -------------------------------------------------------------------------------- /TransitionSystems_template.v: -------------------------------------------------------------------------------- 1 | (** Formal Reasoning About Programs 2 | * Chapter 6: Transition Systems 3 | * Author: Adam Chlipala 4 | * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *) 5 | 6 | Require Import Frap. 7 | 8 | Set Implicit Arguments. 9 | (* This command will treat type arguments to functions as implicit, like in 10 | * Haskell or ML. *) 11 | 12 | 13 | (* Here's a classic recursive, functional program for factorial. *) 14 | Fixpoint fact (n : nat) : nat := 15 | match n with 16 | | O => 1 17 | | S n' => fact n' * S n' 18 | end. 19 | 20 | (* But let's reformulate factorial relationally, as an example to explore 21 | * treatment of inductive relations in Coq. First, these are the states of our 22 | * state machine. *) 23 | Inductive fact_state := 24 | | AnswerIs (answer : nat) 25 | | WithAccumulator (input accumulator : nat). 26 | 27 | (* *Initial* states *) 28 | Inductive fact_init (original_input : nat) : fact_state -> Prop := 29 | | FactInit : fact_init original_input (WithAccumulator original_input 1). 30 | 31 | (** *Final* states *) 32 | Inductive fact_final : fact_state -> Prop := 33 | | FactFinal : forall ans, fact_final (AnswerIs ans). 34 | 35 | (** The most important part: the relation to step between states *) 36 | Inductive fact_step : fact_state -> fact_state -> Prop := 37 | | FactDone : forall acc, 38 | fact_step (WithAccumulator O acc) (AnswerIs acc) 39 | | FactStep : forall n acc, 40 | fact_step (WithAccumulator (S n) acc) (WithAccumulator n (acc * S n)). 41 | 42 | (* We care about more than just single steps. We want to run factorial to 43 | * completion, for which it is handy to define a general relation of 44 | * *transitive-reflexive closure*, like so. *) 45 | Inductive trc {A} (R : A -> A -> Prop) : A -> A -> Prop := 46 | | TrcRefl : forall x, trc R x x 47 | | TrcFront : forall x y z, 48 | R x y 49 | -> trc R y z 50 | -> trc R x z. 51 | 52 | (* Transitive-reflexive closure is so common that it deserves a shorthand notation! *) 53 | Set Warnings "-notation-overridden". (* <-- needed while we play with defining one 54 | * of the book's notations ourselves locally *) 55 | Notation "R ^*" := (trc R) (at level 0). 56 | 57 | (* Now let's use it to execute the factorial program. *) 58 | Example factorial_3 : fact_step^* (WithAccumulator 3 1) (AnswerIs 6). 59 | Proof. 60 | Admitted. 61 | 62 | (* It will be useful to give state machines more first-class status, as 63 | * *transition systems*, formalized by this record type. It has one type 64 | * parameter, [state], which records the type of states. *) 65 | Record trsys state := { 66 | Initial : state -> Prop; 67 | Step : state -> state -> Prop 68 | }. 69 | 70 | (* The example of our factorial program: *) 71 | Definition factorial_sys (original_input : nat) : trsys fact_state := {| 72 | Initial := fact_init original_input; 73 | Step := fact_step 74 | |}. 75 | 76 | (* A useful general notion for transition systems: reachable states *) 77 | Inductive reachable {state} (sys : trsys state) (st : state) : Prop := 78 | | Reachable : forall st0, 79 | sys.(Initial) st0 80 | -> sys.(Step)^* st0 st 81 | -> reachable sys st. 82 | 83 | (* To prove that our state machine is correct, we rely on the crucial technique 84 | * of *invariants*. What is an invariant? Here's a general definition, in 85 | * terms of an arbitrary transition system. *) 86 | Definition invariantFor {state} (sys : trsys state) (invariant : state -> Prop) := 87 | forall s, sys.(Initial) s 88 | -> forall s', sys.(Step)^* s s' 89 | -> invariant s'. 90 | (* That is, when we begin in an initial state and take any number of steps, the 91 | * place we wind up always satisfies the invariant. *) 92 | 93 | (* Here's a simple lemma to help us apply an invariant usefully, 94 | * really just restating the definition. *) 95 | Lemma use_invariant' : forall {state} (sys : trsys state) 96 | (invariant : state -> Prop) s s', 97 | invariantFor sys invariant 98 | -> sys.(Initial) s 99 | -> sys.(Step)^* s s' 100 | -> invariant s'. 101 | Proof. 102 | unfold invariantFor. 103 | simplify. 104 | eapply H. 105 | eassumption. 106 | assumption. 107 | Qed. 108 | 109 | Theorem use_invariant : forall {state} (sys : trsys state) 110 | (invariant : state -> Prop) s, 111 | invariantFor sys invariant 112 | -> reachable sys s 113 | -> invariant s. 114 | Proof. 115 | simplify. 116 | invert H0. 117 | eapply use_invariant'. 118 | eassumption. 119 | eassumption. 120 | assumption. 121 | Qed. 122 | 123 | (* What's the most fundamental way to establish an invariant? Induction! *) 124 | Lemma invariant_induction' : forall {state} (sys : trsys state) 125 | (invariant : state -> Prop), 126 | (forall s, invariant s -> forall s', sys.(Step) s s' -> invariant s') 127 | -> forall s s', sys.(Step)^* s s' 128 | -> invariant s 129 | -> invariant s'. 130 | Proof. 131 | induct 2; propositional. 132 | (* [propositional]: simplify the goal according to the rules of propositional 133 | * logic. *) 134 | 135 | apply IHtrc. 136 | eapply H. 137 | eassumption. 138 | assumption. 139 | Qed. 140 | 141 | Theorem invariant_induction : forall {state} (sys : trsys state) 142 | (invariant : state -> Prop), 143 | (forall s, sys.(Initial) s -> invariant s) 144 | -> (forall s, invariant s -> forall s', sys.(Step) s s' -> invariant s') 145 | -> invariantFor sys invariant. 146 | Proof. 147 | unfold invariantFor; intros. 148 | eapply invariant_induction'. 149 | eassumption. 150 | eassumption. 151 | apply H. 152 | assumption. 153 | Qed. 154 | 155 | Definition fact_invariant (original_input : nat) (st : fact_state) : Prop := 156 | True. 157 | (* We must fill in a better invariant. *) 158 | 159 | Theorem fact_invariant_ok : forall original_input, 160 | invariantFor (factorial_sys original_input) (fact_invariant original_input). 161 | Proof. 162 | Admitted. 163 | 164 | (* Therefore, every reachable state satisfies this invariant. *) 165 | Theorem fact_invariant_always : forall original_input s, 166 | reachable (factorial_sys original_input) s 167 | -> fact_invariant original_input s. 168 | Proof. 169 | simplify. 170 | eapply use_invariant. 171 | apply fact_invariant_ok. 172 | assumption. 173 | Qed. 174 | 175 | (* Therefore, any final state has the right answer! *) 176 | Lemma fact_ok' : forall original_input s, 177 | fact_final s 178 | -> fact_invariant original_input s 179 | -> s = AnswerIs (fact original_input). 180 | Admitted. 181 | 182 | Theorem fact_ok : forall original_input s, 183 | reachable (factorial_sys original_input) s 184 | -> fact_final s 185 | -> s = AnswerIs (fact original_input). 186 | Proof. 187 | simplify. 188 | apply fact_ok'. 189 | assumption. 190 | apply fact_invariant_always. 191 | assumption. 192 | Qed. 193 | 194 | 195 | (** * A simple example of another program as a state transition system *) 196 | 197 | (* We'll formalize this pseudocode for one thread of a concurrent, shared-memory program. 198 | lock(); 199 | local = global; 200 | global = local + 1; 201 | unlock(); 202 | *) 203 | 204 | (* This inductive state effectively encodes all possible combinations of two 205 | * kinds of *local*state* in a thread: 206 | * - program counter 207 | * - values of local variables that may be read eventually *) 208 | Inductive increment_program := 209 | | Lock 210 | | Read 211 | | Write (local : nat) 212 | | Unlock 213 | | Done. 214 | 215 | (* Next, a type for state shared between threads. *) 216 | Record inc_state := { 217 | Locked : bool; (* Does a thread hold the lock? *) 218 | Global : nat (* A shared counter *) 219 | }. 220 | 221 | (* The combined state, from one thread's perspective, using a general 222 | * definition. *) 223 | Record threaded_state shared private := { 224 | Shared : shared; 225 | Private : private 226 | }. 227 | 228 | Definition increment_state := threaded_state inc_state increment_program. 229 | 230 | (* Now a routine definition of the three key relations of a transition system. 231 | * The most interesting logic surrounds saving the counter value in the local 232 | * state after reading. *) 233 | 234 | Inductive increment_init : increment_state -> Prop := 235 | | IncInit : 236 | increment_init {| Shared := {| Locked := false; Global := O |}; 237 | Private := Lock |}. 238 | 239 | Inductive increment_step : increment_state -> increment_state -> Prop := 240 | | IncLock : forall g, 241 | increment_step {| Shared := {| Locked := false; Global := g |}; 242 | Private := Lock |} 243 | {| Shared := {| Locked := true; Global := g |}; 244 | Private := Read |} 245 | | IncRead : forall l g, 246 | increment_step {| Shared := {| Locked := l; Global := g |}; 247 | Private := Read |} 248 | {| Shared := {| Locked := l; Global := g |}; 249 | Private := Write g |} 250 | | IncWrite : forall l g v, 251 | increment_step {| Shared := {| Locked := l; Global := g |}; 252 | Private := Write v |} 253 | {| Shared := {| Locked := l; Global := S v |}; 254 | Private := Unlock |} 255 | | IncUnlock : forall l g, 256 | increment_step {| Shared := {| Locked := l; Global := g |}; 257 | Private := Unlock |} 258 | {| Shared := {| Locked := false; Global := g |}; 259 | Private := Done |}. 260 | 261 | Definition increment_sys := {| 262 | Initial := increment_init; 263 | Step := increment_step 264 | |}. 265 | 266 | 267 | (** * Running transition systems in parallel *) 268 | 269 | (* That last example system is a cop-out: it only runs a single thread. We want 270 | * to run several threads in parallel, sharing the global state. Here's how we 271 | * can do it for just two threads. The key idea is that, while in the new 272 | * system the type of shared state remains the same, we take the Cartesian 273 | * product of the sets of private state. *) 274 | 275 | Inductive parallel_init shared private1 private2 276 | (init1 : threaded_state shared private1 -> Prop) 277 | (init2 : threaded_state shared private2 -> Prop) 278 | : threaded_state shared (private1 * private2) -> Prop := 279 | | Pinit : forall sh pr1 pr2, 280 | init1 {| Shared := sh; Private := pr1 |} 281 | -> init2 {| Shared := sh; Private := pr2 |} 282 | -> parallel_init init1 init2 {| Shared := sh; Private := (pr1, pr2) |}. 283 | 284 | Inductive parallel_step shared private1 private2 285 | (step1 : threaded_state shared private1 -> threaded_state shared private1 -> Prop) 286 | (step2 : threaded_state shared private2 -> threaded_state shared private2 -> Prop) 287 | : threaded_state shared (private1 * private2) 288 | -> threaded_state shared (private1 * private2) -> Prop := 289 | | Pstep1 : forall sh pr1 pr2 sh' pr1', 290 | (* First thread gets to run. *) 291 | step1 {| Shared := sh; Private := pr1 |} {| Shared := sh'; Private := pr1' |} 292 | -> parallel_step step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 293 | {| Shared := sh'; Private := (pr1', pr2) |} 294 | | Pstep2 : forall sh pr1 pr2 sh' pr2', 295 | (* Second thread gets to run. *) 296 | step2 {| Shared := sh; Private := pr2 |} {| Shared := sh'; Private := pr2' |} 297 | -> parallel_step step1 step2 {| Shared := sh; Private := (pr1, pr2) |} 298 | {| Shared := sh'; Private := (pr1, pr2') |}. 299 | 300 | Definition parallel shared private1 private2 301 | (sys1 : trsys (threaded_state shared private1)) 302 | (sys2 : trsys (threaded_state shared private2)) := {| 303 | Initial := parallel_init sys1.(Initial) sys2.(Initial); 304 | Step := parallel_step sys1.(Step) sys2.(Step) 305 | |}. 306 | 307 | (* Example: composing two threads of the kind we formalized earlier *) 308 | Definition increment2_sys := parallel increment_sys increment_sys. 309 | 310 | (* Let's prove that the counter is always 2 when the composed program terminates. *) 311 | 312 | (** We must write an invariant. *) 313 | Inductive increment2_invariant : 314 | threaded_state inc_state (increment_program * increment_program) -> Prop := 315 | | Inc2Inv : forall sh pr1 pr2, 316 | increment2_invariant {| Shared := sh; Private := (pr1, pr2) |}. 317 | (* This isn't it yet! *) 318 | 319 | (* Now, to show it really is an invariant. *) 320 | Theorem increment2_invariant_ok : invariantFor increment2_sys increment2_invariant. 321 | Proof. 322 | Admitted. 323 | 324 | (* Now, to prove our final result about the two incrementing threads, let's use 325 | * a more general fact, about when one invariant implies another. *) 326 | Theorem invariant_weaken : forall {state} (sys : trsys state) 327 | (invariant1 invariant2 : state -> Prop), 328 | invariantFor sys invariant1 329 | -> (forall s, invariant1 s -> invariant2 s) 330 | -> invariantFor sys invariant2. 331 | Proof. 332 | unfold invariantFor; simplify. 333 | apply H0. 334 | eapply H. 335 | eassumption. 336 | assumption. 337 | Qed. 338 | 339 | (* Here's another, much weaker invariant, corresponding exactly to the overall 340 | * correctness property we want to establish for this system. *) 341 | Definition increment2_right_answer 342 | (s : threaded_state inc_state (increment_program * increment_program)) := 343 | s.(Private) = (Done, Done) 344 | -> s.(Shared).(Global) = 2. 345 | 346 | (** Now we can prove that the system only runs to happy states. *) 347 | Theorem increment2_sys_correct : forall s, 348 | reachable increment2_sys s 349 | -> increment2_right_answer s. 350 | Proof. 351 | Admitted. 352 | (*simplify. 353 | eapply use_invariant. 354 | apply invariant_weaken with (invariant1 := increment2_invariant). 355 | (* Note the use of a [with] clause to specify a quantified variable's 356 | * value. *) 357 | 358 | apply increment2_invariant_ok. 359 | 360 | simplify. 361 | invert H0. 362 | unfold increment2_right_answer; simplify. 363 | invert H0. 364 | (* Here we use inversion on an equality, to derive more primitive 365 | * equalities. *) 366 | simplify. 367 | equality. 368 | 369 | assumption. 370 | Qed.*) 371 | -------------------------------------------------------------------------------- /Var.v: -------------------------------------------------------------------------------- 1 | Require Import String. 2 | 3 | 4 | Notation var := string. 5 | Definition var_eq : forall x y : var, {x = y} + {x <> y} := string_dec. 6 | 7 | Infix "==v" := var_eq (no associativity, at level 50). 8 | -------------------------------------------------------------------------------- /_CoqProject: -------------------------------------------------------------------------------- 1 | -R . Frap 2 | -arg -w -arg -undeclared-scope 3 | Map.v 4 | Var.v 5 | Sets.v 6 | Relations.v 7 | Invariant.v 8 | ModelCheck.v 9 | Imp.v 10 | AbstractInterpret.v 11 | FrapWithoutSets.v 12 | Frap.v 13 | BasicSyntax_template.v 14 | BasicSyntax.v 15 | Polymorphism_template.v 16 | Polymorphism.v 17 | DataAbstraction_template.v 18 | DataAbstraction.v 19 | Interpreters_template.v 20 | Interpreters.v 21 | FirstClassFunctions_template.v 22 | FirstClassFunctions.v 23 | RuleInduction_template.v 24 | RuleInduction.v 25 | TransitionSystems_template.v 26 | TransitionSystems.v 27 | IntroToProofScripting_template.v 28 | IntroToProofScripting.v 29 | ModelChecking_template.v 30 | ModelChecking.v 31 | ProofByReflection_template.v 32 | ProofByReflection.v 33 | OperationalSemantics_template.v 34 | OperationalSemantics.v 35 | LogicProgramming_template.v 36 | LogicProgramming.v 37 | AbstractInterpretation.v 38 | CompilerCorrectness_template.v 39 | CompilerCorrectness.v 40 | SubsetTypes_template.v 41 | SubsetTypes.v 42 | LambdaCalculusAndTypeSoundness_template.v 43 | LambdaCalculusAndTypeSoundness.v 44 | EvaluationContexts_template.v 45 | EvaluationContexts.v 46 | DependentInductiveTypes_template.v 47 | DependentInductiveTypes.v 48 | TypesAndMutation.v 49 | HoareLogic_template.v 50 | HoareLogic.v 51 | DeepAndShallowEmbeddings_template.v 52 | DeepAndShallowEmbeddings.v 53 | SepCancel.v 54 | SeparationLogic_template.v 55 | SeparationLogic.v 56 | Connecting.v 57 | ProgramDerivation_template.v 58 | ProgramDerivation.v 59 | SharedMemory.v 60 | ConcurrentSeparationLogic_template.v 61 | ConcurrentSeparationLogic.v 62 | MessagesAndRefinement.v 63 | SessionTypes.v 64 | -------------------------------------------------------------------------------- /_CoqProject.fraplib: -------------------------------------------------------------------------------- 1 | -R . Frap 2 | -arg -w -arg -undeclared-scope 3 | Map.v 4 | Var.v 5 | Sets.v 6 | Relations.v 7 | Invariant.v 8 | ModelCheck.v 9 | Imp.v 10 | AbstractInterpret.v 11 | FrapWithoutSets.v 12 | Frap.v 13 | SepCancel.v 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Formal Reasoning About Programs 5 | 6 |

Formal Reasoning About Programs

7 |

Adam Chlipala

8 | 9 |
10 | 11 |

This is the web site for the early stages of a book introducing both machine-checked proof with the Coq proof assistant and approaches to formal reasoning about program correctness.

12 | 13 |

Grab a Draft

14 | 20 |
21 | 22 |
23 |

Use in classes

24 | 25 |

Classes where FRAP is/was a primary text

26 | 40 | 41 |
42 | 43 | 44 | --------------------------------------------------------------------------------