af23b8c062bcf8328e08bf47f7c3dd3497913333
[tatoo.git] / src / run.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                   Lucca Hirschi, LRI UMR8623                        *)
6 (*                   Université Paris-Sud & CNRS                       *)
7 (*                                                                     *)
8 (*  Copyright 2010-2012 Université Paris-Sud and Centre National de la *)
9 (*  Recherche Scientifique. All rights reserved.  This file is         *)
10 (*  distributed under the terms of the GNU Lesser General Public       *)
11 (*  License, with the special exception on linking described in file   *)
12 (*  ../LICENSE.                                                        *)
13 (*                                                                     *)
14 (***********************************************************************)
15
16 module Node  =
17 struct
18   type t = int
19   let hash n = n
20   let compare = (-)
21   let equal = (=)
22 end
23   
24 module NodeHash = Hashtbl.Make (Node)
25   
26 type t = (StateSet.t*StateSet.t) NodeHash.t
27 (** Map from nodes to query and recognizing states *)
28 (* Note that we do not consider nil nodes *)
29
30 exception Oracle_fail
31 exception Over_max_fail
32 exception Max_fail
33
34 (* Mapped sets for leaves *)
35 let map_leaf asta = (Asta.bot_states_s asta, StateSet.empty)
36
37 (* Build the Oracle *)
38 let rec bu_oracle asta run tree tnode =
39   let node = Tree.preorder tree tnode in
40   if Tree.is_leaf tree tnode
41   then
42     if tnode == Tree.nil
43     then ()
44     else NodeHash.add run node (map_leaf asta)
45   else
46     let tfnode = Tree.first_child tree tnode
47     and tnnode = Tree.next_sibling tree tnode in
48     let fnode,nnode =                            (* their preorders *)
49       (Tree.preorder tree tfnode, Tree.preorder tree tnnode) in
50     begin
51       bu_oracle asta run tree tfnode;
52       bu_oracle asta run tree tnnode;
53       let q_rec n =                     (* compute the set for child/sibling *)
54         try NodeHash.find run n
55         with Not_found -> map_leaf asta in
56       let (_,qfr),(_,qnr) = q_rec fnode,q_rec nnode (* computed in rec call *)
57       and lab = Tree.tag tree tnode in
58       let _,list_tr = Asta.transitions_lab asta lab in (* only reco. tran.*)
59       let rec result set flag = function (* add states which satisfy a transition *)
60         | [] -> set,flag
61         | (q,form) :: tl ->
62           if Formula.eval_form (set,qfr,qnr) form (* evaluates the formula*)
63           then
64             if StateSet.mem q set
65             then result set 0 tl
66             else result (StateSet.add q set) 1 tl
67           else result set 0 tl in
68       let rec fix_point set_i =  (* compute the fixed point of states of node *)
69         let set,flag = result set_i 0 list_tr in
70         if flag = 0 then set
71         else fix_point set in
72       NodeHash.add run node (StateSet.empty, fix_point StateSet.empty)
73     end
74       
75 (* Build the over-approx. of the maximal run *)
76 let rec bu_over_max asta run tree tnode =
77   if (Tree.is_leaf tree tnode)      (* BU_oracle has already created the map *)
78   then
79     ()
80   else
81     let tfnode = Tree.first_child tree tnode
82     and tnnode = Tree.next_sibling tree tnode in
83     begin
84       bu_over_max asta run tree tfnode;
85       bu_over_max asta run tree tnnode;
86       let (fnode,nnode) =
87         (Tree.preorder tree tfnode, Tree.preorder tree tnnode)
88       and node = Tree.preorder tree tnode in          
89       let q_rec n =
90         try NodeHash.find run n
91         with Not_found -> map_leaf asta in
92       let qf,qn = q_rec fnode,q_rec nnode in
93       let lab = Tree.tag tree tnode in
94       let list_tr,_ = Asta.transitions_lab asta lab (* only take query st. *)
95       and _,resultr = try NodeHash.find run node
96         with _ -> raise Over_max_fail in      
97       let rec result set flag = function
98         | [] -> set,flag
99         | (q,form) :: tl ->
100           if Formula.infer_form (set,resultr) qf qn form (* infers the formula*)
101           then if StateSet.mem q set
102             then result set 0 tl
103             else result (StateSet.add q set) 1 tl
104           else result set 0 tl in
105       let rec fix_point set_i = 
106         let set,flag = result set_i 0 list_tr in
107         if flag = 0
108         then set
109         else fix_point set in
110       let result_set = fix_point StateSet.empty in
111       (* we keep the old recognizing states set *)
112       NodeHash.replace run node (result_set, resultr)
113     end
114
115
116 (* Build the maximal run *)
117 let rec tp_max asta run tree tnode =
118   if (Tree.is_leaf tree tnode)      (* BU_oracle has already created the map *)
119   then
120     ()
121   else
122     let node = Tree.preorder tree tnode
123     and tfnode = Tree.first_child tree tnode
124     and tnnode = Tree.next_sibling tree tnode in
125     let (fnode,nnode) =
126       (Tree.preorder tree tfnode, Tree.preorder tree tnnode) in
127     begin
128       if tnode == Tree.root tree        (* we must intersect with top states *)
129       then let setq,_  = try NodeHash.find run node
130         with _ -> raise Max_fail in
131            NodeHash.replace run node
132              ((StateSet.inter (Asta.top_states_s asta) setq),StateSet.empty)
133       else ();
134       let q_rec n =
135         try NodeHash.find run n
136         with Not_found -> map_leaf asta in
137       let qf,qn = q_rec fnode,q_rec nnode in
138       let lab = Tree.tag tree tnode in
139       let list_tr,_ = Asta.transitions_lab asta lab in (* only take query. *)
140       let (set_node,set_nr) as self = try NodeHash.find run node
141         with Not_found -> raise Max_fail in
142       (* We must compute again accepting states from self transitions since
143          previous calls of tp_max may remove them *)
144       let rec comp_acc_self set flag = function
145         | [] -> set,flag
146         | (q,form) :: tl ->
147           if Formula.infer_form set qf qn form
148           then if StateSet.mem q set
149             then comp_acc_self set 0 tl
150             else comp_acc_self (StateSet.add q set) 1 tl
151           else comp_acc_self set 0 tl
152       and rec fix_point selfq_i =
153         let setq,flag = comp_acc_self selfq_i 0 list_tr in
154         if flag = 1 then set
155         else fix_point setq qf qn 0 in
156       NodeHash.replace run node (fix_point set_node, set_nr);
157       
158       let rec result = function
159         | [] -> []
160         | (q,form) :: tl ->
161           if (StateSet.mem q set_node) &&  (* infers & trans. can start here *)
162             (Formula.infer_form self qf qn form)
163           then form :: (result tl)
164           else result tl in
165       let list_form = result list_tr in (* tran. candidates *)
166       (* compute states occuring in transition candidates *)
167       let rec add_st (ql,qr) = function
168         | [] -> ql,qr
169         | f :: tl -> let sql,sqr = Formula.st f in
170                      let ql' = StateSet.union sql ql
171                      and qr' = StateSet.union sqr qr in
172                      add_st (ql',qr') tl in
173       let ql,qr = add_st (StateSet.empty, StateSet.empty) list_form in
174       let qfq,qfr = try NodeHash.find run fnode
175         with | _ -> map_leaf asta
176       and qnq,qnr = try NodeHash.find run nnode
177         with | _ -> map_leaf asta in
178       begin
179         if tfnode == Tree.nil
180         then ()
181         else NodeHash.replace run fnode (StateSet.inter qfq ql,qfr);
182         if tnnode == Tree.nil
183         then ()
184         else NodeHash.replace run nnode (StateSet.inter qnq qr,qnr);
185         (* indeed we delete all states from self transitions!  *)
186         tp_max asta run tree tfnode;
187         tp_max asta run tree tnnode;
188       end;
189     end
190         
191 let compute tree asta =
192   let flag = 2 in                       (* debug  *)
193   let size_tree = 10000 in              (* todo (Tree.size ?) *)
194   let map = NodeHash.create size_tree in
195   bu_oracle asta map tree (Tree.root tree);
196   if flag > 0 then begin
197     bu_over_max asta map tree (Tree.root tree);
198     if flag = 2
199     then
200       tp_max asta map tree (Tree.root tree)
201     else ()
202   end
203   else ();
204   map
205
206 let selected_nodes tree asta =
207   let run = compute tree asta in
208   NodeHash.fold
209     (fun key set acc ->
210       if not(StateSet.is_empty
211                (StateSet.inter (fst set) (Asta.selec_states asta)))        
212       then key :: acc
213       else acc)
214     run []
215
216 let print fmt run =
217   let print_d_set fmt (s_1,s_2) =
218     Format.fprintf fmt "(%a,%a)"
219       StateSet.print s_1 StateSet.print s_2 in
220   let print_map fmt run =
221     let pp = Format.fprintf fmt in
222     if NodeHash.length run = 0
223     then Format.fprintf fmt "ø"
224     else
225       NodeHash.iter (fun cle set -> pp "|  %i->%a  @ " cle print_d_set set)
226         run in
227   let print_box fmt run =
228     let pp = Format.fprintf fmt in
229     pp "@[<hov 0>@.  # Mapping:@.   @[<hov 0>%a@]@]"
230       print_map run
231   in
232   Format.fprintf fmt "@[<hov 0>##### RUN #####@, %a@]@." print_box run