4 Store for Boogie's verification conditions. |
4 Store for Boogie's verification conditions. |
5 *) |
5 *) |
6 |
6 |
7 signature BOOGIE_VCS = |
7 signature BOOGIE_VCS = |
8 sig |
8 sig |
|
9 datatype skel = Nil of string | Imp of skel | Con1 of skel | Con2 of skel | |
|
10 Conj of skel * skel |
|
11 val size_of: skel * 'a -> int |
|
12 val names_of: skel * 'a -> string list |
|
13 val paths_of: skel * term -> (skel * term) list |
|
14 val split_path: int -> skel * term -> (skel * term) * (skel * term) |
|
15 val extract: skel * term -> string -> (skel * term) option |
|
16 |
9 val set: (string * term) list -> theory -> theory |
17 val set: (string * term) list -> theory -> theory |
10 val lookup: theory -> string -> term option |
18 val lookup: theory -> string -> (skel * term) option |
11 val discharge: string * thm -> theory -> theory |
19 val discharge: string * (skel * thm) -> theory -> theory |
12 val close: theory -> theory |
20 val close: theory -> theory |
13 val is_closed: theory -> bool |
21 val is_closed: theory -> bool |
14 val as_list: theory -> (string * term * bool) list |
22 |
|
23 datatype state = Proved | NotProved | PartiallyProved |
|
24 val state_of: theory -> (string * state) list |
|
25 val state_of_vc: theory -> string -> string list * string list |
15 end |
26 end |
16 |
27 |
17 structure Boogie_VCs: BOOGIE_VCS = |
28 structure Boogie_VCs: BOOGIE_VCS = |
18 struct |
29 struct |
19 |
30 |
|
31 (* simplify VCs: drop True, fold premises into conjunctions *) |
|
32 |
|
33 local |
|
34 val dest_eq = HOLogic.dest_eq o HOLogic.dest_Trueprop o Thm.prop_of |
|
35 |
|
36 val true_rules = map dest_eq @{lemma |
|
37 "(True & P) = P" |
|
38 "(P & True) = P" |
|
39 "(P --> True) = True" |
|
40 "(True --> P) = P" |
|
41 by simp_all} |
|
42 |
|
43 val fold_prems = |
|
44 dest_eq @{lemma "(P1 --> P2 --> Q) = ((P1 & P2) --> Q)" by fast} |
|
45 in |
|
46 fun simp_vc thy = Pattern.rewrite_term thy (true_rules @ [fold_prems]) [] |
|
47 end |
|
48 |
|
49 |
|
50 (* VC skeleton: reflect the structure of implications and conjunctions *) |
|
51 |
|
52 datatype skel = |
|
53 Nil of string | (* assertion with label name *) |
|
54 Imp of skel | (* implication: only conclusion is relevant *) |
|
55 Con1 of skel | (* only left conjunct *) |
|
56 Con2 of skel | (* right left conjunct *) |
|
57 Conj of skel * skel (* full conjunction *) |
|
58 |
|
59 val skel_of = |
|
60 let |
|
61 fun skel (@{term "op -->"} $ _ $ u) = Imp (skel u) |
|
62 | skel (@{term "op &"} $ t $ u) = Conj (skel t, skel u) |
|
63 | skel (@{term assert_at} $ Free (n, _) $ _) = Nil n |
|
64 | skel t = raise TERM ("skel_of", [t]) |
|
65 in skel o HOLogic.dest_Trueprop end |
|
66 |
|
67 fun size (Nil _) = 1 |
|
68 | size (Imp sk) = size sk |
|
69 | size (Con1 sk) = size sk |
|
70 | size (Con2 sk) = size sk |
|
71 | size (Conj (sk1, sk2)) = size sk1 + size sk2 |
|
72 |
|
73 fun size_of (sk, _) = size sk |
|
74 |
|
75 fun add_names (Nil name) = cons name (* label names are unique! *) |
|
76 | add_names (Imp sk) = add_names sk |
|
77 | add_names (Con1 sk) = add_names sk |
|
78 | add_names (Con2 sk) = add_names sk |
|
79 | add_names (Conj (sk1, sk2)) = add_names sk1 #> add_names sk2 |
|
80 |
|
81 fun names_of (sk, _) = add_names sk [] |
|
82 |
|
83 |
|
84 fun make_app t u = t $ u |
|
85 fun dest_app (t $ u) = (t, u) |
|
86 | dest_app t = raise TERM ("dest_app", [t]) |
|
87 |
|
88 val make_prop = HOLogic.mk_Trueprop |
|
89 val dest_prop = HOLogic.dest_Trueprop |
|
90 |
|
91 val make_imp = curry HOLogic.mk_imp |
|
92 val dest_imp = HOLogic.dest_imp |
|
93 |
|
94 val make_conj = curry HOLogic.mk_conj |
|
95 fun dest_conj (@{term "op &"} $ t $ u) = (t, u) |
|
96 | dest_conj t = raise TERM ("dest_conj", [t]) |
|
97 |
|
98 |
|
99 fun app_both f g (x, y) = (f x, g y) |
|
100 |
|
101 fun under_imp f r (sk, t) = |
|
102 let val (t1, t2) = dest_imp t |
|
103 in f (sk, t2) |> r (app_both Imp (make_imp t1)) end |
|
104 |
|
105 fun split_conj f r1 r2 r (sk1, sk2, t) = |
|
106 let val (t1, t2) = dest_conj t |
|
107 in |
|
108 f (sk2, t2) |
|
109 |>> r1 (app_both (Conj o pair sk1) (make_conj t1)) |
|
110 ||> r2 (apfst Con2) |
|
111 |> r |
|
112 end |
|
113 |
|
114 val paths_of = |
|
115 let |
|
116 fun chop1 xs = (hd xs, tl xs) |
|
117 |
|
118 fun split (sk, t) = |
|
119 (case sk of |
|
120 Nil _ => [(sk, t)] |
|
121 | Imp sk' => under_imp split map (sk', t) |
|
122 | Con1 sk1 => splt Con1 (sk1, t) |
|
123 | Con2 sk2 => splt Con2 (sk2, t) |
|
124 | Conj (sk1 as Nil _, sk2) => |
|
125 split_conj (chop1 o split) I map (op ::) (sk1, sk2, t) |
|
126 | Conj (sk1, sk2) => |
|
127 let val (t1, t2) = dest_conj t |
|
128 in splt Con1 (sk1, t1) @ splt Con2 (sk2, t2) end) |
|
129 and splt c st = split st |> map (apfst c) |
|
130 |
|
131 in map (apsnd make_prop) o split o apsnd dest_prop end |
|
132 |
|
133 fun split_path i = |
|
134 let |
|
135 fun split_at i (sk, t) = |
|
136 (case sk of |
|
137 Imp sk' => under_imp (split_at i) pairself (sk', t) |
|
138 | Con1 sk1 => split_at i (sk1, t) |> pairself (apfst Con1) |
|
139 | Con2 sk2 => split_at i (sk2, t) |> pairself (apfst Con2) |
|
140 | Conj (sk1, sk2) => |
|
141 if i > 1 |
|
142 then split_conj (split_at (i-1)) I I I (sk1, sk2, t) |
|
143 else app_both (pair (Con1 sk1)) (pair (Con2 sk2)) (dest_conj t) |
|
144 | _ => raise TERM ("split_path: " ^ string_of_int i, [t])) |
|
145 in pairself (apsnd make_prop) o split_at i o apsnd dest_prop end |
|
146 |
|
147 fun extract (sk, t) name = |
|
148 let |
|
149 fun is_in (Nil n) = (n = name, false) |
|
150 | is_in (Imp sk) = is_in sk |
|
151 | is_in (Con1 sk) = is_in sk |
|
152 | is_in (Con2 sk) = is_in sk |
|
153 | is_in (Conj (sk1, sk2)) = |
|
154 if fst (is_in sk1) then (true, true) else is_in sk2 ||> K true |
|
155 |
|
156 fun extr (sk, t) = |
|
157 (case sk of |
|
158 Nil _ => (sk, t) |
|
159 | Imp sk' => under_imp extr I (sk', t) |
|
160 | Con1 sk1 => extr (sk1, t) |> apfst Con1 |
|
161 | Con2 sk2 => extr (sk2, t) |> apfst Con2 |
|
162 | Conj (sk1, sk2) => |
|
163 (case is_in sk1 of |
|
164 (true, true) => extr (sk1, fst (dest_conj t)) |> apfst Con1 |
|
165 | (true, false) => (Con1 sk1, fst (dest_conj t)) |
|
166 | (false, _) => extr (sk2, snd (dest_conj t)) |> apfst Con2)) |
|
167 in |
|
168 (case is_in sk of |
|
169 (true, true) => SOME ((sk, dest_prop t) |> extr |> apsnd make_prop) |
|
170 | (true, false) => SOME (sk, t) |
|
171 | (false, _) => NONE) |
|
172 end |
|
173 |
|
174 |
|
175 fun cut thy = |
|
176 let |
|
177 fun opt_map_both f g = Option.map (app_both f g) |
|
178 |
|
179 fun cut_err (u, t) = raise TERM ("cut: not matching", [u, t]) |
|
180 |
|
181 val matches = Pattern.matches thy |
|
182 |
|
183 fun sub (usk, u) (sk, t) = |
|
184 (case (usk, sk) of |
|
185 (Nil _, Nil _) => if matches (u, t) then NONE else cut_err (u, t) |
|
186 | (Imp usk', Imp sk') => sub_imp (usk', u) (sk', t) |
|
187 |
|
188 | (Con1 usk1, Con1 sk1) => |
|
189 sub (usk1, u) (sk1, t) |> Option.map (apfst Con1) |
|
190 | (Con2 usk2, Con2 sk2) => |
|
191 sub (usk2, u) (sk2, t) |> Option.map (apfst Con2) |
|
192 |
|
193 | (Con1 _, Con2 _) => SOME (sk, t) |
|
194 | (Con2 _, Con1 _) => SOME (sk, t) |
|
195 |
|
196 | (Con1 usk1, Conj (sk1, sk2)) => |
|
197 let val (t1, t2) = dest_conj t |
|
198 in |
|
199 sub (usk1, u) (sk1, t1) |
|
200 |> opt_map_both (Conj o rpair sk2) (fn t1' => make_conj t1' t2) |
|
201 |> SOME o the_default (Con2 sk2, t2) |
|
202 end |
|
203 | (Con2 usk2, Conj (sk1, sk2)) => |
|
204 let val (t1, t2) = dest_conj t |
|
205 in |
|
206 sub (usk2, u) (sk2, t2) |
|
207 |> opt_map_both (Conj o pair sk1) (make_conj t1) |
|
208 |> SOME o the_default (Con1 sk1, t1) |
|
209 end |
|
210 | (Conj (usk1, _), Con1 sk1) => |
|
211 let val (u1, _) = dest_conj u |
|
212 in sub (usk1, u1) (sk1, t) |> Option.map (apfst Con1) end |
|
213 | (Conj (_, usk2), Con2 sk2) => |
|
214 let val (_, u2) = dest_conj u |
|
215 in sub (usk2, u2) (sk2, t) |> Option.map (apfst Con2) end |
|
216 |
|
217 | (Conj (usk1, usk2), Conj (sk1, sk2)) => |
|
218 sub_conj (usk1, usk2, u) (sk1, sk2, t) |
|
219 |
|
220 | _ => cut_err (u, t)) |
|
221 |
|
222 and sub_imp (usk', u) (sk', t) = |
|
223 let |
|
224 val (u1, u2) = dest_imp u |
|
225 val (t1, t2) = dest_imp t |
|
226 in |
|
227 if matches (u1, t1) |
|
228 then sub (usk', u2) (sk', t2) |> opt_map_both Imp (make_imp t1) |
|
229 else cut_err (u, t) |
|
230 end |
|
231 |
|
232 and sub_conj (usk1, usk2, u) (sk1, sk2, t) = |
|
233 let |
|
234 val (u1, u2) = dest_conj u |
|
235 val (t1, t2) = dest_conj t |
|
236 in |
|
237 (case (sub (usk1, u1) (sk1, t1), sub (usk2, u2) (sk2, t2)) of |
|
238 (NONE, NONE) => NONE |
|
239 | (NONE, SOME (sk2', t2')) => SOME (Con2 sk2', t2') |
|
240 | (SOME (sk1', t1'), NONE) => SOME (Con1 sk1', t1') |
|
241 | (SOME (sk1', t1'), SOME (sk2', t2')) => |
|
242 SOME (Conj (sk1', sk2'), make_conj t1' t2')) |
|
243 end |
|
244 in |
|
245 (fn su => fn st => |
|
246 (su, st) |
|
247 |> pairself (apsnd dest_prop) |
|
248 |> uncurry sub |
|
249 |> Option.map (apsnd make_prop)) |
|
250 end |
|
251 |
|
252 |
|
253 local |
|
254 fun imp f (lsk, lthm) (rsk, rthm) = |
|
255 let |
|
256 val mk_prop = Thm.capply @{cterm Trueprop} |
|
257 val ct = Thm.cprop_of lthm |> Thm.dest_arg |> Thm.dest_arg1 |> mk_prop |
|
258 val th = Thm.assume ct |
|
259 fun imp_elim thm = @{thm mp} OF [thm, th] |
|
260 fun imp_intr thm = Thm.implies_intr ct thm COMP_INCR @{thm impI} |
|
261 val (sk, thm) = f (lsk, imp_elim lthm) (rsk, imp_elim rthm) |
|
262 in (Imp sk, imp_intr thm) end |
|
263 |
|
264 fun conj1 thm = @{thm conjunct1} OF [thm] |
|
265 fun conj2 thm = @{thm conjunct2} OF [thm] |
|
266 in |
|
267 fun join (lsk, lthm) (rsk, rthm) = |
|
268 (case (lsk, rsk) of |
|
269 (Nil _, Nil _) => (lsk, lthm) |
|
270 | (Imp lsk', Imp rsk') => imp join (lsk', lthm) (rsk', rthm) |
|
271 |
|
272 | (Con1 lsk1, Con1 rsk1) => join (lsk1, lthm) (rsk1, rthm) |>> Con1 |
|
273 | (Con2 lsk2, Con2 rsk2) => join (lsk2, lthm) (rsk2, rthm) |>> Con2 |
|
274 |
|
275 | (Con1 lsk1, Con2 rsk2) => (Conj (lsk1, rsk2), @{thm conjI} OF [lthm, rthm]) |
|
276 | (Con2 lsk2, Con1 rsk1) => (Conj (rsk1, lsk2), @{thm conjI} OF [rthm, lthm]) |
|
277 |
|
278 | (Con1 lsk1, Conj (rsk1, rsk2)) => |
|
279 let val (sk1, thm) = join (lsk1, lthm) (rsk1, conj1 rthm) |
|
280 in (Conj (sk1, rsk2), @{thm conjI} OF [thm, conj2 rthm]) end |
|
281 | (Con2 lsk2, Conj (rsk1, rsk2)) => |
|
282 let val (sk2, thm) = join (lsk2, lthm) (rsk2, conj2 rthm) |
|
283 in (Conj (rsk1, sk2), @{thm conjI} OF [conj1 rthm, thm]) end |
|
284 | (Conj (lsk1, lsk2), Con1 rsk1) => |
|
285 let val (sk1, thm) = join (lsk1, conj1 lthm) (rsk1, rthm) |
|
286 in (Conj (sk1, lsk2), @{thm conjI} OF [thm, conj2 lthm]) end |
|
287 | (Conj (lsk1, lsk2), Con2 rsk2) => |
|
288 let val (sk2, thm) = join (lsk2, conj2 lthm) (rsk2, rthm) |
|
289 in (Conj (lsk1, sk2), @{thm conjI} OF [conj1 lthm, thm]) end |
|
290 |
|
291 | (Conj (lsk1, lsk2), Conj (rsk1, rsk2)) => |
|
292 let |
|
293 val (sk1, th1) = join (lsk1, conj1 lthm) (rsk1, conj1 rthm) |
|
294 val (sk2, th2) = join (lsk2, conj2 lthm) (rsk2, conj2 rthm) |
|
295 in (Conj (sk1, sk2), @{thm conjI} OF [th1, th2]) end |
|
296 |
|
297 | _ => raise THM ("join: different structure", 0, [lthm, rthm])) |
|
298 end |
|
299 |
|
300 |
|
301 (* the VC store *) |
|
302 |
20 fun err_vcs () = error "undischarged Boogie verification conditions found" |
303 fun err_vcs () = error "undischarged Boogie verification conditions found" |
|
304 |
|
305 datatype vc = |
|
306 VC_NotProved of skel * term | |
|
307 VC_PartiallyProved of (skel * term) * (skel * thm) | |
|
308 VC_Proved of skel * thm |
|
309 |
|
310 fun goal_of (VC_NotProved g) = SOME g |
|
311 | goal_of (VC_PartiallyProved (g, _)) = SOME g |
|
312 | goal_of (VC_Proved _) = NONE |
|
313 |
|
314 fun proof_of (VC_NotProved _) = NONE |
|
315 | proof_of (VC_PartiallyProved (_, p)) = SOME p |
|
316 | proof_of (VC_Proved p) = SOME p |
21 |
317 |
22 structure VCs = Theory_Data |
318 structure VCs = Theory_Data |
23 ( |
319 ( |
24 type T = (term * bool) Symtab.table option |
320 type T = vc Symtab.table option |
25 val empty = NONE |
321 val empty = NONE |
26 val extend = I |
322 val extend = I |
27 fun merge (NONE, NONE) = NONE |
323 fun merge (NONE, NONE) = NONE |
28 | merge _ = err_vcs () |
324 | merge _ = err_vcs () |
29 ) |
325 ) |
30 |
326 |
31 fun set vcs = VCs.map (fn |
327 fun prep thy t = VC_NotProved (` skel_of (simp_vc thy (HOLogic.mk_Trueprop t))) |
32 NONE => SOME (Symtab.make (map (apsnd (rpair false)) vcs)) |
328 |
33 | SOME _ => err_vcs ()) |
329 fun set vcs thy = VCs.map (fn |
34 |
330 NONE => SOME (Symtab.make (map (apsnd (prep thy)) vcs)) |
35 fun lookup thy name = |
331 | SOME _ => err_vcs ()) thy |
|
332 |
|
333 fun lookup thy name = |
36 (case VCs.get thy of |
334 (case VCs.get thy of |
37 SOME vcs => Option.map fst (Symtab.lookup vcs name) |
335 SOME vcs => |
|
336 (case Symtab.lookup vcs name of |
|
337 SOME vc => goal_of vc |
|
338 | NONE => NONE) |
38 | NONE => NONE) |
339 | NONE => NONE) |
39 |
340 |
40 fun discharge (name, thm) thy = VCs.map (fn |
341 fun discharge (name, prf) thy = thy |> VCs.map (Option.map |
41 SOME vcs => SOME (Symtab.map_entry name (fn (t, proved) => |
342 (Symtab.map_entry name (fn |
42 if proved then (t, proved) |
343 VC_NotProved goal => |
43 else (t, Pattern.matches thy (Thm.prop_of thm, t))) vcs) |
344 (case cut thy (apsnd Thm.prop_of prf) goal of |
44 | NONE => NONE) thy |
345 SOME goal' => VC_PartiallyProved (goal', prf) |
|
346 | NONE => VC_Proved prf) |
|
347 | VC_PartiallyProved (goal, proof) => |
|
348 (case cut thy (apsnd Thm.prop_of prf) goal of |
|
349 SOME goal' => VC_PartiallyProved (goal', join prf proof) |
|
350 | NONE => VC_Proved (join prf proof)) |
|
351 | VC_Proved proof => VC_Proved proof))) |
45 |
352 |
46 val close = VCs.map (fn |
353 val close = VCs.map (fn |
47 SOME vcs => |
354 SOME vcs => |
48 if Symtab.exists (fn (_, (_, proved)) => not proved) vcs then err_vcs () |
355 if Symtab.exists (is_some o goal_of o snd) vcs |
|
356 then err_vcs () |
49 else NONE |
357 else NONE |
50 | NONE => NONE) |
358 | NONE => NONE) |
51 |
359 |
52 val is_closed = is_none o VCs.get |
360 val is_closed = is_none o VCs.get |
53 |
361 |
54 fun as_list thy = |
362 |
|
363 datatype state = Proved | NotProved | PartiallyProved |
|
364 |
|
365 fun state_of thy = |
55 (case VCs.get thy of |
366 (case VCs.get thy of |
56 SOME vcs => map (fn (n, (t, p)) => (n, t, p)) (Symtab.dest vcs) |
367 SOME vcs => Symtab.dest vcs |> map (apsnd (fn |
|
368 VC_NotProved _ => NotProved |
|
369 | VC_PartiallyProved _ => PartiallyProved |
|
370 | VC_Proved _ => Proved)) |
57 | NONE => []) |
371 | NONE => []) |
58 |
372 |
|
373 fun names_of' skx = these (Option.map names_of skx) |
|
374 |
|
375 fun state_of_vc thy name = |
|
376 (case VCs.get thy of |
|
377 SOME vcs => |
|
378 (case Symtab.lookup vcs name of |
|
379 SOME vc => (names_of' (proof_of vc), names_of' (goal_of vc)) |
|
380 | NONE => ([], [])) |
|
381 | NONE => ([], [])) |
|
382 |
59 end |
383 end |