31eb26c650486e188d493bbc956794b766bdb3f2
[tatoo.git] / src / run.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                     Kim Nguyen, LRI UMR8623                         *)
6 (*                   Université Paris-Sud & CNRS                       *)
7 (*                                                                     *)
8 (*  Copyright 2010-2013 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 INCLUDE "utils.ml"
17 INCLUDE "debug.ml"
18
19 open Format
20 open Misc
21
22 type stats = { run : int;
23                tree_size : int;
24                cache2_access : int;
25                cache2_hit : int;
26                cache5_access : int;
27                cache5_hit : int;
28              }
29
30 let cache2_hit = ref 0
31 let cache2_access = ref 0
32 let cache5_hit = ref 0
33 let cache5_access = ref 0
34 let reset_stat_counters () =
35   cache2_hit := 0;
36   cache2_access := 0;
37   cache5_hit := 0;
38   cache5_access := 0
39
40
41 module Make (T : Tree.S) =
42  struct
43
44    module NodeSummary =
45    struct
46      (* Pack into an integer the result of the is_* and has_ predicates
47         for a given node *)
48      type t = int
49      let dummy = -1
50     (*
51       4444444444443210
52       4 -> kind
53       3 -> is_left
54       2 -> is_right
55       1 -> has_left
56       0 -> has_right
57     *)
58
59      let has_right (s : t) : bool =
60        Obj.magic (s land 1)
61
62      let has_left (s : t) : bool =
63        Obj.magic ((s lsr 1) land 1)
64
65      let is_right (s : t) : bool =
66        Obj.magic ((s lsr 2) land 1)
67
68      let is_left (s : t) : bool =
69        Obj.magic ((s lsr 3) land 1)
70
71      let kind (s : t) : Tree.NodeKind.t =
72        Obj.magic (s lsr 4)
73
74      let make is_left is_right has_left has_right kind =
75        ((Obj.magic kind) lsl 4) lor
76          ((int_of_bool is_left) lsl 3) lor
77          ((int_of_bool is_right) lsl 2) lor
78          ((int_of_bool has_left) lsl 1) lor
79          (int_of_bool has_right)
80
81    end
82
83    type node_status = {
84      rank : int;
85      sat : StateSet.t;  (* States that are satisfied at the current node *)
86      todo : StateSet.t; (* States that remain to be proven *)
87         (* For every node_status and automaton a,
88            a.states - (sat U todo) = unsat *)
89      summary : NodeSummary.t; (* Summary of the shape of the node *)
90    }
91 (* Describe what is kept at each node for a run *)
92
93    module NodeStatus =
94      struct
95        include Hcons.Make(struct
96          type t = node_status
97          let equal c d =
98            c == d ||
99              c.rank == d.rank &&
100              c.sat == d.sat &&
101              c.todo == d.todo &&
102              c.summary == d.summary
103
104          let hash c =
105            HASHINT4(c.rank,
106                     (c.sat.StateSet.id :> int),
107                     (c.todo.StateSet.id :> int),
108                     c.summary)
109        end
110        )
111        let print ppf s =
112          fprintf ppf
113            "{ rank: %i; sat: %a; todo: %a; summary: _ }"
114            s.node.rank
115            StateSet.print s.node.sat
116            StateSet.print s.node.todo
117      end
118
119    let dummy_status =
120      NodeStatus.make {
121        rank = -1;
122        sat = StateSet.empty;
123        todo = StateSet.empty;
124        summary = NodeSummary.dummy;
125      }
126
127
128    type run = {
129      tree : T.t ;
130      (* The argument of the run *)
131      auto : Ata.t;
132      (* The automaton to be run *)
133      status : NodeStatus.t array;
134      (* A mapping from node preorders to NodeStatus *)
135      unstable : Bitvector.t;
136      (* A bitvector remembering whether a subtree is stable *)
137      mutable redo : bool;
138      (* A boolean indicating whether the run is incomplete *)
139      mutable pass : int;
140      (* The number of times this run was updated *)
141      mutable cache2 : Ata.Formula.t Cache.N2.t;
142      (* A cache from states * label to list of transitions *)
143      mutable cache5 : NodeStatus.t Cache.N5.t;
144    }
145
146    let pass r = r.pass
147    let stable r = not r.redo
148    let auto r = r.auto
149    let tree r = r.tree
150
151
152    let dummy_form = Ata.Formula.stay State.dummy
153
154    let make auto tree =
155      let len = T.size tree in
156      {
157        tree = tree;
158        auto = auto;
159        status = Array.create len dummy_status;
160        unstable = Bitvector.create ~init:true len;
161        redo = true;
162        pass = 0;
163        cache2 = Cache.N2.create dummy_form;
164        cache5 = Cache.N5.create dummy_status;
165      }
166
167    let get_status a i =
168      if i < 0 then dummy_status else Array.get a i
169
170    let unsafe_get_status a i =
171      if i < 0 then dummy_status else Array.unsafe_get a i
172
173 IFDEF HTMLTRACE
174   THEN
175 DEFINE IFTRACE(e) = (e)
176   ELSE
177 DEFINE IFTRACE(e) = ()
178 END
179
180    let html tree node i config msg =
181      let config = config.NodeStatus.node in
182      Html.trace ~msg:msg
183        (T.preorder tree node) i
184        config.todo
185        config.sat
186
187
188
189    let debug msg tree node i config =
190      let config = config.NodeStatus.node in
191      eprintf
192        "DEBUG:%s node: %i\nsat: %a\ntodo: %a\nround: %i\n"
193        msg
194        (T.preorder tree node)
195        StateSet.print config.sat
196        StateSet.print config.todo
197        i
198
199    let get_form cache2 auto tag q =
200      let phi =
201        incr cache2_access;
202        Cache.N2.find cache2 (tag.QName.id :> int) (q :> int)
203      in
204      if phi == dummy_form then
205        let phi = Ata.get_form auto tag q in
206        let () =
207          Cache.N2.add
208            cache2
209            (tag.QName.id :> int)
210            (q :> int) phi
211        in phi
212      else begin
213        incr cache2_hit;
214        phi
215      end
216
217    type trivalent = False | True | Unknown
218    let of_bool = function false -> False | true -> True
219    let or_ t1 t2 =
220      match t1 with
221        False -> t2
222      | True -> True
223      | Unknown -> if t2 == True then True else Unknown
224
225    let and_ t1 t2 =
226      match t1 with
227        False -> False
228      | True -> t2
229      | Unknown -> if t2 == False then False else Unknown
230
231  (* Define as macros to get lazyness *)
232 DEFINE OR_(t1,t2) =
233      match t1 with
234        False -> (t2)
235      | True -> True
236      | Unknown -> if (t2) == True then True else Unknown
237
238 DEFINE AND_(t1,t2) =
239      match t1 with
240        False -> False
241      | True -> (t2)
242      | Unknown -> if (t2) == False then False else Unknown
243
244
245    let eval_form phi fcs nss ps ss summary =
246      let open Ata in
247          let rec loop phi =
248            begin match Formula.expr phi with
249            | Boolean.False -> False
250            | Boolean.True -> True
251            | Boolean.Atom (a, b) ->
252                begin
253                  let open NodeSummary in
254                      match a.Atom.node with
255                      | Move (m, q) ->
256                          let down, ({ NodeStatus.node = n_sum; _ } as sum) =
257                            match m with
258                              `First_child -> true, fcs
259                            | `Next_sibling -> true, nss
260                            | `Parent | `Previous_sibling -> false, ps
261                            | `Stay -> false, ss
262                          in
263                          if sum == dummy_status
264                            || (down && n_sum.rank < ss.NodeStatus.node.rank)
265                            || StateSet.mem q n_sum.todo then
266                            Unknown
267                          else
268                            of_bool (b == StateSet.mem q n_sum.sat)
269                      | Is_first_child -> of_bool (b == is_left summary)
270                      | Is_next_sibling -> of_bool (b == is_right summary)
271                      | Is k -> of_bool (b == (k == kind summary))
272                      | Has_first_child -> of_bool (b == has_left summary)
273                      | Has_next_sibling -> of_bool (b == has_right summary)
274                end
275            | Boolean.And(phi1, phi2) -> AND_ (loop phi1, loop phi2)
276            | Boolean.Or (phi1, phi2) -> OR_ (loop phi1, loop phi2)
277            end
278          in
279          loop phi
280
281
282    let eval_trans_aux auto cache2 tag fcs nss ps old_status =
283      let { sat = old_sat;
284            todo = old_todo;
285            summary = old_summary } as os_node = old_status.NodeStatus.node
286      in
287      let sat, todo =
288        StateSet.fold (fun q ((a_sat, a_todo) as acc) ->
289          let phi =
290            get_form cache2 auto tag q
291          in
292
293          let v = eval_form phi fcs nss ps old_status old_summary in
294          match v with
295            True -> StateSet.add q a_sat, a_todo
296          | False -> acc
297          | Unknown -> a_sat, StateSet.add q a_todo
298        ) old_todo (old_sat, StateSet.empty)
299      in
300      if old_sat != sat || old_todo != todo then
301        NodeStatus.make { os_node with sat; todo }
302      else old_status
303
304
305    let eval_trans auto cache2 cache5 tag fcs nss ps ss =
306      let rec loop old_status =
307        let new_status =
308          eval_trans_aux auto cache2 tag fcs nss ps old_status
309        in
310        if new_status == old_status then old_status else loop new_status
311      in
312      let fcsid = (fcs.NodeStatus.id :> int) in
313      let nssid = (nss.NodeStatus.id :> int) in
314      let psid = (ps.NodeStatus.id :> int) in
315      let ssid = (ss.NodeStatus.id :> int) in
316      let tagid = (tag.QName.id :> int) in
317      let res = Cache.N5.find cache5 tagid ssid fcsid nssid psid in
318      incr cache5_access;
319      if res != dummy_status then begin incr cache5_hit; res end
320      else let new_status = loop ss in
321           Cache.N5.add cache5 tagid ssid fcsid nssid psid new_status;
322           new_status
323
324
325
326   let top_down run =
327     let i = run.pass in
328     let tree = run.tree in
329     let auto = run.auto in
330     let status = run.status in
331     let cache2 = run.cache2 in
332     let cache5 = run.cache5 in
333     let unstable = run.unstable in
334     let states_by_rank = Ata.get_states_by_rank auto in
335     let td_todo = states_by_rank.(i) in
336     let bu_todo = if i + 1 = Array.length states_by_rank then StateSet.empty
337       else
338         states_by_rank.(i+1)
339     in
340     let rec loop node =
341       let node_id = T.preorder tree node in
342       if node == T.nil (*|| not (Bitvector.get unstable node_id)*) then false
343       else begin
344         let parent = T.parent tree node in
345         let fc = T.first_child tree node in
346         let fc_id = T.preorder tree fc in
347         let ns = T.next_sibling tree node in
348         let ns_id = T.preorder tree ns in
349         let tag = T.tag tree node in
350         (* We enter the node from its parent *)
351
352         let status0 =
353           let c = unsafe_get_status status node_id in
354           if c.NodeStatus.node.rank < i then
355             (* first time we visit the node during this run *)
356             NodeStatus.make
357               { rank = i;
358                 sat = c.NodeStatus.node.sat;
359                 todo = td_todo;
360                 summary = let summary = c.NodeStatus.node.summary
361                           in
362                           if summary != NodeSummary.dummy then summary
363                           else
364                             NodeSummary.make
365                               (node == T.first_child tree parent) (* is_left *)
366                               (node == T.next_sibling tree parent) (* is_right *)
367                               (fc != T.nil) (* has_left *)
368                               (ns != T.nil) (* has_right *)
369                               (T.kind tree node) (* kind *)
370               }
371           else c
372         in
373         IFTRACE(html tree node _i status0 "Entering node");
374         (* get the node_statuses for the first child, next sibling and parent *)
375         let ps = unsafe_get_status status (T.preorder tree parent) in
376         let fcs = unsafe_get_status status fc_id in
377         let nss = unsafe_get_status status ns_id in
378         (* evaluate the transitions with all this statuses *)
379         let status1 =
380           if status0.NodeStatus.node.todo == StateSet.empty then status0
381           else begin
382             let status1 = eval_trans auto cache2 cache5 tag fcs nss ps status0 in
383             IFTRACE(html tree node _i status1 "Updating transitions");
384           (* update the cache if the status of the node changed *)
385             if status1 != status0 then status.(node_id) <- status1;
386             status1
387           end
388         in
389         (* recursively traverse the first child *)
390         let unstable_left = loop fc in
391         (* here we re-enter the node from its first child,
392            get the new status of the first child *)
393         let fcs1 = unsafe_get_status status fc_id in
394         (* update the status *)
395         let status1 = if status1.NodeStatus.node.rank < i then
396             NodeStatus.make { status1.NodeStatus.node with
397               rank = i;
398               todo = bu_todo }
399           else
400             status1
401         in
402         let status2 =
403           if status1.NodeStatus.node.todo == StateSet.empty then status1
404           else begin
405             let status2 = eval_trans auto cache2 cache5 tag fcs1 nss ps status1 in
406             IFTRACE(html tree node _i status2
407                       "Updating transitions (after first-child)");
408             if status2 != status1 then status.(node_id) <- status2;
409             status2
410           end
411         in
412         let unstable_right = loop ns in
413         let nss1 = unsafe_get_status status ns_id in
414         let status3 =
415           if status2.NodeStatus.node.todo == StateSet.empty then status2
416           else begin
417             let status3 = eval_trans auto cache2 cache5 tag fcs1 nss1 ps status2 in
418             IFTRACE(html tree node _i status3
419                       "Updating transitions (after next-sibling)");
420           if status3 != status2 then status.(node_id) <- status3;
421           status3
422         end
423         in
424         let unstable_self =
425           (* if either our left or right child is unstable or if we
426              still have transitions pending, the current node is
427              unstable *)
428           unstable_left
429           || unstable_right
430           || StateSet.empty != status3.NodeStatus.node.todo
431         in
432         Bitvector.unsafe_set unstable node_id unstable_self;
433         IFTRACE((if not unstable_self then
434             Html.finalize_node
435               node_id
436               _i
437               Ata.(StateSet.intersect status3.NodeStatus.node.sat
438                      (get_selecting_states auto))));
439         unstable_self
440       end
441     in
442     run.redo <- loop (T.root tree);
443     run.pass <- run.pass + 1
444
445
446   let get_results run =
447     let cache = run.status in
448     let auto = run.auto in
449     let tree = run.tree in
450     let rec loop node acc =
451       if node == T.nil then acc
452       else
453         let acc0 = loop (T.next_sibling tree node) acc in
454         let acc1 = loop (T.first_child tree node) acc0 in
455
456         if Ata.(
457           StateSet.intersect
458             cache.(T.preorder tree node).NodeStatus.node.sat
459             (get_selecting_states auto)) then node::acc1
460         else acc1
461     in
462     loop (T.root tree) []
463
464
465   let get_full_results run =
466     let cache = run.status in
467     let auto = run.auto in
468     let tree = run.tree in
469     let res_mapper = Hashtbl.create MED_H_SIZE in
470     let () =
471       StateSet.iter
472         (fun q -> Hashtbl.add res_mapper q [])
473         (Ata.get_selecting_states auto)
474     in
475     let dummy = [ T.nil ] in
476     let res_mapper = Cache.N1.create dummy in
477     let () =
478       StateSet.iter
479         (fun q -> Cache.N1.add res_mapper (q :> int) [])
480         (Ata.get_selecting_states auto)
481     in
482     let rec loop node =
483       if node != T.nil then
484         let () = loop (T.next_sibling tree node) in
485         let () = loop (T.first_child tree node) in
486         StateSet.iter
487           (fun q ->
488             let res = Cache.N1.find res_mapper (q :> int) in
489             if res != dummy then
490               Cache.N1.add res_mapper (q :> int) (node::res)
491           )
492           cache.(T.preorder tree node).NodeStatus.node.sat
493     in
494     loop (T.root tree);
495     (StateSet.fold_right
496        (fun q acc -> (q, Cache.N1.find res_mapper (q :> int))::acc)
497        (Ata.get_selecting_states auto) [])
498
499
500   let prepare_run run list =
501     let tree = run.tree in
502     let auto = run.auto in
503     let status = run.status in
504     List.iter (fun node ->
505       let parent = T.parent tree node in
506       let fc = T.first_child tree node in
507       let ns = T.next_sibling tree node in
508       let status0 =
509         NodeStatus.make
510           { rank = 0;
511             sat = Ata.get_starting_states auto;
512             todo =
513               StateSet.diff (Ata.get_states auto) (Ata.get_starting_states auto);
514             summary = NodeSummary.make
515               (node == T.first_child tree parent) (* is_left *)
516               (node == T.next_sibling tree parent) (* is_right *)
517               (fc != T.nil) (* has_left *)
518               (ns != T.nil) (* has_right *)
519               (T.kind tree node) (* kind *)
520           }
521       in
522       let node_id = T.preorder tree node in
523       status.(node_id) <- status0) list
524
525   let tree_size = ref 0
526   let pass = ref 0
527   let compute_run auto tree nodes =
528     pass := 0;
529     tree_size := T.size tree;
530     let run = make auto tree in
531     prepare_run run nodes;
532     for i = 0 to Ata.get_max_rank auto do
533       top_down run
534     done;
535     pass := Ata.get_max_rank auto + 1;
536     IFTRACE(Html.gen_trace auto (module T : Tree.S with type t = T.t) tree);
537
538     run
539
540   let full_eval auto tree nodes =
541     let r = compute_run auto tree nodes in
542     get_full_results r
543
544   let eval auto tree nodes =
545     let r = compute_run auto tree nodes in
546     get_results r
547
548   let stats () = {
549     tree_size = !tree_size;
550     run = !pass;
551     cache2_access = !cache2_access;
552     cache2_hit = !cache2_hit;
553     cache5_access = !cache5_access;
554     cache5_hit = !cache5_hit;
555   }
556
557 end