2e0cf95f8136b05ec468a6c43fccc2ae743c91dc
[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 (* first child *)
47     and tnnode = Tree.next_sibling tree tnode in (* next-sibling *)
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,_ = try NodeHash.find run node
141         with _ -> raise Max_fail in
142       let self = try NodeHash.find run node
143         with Not_found -> raise Max_fail in
144       let rec result = function
145         | [] -> []
146         | (q,form) :: tl ->
147           if (Formula.infer_form self qf qn form) &&
148             (StateSet.mem q set_node)   (* infers & trans. can start here *)
149           then form :: (result tl)
150           else result tl in
151       let list_form = result list_tr in (* tran. candidates *)
152       (* compute states occuring in transition candidates *)
153       let rec add_st (ql,qr) = function
154         | [] -> ql,qr
155         | f :: tl -> let sql,sqr = Formula.st f in
156                      let ql' = StateSet.union sql ql
157                      and qr' = StateSet.union sqr qr in
158                      add_st (ql',qr') tl in
159       let ql,qr = add_st (StateSet.empty, StateSet.empty) list_form in
160       let qfq,qfr = try NodeHash.find run fnode
161         with | _ -> map_leaf asta
162       and qnq,qnr = try NodeHash.find run nnode
163         with | _ -> map_leaf asta in
164       begin
165         if tfnode == Tree.nil
166         then ()
167         else NodeHash.replace run fnode (StateSet.inter qfq ql,qfr);
168         if tnnode == Tree.nil
169         then ()
170         else NodeHash.replace run nnode (StateSet.inter qnq qr,qnr);
171         tp_max asta run tree tfnode;
172         tp_max asta run tree tnnode;
173       end;
174     end
175         
176 let compute tree asta =
177   let flag = 2 in                       (* debug  *)
178   let size_tree = 10000 in              (* todo (Tree.size ?) *)
179   let map = NodeHash.create size_tree in
180   bu_oracle asta map tree (Tree.root tree);
181   if flag > 0 then begin
182     bu_over_max asta map tree (Tree.root tree);
183     if flag = 2
184     then
185       tp_max asta map tree (Tree.root tree)
186     else ()
187   end
188   else ();
189   map
190
191 let selected_nodes tree asta =
192   let run = compute tree asta in
193   NodeHash.fold
194     (fun key set acc ->
195       if not(StateSet.is_empty
196                (StateSet.inter (fst set) (Asta.selec_states asta)))        
197       then key :: acc
198       else acc)
199     run []
200
201 let print fmt run =
202   let print_d_set fmt (s_1,s_2) =
203     Format.fprintf fmt "(%a,%a)"
204       StateSet.print s_1 StateSet.print s_2 in
205   let print_map fmt run =
206     let pp = Format.fprintf fmt in
207     if NodeHash.length run = 0
208     then Format.fprintf fmt "ø"
209     else
210       NodeHash.iter (fun cle set -> pp "|  %i->%a  @ " cle print_d_set set)
211         run in
212   let print_box fmt run =
213     let pp = Format.fprintf fmt in
214     pp "@[<hov 0>@.  # Mapping:@.   @[<hov 0>%a@]@]"
215       print_map run
216   in
217   Format.fprintf fmt "@[<hov 0>##### RUN #####@, %a@]@." print_box run