X-Git-Url: http://git.nguyen.vg/gitweb/?p=tatoo.git;a=blobdiff_plain;f=src%2Frun.ml;h=a39d8b43fda7e2d2c025dfb6fcf81cb9ec1ad6ec;hp=fb130845b476179b8db57ffe18f81d4508c586d9;hb=3b9dbcd9318dba41999dc6cc43093edbe5bc4c5d;hpb=4ce31bbf274a8f8ac9cba15c5339459865f2a741 diff --git a/src/run.ml b/src/run.ml index fb13084..a39d8b4 100644 --- a/src/run.ml +++ b/src/run.ml @@ -14,470 +14,200 @@ (***********************************************************************) INCLUDE "utils.ml" -open Format -open Misc +INCLUDE "debug.ml" -module Make (T : Tree.S) = - struct - - module NodeSummary = - struct - (* Pack into an integer the result of the is_* and has_ predicates - for a given node *) - type t = int - let dummy = -1 - (* - 4444444444443210 - 4 -> kind - 3 -> is_left - 2 -> is_right - 1 -> has_left - 0 -> has_right - *) - - let has_right (s : t) : bool = - Obj.magic (s land 1) - - let has_left (s : t) : bool = - Obj.magic ((s lsr 1) land 1) - - let is_right (s : t) : bool = - Obj.magic ((s lsr 2) land 1) - - let is_left (s : t) : bool = - Obj.magic ((s lsr 3) land 1) - - let kind (s : t) : Tree.NodeKind.t = - Obj.magic (s lsr 4) - - let make is_left is_right has_left has_right kind = - ((Obj.magic kind) lsl 4) lor - ((int_of_bool is_left) lsl 3) lor - ((int_of_bool is_right) lsl 2) lor - ((int_of_bool has_left) lsl 1) lor - (int_of_bool has_right) - - end - - type node_status = { - sat : StateSet.t; (* States that are satisfied at the current node *) - todo : StateSet.t; (* States that remain to be proven *) - (* For every node_status and automaton a: - a.states - (sat U todo) = unsat *) - summary : NodeSummary.t; (* Summary of the shape of the node *) - } -(* Describe what is kept at each node for a run *) - - module NodeStatus = - struct - include Hcons.Make(struct - type t = node_status - let equal c d = - c == d || - c.sat == d.sat && - c.todo == d.todo && - c.summary == d.summary - - let hash c = - HASHINT3((c.sat.StateSet.id :> int), - (c.todo.StateSet.id :> int), - c.summary) - end - ) - let print ppf s = - fprintf ppf - "{ sat: %a; todo: %a; summary: _ }" - StateSet.print s.node.sat - StateSet.print s.node.todo - end - - let dummy_status = - NodeStatus.make { sat = StateSet.empty; - todo = StateSet.empty; - summary = NodeSummary.dummy; - } - - - type run = { - tree : T.t ; - (* The argument of the run *) - auto : Ata.t; - (* The automaton to be run *) - status : NodeStatus.t array; - (* A mapping from node preorders to NodeStatus *) - unstable : Bitvector.t; - (* A bitvector remembering whether a subtree is stable *) - mutable redo : bool; - (* A boolean indicating whether the run is incomplete *) - mutable pass : int; - (* The number of times this run was updated *) - mutable cache2 : Ata.Formula.t Cache.N2.t; - (* A cache from states * label to list of transitions *) - mutable cache5 : NodeStatus.t Cache.N5.t; - } - - let pass r = r.pass - let stable r = not r.redo - let auto r = r.auto - let tree r = r.tree - - - let dummy_form = Ata.Formula.stay State.dummy - - let make auto tree = - let len = T.size tree in - { - tree = tree; - auto = auto; - status = Array.create len dummy_status; - unstable = Bitvector.create ~init:true len; - redo = true; - pass = 0; - cache2 = Cache.N2.create dummy_form; - cache5 = Cache.N5.create dummy_status; - } - - let get_status a i = - if i < 0 then dummy_status else Array.get a i - - let unsafe_get_status a i = - if i < 0 then dummy_status else Array.unsafe_get a i - -IFDEF HTMLTRACE - THEN -DEFINE TRACE(e) = (e) - ELSE -DEFINE TRACE(e) = () -END - - let html tree node i config msg = - let config = config.NodeStatus.node in - Html.trace (T.preorder tree node) i - "node: %i
%s
sat: %a
todo: %a
_______________________
" - (T.preorder tree node) - msg - StateSet.print config.sat - StateSet.print config.todo - - - let debug msg tree node i config = - let config = config.NodeStatus.node in - eprintf - "DEBUG:%s node: %i\nsat: %a\ntodo: %a\nround: %i\n" - msg - (T.preorder tree node) - StateSet.print config.sat - StateSet.print config.todo - i - - let get_form cache2 auto tag q = - let phi = - Cache.N2.find cache2 (tag.QName.id :> int) (q :> int) - in - if phi == dummy_form then - let phi = Ata.get_form auto tag q in - let () = - Cache.N2.add - cache2 - (tag.QName.id :> int) - (q :> int) phi - in phi - else phi - - type trivalent = False | True | Unknown - let of_bool = function false -> False | true -> True - let or_ t1 t2 = - match t1 with - False -> t2 - | True -> True - | Unknown -> if t2 == True then True else Unknown - - let and_ t1 t2 = - match t1 with - False -> False - | True -> t2 - | Unknown -> if t2 == False then False else Unknown - - (* Define as macros to get lazyness *) -DEFINE OR_(t1,t2) = - let __t1 = (t1) in - match t1 with - False -> (t2) - | True -> True - | Unknown -> if (t2) == True then True else Unknown - -DEFINE AND_(t1,t2) = - let __t1 = (t1) in - match t1 with - False -> False - | True -> (t2) - | Unknown -> if (t2) == False then False else Unknown - - - let eval_form phi fcs nss ps ss summary = - let open Ata in - let rec loop phi = - begin match Formula.expr phi with - | Boolean.False -> False - | Boolean.True -> True - | Boolean.Atom (a, b) -> - begin - let open NodeSummary in - match a.Atom.node with - | Move (m, q) -> - let { NodeStatus.node = n_sum; _ } as sum = - match m with - `First_child -> fcs - | `Next_sibling -> nss - | `Parent | `Previous_sibling -> ps - | `Stay -> ss - in - if sum == dummy_status || StateSet.mem q n_sum.todo then - Unknown - else - of_bool (b == StateSet.mem q n_sum.sat) - | Is_first_child -> of_bool (b == is_left summary) - | Is_next_sibling -> of_bool (b == is_right summary) - | Is k -> of_bool (b == (k == kind summary)) - | Has_first_child -> of_bool (b == has_left summary) - | Has_next_sibling -> of_bool (b == has_right summary) - end - | Boolean.And(phi1, phi2) -> AND_ (loop phi1, loop phi2) - | Boolean.Or (phi1, phi2) -> OR_ (loop phi1, loop phi2) - end - in - loop phi - - - let eval_trans_aux auto cache2 tag fcs nss ps old_status = - let { sat = old_sat; - todo = old_todo; - summary = old_summary } as os_node = old_status.NodeStatus.node - in - let sat, todo = - StateSet.fold (fun q ((a_sat, a_todo) as acc) -> - let phi = - get_form cache2 auto tag q - in - let v = eval_form phi fcs nss ps old_status old_summary in - match v with - True -> StateSet.add q a_sat, a_todo - | False -> acc - | Unknown -> a_sat, StateSet.add q a_todo - ) old_todo (old_sat, StateSet.empty) - in - if old_sat != sat || old_todo != todo then - NodeStatus.make { os_node with sat; todo } - else old_status - - let eval_trans auto cache2 cache5 tag fcs nss ps ss = - let rec loop old_status = - let new_status = - eval_trans_aux auto cache2 tag fcs nss ps old_status - in - if new_status == old_status then old_status else loop new_status - in - let fcsid = (fcs.NodeStatus.id :> int) in - let nssid = (nss.NodeStatus.id :> int) in - let psid = (ps.NodeStatus.id :> int) in - let ssid = (ss.NodeStatus.id :> int) in - let tagid = (tag.QName.id :> int) in - let res = Cache.N5.find cache5 tagid ssid fcsid nssid psid in - if res != dummy_status then res - else let new_status = loop ss in - Cache.N5.add cache5 tagid ssid fcsid nssid psid new_status; - new_status - - - - let top_down run = - let _i = run.pass in - let tree = run.tree in - let auto = run.auto in - let status = run.status in - let cache2 = run.cache2 in - let cache5 = run.cache5 in - let unstable = run.unstable in - let init_todo = StateSet.diff (Ata.get_states auto) (Ata.get_starting_states auto) in - let rec loop node = - let node_id = T.preorder tree node in - if node == T.nil || not (Bitvector.get unstable node_id) then false else begin - let parent = T.parent tree node in - let fc = T.first_child tree node in - let fc_id = T.preorder tree fc in - let ns = T.next_sibling tree node in - let ns_id = T.preorder tree ns in - let tag = T.tag tree node in - (* We enter the node from its parent *) - - let status0 = - let c = unsafe_get_status status node_id in - if c == dummy_status then - (* first time we visit the node *) - NodeStatus.make - { sat = StateSet.empty; - todo = init_todo; - summary = NodeSummary.make - (node == T.first_child tree parent) (* is_left *) - (node == T.next_sibling tree parent) (* is_right *) - (fc != T.nil) (* has_left *) - (ns != T.nil) (* has_right *) - (T.kind tree node) (* kind *) - } - else c - in - TRACE(html tree node _i status0 "Entering node"); - - (* get the node_statuses for the first child, next sibling and parent *) - let ps = unsafe_get_status status (T.preorder tree parent) in - let fcs = unsafe_get_status status fc_id in - let nss = unsafe_get_status status ns_id in - (* evaluate the transitions with all this statuses *) - let status1 = if status0.NodeStatus.node.todo == StateSet.empty then status0 else begin - let status1 = eval_trans auto cache2 cache5 tag fcs nss ps status0 in - TRACE(html tree node _i status1 "Updating transitions"); - (* update the cache if the status of the node changed *) - if status1 != status0 then status.(node_id) <- status1; - status1 - end - in - (* recursively traverse the first child *) - let unstable_left = loop fc in - (* here we re-enter the node from its first child, - get the new status of the first child *) - let fcs1 = unsafe_get_status status fc_id in - (* update the status *) - let status2 = if status1.NodeStatus.node.todo == StateSet.empty then status1 else begin - let status2 = eval_trans auto cache2 cache5 tag fcs1 nss ps status1 in - TRACE(html tree node _i status2 "Updating transitions (after first-child)"); - if status2 != status1 then status.(node_id) <- status2; - status2 - end - in - let unstable_right = loop ns in - let nss1 = unsafe_get_status status ns_id in - let status3 = if status2.NodeStatus.node.todo == StateSet.empty then status2 else begin - let status3 = eval_trans auto cache2 cache5 tag fcs1 nss1 ps status2 in - TRACE(html tree node _i status3 "Updating transitions (after next-sibling)"); - if status3 != status2 then status.(node_id) <- status3; - status3 - end - in - let unstable_self = - (* if either our left or right child is unstable or if we still have transitions - pending, the current node is unstable *) - unstable_left - || unstable_right - || StateSet.empty != status3.NodeStatus.node.todo - in - Bitvector.unsafe_set unstable node_id unstable_self; - TRACE((if not unstable_self then - Html.finalize_node - node_id - _i - Ata.(StateSet.intersect status3.NodeStatus.node.sat (get_selecting_states auto)))); - unstable_self - end +module Make (T : Tree.S) = +struct + + let eval_form phi tree node fcs nss pars selfs = + let rec loop phi = + let open Boolean in + match Ata.Formula.expr phi with + False -> false + | True -> true + | Or (phi1, phi2) -> loop phi1 || loop phi2 + | And (phi1, phi2) -> loop phi1 && loop phi2 + | Atom (a, b) -> b == Ata.( + match Atom.node a with + Is_first_child -> let par = T.parent tree node in + (T.first_child tree par) == node + | Is_next_sibling -> let par = T.parent tree node in + (T.next_sibling tree par) == node + | Is k -> k == T.kind tree node + | Has_first_child -> T.nil != T.first_child tree node + | Has_next_sibling -> T.nil != T.next_sibling tree node + | Move (m, q) -> + let set = + match m with + `First_child -> fcs + | `Next_sibling -> nss + | `Parent + | `Previous_sibling -> pars + | `Stay -> selfs + in + StateSet.mem q set + ) in - run.redo <- loop (T.root tree); - run.pass <- run.pass + 1 - - - let get_results run = - let cache = run.status in - let auto = run.auto in - let tree = run.tree in - let rec loop node acc = - if node == T.nil then acc + loop phi + + + let eval_trans_aux trans tree node fcs nss pars selfs = + let open Ata in + TransList.fold (fun trs acc -> + let q, _ , phi = Transition.node trs in + let res = eval_form phi tree node fcs nss pars selfs in + if false then begin + Format.eprintf "Formula %a evaluates to %b with context: (fcs=%a, nss=%a, pars=%a, olds=%a) @\n@." + Formula.print phi res + StateSet.print fcs + StateSet.print nss + StateSet.print pars + StateSet.print selfs + end; + if res then + StateSet.add q acc else - let acc0 = loop (T.next_sibling tree node) acc in - let acc1 = loop (T.first_child tree node) acc0 in - - if Ata.( - StateSet.intersect - cache.(T.preorder tree node).NodeStatus.node.sat - (get_selecting_states auto)) then node::acc1 - else acc1 + acc) trans selfs + + let eval_trans trans tree node fcs nss pars sstates = + let rec loop olds = + + let news = eval_trans_aux trans tree node fcs nss pars olds in + if false then begin + Format.eprintf "Saturating formula: olds=%a, news=%a@\n@." + StateSet.print olds + StateSet.print news + end; + if news == olds then olds else + loop news in - loop (T.root tree) [] - - - let get_full_results run = - let cache = run.status in - let auto = run.auto in - let tree = run.tree in - let res_mapper = Hashtbl.create MED_H_SIZE in - let () = - StateSet.iter - (fun q -> Hashtbl.add res_mapper q []) - (Ata.get_selecting_states auto) - in - let dummy = [ T.nil ] in - let res_mapper = Cache.N1.create dummy in - let () = - StateSet.iter - (fun q -> Cache.N1.add res_mapper (q :> int) []) - (Ata.get_selecting_states auto) - in - let rec loop node = - if node != T.nil then - let () = loop (T.next_sibling tree node) in - let () = loop (T.first_child tree node) in - StateSet.iter - (fun q -> - let res = Cache.N1.find res_mapper (q :> int) in - if res != dummy then - Cache.N1.add res_mapper (q :> int) (node::res) - ) - cache.(T.preorder tree node).NodeStatus.node.sat + let r = loop sstates in + if false then begin + Format.eprintf "Evaluating transitions (fcs=%a, nss=%a, pars=%a, olds=%a):@\n\t%a@." + StateSet.print fcs + StateSet.print nss + StateSet.print pars + StateSet.print sstates + (Ata.TransList.print ~sep:"\n\t") trans; + Format.eprintf "Got %a@\n@." StateSet.print r; + end; + r + + + let auto_run auto tree prev_nodes td_states bu_states exit_states _i = + if false then + Format.eprintf "Doing a td (with states: %a) and a bu (with states: %a), exit states are: %a @\n@." + StateSet.print td_states + StateSet.print bu_states + StateSet.print exit_states; + let rec loop res node parset = + if node == T.nil then StateSet.empty else begin + let set,lset,rset = + if Sequence.is_empty prev_nodes then + StateSet.(empty,empty,empty) + else + let set,lset,rset, node' = Sequence.peek prev_nodes in + if node == node' then begin + ignore (Sequence.pop prev_nodes); + set,lset,rset + end + else + StateSet.(empty,empty,empty) + in + let tag = T.tag tree node in + let td_trans = Ata.get_trans auto tag td_states in + let status1 = eval_trans td_trans tree node lset rset parset set in + let fcs = loop res (T.first_child tree node) status1 in + let rres = Sequence.create () in + let nss = loop rres (T.next_sibling tree node) status1 in + let bu_trans = Ata.get_trans auto tag bu_states in + let status2 = eval_trans bu_trans tree node fcs nss parset status1 in + let mstates = StateSet.inter status2 exit_states in + if false then begin + Format.eprintf "On node %i (tag : %a) status0 = %a, status1 = %a, fcs = %a, nss = %a, par = %a, status2 = %a, mstates = %a@\n@." + (T.preorder tree node) + QName.print tag + StateSet.print set + StateSet.print status1 + StateSet.print fcs + StateSet.print nss + StateSet.print parset + StateSet.print status2 + StateSet.print mstates; + end; + if mstates != StateSet.empty then + Sequence.push_front (mstates, + StateSet.inter exit_states fcs, + StateSet.inter exit_states nss, node) res; + Sequence.append res rres; + status2 + end in - loop (T.root tree); - (StateSet.fold_right - (fun q acc -> (q, Cache.N1.find res_mapper (q :> int))::acc) - (Ata.get_selecting_states auto) []) - - - let prepare_run run list = - let tree = run.tree in - let auto = run.auto in - let status = run.status in - List.iter (fun node -> - let parent = T.parent tree node in - let fc = T.first_child tree node in - let ns = T.next_sibling tree node in - let status0 = - NodeStatus.make - { sat = Ata.get_starting_states auto; - todo = - StateSet.diff (Ata.get_states auto) (Ata.get_starting_states auto); - summary = NodeSummary.make - (node == T.first_child tree parent) (* is_left *) - (node == T.next_sibling tree parent) (* is_right *) - (fc != T.nil) (* has_left *) - (ns != T.nil) (* has_right *) - (T.kind tree node) (* kind *) - } - in - let node_id = T.preorder tree node in - status.(node_id) <- status0) list - + let res = Sequence.create () in + ignore (loop res (T.root tree) StateSet.empty); + if false then Format.eprintf "Finished pass: %i @\n-----------------------@\n@." _i; + res + + + + let prepare_run auto l = + let res = Sequence.create () in + let start = Ata.get_starting_states auto in + Sequence.iter (fun n -> Sequence.push_back (start, StateSet.empty, StateSet.empty, n) res) l; + res + + + let main_eval auto tree nodes = + let s_nodes = prepare_run auto nodes in + + let ranked_states = Ata.get_states_by_rank auto in + let acc = ref s_nodes in + let max_rank = Ata.get_max_rank auto in + for i = 0 to max_rank do + let open Ata in + let { td; bu; exit } = ranked_states.(i) in + acc := auto_run auto tree !acc td bu exit i; + if false then begin + Format.eprintf "Intermediate result is: @\n"; + Sequence.iter (fun (s,_,_, n) -> + Format.eprintf "{%a, %i (%a)} " + StateSet.print s + (T.preorder tree n) + QName.print (T.tag tree n)) !acc; + Format.eprintf "@\n@."; + end - let compute_run auto tree nodes = - let run = make auto tree in - prepare_run run nodes; - while run.redo do - top_down run done; - TRACE(Html.gen_trace auto (module T : Tree.S with type t = T.t) tree); - run - - let full_eval auto tree nodes = - let r = compute_run auto tree nodes in - get_full_results r + !acc let eval auto tree nodes = - let r = compute_run auto tree nodes in - get_results r + let res = main_eval auto tree nodes in + let r = Sequence.create () in + Sequence.iter (fun (_,_,_, n) -> Sequence.push_back n r) res; + r + + let full_eval auto tree nodes = + let res = main_eval auto tree nodes in + let dummy = Sequence.create () in + let cache = Cache.N1.create dummy in + Sequence.iter (fun (set, _, _, n) -> + StateSet.iter (fun q -> + let qres = Cache.N1.find cache q in + let qres = + if qres == dummy then begin + let s = Sequence.create () in + Cache.N1.add cache q s; + s + end + else qres + in + Sequence.push_back n qres) set ) + res; + let l = StateSet.fold (fun q acc -> + let res = Cache.N1.find cache q in + (q, res) :: acc) (Ata.get_selecting_states auto) [] + in + List.rev l end