7d37e5b2826e5b51b74f04ea94f09a97b1ddee5d
[tatoo.git] / src / formula.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-04-04 18:46:09 CEST by Kim Nguyen>
18 *)
19
20 INCLUDE "utils.ml"
21
22 open Format
23
24 (*
25
26 (** Implementation of hashconsed Boolean formulae *)
27
28 *)
29 module type ATOM =
30 sig
31   type t
32   val neg : t -> t
33   include Hcons.Abstract with type t := t
34   include Common_sig.Printable with type t := t
35 end
36
37 type ('formula,'atom) expr =
38   | False
39   | True
40   | Or of 'formula * 'formula
41   | And of 'formula * 'formula
42   | Atom of 'atom
43
44 module Make (P: ATOM) =
45 struct
46
47
48   type 'hcons node = {
49     pos : ('hcons,P.t) expr;
50     mutable neg : 'hcons;
51   }
52
53   external hash_const_variant : [> ] -> int = "%identity"
54   external vb : bool -> int = "%identity"
55
56   module rec Node : Hcons.S
57     with type data = Data.t = Hcons.Make (Data)
58     and Data : Common_sig.HashedType  with type t = Node.t node =
59   struct
60     type t =  Node.t node
61     let equal x y =
62       match x.pos, y.pos with
63       | a,b when a == b -> true
64       | Or(xf1, xf2), Or(yf1, yf2)
65       | And(xf1, xf2), And(yf1,yf2)  -> xf1 == yf1 && xf2 == yf2
66       | Atom(p1), Atom(p2) -> p1 == p2
67       | _ -> false
68
69     let hash f =
70       match f.pos with
71       | False -> 0
72       | True -> 1
73       | Or (f1, f2) ->
74           HASHINT3 (PRIME1, Uid.to_int f1.Node.id, Uid.to_int f2.Node.id)
75       | And (f1, f2) ->
76           HASHINT3(PRIME3, Uid.to_int f1.Node.id, Uid.to_int f2.Node.id)
77       | Atom(p) -> HASHINT2(PRIME5, Uid.to_int (P.uid p))
78   end
79
80     type t = Node.t
81     let hash x = x.Node.hash
82     let uid x = x.Node.id
83     let equal = Node.equal
84     let expr f = f.Node.node.pos
85
86     let compare f1 f2 = compare f1.Node.id  f2.Node.id
87     let prio f =
88       match expr f with
89       | True | False -> 10
90       | Atom _ -> 8
91       | And _ -> 6
92       | Or _ -> 1
93
94     let rec print ?(parent=false) ppf f =
95       if parent then fprintf ppf "(";
96       let _ = match expr f with
97       | True -> fprintf ppf "%s" Pretty.top
98       | False -> fprintf ppf "%s" Pretty.bottom
99       | And(f1,f2) ->
100           print ~parent:(prio f > prio f1) ppf f1;
101           fprintf ppf " %s "  Pretty.wedge;
102           print ~parent:(prio f > prio f2) ppf f2;
103       | Or(f1,f2) ->
104           (print ppf f1);
105           fprintf ppf " %s " Pretty.vee;
106           (print ppf f2);
107       | Atom(p) -> fprintf ppf "%a" P.print p
108 (*          let _ = flush_str_formatter() in
109           let fmt = str_formatter in
110           let a_str, d_str =
111           match  dir with
112           | `Left ->  Pretty.down_arrow, Pretty.subscript 1
113           | `Right -> Pretty.down_arrow, Pretty.subscript 2
114           | `Epsilon -> Pretty.epsilon, ""
115           | `Up1 -> Pretty.up_arrow, Pretty.subscript 1
116           | `Up2 -> Pretty.up_arrow, Pretty.subscript 2
117         in
118         fprintf fmt "%s%s" a_str d_str;
119         State.print fmt s;
120         let str = flush_str_formatter() in
121         if b then fprintf ppf "%s" str
122         else Pretty.pp_overline ppf str *)
123   in
124     if parent then fprintf ppf ")"
125
126 let print ppf f =  print ~parent:false ppf f
127
128 let is_true f = (expr f) == True
129 let is_false f = (expr f) == False
130
131
132 let cons pos neg =
133   let nnode = Node.make { pos = neg; neg = Obj.magic 0 } in
134   let pnode = Node.make { pos = pos; neg = nnode } in
135     (Node.node nnode).neg <- pnode; (* works because the neg field isn't taken into
136                                        account for hashing ! *)
137     pnode,nnode
138
139
140 let true_,false_ = cons True False
141
142 let atom_ p = fst (cons (Atom(p)) (Atom(P.neg p)))
143
144 let not_ f = f.Node.node.neg
145
146 let order f1 f2 = if uid f1 < uid f2 then f2,f1 else f1,f2
147
148 let or_ f1 f2 =
149   (* Tautologies: x|x, x|not(x) *)
150
151   if equal f1 f2 then f1
152   else if equal f1 (not_ f2) then true_
153
154   (* simplification *)
155   else if is_true f1 || is_true f2 then true_
156   else if is_false f1 && is_false f2 then false_
157   else if is_false f1 then f2
158   else if is_false f2 then f1
159
160   (* commutativity of | *)
161   else
162     let f1, f2 = order f1 f2 in
163       fst (cons (Or(f1,f2)) (And(not_ f1, not_ f2)))
164
165
166 let and_ f1 f2 =
167   not_ (or_ (not_ f1) (not_ f2))
168
169
170 let of_bool = function true -> true_ | false -> false_
171
172 let fold f phi acc =
173   let rec loop phi acc =
174     match expr phi with
175     | And (phi1, phi2) | Or(phi1, phi2)  ->
176         loop phi2 (loop phi1 (f phi acc))
177     | _ -> f phi acc
178   in
179   loop phi acc
180
181 end