INCLUDE "debug.ml"
module Tree = Tree.Binary
-let gen_id() = Oo.id (object end)
+let gen_id =
+ let id = ref (-1) in
+ fun () -> incr id;!id
+
+
module State = struct
type t = int
type state = State.t
-type predicate = Ptset.t*Ptset.t -> Tree.t -> [ `True | `False | `Maybe ]
+type predicate = [ `Left of (Tree.t -> bool) | `Right of (Tree.t -> bool) |
+ `True
+ ]
+let eval_pred t =
+ function `True -> true
+ | `Left f | `Right f -> f t
+
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 ]*bool*state)
and formula = { fid: int;
- pos : formula_expr;
- neg : formula;
- st : Ptset.t*Ptset.t;
+ pos : formula_expr;
+ neg : formula;
+ st : Ptset.t*Ptset.t;
+ size: int;
}
| 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
+ | 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 equal f1 f2 =
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 (d1 = d2) && (b1=b2) &&(s1=s2) -> true
| Or(g1,g2),Or(h1,h2)
| And(g1,g2),And(h1,h2) -> g1.fid == h1.fid && g2.fid == h2.fid
| _ -> false
let f_pool = WH.create 107
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; neg = f ; st = Ptset.empty,Ptset.empty; size =1; }
+ and f = { fid = 0; pos = False; neg = t; st = Ptset.empty,Ptset.empty; 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 ();
pos = pos;
neg = nnode;
- st = s1; }
+ st = s1;
+ size = size1;}
and nnode = {
fid = gen_id ();
pos = 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 )
+ in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1)
let merge_states f1 f2 =
let sp =
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 =
- try
- Hashtbl.find h s
- with
- Not_found -> `None
-
+
+module HTagSetKey =
+struct
+ type t = Ptset.t*Tag.t
+ let int_hash key = key lsl 31 lor (key lsl 8)
+ let equal (s1,s2) (t1,t2) = Tag.equal s2 t2 && Ptset.equal s1 t1
+ let hash (s,t) = int_hash (Ptset.hash s) lxor ( int_hash (Tag.hash t))
+end
+module HTagSet = Hashtbl.Make(HTagSetKey)
+
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*predicate)) list) Hashtbl.t;
+ delta : (state*Tag.t, (bool*formula*predicate)) Hashtbl.t;
+(* delta : (state,(bool*formula*predicate) TagMap.t) Hashtbl.t; *)
+ sigma : (bool*formula*(predicate list*predicate list)*bool) HTagSet.t;
}
module Pair (X : Set.OrderedType) (Y : Set.OrderedType) =
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>")
+ (if dir = `Left then "↓₁" else "↓₂") 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,_,s) -> PL.singleton (Ptset.singleton s,Ptset.empty)
+ | Atom(`Right,_,s) -> PL.singleton (Ptset.empty,Ptset.singleton s)
| Or(f1,f2) -> PL.union (dnf f1) (dnf f2)
| And(f1,f2) ->
let pl1 = dnf f1
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;
+ HTagSet.iter (fun (qs,t) (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,r = f.st in pr_st ppf (Ptset.elements l);
+ Format.fprintf ppf ", right=";
+ pr_st ppf (Ptset.elements r);
+ Format.fprintf ppf "\n";
+ ) a.sigma;
Format.fprintf ppf "=======================================\n"
module Transitions = struct
- type t = state*TagSet.t*bool*formula
+ type t = state*TagSet.t*bool*formula*predicate
let ( ?< ) x = x
- let ( >< ) state label = state,label
- let ( >=> ) (state,(label,mark)) form = (state,label,mark,form)
+ let ( >< ) state (l,b) = state,(l,b,`True)
+ let ( ><@ ) state (l,b,p) = state,(l,b,p)
+ 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 TS : Set.S with type elt = Tree.t = Set.Make(Tree)
- let res = ref TS.empty
+ module TS =
+ struct
+ type node = Nil | Cons of Tree.t * node | Concat of node*node
+ and t = { node : node; size : int }
+ let node n s = { node=n; size = s }
+
+ let empty = node Nil 0
+
+ let cons e t = node (Cons(e,t.node)) (t.size+1)
+ let concat t1 t2 = node (Concat (t1.node,t2.node)) (t1.size+t2.size)
+ let append e t = concat t (cons e empty)
+
+ let to_list_rev t =
+ let rec aux acc l rest =
+ match l with
+ | Nil -> begin
+ match rest with
+ | Nil -> acc
+ | Cons(e,t) -> aux (e::acc) t Nil
+ | Concat(t1,t2) -> aux acc t1 t2
+ end
+ | Cons(e,r) -> aux (e::acc) r rest
+ | Concat(t1,t2) -> aux acc t1 (Concat(t2,rest))
+ in
+ aux [] t.node Nil
+ let length = function { size = s } -> s
+
+ let iter f { node = n } =
+ let rec loop = function
+ | Nil -> ()
+ | Cons(e,n) -> let _ = f e in loop n
+ | Concat(n1,n2) -> let _ = loop n1 in loop n2
+ in loop n
+
+ end
module BottomUpNew = struct
- let hfeval = Hashtbl.create 17
- let miss = ref 0
+ 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
+
+
+ let eval_form_bool f s1 s2 =
+ let rec eval f = match f.pos with
+ | Atom(`Left,b,q) -> if b == (Ptset.mem q s1) then (true,true,false) else false,false,false
+ | Atom(`Right,b,q) -> if b == (Ptset.mem q s2) then (true,false,true) else false,false,false
+ (* test some inlining *)
+ | True -> true,true,true
+ | False -> 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
+
+
+ module HFEvalDir = Hashtbl.Make(
+ struct
+ type t = int*Ptset.t*[`Left | `Right ]
+ let equal (a,b,c) (d,e,f) =
+ a==d && (Ptset.equal b e) && (c = f)
+ let hash_dir = function `Left -> 7919
+ | `Right -> 3517
+
+ let hash (a,b,c) =
+ a+17*(Ptset.hash b) + 31*(hash_dir c)
+ end)
+
+ let hfeval_dir = HFEvalDir.create 4097
+
+
+ let eval_dir dir f s =
+ let rec eval f = match f.pos with
+ | Atom(d,b,q) when d = dir -> if b == (Ptset.mem q s) then true_ else false_
+ | Atom(_,b,q) -> f
+ (* test some inlining *)
+ | True -> true_
+ | False -> false_
+ | _ ->
+ try
+ HFEvalDir.find hfeval_dir (f.fid,s,dir)
+ with
+ | Not_found ->
+ let r =
+ match f.pos with
+ | Or(f1,f2) ->
+ let f1 = eval f1
+ in
+ if is_true f1 then true_
+ else if is_false f1 then eval f2
+ else or_ f1 f2
+ | And(f1,f2) ->
+ let f1 = eval f1 in
+ if is_false f1 then false_
+ else if is_true f1 then eval f2
+ else and_ f1 f2
+ | _ -> assert false
+ in
+ HFEvalDir.add hfeval_dir (f.fid,s,dir) 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
+
+
+ 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 (Hashtbl.find a.phi q)
+
+ 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 =
-
- 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
- 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
- in
- if b1 && b2 then (true, TS.union r1 r2)
- else (false,TS.empty)
-
- in incr call;eval_aux f
+ let get_trans t a tag r =
+ try
+ let mark,f,predl,has_true =
+ HTagSet.find a.sigma (r,tag)
+ in f.st,f,mark,has_true,r,predl
+ with
+ Not_found ->
+ let f,mark,has_true,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
+ HTagSet.add a.sigma (accq,tag) (mark,f,([],[]),has_true);
+ f.st,f,mark,has_true,accq,([],[])
+
+
+ let check_pred l t = true (*l = [] ||
+ List.exists (function p ->
+ match p with
+ `Left f | `Right f -> f t
+ | _ -> assert false) l
+ *)
- (* 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_among2 a t r acc =
+ let orig = r in
+ let rest = Ptset.inter r a.final in
+ let r = Ptset.diff r rest in
+ if Ptset.is_empty r then rest,acc else
+ if (not (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
+ orig,acc
else
- let tag = Tree.tag t
- and t1 = Tree.first_child t
- and t2 = Tree.next_sibling t
+ let tag = Tree.tag t in
+ let t1 = Tree.first_child t
+ and t2 = Tree.next_sibling t in
+ let (r1,r2),formula,mark,has_true,r,_ = get_trans t a tag r
+ in
+ let s1,res1 = accepting_among2 a t1 r1 acc
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,[])
- 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 formula = eval_dir `Left formula s1 in
+ if is_false formula then rest,acc
+ else
+ if is_true formula then (* tail call equivalent to a top down *)
+ accepting_among2 a t2 orig (if mark then TS.append t res1 else res1)
+ else
+ let s2,res2 = accepting_among2 a t2 r2 res1
+ in
+ let formula = eval_dir `Right formula s2
+ in
+ if is_false formula then rest,res1
+ else
+ orig,(if mark then TS.append t (res2)
+ else res2)
+
+
let run a t =
- let st,res = accepting_among a t a.init in
+ let st,res = accepting_among2 a t a.init TS.empty in
let b = Ptset.is_empty (st) in
- let _ = D(dump_trace t) in
- if b then []
- else (TS.elements res)
-
+ if b then TS.empty
+ else
+ res
end
| _ -> false
end
-module WH = Weak.Make(Node)
-
+module WH =Weak.Make(Node)
+(* struct
+ include Hashtbl.Make(Node)
+ let merge h v =
+ if mem h v then v
+ else (add h v v;v)
+end
+*)
let pool = WH.create 4093
(* Neat trick thanks to Alain Frisch ! *)
(* WH.merge pool *)
-let branch (p,m,l,r) = norm (Branch(p,m,l,r))
+let branch p m l r = norm (Branch(p,m,l,r))
let leaf k = norm (Leaf k)
(* To enforce the invariant that a branch contains two non empty sub-trees *)
let branch_ne = function
| (_,_,e,t) when is_empty e -> t
| (_,_,t,e) when is_empty e -> t
- | (p,m,t0,t1) -> branch (p,m,t0,t1)
+ | (p,m,t0,t1) -> branch p m t0 t1
(********** from here on, only use the smart constructors *************)
let hbit = Array.init 256 naive_highest_bit
let highest_bit_32 x =
- let n = x lsr 24 in if n != 0 then hbit.(n) lsl 24
- else let n = x lsr 16 in if n != 0 then hbit.(n) lsl 16
- else let n = x lsr 8 in if n != 0 then hbit.(n) lsl 8
- else hbit.(x)
+ let n = x lsr 24 in if n != 0 then Array.unsafe_get hbit n lsl 24
+ else let n = x lsr 16 in if n != 0 then Array.unsafe_get hbit n lsl 16
+ else let n = x lsr 8 in if n != 0 then Array.unsafe_get hbit n lsl 8
+ else Array.unsafe_get hbit x
let highest_bit_64 x =
let n = x lsr 32 in if n != 0 then (highest_bit_32 n) lsl 32
let branching_bit p0 p1 = highest_bit (p0 lxor p1)
- let join (p0,t0,p1,t1) =
+ let join p0 t0 p1 t1 =
let m = branching_bit p0 p1 in
if zero_bit p0 m then
- branch (mask p0 m, m, t0, t1)
+ branch (mask p0 m) m t0 t1
else
- branch (mask p0 m, m, t1, t0)
+ branch (mask p0 m) m t1 t0
let match_prefix k p m = (mask k m) == p
let add k t =
let rec ins n = match n.node with
| Empty -> leaf k
- | Leaf j -> if j == k then n else join (k, leaf k, j, n)
+ | Leaf j -> if j == k then n else join k (leaf k) j n
| Branch (p,m,t0,t1) ->
if match_prefix k p m then
if zero_bit k m then
- branch (p, m, ins t0, t1)
+ branch p m (ins t0) t1
else
- branch (p, m, t0, ins t1)
+ branch p m t0 (ins t1)
else
- join (k, leaf k, p, n)
+ join k (leaf k) p n
in
ins t
(* should run in O(1) thanks to Hash consing *)
- let equal = (=)
+ let equal a b = a==b || a.id == b.id
- let compare = compare
+ let compare a b = if a == b then 0 else a.id - b.id
- let rec merge (s,t) =
+ let rec merge s t =
if (equal s t) (* This is cheap thanks to hash-consing *)
then s
else
| _, Leaf k -> add k s
| Branch (p,m,s0,s1), Branch (q,n,t0,t1) ->
if m == n && match_prefix q p m then
- branch (p, m, merge (s0,t0), merge (s1,t1))
+ branch p m (merge s0 t0) (merge s1 t1)
else if m > n && match_prefix q p m then
if zero_bit q m then
- branch (p, m, merge (s0,t), s1)
+ branch p m (merge s0 t) s1
else
- branch (p, m, s0, merge (s1,t))
- else if m < n && match_prefix p q n then
-
+ branch p m s0 (merge s1 t)
+ else if m < n && match_prefix p q n then
if zero_bit p n then
- branch (q, n, merge (s,t0), t1)
+ branch q n (merge s t0) t1
else
- branch (q, n, t0, merge (s,t1))
+ branch q n t0 (merge s t1)
else
(* The prefixes disagree. *)
- join (p, s, q, t)
+ join p s q t
- let union s t = merge (s,t)
+
let rec subset s1 s2 = (equal s1 s2) ||
match (s1.node,s2.node) with
subset l1 r2 && subset r1 r2
else
false
+
+ let union s t =
+ merge s t
let rec inter s1 s2 =
- if (equal s1 s2)
+ if equal s1 s2
then s1
else
match (s1.node,s2.node) with
| _, Leaf k2 -> if mem k2 s1 then s2 else empty
| Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) ->
if m1 == m2 && p1 == p2 then
- merge (inter l1 l2, inter r1 r2)
+ merge (inter l1 l2) (inter r1 r2)
else if m1 > m2 && match_prefix p2 p1 m1 then
inter (if zero_bit p2 m1 then l1 else r1) s2
else if m1 < m2 && match_prefix p1 p2 m2 then
empty
let rec diff s1 s2 =
- if (equal s1 s2)
+ if equal s1 s2
then empty
else
match (s1.node,s2.node) with
| _, Leaf k2 -> remove k2 s1
| Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) ->
if m1 == m2 && p1 == p2 then
- merge (diff l1 l2, diff r1 r2)
+ merge (diff l1 l2) (diff r1 r2)
else if m1 > m2 && match_prefix p2 p1 m1 then
if zero_bit p2 m1 then
- merge (diff l1 s2, r1)
+ merge (diff l1 s2) r1
else
- merge (l1, diff r1 s2)
+ merge l1 (diff r1 s2)
else if m1 < m2 && match_prefix p1 p2 m2 then
if zero_bit p1 m2 then diff s1 l2 else diff s1 r2
else