Put the move type of automata in a Move module and add auxiliary function to create...
[tatoo.git] / src / ata.ml
index add2775..3263e46 100644 (file)
@@ -22,6 +22,57 @@ type move = [ `First_child
             | `Previous_sibling
             | `Stay ]
 
+module Move =
+  struct
+    type t = move
+    type 'a table = 'a array
+    let idx = function
+      | `First_child -> 0
+      | `Next_sibling -> 1
+      | `Parent -> 2
+      | `Previous_sibling -> 3
+      | `Stay -> 4
+    let ridx = function
+      | 0 -> `First_child
+      | 1 -> `Next_sibling
+      | 2 -> `Parent
+      | 3 -> `Previous_sibling
+      | 4 -> `Stay
+      | _ -> assert false
+
+    let create_table a = Array.make 5 a
+    let get m k = m.(idx k)
+    let set m k v = m.(idx k) <- v
+    let iter f m = Array.iteri (fun i v -> f (ridx i) v) m
+    let fold f m acc =
+      let acc = ref acc in
+      iter (fun i v -> acc := f i v !acc) m;
+      !acc
+    let for_all p m =
+      try
+        iter (fun i v -> if not (p i v) then raise Exit) m;
+        true
+      with
+        Exit -> false
+    let exists p m =
+      try
+        iter (fun i v -> if p i v then raise Exit) m;
+        false
+      with
+        Exit -> true
+    let print ppf m =
+      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
+
+    let print_table pr_e ppf m =
+      iter (fun i v -> fprintf ppf "%a: %a" print i pr_e v;
+        if (idx i) < 4 then fprintf ppf ", ") m
+  end
+
 type predicate = Move of move * State.t
                  | Is_first_child
                  | Is_next_sibling
@@ -43,15 +94,8 @@ struct
 
   let print ppf a =
     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
+    | Move (m, q) ->
+      fprintf ppf "%a%a" Move.print m 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
@@ -107,12 +151,19 @@ struct
 
   let stay q = mk_move `Stay q
 
-  let get_states phi =
-    fold (fun phi acc ->
+  let get_states_by_move phi =
+    let table = Move.create_table StateSet.empty in
+    iter (fun phi ->
       match expr phi with
-      | Boolean.Atom ({ Atom.node = Move(_,q) ; _ }, _) ->  StateSet.add q acc
-      | _ -> acc
-    ) phi StateSet.empty
+      | Boolean.Atom ({ Atom.node = Move(v,q) ; _ }, _) ->
+        let s = Move.get table v in
+        Move.set table v (StateSet.add q s)
+      | _ -> ()
+    ) phi;
+    table
+  let get_states phi =
+    let table = get_states_by_move phi in
+    Move.fold (fun _ s acc -> StateSet.union s acc) table StateSet.empty
 
 end
 
@@ -175,11 +226,13 @@ let print fmt a =
   fprintf fmt
     "Internal UID: %i@\n\
      States: %a@\n\
+     Number of states: %i@\n\
      Starting states: %a@\n\
      Selection states: %a@\n\
      Alternating transitions:@\n"
     (a.id :> int)
     StateSet.print a.states
+    (StateSet.cardinal a.states)
     StateSet.print a.starting_states
     StateSet.print a.selecting_states;
   let trs =
@@ -227,7 +280,14 @@ let get_trans a tag states =
   ) states TransList.nil
 
 
-
+let get_form a tag q =
+  try
+    let trs = Hashtbl.find a.transitions q in
+    List.fold_left (fun aphi (labs, phi) ->
+      if QNameSet.mem tag labs then Formula.or_ aphi phi else aphi
+    ) Formula.false_ trs
+  with
+    Not_found -> Formula.false_
 
 (*
   [complete transitions a] ensures that for each state q
@@ -485,3 +545,61 @@ let merge a1 a2 =
       in
       a1.transitions
   }
+
+
+let link a1 a2 q link_phi =
+  { a1 with
+    states = StateSet.union a1.states a2.states;
+    selecting_states = StateSet.singleton q;
+    starting_states = StateSet.union a1.starting_states a2.starting_states;
+    transitions =
+      let () =
+        Hashtbl.iter (fun k v -> Hashtbl.add a1.transitions k v) a2.transitions
+      in
+      Hashtbl.add a1.transitions q [(QNameSet.any, link_phi)];
+      a1.transitions
+  }
+
+let union a1 a2 =
+  let a1 = copy a1 in
+  let a2 = copy a2 in
+  let q = State.make () in
+  let link_phi =
+    StateSet.fold
+      (fun q phi -> Formula.(or_ (stay q) phi))
+      (StateSet.union a1.selecting_states a2.selecting_states)
+      Formula.false_
+  in
+  link a1 a2 q link_phi
+
+let inter a1 a2 =
+  let a1 = copy a1 in
+  let a2 = copy a2 in
+  let q = State.make () in
+  let link_phi =
+    StateSet.fold
+      (fun q phi -> Formula.(and_ (stay q) phi))
+      (StateSet.union a1.selecting_states a2.selecting_states)
+      Formula.true_
+  in
+  link a1 a2 q link_phi
+
+let neg a =
+  let a = copy a in
+  let q = State.make () in
+  let link_phi = 
+    StateSet.fold
+      (fun q phi -> Formula.(and_ (not_(stay q)) phi))
+      a.selecting_states
+      Formula.true_
+  in
+  let () = Hashtbl.add a.transitions q [(QNameSet.any, link_phi)] in
+  let a =
+    { a with
+      selecting_states = StateSet.singleton q;
+    }
+  in
+  normalize_negations a; a
+
+let diff a1 a2 = inter a1 (neg a2)
+