(***********************************************************************) (* *) (* TAToo *) (* *) (* Kim Nguyen, LRI UMR8623 *) (* Université Paris-Sud & CNRS *) (* *) (* Copyright 2010-2013 Université Paris-Sud and Centre National de la *) (* Recherche Scientifique. All rights reserved. This file is *) (* distributed under the terms of the GNU Lesser General Public *) (* License, with the special exception on linking described in file *) (* ../LICENSE. *) (* *) (***********************************************************************) (* Time-stamp: *) INCLUDE "utils.ml" open Format open Utils module Make (T : Tree.Sig.S) : sig val eval : Ata.t -> T.t -> T.node -> T.node list end = struct type cache = StateSet.t Cache.N1.t let get c t n = Cache.N1.find c (T.preorder t n) let set c t n v = Cache.N1.add c (T.preorder t n) v module Info = struct type t = { is_left : bool; is_right : bool; has_left : bool; has_right : bool; kind : Tree.Common.NodeKind.t; } let equal a b = a = b let hash a = Hashtbl.hash a end module NodeInfo = Hcons.Make(Info) let eval_form phi node_info fcs nss ps ss = let open NodeInfo in let open Info in let rec loop phi = begin match Ata.SFormula.expr phi with Formula.True -> true | Formula.False -> false | Formula.Atom a -> let p, b, q = Ata.Atom.node a in let pos = let open Ata in match p with | First_child -> StateSet.mem q fcs | Next_sibling -> StateSet.mem q nss | Parent | Previous_sibling -> StateSet.mem q ps | Stay -> StateSet.mem q ss | Is_first_child -> node_info.node.is_left | Is_next_sibling -> node_info.node.is_right | Is k -> k == node_info.node.kind | Has_first_child -> node_info.node.has_left | Has_next_sibling -> node_info.node.has_right in if Ata.is_move p && (not b) then eprintf "Warning: Invalid negative atom %a" Ata.Atom.print a; b == pos | Formula.And(phi1, phi2) -> loop phi1 && loop phi2 | Formula.Or (phi1, phi2) -> loop phi1 || loop phi2 end in loop phi let eval_trans cache ltrs node_info fcs nss ps ss = let j = (node_info.NodeInfo.id :> int) and k = (fcs.StateSet.id :> int) and l = (nss.StateSet.id :> int) and m = (ps.StateSet.id :> int) in let rec loop ltrs ss = let i = (ltrs.Ata.TransList.id :> int) and n = (ss.StateSet.id :> int) in let (new_ltrs, new_ss) as res = let res = Cache.N6.find cache i j k l m n in if res == Cache.N6.dummy cache then let res = Ata.TransList.fold (fun trs (acct, accs) -> let q, _, phi = Ata.Transition.node trs in if StateSet.mem q accs then (acct, accs) else if eval_form phi node_info fcs nss ps accs then (acct, StateSet.add q accs) else (Ata.TransList.cons trs acct, accs) ) ltrs (Ata.TransList.nil, ss) in Cache.N6.add cache i j k l m n res; res else res in if new_ss == ss then res else loop new_ltrs new_ss in loop ltrs ss let top_down_run auto tree node cache trans_cache2 trans_cache6 _i = let redo = ref false in let rec loop node = if node != T.nil then begin let parent = T.parent tree node in let fc = T.first_child tree node in let ns = T.next_sibling tree node in let tag = T.tag tree node in let states0 = get cache tree node in let trans0 = let trs = Cache.N2.find trans_cache2 (tag.QName.id :> int) (auto.Ata.states.StateSet.id :> int) in if trs == Cache.N2.dummy trans_cache2 then let trs = Ata.get_trans auto auto.Ata.states tag in (Cache.N2.add trans_cache2 (tag.QName.id :> int) (auto.Ata.states.StateSet.id :> int) trs; trs) else trs in let ps = get cache tree parent in let fcs = get cache tree fc in let nss = get cache tree ns in let node_info = NodeInfo.make (Info.({ is_left = node == T.first_child tree parent; is_right = node == T.next_sibling tree parent; has_left = fc != T.nil; has_right = ns != T.nil; kind = T.kind tree node })) in let trans1, states1 = eval_trans trans_cache6 trans0 node_info fcs nss ps states0 in if states1 != states0 then set cache tree node states1; let () = loop fc in let fcs1 = get cache tree fc in let trans2, states2 = eval_trans trans_cache6 trans1 node_info fcs1 nss ps states1 in if states2 != states1 then set cache tree node states2; let () = loop ns in let _, states3 = eval_trans trans_cache6 trans2 node_info fcs1 (get cache tree ns) ps states2 in if states3 != states2 then set cache tree node states3; if states0 != states3 && (not !redo) then redo := true end in loop node; !redo let get_results auto tree node cache = let rec loop node acc = if node == T.nil then acc else let acc0 = loop (T.next_sibling tree node) acc in let acc1 = loop (T.first_child tree node) acc0 in if StateSet.intersect (get cache tree node) auto.Ata.selection_states then node::acc1 else acc1 in loop node [] let eval auto tree node = let cache = Cache.N1.create (T.size tree) StateSet.empty in let redo = ref true in let iter = ref 0 in let dummy2 = Ata.TransList.cons (Ata.Transition.make (State.dummy,QNameSet.empty, Ata.SFormula.false_)) Ata.TransList.nil in let dummy6 = (dummy2, StateSet.empty) in let trans_cache6 = Cache.N6.create 17 dummy6 in let trans_cache2 = Cache.N2.create 17 dummy2 in let () = at_exit (fun () -> let num_phi = ref 0 in let num_trans = ref 0 in Cache.N6.iteri (fun _ _ _ _ _ _ _ b -> if not b then incr num_phi) trans_cache6; Cache.N2.iteri (fun _ _ _ b -> if not b then incr num_trans) trans_cache2; Format.eprintf "PROFILE:materialized %i transitions and %i configurations\n@." !num_trans !num_phi ) in while !redo do redo := top_down_run auto tree node cache trans_cache2 trans_cache6 !iter; incr iter; done; get_results auto tree node cache end