Add a counter for eval/infer.
[tatoo.git] / src / formula.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                     Kim Nguyen, 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 INCLUDE "utils.ml"
16
17 open Format
18 type move = [ `Left | `Right | `Self ]
19 type 'hcons expr =
20   | False | True
21   | Or of 'hcons * 'hcons
22   | And of 'hcons * 'hcons
23   | Atom of (move * bool * State.t)
24
25 type 'hcons node = {
26   pos : 'hcons expr;
27   mutable neg : 'hcons;
28   st : StateSet.t * StateSet.t * StateSet.t;
29   size: int; (* Todo check if this is needed *)
30 }
31
32 external hash_const_variant : [> ] -> int = "%identity"
33 external vb : bool -> int = "%identity"
34
35 module rec Node : Hcons.S
36   with type data = Data.t = Hcons.Make (Data)
37   and Data : Hashtbl.HashedType  with type t = Node.t node =
38   struct
39     type t =  Node.t node
40     let equal x y = x.size == y.size &&
41       match x.pos, y.pos with
42       | a,b when a == b -> true
43       | Or(xf1, xf2), Or(yf1, yf2)
44       | And(xf1, xf2), And(yf1,yf2)  -> (xf1 == yf1) && (xf2 == yf2)
45       | Atom(d1, p1, s1), Atom(d2 ,p2 ,s2) -> d1 == d2 && p1 == p2 && s1 == s2
46       | _ -> false
47
48     let hash f =
49       match f.pos with
50       | False -> 0
51       | True -> 1
52       | Or (f1, f2) ->
53         HASHINT3 (PRIME1, Uid.to_int f1.Node.id, Uid.to_int f2.Node.id)
54       | And (f1, f2) ->
55         HASHINT3(PRIME3, Uid.to_int f1.Node.id, Uid.to_int f2.Node.id)
56
57       | Atom(d, p, s) -> HASHINT4(PRIME5, hash_const_variant d,vb p,s)
58   end
59
60 type t = Node.t
61 let hash x = x.Node.key
62 let uid x = x.Node.id
63 let equal = Node.equal
64 let expr f = f.Node.node.pos
65 let st f = f.Node.node.st
66 let size f = f.Node.node.size
67 let compare f1 f2 = compare f1.Node.id  f2.Node.id
68 let prio f =
69   match expr f with
70     | True | False -> 10
71     | Atom _ -> 8
72     | And _ -> 6
73     | Or _ -> 1
74       
75 (* Begin Lucca Hirschi *)
76 module type HcEval =
77 sig
78   type t = StateSet.t*StateSet.t*StateSet.t*Node.t
79   val equal : t -> t -> bool
80   val hash : t -> int
81 end
82   
83 type dStateS = StateSet.t*StateSet.t
84 module type HcInfer =
85 sig
86   type t = dStateS*dStateS*dStateS*Node.t
87   val equal : t -> t -> bool
88   val hash : t -> int
89 end
90     
91 module HcEval : HcEval = struct
92   type t =
93       StateSet.t*StateSet.t*StateSet.t*Node.t
94   let equal (s,l,r,f) (s',l',r',f') = StateSet.equal s s' &&
95     StateSet.equal l l' && StateSet.equal r r' && Node.equal f f'
96   let hash (s,l,r,f) =
97     HASHINT4(StateSet.hash s, StateSet.hash l, StateSet.hash r, Node.hash f)
98 end
99   
100 let dequal (x,y) (x',y') = StateSet.equal x x' && StateSet.equal y y'
101 let dhash (x,y) = HASHINT2(StateSet.hash x, StateSet.hash y)
102 module HcInfer : HcInfer = struct
103   type t = dStateS*dStateS*dStateS*Node.t
104   let equal (s,l,r,f) (s',l',r',f') = dequal s s' &&
105     dequal l l' && dequal r r' && Node.equal f f'
106   let hash (s,l,r,f) =
107     HASHINT4(dhash s, dhash l, dhash r, Node.hash f)
108 end
109
110 module HashEval = Hashtbl.Make(HcEval)
111 module HashInfer = Hashtbl.Make(HcInfer)
112 type hcEval = bool Hashtbl.Make(HcEval).t
113 type hcInfer = bool Hashtbl.Make(HcInfer).t
114
115 let num_call = ref 0
116 let num_miss = ref 0
117 let num_call_i = ref 0
118 let num_miss_i = ref 0
119 let () = at_exit(fun () -> Format.fprintf Format.err_formatter
120   "Num: call %d, Num Miss: %d\n%!" (!num_call) (!num_miss);
121   Format.fprintf Format.err_formatter
122     "Num: call_i %d, Num Miss_i: %d\n%!" (!num_call_i) (!num_miss_i))
123
124 let rec eval_form (q,qf,qn) f hashEval =
125   incr num_call;
126   try HashEval.find hashEval (q,qf,qn,f)
127   with _ ->
128     incr num_miss;  
129   let res = match expr f with
130       | False -> false
131       | True -> true 
132       | And(f1,f2) -> eval_form (q,qf,qn) f1 hashEval &&
133         eval_form (q,qf,qn) f2 hashEval
134       | Or(f1,f2) -> eval_form (q,qf,qn) f1 hashEval ||
135         eval_form (q,qf,qn) f2 hashEval
136       | Atom(dir, b, s) -> 
137         let set = match dir with
138           |`Left -> qf | `Right -> qn | `Self -> q in
139         if b then StateSet.mem s set
140         else not (StateSet.mem s set) in
141     HashEval.add hashEval (q,qf,qn,f) res;
142     res
143       
144 let rec infer_form sq sqf sqn f hashInfer =
145   incr num_call_i;
146   try HashInfer.find hashInfer (sq,sqf,sqn,f)
147   with _ ->
148   incr num_miss_i;
149   let res = match expr f with
150     | False -> false
151     | True -> true
152     | And(f1,f2) -> infer_form sq sqf sqn f1 hashInfer &&
153       infer_form sq sqf sqn f2 hashInfer
154     | Or(f1,f2) -> infer_form sq sqf sqn f1 hashInfer ||
155       infer_form sq sqf sqn f2 hashInfer
156     | Atom(dir, b, s) -> 
157       let setq, setr = match dir with
158         | `Left -> sqf | `Right -> sqn | `Self -> sq in
159     (* WG: WE SUPPOSE THAT Q^r and Q^q are disjoint ! *)
160       let mem =  StateSet.mem s setq || StateSet.mem s setr in
161       if b then mem else not mem in
162   HashInfer.add hashInfer (sq,sqf,sqn,f) res;
163   res   
164 (* End *)
165       
166 let rec print ?(parent=false) ppf f =
167   if parent then fprintf ppf "(";
168   let _ = match expr f with
169     | True -> fprintf ppf "%s" Pretty.top
170     | False -> fprintf ppf "%s" Pretty.bottom
171     | And(f1,f2) ->
172       print ~parent:(prio f > prio f1) ppf f1;
173       fprintf ppf " %s "  Pretty.wedge;
174       print ~parent:(prio f > prio f2) ppf f2;
175     | Or(f1,f2) ->
176       (print ppf f1);
177       fprintf ppf " %s " Pretty.vee;
178       (print ppf f2);
179     | Atom(dir, b, s) ->
180       let _ = flush_str_formatter() in
181       let fmt = str_formatter in
182         let a_str, d_str =
183           match  dir with
184           | `Left ->  Pretty.down_arrow, Pretty.subscript 1
185           | `Right -> Pretty.down_arrow, Pretty.subscript 2
186           | `Self -> Pretty.down_arrow, Pretty.subscript 0
187         in
188         fprintf fmt "%s%s" a_str d_str;
189         State.print fmt s;
190         let str = flush_str_formatter() in
191         if b then fprintf ppf "%s" str
192         else Pretty.pp_overline ppf str
193   in
194     if parent then fprintf ppf ")"
195
196 let print ppf f =  print ~parent:false ppf f
197
198 let is_true f = (expr f) == True
199 let is_false f = (expr f) == False
200
201
202 let cons pos neg s1 s2 size1 size2 =
203   let nnode = Node.make { pos = neg; neg = (Obj.magic 0); st = s2; size = size2 } in
204   let pnode = Node.make { pos = pos; neg = nnode ; st = s1; size = size1 } in
205     (Node.node nnode).neg <- pnode; (* works because the neg field isn't taken into
206                                        account for hashing ! *)
207     pnode,nnode
208
209
210 let empty_triple = StateSet.empty, StateSet.empty, StateSet.empty
211 let true_,false_ = cons True False empty_triple empty_triple 0 0
212 let atom_ d p s =
213   let si = StateSet.singleton s in
214   let ss = match d with
215     | `Left -> StateSet.empty, si, StateSet.empty
216     | `Right -> StateSet.empty, StateSet.empty, si
217     | `Self -> si, StateSet.empty, StateSet.empty
218   in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1)
219
220 let not_ f = f.Node.node.neg
221
222 let union_triple (s1,l1,r1) (s2,l2, r2) =
223   StateSet.union s1 s2,
224   StateSet.union l1 l2,
225   StateSet.union r1 r2
226
227 let merge_states f1 f2 =
228   let sp =
229     union_triple (st f1) (st f2)
230   and sn =
231     union_triple (st (not_ f1)) (st (not_ f2))
232   in
233     sp,sn
234
235 let order f1 f2 = if uid f1  < uid f2 then f2,f1 else f1,f2
236
237 let or_ f1 f2 =
238   (* Tautologies: x|x, x|not(x) *)
239
240   if equal f1 f2 then f1
241   else if equal f1 (not_ f2) then true_
242
243   (* simplification *)
244   else if is_true f1 || is_true f2 then true_
245   else if is_false f1 && is_false f2 then false_
246   else if is_false f1 then f2
247   else if is_false f2 then f1
248
249   (* commutativity of | *)
250   else
251     let f1, f2 = order f1 f2 in
252     let psize = (size f1) + (size f2) in
253     let nsize = (size (not_ f1)) + (size (not_ f2)) in
254     let sp, sn = merge_states f1 f2 in
255       fst (cons (Or(f1,f2)) (And(not_ f1, not_ f2)) sp sn psize nsize)
256
257
258 let and_ f1 f2 =
259   not_ (or_ (not_ f1) (not_ f2))
260
261
262 let of_bool = function true -> true_ | false -> false_
263
264
265 module Infix = struct
266   let ( +| ) f1 f2 = or_ f1 f2
267
268   let ( *& ) f1 f2 = and_ f1 f2
269
270   let ( *+ ) d s = atom_ d true s
271   let ( *- ) d s = atom_ d false s
272 end