added optimisations in the run function
[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
6 (* Todo : move elsewhere *)
7 external vb : bool -> int = "%identity"
8
9 module State : 
10 sig 
11   include Sigs.T with type t = int 
12   val make : unit -> t 
13 end =
14 struct
15   type t = int
16   let make = 
17     let id = ref (-1) in
18       fun () -> incr id;!id
19   let compare = (-)
20   let equal = (==)
21   external hash : t -> int =  "%identity"
22   let print fmt x = Format.fprintf fmt "%i" x
23   let dump fmt x = print fmt x
24   let check x = 
25     if x < 0 then failwith (Printf.sprintf "State: Assertion %i < 0 failed" x)
26 end
27
28 module StateSet = Ptset.Int
29   
30 module Formula =
31 struct
32     type 'hcons expr = 
33       | False | True
34       | Or of 'hcons * 'hcons
35       | And of 'hcons * 'hcons
36       | Atom of ([ `Left | `Right  | `LLeft | `RRight  ]*bool*State.t)
37
38     type 'hcons node = {
39       pos : 'hcons expr;
40       mutable neg : 'hcons;
41       st : (StateSet.t*StateSet.t*StateSet.t)*(StateSet.t*StateSet.t*StateSet.t);
42       size: int; (* Todo check if this is needed *)
43     }
44         
45     external hash_const_variant : [> ] -> int = "%identity" 
46     module rec Node : Hcons.S with type data = Data.t = Hcons.Make (Data)
47     and Data : Hashtbl.HashedType  with type t = Node.t node =
48     struct 
49     type t =  Node.t node
50     let equal x y = x.size == y.size &&
51       match x.pos,y.pos with
52         | a,b when a == b -> true
53         | Or(xf1,xf2),Or(yf1,yf2) 
54         | And(xf1,xf2),And(yf1,yf2)  -> (xf1 == yf1) && (xf2 == yf2)
55         | Atom(d1,p1,s1), Atom(d2,p2,s2) -> d1 == d2 && (p1==p2) && s1 == s2
56         | _ -> false
57     let hash f = 
58       match f.pos with
59         | False -> 0
60         | True -> 1
61         | Or (f1,f2) -> HASHINT3(PRIME2,f1.Node.id, f2.Node.id)
62         | And (f1,f2) -> HASHINT3(PRIME3,f1.Node.id,f2.Node.id)
63         | Atom(d,p,s) -> HASHINT4(PRIME4,hash_const_variant d,vb p,s)       
64     end
65
66     type t = Node.t
67     let hash x = x.Node.key
68     let uid x = x.Node.id
69     let equal = Node.equal 
70     let expr f = f.Node.node.pos 
71     let st f = f.Node.node.st
72     let size f = f.Node.node.size
73       
74     let prio f = 
75       match expr f with
76         | True | False -> 10
77         | Atom _ -> 8
78         | And _ -> 6
79         | Or _ -> 1
80
81     let rec print ?(parent=false) ppf f =
82       if parent then Format.fprintf ppf "(";
83       let _ = match expr f with
84         | True -> Format.fprintf ppf "T"
85         | False -> Format.fprintf ppf "F"
86         | And(f1,f2) -> 
87             print ~parent:(prio f > prio f1) ppf f1;
88             Format.fprintf ppf " ∧ ";
89             print ~parent:(prio f > prio f2) ppf f2;
90         | Or(f1,f2) -> 
91             (print ppf f1);
92             Format.fprintf ppf " ∨ ";
93             (print ppf f2);
94         | Atom(dir,b,s) -> Format.fprintf ppf "%s%s[%i]"
95             (if b then "" else "¬")
96               (match  dir with 
97                  | `Left ->  "↓₁" 
98                  | `Right -> "↓₂"
99                  | `LLeft ->  "⇓₁" 
100                  | `RRight -> "⇓₂") s
101       in
102         if parent then Format.fprintf ppf ")"
103           
104     let print ppf f =  print ~parent:false ppf f
105       
106     let is_true f = (expr f) == True
107     let is_false f = (expr f) == False
108
109
110     let cons pos neg s1 s2 size1 size2 =
111       let nnode = Node.make { pos = neg; neg = (Obj.magic 0); st = s2; size = size2 } in
112       let pnode = Node.make { pos = pos; neg = nnode ; st = s1; size = size1 }
113       in 
114         (Node.node nnode).neg <- pnode; (* works because the neg field isn't taken into
115                                             account for hashing ! *)
116         pnode,nnode
117
118     let empty_triple = StateSet.empty,StateSet.empty,StateSet.empty
119     let empty_hex = empty_triple,empty_triple
120     let true_,false_ = cons True False empty_hex empty_hex 0 0
121     let atom_ d p s = 
122       let si = StateSet.singleton s in
123       let ss = match d with
124         | `Left -> (si,StateSet.empty,si),empty_triple
125         | `Right -> empty_triple,(si,StateSet.empty,si)
126         | `LLeft -> (StateSet.empty,si,si),empty_triple
127         | `RRight -> empty_triple,(StateSet.empty,si,si)
128       in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1)
129
130     let not_ f = f.Node.node.neg
131     let union_hex  ((l1,ll1,lll1),(r1,rr1,rrr1))  ((l2,ll2,lll2),(r2,rr2,rrr2)) =
132       (StateSet.mem_union l1 l2 ,StateSet.mem_union ll1 ll2,StateSet.mem_union lll1 lll2),
133       (StateSet.mem_union r1 r2 ,StateSet.mem_union rr1 rr2,StateSet.mem_union rrr1 rrr2)
134       
135     let merge_states f1 f2 =
136       let sp = 
137         union_hex (st f1) (st f2)
138       and sn = 
139         union_hex (st (not_ f1)) (st (not_ f2))
140       in
141         sp,sn
142
143     let order f1 f2 = if uid f1  < uid f2 then f2,f1 else f1,f2 
144
145     let or_ f1 f2 = 
146       (* Tautologies: x|x, x|not(x) *)
147
148       if equal f1 f2 then f1 else        
149       if equal f1 (not_ f2) then true_ else
150
151       (* simplification *)
152       if is_true f1 || is_true f2 then true_ else
153       if is_false f1 && is_false f2 then false_ else
154       if is_false f1 then f2 else
155       if is_false f2 then f1 else
156
157       (* commutativity of | *)
158       
159       let f1,f2 = order f1 f2 in
160       let psize = (size f1) + (size f2) in
161       let nsize = (size (not_ f1)) + (size (not_ f2)) in
162       let sp,sn = merge_states f1 f2 in
163       fst (cons (Or(f1,f2)) (And(not_ f1,not_ f2)) sp sn psize nsize)
164               
165                       
166     let and_ f1 f2 = 
167
168       (* Tautologies: x&x, x&not(x) *)
169
170       if equal f1 f2 then f1 else 
171       if equal f1 (not_ f2) then false_ else
172
173         (* simplifications *)
174
175       if is_true f1 && is_true f2 then true_ else
176       if is_false f1 || is_false f2 then false_ else
177       if is_true f1 then f2 else
178       if is_true f2 then f1 else
179       
180       (* commutativity of & *)
181
182       let f1,f2 = order f1 f2 in        
183       let psize = (size f1) + (size f2) in
184       let nsize = (size (not_ f1)) + (size (not_ f2)) in
185       let sp,sn = merge_states f1 f2 in
186         fst (cons (And(f1,f2)) (Or(not_ f1,not_ f2)) sp sn psize nsize)               
187     module Infix = struct
188     let ( +| ) f1 f2 = or_ f1 f2
189     let ( *& ) f1 f2 = and_ f1 f2
190     let ( *+ ) d s = atom_ d true s
191     let ( *- ) d s = atom_ d false s
192     end
193 end
194   
195 module Transition = struct
196   
197   type node = State.t*TagSet.t*bool*Formula.t*bool
198   include Hcons.Make(struct
199                        type t = node
200                        let hash (s,ts,m,f,b) = HASHINT5(s,TagSet.uid ts,Formula.uid f,vb m,vb b)
201                        let equal (s,ts,b,f,m) (s',ts',b',f',m') = 
202                          s == s' && ts == ts' && b==b' && m==m' && f == f'
203                      end)
204     
205   let print ppf f = let (st,ts,mark,form,b) = node f in
206     Format.fprintf ppf "(%i, " st;
207     TagSet.print ppf ts;
208     Format.fprintf ppf ") %s" (if mark then "⇒" else "→");
209     Formula.print ppf form;
210     Format.fprintf ppf "%s%!" (if b then " (b)" else "")
211
212
213   module Infix = struct
214   let ( ?< ) x = x
215   let ( >< ) state (l,mark) = state,(l,mark,false)
216   let ( ><@ ) state (l,mark) = state,(l,mark,true)
217   let ( >=> ) (state,(label,mark,bur)) form = (state,label,(make (state,label,mark,form,bur)))
218   end
219
220 end
221
222 module TransTable = Hashtbl
223  
224 module Formlist = struct 
225   include Hlist.Make(Transition)
226   let print ppf fl = 
227     iter (fun t -> Transition.print ppf t; Format.pp_print_newline ppf ()) fl
228 end
229
230 module Formlistlist = 
231 struct
232   include Hlist.Make(Formlist)
233   let print ppf fll =
234     iter (fun fl -> Formlist.print ppf fl; Format.pp_print_newline ppf ())fll
235 end
236   
237 type 'a t = { 
238     id : int;
239     mutable states : Ptset.Int.t;
240     init : Ptset.Int.t;
241     starstate : Ptset.Int.t option;
242     (* Transitions of the Alternating automaton *)
243     trans : (State.t,(TagSet.t*Transition.t) list) Hashtbl.t;
244     query_string: string;
245  }
246
247         
248 let dump ppf a = 
249   Format.fprintf ppf "Automaton (%i) :\n" a.id;
250   Format.fprintf ppf "States : "; StateSet.print ppf a.states;
251   Format.fprintf ppf "\nInitial states : "; StateSet.print ppf a.init;
252   Format.fprintf ppf "\nAlternating transitions :\n";
253   let l = Hashtbl.fold (fun k t acc -> 
254                           (List.map (fun (ts,tr) -> (ts,k),Transition.node tr) t) @ acc) a.trans [] in
255   let l = List.sort (fun ((tsx,x),_) ((tsy,y),_) -> 
256                        if y-x == 0 then TagSet.compare tsy tsx else y-x) l in
257   let maxh,maxt,l_print = 
258     List.fold_left (
259       fun (maxh,maxt,l) ((ts,q),(_,_,b,f,_)) ->                   
260         let s = 
261           if TagSet.is_finite ts 
262           then "{" ^ (TagSet.fold (fun t a -> a ^ " '" ^ (Tag.to_string t)^"'") ts "") ^" }"
263           else let cts = TagSet.neg ts in
264           if TagSet.is_empty cts then "*" else
265           (TagSet.fold (fun t a -> a ^ " " ^ (Tag.to_string t)) cts "*\\{"
266           )^ "}"
267         in
268         let s = Printf.sprintf "(%s,%i)" s q in
269         let s_frm =
270           Formula.print Format.str_formatter f;
271           Format.flush_str_formatter()     
272         in
273           (max (String.length s) maxh, max (String.length s_frm) maxt,
274            (s,(if b then "⇒" else "→"),s_frm)::l)) (0,0,[]) l
275   in
276     Format.fprintf ppf "%s\n%!" (String.make (maxt+maxh+3) '_');
277     List.iter (fun (s,m,f) -> let s = s ^ (String.make (maxh-(String.length s)) ' ') in
278                  Format.fprintf ppf "%s %s %s\n" s m f) l_print;
279     Format.fprintf ppf "%s\n%!" (String.make (maxt+maxh+3) '_')
280     
281
282 module FormTable = Hashtbl.Make(struct
283                                   type t = Formula.t*StateSet.t*StateSet.t
284                                   let equal (f1,s1,t1) (f2,s2,t2) =
285                                     f1 == f2 && s1 == s2 && t1 == t2
286                                   let hash (f,s,t) = 
287                                     HASHINT3(Formula.uid f ,StateSet.uid s,StateSet.uid t)
288                                 end)
289 module F = Formula
290
291 let eval_form_bool = 
292   let h_f = FormTable.create BIG_H_SIZE in
293     fun f s1 s2 ->
294       let rec loop f =
295         match F.expr f with
296           | F.True -> true,true,true
297           | F.False -> false,false,false
298           | F.Atom((`Left|`LLeft),b,q) ->
299               if b == (StateSet.mem q s1) 
300               then (true,true,false) 
301               else false,false,false
302           | F.Atom(_,b,q) -> 
303               if b == (StateSet.mem q s2) 
304               then (true,false,true)
305               else false,false,false    
306           | f' -> 
307               try FormTable.find h_f (f,s1,s2)
308               with Not_found -> let r =
309                 match f' with
310                   | F.Or(f1,f2) ->          
311                       let b1,rl1,rr1 = loop f1
312                       in
313                         if b1 && rl1 && rr1 then (true,true,true)  else
314                           let b2,rl2,rr2 = loop f2  in
315                           let rl1,rr1 = if b1 then rl1,rr1 else false,false
316                           and rl2,rr2 = if b2 then rl2,rr2 else false,false
317                           in (b1 || b2, rl1||rl2,rr1||rr2)
318                                
319                   | F.And(f1,f2) -> 
320                       let b1,rl1,rr1 = loop f1 in
321                         if b1 && rl1 && rr1 then (true,true,true) else
322                           if b1 then 
323                             let b2,rl2,rr2 = loop f2 in
324                               if b2 then (true,rl1||rl2,rr1||rr2) else (false,false,false)
325                           else (false,false,false)
326                   | _ -> assert false
327               in FormTable.add h_f (f,s1,s2) r;r
328       in loop f
329
330            
331 module FTable = Hashtbl.Make( struct
332                                 type t = Tag.t*Formlist.t*StateSet.t*StateSet.t
333                                 let equal (tg1,f1,s1,t1) (tg2,f2,s2,t2) =
334                                   tg1 == tg2 && f1 == f2 &&  s1 == s2 && t1 == t2;;
335                                 let hash (tg,f,s,t) =  HASHINT4(tg,Formlist.uid f ,StateSet.uid s,StateSet.uid t);;
336                               end)
337
338
339 let h_f = FTable.create BIG_H_SIZE 
340
341 let eval_formlist tag s1 s2 fl =
342   let rec loop fl =
343           try 
344             FTable.find h_f (tag,fl,s1,s2)
345           with 
346             | Not_found  -> 
347                 match Formlist.node fl with
348                   | Formlist.Cons(f,fll) ->
349                       let q,ts,mark,f,_ = Transition.node f in
350                       let b,b1,b2 = 
351                         if TagSet.mem tag ts then eval_form_bool f s1 s2 else (false,false,false)
352                       in
353                       let (s,(b',b1',b2',amark)) as res = loop fll in
354                       let r = if b then (StateSet.add q s, (b, b1'||b1,b2'||b2,mark||amark))
355                       else res
356                       in FTable.add h_f (tag,fl,s1,s2) r;r
357                   | Formlist.Nil -> StateSet.empty,(false,false,false,false)
358   in loop fl
359               
360 let tags_of_state a q = 
361   Hashtbl.fold  
362     (fun p l acc -> 
363        if p == q then List.fold_left 
364          (fun acc (ts,t) -> 
365             let _,_,_,_,aux = Transition.node t in
366               if aux then acc else
367                 TagSet.cup ts acc) acc l
368          
369        else acc) a.trans TagSet.empty
370       
371       
372
373     let tags a qs = 
374       let ts = Ptset.Int.fold (fun q acc -> TagSet.cup acc (tags_of_state a q)) qs TagSet.empty
375       in
376         if TagSet.is_finite ts 
377         then `Positive(TagSet.positive ts)
378         else `Negative(TagSet.negative ts)
379         
380     let inter_text a b =
381       match b with
382         | `Positive s -> let r = Ptset.Int.inter a s in (r,Ptset.Int.mem Tag.pcdata r, true)
383         | `Negative s -> let r = Ptset.Int.diff a s in (r, Ptset.Int.mem Tag.pcdata r, false)
384       
385
386     module type ResultSet = 
387     sig
388       type t
389       type elt = [` Tree ] Tree.node
390       val empty : t
391       val cons : elt -> t -> t
392       val concat : t -> t -> t
393       val iter : ( elt -> unit) -> t -> unit
394       val fold : ( elt -> 'a -> 'a) -> t -> 'a -> 'a
395       val map : ( elt -> elt) -> t -> t
396       val length : t -> int
397       val merge : (bool*bool*bool*bool) -> elt -> t -> t -> t 
398     end
399
400     module Integer : ResultSet =
401     struct
402       type t = int
403       type elt = [`Tree] Tree.node
404       let empty = 0
405       let cons _ x = x+1
406       let concat x y = x + y
407       let iter _ _ = failwith "iter not implemented"
408       let fold _ _ _ = failwith "fold not implemented"
409       let map _ _ = failwith "map not implemented"
410       let length x = x
411       let merge (rb,rb1,rb2,mark) t res1 res2 = 
412         if rb then
413           let res1 = if rb1 then res1 else 0
414           and res2 = if rb2 then res2 else 0
415           in
416             if mark then 1+res1+res2
417             else res1+res2
418         else 0
419     end
420
421     module IdSet : ResultSet = 
422     struct
423       type elt = [`Tree] Tree.node
424       type node = Nil 
425                   | Cons of elt * node 
426                   | Concat of node*node
427    
428       and t = { node : node;
429                 length :  int }
430
431       let empty = { node = Nil; length = 0 }
432         
433       let cons e t = { node = Cons(e,t.node); length = t.length+1 }
434       let concat t1 t2 = { node = Concat(t1.node,t2.node); length = t1.length+t2.length }
435       let append e t = { node = Concat(t.node,Cons(e,Nil)); length = t.length+1 } 
436         
437       let fold f l acc = 
438         let rec loop acc t = match t with
439           | Nil -> acc
440           | Cons (e,t) -> loop (f e acc) t
441           | Concat (t1,t2) -> loop (loop acc t1) t2
442         in
443           loop acc l.node
444             
445       let length l = l.length
446         
447         
448       let iter f l =
449         let rec loop = function
450           | Nil -> ()
451           | Cons (e,t) -> f e; loop t
452           | Concat(t1,t2) -> loop t1;loop t2
453         in loop l.node
454
455       let map f l =
456         let rec loop = function 
457           | Nil -> Nil
458           | Cons(e,t) -> Cons(f e, loop t)
459           | Concat(t1,t2) -> Concat(loop t1,loop t2)
460         in
461           { l with node = loop l.node }
462             
463       let merge (rb,rb1,rb2,mark) t res1 res2 = 
464         if rb then
465           let res1 = if rb1 then res1 else empty
466           and res2 = if rb2 then res2 else empty
467           in
468             if mark then { node = Cons(t,(Concat(res1.node,res2.node)));
469                            length = res1.length + res2.length + 1;}
470             else
471               { node = (Concat(res1.node,res2.node));
472                 length = res1.length + res2.length ;}
473         else empty        
474
475            
476     end
477     module GResult = struct
478       type t
479       type elt = [` Tree] Tree.node
480       external create_empty : int -> t = "caml_result_set_create"
481       external set : t -> int -> t = "caml_result_set_set"
482       external next : t -> int -> int = "caml_result_set_next"
483       external clear : t -> int -> int -> unit = "caml_result_set_clear"
484       let empty = create_empty 100000000
485         
486       let cons e t = set t (Obj.magic e)
487       let concat _ t = t
488       let iter f t =
489         let rec loop i = 
490           if i == -1 then ()
491           else (f (Obj.magic i);loop (next t i))
492         in loop 0
493           
494       let fold _ _ _ = failwith "noop"
495       let map _ _ = failwith "noop"
496       let length t = let cpt = ref ~-1 in
497       iter (fun _ -> incr cpt) t; !cpt
498       
499       let merge (rb,rb1,rb2,mark) elt t1 t2 =
500         if mark then (set t1 (Obj.magic elt) ; t1) else t1
501           
502     end
503     module Run (RS : ResultSet) =
504     struct
505
506       module SList = Hlist.Make (StateSet)
507
508
509
510 IFDEF DEBUG
511 THEN
512       module IntSet = Set.Make(struct type t = int let compare = (-) end)
513 INCLUDE "html_trace.ml"
514               
515 END             
516       let mk_fun f s = D_IGNORE_(register_funname f s,f)
517       let mk_app_fun f arg s = let g = f arg in 
518         D_IGNORE_(register_funname g ((get_funname f) ^ " " ^ s), g) 
519       let mk_app_fun2 f arg1 arg2 s = let g = f arg1 arg2 in 
520         D_IGNORE_(register_funname g ((get_funname f) ^ " " ^ s), g) 
521
522       let string_of_ts tags = (Ptset.Int.fold (fun t a -> a ^ " " ^ (Tag.to_string t) ) tags "{")^ " }"
523
524
525       module Algebra =
526         struct
527           type jump = [ `NIL | `ANY |`ANYNOTEXT | `JUMP ]
528           type t = jump*Ptset.Int.t*Ptset.Int.t
529           let jts = function 
530           | `JUMP -> "JUMP"
531           | `NIL -> "NIL"
532           | `ANY -> "ANY"
533           | `ANYNOTEXT -> "ANYNOTEXT"
534           let merge_jump (j1,c1,l1) (j2,c2,l2) = 
535             match j1,j2 with
536               | _,`NIL -> (j1,c1,l1)
537               | `NIL,_ -> (j2,c2,l2)
538               | `ANY,_ -> (`ANY,Ptset.Int.empty,Ptset.Int.empty)
539               | _,`ANY -> (`ANY,Ptset.Int.empty,Ptset.Int.empty)
540               | `ANYNOTEXT,_ -> 
541                   if Ptset.Int.mem Tag.pcdata (Ptset.Int.union c2 l2) then
542                   (`ANY,Ptset.Int.empty,Ptset.Int.empty)
543                   else
544                   (`ANYNOTEXT,Ptset.Int.empty,Ptset.Int.empty)
545               | _,`ANYNOTEXT -> 
546                   if Ptset.Int.mem Tag.pcdata (Ptset.Int.union c1 l1) then
547                   (`ANY,Ptset.Int.empty,Ptset.Int.empty)
548                   else
549                   (`ANYNOTEXT,Ptset.Int.empty,Ptset.Int.empty)
550               | `JUMP,`JUMP -> (`JUMP, Ptset.Int.union c1 c2,Ptset.Int.union l1 l2)
551
552           let merge_jump_list = function 
553             | [] -> `NIL,Ptset.Int.empty,Ptset.Int.empty
554             | p::r -> 
555                 List.fold_left (merge_jump) p r
556               
557           let labels a s = 
558             Hashtbl.fold 
559             (
560               fun q l acc -> 
561                 if (q == s)
562                 then 
563
564                   (List.fold_left 
565                       (fun acc (ts,f) ->
566                         let _,_,_,_,bur = Transition.node f in
567                         if bur then acc else TagSet.cup acc ts) 
568                     acc l)
569                 else acc ) a.trans TagSet.empty
570           exception Found
571             
572           let is_rec a s access = 
573             List.exists
574               (fun (_,t) -> let _,_,_,f,_ = Transition.node t in
575               StateSet.mem s ((fun (_,_,x) -> x) (access (Formula.st f)))) (Hashtbl.find a.trans s) 
576                      
577
578           let decide a c_label l_label dir_states dir =
579                         
580             let l = StateSet.fold 
581               (fun s l -> 
582                  let s_rec = is_rec a s (if dir then fst else snd) in
583                  let s_rec = if dir then s_rec else
584                  (* right move *)
585                  is_rec a s fst
586                  in
587                  let s_lab = labels a s in
588                  let jmp,cc,ll = 
589                    if (not (TagSet.is_finite s_lab)) then
590                    if TagSet.mem Tag.pcdata s_lab then  (`ANY,Ptset.Int.empty,Ptset.Int.empty)
591                    else (`ANYNOTEXT,Ptset.Int.empty,Ptset.Int.empty)
592                    else 
593                    if s_rec 
594                    then (`JUMP,Ptset.Int.empty, TagSet.positive 
595                            (TagSet.cap (TagSet.inj_positive l_label) s_lab))
596                    else (`JUMP,TagSet.positive 
597                            (TagSet.cap (TagSet.inj_positive c_label) s_lab),
598                          Ptset.Int.empty )
599                  in
600                    (if jmp != `ANY 
601                     && jmp != `ANYNOTEXT 
602                     && Ptset.Int.is_empty cc 
603                     && Ptset.Int.is_empty ll
604                     then (`NIL,Ptset.Int.empty,Ptset.Int.empty)
605                     else  (jmp,cc,ll))::l) dir_states []
606             in merge_jump_list l                            
607             
608               
609         end 
610
611
612
613       let choose_jump (d,cl,ll) f_nil f_t1 f_s1 f_tn f_sn f_s1n f_notext f_maytext =
614         match d with
615           | `NIL -> (`NIL,f_nil)
616           | `ANYNOTEXT -> `ANY,f_notext
617           | `ANY -> `ANY,f_maytext
618           | `JUMP -> 
619               if Ptset.Int.is_empty cl then
620               if Ptset.Int.is_singleton ll then
621               let tag = Ptset.Int.choose ll in 
622               (`TAG(tag),mk_app_fun f_tn tag (Tag.to_string tag))
623               else
624               (`MANY(ll),mk_app_fun f_sn ll (string_of_ts ll))
625               else if Ptset.Int.is_empty ll then
626               if Ptset.Int.is_singleton cl then
627               let tag = Ptset.Int.choose cl in 
628               (`TAG(tag),mk_app_fun f_t1 tag (Tag.to_string tag))
629               else
630               (`MANY(cl),mk_app_fun f_s1 cl (string_of_ts cl))
631               else
632               (`ANY,mk_app_fun2 f_s1n cl ll ((string_of_ts cl) ^ " " ^ (string_of_ts ll)))
633
634           | _ -> assert false
635           
636       let choose_jump_down tree d =
637         choose_jump d
638           (mk_fun (fun _ -> Tree.nil) "Tree.mk_nil")
639           (mk_fun (Tree.tagged_child tree) "Tree.tagged_child") 
640           (mk_fun (Tree.select_child tree) "Tree.select_child")
641           (mk_fun (Tree.tagged_desc tree) "Tree.tagged_desc")
642           (mk_fun (Tree.select_desc tree) "Tree.select_desc") 
643           (mk_fun (fun _ _ -> Tree.first_child tree) "[FIRSTCHILD]Tree.select_child_desc")
644           (mk_fun (Tree.first_element tree) "Tree.first_element")
645           (mk_fun (Tree.first_child tree) "Tree.first_child") 
646
647       let choose_jump_next tree d = 
648         choose_jump d
649           (mk_fun (fun _ _ -> Tree.nil) "Tree.mk_nil2")
650           (mk_fun (Tree.tagged_sibling_ctx tree) "Tree.tagged_sibling_ctx")
651           (mk_fun (Tree.select_sibling_ctx tree) "Tree.select_sibling_ctx")
652           (mk_fun (Tree.tagged_foll_ctx tree) "Tree.tagged_foll_ctx")
653           (mk_fun (Tree.select_foll_ctx tree) "Tree.select_foll_ctx")
654           (mk_fun (fun _ _ -> Tree.next_sibling_ctx tree) "[NEXTSIBLING]Tree.select_sibling_foll_ctx")
655           (mk_fun (Tree.next_element_ctx tree) "Tree.next_element_ctx")   
656           (mk_fun (Tree.next_sibling_ctx tree) "Tree.node_sibling_ctx")   
657                           
658           
659       module SListTable = Hashtbl.Make(struct type t = SList.t
660                                               let equal = (==)
661                                               let hash t = t.SList.Node.id 
662                                        end)
663       module TransCache = 
664       struct
665         type 'a t = Obj.t array SListTable.t
666         let create n = SListTable.create n
667         let dummy = Obj.repr (fun _ -> assert false)
668         let find (h :'a t) tag slist : 'a =
669           let tab = 
670             try
671               SListTable.find h slist
672             with
673                Not_found -> 
674                  SListTable.add h slist (Array.create 10000 dummy);
675                  raise Not_found
676           in
677           let res = tab.(tag) in
678           if res == dummy then raise Not_found else (Obj.magic res)
679
680         let add (h : 'a t) tag slist (data : 'a) =
681           let tab = 
682             try
683               SListTable.find h slist
684             with
685                Not_found -> 
686                  let arr = Array.create 10000 dummy in
687                  SListTable.add h slist arr;
688                  arr
689           in
690           tab.(tag) <- (Obj.repr data)
691           
692
693       end
694
695       let td_trans = TransCache.create 10000 (* should be number of tags *number of states^2
696                                                 in the document *)
697
698       let empty_size n =
699         let rec loop acc = function 0 -> acc
700           | n -> loop (SList.cons StateSet.empty acc) (n-1)
701         in loop SList.nil n
702              
703
704       module Fold2ResOld = Hashtbl.Make(struct 
705                                        type t = Formlistlist.t*SList.t*SList.t
706                                        let hash (f,s,t) = HASHINT3(f.Formlistlist.Node.id,
707                                                                    s.SList.Node.id,
708                                                                    t.SList.Node.id)
709                                        let equal (a,b,c) (d,e,f) = a==d && b == e && c == f
710                                      end)
711
712       module FllTable = Hashtbl.Make (struct type t = Formlistlist.t
713                                              let equal = (==)
714                                              let hash t = t.Formlistlist.Node.id
715                                       end)
716         
717       module Fold2Res =
718       struct
719         type 'a t = 'a SListTable.t SListTable.t FllTable.t
720         let create n = Array.init 10000 (fun _ -> FllTable.create n)
721
722         let find h tag fl s1 s2 =
723           let hf = h.(tag) in
724           let hs1 = FllTable.find hf fl in
725           let hs2 = SListTable.find hs1 s1 in
726           SListTable.find hs2 s2
727           
728         let add h tag fl s1 s2 data = 
729           let hf = h.(tag) in
730           let hs1 =
731             try FllTable.find hf fl with
732               | Not_found -> 
733                   let hs1 = SListTable.create SMALL_H_SIZE
734                   in FllTable.add hf fl hs1;hs1
735           in
736           let hs2 =
737             try SListTable.find hs1 s1
738             with
739               | Not_found ->
740                   let hs2 = SListTable.create SMALL_H_SIZE
741                   in SListTable.add hs1 s1 hs2;hs2
742           in
743           SListTable.add hs2 s2 data
744       end
745
746       let h_fold2 = Fold2Res.create SMALL_H_SIZE
747       
748       let top_down ?(noright=false) a tree t slist ctx slot_size =      
749         let pempty = empty_size slot_size in    
750         let rempty = Array.make slot_size RS.empty in
751         (* evaluation starts from the right so we put sl1,res1 at the end *)
752         let eval_fold2_slist fll t tag (sl2,res2) (sl1,res1) =
753           let res = Array.copy rempty in
754           try
755             let r,b,btab = Fold2Res.find h_fold2 tag fll sl1 sl2  in
756             if b then for i=0 to slot_size - 1 do
757               res.(i) <- RS.merge btab.(i) t res1.(i) res2.(i);
758             done;
759             r,res
760           with
761              Not_found ->
762                let btab = Array.make slot_size (false,false,false,false) in         
763                let rec fold l1 l2 fll i aq ab = 
764                  match fll.Formlistlist.Node.node,
765                    l1.SList.Node.node,
766                    l2.SList.Node.node
767                  with        
768                    | Formlistlist.Cons(fl,fll),
769                     SList.Cons(s1,ll1),
770                     SList.Cons(s2,ll2) ->
771                        let r',((b,_,_,_) as flags) = eval_formlist tag s1 s2 fl in
772                        let _ = btab.(i) <- flags
773                        in
774                        fold ll1 ll2 fll (i+1) (SList.cons r' aq) (b||ab)
775                    | _ -> aq,ab
776                in
777                let r,b = fold sl1 sl2 fll 0 SList.nil false in
778                Fold2Res.add h_fold2 tag fll sl1 sl2 (r,b,btab);
779                if b then for i=0 to slot_size - 1 do
780                  res.(i) <- RS.merge btab.(i) t res1.(i) res2.(i);
781                done;
782                r,res
783         in
784
785         let null_result = (pempty,Array.copy rempty) in
786         let rec loop t slist ctx =
787           if t == Tree.nil then null_result else get_trans t slist (Tree.tag tree t) ctx
788         and loop_tag tag t slist ctx =
789           if t == Tree.nil then null_result else get_trans t slist tag ctx
790         and loop_no_right t slist ctx = 
791           if t == Tree.nil then null_result else get_trans ~noright:true t slist (Tree.tag tree t) ctx
792         and get_trans ?(noright=false) t slist tag ctx = 
793           let cont = 
794             try
795               TransCache.find td_trans tag slist
796             with        
797               | Not_found ->
798                   let fl_list,llist,rlist,ca,da,sa,fa = 
799                     SList.fold 
800                       (fun set (fll_acc,lllacc,rllacc,ca,da,sa,fa) -> (* For each set *)
801                          let fl,ll,rr,ca,da,sa,fa = 
802                            StateSet.fold
803                              (fun q acc ->                          
804                                 List.fold_left 
805                                   (fun ((fl_acc,ll_acc,rl_acc,c_acc,d_acc,s_acc,f_acc) as acc) 
806                                      (ts,t)  ->
807                                        if (TagSet.mem tag ts)
808                                        then 
809                                          let _,_,_,f,_ = Transition.node t in
810                                          let (child,desc,below),(sibl,foll,after) = Formula.st f in
811                                            (Formlist.cons t fl_acc,
812                                             StateSet.union ll_acc below,
813                                             StateSet.union rl_acc after,
814                                             StateSet.union child c_acc,
815                                             StateSet.union desc d_acc,
816                                             StateSet.union sibl s_acc,
817                                             StateSet.union foll f_acc)           
818                                        else acc ) acc (
819                                     try Hashtbl.find a.trans q 
820                                     with
821                                         Not_found -> Printf.eprintf "Looking for state %i, doesn't exist!!!\n%!"
822                                           q;[]
823                                   )
824                                   
825                              ) set (Formlist.nil,StateSet.empty,StateSet.empty,ca,da,sa,fa)
826                          in (Formlistlist.cons fl fll_acc), (SList.cons ll lllacc), (SList.cons rr rllacc),ca,da,sa,fa)
827                       slist (Formlistlist.nil,SList.nil,SList.nil,StateSet.empty,StateSet.empty,StateSet.empty,StateSet.empty)
828                   in                    
829                     (* Logic to chose the first and next function *)
830                   let tags_child,tags_below,tags_siblings,tags_after = Tree.tags tree tag in
831                   let d_f = Algebra.decide a tags_child tags_below (StateSet.union ca da) true in
832                   let d_n = Algebra.decide a tags_siblings tags_after (StateSet.union sa fa) false in
833                   let f_kind,first = choose_jump_down tree d_f
834                   and n_kind,next = if noright then (`NIL, fun _ _ -> Tree.nil )
835                   else choose_jump_next tree d_n in
836                   let empty_res = null_result in
837                   let cont =
838                     match f_kind,n_kind with
839                       | `NIL,`NIL ->
840                           (fun t _ -> eval_fold2_slist fl_list t (Tree.tag tree t) empty_res empty_res)
841                       |  _,`NIL -> (
842                            match f_kind with
843                              |`TAG(tag') ->
844                                 (fun t _ -> eval_fold2_slist fl_list t (Tree.tag tree t) empty_res
845                                   (loop_tag tag' (first t) llist t ))
846                              | `ANY ->
847                                  (fun t _ -> eval_fold2_slist fl_list t (Tree.tag tree t) empty_res
848                                    (loop (first t) llist t ))
849                              | _ -> assert false)
850                       | `NIL,_ -> (
851                           match n_kind with
852                             |`TAG(tag') ->
853                                if SList.equal rlist slist && tag == tag' then
854                                let rec loop t ctx = 
855                                  if t == Tree.nil then empty_res else 
856                                  let res2 = loop (next t ctx) ctx in                               
857                                  eval_fold2_slist fl_list t tag res2 empty_res            
858                                in loop
859                                else
860                                (fun t ctx -> eval_fold2_slist fl_list t (Tree.tag tree t)
861                                  (loop_tag tag' (next t ctx) rlist ctx ) empty_res)
862                                                                                              
863                             | `ANY ->
864                                 (fun t ctx -> eval_fold2_slist fl_list t (Tree.tag tree t)
865                                    (loop (next t ctx) rlist ctx ) empty_res)
866                                   
867                             | _ -> assert false)
868                           
869                       | `TAG(tag1),`TAG(tag2) ->                          
870                           (fun t ctx ->
871                              eval_fold2_slist fl_list t (Tree.tag tree t)
872                                (loop_tag tag2 (next t ctx) rlist ctx )
873                                (loop_tag tag1 (first t) llist t ))
874  
875                       | `TAG(tag'),`ANY ->
876                           (fun t ctx ->
877                             eval_fold2_slist fl_list t (Tree.tag tree t)
878                               (loop (next t ctx) rlist ctx )
879                               (loop_tag tag' (first t) llist t ))
880                                                                            
881                       | `ANY,`TAG(tag') ->
882                           (fun t ctx ->
883                             eval_fold2_slist fl_list t (Tree.tag tree t)
884                               (loop_tag tag' (next t ctx) rlist ctx )
885                               (loop (first t) llist t ))
886                                                                    
887                       | `ANY,`ANY ->
888                           if SList.equal slist rlist && SList.equal slist llist
889                           then
890                           let rec loop t ctx = 
891                             if t == Tree.nil then empty_res else
892                             let r1 = loop (first t) t 
893                             and r2 = loop (next t ctx) ctx
894                             in
895                             eval_fold2_slist fl_list t (Tree.tag tree t) r2 r1
896                           in loop
897                           else 
898                           (fun t ctx ->
899                              eval_fold2_slist fl_list t (Tree.tag tree t)
900                                (loop (next t ctx) rlist ctx )
901                                (loop (first t) llist t ))
902                       | _,_ -> 
903                           (fun t ctx ->
904                              eval_fold2_slist fl_list t (Tree.tag tree t)
905                                (loop (next t ctx) rlist ctx )
906                                (loop (first t) llist t ))
907                       | _ -> assert false
908                   in
909                   let cont = D_IF_( (fun t ctx ->
910                                        let a,b = cont t ctx in
911                                        register_trace tree t (slist,a,fl_list,first,next,ctx);
912                                        (a,b)
913                                     ) ,cont)
914                   in
915                   (TransCache.add td_trans tag slist (Obj.repr cont) ;cont)
916           in (Obj.magic cont) t ctx
917                
918         in 
919           (if noright then loop_no_right else loop) t slist ctx
920
921         let run_top_down a tree =
922           let init = SList.cons a.init SList.nil in
923           let _,res = top_down a tree Tree.root init Tree.root 1 
924           in 
925             D_IGNORE_(
926               output_trace a tree "trace.html"
927                 (RS.fold (fun t a -> IntSet.add (Tree.id tree t) a) res.(0) IntSet.empty),
928               res.(0))
929         ;;
930
931         module Configuration =
932         struct
933           module Ptss = Set.Make(StateSet)
934           module IMap = Map.Make(StateSet)
935           type t = { hash : int;
936                         sets : Ptss.t;
937                         results : RS.t IMap.t }
938           let empty = { hash = 0;
939                         sets = Ptss.empty;
940                         results = IMap.empty;
941                       }
942           let is_empty c = Ptss.is_empty c.sets
943           let add c s r =
944             if Ptss.mem s c.sets then
945               { c with results = IMap.add s (RS.concat r (IMap.find s c.results)) c.results}
946             else
947               { hash = HASHINT2(c.hash,Ptset.Int.uid s);
948                 sets = Ptss.add s c.sets;
949                 results = IMap.add s r c.results
950               }
951
952           let pr fmt c = Format.fprintf fmt "{";
953             Ptss.iter (fun s -> StateSet.print fmt s;
954                         Format.fprintf fmt "  ") c.sets;
955             Format.fprintf fmt "}\n%!";
956             IMap.iter (fun k d -> 
957                          StateSet.print fmt k;
958                          Format.fprintf fmt "-> %i\n" (RS.length d)) c.results;                  
959             Format.fprintf fmt "\n%!"
960               
961           let merge c1 c2  =
962             let acc1 =
963               IMap.fold 
964                 ( fun s r acc ->
965                     IMap.add s
966                       (try 
967                          RS.concat r (IMap.find s acc)
968                        with
969                          | Not_found -> r) acc) c1.results IMap.empty 
970             in
971             let imap =
972                 IMap.fold (fun s r acc -> 
973                              IMap.add s
974                                (try 
975                                   RS.concat r (IMap.find s acc)
976                                 with
977                                   | Not_found -> r) acc)  c2.results acc1
978             in
979             let h,s =
980               Ptss.fold 
981                 (fun s (ah,ass) -> (HASHINT2(ah,Ptset.Int.uid s),
982                                     Ptss.add s ass))
983                 (Ptss.union c1.sets c2.sets) (0,Ptss.empty)
984             in
985               { hash = h;
986                 sets =s;
987                 results = imap }
988
989         end
990
991         let h_fold = Hashtbl.create 511 
992
993         let fold_f_conf  tree t slist fl_list conf dir= 
994           let tag = Tree.tag tree t in
995           let rec loop sl fl acc =
996             match SList.node sl,fl with
997               |SList.Nil,[] -> acc
998               |SList.Cons(s,sll), formlist::fll ->
999                  let r',(rb,rb1,rb2,mark) = 
1000                    let key = SList.hash sl,Formlist.hash formlist,dir in
1001                    try 
1002                      Hashtbl.find h_fold key
1003                    with
1004                       Not_found -> let res = 
1005                         if dir then eval_formlist tag s Ptset.Int.empty formlist
1006                         else eval_formlist tag Ptset.Int.empty s formlist 
1007                       in (Hashtbl.add h_fold key res;res)
1008                  in
1009                  if rb && ((dir&&rb1)|| ((not dir) && rb2))
1010                  then 
1011                  let acc = 
1012                    let old_r = 
1013                      try Configuration.IMap.find s conf.Configuration.results
1014                      with Not_found -> RS.empty
1015                    in
1016                    Configuration.add acc r' (if mark then RS.cons t old_r else old_r)                   
1017                  in
1018                  loop sll fll acc
1019                  else loop sll fll acc
1020               | _ -> assert false
1021           in
1022             loop slist fl_list Configuration.empty
1023
1024         let h_trans = Hashtbl.create 4096
1025
1026         let get_up_trans slist ptag a tree =      
1027           let key = (HASHINT2(SList.uid slist,ptag)) in
1028             try
1029           Hashtbl.find h_trans key              
1030           with
1031           | Not_found ->  
1032               let f_list =
1033                 Hashtbl.fold (fun q l acc ->
1034                                 List.fold_left (fun fl_acc (ts,t)  ->
1035                                                   if TagSet.mem ptag ts then Formlist.cons t fl_acc
1036                                                   else fl_acc)
1037                                   
1038                                   acc l)
1039                   a.trans Formlist.nil
1040               in
1041               let res = SList.fold (fun _ acc -> f_list::acc) slist [] 
1042               in
1043                 (Hashtbl.add h_trans key res;res) 
1044                   
1045
1046               
1047         let h_tdconf = Hashtbl.create 511 
1048         let rec bottom_up a tree t conf next jump_fun root dotd init accu = 
1049           if (not dotd) && (Configuration.is_empty conf ) then
1050           accu,conf,next 
1051           else
1052
1053           let below_right = Tree.is_below_right tree t next in 
1054           
1055           let accu,rightconf,next_of_next =         
1056             if below_right then (* jump to the next *)
1057             bottom_up a tree next conf (jump_fun next) jump_fun (Tree.next_sibling tree t) true init accu
1058             else accu,Configuration.empty,next
1059           in 
1060           let sub =
1061             if dotd then
1062             if below_right then prepare_topdown a tree t true
1063             else prepare_topdown a tree t false
1064             else conf
1065           in
1066           let conf,next =
1067             (Configuration.merge rightconf sub, next_of_next)
1068           in
1069           if t == root then  accu,conf,next else
1070           let parent = Tree.binary_parent tree t in
1071           let ptag = Tree.tag tree parent in
1072           let dir = Tree.is_left tree t in
1073           let slist = Configuration.Ptss.fold (fun e a -> SList.cons e a) conf.Configuration.sets SList.nil in
1074           let fl_list = get_up_trans slist ptag a parent in
1075           let slist = SList.rev (slist) in 
1076           let newconf = fold_f_conf tree parent slist fl_list conf dir in
1077           let accu,newconf = Configuration.IMap.fold (fun s res (ar,nc) ->
1078                                                         if Ptset.Int.intersect s init then
1079                                                           ( RS.concat res ar ,nc)
1080                                                         else (ar,Configuration.add nc s res))
1081             (newconf.Configuration.results) (accu,Configuration.empty) 
1082           in
1083
1084             bottom_up a tree parent newconf next jump_fun root false init accu
1085               
1086         and prepare_topdown a tree t noright =
1087           let tag = Tree.tag tree t in
1088           let r = 
1089             try
1090               Hashtbl.find h_tdconf tag
1091             with
1092               | Not_found -> 
1093                   let res = Hashtbl.fold (fun q l acc -> 
1094                                             if List.exists (fun (ts,_) -> TagSet.mem tag ts) l
1095                                             then Ptset.Int.add q acc
1096                                             else acc) a.trans Ptset.Int.empty
1097                   in Hashtbl.add h_tdconf tag res;res
1098           in 
1099 (*        let _ = pr ", among ";
1100             StateSet.print fmt (Ptset.Int.elements r);
1101             pr "\n%!";
1102           in *)
1103           let r = SList.cons r SList.nil in
1104           let set,res = top_down (~noright:noright) a tree t r t 1 in
1105           let set = match SList.node set with
1106             | SList.Cons(x,_) ->x
1107             | _ -> assert false 
1108           in
1109           Configuration.add Configuration.empty set res.(0) 
1110
1111
1112
1113         let run_bottom_up a tree k =
1114           let t = Tree.root in
1115           let trlist = Hashtbl.find a.trans (StateSet.choose a.init)
1116           in
1117           let init = List.fold_left 
1118             (fun acc (_,t) ->
1119                let _,_,_,f,_ = Transition.node t in 
1120                let _,_,l = fst ( Formula.st f ) in
1121                  StateSet.union acc l)
1122             StateSet.empty trlist
1123           in
1124           let tree1,jump_fun =
1125             match k with
1126               | `TAG (tag) -> 
1127                   (*Tree.tagged_lowest t tag, fun tree -> Tree.tagged_next tree tag*)
1128                   (Tree.tagged_desc tree tag t, let jump = Tree.tagged_foll_ctx tree tag
1129                   in fun n -> jump n t )
1130               | `CONTAINS(_) -> (Tree.text_below tree t,let jump = Tree.text_next tree 
1131                                  in fun n -> jump n t)
1132               | _ -> assert false
1133           in
1134           let tree2 = jump_fun tree1 in
1135           let rec loop t next acc = 
1136             let acc,conf,next_of_next = bottom_up a tree t
1137               Configuration.empty next jump_fun (Tree.root) true init acc
1138             in 
1139             let acc = Configuration.IMap.fold 
1140               ( fun s res acc -> if StateSet.intersect init s
1141                 then RS.concat res acc else acc) conf.Configuration.results acc
1142             in
1143               if Tree.is_nil next_of_next  (*|| Tree.equal next next_of_next *)then
1144                 acc
1145               else loop next_of_next (jump_fun next_of_next) acc
1146           in
1147           loop tree1 tree2 RS.empty
1148
1149
1150     end
1151           
1152     let top_down_count a t = let module RI = Run(Integer) in Integer.length (RI.run_top_down a t)
1153     let top_down a t = let module RI = Run(IdSet) in (RI.run_top_down a t)
1154     let bottom_up_count a t k = let module RI = Run(Integer) in Integer.length (RI.run_bottom_up a t k)
1155
1156