(* Todo refactor and remove this alias *)
INCLUDE "debug.ml"
-module Tree = Tree.Binary
+let gen_id =
+ let id = ref (-1) in
+ fun () -> incr id;!id
+
+ module TS =
+ struct
+ type t = Nil | Cons of Tree.t * t | Concat of t*t
+ let empty = Nil
+
+ let cons e t = Cons(e,t)
+ let concat t1 t2 = Concat (t1,t2)
+ let append e t = Concat(t,Cons(e,Nil))
+
+ let fold f l acc =
+ let rec loop acc = function
+ | Nil -> acc
+ | Cons(e,t) -> loop (f e acc) t
+ | Concat(t1,t2) -> loop (loop acc t1) t2
+ in
+ loop acc l
+
+ let length l = fold (fun _ x -> x+1) l 0
+
+
+ let iter f l =
+ let rec loop = function
+ | Nil -> ()
+ | Cons(e,t) -> let _ = f e in loop t
+ | Concat(t1,t2) -> let _ = loop t1 in loop t2
+ in loop l
+
+ end
+
+
+
+let h_union = Hashtbl.create 4097
+
+let pt_cup s1 s2 =
+ let h = (Ptset.hash s1)*(Ptset.hash s2) - ((Ptset.hash s2)+(Ptset.hash s1)) in
+ try
+ Hashtbl.find h_union h
+ with
+ | Not_found -> let s = Ptset.union s1 s2
+ in
+ Hashtbl.add h_union h s;s
+
-let gen_id() = Oo.id (object end)
module State = struct
type t = int
type state = State.t
-type predicate = Ptset.t*Ptset.t -> Tree.t -> [ `True | `False | `Maybe ]
+
type formula_expr =
| False | True
- | Or of formula * formula
- | And of formula * formula
- | Atom of ([ `Left | `Right ]*bool*state*predicate option)
+ | Or of formula * formula
+ | And of formula * formula
+ | Atom of ([ `Left | `Right | `LLeft | `RRight ]*bool*state)
and formula = { fid: int;
- pos : formula_expr;
- neg : formula;
- st : Ptset.t*Ptset.t;
+ fkey : int;
+ pos : formula_expr;
+ neg : formula;
+ st : (Ptset.t*Ptset.t*Ptset.t)*(Ptset.t*Ptset.t*Ptset.t);
+ size: int;
}
+external hash_const_variant : [> ] -> int = "%identity"
+external int_bool : bool -> int = "%identity"
+
+let hash_node_form t = match t with
+ | False -> 0
+ | True -> 1
+ | And(f1,f2) -> (2+17*f1.fkey + 37*f2.fkey) (*land max_int *)
+ | Or(f1,f2) -> (3+101*f1.fkey + 253*f2.fkey) (*land max_int *)
+ | Atom(v,b,s) -> ((hash_const_variant v) + (3846*(int_bool b) +257) + (s lsl 13 - s)) (*land max_int *)
+
module FormNode =
struct
type t = formula
- let hash = function
- | False -> 0
- | True -> 1
- | And(f1,f2) -> 2+17*f1.fid + 37*f2.fid
- | Or(f1,f2) -> 3+101*f1.fid + 253*f2.fid
- | Atom(d,b,s,_) -> 5+(if d=`Left then 11 else 19)*(if b then 23 else 31)*s
-
- let hash t = (hash t.pos) land max_int
-
+
+ let hash t = t.fkey
let equal f1 f2 =
+ if f1.fid == f2.fid || f1.fkey == f2.fkey || f1.pos == f2.pos then true
+ else
match f1.pos,f2.pos with
| False,False | True,True -> true
- | Atom(d1,b1,s1,_), Atom(d2,b2,s2,_) when (d1 = d2) && (b1=b2) &&(s1=s2) -> true
+ | Atom(d1,b1,s1), Atom(d2,b2,s2) when (b1==b2) && (s1==s2) && (d1 = d2) -> true
| Or(g1,g2),Or(h1,h2)
| And(g1,g2),And(h1,h2) -> g1.fid == h1.fid && g2.fid == h2.fid
| _ -> false
+
end
module WH = Weak.Make(FormNode)
let f_pool = WH.create 107
+let empty_triple = Ptset.empty,Ptset.empty,Ptset.empty
+let empty_hex = empty_triple,empty_triple
+
let true_,false_ =
- let rec t = { fid = 1; pos = True; neg = f ; st = Ptset.empty,Ptset.empty}
- and f = { fid = 0; pos = False; neg = t; st = Ptset.empty,Ptset.empty }
+ let rec t = { fid = 1; pos = True; fkey=1; neg = f ; st = empty_hex; size =1; }
+ and f = { fid = 0; pos = False; fkey=0; neg = t; st = empty_hex; size = 1; }
in
WH.add f_pool f;
WH.add f_pool t;
let is_false f = f.fid == 0
-let cons pos neg s1 s2 =
+let cons pos neg s1 s2 size1 size2 =
let rec pnode =
{ fid = gen_id ();
+ fkey = hash_node_form pos;
pos = pos;
neg = nnode;
- st = s1; }
+ st = s1;
+ size = size1;}
and nnode = {
fid = gen_id ();
pos = neg;
+ fkey = hash_node_form neg;
neg = pnode;
st = s2;
+ size = size2;
}
in
(WH.merge f_pool pnode),(WH.merge f_pool nnode)
-let atom_ ?(pred=None) d p s =
+let atom_ d p s =
let si = Ptset.singleton s in
let ss = match d with
- | `Left -> si,Ptset.empty
- | `Right -> Ptset.empty,si
- in fst (cons (Atom(d,p,s,pred)) (Atom(d,not p,s,pred)) ss ss )
+ | `Left -> (si,Ptset.empty,si),empty_triple
+ | `Right -> empty_triple,(si,Ptset.empty,si)
+ | `LLeft -> (Ptset.empty,si,si),empty_triple
+ | `RRight -> empty_triple,(Ptset.empty,si,si)
+ in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1)
+
+let union_hex ((l1,ll1,lll1),(r1,rr1,rrr1)) ((l2,ll2,lll2),(r2,rr2,rrr2)) =
+ (pt_cup l1 l2 ,pt_cup ll1 ll2,pt_cup lll1 lll2),
+ (pt_cup r1 r2 ,pt_cup rr1 rr2,pt_cup rrr1 rrr2)
let merge_states f1 f2 =
let sp =
- Ptset.union (fst f1.st) (fst f2.st),
- Ptset.union (snd f1.st) (snd f2.st)
+ union_hex f1.st f2.st
and sn =
- Ptset.union (fst f1.neg.st) (fst f2.neg.st),
- Ptset.union (snd f1.neg.st) (snd f2.neg.st)
+ union_hex f1.neg.st f2.neg.st
in
sp,sn
+
+let full_or_ f1 f2 =
+ let f1,f2 = if f1.fid < f2.fid then f2,f1 else f1,f2 in
+ let sp,sn = merge_states f1 f2 in
+ let psize = f1.size + f2.size in
+ let nsize = f1.neg.size + f2.neg.size in
+ fst (cons (Or(f1,f2)) (And(f1.neg,f2.neg)) sp sn psize nsize )
let or_ f1 f2 =
+ let f1,f2 = if f1.fid < f2.fid then f2,f1 else f1,f2 in
if is_true f1 || is_true f2 then true_
else if is_false f1 && is_false f2 then false_
else if is_false f1 then f2
else if is_false f2 then f1
else
+ let psize = f1.size + f2.size in
+ let nsize = f1.neg.size + f2.neg.size in
let sp,sn = merge_states f1 f2 in
- fst (cons (Or(f1,f2)) (And(f1.neg,f2.neg)) sp sn)
+ fst (cons (Or(f1,f2)) (And(f1.neg,f2.neg)) sp sn psize nsize)
let and_ f1 f2 =
+ let f1,f2 = if f1.fid < f2.fid then f2,f1 else f1,f2 in
if is_true f1 && is_true f2 then true_
else if is_false f1 || is_false f2 then false_
else if is_true f1 then f2
else if is_true f2 then f1
else
+ let psize = f1.size + f2.size in
+ let nsize = f1.neg.size + f2.neg.size in
let sp,sn = merge_states f1 f2 in
- fst (cons (And(f1,f2)) (Or(f1.neg,f2.neg)) sp sn)
+ fst (cons (And(f1,f2)) (Or(f1.neg,f2.neg)) sp sn psize nsize)
let not_ f = f.neg
-type property = [ `None | `Existential ]
-let get_prop h s =
+let k_hash (s,t) = ((Ptset.hash s)) lsl 31 lxor (Tag.hash t)
+
+module HTagSetKey =
+struct
+ type t = Ptset.t*Tag.t
+ let equal (s1,s2) (t1,t2) = (s2 == t2) && Ptset.equal s1 t1
+ let hash = k_hash
+end
+
+module HTagSet =
+struct
+ type key = Ptset.t*Tag.t
+ let equal (s1,s2) (t1,t2) = (s2 == t2) && Ptset.equal s1 t1
+ let hash (s,t) = ((Ptset.hash s)) lsl 31 lxor (Tag.hash t)
+
+type 'a t =
+ { mutable size: int; (* number of elements *)
+ mutable data: (key,'a) bucketlist array } (* the buckets *)
+
+and ('a, 'b) bucketlist =
+ Empty
+ | Cons of 'a * 'b * ('a, 'b) bucketlist
+
+let create initial_size =
+ let s = min (max 1 initial_size) Sys.max_array_length in
+ { size = 0; data = Array.make s Empty }
+
+let clear h =
+ for i = 0 to Array.length h.data - 1 do
+ h.data.(i) <- Empty
+ done;
+ h.size <- 0
+
+let copy h =
+ { size = h.size;
+ data = Array.copy h.data }
+
+let length h = h.size
+
+let resize tbl =
+ let odata = tbl.data in
+ let osize = Array.length odata in
+ let nsize = min (2 * osize + 1) Sys.max_array_length in
+ if nsize <> osize then begin
+ let ndata = Array.create nsize Empty in
+ let rec insert_bucket = function
+ Empty -> ()
+ | Cons(key, data, rest) ->
+ insert_bucket rest; (* preserve original order of elements *)
+ let nidx = (hash key) mod nsize in
+ ndata.(nidx) <- Cons(key, data, ndata.(nidx)) in
+ for i = 0 to osize - 1 do
+ insert_bucket odata.(i)
+ done;
+ tbl.data <- ndata;
+ end
+
+let add h key info =
+ let i = (hash key) mod (Array.length h.data) in
+ let bucket = Cons(key, info, h.data.(i)) in
+ h.data.(i) <- bucket;
+ h.size <- succ h.size;
+ if h.size > Array.length h.data lsl 1 then resize h
+
+let remove h key =
+ let rec remove_bucket = function
+ Empty ->
+ Empty
+ | Cons(k, i, next) ->
+ if equal k key
+ then begin h.size <- pred h.size; next end
+ else Cons(k, i, remove_bucket next) in
+ let i = (hash key) mod (Array.length h.data) in
+ h.data.(i) <- remove_bucket h.data.(i)
+
+let rec find_rec key = function
+ Empty ->
+ raise Not_found
+ | Cons(k, d, rest) ->
+ if equal key k then d else find_rec key rest
+
+let find h key =
+ match h.data.((hash key) mod (Array.length h.data)) with
+ Empty -> raise Not_found
+ | Cons(k1, d1, rest1) ->
+ if equal key k1 then d1 else
+ match rest1 with
+ Empty -> raise Not_found
+ | Cons(k2, d2, rest2) ->
+ if equal key k2 then d2 else
+ match rest2 with
+ Empty -> raise Not_found
+ | Cons(k3, d3, rest3) ->
+ if equal key k3 then d3 else find_rec key rest3
+
+let find_all h key =
+ let rec find_in_bucket = function
+ Empty ->
+ []
+ | Cons(k, d, rest) ->
+ if equal k key
+ then d :: find_in_bucket rest
+ else find_in_bucket rest in
+ find_in_bucket h.data.((hash key) mod (Array.length h.data))
+
+let replace h key info =
+ let rec replace_bucket = function
+ Empty ->
+ raise Not_found
+ | Cons(k, i, next) ->
+ if equal k key
+ then Cons(k, info, next)
+ else Cons(k, i, replace_bucket next) in
+ let i = (hash key) mod (Array.length h.data) in
+ let l = h.data.(i) in
try
- Hashtbl.find h s
- with
- Not_found -> `None
-
+ h.data.(i) <- replace_bucket l
+ with Not_found ->
+ h.data.(i) <- Cons(key, info, l);
+ h.size <- succ h.size;
+ if h.size > Array.length h.data lsl 1 then resize h
+
+let mem h key =
+ let rec mem_in_bucket = function
+ | Empty ->
+ false
+ | Cons(k, d, rest) ->
+ equal k key || mem_in_bucket rest in
+ mem_in_bucket h.data.((hash key) mod (Array.length h.data))
+
+let iter f h =
+ let rec do_bucket = function
+ Empty ->
+ ()
+ | Cons(k, d, rest) ->
+ f k d; do_bucket rest in
+ let d = h.data in
+ for i = 0 to Array.length d - 1 do
+ do_bucket d.(i)
+ done
+
+let fold f h init =
+ let rec do_bucket b accu =
+ match b with
+ Empty ->
+ accu
+ | Cons(k, d, rest) ->
+ do_bucket rest (f k d accu) in
+ let d = h.data in
+ let accu = ref init in
+ for i = 0 to Array.length d - 1 do
+ accu := do_bucket d.(i) !accu
+ done;
+ !accu
+
+
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+type dispatch = { first : Tree.t -> Tree.t;
+ flabel : string;
+ next : Tree.t -> Tree.t -> Tree.t;
+ nlabel : string;
+ }
type t = {
id : int;
- states : Ptset.t;
+ mutable states : Ptset.t;
init : Ptset.t;
- final : Ptset.t;
+ mutable final : Ptset.t;
universal : Ptset.t;
(* Transitions of the Alternating automaton *)
- (* (tags,q) -> (marking,formula) *)
- phi : ((TagSet.t*state),(bool*formula)) Hashtbl.t;
- delta : (TagSet.t,(Ptset.t*bool*Ptset.t*Ptset.t)) Hashtbl.t;
- properties : (state,property) Hashtbl.t;
- }
+ phi : (state,(TagSet.t*(bool*formula*bool)) list) Hashtbl.t;
+ sigma : (dispatch*bool*formula) HTagSet.t;
+}
module Pair (X : Set.OrderedType) (Y : Set.OrderedType) =
struct
module PL = Set.Make (Pair (Ptset) (Ptset))
- let pr_st ppf l = Format.fprintf ppf "{";
+ let pr_st ppf l = Format.fprintf ppf "{";
begin
match l with
| [] -> ()
Format.fprintf ppf " }"
let rec pr_frm ppf f = match f.pos with
| True -> Format.fprintf ppf "⊤"
- | False -> Format.fprintf ppf "â\8a¤"
+ | False -> Format.fprintf ppf "â\8a¥"
| And(f1,f2) ->
Format.fprintf ppf "(";
(pr_frm ppf f1);
(pr_frm ppf f1);
Format.fprintf ppf " ∨ ";
(pr_frm ppf f2);
- | Atom(dir,b,s,p) -> Format.fprintf ppf "%s%s[%i]%s"
+ | Atom(dir,b,s) -> Format.fprintf ppf "%s%s[%i]"
(if b then "" else "¬")
- (if dir = `Left then "↓₁" else "↓₂")s
- (match p with None -> "" | _ -> " <hint>")
+ (match dir with
+ | `Left -> "↓₁"
+ | `Right -> "↓₂"
+ | `LLeft -> "⇓₁"
+ | `RRight -> "⇓₂") s
let dnf_hash = Hashtbl.create 17
let rec dnf_aux f = match f.pos with
| False -> PL.empty
| True -> PL.singleton (Ptset.empty,Ptset.empty)
- | Atom(`Left,_,s,_) -> PL.singleton (Ptset.singleton s,Ptset.empty)
- | Atom(`Right,_,s,_) -> PL.singleton (Ptset.empty,Ptset.singleton s)
+ | Atom((`Left|`LLeft),_,s) -> PL.singleton (Ptset.singleton s,Ptset.empty)
+ | Atom((`Right|`RRight),_,s) -> PL.singleton (Ptset.empty,Ptset.singleton s)
| Or(f1,f2) -> PL.union (dnf f1) (dnf f2)
| And(f1,f2) ->
- let pl1 = dnf f1
- and pl2 = dnf f2
- in
- PL.fold (fun (s1,s2) acc ->
- PL.fold ( fun (s1', s2') acc' ->
- (PL.add
- ((Ptset.union s1 s1'),
- (Ptset.union s2 s2')) acc') )
- pl2 acc )
- pl1 PL.empty
-
-
- and dnf f =
- try
+ let pl1 = dnf f1
+ and pl2 = dnf f2
+ in
+ PL.fold (fun (s1,s2) acc ->
+ PL.fold ( fun (s1', s2') acc' ->
+ (PL.add
+ ((Ptset.union s1 s1'),
+ (Ptset.union s2 s2')) acc') )
+ pl2 acc )
+ pl1 PL.empty
+
+
+ and dnf f =
+ try
Hashtbl.find dnf_hash f.fid
with
- Not_found ->
- let d = dnf_aux f in
- Hashtbl.add dnf_hash f.fid d;d
-
-
+ Not_found ->
+ let d = dnf_aux f in
+ Hashtbl.add dnf_hash f.fid d;d
+
+
+ let can_top_down f =
+ let nf = dnf f in
+ if (PL.cardinal nf > 3)then None
+ else match PL.elements nf with
+ | [(s1,s2); (t1,t2); (u1,u2)] when
+ Ptset.is_empty s1 && Ptset.is_empty s2 && Ptset.is_empty t1 && Ptset.is_empty u2
+ -> Some(true,t2,u1)
+ | [(t1,t2); (u1,u2)] when Ptset.is_empty t1 && Ptset.is_empty u2
+ -> Some(false,t2,u1)
+ | _ -> None
+
+
let equal_form f1 f2 =
(f1.fid == f2.fid) || (FormNode.equal f1 f2) || (PL.equal (dnf f1) (dnf f2))
-
- let alt_trans_to_nfa ?(accu=[]) ts s mark f =
- (* todo memoize *)
- let f' = dnf f in
- PL.fold (fun (s1,s2) acc -> (ts,s,mark,s1,s2)::acc) f' accu
-
- let possible_trans ?(accu=[]) a q tag =
- (* todo change the data structure to avoid creating (,) *)
- let ata_trans =
- Hashtbl.fold (fun (ts,s) (m,f) acc ->
- if (q==s) && (TagSet.mem tag ts)
- then (ts,s,m,f)::acc
- else acc) a.phi []
- in
- if ata_trans != []
- then begin
- List.iter (fun (ts,s,m,f) ->
- (* The following builds too many transitions in the nfa
- let ts' = TagSet.remove tag ts
- in
- Hashtbl.remove a.phi (ts,s);
- if not (TagSet.is_empty ts')
- then Hashtbl.add a.phi (ts',s) (m,f)
- *)
- Hashtbl.remove a.phi (ts,s)
- ) ata_trans;
- (* let tstag = TagSet.tag tag in *)
- let nfa_trs = List.fold_left (fun acc (ts,s,m,f) ->
- alt_trans_to_nfa ~accu:acc ts s m f) [] ata_trans
- in
- List.iter (fun (ts,s,m,s1,s2) ->
- Hashtbl.add a.delta ts ((Ptset.singleton s),m,s1,s2)) nfa_trs
- end;
- Hashtbl.fold (fun ts (s,m,s1,s2) acc ->
- if (Ptset.mem q s) && (TagSet.mem tag ts)
- then (m,s1,s2)::acc else acc) a.delta accu
-
let dump ppf a =
Format.fprintf ppf "Automaton (%i) :\n" a.id;
Format.fprintf ppf "States : "; pr_st ppf (Ptset.elements a.states);
Format.fprintf ppf "\nFinal states : "; pr_st ppf (Ptset.elements a.final);
Format.fprintf ppf "\nUniversal states : "; pr_st ppf (Ptset.elements a.universal);
Format.fprintf ppf "\nAlternating transitions :\n------------------------------\n";
- let l = Hashtbl.fold (fun k t acc -> (k,t)::acc) a.phi [] in
+ let l = Hashtbl.fold (fun k t acc ->
+ (List.map (fun (t,(m,f,p)) -> (t,k),(m,f,p)) t)@ acc) a.phi [] in
let l = List.sort (fun ((tsx,x),_) ((tsy,y),_) -> if x-y == 0 then TagSet.compare tsx tsy else x-y) l in
- List.iter (fun ((ts,q),(b,f)) ->
+ List.iter (fun ((ts,q),(b,f,_)) ->
let s =
- try
- Tag.to_string (TagSet.choose ts)
- with
- | _ -> "*"
+ if TagSet.is_finite ts
+ then "{" ^ (TagSet.fold (fun t a -> a ^ " '" ^ (Tag.to_string t)^"'") ts "") ^" }"
+ else let cts = TagSet.neg ts in
+ if TagSet.is_empty cts then "*" else
+ (TagSet.fold (fun t a -> a ^ " " ^ (Tag.to_string t)) cts "*\\{"
+ )^ "}"
in
Format.fprintf ppf "(%s,%i) %s " s q (if b then "=>" else "->");
pr_frm ppf f;
Format.fprintf ppf "\n")l;
Format.fprintf ppf "NFA transitions :\n------------------------------\n";
- Hashtbl.iter (fun (ts) (q,b,s1,s2) ->
-
- let s =
- try
- Tag.to_string (TagSet.choose ts)
- with
- | _ -> "*"
- in
- pr_st ppf (Ptset.elements q);
- Format.fprintf ppf ",%s %s " s (if b then "=>" else "->");
- Format.fprintf ppf "(";
- pr_st ppf (Ptset.elements s1);
- Format.fprintf ppf ",";
- pr_st ppf (Ptset.elements s2);
- Format.fprintf ppf ")\n" ) a.delta;
- Format.fprintf ppf "=======================================\n"
+ HTagSet.iter (fun (qs,t) (disp,b,f) ->
+ pr_st ppf (Ptset.elements qs);
+ Format.fprintf ppf ",%s %s " (Tag.to_string t) (if b then "=>" else "->");
+ pr_frm ppf f;
+ Format.fprintf ppf "(fid=%i) left=" f.fid;
+ let (l,ll,_),(r,rr,_) = f.st in
+ pr_st ppf (Ptset.elements l);
+ Format.fprintf ppf ", ";
+ pr_st ppf (Ptset.elements ll);
+ Format.fprintf ppf ", right=";
+ pr_st ppf (Ptset.elements r);
+ Format.fprintf ppf ", ";
+ pr_st ppf (Ptset.elements rr);
+ Format.fprintf ppf ", first=%s, next=%s\n" disp.flabel disp.nlabel;
+ ) a.sigma;
+ Format.fprintf ppf "=======================================\n%!"
module Transitions = struct
- type t = state*TagSet.t*bool*formula
+ type t = state*TagSet.t*bool*formula*bool
let ( ?< ) x = x
- let ( >< ) state label = state,label
- let ( >=> ) (state,(label,mark)) form = (state,label,mark,form)
+ let ( >< ) state (l,b) = state,(l,b,false)
+ let ( ><@ ) state (l,b) = state,(l,b,true)
+ let ( >=> ) (state,(label,mark,pred)) form = (state,label,mark,form,pred)
let ( +| ) f1 f2 = or_ f1 f2
let ( *& ) f1 f2 = and_ f1 f2
let ( ** ) d s = atom_ d true s
end
type transition = Transitions.t
- let equal_trans (q1,t1,m1,f1) (q2,t2,m2,f2) =
+ let equal_trans (q1,t1,m1,f1,_) (q2,t2,m2,f2,_) =
(q1 == q2) && (TagSet.equal t1 t2) && (m1 == m2) && (equal_form f1 f2)
+
+
+ module HFEval = Hashtbl.Make(
+ struct
+ type t = int*Ptset.t*Ptset.t
+ let equal (a,b,c) (d,e,f) =
+ a==d && (Ptset.equal b e) && (Ptset.equal c f)
+ let hash (a,b,c) =
+ a+17*(Ptset.hash b) + 31*(Ptset.hash c)
+ end)
+
+ let hfeval = HFEval.create 4097
- module TS : Set.S with type elt = Tree.t = Set.Make(Tree)
- let res = ref TS.empty
+ let eval_form_bool f s1 s2 =
+ let rec eval f = match f.pos with
+ (* test some inlining *)
+ | True -> true,true,true
+ | False -> false,false,false
+ | Atom((`Left|`LLeft),b,q) -> if b == (Ptset.mem q s1) then (true,true,false) else false,false,false
+ | Atom(_,b,q) -> if b == (Ptset.mem q s2) then (true,false,true) else false,false,false
+ | _ ->
+ try
+ HFEval.find hfeval (f.fid,s1,s2)
+ with
+ | Not_found -> let r =
+ match f.pos with
+ | Or(f1,f2) ->
+ let b1,rl1,rr1 = eval f1
+ in
+ if b1 && rl1 && rr1 then (true,true,true)
+ else
+ let b2,rl2,rr2 = eval f2
+ in
+ let rl1,rr1 = if b1 then rl1,rr1 else false,false
+ and rl2,rr2 = if b2 then rl2,rr2 else false,false
+ in (b1 || b2, rl1||rl2,rr1||rr2)
+ | And(f1,f2) ->
+ let b1,rl1,rr1 = eval f1 in
+ if b1 && rl1 && rr1 then (true,true,true)
+ else if b1
+ then let b2,rl2,rr2 = eval f2 in
+ if b2 then (true,rl1||rl2,rr1||rr2)
+ else (false,false,false)
+ else (false,false,false)
+ | _ -> assert false
+ in
+ HFEval.add hfeval (f.fid,s1,s2) r;
+ r
+ in eval f
+
+
+ let fstate_pool = Hashtbl.create 11
+
+ let merge_pred a b = match a,b with
+ | Some(f1), Some(f2) -> Some(fun x -> f1 x || f2 x)
+ | None,None -> None
+ | None,Some(_) -> b
+ | Some(_),None -> a
+
+ let acc_pred p l1 l2 = match p with
+ | `Left _ -> p::l1,l2
+ | `Right _ -> l1,p::l2
+ | _ -> l1,l2
- module BottomUpNew = struct
+
+
+
+ let tags_of_state a q = Hashtbl.fold
+ (fun p l acc ->
+ if p == q then
+ List.fold_left
+ (fun acc (ts,(_,_,aux)) ->
+ if aux then acc else
+ TagSet.cup ts acc) acc l
+ else acc) a.phi TagSet.empty
-IFDEF DEBUG
-THEN
- type trace =
- | TNil of Ptset.t*Ptset.t
- | TNode of Ptset.t*Ptset.t*bool* (int*bool*formula) list
-
- let traces = Hashtbl.create 17
- let dump_trace t =
- let out = open_out "debug_trace.dot"
- in
- let outf = Format.formatter_of_out_channel out in
-
- let rec aux t num =
- if Tree.is_node t
- then
- match (try Hashtbl.find traces (Tree.id t) with Not_found -> TNil(Ptset.empty,Ptset.empty)) with
- | TNode(r,s,mark,trs) ->
- let numl = aux (Tree.left t) num in
- let numr = aux (Tree.right t) (numl+1) in
- let mynum = numr + 1 in
- Format.fprintf outf "n%i [ label=\"<%s>\\nr=" mynum (Tag.to_string (Tree.tag t));
- pr_st outf (Ptset.elements r);
- Format.fprintf outf "\\ns=";
- pr_st outf (Ptset.elements s);
- List.iter (fun (q,m,f) ->
- Format.fprintf outf "\\n%i %s" q (if m then "⇨" else "→");
- pr_frm outf f ) trs;
- Format.fprintf outf "\", %s shape=box ];\n"
- (if mark then "color=cyan1, style=filled," else "");
- let _ = Format.fprintf outf "n%i -> n%i;\n" mynum numl in
- let _ = Format.fprintf outf "n%i -> n%i;\n" mynum numr in
- mynum
- | TNil(r,s) -> Format.fprintf outf "n%i [ shape=box, label=\"Nil\\nr=" num;
- pr_st outf (Ptset.elements r);
- Format.fprintf outf "\\ns=";
- pr_st outf (Ptset.elements s);
- Format.fprintf outf "\"];\n";num
- else
- match Hashtbl.find traces (-10) with
- | TNil(r,s) ->
- Format.fprintf outf "n%i [ shape=box, label=\"Nil\\nr=" num;
- pr_st outf (Ptset.elements r);
- Format.fprintf outf "\\ns=";
- pr_st outf (Ptset.elements s);
- Format.fprintf outf "\"];\n";
- num
- | _ -> assert false
+
+ let tags a qs =
+ let ts = Ptset.fold (fun q acc -> TagSet.cup acc (tags_of_state a q)) qs TagSet.empty
in
- Format.fprintf outf "digraph G {\n";
- ignore(aux t 0);
- Format.fprintf outf "}\n%!";
- close_out out;
- ignore(Sys.command "dot -Tsvg debug_trace.dot > debug_trace.svg")
-END
-
-
-
- let hfeval = Hashtbl.create 17
- let miss = ref 0
- let call = ref 0
- let rec findlist s1 s2 = function
- | [] -> raise Not_found
- | ((ss1,ss2),r)::_ when
- (not (Ptset.is_empty s1)) && (Ptset.subset s1 ss1) &&
- (not (Ptset.is_empty s2)) && (Ptset.subset s2 ss2) -> r
- | _::r -> findlist s1 s2 r
-
- let eval_form f s1 s2 res1 res2 =
+ if TagSet.is_finite ts
+ then `Positive(TagSet.positive ts)
+ else `Negative(TagSet.negative ts)
- let rec eval_aux f = match f.pos with
- | Atom(`Left,b,q,_) -> if b == (Ptset.mem q s1) then (true,res1) else false,TS.empty
- | Atom(`Right,b,q,_) -> if b == (Ptset.mem q s2) then (true,res2) else false,TS.empty
- | True -> true,(TS.union res1 res2)
- | False -> false,TS.empty
- | Or(f1,f2) ->
- let b1,r1 = eval_aux f1
- and b2,r2 = eval_aux f2
+
+
+
+ let merge_trans t a tag q acc =
+ List.fold_left (fun (accf,accm,acchtrue) (ts,(m,f,pred)) ->
+ if TagSet.mem tag ts
+ then
+ let tmpf,hastrue =
+ if is_true f then
+ let newfinal =
+ try Hashtbl.find fstate_pool f.fid with
+ | Not_found -> let s = mk_state() in
+ a.states <- Ptset.add s a.states;
+ a.final <- Ptset.add s a.final;
+ Hashtbl.add fstate_pool f.fid s;s
+ in
+ (atom_ `Left true newfinal),true
+ else f,false in
+ (or_ tmpf accf,accm||m,acchtrue||hastrue)
+ else (accf,accm,acchtrue)
+ ) acc (try Hashtbl.find a.phi q with Not_found -> [])
+
+ let inter_text a b =
+ match b with
+ | `Positive s -> let r = Ptset.inter a s in (r,Ptset.mem Tag.pcdata r, true)
+ | `Negative s -> (Ptset.empty, not (Ptset.mem Tag.pcdata s), false)
+
+ let mk_nil_ctx x _ = Tree.mk_nil x
+ let next_sibling_ctx x _ = Tree.next_sibling x
+ let r_ignore _ x = x
+
+
+
+ let get_trans t a tag r =
+ try
+ let dispatch,mark,f =
+ HTagSet.find a.sigma (r,tag)
+ in f.st,dispatch,f,mark,r
+ with
+ Not_found ->
+ let f,mark,_,accq =
+ Ptset.fold (fun q (accf,accm,acchtrue,accq) ->
+ let naccf,naccm,nacctrue =
+ merge_trans t a tag q (accf,accm,acchtrue )
+ in
+ if is_false naccf then (naccf,naccm,nacctrue,accq)
+ else (naccf,naccm,nacctrue,Ptset.add q accq)
+ )
+ r (false_,false,false,Ptset.empty)
+ in
+ let (ls,lls,_),(rs,rrs,_) = f.st in
+ let tb,ta =
+ Tree.tags t tag
+ in
+ let tl,htlt,lfin = inter_text tb (tags a ls)
+ and tll,htllt,llfin = inter_text tb (tags a lls)
+ and tr,htrt,rfin = inter_text ta (tags a rs)
+ and trr,htrrt,rrfin = inter_text ta (tags a rrs)
in
- let r1 = if b1 then r1 else TS.empty
- and r2 = if b2 then r2 else TS.empty
- in (b1 || b2, TS.union r1 r2)
-
- | And(f1,f2) ->
- let b1,r1 = eval_aux f1
- and b2,r2 = eval_aux f2
+ let first,flabel =
+ if (llfin && lfin) then (* no stars *)
+ (if htlt || htllt then (Tree.text_below, "#text_below")
+ else
+ let etl = Ptset.is_empty tl
+ and etll = Ptset.is_empty tll
+ in
+ if (etl && etll)
+ then (Tree.mk_nil, "#mk_nil")
+ else
+ if etl then
+ if Ptset.is_singleton tll
+ then (Tree.tagged_desc (Ptset.choose tll), "#tagged_desc")
+ else (Tree.select_desc_only tll, "#select_desc_only")
+ else if etll then (Tree.node_child,"#node_child")
+ else (Tree.select_below tl tll,"#select_below"))
+ else (* stars or node() *)
+ if htlt||htllt then (Tree.first_child,"#first_child")
+ else (Tree.node_child,"#node_child")
+ and next,nlabel =
+ if (rrfin && rfin) then (* no stars *)
+ ( if htrt || htrrt
+ then (Tree.text_next, "#text_next")
+ else
+ let etr = Ptset.is_empty tr
+ and etrr = Ptset.is_empty trr
+ in
+ if etr && etrr
+ then (mk_nil_ctx, "#mk_nil_ctx")
+ else
+ if etr then
+ if Ptset.is_singleton trr
+ then (Tree.tagged_foll_below (Ptset.choose trr),"#tagged_foll_below")
+ else (Tree.select_foll_only trr,"#select_foll_only")
+ else if etrr then (Tree.node_sibling_ctx,"#node_sibling_ctx")
+ else
+ (Tree.select_next tr trr,"#select_next") )
+
+ else if htrt || htrrt then (Tree.next_sibling_ctx,"#next_sibling_ctx")
+ else (Tree.node_sibling_ctx,"#node_sibling_ctx")
+ in
+ let dispatch = { first = first; flabel = flabel; next = next; nlabel = nlabel}
+ in
+ HTagSet.add a.sigma (accq,tag) (dispatch,mark,f);
+ f.st,dispatch,f,mark,accq
+
+ let rec accepting_among a t orig ctx =
+ let rest = Ptset.inter orig a.universal in
+ let r = Ptset.diff orig rest in
+ if Ptset.is_empty r then rest,0,TS.empty else
+ if Tree.is_nil t
+ then orig,0,TS.empty
+ else
+ let ((_,_,llls),(_,_,rrrs)),dispatch,formula,mark,r' =
+ get_trans t a (Tree.tag t) r
in
- if b1 && b2 then (true, TS.union r1 r2)
- else (false,TS.empty)
+ let s1,n1,res1 = accepting_among a (dispatch.first t) llls t in
+ let s2,n2,res2 = accepting_among a (dispatch.next t ctx) rrrs ctx in
+ let rb,rb1,rb2 = eval_form_bool formula s1 s2 in
+ if rb
+ then
+ let n1,res1 = if rb1 then n1,res1 else 0,TS.empty
+ and n2,res2 = if rb2 then n2,res2 else 0,TS.empty
+ in
+ if mark
+ then r',1+n1+n2,TS.Cons(t,(TS.Concat(res1,res2)))
+ else r',n1+n2,TS.Concat(res1,res2)
+ else Ptset.empty,0,TS.empty
- in incr call;eval_aux f
-
- (* If true, then the formule may evaluate to true in the future,
- if false it will always return false, i.e. necessary conditions are not
- satisfied
- *)
-
- let val3 = function true -> `True
- | false -> `False
-
- let or3 a b = match a,b with
- | `True,_ | _,`True -> `True
- | `False,`False -> `False
- | _ -> `Maybe
-
- let and3 a b = match a,b with
- | `True,`True -> `True
- | `False,_ | _,`False -> `False
- | _ -> `Maybe
- let not3 = function
- | `True -> `False
- | `False -> `True
- | `Maybe -> `Maybe
-
- let true3 = function true -> `Maybe
- | false -> `False
-
- let may_eval (s1,s2) f t =
- let rec aux f = match f.pos with
- | True -> `True
- | False -> `False
- | Or(f1,f2) -> or3 (aux f1) (aux f2)
- | And(f1,f2) -> and3 (aux f1) (aux f2)
- | Atom(dir,b,q,predo) ->
- and3 (true3 ((Ptset.mem q (match dir with
- | `Left -> s1
- | `Right -> s2)) == b))
- (match predo with
- | Some pred -> (pred (s1,s2) t)
- | None -> `True)
-
- in aux f
-
- let rec accepting_among a t r =
- let r = Ptset.diff r a.final in
- let rest = Ptset.inter a.final r in
- if Ptset.is_empty r then r,TS.empty else
- if (not (Tree.is_node t))
+ let rec accepting_among_count a t orig ctx =
+ let rest = Ptset.inter orig a.universal in
+ let r = Ptset.diff orig rest in
+ if Ptset.is_empty r then rest,0 else
+ if Tree.is_node t
then
- let _ = D(Hashtbl.add traces (-10) (TNil(r,Ptset.inter a.final r)))
- in
- Ptset.inter a.final r,TS.empty
- else
- let tag = Tree.tag t
- and t1 = Tree.first_child t
- and t2 = Tree.next_sibling t
+ let ((_,_,llls),(_,_,rrrs)),dispatch,formula,mark,r' =
+ get_trans t a (Tree.tag t) r
in
- let r1,r2,trs =
- Hashtbl.fold (fun (ts,q) ((m,f)as tr) ((ar1,ar2,lt)as acc) ->
- if (TagSet.mem tag ts) && Ptset.mem q r
- then begin
- (* Format.fprintf Format.err_formatter "Tree with tag %s qualifies for transition : (%s,%i)%s"
- (Tag.to_string tag)
- (try
- Tag.to_string (TagSet.choose ts)
- with
- | _ -> "*" )
- q
- (if m then "=>" else "->");
- pr_frm Format.err_formatter f;
- Format.fprintf Format.err_formatter "\n"; *)
- let ls,rs = f.st in
- Ptset.union ls ar1,Ptset.union rs ar2,(q,tr)::lt
- end
- else acc
- ) a.phi (Ptset.empty,Ptset.empty,[])
+ let s1,res1 = accepting_among_count a (dispatch.first t) llls t
+ and s2,res2 = accepting_among_count a (dispatch.next t ctx) rrrs ctx
in
- let rtrue,rfalse,rmay,trs,selnodes =
- List.fold_left (fun (at,af,am,atrs,selnodes) (q,(m,f)) ->
- let ppf = Format.err_formatter in
- match (*may_eval (r1,r2) f t *) `Maybe with
- | `True ->
- (* Format.fprintf ppf "Will skip (%i) %s " q (if m then "=>" else "->");
- pr_frm ppf f;
- Format.fprintf ppf ", always true \n"; *)
- (Ptset.add q at),af,am,atrs,TS.add t selnodes
- | `False ->
- (*Format.fprintf ppf "Will skip (%i) %s " q (if m then "=>" else "->");
- pr_frm ppf f;
- Format.fprintf ppf ", always false \n"; *)
- at,(Ptset.add q af),am,atrs,selnodes
-
- | `Maybe ->
-(* Format.fprintf ppf "Must take (%i) %s " q (if m then "=>" else "->");
- pr_frm ppf f;
- Format.fprintf ppf "\n"; *)
- at,af,(Ptset.add q am),(q,(m,f))::atrs,selnodes)
- (Ptset.empty,Ptset.empty,Ptset.empty,[],TS.empty) trs
- in
- let rr1,rr2,trs =
- List.fold_left (fun ((ar1,ar2,trs)as acc) ((q,(_,f)as tr)) ->
- if Ptset.mem q rmay
- then let ls,rs = f.st in
- Ptset.union ls ar1,Ptset.union rs ar2,tr::trs
- else acc) (Ptset.empty,Ptset.empty,[]) trs
- in
- let s1,res1 = accepting_among a t1 rr1
- and s2,res2 = accepting_among a t2 rr2
- in
- let res,set,mark,trs = List.fold_left (fun ((sel_nodes,res,amark,acctr) as acc) (q,(mark,f)) ->
- let b,resnodes = eval_form f s1 s2 res1 res2 in
- (* if b then begin
- pr_st Format.err_formatter (Ptset.elements s1);
- Format.fprintf Format.err_formatter ",";
- pr_st Format.err_formatter (Ptset.elements s2);
- Format.fprintf Format.err_formatter " satisfies ";
- pr_frm Format.err_formatter f;
- Format.fprintf Format.err_formatter " for input tree %s\n" (Tag.to_string tag);
- end; *)
- if b
- then
- (TS.union
- (if mark then TS.add t resnodes else resnodes)
- sel_nodes)
- ,Ptset.add q res,amark||mark,(q,mark,f)::acctr
- else acc
- ) (TS.empty,rtrue,false,[]) trs
- in
-
- let set = Ptset.union a.final set in
- let _ = D(Hashtbl.add traces (Tree.id t) (TNode(r,set,mark,trs))) in
- set,res
-
-
+ let rb,rb1,rb2 = eval_form_bool formula s1 s2 in
+ if rb
+ then
+ let res1 = if rb1 then res1 else 0
+ and res2 = if rb2 then res2 else 0
+ in r', if mark then 1+res1+res2 else res1+res2
+ else Ptset.empty,0
+ else orig,0
+
+
let run a t =
- let st,res = accepting_among a t a.init in
- let b = Ptset.is_empty (st) in
- let _ = D(dump_trace t) in
- if b then []
- else (TS.elements res)
+ let st,n,res = accepting_among a t a.init t in
+ if Ptset.is_empty (st) then TS.empty,0 else res,n
+
+
+ let run_count a t =
+ let st,res = accepting_among_count a t a.init t in
+ if Ptset.is_empty (st) then 0 else res
+
+
+ let run_time _ _ = failwith "blah"
+
+
+
+
+(*
end
+*)