2 (** {1 A certified WP calculus} *)
4 (** {2 A simple imperative language, syntax and semantics} *)
8 (** terms and formulas *)
10 type datatype = Tint | Tbool
12 type operator = Oplus | Ominus | Omult | Ole
20 | Tbin term operator term
27 | Flet ident term fmla
28 | Fforall ident datatype fmla
38 type env = IdMap.map ident value
40 (** semantics of formulas *)
42 function eval_bin (x:value) (op:operator) (y:value) : value =
47 | Ominus -> Vint (x-y)
49 | Ole -> Vbool (if x <= y then True else False)
54 function get_env (i:ident) (e:env) : value = IdMap.get e i
56 function eval_term (sigma:env) (pi:env) (t:term) : value =
59 | Tvar id -> get_env id pi
60 | Tderef id -> get_env id sigma
62 eval_bin (eval_term sigma pi t1) op (eval_term sigma pi t2)
65 predicate eval_fmla (sigma:env) (pi:env) (f:fmla) =
67 | Fterm t -> eval_term sigma pi t = Vbool True
68 | Fand f1 f2 -> eval_fmla sigma pi f1 /\ eval_fmla sigma pi f2
69 | Fnot f -> not (eval_fmla sigma pi f)
70 | Fimplies f1 f2 -> eval_fmla sigma pi f1 -> eval_fmla sigma pi f2
72 eval_fmla sigma (IdMap.set pi x (eval_term sigma pi t)) f
74 forall n:int. eval_fmla sigma (IdMap.set pi x (Vint n)) f
75 | Fforall x Tbool f ->
77 eval_fmla sigma (IdMap.set pi x (Vbool b)) f
80 (** substitution of a reference `r` by a logic variable `v`
81 warning: proper behavior only guaranted if `v` is fresh *)
83 let rec function subst_term (e:term) (r:ident) (v:ident) : term =
87 | Tderef x -> if r=x then Tvar v else e
88 | Tbin e1 op e2 -> Tbin (subst_term e1 r v) op (subst_term e2 r v)
91 predicate fresh_in_term (id:ident) (t:term) =
96 | Tbin t1 _ t2 -> fresh_in_term id t1 /\ fresh_in_term id t2
99 lemma eval_subst_term:
100 forall sigma pi:env, e:term, x:ident, v:ident.
102 eval_term sigma pi (subst_term e x v) =
103 eval_term (IdMap.set sigma x (IdMap.get pi v)) pi e
105 lemma eval_term_change_free :
106 forall t:term, sigma pi:env, id:ident, v:value.
107 fresh_in_term id t ->
108 eval_term sigma (IdMap.set pi id v) t = eval_term sigma pi t
110 predicate fresh_in_fmla (id:ident) (f:fmla) =
112 | Fterm e -> fresh_in_term id e
113 | Fand f1 f2 | Fimplies f1 f2 ->
114 fresh_in_fmla id f1 /\ fresh_in_fmla id f2
115 | Fnot f -> fresh_in_fmla id f
116 | Flet y t f -> id <> y /\ fresh_in_term id t /\ fresh_in_fmla id f
117 | Fforall y _ f -> id <> y /\ fresh_in_fmla id f
120 let rec function subst (f:fmla) (x:ident) (v:ident) : fmla =
122 | Fterm e -> Fterm (subst_term e x v)
123 | Fand f1 f2 -> Fand (subst f1 x v) (subst f2 x v)
124 | Fnot f -> Fnot (subst f x v)
125 | Fimplies f1 f2 -> Fimplies (subst f1 x v) (subst f2 x v)
126 | Flet y t f -> Flet y (subst_term t x v) (subst f x v)
127 | Fforall y ty f -> Fforall y ty (subst f x v)
132 forall f:fmla, sigma pi:env, x:ident, v:ident.
134 (eval_fmla sigma pi (subst f x v) <->
135 eval_fmla (IdMap.set sigma x (IdMap.get pi v)) pi f)
138 forall f:fmla, sigma pi:env, id1 id2:ident, v1 v2:value.
140 (eval_fmla sigma (IdMap.set (IdMap.set pi id1 v1) id2 v2) f <->
141 eval_fmla sigma (IdMap.set (IdMap.set pi id2 v2) id1 v1) f)
143 lemma eval_change_free :
144 forall f:fmla, sigma pi:env, id:ident, v:value.
145 fresh_in_fmla id f ->
146 (eval_fmla sigma (IdMap.set pi id v) f <-> eval_fmla sigma pi f)
156 | Swhile term fmla stmt
159 forall s:stmt. s=Sskip \/s<>Sskip
161 (** small-steps semantics for statements *)
163 inductive one_step env env stmt env env stmt =
166 forall sigma pi:env, x:ident, e:term.
167 one_step sigma pi (Sassign x e)
168 (IdMap.set sigma x (eval_term sigma pi e)) pi
172 forall sigma pi sigma' pi':env, i1 i1' i2:stmt.
173 one_step sigma pi i1 sigma' pi' i1' ->
174 one_step sigma pi (Sseq i1 i2) sigma' pi' (Sseq i1' i2)
177 forall sigma pi:env, i:stmt.
178 one_step sigma pi (Sseq Sskip i) sigma pi i
181 forall sigma pi:env, e:term, i1 i2:stmt.
182 eval_term sigma pi e = (Vbool True) ->
183 one_step sigma pi (Sif e i1 i2) sigma pi i1
186 forall sigma pi:env, e:term, i1 i2:stmt.
187 eval_term sigma pi e = (Vbool False) ->
188 one_step sigma pi (Sif e i1 i2) sigma pi i2
191 forall sigma pi:env, f:fmla.
192 eval_fmla sigma pi f ->
193 one_step sigma pi (Sassert f) sigma pi Sskip
195 | one_step_while_true:
196 forall sigma pi:env, e:term, inv:fmla, i:stmt.
197 eval_fmla sigma pi inv ->
198 eval_term sigma pi e = (Vbool True) ->
199 one_step sigma pi (Swhile e inv i) sigma pi (Sseq i (Swhile e inv i))
201 | one_step_while_false:
202 forall sigma pi:env, e:term, inv:fmla, i:stmt.
203 eval_fmla sigma pi inv ->
204 eval_term sigma pi e = (Vbool False) ->
205 one_step sigma pi (Swhile e inv i) sigma pi Sskip
210 forall s:state, i:stmt.
212 exists s':state, i':stmt. one_step s i s' i'
216 (** many steps of execution *)
218 inductive many_steps env env stmt env env stmt int =
220 forall sigma pi:env, i:stmt. many_steps sigma pi i sigma pi i 0
222 forall sigma1 pi1 sigma2 pi2 sigma3 pi3:env, i1 i2 i3:stmt, n:int.
223 one_step sigma1 pi1 i1 sigma2 pi2 i2 ->
224 many_steps sigma2 pi2 i2 sigma3 pi3 i3 n ->
225 many_steps sigma1 pi1 i1 sigma3 pi3 i3 (n+1)
228 forall sigma1 pi1 sigma2 pi2:env, i1 i2:stmt, n:int.
229 many_steps sigma1 pi1 i1 sigma2 pi2 i2 n -> n >= 0
231 lemma many_steps_seq:
232 forall sigma1 pi1 sigma3 pi3:env, i1 i2:stmt, n:int.
233 many_steps sigma1 pi1 (Sseq i1 i2) sigma3 pi3 Sskip n ->
234 exists sigma2 pi2:env, n1 n2:int.
235 many_steps sigma1 pi1 i1 sigma2 pi2 Sskip n1 /\
236 many_steps sigma2 pi2 i2 sigma3 pi3 Sskip n2 /\
241 predicate valid_fmla (p:fmla) = forall sigma pi:env. eval_fmla sigma pi p
243 (** {3 Hoare triples} *)
245 (** partial correctness *)
246 predicate valid_triple (p:fmla) (i:stmt) (q:fmla) =
247 forall sigma pi:env. eval_fmla sigma pi p ->
248 forall sigma' pi':env, n:int. many_steps sigma pi i sigma' pi' Sskip n ->
249 eval_fmla sigma' pi' q
251 (*** total correctness *)
253 predicate total_valid_triple (p:fmla) (i:stmt) (q:fmla) =
254 forall s:state. eval_fmla s p ->
255 exists s':state, n:int. many_steps s i s' Sskip n /\
267 function my_sigma : env = Const.const (Vint 0)
268 function my_pi : env = Const.const (Vint 42)
271 eval_term my_sigma my_pi (Tconst 13) = Vint 13
274 eval_term my_sigma my_pi (Tvar 0) = Vint 42
277 eval_term my_sigma my_pi (Tderef 0) = Vint 0
280 eval_term my_sigma my_pi (Tbin (Tvar 0) Oplus (Tconst 13)) = Vint 55
284 forall sigma' pi':env.
285 one_step my_sigma my_pi (Sassign x (Tconst 42)) sigma' pi' Sskip ->
286 IdMap.get sigma' x = Vint 42
290 forall sigma1 pi1 sigma2 pi2:env, i:stmt.
291 one_step my_sigma my_pi
292 (Sif (Tbin (Tderef x) Ole (Tconst 10))
293 (Sassign x (Tconst 13))
294 (Sassign x (Tconst 42)))
296 one_step sigma1 pi1 i sigma2 pi2 Sskip ->
297 IdMap.get sigma2 x = Vint 13
301 (** {2 Hoare logic} *)
308 (** Hoare logic rules (partial correctness) *)
310 lemma consequence_rule:
311 forall p p' q q':fmla, i:stmt.
312 valid_fmla (Fimplies p' p) ->
313 valid_triple p i q ->
314 valid_fmla (Fimplies q q') ->
318 forall q:fmla. valid_triple q Sskip q
321 forall q:fmla, x id:ident, e:term.
322 fresh_in_fmla id q ->
323 valid_triple (Flet id e (subst q x id)) (Sassign x e) q
326 forall p q r:fmla, i1 i2:stmt.
327 valid_triple p i1 r /\ valid_triple r i2 q ->
328 valid_triple p (Sseq i1 i2) q
331 forall e:term, p q:fmla, i1 i2:stmt.
332 valid_triple (Fand p (Fterm e)) i1 q /\
333 valid_triple (Fand p (Fnot (Fterm e))) i2 q ->
334 valid_triple p (Sif e i1 i2) q
337 forall f p:fmla. valid_fmla (Fimplies p f) ->
338 valid_triple p (Sassert f) p
340 lemma assert_rule_ext:
342 valid_triple (Fimplies f p) (Sassert f) p
345 forall e:term, inv:fmla, i:stmt.
346 valid_triple (Fand (Fterm e) inv) i inv ->
347 valid_triple inv (Swhile e inv i) (Fand (Fnot (Fterm e)) inv)
349 lemma while_rule_ext:
350 forall e:term, inv inv':fmla, i:stmt.
351 valid_fmla (Fimplies inv' inv) ->
352 valid_triple (Fand (Fterm e) inv') i inv' ->
353 valid_triple inv' (Swhile e inv i) (Fand (Fnot (Fterm e)) inv')
359 (** {2 WP calculus} *)
366 clone set.SetApp as S with type elt = ident, val eq = Int.(=)
368 predicate assigns (sigma:env) (a:Set.fset ident) (sigma':env) =
369 forall i:ident. not (Set.mem i a) ->
370 IdMap.get sigma i = IdMap.get sigma' i
373 forall sigma:env, a:Set.fset ident. assigns sigma a sigma
376 forall sigma1 sigma2 sigma3:env, a:Set.fset ident.
377 assigns sigma1 a sigma2 /\ assigns sigma2 a sigma3 ->
378 assigns sigma1 a sigma3
380 lemma assigns_union_left:
381 forall sigma sigma':env, s1 s2:Set.fset ident.
382 assigns sigma s1 sigma' -> assigns sigma (Set.union s1 s2) sigma'
384 lemma assigns_union_right:
385 forall sigma sigma':env, s1 s2:Set.fset ident.
386 assigns sigma s2 sigma' -> assigns sigma (Set.union s1 s2) sigma'
389 predicate stmt_writes (i:stmt) (w:Set.fset ident) =
391 | Sskip | Sassert _ -> true
392 | Sassign id _ -> Set.mem id w
393 | Sseq s1 s2 | Sif _ s1 s2 -> stmt_writes s1 w /\ stmt_writes s2 w
394 | Swhile _ _ s -> stmt_writes s w
398 let rec compute_writes (s:stmt) : S.set
400 forall sigma pi sigma' pi':env, n:int.
401 many_steps sigma pi s sigma' pi' Sskip n ->
402 assigns sigma result sigma' }
405 | Sskip -> S.empty ()
406 | Sassign i _ -> S.singleton i
407 | Sseq s1 s2 -> S.union (compute_writes s1) (compute_writes s2)
408 | Sif _ s1 s2 -> S.union (compute_writes s1) (compute_writes s2)
409 | Swhile _ _ s -> compute_writes s
410 | Sassert _ -> S.empty ()
413 val fresh_from_fmla (q:fmla) : ident
414 ensures { fresh_in_fmla result q }
416 val abstract_effects (i:stmt) (f:fmla) : fmla
417 ensures { forall sigma pi:env. eval_fmla sigma pi result ->
418 eval_fmla sigma pi f /\
420 forall sigma':env, w:Set.set ident.
421 stmt_writes i w /\ assigns sigma w sigma' ->
422 eval_fmla sigma' pi result
424 forall sigma' pi':env, n:int.
425 many_steps sigma pi i sigma' pi' Sskip n ->
426 eval_fmla sigma' pi' result
431 let rec wp (i:stmt) (q:fmla)
432 ensures { valid_triple result i q }
436 | Sseq i1 i2 -> wp i1 (wp i2 q)
438 let id = fresh_from_fmla q in Flet id e (subst q x id)
440 Fand (Fimplies (Fterm e) (wp i1 q))
441 (Fimplies (Fnot (Fterm e)) (wp i2 q))
443 Fimplies f q (* liberal wp, no termination required *)
444 (* Fand f q *) (* strict wp, termination required *)
449 (Fimplies (Fand (Fterm e) inv) (wp i inv))
450 (Fimplies (Fand (Fnot (Fterm e)) inv) q)))
461 compile-command: "why3ide wp2.mlw"