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