├── .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 |
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 |
27 | 6.822 at MIT (Spring 2022 , Spring 2021, Spring 2020, Spring 2018, Spring 2017 [as 6.887], Spring 2016 [as 6.887])
28 |
36 | EECS 755 at U. Kansas (Spring 2020 )
37 | CS6225 at IIT Madras (Spring 2020 )
38 | CSE 505 at U. Washington (Fall 2018 )
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------