Add a caching module.
[tatoo.git] / src / auto / eval.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 (*
17   Time-stamp: <Last modified on 2013-03-13 14:56:29 CET by Kim Nguyen>
18 *)
19
20 INCLUDE "utils.ml"
21 open Format
22 open Utils
23
24 module Make (T : Tree.Sig.S) = struct
25
26   type cache = (int, StateSet.t) Hashtbl.t
27
28   let get c t n =
29     try Hashtbl.find c (T.preorder t n)
30     with Not_found -> StateSet.empty
31
32   let set c t n v = Hashtbl.replace c (T.preorder t n) v
33   let eval_form  phi tree node fcs nss ps ss =
34     let rec loop phi =
35       match Ata.SFormula.expr phi with
36         Formula.True -> true
37       | Formula.False -> false
38       | Formula.Atom a ->
39           let p, b, q = Ata.Atom.node a in
40           let pos =
41             let open Ata in
42             match p with
43             | First_child -> StateSet.mem q fcs
44             | Next_sibling ->  StateSet.mem q nss
45             | Parent | Previous_sibling -> StateSet.mem q ps
46             | Stay -> StateSet.mem q ss
47             | Is_first_child ->
48                 node == (T.first_child tree (T.parent tree node))
49             | Is_next_sibling ->
50                 node == (T.next_sibling tree (T.parent tree node))
51             | Is k -> k == (T.kind tree node)
52             | Has_first_child ->
53                 T.nil != T.first_child tree node
54             | Has_next_sibling ->
55                 T.nil != T.next_sibling tree node
56           in
57           if Ata.is_move p && (not b) then
58             eprintf "Warning: Invalid negative atom %a" Ata.Atom.print a;
59           b == pos
60       | Formula.And(phi1, phi2) -> loop phi1 && loop phi2
61       | Formula.Or (phi1, phi2) -> loop phi1 || loop phi2
62     in
63     loop phi
64
65   let eval_trans l tree node fcs nss ps ss acc =
66     List.fold_left (fun (acct, accs) ((q, phi) as trs) ->
67       if StateSet.mem q accs then (acct, accs) else
68       if eval_form phi tree node fcs nss ps ss then
69         (acct, StateSet.add q accs)
70       else
71         (trs::acct, accs)
72     ) ([], acc) l
73
74   let top_down_run auto tree node cache _i =
75     let redo = ref false in
76     let rec loop node =
77       if node != T.nil then begin
78         let parent = T.parent tree node in
79         let fc = T.first_child tree node in
80         let ns = T.next_sibling tree node in
81         let states0 = get cache tree node in
82         let tag = T.tag tree node in
83         let trans0 = Ata.get_trans auto auto.Ata.states tag in
84         let ps = get cache tree parent in
85         let fcs = get cache tree fc in
86         let nss = get cache tree ns in
87         let trans1, states1 =
88           eval_trans trans0 tree node fcs nss ps states0 states0
89         in
90         if states1 != states0 then set cache tree node states1;
91         let () = loop fc in
92         let fcs1 = get cache tree fc in
93         let trans2, states2 =
94           eval_trans trans1 tree node fcs1 nss ps states1 states1
95         in
96         if states2 != states1 then set cache tree node states2;
97         let () = loop ns in
98         let _, states3 =
99           eval_trans trans2 tree node fcs1 (get cache tree ns) ps states2 states2
100         in
101         if states3 != states2 then set cache tree node states3;
102         if states0 != states3 && (not !redo) then redo := true
103       end
104     in
105     loop node;
106     !redo
107
108   let get_results auto tree node cache =
109     let rec loop node acc =
110       if node == T.nil then acc
111       else
112         let acc0 = loop (T.next_sibling tree node) acc in
113         let acc1 = loop (T.first_child tree node) acc0 in
114
115         if StateSet.intersect (get cache tree node) auto.Ata.selection_states then
116           node::acc1
117         else
118           acc1
119     in
120     loop node []
121
122   let eval auto tree node =
123     let cache = Hashtbl.create 511 in
124     let redo = ref true in
125     let iter = ref 0 in
126     while !redo do
127       redo := top_down_run auto tree node cache !iter;
128       incr iter;
129     done;
130     get_results auto tree node cache
131
132 end