Release coccinelle-0.2.0
[bpt/coccinelle.git] / ctl / ctl_engine.ml
CommitLineData
9f8e26f4
C
1(*
2 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
4 * This file is part of Coccinelle.
5 *
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
9 *
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
20 *)
21
22
34e49164
C
23(*external c_counter : unit -> int = "c_counter"*)
24let timeout = 800
25(* Optimize triples_conj by first extracting the intersection of the two sets,
26which can certainly be in the intersection *)
27let pTRIPLES_CONJ_OPT = ref true
28(* For complement, make NegState for the negation of a single state *)
29let pTRIPLES_COMPLEMENT_OPT = ref true
30(* For complement, do something special for the case where the environment
31and witnesses are empty *)
32let pTRIPLES_COMPLEMENT_SIMPLE_OPT = ref true
33(* "Double negate" the arguments of the path operators *)
34let pDOUBLE_NEGATE_OPT = ref true
35(* Only do pre_forall/pre_exists on new elements in fixpoint iteration *)
36let pNEW_INFO_OPT = ref true
37(* Filter the result of the label function to drop entries that aren't
38compatible with any of the available environments *)
39let pREQUIRED_ENV_OPT = ref true
40(* Memoize the raw result of the label function *)
41let pSATLABEL_MEMO_OPT = ref true
42(* Filter results according to the required states *)
43let pREQUIRED_STATES_OPT = ref true
44(* Drop negative witnesses at Uncheck *)
45let pUNCHECK_OPT = ref true
46let pANY_NEG_OPT = ref true
47let pLazyOpt = ref true
48
485bce71
C
49(* Nico: This stack is use for graphical traces *)
50let graph_stack = ref ([] : string list)
51let graph_hash = (Hashtbl.create 101)
52
34e49164
C
53(*
54let pTRIPLES_CONJ_OPT = ref false
55let pTRIPLES_COMPLEMENT_OPT = ref false
56let pTRIPLES_COMPLEMENT_SIMPLE_OPT = ref false
57let pDOUBLE_NEGATE_OPT = ref false
58let pNEW_INFO_OPT = ref false
59let pREQUIRED_ENV_OPT = ref false
60let pSATLABEL_MEMO_OPT = ref false
61let pREQUIRED_STATES_OPT = ref false
62let pUNCHECK_OPT = ref false
63let pANY_NEG_OPT = ref false
64let pLazyOpt = ref false
65*)
66
67
68let step_count = ref 0
69exception Steps
70let inc_step _ =
71 if not (!step_count = 0)
72 then
73 begin
74 step_count := !step_count - 1;
75 if !step_count = 0 then raise Steps
76 end
77
78let inc cell = cell := !cell + 1
79
80let satEU_calls = ref 0
81let satAW_calls = ref 0
82let satAU_calls = ref 0
83let satEF_calls = ref 0
84let satAF_calls = ref 0
85let satEG_calls = ref 0
86let satAG_calls = ref 0
87
88let triples = ref 0
89
90let ctr = ref 0
91let new_let _ =
92 let c = !ctr in
93 ctr := c + 1;
94 Printf.sprintf "_fresh_r_%d" c
95
96(* **********************************************************************
97 *
98 * Implementation of a Witness Tree model checking engine for CTL-FVex
99 *
100 *
101 * **********************************************************************)
102
103(* ********************************************************************** *)
104(* Module: SUBST (substitutions: meta. vars and values) *)
105(* ********************************************************************** *)
106
107module type SUBST =
108 sig
109 type value
110 type mvar
111 val eq_mvar: mvar -> mvar -> bool
112 val eq_val: value -> value -> bool
113 val merge_val: value -> value -> value
114 val print_mvar : mvar -> unit
115 val print_value : value -> unit
116 end
117;;
118
119(* ********************************************************************** *)
120(* Module: GRAPH (control flow graphs / model) *)
121(* ********************************************************************** *)
122
123module type GRAPH =
124 sig
125 type node
126 type cfg
127 val predecessors: cfg -> node -> node list
128 val successors: cfg -> node -> node list
129 val extract_is_loop : cfg -> node -> bool
130 val print_node : node -> unit
131 val size : cfg -> int
485bce71
C
132 val print_graph : cfg -> string option ->
133 (node * string) list -> (node * string) list -> string -> unit
34e49164
C
134 end
135;;
136
137module OGRAPHEXT_GRAPH =
138 struct
139 type node = int;;
140 type cfg = (string,unit) Ograph_extended.ograph_mutable;;
141 let predecessors cfg n = List.map fst ((cfg#predecessors n)#tolist);;
142 let print_node i = Format.print_string (Common.i_to_s i)
143 end
144;;
145
146(* ********************************************************************** *)
147(* Module: PREDICATE (predicates for CTL formulae) *)
148(* ********************************************************************** *)
149
150module type PREDICATE =
151sig
152 type t
153 val print_predicate : t -> unit
154end
155
156
157(* ********************************************************************** *)
158
159(* ---------------------------------------------------------------------- *)
160(* Misc. useful generic functions *)
161(* ---------------------------------------------------------------------- *)
162
485bce71
C
163let get_graph_files () = !graph_stack
164let get_graph_comp_files outfile = Hashtbl.find_all graph_hash outfile
165
34e49164
C
166let head = List.hd
167
168let tail l =
169 match l with
170 [] -> []
171 | (x::xs) -> xs
172;;
173
174let foldl = List.fold_left;;
175
176let foldl1 f xs = foldl f (head xs) (tail xs)
177
178type 'a esc = ESC of 'a | CONT of 'a
179
180let foldr = List.fold_right;;
181
182let concat = List.concat;;
183
184let map = List.map;;
185
186let filter = List.filter;;
187
188let partition = List.partition;;
189
190let concatmap f l = List.concat (List.map f l);;
191
192let maybe f g opt =
193 match opt with
194 | None -> g
195 | Some x -> f x
196;;
197
198let some_map f opts = map (maybe (fun x -> Some (f x)) None) opts
199
200let some_tolist_alt opts = concatmap (maybe (fun x -> [x]) []) opts
201
202let rec some_tolist opts =
203 match opts with
204 | [] -> []
205 | (Some x)::rest -> x::(some_tolist rest)
206 | _::rest -> some_tolist rest
207;;
208
209let rec groupBy eq l =
210 match l with
211 [] -> []
212 | (x::xs) ->
213 let (xs1,xs2) = partition (fun x' -> eq x x') xs in
214 (x::xs1)::(groupBy eq xs2)
215;;
216
217let group l = groupBy (=) l;;
218
219let rec memBy eq x l =
220 match l with
221 [] -> false
222 | (y::ys) -> if (eq x y) then true else (memBy eq x ys)
223;;
224
225let rec nubBy eq ls =
226 match ls with
227 [] -> []
228 | (x::xs) when (memBy eq x xs) -> nubBy eq xs
229 | (x::xs) -> x::(nubBy eq xs)
230;;
231
232let rec nub ls =
233 match ls with
234 [] -> []
235 | (x::xs) when (List.mem x xs) -> nub xs
236 | (x::xs) -> x::(nub xs)
237;;
238
239let state_compare (s1,_,_) (s2,_,_) = compare s1 s2
240
241let setifyBy eq xs = nubBy eq xs;;
242
243let setify xs = nub xs;;
244
245let inner_setify xs = List.sort compare (nub xs);;
246
247let unionBy compare eq xs = function
248 [] -> xs
249 | ys ->
250 let rec loop = function
251 [] -> ys
252 | x::xs -> if memBy eq x ys then loop xs else x::(loop xs) in
253 List.sort compare (loop xs)
254;;
255
256let union xs ys = unionBy state_compare (=) xs ys;;
257
258let setdiff xs ys = filter (fun x -> not (List.mem x ys)) xs;;
259
260let subseteqBy eq xs ys = List.for_all (fun x -> memBy eq x ys) xs;;
261
262let subseteq xs ys = List.for_all (fun x -> List.mem x ys) xs;;
263let supseteq xs ys = subseteq ys xs
264
265let setequalBy eq xs ys = (subseteqBy eq xs ys) & (subseteqBy eq ys xs);;
266
267let setequal xs ys = (subseteq xs ys) & (subseteq ys xs);;
268
269(* Fix point calculation *)
270let rec fix eq f x =
271 let x' = f x in if (eq x' x) then x' else fix eq f x'
272;;
273
274(* Fix point calculation on set-valued functions *)
275let setfix f x = (fix subseteq f x) (*if new is a subset of old, stop*)
276let setgfix f x = (fix supseteq f x) (*if new is a supset of old, stop*)
277
278let get_states l = nub (List.map (function (s,_,_) -> s) l)
279
280(* ********************************************************************** *)
281(* Module: CTL_ENGINE *)
282(* ********************************************************************** *)
283
284module CTL_ENGINE =
285 functor (SUB : SUBST) ->
286 functor (G : GRAPH) ->
287 functor (P : PREDICATE) ->
288struct
289
290module A = Ast_ctl
291
292type substitution = (SUB.mvar, SUB.value) Ast_ctl.generic_substitution
293
294type ('pred,'anno) witness =
295 (G.node, substitution,
296 ('pred, SUB.mvar, 'anno) Ast_ctl.generic_ctl list)
297 Ast_ctl.generic_witnesstree
298
299type ('pred,'anno) triples =
300 (G.node * substitution * ('pred,'anno) witness list) list
301
302(* ---------------------------------------------------------------------- *)
303(* Pretty printing functions *)
304(* ---------------------------------------------------------------------- *)
305
306let (print_generic_substitution : substitution -> unit) = fun substxs ->
307 let print_generic_subst = function
308 A.Subst (mvar, v) ->
309 SUB.print_mvar mvar; Format.print_string " --> "; SUB.print_value v
310 | A.NegSubst (mvar, v) ->
311 SUB.print_mvar mvar; Format.print_string " -/-> "; SUB.print_value v in
312 Format.print_string "[";
313 Common.print_between (fun () -> Format.print_string ";" )
314 print_generic_subst substxs;
315 Format.print_string "]"
316
317let rec (print_generic_witness: ('pred, 'anno) witness -> unit) =
318 function
319 | A.Wit (state, subst, anno, childrens) ->
320 Format.print_string "wit ";
321 G.print_node state;
322 print_generic_substitution subst;
323 (match childrens with
324 [] -> Format.print_string "{}"
325 | _ ->
326 Format.force_newline(); Format.print_string " "; Format.open_box 0;
327 print_generic_witnesstree childrens; Format.close_box())
328 | A.NegWit(wit) ->
329 Format.print_string "!";
330 print_generic_witness wit
331
332and (print_generic_witnesstree: ('pred,'anno) witness list -> unit) =
333 fun witnesstree ->
334 Format.open_box 1;
335 Format.print_string "{";
336 Common.print_between
337 (fun () -> Format.print_string ";"; Format.force_newline() )
338 print_generic_witness witnesstree;
339 Format.print_string "}";
340 Format.close_box()
341
342and print_generic_triple (node,subst,tree) =
343 G.print_node node;
344 print_generic_substitution subst;
345 print_generic_witnesstree tree
346
347and (print_generic_algo : ('pred,'anno) triples -> unit) = fun xs ->
348 Format.print_string "<";
349 Common.print_between
350 (fun () -> Format.print_string ";"; Format.force_newline())
351 print_generic_triple xs;
352 Format.print_string ">"
353;;
354
355let print_state (str : string) (l : ('pred,'anno) triples) =
356 Printf.printf "%s\n" str;
357 List.iter (function x ->
358 print_generic_triple x; Format.print_newline(); flush stdout)
359 (List.sort compare l);
360 Printf.printf "\n"
361
362let print_required_states = function
363 None -> Printf.printf "no required states\n"
364 | Some states ->
365 Printf.printf "required states: ";
366 List.iter
367 (function x ->
368 G.print_node x; Format.print_string " "; Format.print_flush())
369 states;
370 Printf.printf "\n"
371
372let mkstates states = function
373 None -> states
374 | Some states -> states
485bce71
C
375
376let print_graph grp required_states res str = function
377 A.Exists (keep,v,phi) -> ()
378 | phi ->
379 if !Flag_ctl.graphical_trace && not !Flag_ctl.checking_reachability
380 then
381 match phi with
382 | A.Exists (keep,v,phi) -> ()
383 | _ ->
384 let label =
385 Printf.sprintf "%s%s"
386 (String.escaped
387 (Common.format_to_string
388 (function _ ->
389 Pretty_print_ctl.pp_ctl
390 (P.print_predicate, SUB.print_mvar)
391 false phi)))
392 str in
393 let file = (match !Flag.currentfile with
394 None -> "graphical_trace"
395 | Some f -> f
396 ) in
397 (if not (List.mem file !graph_stack) then
398 graph_stack := file :: !graph_stack);
399 let filename = Filename.temp_file (file^":") ".dot" in
400 Hashtbl.add graph_hash file filename;
401 G.print_graph grp
402 (if !Flag_ctl.gt_without_label then None else (Some label))
403 (match required_states with
404 None -> []
405 | Some required_states ->
406 (List.map (function s -> (s,"blue")) required_states))
407 (List.map (function (s,_,_) -> (s,"\"#FF8080\"")) res) filename
408
409let print_graph_c grp required_states res ctr phi =
410 let str = "iter: "^(string_of_int !ctr) in
411 print_graph grp required_states res str phi
412
34e49164
C
413(* ---------------------------------------------------------------------- *)
414(* *)
415(* ---------------------------------------------------------------------- *)
416
417
418(* ************************* *)
419(* Substitutions *)
420(* ************************* *)
421
422let dom_sub sub =
423 match sub with
424 | A.Subst(x,_) -> x
425 | A.NegSubst(x,_) -> x
426;;
427
428let ran_sub sub =
429 match sub with
430 | A.Subst(_,x) -> x
431 | A.NegSubst(_,x) -> x
432;;
433
434let eq_subBy eqx eqv sub sub' =
435 match (sub,sub') with
436 | (A.Subst(x,v),A.Subst(x',v')) -> (eqx x x') && (eqv v v')
437 | (A.NegSubst(x,v),A.NegSubst(x',v')) -> (eqx x x') && (eqv v v')
438 | _ -> false
439;;
440
441(* NOTE: functor *)
442let eq_sub sub sub' = eq_subBy SUB.eq_mvar SUB.eq_val sub sub'
443
444let eq_subst th th' = setequalBy eq_sub th th';;
445
446let merge_subBy eqx (===) (>+<) sub sub' =
447 (* variable part is guaranteed to be the same *)
448 match (sub,sub') with
449 (A.Subst (x,v),A.Subst (x',v')) ->
450 if (v === v')
451 then Some [A.Subst(x, v >+< v')]
452 else None
453 | (A.NegSubst(x,v),A.Subst(x',v')) ->
454 if (not (v === v'))
455 then Some [A.Subst(x',v')]
456 else None
457 | (A.Subst(x,v),A.NegSubst(x',v')) ->
458 if (not (v === v'))
459 then Some [A.Subst(x,v)]
460 else None
461 | (A.NegSubst(x,v),A.NegSubst(x',v')) ->
462 if (v === v')
463 then
464 let merged = v >+< v' in
465 if merged = v && merged = v'
466 then Some [A.NegSubst(x,v >+< v')]
467 else
468 (* positions are compatible, but not identical. keep apart. *)
469 Some [A.NegSubst(x,v);A.NegSubst(x',v')]
470 else Some [A.NegSubst(x,v);A.NegSubst(x',v')]
471;;
472
473(* NOTE: functor *)
474let merge_sub sub sub' =
475 merge_subBy SUB.eq_mvar SUB.eq_val SUB.merge_val sub sub'
476
477let clean_substBy eq cmp theta = List.sort cmp (nubBy eq theta);;
478
479(* NOTE: we sort by using the generic "compare" on (meta-)variable
480 * names; we could also require a definition of compare for meta-variables
481 * or substitutions but that seems like overkill for sorting
482 *)
483let clean_subst theta =
484 let res =
485 clean_substBy eq_sub
486 (fun s s' ->
487 let res = compare (dom_sub s) (dom_sub s') in
488 if res = 0
489 then
490 match (s,s') with
491 (A.Subst(_,_),A.NegSubst(_,_)) -> -1
492 | (A.NegSubst(_,_),A.Subst(_,_)) -> 1
493 | _ -> compare (ran_sub s) (ran_sub s')
494 else res)
495 theta in
496 let rec loop = function
497 [] -> []
498 | (A.Subst(x,v)::A.NegSubst(y,v')::rest) when SUB.eq_mvar x y ->
499 loop (A.Subst(x,v)::rest)
500 | x::xs -> x::(loop xs) in
501 loop res
502
503let top_subst = [];; (* Always TRUE subst. *)
504
505(* Split a theta in two parts: one with (only) "x" and one without *)
506(* NOTE: functor *)
507let split_subst theta x =
508 partition (fun sub -> SUB.eq_mvar (dom_sub sub) x) theta;;
509
510exception SUBST_MISMATCH
511let conj_subst theta theta' =
512 match (theta,theta') with
513 | ([],_) -> Some theta'
514 | (_,[]) -> Some theta
515 | _ ->
516 let rec classify = function
517 [] -> []
518 | [x] -> [(dom_sub x,[x])]
519 | x::xs ->
520 (match classify xs with
521 ((nm,y)::ys) as res ->
522 if dom_sub x = nm
523 then (nm,x::y)::ys
524 else (dom_sub x,[x])::res
525 | _ -> failwith "not possible") in
526 let merge_all theta theta' =
527 foldl
528 (function rest ->
529 function sub ->
530 foldl
531 (function rest ->
532 function sub' ->
533 match (merge_sub sub sub') with
534 Some subs -> subs @ rest
535 | _ -> raise SUBST_MISMATCH)
536 rest theta')
537 [] theta in
538 let rec loop = function
539 ([],ctheta') ->
540 List.concat (List.map (function (_,ths) -> ths) ctheta')
541 | (ctheta,[]) ->
542 List.concat (List.map (function (_,ths) -> ths) ctheta)
543 | ((x,ths)::xs,(y,ths')::ys) ->
544 (match compare x y with
545 0 -> (merge_all ths ths') @ loop (xs,ys)
546 | -1 -> ths @ loop (xs,((y,ths')::ys))
547 | 1 -> ths' @ loop (((x,ths)::xs),ys)
548 | _ -> failwith "not possible") in
549 try Some (clean_subst(loop (classify theta, classify theta')))
550 with SUBST_MISMATCH -> None
551;;
552
553(* theta' must be a subset of theta *)
554let conj_subst_none theta theta' =
555 match (theta,theta') with
556 | (_,[]) -> Some theta
557 | ([],_) -> None
558 | _ ->
559 let rec classify = function
560 [] -> []
561 | [x] -> [(dom_sub x,[x])]
562 | x::xs ->
563 (match classify xs with
564 ((nm,y)::ys) as res ->
565 if dom_sub x = nm
566 then (nm,x::y)::ys
567 else (dom_sub x,[x])::res
568 | _ -> failwith "not possible") in
569 let merge_all theta theta' =
570 foldl
571 (function rest ->
572 function sub ->
573 foldl
574 (function rest ->
575 function sub' ->
576 match (merge_sub sub sub') with
577 Some subs -> subs @ rest
578 | _ -> raise SUBST_MISMATCH)
579 rest theta')
580 [] theta in
581 let rec loop = function
582 (ctheta,[]) ->
583 List.concat (List.map (function (_,ths) -> ths) ctheta)
584 | ([],ctheta') -> raise SUBST_MISMATCH
585 | ((x,ths)::xs,(y,ths')::ys) ->
586 (match compare x y with
587 0 -> (merge_all ths ths') @ loop (xs,ys)
588 | -1 -> ths @ loop (xs,((y,ths')::ys))
589 | 1 -> raise SUBST_MISMATCH
590 | _ -> failwith "not possible") in
591 try Some (clean_subst(loop (classify theta, classify theta')))
592 with SUBST_MISMATCH -> None
593;;
594
595let negate_sub sub =
596 match sub with
597 | A.Subst(x,v) -> A.NegSubst (x,v)
598 | A.NegSubst(x,v) -> A.Subst(x,v)
599;;
600
601(* Turn a (big) theta into a list of (small) thetas *)
602let negate_subst theta = (map (fun sub -> [negate_sub sub]) theta);;
603
604
605(* ************************* *)
606(* Witnesses *)
607(* ************************* *)
608
609(* Always TRUE witness *)
610let top_wit = ([] : (('pred, 'anno) witness list));;
611
612let eq_wit wit wit' = wit = wit';;
613
614let union_wit wit wit' = (*List.sort compare (wit' @ wit) for popl*)
615 let res = unionBy compare (=) wit wit' in
616 let anynegwit = (* if any is neg, then all are *)
617 List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in
618 if anynegwit res
619 then List.filter (function A.NegWit _ -> true | A.Wit _ -> false) res
620 else res
621
622let negate_wit wit = A.NegWit wit (*
623 match wit with
624 | A.Wit(s,th,anno,ws) -> A.NegWitWit(s,th,anno,ws)
625 | A.NegWitWit(s,th,anno,ws) -> A.Wit(s,th,anno,ws)*)
626;;
627
628let negate_wits wits =
629 List.sort compare (map (fun wit -> [negate_wit wit]) wits);;
630
631let unwitify trips =
632 let anynegwit = (* if any is neg, then all are *)
633 List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in
634 setify
635 (List.fold_left
636 (function prev ->
637 function (s,th,wit) ->
638 if anynegwit wit then prev else (s,th,top_wit)::prev)
639 [] trips)
640
641(* ************************* *)
642(* Triples *)
643(* ************************* *)
644
645(* Triples are equal when the constituents are equal *)
646let eq_trip (s,th,wit) (s',th',wit') =
647 (s = s') && (eq_wit wit wit') && (eq_subst th th');;
648
649let triples_top states = map (fun s -> (s,top_subst,top_wit)) states;;
650
651let normalize trips =
652 List.map
653 (function (st,th,wit) -> (st,List.sort compare th,List.sort compare wit))
654 trips
655
656
657(* conj opt doesn't work ((1,[],{{x=3}}) v (1,[],{{x=4}})) & (1,[],{{x=4}}) =
658(1,[],{{x=3},{x=4}}), not (1,[],{{x=4}}) *)
659let triples_conj trips trips' =
660 let (trips,shared,trips') =
661 if false && !pTRIPLES_CONJ_OPT (* see comment above *)
662 then
663 let (shared,trips) =
664 List.partition (function t -> List.mem t trips') trips in
665 let trips' =
666 List.filter (function t -> not(List.mem t shared)) trips' in
667 (trips,shared,trips')
668 else (trips,[],trips') in
669 foldl (* returns a set - setify inlined *)
670 (function rest ->
671 function (s1,th1,wit1) ->
672 foldl
673 (function rest ->
674 function (s2,th2,wit2) ->
675 if (s1 = s2) then
676 (match (conj_subst th1 th2) with
677 Some th ->
678 let t = (s1,th,union_wit wit1 wit2) in
679 if List.mem t rest then rest else t::rest
680 | _ -> rest)
681 else rest)
682 rest trips')
683 shared trips
684;;
685
686(* ignore the state in the right argument. always pretend it is the same as
687the left one *)
688(* env on right has to be a subset of env on left *)
689let triples_conj_none trips trips' =
690 let (trips,shared,trips') =
691 if false && !pTRIPLES_CONJ_OPT (* see comment above *)
692 then
693 let (shared,trips) =
694 List.partition (function t -> List.mem t trips') trips in
695 let trips' =
696 List.filter (function t -> not(List.mem t shared)) trips' in
697 (trips,shared,trips')
698 else (trips,[],trips') in
699 foldl (* returns a set - setify inlined *)
700 (function rest ->
701 function (s1,th1,wit1) ->
702 foldl
703 (function rest ->
704 function (s2,th2,wit2) ->
705 match (conj_subst_none th1 th2) with
706 Some th ->
707 let t = (s1,th,union_wit wit1 wit2) in
708 if List.mem t rest then rest else t::rest
709 | _ -> rest)
710 rest trips')
711 shared trips
712;;
713
714exception AW
715
716let triples_conj_AW trips trips' =
717 let (trips,shared,trips') =
718 if false && !pTRIPLES_CONJ_OPT
719 then
720 let (shared,trips) =
721 List.partition (function t -> List.mem t trips') trips in
722 let trips' =
723 List.filter (function t -> not(List.mem t shared)) trips' in
724 (trips,shared,trips')
725 else (trips,[],trips') in
726 foldl (* returns a set - setify inlined *)
727 (function rest ->
728 function (s1,th1,wit1) ->
729 foldl
730 (function rest ->
731 function (s2,th2,wit2) ->
732 if (s1 = s2) then
733 (match (conj_subst th1 th2) with
734 Some th ->
735 let t = (s1,th,union_wit wit1 wit2) in
736 if List.mem t rest then rest else t::rest
737 | _ -> raise AW)
738 else rest)
739 rest trips')
740 shared trips
741;;
742
743(* *************************** *)
744(* NEGATION (NegState style) *)
745(* *************************** *)
746
747(* Constructive negation at the state level *)
748type ('a) state =
749 PosState of 'a
750 | NegState of 'a list
751;;
752
753let compatible_states = function
754 (PosState s1, PosState s2) ->
755 if s1 = s2 then Some (PosState s1) else None
756 | (PosState s1, NegState s2) ->
757 if List.mem s1 s2 then None else Some (PosState s1)
758 | (NegState s1, PosState s2) ->
759 if List.mem s2 s1 then None else Some (PosState s2)
760 | (NegState s1, NegState s2) -> Some (NegState (s1 @ s2))
761;;
762
763(* Conjunction on triples with "special states" *)
764let triples_state_conj trips trips' =
765 let (trips,shared,trips') =
766 if !pTRIPLES_CONJ_OPT
767 then
768 let (shared,trips) =
769 List.partition (function t -> List.mem t trips') trips in
770 let trips' =
771 List.filter (function t -> not(List.mem t shared)) trips' in
772 (trips,shared,trips')
773 else (trips,[],trips') in
774 foldl
775 (function rest ->
776 function (s1,th1,wit1) ->
777 foldl
778 (function rest ->
779 function (s2,th2,wit2) ->
780 match compatible_states(s1,s2) with
781 Some s ->
782 (match (conj_subst th1 th2) with
783 Some th ->
784 let t = (s,th,union_wit wit1 wit2) in
785 if List.mem t rest then rest else t::rest
786 | _ -> rest)
787 | _ -> rest)
788 rest trips')
789 shared trips
790;;
791
792let triple_negate (s,th,wits) =
793 let negstates = (NegState [s],top_subst,top_wit) in
794 let negths = map (fun th -> (PosState s,th,top_wit)) (negate_subst th) in
795 let negwits = map (fun nwit -> (PosState s,th,nwit)) (negate_wits wits) in
796 negstates :: (negths @ negwits) (* all different *)
797
798(* FIX ME: it is not necessary to do full conjunction *)
799let triples_complement states (trips : ('pred, 'anno) triples) =
800 if !pTRIPLES_COMPLEMENT_OPT
801 then
802 (let cleanup (s,th,wit) =
803 match s with
804 PosState s' -> [(s',th,wit)]
805 | NegState ss ->
806 assert (th=top_subst);
807 assert (wit=top_wit);
808 map (fun st -> (st,top_subst,top_wit)) (setdiff states ss) in
809 let (simple,complex) =
810 if !pTRIPLES_COMPLEMENT_SIMPLE_OPT
811 then
812 let (simple,complex) =
813 List.partition (function (s,[],[]) -> true | _ -> false) trips in
814 let simple =
815 [(NegState(List.map (function (s,_,_) -> s) simple),
816 top_subst,top_wit)] in
817 (simple,complex)
818 else ([(NegState [],top_subst,top_wit)],trips) in
819 let rec compl trips =
820 match trips with
821 [] -> simple
822 | (t::ts) -> triples_state_conj (triple_negate t) (compl ts) in
823 let compld = (compl complex) in
824 let compld = concatmap cleanup compld in
825 compld)
826 else
827 let negstates (st,th,wits) =
828 map (function st -> (st,top_subst,top_wit)) (setdiff states [st]) in
829 let negths (st,th,wits) =
830 map (function th -> (st,th,top_wit)) (negate_subst th) in
831 let negwits (st,th,wits) =
832 map (function nwit -> (st,th,nwit)) (negate_wits wits) in
833 match trips with
834 [] -> map (function st -> (st,top_subst,top_wit)) states
835 | x::xs ->
836 setify
837 (foldl
838 (function prev ->
839 function cur ->
840 triples_conj (negstates cur @ negths cur @ negwits cur) prev)
841 (negstates x @ negths x @ negwits x) xs)
842;;
843
844let triple_negate (s,th,wits) =
845 let negths = map (fun th -> (s,th,top_wit)) (negate_subst th) in
846 let negwits = map (fun nwit -> (s,th,nwit)) (negate_wits wits) in
847 ([s], negths @ negwits) (* all different *)
848
849let print_compl_state str (n,p) =
850 Printf.printf "%s neg: " str;
851 List.iter
852 (function x -> G.print_node x; Format.print_flush(); Printf.printf " ")
853 n;
854 Printf.printf "\n";
855 print_state "pos" p
856
857let triples_complement states (trips : ('pred, 'anno) triples) =
858 if trips = []
859 then map (function st -> (st,top_subst,top_wit)) states
860 else
861 let cleanup (neg,pos) =
862 let keep_pos =
863 List.filter (function (s,_,_) -> List.mem s neg) pos in
864 (map (fun st -> (st,top_subst,top_wit)) (setdiff states neg)) @
865 keep_pos in
866 let trips = List.sort state_compare trips in
867 let all_negated = List.map triple_negate trips in
868 let merge_one (neg1,pos1) (neg2,pos2) =
869 let (pos1conj,pos1keep) =
870 List.partition (function (s,_,_) -> List.mem s neg2) pos1 in
871 let (pos2conj,pos2keep) =
872 List.partition (function (s,_,_) -> List.mem s neg1) pos2 in
873 (Common.union_set neg1 neg2,
874 (triples_conj pos1conj pos2conj) @ pos1keep @ pos2keep) in
875 let rec inner_loop = function
876 x1::x2::rest -> (merge_one x1 x2) :: (inner_loop rest)
877 | l -> l in
878 let rec outer_loop = function
879 [x] -> x
880 | l -> outer_loop (inner_loop l) in
881 cleanup (outer_loop all_negated)
882
883(* ********************************** *)
884(* END OF NEGATION (NegState style) *)
885(* ********************************** *)
886
887(* now this is always true, so we could get rid of it *)
888let something_dropped = ref true
889
890let triples_union trips trips' =
891 (*unionBy compare eq_trip trips trips';;*)
892 (* returns -1 is t1 > t2, 1 if t2 >= t1, and 0 otherwise *)
893(*
894The following does not work. Suppose we have ([x->3],{A}) and ([],{A,B}).
895Then, the following says that since the first is a more restrictive
896environment and has fewer witnesses, then it should be dropped. But having
897fewer witnesses is not necessarily less informative than having more,
898because fewer witnesses can mean the absence of the witness-causing thing.
899So the fewer witnesses have to be kept around.
900subseteq changed to = to make it hopefully work
901*)
902 if !pNEW_INFO_OPT
903 then
904 begin
905 something_dropped := false;
906 if trips = trips'
907 then (something_dropped := true; trips)
908 else
909 let subsumes (s1,th1,wit1) (s2,th2,wit2) =
910 if s1 = s2
911 then
912 (match conj_subst th1 th2 with
913 Some conj ->
914 if conj = th1
915 then if (*subseteq*) wit1 = wit2 then 1 else 0
916 else
917 if conj = th2
918 then if (*subseteq*) wit2 = wit1 then (-1) else 0
919 else 0
920 | None -> 0)
921 else 0 in
922 let rec first_loop second = function
923 [] -> second
924 | x::xs -> first_loop (second_loop x second) xs
925 and second_loop x = function
926 [] -> [x]
927 | (y::ys) as all ->
928 match subsumes x y with
929 1 -> something_dropped := true; all
930 | (-1) -> second_loop x ys
931 | _ -> y::(second_loop x ys) in
932 first_loop trips trips'
933 end
934 else unionBy compare eq_trip trips trips'
935
936
937let triples_witness x unchecked not_keep trips =
938 let anyneg = (* if any is neg, then all are *)
939 List.exists (function A.NegSubst _ -> true | A.Subst _ -> false) in
940 let anynegwit = (* if any is neg, then all are *)
941 List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in
942 let allnegwit = (* if any is neg, then all are *)
943 List.for_all (function A.NegWit _ -> true | A.Wit _ -> false) in
944 let negtopos =
945 List.map (function A.NegWit w -> w | A.Wit _ -> failwith "bad wit")in
946 let res =
947 List.fold_left
948 (function prev ->
949 function (s,th,wit) as t ->
950 let (th_x,newth) = split_subst th x in
951 match th_x with
952 [] ->
953 (* one consider whether if not not_keep is true, then we should
954 fail. but it could be that the variable is a used_after and
955 then it is the later rule that should fail and not this one *)
956 if not not_keep && !Flag_ctl.verbose_ctl_engine
957 then
958 (SUB.print_mvar x; Format.print_flush();
959 print_state ": empty witness from" [t]);
960 t::prev
961 | l when anyneg l && !pANY_NEG_OPT -> prev
962 (* see tests/nestseq for how neg bindings can come up even
963 without eg partial matches
964 (* negated substitution only allowed with negwits.
965 just dropped *)
966 if anynegwit wit && allnegwit wit (* nonempty negwit list *)
967 then prev
968 else
969 (print_generic_substitution l; Format.print_newline();
970 failwith"unexpected negative binding with positive witnesses")*)
971 | _ ->
972 let new_triple =
973 if unchecked or not_keep
974 then (s,newth,wit)
975 else
976 if anynegwit wit && allnegwit wit
977 then (s,newth,[A.NegWit(A.Wit(s,th_x,[],negtopos wit))])
978 else (s,newth,[A.Wit(s,th_x,[],wit)]) in
979 new_triple::prev)
980 [] trips in
981 if unchecked || !Flag_ctl.partial_match (* the only way to have a NegWit *)
982 then setify res
983 else List.rev res
984;;
985
986
987(* ---------------------------------------------------------------------- *)
988(* SAT - Model Checking Algorithm for CTL-FVex *)
989(* *)
990(* TODO: Implement _all_ operators (directly) *)
991(* ---------------------------------------------------------------------- *)
992
993
994(* ************************************* *)
995(* The SAT algorithm and special helpers *)
996(* ************************************* *)
997
998let rec pre_exist dir (grp,_,_) y reqst =
999 let check s =
1000 match reqst with None -> true | Some reqst -> List.mem s reqst in
1001 let exp (s,th,wit) =
1002 concatmap
1003 (fun s' -> if check s' then [(s',th,wit)] else [])
1004 (match dir with
1005 A.FORWARD -> G.predecessors grp s
1006 | A.BACKWARD -> G.successors grp s) in
1007 setify (concatmap exp y)
1008;;
1009
1010exception Empty
1011
1012let pre_forall dir (grp,_,states) y all reqst =
1013 let check s =
1014 match reqst with
1015 None -> true | Some reqst -> List.mem s reqst in
1016 let pred =
1017 match dir with
1018 A.FORWARD -> G.predecessors | A.BACKWARD -> G.successors in
1019 let succ =
1020 match dir with
1021 A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in
1022 let neighbors =
1023 List.map
1024 (function p -> (p,succ grp p))
1025 (setify
1026 (concatmap
1027 (function (s,_,_) -> List.filter check (pred grp s)) y)) in
1028 (* would a hash table be more efficient? *)
1029 let all = List.sort state_compare all in
1030 let rec up_nodes child s = function
1031 [] -> []
1032 | (s1,th,wit)::xs ->
1033 (match compare s1 child with
1034 -1 -> up_nodes child s xs
1035 | 0 -> (s,th,wit)::(up_nodes child s xs)
1036 | _ -> []) in
1037 let neighbor_triples =
1038 List.fold_left
1039 (function rest ->
1040 function (s,children) ->
1041 try
1042 (List.map
1043 (function child ->
1044 match up_nodes child s all with [] -> raise Empty | l -> l)
1045 children) :: rest
1046 with Empty -> rest)
1047 [] neighbors in
1048 match neighbor_triples with
1049 [] -> []
1050 | _ ->
1051 (*normalize*)
1052 (foldl1 (@) (List.map (foldl1 triples_conj) neighbor_triples))
1053
1054let pre_forall_AW dir (grp,_,states) y all reqst =
1055 let check s =
1056 match reqst with
1057 None -> true | Some reqst -> List.mem s reqst in
1058 let pred =
1059 match dir with
1060 A.FORWARD -> G.predecessors | A.BACKWARD -> G.successors in
1061 let succ =
1062 match dir with
1063 A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in
1064 let neighbors =
1065 List.map
1066 (function p -> (p,succ grp p))
1067 (setify
1068 (concatmap
1069 (function (s,_,_) -> List.filter check (pred grp s)) y)) in
1070 (* would a hash table be more efficient? *)
1071 let all = List.sort state_compare all in
1072 let rec up_nodes child s = function
1073 [] -> []
1074 | (s1,th,wit)::xs ->
1075 (match compare s1 child with
1076 -1 -> up_nodes child s xs
1077 | 0 -> (s,th,wit)::(up_nodes child s xs)
1078 | _ -> []) in
1079 let neighbor_triples =
1080 List.fold_left
1081 (function rest ->
1082 function (s,children) ->
1083 (List.map
1084 (function child ->
1085 match up_nodes child s all with [] -> raise AW | l -> l)
1086 children) :: rest)
1087 [] neighbors in
1088 match neighbor_triples with
1089 [] -> []
1090 | _ -> foldl1 (@) (List.map (foldl1 triples_conj_AW) neighbor_triples)
1091
1092(* drop_negwits will call setify *)
1093let satEX dir m s reqst = pre_exist dir m s reqst;;
1094
1095let satAX dir m s reqst = pre_forall dir m s s reqst
1096;;
1097
1098(* E[phi1 U phi2] == phi2 \/ (phi1 /\ EXE[phi1 U phi2]) *)
485bce71 1099let satEU dir ((_,_,states) as m) s1 s2 reqst print_graph =
978fd7e5
C
1100 (*Printf.printf "EU\n";
1101 let ctr = ref 0 in*)
34e49164
C
1102 inc satEU_calls;
1103 if s1 = []
1104 then s2
1105 else
1106 (*let ctr = ref 0 in*)
1107 if !pNEW_INFO_OPT
1108 then
1109 let rec f y new_info =
1110 inc_step();
1111 match new_info with
1112 [] -> y
1113 | new_info ->
978fd7e5
C
1114 (*ctr := !ctr + 1;
1115 print_graph y ctr;*)
34e49164
C
1116 let first = triples_conj s1 (pre_exist dir m new_info reqst) in
1117 let res = triples_union first y in
1118 let new_info = setdiff res y in
1119 (*Printf.printf "iter %d res %d new_info %d\n"
1120 !ctr (List.length res) (List.length new_info);
978fd7e5
C
1121 print_state "res" res;
1122 print_state "new_info" new_info;
34e49164
C
1123 flush stdout;*)
1124 f res new_info in
1125 f s2 s2
1126 else
1127 let f y =
1128 inc_step();
978fd7e5
C
1129 (*ctr := !ctr + 1;
1130 print_graph y ctr;*)
34e49164
C
1131 let pre = pre_exist dir m y reqst in
1132 triples_union s2 (triples_conj s1 pre) in
1133 setfix f s2
1134;;
1135
1136(* EF phi == E[true U phi] *)
1137let satEF dir m s2 reqst =
1138 inc satEF_calls;
1139 (*let ctr = ref 0 in*)
1140 if !pNEW_INFO_OPT
1141 then
1142 let rec f y new_info =
1143 inc_step();
1144 match new_info with
1145 [] -> y
1146 | new_info ->
1147 (*ctr := !ctr + 1;
1148 print_state (Printf.sprintf "iteration %d\n" !ctr) y;*)
1149 let first = pre_exist dir m new_info reqst in
1150 let res = triples_union first y in
1151 let new_info = setdiff res y in
1152 (*Printf.printf "EF %s iter %d res %d new_info %d\n"
1153 (if dir = A.BACKWARD then "reachable" else "real ef")
1154 !ctr (List.length res) (List.length new_info);
1155 print_state "new info" new_info;
1156 flush stdout;*)
1157 f res new_info in
1158 f s2 s2
1159 else
1160 let f y =
1161 inc_step();
1162 let pre = pre_exist dir m y reqst in
1163 triples_union s2 pre in
1164 setfix f s2
1165
1166
1167type ('pred,'anno) auok =
1168 AUok of ('pred,'anno) triples | AUfailed of ('pred,'anno) triples
1169
1170(* A[phi1 U phi2] == phi2 \/ (phi1 /\ AXA[phi1 U phi2]) *)
485bce71
C
1171let satAU dir ((cfg,_,states) as m) s1 s2 reqst print_graph =
1172 let ctr = ref 0 in
34e49164
C
1173 inc satAU_calls;
1174 if s1 = []
1175 then AUok s2
1176 else
1177 (*let ctr = ref 0 in*)
1178 let pre_forall =
1179 if !Flag_ctl.loop_in_src_code
1180 then pre_forall_AW
1181 else pre_forall in
1182 if !pNEW_INFO_OPT
1183 then
1184 let rec f y newinfo =
1185 inc_step();
1186 match newinfo with
1187 [] -> AUok y
1188 | new_info ->
485bce71
C
1189 ctr := !ctr + 1;
1190 (*print_state (Printf.sprintf "iteration %d\n" !ctr) y;
34e49164 1191 flush stdout;*)
485bce71 1192 print_graph y ctr;
34e49164
C
1193 let pre =
1194 try Some (pre_forall dir m new_info y reqst)
1195 with AW -> None in
1196 match pre with
1197 None -> AUfailed y
1198 | Some pre ->
1199 match triples_conj s1 pre with
1200 [] -> AUok y
1201 | first ->
1202 (*print_state "s1" s1;
1203 print_state "pre" pre;
1204 print_state "first" first;*)
1205 let res = triples_union first y in
1206 let new_info =
1207 if not !something_dropped
1208 then first
1209 else setdiff res y in
1210 (*Printf.printf
1211 "iter %d res %d new_info %d\n"
1212 !ctr (List.length res) (List.length new_info);
1213 flush stdout;*)
1214 f res new_info in
1215 f s2 s2
1216 else
1217 if !Flag_ctl.loop_in_src_code
1218 then AUfailed s2
1219 else
1220 (*let setfix =
1221 fix (function s1 -> function s2 ->
1222 let s1 = List.map (function (s,th,w) -> (s,th,nub w)) s1 in
1223 let s2 = List.map (function (s,th,w) -> (s,th,nub w)) s2 in
1224 subseteq s1 s2) in for popl *)
1225 let f y =
1226 inc_step();
485bce71
C
1227 ctr := !ctr + 1;
1228 print_graph y ctr;
34e49164
C
1229 let pre = pre_forall dir m y y reqst in
1230 triples_union s2 (triples_conj s1 pre) in
1231 AUok (setfix f s2)
1232;;
1233
1234
1235(* reqst could be the states of s1 *)
1236 (*
1237 let lstates = mkstates states reqst in
1238 let initial_removed =
1239 triples_complement lstates (triples_union s1 s2) in
1240 let initial_base = triples_conj s1 (triples_complement lstates s2) in
1241 let rec loop base removed =
1242 let new_removed =
1243 triples_conj base (pre_exist dir m removed reqst) in
1244 let new_base =
1245 triples_conj base (triples_complement lstates new_removed) in
1246 if supseteq new_base base
1247 then triples_union base s2
1248 else loop new_base new_removed in
1249 loop initial_base initial_removed *)
1250
1251let satAW dir ((grp,_,states) as m) s1 s2 reqst =
1252 inc satAW_calls;
1253 if s1 = []
1254 then s2
1255 else
1256 (*
1257 This works extremely badly when the region is small and the end of the
1258 region is very ambiguous, eg free(x) ... x
1259 see free.c
1260 if !pNEW_INFO_OPT
1261 then
1262 let get_states l = setify(List.map (function (s,_,_) -> s) l) in
1263 let ostates = Common.union_set (get_states s1) (get_states s2) in
1264 let succ =
1265 (match dir with
1266 A.FORWARD -> G.successors grp
1267 | A.BACKWARD -> G.predecessors grp) in
1268 let states =
1269 List.fold_left Common.union_set ostates (List.map succ ostates) in
1270 let negphi = triples_complement states s1 in
1271 let negpsi = triples_complement states s2 in
1272 triples_complement ostates
1273 (satEU dir m negpsi (triples_conj negphi negpsi) (Some ostates))
1274 else
1275 *)
1276 (*let ctr = ref 0 in*)
1277 let f y =
1278 inc_step();
1279 (*ctr := !ctr + 1;
1280 Printf.printf "iter %d y %d\n" !ctr (List.length y);
1281 print_state "y" y;
1282 flush stdout;*)
1283 let pre = pre_forall dir m y y reqst in
978fd7e5 1284 (*print_state "pre" pre;*)
34e49164
C
1285 let conj = triples_conj s1 pre in (* or triples_conj_AW *)
1286 triples_union s2 conj in
978fd7e5
C
1287 let drop_wits = List.map (function (s,e,_) -> (s,e,[])) in
1288 (* drop wits on s1 represents that we don't want any witnesses from
1289 the case that infinitely loops, only from the case that gets
1290 out of the loop. s1 is like a guard. To see the problem, consider
1291 an example where both s1 and s2 match some code after the loop.
1292 we only want the witness from s2. *)
fc1ad971 1293 setgfix f (triples_union (nub(drop_wits s1)) s2)
34e49164
C
1294;;
1295
1296let satAF dir m s reqst =
1297 inc satAF_calls;
1298 if !pNEW_INFO_OPT
1299 then
1300 let rec f y newinfo =
1301 inc_step();
1302 match newinfo with
1303 [] -> y
1304 | new_info ->
1305 let first = pre_forall dir m new_info y reqst in
1306 let res = triples_union first y in
1307 let new_info = setdiff res y in
1308 f res new_info in
1309 f s s
1310 else
1311 let f y =
1312 inc_step();
1313 let pre = pre_forall dir m y y reqst in
1314 triples_union s pre in
1315 setfix f s
1316
1317let satAG dir ((_,_,states) as m) s reqst =
1318 inc satAG_calls;
1319 let f y =
1320 inc_step();
1321 let pre = pre_forall dir m y y reqst in
1322 triples_conj y pre in
1323 setgfix f s
1324
1325let satEG dir ((_,_,states) as m) s reqst =
1326 inc satEG_calls;
1327 let f y =
1328 inc_step();
1329 let pre = pre_exist dir m y reqst in
1330 triples_conj y pre in
1331 setgfix f s
1332
1333(* **************************************************************** *)
1334(* Inner And - a way of dealing with multiple matches within a node *)
1335(* **************************************************************** *)
1336(* applied to the result of matching a node. collect witnesses when the
1337states and environments are the same *)
1338
1339let inner_and trips =
1340 let rec loop = function
1341 [] -> ([],[])
1342 | (s,th,w)::trips ->
1343 let (cur,acc) = loop trips in
1344 (match cur with
1345 (s',_,_)::_ when s = s' ->
1346 let rec loop' = function
1347 [] -> [(s,th,w)]
1348 | ((_,th',w') as t')::ts' ->
1349 (match conj_subst th th' with
1350 Some th'' -> (s,th'',union_wit w w')::ts'
1351 | None -> t'::(loop' ts')) in
1352 (loop' cur,acc)
1353 | _ -> ([(s,th,w)],cur@acc)) in
1354 let (cur,acc) =
1355 loop (List.sort state_compare trips) (* is this sort needed? *) in
1356 cur@acc
1357
1358(* *************** *)
1359(* Partial matches *)
1360(* *************** *)
1361
1362let filter_conj states unwanted partial_matches =
1363 let x =
1364 triples_conj (triples_complement states (unwitify unwanted))
1365 partial_matches in
1366 triples_conj (unwitify x) (triples_complement states x)
1367
1368let strict_triples_conj strict states trips trips' =
1369 let res = triples_conj trips trips' in
1370 if !Flag_ctl.partial_match && strict = A.STRICT
1371 then
1372 let fail_left = filter_conj states trips trips' in
1373 let fail_right = filter_conj states trips' trips in
1374 let ors = triples_union fail_left fail_right in
1375 triples_union res ors
1376 else res
1377
1378let strict_triples_conj_none strict states trips trips' =
1379 let res = triples_conj_none trips trips' in
1380 if !Flag_ctl.partial_match && strict = A.STRICT
1381 then
1382 let fail_left = filter_conj states trips trips' in
1383 let fail_right = filter_conj states trips' trips in
1384 let ors = triples_union fail_left fail_right in
1385 triples_union res ors
1386 else res
1387
1388let left_strict_triples_conj strict states trips trips' =
1389 let res = triples_conj trips trips' in
1390 if !Flag_ctl.partial_match && strict = A.STRICT
1391 then
1392 let fail_left = filter_conj states trips trips' in
1393 triples_union res fail_left
1394 else res
1395
1396let strict_A1 strict op failop dir ((_,_,states) as m) trips required_states =
1397 let res = op dir m trips required_states in
1398 if !Flag_ctl.partial_match && strict = A.STRICT
1399 then
1400 let states = mkstates states required_states in
1401 let fail = filter_conj states res (failop dir m trips required_states) in
1402 triples_union res fail
1403 else res
1404
1405let strict_A2 strict op failop dir ((_,_,states) as m) trips trips'
1406 required_states =
1407 let res = op dir m trips trips' required_states in
1408 if !Flag_ctl.partial_match && strict = A.STRICT
1409 then
1410 let states = mkstates states required_states in
1411 let fail = filter_conj states res (failop dir m trips' required_states) in
1412 triples_union res fail
1413 else res
1414
1415let strict_A2au strict op failop dir ((_,_,states) as m) trips trips'
485bce71
C
1416 required_states print_graph =
1417 match op dir m trips trips' required_states print_graph with
34e49164
C
1418 AUok res ->
1419 if !Flag_ctl.partial_match && strict = A.STRICT
1420 then
1421 let states = mkstates states required_states in
1422 let fail =
1423 filter_conj states res (failop dir m trips' required_states) in
1424 AUok (triples_union res fail)
1425 else AUok res
1426 | AUfailed res -> AUfailed res
1427
1428(* ********************* *)
1429(* Environment functions *)
1430(* ********************* *)
1431
1432let drop_wits required_states s phi =
1433 match required_states with
1434 None -> s
1435 | Some states -> List.filter (function (s,_,_) -> List.mem s states) s
1436
1437
1438let print_required required =
1439 List.iter
1440 (function l ->
1441 Format.print_string "{";
1442 List.iter
1443 (function reqd ->
1444 print_generic_substitution reqd; Format.print_newline())
1445 l;
1446 Format.print_string "}";
1447 Format.print_newline())
1448 required
1449
1450exception Too_long
1451
1452let extend_required trips required =
1453 if !Flag_ctl.partial_match
1454 then required
1455 else
1456 if !pREQUIRED_ENV_OPT
1457 then
1458 (* make it a set *)
1459 let envs =
1460 List.fold_left
1461 (function rest ->
1462 function (_,t,_) -> if List.mem t rest then rest else t::rest)
1463 [] trips in
1464 let envs = if List.mem [] envs then [] else envs in
1465 match (envs,required) with
1466 ([],_) -> required
1467 | (envs,hd::tl) ->
1468 (try
1469 let hdln = List.length hd + 5 (* let it grow a little bit *) in
1470 let (_,merged) =
1471 let add x (ln,y) =
1472 if List.mem x y
1473 then (ln,y)
1474 else if ln + 1 > hdln then raise Too_long else (ln+1,x::y) in
1475 foldl
1476 (function rest ->
1477 function t ->
1478 foldl
1479 (function rest ->
1480 function r ->
1481 match conj_subst t r with
1482 None -> rest | Some th -> add th rest)
1483 rest hd)
1484 (0,[]) envs in
1485 merged :: tl
1486 with Too_long -> envs :: required)
1487 | (envs,_) -> envs :: required
1488 else required
1489
1490let drop_required v required =
1491 if !pREQUIRED_ENV_OPT
1492 then
1493 let res =
1494 inner_setify
1495 (List.map
1496 (function l ->
1497 inner_setify
1498 (List.map (List.filter (function sub -> not(dom_sub sub = v))) l))
1499 required) in
1500 (* check whether an entry has become useless *)
1501 List.filter (function l -> not (List.exists (function x -> x = []) l)) res
1502 else required
1503
1504(* no idea how to write this function ... *)
1505let memo_label =
1506 (Hashtbl.create(50) : (P.t, (G.node * substitution) list) Hashtbl.t)
1507
1508let satLabel label required p =
1509 let triples =
1510 if !pSATLABEL_MEMO_OPT
1511 then
1512 try
1513 let states_subs = Hashtbl.find memo_label p in
1514 List.map (function (st,th) -> (st,th,[])) states_subs
1515 with
1516 Not_found ->
1517 let triples = setify(label p) in
1518 Hashtbl.add memo_label p
1519 (List.map (function (st,th,_) -> (st,th)) triples);
1520 triples
1521 else setify(label p) in
1522 normalize
1523 (if !pREQUIRED_ENV_OPT
1524 then
1525 foldl
1526 (function rest ->
1527 function ((s,th,_) as t) ->
1528 if List.for_all
1529 (List.exists (function th' -> not(conj_subst th th' = None)))
1530 required
1531 then t::rest
1532 else rest)
1533 [] triples
1534 else triples)
1535
1536let get_required_states l =
1537 if !pREQUIRED_STATES_OPT && not !Flag_ctl.partial_match
1538 then
1539 Some(inner_setify (List.map (function (s,_,_) -> s) l))
1540 else None
1541
1542let get_children_required_states dir (grp,_,_) required_states =
1543 if !pREQUIRED_STATES_OPT && not !Flag_ctl.partial_match
1544 then
1545 match required_states with
1546 None -> None
1547 | Some states ->
1548 let fn =
1549 match dir with
1550 A.FORWARD -> G.successors
1551 | A.BACKWARD -> G.predecessors in
1552 Some (inner_setify (List.concat (List.map (fn grp) states)))
1553 else None
1554
1555let reachable_table =
1556 (Hashtbl.create(50) : (G.node * A.direction, G.node list) Hashtbl.t)
1557
1558(* like satEF, but specialized for get_reachable *)
1559let reachsatEF dir (grp,_,_) s2 =
1560 let dirop =
1561 match dir with A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in
1562 let union = unionBy compare (=) in
1563 let rec f y = function
1564 [] -> y
1565 | new_info ->
1566 let (pre_collected,new_info) =
1567 List.partition (function Common.Left x -> true | _ -> false)
1568 (List.map
1569 (function x ->
1570 try Common.Left (Hashtbl.find reachable_table (x,dir))
1571 with Not_found -> Common.Right x)
1572 new_info) in
1573 let y =
1574 List.fold_left
1575 (function rest ->
1576 function Common.Left x -> union x rest
1577 | _ -> failwith "not possible")
1578 y pre_collected in
1579 let new_info =
1580 List.map
1581 (function Common.Right x -> x | _ -> failwith "not possible")
1582 new_info in
1583 let first = inner_setify (concatmap (dirop grp) new_info) in
1584 let new_info = setdiff first y in
1585 let res = new_info @ y in
1586 f res new_info in
1587 List.rev(f s2 s2) (* put root first *)
1588
1589let get_reachable dir m required_states =
1590 match required_states with
1591 None -> None
1592 | Some states ->
1593 Some
1594 (List.fold_left
1595 (function rest ->
1596 function cur ->
1597 if List.mem cur rest
1598 then rest
1599 else
1600 Common.union_set
1601 (try Hashtbl.find reachable_table (cur,dir)
1602 with
1603 Not_found ->
1604 let states = reachsatEF dir m [cur] in
1605 Hashtbl.add reachable_table (cur,dir) states;
1606 states)
1607 rest)
1608 [] states)
1609
1610let ctr = ref 0
1611let new_var _ =
1612 let c = !ctr in
1613 ctr := !ctr + 1;
1614 Printf.sprintf "_c%d" c
1615
1616(* **************************** *)
1617(* End of environment functions *)
1618(* **************************** *)
1619
1620type ('code,'value) cell = Frozen of 'code | Thawed of 'value
1621
1622let rec satloop unchecked required required_states
1623 ((grp,label,states) as m) phi env =
1624 let rec loop unchecked required required_states phi =
1625 (*Common.profile_code "satloop" (fun _ -> *)
1626 let res =
1627 match phi with
1628 A.False -> []
1629 | A.True -> triples_top states
1630 | A.Pred(p) -> satLabel label required p
1631 | A.Uncheck(phi1) ->
1632 let unchecked = if !pUNCHECK_OPT then true else false in
1633 loop unchecked required required_states phi1
1634 | A.Not(phi) ->
1635 let phires = loop unchecked required required_states phi in
1636 (*let phires =
1637 List.map (function (s,th,w) -> (s,th,[])) phires in*)
1638 triples_complement (mkstates states required_states)
1639 phires
1640 | A.Or(phi1,phi2) ->
1641 triples_union
1642 (loop unchecked required required_states phi1)
1643 (loop unchecked required required_states phi2)
1644 | A.SeqOr(phi1,phi2) ->
1645 let res1 = loop unchecked required required_states phi1 in
1646 let res2 = loop unchecked required required_states phi2 in
1647 let res1neg = unwitify res1 in
1648 triples_union res1
1649 (triples_conj
1650 (triples_complement (mkstates states required_states) res1neg)
1651 res2)
1652 | A.And(strict,phi1,phi2) ->
1653 (* phi1 is considered to be more likely to be [], because of the
1654 definition of asttoctl. Could use heuristics such as the size of
1655 the term *)
1656 let pm = !Flag_ctl.partial_match in
1657 (match (pm,loop unchecked required required_states phi1) with
1658 (false,[]) when !pLazyOpt -> []
1659 | (_,phi1res) ->
1660 let new_required = extend_required phi1res required in
1661 let new_required_states = get_required_states phi1res in
1662 (match (pm,loop unchecked new_required new_required_states phi2)
1663 with
1664 (false,[]) when !pLazyOpt -> []
1665 | (_,phi2res) ->
1666 strict_triples_conj strict
1667 (mkstates states required_states)
1668 phi1res phi2res))
1669 | A.AndAny(dir,strict,phi1,phi2) ->
1670 (* phi2 can appear anywhere that is reachable *)
1671 let pm = !Flag_ctl.partial_match in
1672 (match (pm,loop unchecked required required_states phi1) with
1673 (false,[]) -> []
1674 | (_,phi1res) ->
1675 let new_required = extend_required phi1res required in
1676 let new_required_states = get_required_states phi1res in
1677 let new_required_states =
1678 get_reachable dir m new_required_states in
1679 (match (pm,loop unchecked new_required new_required_states phi2)
1680 with
1681 (false,[]) -> phi1res
1682 | (_,phi2res) ->
1683 (match phi1res with
1684 [] -> (* !Flag_ctl.partial_match must be true *)
1685 if phi2res = []
1686 then []
1687 else
1688 let s = mkstates states required_states in
1689 List.fold_left
1690 (function a -> function b ->
1691 strict_triples_conj strict s a [b])
1692 [List.hd phi2res] (List.tl phi2res)
1693 | [(state,_,_)] ->
1694 let phi2res =
1695 List.map (function (s,e,w) -> [(state,e,w)]) phi2res in
1696 let s = mkstates states required_states in
1697 List.fold_left
1698 (function a -> function b ->
1699 strict_triples_conj strict s a b)
1700 phi1res phi2res
1701 | _ ->
1702 failwith
1703 "only one result allowed for the left arg of AndAny")))
1704 | A.HackForStmt(dir,strict,phi1,phi2) ->
1705 (* phi2 can appear anywhere that is reachable *)
1706 let pm = !Flag_ctl.partial_match in
1707 (match (pm,loop unchecked required required_states phi1) with
1708 (false,[]) -> []
1709 | (_,phi1res) ->
1710 let new_required = extend_required phi1res required in
1711 let new_required_states = get_required_states phi1res in
1712 let new_required_states =
1713 get_reachable dir m new_required_states in
1714 (match (pm,loop unchecked new_required new_required_states phi2)
1715 with
1716 (false,[]) -> phi1res
1717 | (_,phi2res) ->
1718 (* if there is more than one state, something about the
1719 environment has to ensure that the right triples of
1720 phi2 get associated with the triples of phi1.
1721 the asttoctl2 has to ensure that that is the case.
1722 these should thus be structural properties.
1723 env of phi2 has to be a proper subset of env of phi1
1724 to ensure all end up being consistent. no new triples
1725 should be generated. strict_triples_conj_none takes
1726 care of this.
1727 *)
1728 let s = mkstates states required_states in
1729 List.fold_left
1730 (function acc ->
1731 function (st,th,_) as phi2_elem ->
1732 let inverse =
1733 triples_complement [st] [(st,th,[])] in
1734 strict_triples_conj_none strict s acc
1735 (phi2_elem::inverse))
1736 phi1res phi2res))
1737 | A.InnerAnd(phi) ->
1738 inner_and(loop unchecked required required_states phi)
1739 | A.EX(dir,phi) ->
1740 let new_required_states =
1741 get_children_required_states dir m required_states in
1742 satEX dir m (loop unchecked required new_required_states phi)
1743 required_states
1744 | A.AX(dir,strict,phi) ->
1745 let new_required_states =
1746 get_children_required_states dir m required_states in
1747 let res = loop unchecked required new_required_states phi in
1748 strict_A1 strict satAX satEX dir m res required_states
1749 | A.EF(dir,phi) ->
1750 let new_required_states = get_reachable dir m required_states in
1751 satEF dir m (loop unchecked required new_required_states phi)
1752 new_required_states
1753 | A.AF(dir,strict,phi) ->
1754 if !Flag_ctl.loop_in_src_code
1755 then
1756 loop unchecked required required_states
1757 (A.AU(dir,strict,A.True,phi))
1758 else
1759 let new_required_states = get_reachable dir m required_states in
1760 let res = loop unchecked required new_required_states phi in
1761 strict_A1 strict satAF satEF dir m res new_required_states
1762 | A.EG(dir,phi) ->
1763 let new_required_states = get_reachable dir m required_states in
1764 satEG dir m (loop unchecked required new_required_states phi)
1765 new_required_states
1766 | A.AG(dir,strict,phi) ->
1767 let new_required_states = get_reachable dir m required_states in
1768 let res = loop unchecked required new_required_states phi in
1769 strict_A1 strict satAG satEF dir m res new_required_states
1770 | A.EU(dir,phi1,phi2) ->
1771 let new_required_states = get_reachable dir m required_states in
1772 (match loop unchecked required new_required_states phi2 with
1773 [] when !pLazyOpt -> []
1774 | s2 ->
1775 let new_required = extend_required s2 required in
1776 let s1 = loop unchecked new_required new_required_states phi1 in
485bce71
C
1777 satEU dir m s1 s2 new_required_states
1778 (fun y ctr -> print_graph_c grp new_required_states y ctr phi))
34e49164
C
1779 | A.AW(dir,strict,phi1,phi2) ->
1780 let new_required_states = get_reachable dir m required_states in
1781 (match loop unchecked required new_required_states phi2 with
1782 [] when !pLazyOpt -> []
1783 | s2 ->
1784 let new_required = extend_required s2 required in
1785 let s1 = loop unchecked new_required new_required_states phi1 in
1786 strict_A2 strict satAW satEF dir m s1 s2 new_required_states)
1787 | A.AU(dir,strict,phi1,phi2) ->
1788 (*Printf.printf "using AU\n"; flush stdout;*)
1789 let new_required_states = get_reachable dir m required_states in
1790 (match loop unchecked required new_required_states phi2 with
1791 [] when !pLazyOpt -> []
1792 | s2 ->
1793 let new_required = extend_required s2 required in
1794 let s1 = loop unchecked new_required new_required_states phi1 in
1795 let res =
485bce71
C
1796 strict_A2au strict satAU satEF dir m s1 s2 new_required_states
1797 (fun y ctr ->
1798 print_graph_c grp new_required_states y ctr phi) in
34e49164
C
1799 match res with
1800 AUok res -> res
1801 | AUfailed tmp_res ->
1802 (* found a loop, have to try AW *)
1803 (* the formula is
1804 A[E[phi1 U phi2] & phi1 W phi2]
1805 the and is nonstrict *)
1806 (* tmp_res is bigger than s2, so perhaps closer to s1 *)
1807 (*Printf.printf "using AW\n"; flush stdout;*)
1808 let s1 =
485bce71
C
1809 triples_conj
1810 (satEU dir m s1 tmp_res new_required_states
1811 (* no graph, for the moment *)
1812 (fun y str -> ()))
34e49164 1813 s1 in
978fd7e5
C
1814 strict_A2 strict satAW satEF dir m s1 s2 new_required_states
1815 )
34e49164
C
1816 | A.Implies(phi1,phi2) ->
1817 loop unchecked required required_states (A.Or(A.Not phi1,phi2))
1818 | A.Exists (keep,v,phi) ->
1819 let new_required = drop_required v required in
1820 triples_witness v unchecked (not keep)
1821 (loop unchecked new_required required_states phi)
1822 | A.Let(v,phi1,phi2) ->
1823 (* should only be used when the properties unchecked, required,
1824 and required_states are known to be the same or at least
1825 compatible between all the uses. this is not checked. *)
1826 let res = loop unchecked required required_states phi1 in
1827 satloop unchecked required required_states m phi2 ((v,res) :: env)
1828 | A.LetR(dir,v,phi1,phi2) ->
1829 (* should only be used when the properties unchecked, required,
1830 and required_states are known to be the same or at least
1831 compatible between all the uses. this is not checked. *)
485bce71 1832 (* doesn't seem to be used any more *)
34e49164
C
1833 let new_required_states = get_reachable dir m required_states in
1834 let res = loop unchecked required new_required_states phi1 in
1835 satloop unchecked required required_states m phi2 ((v,res) :: env)
1836 | A.Ref(v) ->
1837 let res = List.assoc v env in
1838 if unchecked
1839 then List.map (function (s,th,_) -> (s,th,[])) res
1840 else res
1841 | A.XX(phi) -> failwith "should have been removed" in
1842 if !Flag_ctl.bench > 0 then triples := !triples + (List.length res);
485bce71
C
1843 let res = drop_wits required_states res phi (* ) *) in
1844 print_graph grp required_states res "" phi;
1845 res in
34e49164
C
1846
1847 loop unchecked required required_states phi
1848;;
1849
1850
1851(* SAT with tracking *)
1852let rec sat_verbose_loop unchecked required required_states annot maxlvl lvl
1853 ((_,label,states) as m) phi env =
1854 let anno res children = (annot lvl phi res children,res) in
1855 let satv unchecked required required_states phi0 env =
1856 sat_verbose_loop unchecked required required_states annot maxlvl (lvl+1)
1857 m phi0 env in
1858 if (lvl > maxlvl) && (maxlvl > -1) then
1859 anno (satloop unchecked required required_states m phi env) []
1860 else
1861 let (child,res) =
1862 match phi with
1863 A.False -> anno [] []
1864 | A.True -> anno (triples_top states) []
1865 | A.Pred(p) ->
1866 Printf.printf "label\n"; flush stdout;
1867 anno (satLabel label required p) []
1868 | A.Uncheck(phi1) ->
1869 let unchecked = if !pUNCHECK_OPT then true else false in
1870 let (child1,res1) = satv unchecked required required_states phi1 env in
1871 Printf.printf "uncheck\n"; flush stdout;
1872 anno res1 [child1]
1873 | A.Not(phi1) ->
1874 let (child,res) =
1875 satv unchecked required required_states phi1 env in
1876 Printf.printf "not\n"; flush stdout;
1877 anno (triples_complement (mkstates states required_states) res) [child]
1878 | A.Or(phi1,phi2) ->
1879 let (child1,res1) =
1880 satv unchecked required required_states phi1 env in
1881 let (child2,res2) =
1882 satv unchecked required required_states phi2 env in
1883 Printf.printf "or\n"; flush stdout;
1884 anno (triples_union res1 res2) [child1; child2]
1885 | A.SeqOr(phi1,phi2) ->
1886 let (child1,res1) =
1887 satv unchecked required required_states phi1 env in
1888 let (child2,res2) =
1889 satv unchecked required required_states phi2 env in
1890 let res1neg =
1891 List.map (function (s,th,_) -> (s,th,[])) res1 in
1892 Printf.printf "seqor\n"; flush stdout;
1893 anno (triples_union res1
1894 (triples_conj
1895 (triples_complement (mkstates states required_states)
1896 res1neg)
1897 res2))
1898 [child1; child2]
1899 | A.And(strict,phi1,phi2) ->
1900 let pm = !Flag_ctl.partial_match in
1901 (match (pm,satv unchecked required required_states phi1 env) with
1902 (false,(child1,[])) ->
1903 Printf.printf "and\n"; flush stdout; anno [] [child1]
1904 | (_,(child1,res1)) ->
1905 let new_required = extend_required res1 required in
1906 let new_required_states = get_required_states res1 in
1907 (match (pm,satv unchecked new_required new_required_states phi2
1908 env) with
1909 (false,(child2,[])) ->
1910 Printf.printf "and\n"; flush stdout; anno [] [child1;child2]
1911 | (_,(child2,res2)) ->
1912 Printf.printf "and\n"; flush stdout;
1913 let res =
1914 strict_triples_conj strict
1915 (mkstates states required_states)
1916 res1 res2 in
1917 anno res [child1; child2]))
1918 | A.AndAny(dir,strict,phi1,phi2) ->
1919 let pm = !Flag_ctl.partial_match in
1920 (match (pm,satv unchecked required required_states phi1 env) with
1921 (false,(child1,[])) ->
1922 Printf.printf "and\n"; flush stdout; anno [] [child1]
1923 | (_,(child1,res1)) ->
1924 let new_required = extend_required res1 required in
1925 let new_required_states = get_required_states res1 in
1926 let new_required_states =
1927 get_reachable dir m new_required_states in
1928 (match (pm,satv unchecked new_required new_required_states phi2
1929 env) with
1930 (false,(child2,[])) ->
1931 Printf.printf "andany\n"; flush stdout;
1932 anno res1 [child1;child2]
1933 | (_,(child2,res2)) ->
1934 (match res1 with
1935 [] -> (* !Flag_ctl.partial_match must be true *)
1936 if res2 = []
1937 then anno [] [child1; child2]
1938 else
1939 let res =
1940 let s = mkstates states required_states in
1941 List.fold_left
1942 (function a -> function b ->
1943 strict_triples_conj strict s a [b])
1944 [List.hd res2] (List.tl res2) in
1945 anno res [child1; child2]
1946 | [(state,_,_)] ->
1947 let res2 =
1948 List.map (function (s,e,w) -> [(state,e,w)]) res2 in
1949 Printf.printf "andany\n"; flush stdout;
1950 let res =
1951 let s = mkstates states required_states in
1952 List.fold_left
1953 (function a -> function b ->
1954 strict_triples_conj strict s a b)
1955 res1 res2 in
1956 anno res [child1; child2]
1957 | _ ->
1958 failwith
1959 "only one result allowed for the left arg of AndAny")))
1960 | A.HackForStmt(dir,strict,phi1,phi2) ->
1961 let pm = !Flag_ctl.partial_match in
1962 (match (pm,satv unchecked required required_states phi1 env) with
1963 (false,(child1,[])) ->
1964 Printf.printf "and\n"; flush stdout; anno [] [child1]
1965 | (_,(child1,res1)) ->
1966 let new_required = extend_required res1 required in
1967 let new_required_states = get_required_states res1 in
1968 let new_required_states =
1969 get_reachable dir m new_required_states in
1970 (match (pm,satv unchecked new_required new_required_states phi2
1971 env) with
1972 (false,(child2,[])) ->
1973 Printf.printf "andany\n"; flush stdout;
1974 anno res1 [child1;child2]
1975 | (_,(child2,res2)) ->
1976 let res =
1977 let s = mkstates states required_states in
1978 List.fold_left
1979 (function acc ->
1980 function (st,th,_) as phi2_elem ->
1981 let inverse =
1982 triples_complement [st] [(st,th,[])] in
1983 strict_triples_conj_none strict s acc
1984 (phi2_elem::inverse))
1985 res1 res2 in
1986 anno res [child1; child2]))
1987 | A.InnerAnd(phi1) ->
1988 let (child1,res1) = satv unchecked required required_states phi1 env in
1989 Printf.printf "uncheck\n"; flush stdout;
1990 anno (inner_and res1) [child1]
1991 | A.EX(dir,phi1) ->
1992 let new_required_states =
1993 get_children_required_states dir m required_states in
1994 let (child,res) =
1995 satv unchecked required new_required_states phi1 env in
1996 Printf.printf "EX\n"; flush stdout;
1997 anno (satEX dir m res required_states) [child]
1998 | A.AX(dir,strict,phi1) ->
1999 let new_required_states =
2000 get_children_required_states dir m required_states in
2001 let (child,res) =
2002 satv unchecked required new_required_states phi1 env in
2003 Printf.printf "AX\n"; flush stdout;
2004 let res = strict_A1 strict satAX satEX dir m res required_states in
2005 anno res [child]
2006 | A.EF(dir,phi1) ->
2007 let new_required_states = get_reachable dir m required_states in
2008 let (child,res) =
2009 satv unchecked required new_required_states phi1 env in
2010 Printf.printf "EF\n"; flush stdout;
2011 anno (satEF dir m res new_required_states) [child]
2012 | A.AF(dir,strict,phi1) ->
2013 if !Flag_ctl.loop_in_src_code
2014 then
2015 satv unchecked required required_states
2016 (A.AU(dir,strict,A.True,phi1))
2017 env
2018 else
2019 (let new_required_states = get_reachable dir m required_states in
2020 let (child,res) =
2021 satv unchecked required new_required_states phi1 env in
2022 Printf.printf "AF\n"; flush stdout;
2023 let res =
2024 strict_A1 strict satAF satEF dir m res new_required_states in
2025 anno res [child])
2026 | A.EG(dir,phi1) ->
2027 let new_required_states = get_reachable dir m required_states in
2028 let (child,res) =
2029 satv unchecked required new_required_states phi1 env in
2030 Printf.printf "EG\n"; flush stdout;
2031 anno (satEG dir m res new_required_states) [child]
2032 | A.AG(dir,strict,phi1) ->
2033 let new_required_states = get_reachable dir m required_states in
2034 let (child,res) =
2035 satv unchecked required new_required_states phi1 env in
2036 Printf.printf "AG\n"; flush stdout;
2037 let res = strict_A1 strict satAG satEF dir m res new_required_states in
2038 anno res [child]
2039
2040 | A.EU(dir,phi1,phi2) ->
2041 let new_required_states = get_reachable dir m required_states in
2042 (match satv unchecked required new_required_states phi2 env with
2043 (child2,[]) ->
2044 Printf.printf "EU\n"; flush stdout;
2045 anno [] [child2]
2046 | (child2,res2) ->
2047 let new_required = extend_required res2 required in
2048 let (child1,res1) =
2049 satv unchecked new_required new_required_states phi1 env in
2050 Printf.printf "EU\n"; flush stdout;
485bce71
C
2051 anno (satEU dir m res1 res2 new_required_states (fun y str -> ()))
2052 [child1; child2])
34e49164
C
2053 | A.AW(dir,strict,phi1,phi2) ->
2054 failwith "should not be used" (*
2055 let new_required_states = get_reachable dir m required_states in
2056 (match satv unchecked required new_required_states phi2 env with
2057 (child2,[]) ->
2058 Printf.printf "AW %b\n" unchecked; flush stdout; anno [] [child2]
2059 | (child2,res2) ->
2060 let new_required = extend_required res2 required in
2061 let (child1,res1) =
2062 satv unchecked new_required new_required_states phi1 env in
2063 Printf.printf "AW %b\n" unchecked; flush stdout;
2064 let res =
2065 strict_A2 strict satAW satEF dir m res1 res2
2066 new_required_states in
2067 anno res [child1; child2]) *)
2068 | A.AU(dir,strict,phi1,phi2) ->
2069 let new_required_states = get_reachable dir m required_states in
2070 (match satv unchecked required new_required_states phi2 env with
2071 (child2,[]) ->
2072 Printf.printf "AU\n"; flush stdout; anno [] [child2]
2073 | (child2,s2) ->
2074 let new_required = extend_required s2 required in
2075 let (child1,s1) =
2076 satv unchecked new_required new_required_states phi1 env in
2077 Printf.printf "AU\n"; flush stdout;
2078 let res =
485bce71
C
2079 strict_A2au strict satAU satEF dir m s1 s2 new_required_states
2080 (fun y str -> ()) in
34e49164
C
2081 (match res with
2082 AUok res ->
2083 anno res [child1; child2]
2084 | AUfailed tmp_res ->
2085 (* found a loop, have to try AW *)
2086 (* the formula is
2087 A[E[phi1 U phi2] & phi1 W phi2]
2088 the and is nonstrict *)
2089 (* tmp_res is bigger than s2, so perhaps closer to s1 *)
2090 Printf.printf "AW\n"; flush stdout;
2091 let s1 =
485bce71
C
2092 triples_conj
2093 (satEU dir m s1 tmp_res new_required_states
2094 (* no graph, for the moment *)
2095 (fun y str -> ()))
2096 s1 in
34e49164
C
2097 let res =
2098 strict_A2 strict satAW satEF dir m s1 s2 new_required_states in
2099 anno res [child1; child2]))
2100 | A.Implies(phi1,phi2) ->
2101 satv unchecked required required_states
2102 (A.Or(A.Not phi1,phi2))
2103 env
2104 | A.Exists (keep,v,phi1) ->
2105 let new_required = drop_required v required in
2106 let (child,res) =
2107 satv unchecked new_required required_states phi1 env in
2108 Printf.printf "exists\n"; flush stdout;
2109 anno (triples_witness v unchecked (not keep) res) [child]
2110 | A.Let(v,phi1,phi2) ->
2111 let (child1,res1) =
2112 satv unchecked required required_states phi1 env in
2113 let (child2,res2) =
2114 satv unchecked required required_states phi2 ((v,res1) :: env) in
2115 anno res2 [child1;child2]
2116 | A.LetR(dir,v,phi1,phi2) ->
2117 let new_required_states = get_reachable dir m required_states in
2118 let (child1,res1) =
2119 satv unchecked required new_required_states phi1 env in
2120 let (child2,res2) =
2121 satv unchecked required required_states phi2 ((v,res1) :: env) in
2122 anno res2 [child1;child2]
2123 | A.Ref(v) ->
2124 Printf.printf "Ref\n"; flush stdout;
2125 let res = List.assoc v env in
2126 let res =
2127 if unchecked
2128 then List.map (function (s,th,_) -> (s,th,[])) res
2129 else res in
2130 anno res []
2131 | A.XX(phi) -> failwith "should have been removed" in
2132 let res1 = drop_wits required_states res phi in
2133 if not(res1 = res)
2134 then
2135 begin
2136 print_required_states required_states;
2137 print_state "after drop_wits" res1 end;
2138 (child,res1)
2139
2140;;
2141
2142let sat_verbose annotate maxlvl lvl m phi =
2143 sat_verbose_loop false [] None annotate maxlvl lvl m phi []
2144
2145(* Type for annotations collected in a tree *)
2146type ('a) witAnnoTree = WitAnno of ('a * ('a witAnnoTree) list);;
2147
2148let sat_annotree annotate m phi =
2149 let tree_anno l phi res chld = WitAnno(annotate l phi res,chld) in
2150 sat_verbose_loop false [] None tree_anno (-1) 0 m phi []
2151;;
2152
2153(*
2154let sat m phi = satloop m phi []
2155;;
2156*)
2157
2158let simpleanno l phi res =
2159 let pp s =
2160 Format.print_string ("\n" ^ s ^ "\n------------------------------\n");
2161 print_generic_algo (List.sort compare res);
2162 Format.print_string "\n------------------------------\n\n" in
2163 let pp_dir = function
2164 A.FORWARD -> ()
2165 | A.BACKWARD -> pp "^" in
2166 match phi with
2167 | A.False -> pp "False"
2168 | A.True -> pp "True"
2169 | A.Pred(p) -> pp ("Pred" ^ (Common.dump p))
2170 | A.Not(phi) -> pp "Not"
2171 | A.Exists(_,v,phi) -> pp ("Exists " ^ (Common.dump(v)))
2172 | A.And(_,phi1,phi2) -> pp "And"
2173 | A.AndAny(dir,_,phi1,phi2) -> pp "AndAny"
2174 | A.HackForStmt(dir,_,phi1,phi2) -> pp "HackForStmt"
2175 | A.Or(phi1,phi2) -> pp "Or"
2176 | A.SeqOr(phi1,phi2) -> pp "SeqOr"
2177 | A.Implies(phi1,phi2) -> pp "Implies"
2178 | A.AF(dir,_,phi1) -> pp "AF"; pp_dir dir
2179 | A.AX(dir,_,phi1) -> pp "AX"; pp_dir dir
2180 | A.AG(dir,_,phi1) -> pp "AG"; pp_dir dir
2181 | A.AW(dir,_,phi1,phi2)-> pp "AW"; pp_dir dir
2182 | A.AU(dir,_,phi1,phi2)-> pp "AU"; pp_dir dir
2183 | A.EF(dir,phi1) -> pp "EF"; pp_dir dir
2184 | A.EX(dir,phi1) -> pp "EX"; pp_dir dir
2185 | A.EG(dir,phi1) -> pp "EG"; pp_dir dir
2186 | A.EU(dir,phi1,phi2) -> pp "EU"; pp_dir dir
2187 | A.Let (x,phi1,phi2) -> pp ("Let"^" "^x)
2188 | A.LetR (dir,x,phi1,phi2) -> pp ("LetR"^" "^x); pp_dir dir
2189 | A.Ref(s) -> pp ("Ref("^s^")")
2190 | A.Uncheck(s) -> pp "Uncheck"
2191 | A.InnerAnd(s) -> pp "InnerAnd"
2192 | A.XX(phi1) -> pp "XX"
2193;;
2194
2195
2196(* pad: Rene, you can now use the module pretty_print_ctl.ml to
2197 print a ctl formula more accurately if you want.
2198 Use the print_xxx provided in the different module to call
2199 Pretty_print_ctl.pp_ctl.
2200 *)
2201
2202let simpleanno2 l phi res =
2203 begin
2204 Pretty_print_ctl.pp_ctl (P.print_predicate, SUB.print_mvar) false phi;
2205 Format.print_newline ();
2206 Format.print_string "----------------------------------------------------";
2207 Format.print_newline ();
2208 print_generic_algo (List.sort compare res);
2209 Format.print_newline ();
2210 Format.print_string "----------------------------------------------------";
2211 Format.print_newline ();
2212 Format.print_newline ();
2213 end
2214
2215
2216(* ---------------------------------------------------------------------- *)
2217(* Benchmarking *)
2218(* ---------------------------------------------------------------------- *)
2219
2220type optentry = bool ref * string
2221type options = {label : optentry; unch : optentry;
2222 conj : optentry; compl1 : optentry; compl2 : optentry;
2223 newinfo : optentry;
2224 reqenv : optentry; reqstates : optentry}
2225
2226let options =
2227 {label = (pSATLABEL_MEMO_OPT,"satlabel_memo_opt");
2228 unch = (pUNCHECK_OPT,"uncheck_opt");
2229 conj = (pTRIPLES_CONJ_OPT,"triples_conj_opt");
2230 compl1 = (pTRIPLES_COMPLEMENT_OPT,"triples_complement_opt");
2231 compl2 = (pTRIPLES_COMPLEMENT_SIMPLE_OPT,"triples_complement_simple_opt");
2232 newinfo = (pNEW_INFO_OPT,"new_info_opt");
2233 reqenv = (pREQUIRED_ENV_OPT,"required_env_opt");
2234 reqstates = (pREQUIRED_STATES_OPT,"required_states_opt")}
2235
2236let baseline =
2237 [("none ",[]);
2238 ("label ",[options.label]);
2239 ("unch ",[options.unch]);
2240 ("unch and label ",[options.label;options.unch])]
2241
2242let conjneg =
2243 [("conj ", [options.conj]);
2244 ("compl1 ", [options.compl1]);
2245 ("compl12 ", [options.compl1;options.compl2]);
2246 ("conj/compl12 ", [options.conj;options.compl1;options.compl2]);
2247 ("conj unch satl ", [options.conj;options.unch;options.label]);
2248(*
2249 ("compl1 unch satl ", [options.compl1;options.unch;options.label]);
2250 ("compl12 unch satl ",
2251 [options.compl1;options.compl2;options.unch;options.label]); *)
2252 ("conj/compl12 unch satl ",
2253 [options.conj;options.compl1;options.compl2;options.unch;options.label])]
2254
2255let path =
2256 [("newinfo ", [options.newinfo]);
2257 ("newinfo unch satl ", [options.newinfo;options.unch;options.label])]
2258
2259let required =
2260 [("reqenv ", [options.reqenv]);
2261 ("reqstates ", [options.reqstates]);
2262 ("reqenv/states ", [options.reqenv;options.reqstates]);
2263(* ("reqenv unch satl ", [options.reqenv;options.unch;options.label]);
2264 ("reqstates unch satl ",
2265 [options.reqstates;options.unch;options.label]);*)
2266 ("reqenv/states unch satl ",
2267 [options.reqenv;options.reqstates;options.unch;options.label])]
2268
2269let all_options =
2270 [options.label;options.unch;options.conj;options.compl1;options.compl2;
2271 options.newinfo;options.reqenv;options.reqstates]
2272
2273let all =
2274 [("all ",all_options)]
2275
2276let all_options_but_path =
2277 [options.label;options.unch;options.conj;options.compl1;options.compl2;
2278 options.reqenv;options.reqstates]
2279
2280let all_but_path = ("all but path ",all_options_but_path)
2281
2282let counters =
2283 [(satAW_calls, "satAW", ref 0);
2284 (satAU_calls, "satAU", ref 0);
2285 (satEF_calls, "satEF", ref 0);
2286 (satAF_calls, "satAF", ref 0);
2287 (satEG_calls, "satEG", ref 0);
2288 (satAG_calls, "satAG", ref 0);
2289 (satEU_calls, "satEU", ref 0)]
2290
2291let perms =
2292 map
2293 (function (opt,x) ->
2294 (opt,x,ref 0.0,ref 0,
2295 List.map (function _ -> (ref 0, ref 0, ref 0)) counters))
2296 [List.hd all;all_but_path]
2297 (*(all@baseline@conjneg@path@required)*)
2298
2299exception Out
2300
2301let rec iter fn = function
2302 1 -> fn()
2303 | n -> let _ = fn() in
2304 (Hashtbl.clear reachable_table;
2305 Hashtbl.clear memo_label;
2306 triples := 0;
2307 iter fn (n-1))
2308
2309let copy_to_stderr fl =
2310 let i = open_in fl in
2311 let rec loop _ =
2312 Printf.fprintf stderr "%s\n" (input_line i);
2313 loop() in
2314 try loop() with _ -> ();
2315 close_in i
2316
2317let bench_sat (_,_,states) fn =
2318 List.iter (function (opt,_) -> opt := false) all_options;
2319 let answers =
2320 concatmap
2321 (function (name,options,time,trips,counter_info) ->
2322 let iterct = !Flag_ctl.bench in
2323 if !time > float_of_int timeout then time := -100.0;
2324 if not (!time = -100.0)
2325 then
2326 begin
2327 Hashtbl.clear reachable_table;
2328 Hashtbl.clear memo_label;
2329 List.iter (function (opt,_) -> opt := true) options;
2330 List.iter (function (calls,_,save_calls) -> save_calls := !calls)
2331 counters;
2332 triples := 0;
2333 let res =
2334 let bef = Sys.time() in
2335 try
2336 Common.timeout_function timeout
2337 (fun () ->
2338 let bef = Sys.time() in
2339 let res = iter fn iterct in
2340 let aft = Sys.time() in
2341 time := !time +. (aft -. bef);
2342 trips := !trips + !triples;
2343 List.iter2
2344 (function (calls,_,save_calls) ->
2345 function (current_calls,current_cfg,current_max_cfg) ->
2346 current_calls :=
2347 !current_calls + (!calls - !save_calls);
2348 if (!calls - !save_calls) > 0
2349 then
2350 (let st = List.length states in
2351 current_cfg := !current_cfg + st;
2352 if st > !current_max_cfg
2353 then current_max_cfg := st))
2354 counters counter_info;
2355 [res])
2356 with
2357 Common.Timeout ->
2358 begin
2359 let aft = Sys.time() in
2360 time := -100.0;
2361 Printf.fprintf stderr "Timeout at %f on: %s\n"
2362 (aft -. bef) name;
2363 []
2364 end in
2365 List.iter (function (opt,_) -> opt := false) options;
2366 res
2367 end
2368 else [])
2369 perms in
2370 Printf.fprintf stderr "\n";
2371 match answers with
2372 [] -> []
2373 | res::rest ->
2374 (if not(List.for_all (function x -> x = res) rest)
2375 then
2376 (List.iter (print_state "a state") answers;
2377 Printf.printf "something doesn't work\n");
2378 res)
2379
2380let print_bench _ =
2381 let iterct = !Flag_ctl.bench in
2382 if iterct > 0
2383 then
2384 (List.iter
2385 (function (name,options,time,trips,counter_info) ->
2386 Printf.fprintf stderr "%s Numbers: %f %d "
2387 name (!time /. (float_of_int iterct)) !trips;
2388 List.iter
2389 (function (calls,cfg,max_cfg) ->
2390 Printf.fprintf stderr "%d %d %d " (!calls / iterct) !cfg !max_cfg)
2391 counter_info;
2392 Printf.fprintf stderr "\n")
2393 perms)
2394
2395(* ---------------------------------------------------------------------- *)
2396(* preprocessing: ignore irrelevant functions *)
2397
2398let preprocess (cfg,_,_) label = function
2399 [] -> true (* no information, try everything *)
2400 | l ->
2401 let sz = G.size cfg in
2402 let verbose_output pred = function
2403 [] ->
2404 Printf.printf "did not find:\n";
2405 P.print_predicate pred; Format.print_newline()
2406 | _ ->
2407 Printf.printf "found:\n";
2408 P.print_predicate pred; Format.print_newline();
2409 Printf.printf "but it was not enough\n" in
2410 let get_any verbose x =
2411 let res =
2412 try Hashtbl.find memo_label x
2413 with
2414 Not_found ->
2415 (let triples = label x in
2416 let filtered =
2417 List.map (function (st,th,_) -> (st,th)) triples in
2418 Hashtbl.add memo_label x filtered;
2419 filtered) in
2420 if verbose then verbose_output x res;
2421 not([] = res) in
2422 let get_all l =
2423 (* don't bother testing when there are more patterns than nodes *)
2424 if List.length l > sz-2
2425 then false
2426 else List.for_all (get_any false) l in
2427 if List.exists get_all l
2428 then true
2429 else
2430 (if !Flag_ctl.verbose_match
2431 then
2432 List.iter (List.iter (function x -> let _ = get_any true x in ()))
2433 l;
2434 false)
2435
2436let filter_partial_matches trips =
2437 if !Flag_ctl.partial_match
2438 then
2439 let anynegwit = (* if any is neg, then all are *)
2440 List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in
2441 let (bad,good) =
2442 List.partition (function (s,th,wit) -> anynegwit wit) trips in
2443 (match bad with
2444 [] -> ()
2445 | _ -> print_state "partial matches" bad; Format.print_newline());
2446 good
2447 else trips
2448
2449(* ---------------------------------------------------------------------- *)
2450(* Main entry point for engine *)
2451let sat m phi reqopt =
2452 try
2453 (match !Flag_ctl.steps with
2454 None -> step_count := 0
2455 | Some x -> step_count := x);
2456 Hashtbl.clear reachable_table;
2457 Hashtbl.clear memo_label;
2458 let (x,label,states) = m in
2459 if (!Flag_ctl.bench > 0) or (preprocess m label reqopt)
2460 then
2461 ((* to drop when Yoann initialized this flag *)
2462 if List.exists (G.extract_is_loop x) states
2463 then Flag_ctl.loop_in_src_code := true;
2464 let m = (x,label,List.sort compare states) in
2465 let res =
2466 if(!Flag_ctl.verbose_ctl_engine)
2467 then
2468 let fn _ = snd (sat_annotree simpleanno2 m phi) in
2469 if !Flag_ctl.bench > 0
2470 then bench_sat m fn
2471 else fn()
2472 else
2473 let fn _ = satloop false [] None m phi [] in
2474 if !Flag_ctl.bench > 0
2475 then bench_sat m fn
2476 else Common.profile_code "ctl" (fun _ -> fn()) in
2477 let res = filter_partial_matches res in
2478 (*
2479 Printf.printf "steps: start %d, stop %d\n"
2480 (match !Flag_ctl.steps with Some x -> x | _ -> 0)
2481 !step_count;
2482 Printf.printf "triples: %d\n" !triples;
2483 print_state "final result" res;
2484 *)
708f4980 2485 List.sort compare res)
34e49164
C
2486 else
2487 (if !Flag_ctl.verbose_ctl_engine
2488 then Common.pr2 "missing something required";
2489 [])
2490 with Steps -> []
2491;;
2492
2493(* ********************************************************************** *)
2494(* End of Module: CTL_ENGINE *)
2495(* ********************************************************************** *)
2496end
2497;;