1 (***********************************************************************)
5 (* Lucca Hirschi, LRI UMR8623 *)
6 (* Université Paris-Sud & CNRS *)
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 *)
14 (***********************************************************************)
24 module NodeHash = Hashtbl.Make (Node)
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 *)
31 exception Over_max_fail
34 (* Mapped sets for leaves *)
35 let map_leaf asta = (Asta.bot_states_s asta, StateSet.empty)
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
44 else NodeHash.add run node (map_leaf asta)
46 let tfnode = Tree.first_child_x 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
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 *)
62 if Formula.eval_form (set,qfr,qnr) form (* evaluates the formula*)
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
72 NodeHash.add run node (StateSet.empty, fix_point StateSet.empty)
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 *)
81 let tfnode = Tree.first_child_x tree tnode
82 and tnnode = Tree.next_sibling tree tnode in
84 bu_over_max asta run tree tfnode;
85 bu_over_max asta run tree tnnode;
87 (Tree.preorder tree tfnode, Tree.preorder tree tnnode)
88 and node = Tree.preorder tree tnode in
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 | [] -> if flag = 0 then set else result set 0 list_tr
100 if StateSet.mem q set
102 else if Formula.infer_form (set,resultr) qf qn form
103 then result (StateSet.add q set) 1 tl
104 else result set 0 tl in
105 let result_set = result StateSet.empty 0 list_tr in
106 (* we keep the old recognizing states set *)
107 NodeHash.replace run node (result_set, resultr)
111 (* Build the maximal run *)
112 let rec tp_max asta run tree tnode =
113 if (Tree.is_leaf tree tnode) (* BU_oracle has already created the map *)
117 let node = Tree.preorder tree tnode
118 and tfnode = Tree.first_child_x tree tnode
119 and tnnode = Tree.next_sibling tree tnode in
121 (Tree.preorder tree tfnode, Tree.preorder tree tnnode) in
123 if tnode == Tree.root tree (* we must intersect with top states *)
124 then let setq,_ = try NodeHash.find run node
125 with _ -> raise Max_fail in
126 NodeHash.replace run node
127 ((StateSet.inter (Asta.top_states_s asta) setq),StateSet.empty)
130 try NodeHash.find run n
131 with Not_found -> map_leaf asta in
132 let qf,qn = q_rec fnode,q_rec nnode in
133 let lab = Tree.tag tree tnode in
134 let list_tr,_ = Asta.transitions_lab asta lab in (* only take query. *)
135 let (self_q,self_r) = try NodeHash.find run node
136 with Not_found -> raise Max_fail in
138 (* We must compute again accepting states from self transitions since
139 previous calls of tp_max may remove them *)
140 let rec result_q self_q queue = function (* for initializing the queue *)
143 if (StateSet.mem q self_q)
145 let q_cand,_,_ = Formula.st form in
146 StateSet.iter (fun x -> Queue.push x queue) q_cand;
147 result_q (StateSet.add q self_q) queue tl;
149 else result_q self_q queue tl
150 and result_st_q self_q queue flag = function (*for computing the fixed p*)
153 if Formula.infer_form (self_q,self_r) qf qn form
155 let q_cand,_,_ = Formula.st form in
156 StateSet.iter (fun x -> Queue.push x queue) q_cand;
157 result_st_q self_q queue 1 tl;
159 else result_st_q self_q queue flag tl in
160 let rec comp_acc_self self_q_i queue = (* compute the fixed point *)
161 if Queue.is_empty queue
164 let q = Queue.pop queue in
165 let list_q,_ = Asta.transitions_st_lab asta q lab in
166 let flag,queue = result_st_q self_q_i queue 0 list_q in
167 let self_q = if flag = 1 then StateSet.add q self_q_i else self_q_i in
168 comp_acc_self self_q queue in
170 let self,queue_init = result_q self_q (Queue.create()) list_tr in
171 let self_q = comp_acc_self self_q queue_init in
172 NodeHash.replace run node (self_q,self_r);
173 (* From now, the correct set of states is mapped to node! *)
174 let rec result = function
177 if (StateSet.mem q self) && (* infers & trans. can start here *)
178 (Formula.infer_form (self_q,self_r) qf qn form)
179 then form :: (result tl)
181 let list_form = result list_tr in (* tran. candidates *)
182 (* compute states occuring in transition candidates *)
183 let rec add_st (ql,qr) = function
185 | f :: tl -> let sqs,sql,sqr = Formula.st f in
186 let ql' = StateSet.union sql ql
187 and qr' = StateSet.union sqr qr in
188 add_st (ql',qr') tl in
189 let ql,qr = add_st (StateSet.empty, StateSet.empty) list_form in
190 let qfq,qfr = try NodeHash.find run fnode
191 with | _ -> map_leaf asta
192 and qnq,qnr = try NodeHash.find run nnode
193 with | _ -> map_leaf asta in
195 if tfnode == Tree.nil || Tree.is_attribute tree tnode
197 else NodeHash.replace run fnode (StateSet.inter qfq ql,qfr);
198 if tnnode == Tree.nil || Tree.is_attribute tree tnode
200 else NodeHash.replace run nnode (StateSet.inter qnq qr,qnr);
201 (* indeed we delete all states from self transitions! *)
202 tp_max asta run tree tfnode;
203 tp_max asta run tree tnnode;
207 let compute tree asta =
208 let flag = 2 in (* debug *)
209 let size_tree = 10000 in (* todo (Tree.size ?) *)
210 let map = NodeHash.create size_tree in
211 bu_oracle asta map tree (Tree.root tree);
212 if flag > 0 then begin
213 bu_over_max asta map tree (Tree.root tree);
216 tp_max asta map tree (Tree.root tree)
222 let selected_nodes tree asta =
223 let run = compute tree asta in
226 if not(StateSet.is_empty
227 (StateSet.inter (fst set) (Asta.selec_states asta)))
233 let print_d_set fmt (s_1,s_2) =
234 Format.fprintf fmt "(%a,%a)"
235 StateSet.print s_1 StateSet.print s_2 in
236 let print_map fmt run =
237 let pp = Format.fprintf fmt in
238 if NodeHash.length run = 0
239 then Format.fprintf fmt "ø"
241 NodeHash.iter (fun cle set -> pp "| %i->%a @ " cle print_d_set set)
243 let print_box fmt run =
244 let pp = Format.fprintf fmt in
245 pp "@[<hov 0>@. # Mapping:@. @[<hov 0>%a@]@]"
248 Format.fprintf fmt "@[<hov 0>##### RUN #####@, %a@]@." print_box run