Rework the formula predicates:
[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-09 09:22:47 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_attribute ->
52                 QName.has_attribute_prefix (T.tag tree node)
53             | Has_first_child ->
54                 T.nil != T.first_child tree node
55             | Has_next_sibling ->
56                 T.nil != T.next_sibling tree node
57           in
58           if Ata.is_move p && (not b) then
59             eprintf "Warning: Invalid negative atom %a" Ata.Atom.print a;
60           b == pos
61       | Formula.And(phi1, phi2) -> loop phi1 && loop phi2
62       | Formula.Or (phi1, phi2) -> loop phi1 || loop phi2
63     in
64     loop phi
65
66   let eval_trans l tree node fcs nss ps ss acc =
67     List.fold_left (fun (acct, accs) ((q, phi) as trs) ->
68       if StateSet.mem q accs then (acct, accs) else
69       if eval_form phi tree node fcs nss ps ss then
70         (acct, StateSet.add q accs)
71       else
72         (trs::acct, accs)
73     ) ([], acc) l
74
75   let top_down_run auto tree node cache i =
76     let redo = ref false in
77     let rec loop node =
78       if node != T.nil then begin
79         let parent = T.parent tree node in
80         let fc = T.first_child tree node in
81         let ns = T.next_sibling tree node in
82         let states0 = get cache tree node in
83         let tag = T.tag tree node in
84         let trans0 = Ata.get_trans auto auto.Ata.states tag in
85         let ps = get cache tree parent in
86         let fcs = get cache tree fc in
87         let nss = get cache tree ns in
88         eprintf "-- [Iteration % 4d] --\n node: %a\n%!" i T.print_node node;
89         List.iter (fun (q, phi) -> eprintf " %a -> %a\n"
90           State.print q Ata.SFormula.print phi) trans0;
91         eprintf "----------------------\n%!";
92         let trans1, states1 =
93           eval_trans trans0 tree node fcs nss ps states0 states0
94         in
95         if states1 != states0 then set cache tree node states1;
96         let () = loop fc in
97         let fcs1 = get cache tree fc in
98         let trans2, states2 =
99           eval_trans trans1 tree node fcs1 nss ps states1 states1
100         in
101         if states2 != states1 then set cache tree node states2;
102         let () = loop ns in
103         let _, states3 =
104           eval_trans trans2 tree node fcs1 (get cache tree ns) ps states2 states2
105         in
106         if states3 != states2 then set cache tree node states3;
107         if states0 != states3 && (not !redo) then redo := true
108       end
109     in
110     loop node;
111     !redo
112
113   let get_results auto tree node cache =
114     let rec loop node acc =
115       if node == T.nil then acc
116       else
117         let acc0 = loop (T.next_sibling tree node) acc in
118         let acc1 = loop (T.first_child tree node) acc0 in
119
120         if StateSet.intersect (get cache tree node) auto.Ata.selection_states then
121           node::acc1
122         else
123           acc1
124     in
125     loop node []
126
127   let eval auto tree node =
128     let cache = Hashtbl.create 511 in
129     let redo = ref true in
130     let iter = ref 0 in
131     while !redo do
132       redo := top_down_run auto tree node cache !iter;
133       incr iter;
134     done;
135     get_results auto tree node cache
136
137 end