Half way through refactoring
[SXSI/xpathcomp.git] / ata.ml
1 INCLUDE "debug.ml"
2 INCLUDE "utils.ml"
3
4 type jump_kind = [ `TAG of Tag.t | `CONTAINS of string | `NOTHING ]
5 let cpt_trans = ref 0
6 let miss_trans = ref 0
7 let cpt_eval = ref 0
8 let miss_eval = ref 0
9
10 (* Todo : move elsewhere *)
11 external vb : bool -> int = "%identity"
12
13 module State : 
14 sig 
15   include Sigs.T with type t = int 
16   val make : unit -> t 
17 end =
18 struct
19   type t = int
20   let make = 
21     let id = ref (-1) in
22       fun () -> incr id;!id
23   let compare = (-)
24   let equal = (==)
25   external hash : t -> int =  "%identity"
26   let print fmt x = Format.fprintf fmt "%i" x
27   let dump fmt x = print fmt x
28   let check x = 
29     if x < 0 then failwith (Printf.sprintf "State: Assertion %i < 0 failed" x)
30 end
31
32 module StateSet = struct
33   include Ptset.Int
34   let print ppf s = 
35     Format.pp_print_string ppf "{ ";
36     iter (fun i -> Format.fprintf ppf "%i " i) s;
37     Format.pp_print_string ppf "}";
38     Format.pp_print_flush ppf ()
39 end
40   
41 module Formula =
42 struct
43     type 'hcons expr = 
44       | False | True
45       | Or of 'hcons * 'hcons
46       | And of 'hcons * 'hcons
47       | Atom of ([ `Left | `Right  | `LLeft | `RRight  ]*bool*State.t)
48     type 'hcons node = {
49       pos : 'hcons expr;
50       mutable neg : 'hcons;
51       st : (StateSet.t*StateSet.t*StateSet.t)*(StateSet.t*StateSet.t*StateSet.t);
52       size: int; (* Todo check if this is needed *)
53     }
54         
55     external hash_const_variant : [> ] -> int = "%identity" 
56     module rec HNode : Hcons.S with type data = Node.t = Hcons.Make (Node)
57     and Node : Hashtbl.HashedType  with type t = HNode.t node =
58     struct 
59     type t =  HNode.t node
60     let equal x y = x.size == y.size &&
61       match x.pos,y.pos with
62       | False,False
63       | True,True -> true
64       | Or(xf1,xf2),Or(yf1,yf2) 
65       | And(xf1,xf2),And(yf1,yf2)  -> (HNode.equal xf1 yf1) && (HNode.equal xf2 yf2)
66       | Atom(d1,p1,s1), Atom(d2,p2,s2) -> d1 == d2 && (p1==p2) && s1 == s2
67       | _ -> false
68     let hash f = 
69       match f.pos with
70         | False -> 0
71         | True -> 1
72         | Or (f1,f2) -> HASHINT3(PRIME2,HNode.hash f1,HNode.hash f2)
73         | And (f1,f2) -> HASHINT3(PRIME3,HNode.hash f1,HNode.hash f2)
74         | Atom(d,p,s) -> HASHINT4(PRIME4,hash_const_variant d,vb p,s)       
75     end
76
77     type t = HNode.t
78     let hash = HNode.hash 
79     let uid = HNode.uid 
80     let equal = HNode.equal 
81     let expr f = (HNode.node f).pos
82     let st f = (HNode.node f ).st
83     let size f = (HNode.node f).size
84       
85     let prio f = 
86       match expr f with
87         | True | False -> 10
88         | Atom _ -> 8
89         | And _ -> 6
90         | Or _ -> 1
91
92     let rec print ?(parent=false) ppf f =
93       if parent then Format.fprintf ppf "(";
94       let _ = match expr f with
95         | True -> Format.fprintf ppf "T"
96         | False -> Format.fprintf ppf "F"
97         | And(f1,f2) -> 
98             print ~parent:(prio f > prio f1) ppf f1;
99             Format.fprintf ppf " ∧ ";
100             print ~parent:(prio f > prio f2) ppf f2;
101         | Or(f1,f2) -> 
102             (print ppf f1);
103             Format.fprintf ppf " ∨ ";
104             (print ppf f2);
105         | Atom(dir,b,s) -> Format.fprintf ppf "%s%s[%i]"
106             (if b then "" else "¬")
107               (match  dir with 
108                  | `Left ->  "↓₁" 
109                  | `Right -> "↓₂"
110                  | `LLeft ->  "⇓₁" 
111                  | `RRight -> "⇓₂") s
112       in
113         if parent then Format.fprintf ppf ")"
114           
115     let print ppf f =  print ~parent:false ppf f
116       
117     let is_true f = (expr f) == True
118     let is_false f = (expr f) == False
119
120
121     let cons pos neg s1 s2 size1 size2 =
122       let nnode = HNode.make { pos = neg; neg = (Obj.magic 0); st = s2; size = size2 } in
123       let pnode = HNode.make { pos = pos; neg = nnode ; st = s1; size = size1 }
124       in 
125         (HNode.node nnode).neg <- pnode; (* works because the neg field isn't taken into
126                                             account for hashing ! *)
127         pnode,nnode
128
129     let empty_triple = StateSet.empty,StateSet.empty,StateSet.empty
130     let empty_hex = empty_triple,empty_triple
131     let true_,false_ = cons True False empty_hex empty_hex 0 0
132     let atom_ d p s = 
133       let si = StateSet.singleton s in
134       let ss = match d with
135         | `Left -> (si,StateSet.empty,si),empty_triple
136         | `Right -> empty_triple,(si,StateSet.empty,si)
137         | `LLeft -> (StateSet.empty,si,si),empty_triple
138         | `RRight -> empty_triple,(StateSet.empty,si,si)
139       in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1)
140
141     let not_ f = (HNode.node f).neg
142     let union_hex  ((l1,ll1,lll1),(r1,rr1,rrr1))  ((l2,ll2,lll2),(r2,rr2,rrr2)) =
143       (StateSet.mem_union l1 l2 ,StateSet.mem_union ll1 ll2,StateSet.mem_union lll1 lll2),
144       (StateSet.mem_union r1 r2 ,StateSet.mem_union rr1 rr2,StateSet.mem_union rrr1 rrr2)
145       
146     let merge_states f1 f2 =
147       let sp = 
148         union_hex (st f1) (st f2)
149       and sn = 
150         union_hex (st (not_ f1)) (st (not_ f2))
151       in
152         sp,sn
153
154     let order f1 f2 = if uid f1  < uid f2 then f2,f1 else f1,f2 
155
156     let or_ f1 f2 = 
157       (* Tautologies: x|x, x|not(x) *)
158
159       if equal f1 f2 then f1 else        
160       if equal f1 (not_ f2) then true_ else
161
162       (* simplification *)
163       if is_true f1 || is_true f2 then true_ else
164       if is_false f1 && is_false f2 then false_ else
165       if is_false f1 then f2 else
166       if is_false f2 then f1 else
167
168       (* commutativity of | *)
169       
170       let f1,f2 = order f1 f2 in
171       let psize = (size f1) + (size f2) in
172       let nsize = (size (not_ f1)) + (size (not_ f2)) in
173       let sp,sn = merge_states f1 f2 in
174         fst (cons (Or(f1,f2)) (And(not_ f1,not_ f2)) sp sn psize nsize)
175               
176                       
177     let and_ f1 f2 = 
178
179       (* Tautologies: x&x, x&not(x) *)
180
181       if equal f1 f2 then f1 else 
182       if equal f1 (not_ f2) then false_ else
183
184         (* simplifications *)
185
186       if is_true f1 && is_true f2 then true_ else
187       if is_false f1 || is_false f2 then false_ else
188       if is_true f1 then f2 else
189       if is_true f2 then f1 else
190       
191       (* commutativity of & *)
192
193       let f1,f2 = order f1 f2 in        
194       let psize = (size f1) + (size f2) in
195       let nsize = (size (not_ f1)) + (size (not_ f2)) in
196       let sp,sn = merge_states f1 f2 in
197         fst (cons (And(f1,f2)) (Or(not_ f1,not_ f2)) sp sn psize nsize)               
198     module Infix = struct
199     let ( +| ) f1 f2 = or_ f1 f2
200     let ( *& ) f1 f2 = and_ f1 f2
201     let ( *+ ) d s = atom_ d true s
202     let ( *- ) d s = atom_ d false s
203     end
204 end
205   
206 module Transition = struct
207   
208   type node = State.t*bool*Formula.t*bool
209   include Hcons.Make(struct
210                        type t = node
211                        let hash (s,m,f,b) = HASHINT4(s,Formula.uid f,vb m,vb b)
212                        let equal (s,b,f,m) (s',b',f',m') = 
213                          s == s' && b==b' && m==m' && Formula.equal f f' 
214                      end)
215     
216   let print ppf f = let (st,mark,form,_) = node f in
217     Format.fprintf ppf "%i %s" st (if mark then "⇒" else "→");
218     Formula.print ppf form;
219     Format.pp_print_flush ppf ()
220   module Infix = struct
221   let ( ?< ) x = x
222   let ( >< ) state (l,mark) = state,(l,mark,true)
223   let ( ><@ ) state (l,mark) = state,(l,mark,false)
224   let ( >=> ) (state,(label,mark,bur)) form = (state,label,(make (state,mark,form,bur)))
225   end
226
227 end
228
229 module SetTagKey =
230 struct 
231   type t = Ptset.Int.t*Tag.t 
232   let equal (s1,t1) (s2,t2) =  (t1 == t2) &&  Ptset.Int.equal s1 s2
233   let hash (s,t) = HASHINT2(Ptset.Int.hash s,Tag.hash t)
234 end
235
236 module TransTable = Hashtbl
237 module CachedTransTable = Hashtbl.Make(SetTagKey)
238  
239 module Formlist = struct 
240   include Ptset.Make(Transition)
241   let print ppf fl = 
242     iter (fun t -> Transition.print ppf t; Format.pp_print_newline ppf ()) fl
243 end
244
245   
246 type 'a t = { 
247     id : int;
248     mutable states : Ptset.Int.t;
249     init : Ptset.Int.t;
250     starstate : Ptset.Int.t option;
251     (* Transitions of the Alternating automaton *)
252     trans : (State.t,(TagSet.t*Transition.t) list) Hashtbl.t;
253     query_string: string;
254  }
255
256         
257 let dump ppf a = 
258   Format.fprintf ppf "Automaton (%i) :\n" a.id;
259   Format.fprintf ppf "States : "; StateSet.print ppf a.states;
260   Format.fprintf ppf "\nInitial states : "; StateSet.print ppf a.init;
261   Format.fprintf ppf "\nAlternating transitions :\n";
262   let l = Hashtbl.fold (fun k t acc -> 
263                           (List.map (fun (ts,tr) -> (ts,k),Transition.node tr) t) @ acc) a.trans [] in
264   let l = List.sort (fun ((tsx,x),_) ((tsy,y),_) -> 
265                        if y-x == 0 then TagSet.compare tsy tsx else y-x) l in
266   let maxh,maxt,l_print = 
267     List.fold_left (
268       fun (maxh,maxt,l) ((ts,q),(_,b,f,_)) ->                     
269         let s = 
270           if TagSet.is_finite ts 
271           then "{" ^ (TagSet.fold (fun t a -> a ^ " '" ^ (Tag.to_string t)^"'") ts "") ^" }"
272           else let cts = TagSet.neg ts in
273             if TagSet.is_empty cts then "*" else
274             (TagSet.fold (fun t a -> a ^ " " ^ (Tag.to_string t)) cts "*\\{"
275             )^ "}"
276         in
277         let s = Printf.sprintf "(%s,%i)" s q in
278         let s_frm =
279           Formula.print Format.str_formatter f;
280           Format.flush_str_formatter()     
281         in
282           (max (String.length s) maxh, max (String.length s_frm) maxt,
283            (s,(if b then "⇒" else "→"),s_frm)::l)) (0,0,[]) l
284   in
285     Format.fprintf ppf "%s\n%!" (String.make (maxt+maxh+3) '_');
286     List.iter (fun (s,m,f) -> let s = s ^ (String.make (maxh-(String.length s)) ' ') in
287                  Format.fprintf ppf "%s %s %s\n" s m f) l_print;
288     Format.fprintf ppf "%s\n%!" (String.make (maxt+maxh+3) '_')
289     
290
291 module MemoForm = Memoizer.Make(
292   Hashtbl.Make(struct
293                  type t = Formula.t*(StateSet.t*StateSet.t)
294                  let equal (f1,(s1,t1)) (f2,(s2,t2)) =
295                    Formula.equal f1 f2 && StateSet.equal s1 s2 && StateSet.equal t1 t2
296                  let hash (f,(s,t)) = 
297                    HASHINT3(Formula.uid f ,StateSet.uid s,StateSet.uid t)
298                end))
299       
300 module F = Formula
301
302     let eval_form_bool f s1 s2 =   
303       let sets = (s1,s2) in
304       let eval = MemoForm.make_rec( 
305         fun eval (f,_) ->
306           match F.expr f with
307             | F.True -> true,true,true
308             | F.False -> false,false,false
309             | F.Atom((`Left|`LLeft),b,q) ->
310                 if b == (StateSet.mem q s1) 
311                 then (true,true,false) 
312                 else false,false,false
313             | F.Atom(_,b,q) -> 
314                 if b == (StateSet.mem q s2) 
315                 then (true,false,true)
316                 else false,false,false                  
317             | F.Or(f1,f2) ->        
318                 let b1,rl1,rr1 = eval (f1,sets)
319                 in
320                   if b1 && rl1 && rr1 then (true,true,true)  else
321                   let b2,rl2,rr2 = eval (f2,sets)  in
322                   let rl1,rr1 = if b1 then rl1,rr1 else false,false
323                   and rl2,rr2 = if b2 then rl2,rr2 else false,false
324                   in (b1 || b2, rl1||rl2,rr1||rr2)
325
326         | F.And(f1,f2) -> 
327             let b1,rl1,rr1 = eval (f1,sets) in
328               if b1 && rl1 && rr1 then (true,true,true) else
329               if b1 then 
330               let b2,rl2,rr2 = eval (f2,sets) in
331                 if b2 then (true,rl1||rl2,rr1||rr2) else (false,false,false)
332               else (false,false,false)      
333       )
334       in
335         eval (f,sets)
336
337
338     module MemoFormlist = Memoizer.Make(
339       Hashtbl.Make(struct
340                      type t = Formlist.t*(StateSet.t*StateSet.t)
341                      let equal (f1,(s1,t1)) (f2,(s2,t2)) =
342                        Formlist.equal f1 f2 && StateSet.equal s1 s2 && StateSet.equal t1 t2
343                      let hash (f,(s,t)) = 
344                        HASHINT3(Formlist.uid f ,StateSet.uid s,StateSet.uid t)
345                    end))
346
347     let eval_formlist ?(memo=true) s1 s2 fl = 
348       let sets = (s1,s2) in
349       let eval = MemoFormlist.make_rec (
350         fun eval (fl,_) ->
351           if Formlist.is_empty fl 
352           then StateSet.empty,false,false,false,false
353           else 
354           let f,fll = Formlist.uncons fl in
355           let q,mark,f,_ = Transition.node f in
356           let b,b1,b2 = eval_form_bool f s1 s2 in
357           let s,b',b1',b2',amark = eval (fll,sets) in
358             if b then (StateSet.add q s, b, b1'||b1,b2'||b2,mark||amark)
359             else s,b',b1',b2',amark )
360       in eval (fl,sets)
361               
362               
363     let tags_of_state a q = 
364       Hashtbl.fold  
365         (fun p l acc -> 
366            if p == q then List.fold_left 
367            
368            (fun acc (ts,t) -> 
369               let _,_,_,aux = Transition.node t in
370                 if aux then acc else
371                 TagSet.cup ts acc) acc l
372            
373            else acc) a.trans TagSet.empty
374       
375       
376
377     let tags a qs = 
378       let ts = Ptset.Int.fold (fun q acc -> TagSet.cup acc (tags_of_state a q)) qs TagSet.empty
379       in
380         if TagSet.is_finite ts 
381         then `Positive(TagSet.positive ts)
382         else `Negative(TagSet.negative ts)
383         
384     let inter_text a b =
385       match b with
386         | `Positive s -> let r = Ptset.Int.inter a s in (r,Ptset.Int.mem Tag.pcdata r, true)
387         | `Negative s -> let r = Ptset.Int.diff a s in (r, Ptset.Int.mem Tag.pcdata r, false)
388
389     let mk_nil_ctx x _ = Tree.mk_nil x
390     let next_sibling_ctx x _ = Tree.next_sibling x 
391     let r_ignore _ x = x
392       
393     let set_get_tag r t = r := (fun _ -> t)
394
395     module type ResultSet = 
396     sig
397       type t
398       val empty : t
399       val cons : Tree.t -> t -> t
400       val concat : t -> t -> t
401       val iter : (Tree.t -> unit) -> t -> unit
402       val fold : (Tree.t -> 'a -> 'a) -> t -> 'a -> 'a
403       val map : (Tree.t -> Tree.t) -> t -> t
404       val length : t -> int
405     end
406
407     module Integer : ResultSet =
408     struct
409       type t = int
410       let empty = 0
411       let cons _ x = x+1
412       let concat x y = x + y
413       let iter _ _ = failwith "iter not implemented"
414       let fold _ _ _ = failwith "fold not implemented"
415       let map _ _ = failwith "map not implemented"
416       let length x = x
417     end
418
419     module IdSet : ResultSet = 
420     struct
421       type node = Nil 
422                   | Cons of Tree.t * node 
423                   | Concat of node*node
424    
425       and t = { node : node;
426                 length :  int }
427
428       let empty = { node = Nil; length = 0 }
429         
430       let cons e t = { node = Cons(e,t.node); length = t.length+1 }
431       let concat t1 t2 = { node = Concat(t1.node,t2.node); length = t1.length+t2.length }
432       let append e t = { node = Concat(t.node,Cons(e,Nil)); length = t.length+1 } 
433         
434       let fold f l acc = 
435         let rec loop acc t = match t with
436           | Nil -> acc
437           | Cons (e,t) -> loop (f e acc) t
438           | Concat (t1,t2) -> loop (loop acc t1) t2
439         in
440           loop acc l.node
441             
442       let length l = l.length
443         
444         
445       let iter f l =
446         let rec loop = function
447           | Nil -> ()
448           | Cons (e,t) -> f e; loop t
449           | Concat(t1,t2) -> loop t1;loop t2
450         in loop l.node
451
452       let map f l =
453         let rec loop = function 
454           | Nil -> Nil
455           | Cons(e,t) -> Cons(f e, loop t)
456           | Concat(t1,t2) -> Concat(loop t1,loop t2)
457         in
458           { l with node = loop l.node }
459
460            
461     end
462
463     module Run (RS : ResultSet) =
464     struct
465
466
467       let fmt = Format.err_formatter
468       let pr x = Format.fprintf fmt x
469         
470       type ptset_list = Nil | Cons of Ptset.Int.t*int*ptset_list
471       let hpl l = match l with
472         | Nil -> 0
473         | Cons (_,i,_) -> i 
474
475       let cons s l = Cons (s,(Ptset.Int.hash s) + 65599 * (hpl l), l)
476           
477       let rec empty_size n = 
478         if n == 0 then Nil
479         else cons Ptset.Int.empty (empty_size (n-1))
480         
481       let fold_pl f l acc = 
482         let rec loop l acc = match l with
483             Nil -> acc
484           | Cons(s,h,pl) -> loop pl (f s h acc)
485         in
486           loop l acc
487       let map_pl f l = 
488         let rec loop =
489           function Nil -> Nil 
490             | Cons(s,h,ll) -> cons (f s) (loop ll) 
491         in loop l
492       let iter_pl f l = 
493         let rec loop =
494           function Nil -> ()
495             | Cons(s,h,ll) ->  (f s);(loop ll) 
496         in loop l
497
498       let rev_pl l = 
499         let rec loop acc l = match l with 
500           | Nil -> acc
501           | Cons(s,_,ll) -> loop (cons s acc) ll
502         in
503           loop Nil l
504
505       let rev_map_pl f l  = 
506         let rec loop acc l = 
507           match l with 
508             | Nil -> acc
509             | Cons(s,_,ll) -> loop (cons (f s) acc) ll
510         in
511           loop Nil l
512
513       module IntSet = Set.Make(struct type t = int let compare = (-) end)
514
515
516 IFDEF DEBUG
517 THEN
518 INCLUDE "html_trace.ml"
519               
520 END             
521
522       let td_trans = Hashtbl.create 4096
523       let mk_fun f s = D_IGNORE_(register_funname f s,f)
524       let mk_app_fun f arg s = let g = f arg in 
525         D_IGNORE_(register_funname g ((get_funname f) ^ " " ^ s), g) 
526
527       let string_of_ts tags = (Ptset.Int.fold (fun t a -> a ^ " " ^ (Tag.to_string t) ) tags "{")^ " }"
528         
529       let choose_jump tagset qtags1 qtagsn a f_nil f_text f_t1 f_s1 f_tn f_sn f_notext =
530         let tags1,hastext1,fin1 = inter_text tagset (tags a qtags1) in
531         let tagsn,hastextn,finn = inter_text tagset (tags a qtagsn) in
532           if (hastext1||hastextn) then f_text  (* jumping to text nodes doesn't work really well *)
533           else if (Ptset.Int.is_empty tags1) && (Ptset.Int.is_empty tagsn) then f_nil
534           else if (Ptset.Int.is_empty tagsn) then 
535             if (Ptset.Int.is_singleton tags1) 
536             then (* TaggedChild/Sibling *)
537               let tag = (Ptset.Int.choose tags1) in mk_app_fun f_t1 tag (Tag.to_string tag)
538             else (* SelectChild/Sibling *)
539               mk_app_fun f_s1 tags1 (string_of_ts tags1)
540           else if (Ptset.Int.is_empty tags1) then 
541             if (Ptset.Int.is_singleton tagsn) 
542             then (* TaggedDesc/Following *)
543               let tag = (Ptset.Int.choose tagsn) in  mk_app_fun f_tn tag (Tag.to_string tag)
544             else (* SelectDesc/Following *)
545               mk_app_fun f_sn tagsn (string_of_ts tagsn) 
546           else f_notext
547           
548       let choose_jump_down a b c d =
549         choose_jump a b c d
550           (mk_fun (Tree.mk_nil) "Tree.mk_nil")
551           (mk_fun (Tree.text_below) "Tree.text_below")
552           (mk_fun (fun _ -> Tree.node_child) "[TaggedChild]Tree.node_child") (* !! no tagged_child in Tree.ml *)
553           (mk_fun (fun _ -> Tree.node_child) "[SelectChild]Tree.node_child") (* !! no select_child in Tree.ml *)
554           (mk_fun (Tree.tagged_desc) "Tree.tagged_desc")
555           (mk_fun (fun _ -> Tree.node_child ) "[SelectDesc]Tree.node_child") (* !! no select_desc *)
556           (mk_fun (Tree.node_child) "Tree.node_child")
557
558       let choose_jump_next a b c d = 
559         choose_jump a b c d
560           (mk_fun (fun t _ -> Tree.mk_nil t) "Tree.mk_nil2")
561           (mk_fun (Tree.text_next) "Tree.text_next")
562           (mk_fun (fun _ -> Tree.node_sibling_ctx) "[TaggedSibling]Tree.node_sibling_ctx")(* !! no tagged_sibling in Tree.ml *)
563           (mk_fun (fun _ -> Tree.node_sibling_ctx) "[SelectSibling]Tree.node_sibling_ctx")(* !! no select_sibling in Tree.ml *)
564           (mk_fun (Tree.tagged_foll_below) "Tree.tagged_foll_below")
565           (mk_fun (fun _ -> Tree.node_sibling_ctx) "[SelectFoll]Tree.node_sibling_ctx")(* !! no select_foll *)
566           (mk_fun (Tree.node_sibling_ctx) "Tree.node_sibling_ctx")        
567                                 
568       let get_trans slist tag a t = 
569         try 
570           Hashtbl.find td_trans (tag,hpl slist)
571         with
572           | Not_found -> 
573               let fl_list,llist,rlist,ca,da,sa,fa = 
574                 fold_pl 
575                   (fun set _  (fll_acc,lllacc,rllacc,ca,da,sa,fa) -> (* For each set *)
576                      let fl,ll,rr,ca,da,sa,fa = 
577                        StateSet.fold
578                          (fun q acc ->                      
579                             List.fold_left 
580                               (fun ((fl_acc,ll_acc,rl_acc,c_acc,d_acc,s_acc,f_acc) as acc) 
581                                  (ts,t)  ->
582                                    if (TagSet.mem tag ts)
583                                    then 
584                                    let _,_,f,_ = Transition.node t in
585                                    let (child,desc,below),(sibl,foll,after) = Formula.st f in
586                                      (Formlist.add t fl_acc,
587                                       StateSet.union ll_acc below,
588                                       StateSet.union rl_acc after,
589                                       StateSet.union child c_acc,
590                                       StateSet.union desc d_acc,
591                                       StateSet.union sibl s_acc,
592                                       StateSet.union foll f_acc)                 
593                                    else acc ) acc (
594                                 try Hashtbl.find a.trans q 
595                                 with
596                                     Not_found -> Printf.eprintf "Looking for state %i, doesn't exist!!!\n%!"
597                                       q;[]
598                               )
599                               
600                          ) set (Formlist.empty,StateSet.empty,StateSet.empty,ca,da,sa,fa)
601                      in fl::fll_acc, cons ll lllacc, cons rr rllacc,ca,da,sa,fa)
602                   slist ([],Nil,Nil,StateSet.empty,StateSet.empty,StateSet.empty,StateSet.empty)
603               in
604                 (* Logic to chose the first and next function *)
605               let tags_below,tags_after = Tree.tags t tag in
606               let first = choose_jump_down tags_below ca da a
607               and next = choose_jump_next tags_after sa fa a in 
608               let v = (fl_list,llist,rlist,first,next) in
609                 Hashtbl.add td_trans (tag, hpl slist) v; v
610                   
611       let merge rb rb1 rb2 mark t res1 res2 = 
612         if rb 
613         then 
614           let res1 = if rb1 then res1 else RS.empty
615           and res2 = if rb2 then res2 else RS.empty
616           in
617             if mark then RS.cons t (RS.concat res1 res2)
618             else RS.concat res1 res2
619         else RS.empty 
620
621       let top_down ?(noright=false) a t slist ctx slot_size =   
622         let pempty = empty_size slot_size in    
623         let eval_fold2_slist fll sl1 sl2 res1 res2 t =
624           let res = Array.copy res1 in
625           let rec fold l1 l2 fll i aq = match l1,l2,fll with
626             | Cons(s1,_,ll1), Cons(s2, _ ,ll2),fl::fll -> 
627                 let r',rb,rb1,rb2,mark = eval_formlist s1 s2 fl in
628                 let _ = res.(i) <- merge rb rb1 rb2 mark t res1.(i) res2.(i) 
629                 in                
630                   fold ll1 ll2 fll (i+1) (cons r' aq)
631             | Nil, Nil,[] -> aq,res
632             | _ -> assert false
633           in
634             fold sl1 sl2 fll 0 Nil
635         in
636         let null_result() = (pempty,Array.make slot_size RS.empty) in
637         let rec loop t slist ctx = 
638           if Tree.is_nil t then null_result()
639           else      
640             let tag = Tree.tag t in        
641             let fl_list,llist,rlist,first,next = get_trans slist tag a t in
642             let sl1,res1 = loop (first t) llist t in
643             let sl2,res2 = loop (next t ctx) rlist ctx in
644             let res = eval_fold2_slist fl_list sl1 sl2 res1 res2 t          
645             in
646               D_IGNORE_(
647                 register_trace t (slist,(fst res),sl1,sl2,fl_list,first,next,ctx),
648                 res)
649         in
650         let loop_no_right t slist ctx =
651           if Tree.is_nil t then null_result()
652           else      
653             let tag = Tree.tag t in
654             let fl_list,llist,rlist,first,next = get_trans slist tag a t in
655             let sl1,res1 = loop (first t) llist t in
656             let sl2,res2 = null_result() in
657             let res = eval_fold2_slist fl_list sl1 sl2 res1 res2 t
658             in  
659               D_IGNORE_(
660                 register_trace t (slist,(fst res),sl1,sl2,fl_list,first,next,ctx),
661                 res)
662         in
663           (if noright then loop_no_right else loop) t slist ctx
664             
665
666         let run_top_down a t =
667           let init = cons a.init Nil in
668           let _,res = top_down a t init t 1 
669           in 
670             D_IGNORE_(
671               output_trace a t "trace.html"
672                 (RS.fold (fun t a -> IntSet.add (Tree.id t) a) res.(0) IntSet.empty),
673               res.(0))
674         ;;
675
676         module Configuration =
677         struct
678           module Ptss = Set.Make(StateSet)
679           module IMap = Map.Make(StateSet)
680           type t = { hash : int;
681                         sets : Ptss.t;
682                         results : RS.t IMap.t }
683           let empty = { hash = 0;
684                         sets = Ptss.empty;
685                         results = IMap.empty;
686                       }
687           let is_empty c = Ptss.is_empty c.sets
688           let add c s r =
689             if Ptss.mem s c.sets then
690               { c with results = IMap.add s (RS.concat r (IMap.find s c.results)) c.results}
691             else
692               { hash = HASHINT2(c.hash,Ptset.Int.hash s);
693                 sets = Ptss.add s c.sets;
694                 results = IMap.add s r c.results
695               }
696
697           let pr fmt c = Format.fprintf fmt "{";
698             Ptss.iter (fun s -> StateSet.print fmt s;
699                         Format.fprintf fmt "  ") c.sets;
700             Format.fprintf fmt "}\n%!";
701             IMap.iter (fun k d -> 
702                          StateSet.print fmt k;
703                          Format.fprintf fmt "-> %i\n" (RS.length d)) c.results;                  
704             Format.fprintf fmt "\n%!"
705             
706           let merge c1 c2  =
707             let acc1 = IMap.fold (fun s r acc -> 
708                                     IMap.add s
709                                       (try 
710                                          RS.concat r (IMap.find s acc)
711                                        with
712                                          | Not_found -> r) acc) c1.results IMap.empty 
713             in
714             let imap =
715               IMap.fold (fun s r acc -> 
716                            IMap.add s
717                              (try 
718                                 RS.concat r (IMap.find s acc)
719                               with
720                                 | Not_found -> r) acc)  c2.results acc1
721             in
722             let h,s =
723               Ptss.fold 
724                 (fun s (ah,ass) -> (HASHINT2(ah,Ptset.Int.hash s),
725                                     Ptss.add s ass))
726                 (Ptss.union c1.sets c2.sets) (0,Ptss.empty)
727             in
728               { hash = h;
729                 sets =s;
730                 results = imap }
731
732         end
733
734         let h_fold = Hashtbl.create 511 
735
736         let fold_f_conf  t slist fl_list conf dir= 
737           let rec loop sl fl acc =
738             match sl,fl with
739               |Nil,[] -> acc
740               | Cons(s,hs,sll), formlist::fll ->
741                   let r',rb,rb1,rb2,mark = 
742                     try 
743                       Hashtbl.find h_fold (hs,Formlist.hash formlist,dir)
744                     with
745                         Not_found -> let res = 
746                           if dir then eval_formlist ~memo:false s Ptset.Int.empty formlist
747                           else eval_formlist ~memo:false Ptset.Int.empty s formlist 
748                         in (Hashtbl.add h_fold (hs,Formlist.hash formlist,dir) res;res)
749                   in(*
750                   let _ = pr "Evaluating on set (%s) with tree %s=%s" 
751                     (if dir then "left" else "right")
752                     (Tag.to_string (Tree.tag t))
753                     (Tree.dump_node t) ;
754                     StateSet.print fmt (Ptset.Int.elements s);
755                     pr ", formualae (with hash %i): \n" (Formlist.hash formlist);
756                     Formlist.pr fmt formlist;
757                     pr "result is ";
758                     StateSet.print fmt (Ptset.Int.elements r');
759                     pr " %b %b %b %b \n%!" rb rb1 rb2 mark ; 
760                   in *)
761                     if rb && ((dir&&rb1)|| ((not dir) && rb2))
762                     then 
763                       let acc = 
764                         let old_r = 
765                           try Configuration.IMap.find s conf.Configuration.results
766                           with Not_found -> RS.empty
767                         in
768                           Configuration.add acc r' (if mark then RS.cons t old_r else old_r)                    
769                       in
770                         loop sll fll acc
771                     else loop sll fll acc
772               | _ -> assert false
773           in
774             loop slist fl_list Configuration.empty
775
776         let h_trans = Hashtbl.create 4096
777
778         let get_up_trans slist ptag a tree =      
779           let key = (HASHINT2(hpl slist,Tag.hash ptag)) in
780             try
781           Hashtbl.find h_trans key              
782           with
783           | Not_found ->  
784               let f_list =
785                 Hashtbl.fold (fun q l acc ->
786                                 List.fold_left (fun fl_acc (ts,t)  ->
787                                                   if TagSet.mem ptag ts then Formlist.add t fl_acc
788                                                   else fl_acc)
789                                   
790                                   acc l)
791                   a.trans Formlist.empty
792               in
793               let res = fold_pl (fun _ _ acc -> f_list::acc) slist [] 
794               in
795                 (Hashtbl.add h_trans key res;res) 
796                   
797               
798         let h_tdconf = Hashtbl.create 511 
799         let rec bottom_up a tree conf next jump_fun root dotd init accu = 
800           if (not dotd) && (Configuration.is_empty conf ) then
801 (*                  let _ = pr "Returning early from %s, with accu %i, next is %s\n%!" 
802                     (Tree.dump_node tree) (Obj.magic accu) (Tree.dump_node next)
803                     in *)
804             accu,conf,next 
805           else
806 (*          let _ =   
807             pr "Going bottom up for tree with tag %s configuration is" 
808             (if Tree.is_nil tree then "###" else Tag.to_string (Tree.tag tree));
809             Configuration.pr fmt conf 
810             in *)
811             let below_right = Tree.is_below_right tree next in 
812               (*          let _ = Format.fprintf Format.err_formatter "below_right %s %s = %b\n%!"
813                           (Tree.dump_node tree) (Tree.dump_node next)  below_right
814                           in *)
815             let accu,rightconf,next_of_next =       
816             if below_right then (* jump to the next *)
817 (*            let _ = pr "Jumping to %s tag %s\n%!" (Tree.dump_node next) (Tag.to_string (Tree.tag next)) in   *)
818               bottom_up a next conf (jump_fun next) jump_fun (Tree.next_sibling tree) true init accu
819             else accu,Configuration.empty,next
820           in 
821 (*        let _ = if below_right then pr "Returning from jump to next = %s\n" (Tree.dump_node next)in   *)
822           let sub =
823             if dotd then
824               if below_right then (* only recurse on the left subtree *)
825 (*              let _ = pr "Topdown on left subtree\n%!" in      *)
826                 prepare_topdown a tree true
827               else 
828 (*              let _ = pr "Topdown on whole tree\n%!" in *)
829                 prepare_topdown a tree false
830             else conf
831           in
832           let conf,next =
833             (Configuration.merge rightconf sub, next_of_next)
834           in
835             if Tree.equal tree root then 
836 (*              let _ = pr "Stopping at root, configuration after topdown is:" ;
837                 Configuration.pr fmt conf;
838                 pr "\n%!"               
839               in *)  accu,conf,next 
840             else              
841           let parent = Tree.binary_parent tree in
842           let ptag = Tree.tag parent in
843           let dir = Tree.is_left tree in
844           let slist = Configuration.Ptss.fold (fun e a -> cons e a) conf.Configuration.sets Nil in
845           let fl_list = get_up_trans slist ptag a parent in
846           let slist = rev_pl (slist) in 
847 (*        let _ = pr "Current conf is : %s " (Tree.dump_node tree); 
848             Configuration.pr fmt conf;
849             pr "\n" 
850           in *)
851           let newconf = fold_f_conf parent slist fl_list conf dir in
852 (*        let _ = pr "New conf before pruning is (dir=%b):" dir;
853             Configuration.pr fmt newconf ;
854             pr "accu is %i\n" (RS.length accu);
855           in        *)
856           let accu,newconf = Configuration.IMap.fold (fun s res (ar,nc) ->
857                                                         if Ptset.Int.intersect s init then
858                                                           ( RS.concat res ar ,nc)
859                                                         else (ar,Configuration.add nc s res))
860             (newconf.Configuration.results) (accu,Configuration.empty) 
861           in
862 (*        let _ = pr "New conf after pruning is (dir=%b):" dir;
863             Configuration.pr fmt newconf ;
864             pr "accu is %i\n" (RS.length accu);
865           in        *)
866             bottom_up a parent newconf next jump_fun root false init accu
867
868         and prepare_topdown a t noright =
869           let tag = Tree.tag t in
870 (*        pr "Going top down on tree with tag %s = %s "  
871             (if Tree.is_nil t then "###" else (Tag.to_string(Tree.tag t))) (Tree.dump_node t); *)
872           let r = 
873             try
874               Hashtbl.find h_tdconf tag
875             with
876               | Not_found -> 
877                   let res = Hashtbl.fold (fun q l acc -> 
878                                             if List.exists (fun (ts,_) -> TagSet.mem tag ts) l
879                                             then Ptset.Int.add q acc
880                                             else acc) a.trans Ptset.Int.empty
881                   in Hashtbl.add h_tdconf tag res;res
882           in 
883 (*        let _ = pr ", among ";
884             StateSet.print fmt (Ptset.Int.elements r);
885             pr "\n%!";
886           in *)
887           let r = cons r Nil in
888           let set,res = top_down (~noright:noright) a t r t 1 in
889           let set = match set with
890             | Cons(x,_,Nil) ->x
891             | _ -> assert false 
892           in 
893 (*          pr "Result of topdown run is %!";
894             StateSet.print fmt (Ptset.Int.elements set);
895             pr ", number is %i\n%!" (RS.length res.(0));  *)
896             Configuration.add Configuration.empty set res.(0) 
897
898
899
900         let run_bottom_up a t k =
901           let trlist = Hashtbl.find a.trans (Ptset.Int.choose a.init)
902           in
903           let init = List.fold_left 
904             (fun acc (_,t) ->
905                let _,_,f,_ = Transition.node t in 
906                let _,_,l = fst ( Formula.st f ) in
907                  Ptset.Int.union acc l)
908             Ptset.Int.empty trlist
909           in
910           let tree1,jump_fun =
911             match k with
912               | `TAG (tag) -> 
913                   (*Tree.tagged_lowest t tag, fun tree -> Tree.tagged_next tree tag*)
914                   (Tree.tagged_desc tag t, fun tree -> Tree.tagged_foll_below tag tree t)
915               | `CONTAINS(_) -> (Tree.text_below t,fun tree -> Tree.text_next tree t)
916               | _ -> assert false
917           in
918           let tree2 = jump_fun tree1 in
919           let rec loop tree next acc = 
920 (*          let _ = pr "\n_________________________\nNew iteration\n" in 
921             let _ = pr "Jumping to %s\n%!" (Tree.dump_node tree) in  *)
922             let acc,conf,next_of_next = bottom_up a tree 
923               Configuration.empty next jump_fun (Tree.root tree) true init acc
924             in 
925               (*            let _ = pr "End of first iteration, conf is:\n%!";
926                             Configuration.pr fmt conf 
927                             in *)             
928             let acc = Configuration.IMap.fold 
929               ( fun s res acc -> if Ptset.Int.intersect init s
930                 then RS.concat res acc else acc) conf.Configuration.results acc
931             in
932               if Tree.is_nil next_of_next  (*|| Tree.equal next next_of_next *)then
933                 acc
934               else loop next_of_next (jump_fun next_of_next) acc
935           in
936           loop tree1 tree2 RS.empty
937
938
939     end
940           
941     let top_down_count a t = let module RI = Run(Integer) in Integer.length (RI.run_top_down a t)
942     let top_down a t = let module RI = Run(IdSet) in (RI.run_top_down a t)
943     let bottom_up_count a t k = let module RI = Run(Integer) in Integer.length (RI.run_bottom_up a t k)
944
945