Sanitize the representation of formula
[tatoo.git] / src / ata.ml
index df43392..3fa2698 100644 (file)
 
 INCLUDE "utils.ml"
 open Format
+type move = [ `First_child
+            | `Next_sibling
+            | `Parent
+            | `Previous_sibling
+            | `Stay ]
 
-type predicate = | First_child
-                 | Next_sibling
-                 | Parent
-                 | Previous_sibling
-                 | Stay
+type predicate = Move of move * State.t
                  | Is_first_child
                  | Is_next_sibling
-                 | Is of (Tree.NodeKind.t)
+                 | Is of Tree.NodeKind.t
                  | Has_first_child
                  | Has_next_sibling
 
-let is_move p = match p with
-| First_child | Next_sibling
-| Parent | Previous_sibling | Stay -> true
-| _ -> false
+let is_move = function Move _ -> true | _ -> false
 
-
-type atom = predicate * bool * State.t
-
-module Atom : (Formula.ATOM with type data = atom) =
+module Atom : (Boolean.ATOM with type data = predicate) =
 struct
 
   module Node =
   struct
-    type t = atom
+    type t = predicate
     let equal n1 n2 = n1 = n2
     let hash n = Hashtbl.hash n
   end
@@ -48,85 +43,74 @@ struct
   include Hcons.Make(Node)
 
   let print ppf a =
-    let p, b, q = a.node in
-    if not b then fprintf ppf "%s" Pretty.lnot;
-    match p with
-    | First_child -> fprintf ppf "FC(%a)" State.print q
-    | Next_sibling -> fprintf ppf "NS(%a)" State.print q
-    | Parent -> fprintf ppf "FC%s(%a)" Pretty.inverse State.print q
-    | Previous_sibling -> fprintf ppf "NS%s(%a)" Pretty.inverse State.print q
-    | Stay -> fprintf ppf "%s(%a)" Pretty.epsilon State.print q
-    | Is_first_child -> fprintf ppf "FC%s?" Pretty.inverse
-    | Is_next_sibling -> fprintf ppf "NS%s?" Pretty.inverse
+    match a.node with
+    | Move (m, q) -> begin
+      match m with
+        `First_child -> fprintf ppf "%s" Pretty.down_arrow
+      | `Next_sibling -> fprintf ppf "%s" Pretty.right_arrow
+      | `Parent -> fprintf ppf "%s" Pretty.up_arrow
+      | `Previous_sibling -> fprintf ppf "%s" Pretty.left_arrow
+      | `Stay -> fprintf ppf "%s" Pretty.bullet
+    end;
+        fprintf ppf "%a" State.print q
+    | Is_first_child -> fprintf ppf "%s?" Pretty.up_arrow
+    | Is_next_sibling -> fprintf ppf "%s?" Pretty.left_arrow
     | Is k -> fprintf ppf "is-%a?" Tree.NodeKind.print k
-    | Has_first_child -> fprintf ppf "FC?"
-    | Has_next_sibling -> fprintf ppf "NS?"
-
-  let neg a =
-    let p, b, q = a.node in
-    make (p, not b, q)
-
+    | Has_first_child -> fprintf ppf "%s?" Pretty.down_arrow
+    | Has_next_sibling -> fprintf ppf "%s?" Pretty.right_arrow
 
 end
 
-module SFormula =
+module Formula =
 struct
-  include Formula.Make(Atom)
+  include Boolean.Make(Atom)
   open Tree.NodeKind
-  let mk_atom a b c = atom_ (Atom.make (a,b,c))
-  let mk_kind k = mk_atom (Is k) true State.dummy
-  let has_first_child =
-    (mk_atom Has_first_child true State.dummy)
+  let mk_atom a = atom_ (Atom.make a)
+  let mk_kind k = mk_atom (Is k)
+
+  let has_first_child = mk_atom Has_first_child
 
-  let has_next_sibling =
-    (mk_atom Has_next_sibling true State.dummy)
+  let has_next_sibling = mk_atom Has_next_sibling
 
-  let is_first_child =
-    (mk_atom Is_first_child true State.dummy)
+  let is_first_child = mk_atom Is_first_child
 
-  let is_next_sibling =
-    (mk_atom Is_next_sibling true State.dummy)
+  let is_next_sibling = mk_atom Is_next_sibling
 
-  let is_attribute =
-    (mk_atom (Is Attribute) true State.dummy)
+  let is_attribute = mk_atom (Is Attribute)
 
-  let is_element =
-    (mk_atom (Is Element) true State.dummy)
+  let is_element = mk_atom (Is Element)
 
-  let is_processing_instruction =
-    (mk_atom (Is ProcessingInstruction) true State.dummy)
+  let is_processing_instruction = mk_atom (Is ProcessingInstruction)
 
-  let is_comment =
-    (mk_atom (Is Comment) true State.dummy)
+  let is_comment = mk_atom (Is Comment)
 
+  let mk_move m q = mk_atom (Move(m,q))
   let first_child q =
-  and_
-    (mk_atom First_child true q)
-    has_first_child
+    and_
+      (mk_move `First_child q)
+      has_first_child
 
   let next_sibling q =
   and_
-    (mk_atom Next_sibling true q)
+    (mk_move `Next_sibling q)
     has_next_sibling
 
   let parent q =
   and_
-    (mk_atom Parent true q)
+    (mk_move `Parent  q)
     is_first_child
 
   let previous_sibling q =
   and_
-    (mk_atom Previous_sibling true q)
+    (mk_move `Previous_sibling q)
     is_next_sibling
 
-  let stay q =
-    (mk_atom Stay true q)
+  let stay q = mk_move `Stay q
 
   let get_states phi =
     fold (fun phi acc ->
       match expr phi with
-      | Formula.Atom a -> let _, _, q = Atom.node a in
-                          if q != State.dummy then StateSet.add q acc else acc
+      | Boolean.Atom ({ Atom.node = Move(_,q) ; _ }, _) ->  StateSet.add q acc
       | _ -> acc
     ) phi StateSet.empty
 
@@ -134,11 +118,11 @@ end
 
 
 module Transition = Hcons.Make (struct
-  type t = State.t * QNameSet.t * SFormula.t
+  type t = State.t * QNameSet.t * Formula.t
   let equal (a, b, c) (d, e, f) =
     a == d && b == e && c == f
   let hash (a, b, c) =
-    HASHINT4 (PRIME1, a, ((QNameSet.uid b) :> int), ((SFormula.uid c) :> int))
+    HASHINT4 (PRIME1, a, ((QNameSet.uid b) :> int), ((Formula.uid c) :> int))
 end)
 
 
@@ -151,7 +135,7 @@ end =
     let print ppf ?(sep="\n") l =
       iter (fun t ->
         let q, lab, f = Transition.node t in
-        fprintf ppf "%a, %a -> %a%s" State.print q QNameSet.print lab SFormula.print f sep) l
+        fprintf ppf "%a, %a -> %a%s" State.print q QNameSet.print lab Formula.print f sep) l
   end
 
 
@@ -218,7 +202,7 @@ type t = {
   id : Uid.t;
   mutable states : StateSet.t;
   mutable selection_states: StateSet.t;
-  transitions: (State.t, (QNameSet.t*SFormula.t) list) Hashtbl.t;
+  transitions: (State.t, (QNameSet.t*Formula.t) list) Hashtbl.t;
   mutable cache2 : TransList.t Cache.N2.t;
   mutable cache4 : Config.t Cache.N4.t;
 }
@@ -226,7 +210,7 @@ type t = {
 let next = Uid.make_maker ()
 
 let dummy2 = TransList.cons
-  (Transition.make (State.dummy,QNameSet.empty, SFormula.false_))
+  (Transition.make (State.dummy,QNameSet.empty, Formula.false_))
   TransList.nil
 
 
@@ -300,30 +284,33 @@ let get_trans a tag states =
 
 let simplify_atom atom pos q { Config.node=config; _ } =
   if (pos && StateSet.mem q config.sat)
-    || ((not pos) && StateSet.mem q config.unsat) then SFormula.true_
+    || ((not pos) && StateSet.mem q config.unsat) then Formula.true_
   else if (pos && StateSet.mem q config.unsat)
-      || ((not pos) && StateSet.mem q config.sat) then SFormula.false_
+      || ((not pos) && StateSet.mem q config.sat) then Formula.false_
   else atom
 
 let eval_form phi fcs nss ps ss summary =
   let rec loop phi =
-    begin match SFormula.expr phi with
-      Formula.True | Formula.False -> phi
-    | Formula.Atom a ->
-        let p, b, q = Atom.node a in begin
-          match p with
-          | First_child -> simplify_atom phi b q fcs
-          | Next_sibling -> simplify_atom phi b q nss
-          | Parent | Previous_sibling -> simplify_atom phi b q ps
-          | Stay -> simplify_atom phi b q ss
-          | Is_first_child -> SFormula.of_bool (b == (is_left summary))
-          | Is_next_sibling -> SFormula.of_bool (b == (is_right summary))
-          | Is k -> SFormula.of_bool (b == (k == (kind summary)))
-          | Has_first_child -> SFormula.of_bool (b == (has_left summary))
-          | Has_next_sibling -> SFormula.of_bool (b == (has_right summary))
+    begin match Formula.expr phi with
+      Boolean.True | Boolean.False -> phi
+    | Boolean.Atom (a, b) ->
+        begin
+          match a.Atom.node with
+          | Move (m, q) -> 
+              let states = match m with
+                `First_child -> fcs
+              | `Next_sibling -> nss
+              | `Parent | `Previous_sibling -> ps
+              | `Stay -> ss
+              in simplify_atom phi b q states
+          | Is_first_child -> Formula.of_bool (b == (is_left summary))
+          | Is_next_sibling -> Formula.of_bool (b == (is_right summary))
+          | Is k -> Formula.of_bool (b == (k == (kind summary)))
+          | Has_first_child -> Formula.of_bool (b == (has_left summary))
+          | Has_next_sibling -> Formula.of_bool (b == (has_right summary))
         end
-    | Formula.And(phi1, phi2) -> SFormula.and_ (loop phi1) (loop phi2)
-    | Formula.Or (phi1, phi2) -> SFormula.or_  (loop phi1) (loop phi2)
+    | Boolean.And(phi1, phi2) -> Formula.and_ (loop phi1) (loop phi2)
+    | Boolean.Or (phi1, phi2) -> Formula.or_  (loop phi1) (loop phi2)
     end
   in
   loop phi
@@ -354,9 +341,9 @@ let eval_trans auto fcs nss ps ss =
                 let new_phi =
                   eval_form phi fcs nss ps old_config old_summary
                 in
-                if SFormula.is_true new_phi then
+                if Formula.is_true new_phi then
                   StateSet.add q a_sat, a_unsat, StateSet.add q a_rem, a_kept, a_todo
-                else if SFormula.is_false new_phi then
+                else if Formula.is_false new_phi then
                   a_sat, StateSet.add q a_unsat, StateSet.add q a_rem, a_kept, a_todo
                 else
                   let new_tr = Transition.make (q, lab, new_phi) in
@@ -389,11 +376,11 @@ let add_trans a q s f =
       let lab2 = QNameSet.diff labs s in
       let tr1 =
         if QNameSet.is_empty lab1 then []
-        else [ (lab1, SFormula.or_ phi f) ]
+        else [ (lab1, Formula.or_ phi f) ]
       in
       let tr2 =
         if QNameSet.is_empty lab2 then []
-        else [ (lab2, SFormula.or_ phi f) ]
+        else [ (lab2, Formula.or_ phi f) ]
       in
       (QNameSet.union acup labs, tr1@ tr2 @ atrs)
     ) (QNameSet.empty, []) trs
@@ -433,7 +420,7 @@ let print fmt a =
   let strs_strings, max_pre, max_all = List.fold_left (fun (accl, accp, acca) (q, s, f) ->
     let s1 = State.print _str_fmt q; _flush_str_fmt () in
     let s2 = QNameSet.print _str_fmt s;  _flush_str_fmt () in
-    let s3 = SFormula.print _str_fmt f;  _flush_str_fmt () in
+    let s3 = Formula.print _str_fmt f;  _flush_str_fmt () in
     let pre = Pretty.length s1 + Pretty.length s2 in
     let all = Pretty.length s3 in
     ( (q, s1, s2, s3) :: accl, max accp pre, max acca all)
@@ -467,7 +454,7 @@ let complete_transitions a =
     let nqtrans =
       if QNameSet.is_empty rem then qtrans
       else
-        (rem, SFormula.false_) :: qtrans
+        (rem, Formula.false_) :: qtrans
     in
     Hashtbl.replace a.transitions q nqtrans
   ) a.states
@@ -479,7 +466,7 @@ let cleanup_states a =
       memo := StateSet.add q !memo;
       let trs = try Hashtbl.find a.transitions q with Not_found -> [] in
       List.iter (fun (_, phi) ->
-        StateSet.iter loop (SFormula.get_states phi)) trs
+        StateSet.iter loop (Formula.get_states phi)) trs
     end
   in
   StateSet.iter loop a.selection_states;
@@ -496,39 +483,39 @@ let normalize_negations auto =
   let memo_state = Hashtbl.create 17 in
   let todo = Queue.create () in
   let rec flip b f =
-    match SFormula.expr f with
-      Formula.True | Formula.False -> if b then f else SFormula.not_ f
-    | Formula.Or(f1, f2) -> (if b then SFormula.or_ else SFormula.and_)(flip b f1) (flip b f2)
-    | Formula.And(f1, f2) -> (if b then SFormula.and_ else SFormula.or_)(flip b f1) (flip b f2)
-    | Formula.Atom(a) -> begin
-      let l, b', q = Atom.node a in
-      if q == State.dummy then if b then f else SFormula.not_ f
-      else
-        if b == b' then begin
-        (* a appears positively, either no negation or double negation *)
-          if not (Hashtbl.mem memo_state (q,b)) then Queue.add (q,true) todo;
-          SFormula.atom_ (Atom.make (l, true, q))
-        end else begin
+    match Formula.expr f with
+      Boolean.True | Boolean.False -> if b then f else Formula.not_ f
+    | Boolean.Or(f1, f2) -> (if b then Formula.or_ else Formula.and_)(flip b f1) (flip b f2)
+    | Boolean.And(f1, f2) -> (if b then Formula.and_ else Formula.or_)(flip b f1) (flip b f2)
+    | Boolean.Atom(a, b') -> begin
+      match a.Atom.node with
+      | Move (m,  q) ->
+          if b == b' then begin
+          (* a appears positively, either no negation or double negation *)
+            if not (Hashtbl.mem memo_state (q,b)) then Queue.add (q,true) todo;
+            Formula.mk_atom (Move(m, q))
+          end else begin
         (* need to reverse the atom
            either we have a positive state deep below a negation
            or we have a negative state in a positive formula
            b' = sign of the state
            b = sign of the enclosing formula
         *)
-        let not_q =
-          try
+            let not_q =
+              try
             (* does the inverted state of q exist ? *)
-            Hashtbl.find memo_state (q, false)
-          with
-            Not_found ->
+                Hashtbl.find memo_state (q, false)
+              with
+                Not_found ->
               (* create a new state and add it to the todo queue *)
-              let nq = State.make () in
-              auto.states <- StateSet.add nq auto.states;
-              Hashtbl.add memo_state (q, false) nq;
-              Queue.add (q, false) todo; nq
-        in
-        SFormula.atom_ (Atom.make (l, true, not_q))
-      end
+                  let nq = State.make () in
+                  auto.states <- StateSet.add nq auto.states;
+                  Hashtbl.add memo_state (q, false) nq;
+                  Queue.add (q, false) todo; nq
+            in
+            Formula.mk_atom (Move (m,not_q))
+          end
+      | _ -> if b then f else Formula.not_ f
     end
   in
   (* states that are not reachable from a selection stat are not interesting *)
@@ -553,5 +540,3 @@ let normalize_negations auto =
     Hashtbl.replace auto.transitions q' trans';
   done;
   cleanup_states auto
-
-