(* Time-stamp: <modified the 07/06/2019 (at 17:37) by Erwan Jahier> *) open Algo open Sasacore let (update_env_with_init : Env.t -> Process.t list -> Env.t) = fun e pl -> let (aux: Env.t -> Process.t -> Env.t) = fun e p -> Env.set e p.pid p.init in List.fold_left aux e pl (** Returns the channel number that let [p_neighbor] access to the content of [p], if [p] is a neighbor of [p_neighbor]. Returns -1 if [p] is not a neigbhbor of [p_neigbor], which can happen in directed graphs. *) let (reply: Topology.t -> string -> string -> int) = fun g p p_neighbor -> let rec f i = function | [] -> (-1) (* may happen in directed graphs *) | x::t -> if x=p then i else f (i+1) t in f 0 (g.succ p_neighbor) let (get_neighors: Topology.t -> Env.t -> Topology.node_id -> Algo.neighbor list) = fun g e source_id -> let idl = g.succ source_id in List.map (fun neighbor_id -> let node = g.of_id neighbor_id in let algo_id = Filename.chop_suffix node.file ".ml" in let vars = Algo.get_vars algo_id in { lenv= Env.get_copy vars e node.id; n_vars = vars; (* XXX For the 2 fields above, check the graph kind (anonymous, identified, etc. *) pid = (fun () -> node.id); reply = (fun () -> reply g source_id neighbor_id); } ) idl let (dump_process: Process.t * Algo.neighbor list -> unit) = fun (p,nl) -> let pvars = StringOf.algo_vars p.variables in let neighbors = List.map StringOf.algo_neighbor nl in Printf.printf "process %s\n\tvars:%s\n\tneighors: \n\t\t%s\n" p.pid pvars (String.concat "\n\t\t" neighbors) open Process let _string_of_local_env p lenv = List.fold_left (fun acc (n,_) -> Printf.sprintf "%s %s=%s" acc n (Algo.value_to_string (lenv n))) "" p.variables let (update_env: Env.t -> Process.t * Algo.local_env -> Env.t) = fun e (p, lenv) -> Env.set e p.pid lenv open SasArg let (update_neighbor_env: Env.t -> Algo.neighbor -> Algo.neighbor) = fun e n -> { n with lenv= Env.get_copy n.Algo.n_vars e (n.Algo.pid ())} type layout = (Process.t * Algo.neighbor list) list type enable_processes = (Process.t * Algo.neighbor list * Algo.action) list list * bool list list let (get_enable_processes: layout -> Env.t -> enable_processes) = fun pl_n e -> let all = List.fold_left (fun acc (p,nl) -> let nl4algo = List.map (update_neighbor_env e) nl in let lenv = Env.get e p.pid in let al = p.enable nl4algo lenv in let al = List.map (fun a -> p,nl,a) al in al::acc) [] pl_n in assert (List.length pl_n = List.length all); let all = List.rev all in let enab_ll = List.map2 (fun (p,_) al -> let al = List.map (fun (_,_,a) -> a) al in List.map (fun a_static -> List.mem a_static al) p.actions) pl_n all in all, enab_ll let (do_step : (Process.t * Algo.neighbor list * action) list -> Env.t -> Env.t) = fun pnal e -> let lenv_list = List.map (fun (p,nl,a) -> let nl4algo = List.map (update_neighbor_env e) nl in let lenv = Env.get e p.pid in p, p.step nl4algo lenv a) pnal in (* 4: update the env *) let ne = List.fold_left update_env e lenv_list in ne type t = SasArg.t * layout * Env.t let (get_inputs_rif_decl: SasArg.t -> Process.t list -> (string * string) list) = fun args pl -> if args.demon <> Custom then if args.dummy_input then ["_dummy","bool"] else [] else let f p = List.map (fun a -> p.pid ^(if a="" then "" else "_")^a ,"bool") p.actions in List.flatten (List.map f pl) let (get_outputs_rif_decl: SasArg.t -> Process.t list -> (string * string) list) = fun args pl -> let lll = List.map (fun p -> List.map (fun (n,vt) -> Algo.vart_to_rif_decl vt (Printf.sprintf "%s_%s" p.pid n)) p.variables) pl in let algo_vars = List.flatten (List.flatten lll) in let action_vars_enab = List.flatten (List.map (fun p -> List.map (fun a -> (Printf.sprintf "Enab_%s_%s" p.pid a),"bool") p.actions) pl) in let action_vars = if args.demon = Custom then [] else List.flatten (List.map (fun p -> List.map (fun a -> (Printf.sprintf "%s_%s" p.pid a),"bool") p.actions) pl) in algo_vars @ action_vars_enab @ action_vars let (env_rif_decl: SasArg.t -> Process.t list -> string) = fun args pl -> let ssl = get_outputs_rif_decl args pl in String.concat " " (List.map (fun (base, tstr) -> Printf.sprintf "\"%s\":%s" base tstr) ssl) let (make : bool -> string array -> t) = fun dynlink argv -> let args = try SasArg.parse argv; with Failure(e) -> output_string stdout e; flush stdout ; exit 2 | e -> output_string stdout (Printexc.to_string e); flush stdout; exit 2 in try let dot_file = args.topo in let g = Topology.read dot_file in let nl = g.nodes in let pidl = List.map (fun n -> n.Topology.id) nl in let nstr = String.concat "," pidl in Algo.set_card (List.length nl); Algo.verbose_level := args.verbose; Random.init args.seed; if !Algo.verbose_level > 0 then Printf.eprintf "nodes: %s\nedges:\n" nstr; let algo_files = List.map (fun n -> n.Topology.file) nl in if dynlink then List.iter Process.dynlink_nodes (List.sort_uniq compare algo_files); let e = Env.init () in let algo_neighors = List.map (get_neighors g e) pidl in let pl = List.map2 (Process.make (args.demon=Custom)) nl algo_neighors in let e = update_env_with_init e pl in let pl_n = List.combine pl algo_neighors in if !Algo.verbose_level > 0 then List.iter dump_process pl_n; if args.output_algos then ( let fl = List.map (fun n -> Filename.chop_extension n.Topology.file) nl in let fl = List.sort_uniq compare fl in Printf.printf "%s\n" (String.concat "\n" fl); flush stdout; exit 0 ); if args.gen_lutin then ( let fn = (Filename.remove_extension args.topo) ^ ".lut" in if Sys.file_exists fn then ( Printf.eprintf "%s already exists: rename it to proceed.\n" fn; flush stderr; exit 1 ) else let oc = open_out fn in Printf.fprintf oc "%s" (GenLutin.f pl); flush oc; close_out oc; exit 0); if args.rif then ( Printf.printf "%s" (Mypervasives.entete "#" SasaVersion.str SasaVersion.sha); if args.demon <> Demon.Custom then Printf.printf "#seed %i\n" args.seed; let inputs_decl = get_inputs_rif_decl args pl in Printf.printf "#inputs %s\n" (String.concat " " (List.map (fun (vn,vt) -> Printf.sprintf "\"%s\":%s" vn vt) inputs_decl)); Printf.printf "#outputs %s\n" (env_rif_decl args pl); flush stdout ) else ( if args.demon <> Demon.Custom then ( Printf.printf "The pseudo-random engine is used with seed %i\n" args.seed; flush stdout ); ); if args.ifi then ( List.iter (fun p -> List.iter (fun a -> ignore (RifRead.bool (args.verbose>1) p.pid a)) p.actions) pl; Printf.eprintf "Ignoring the first vectors of sasa inputs\n"; flush stderr; ); args, pl_n, e with | Dynlink.Error e -> Printf.printf "Error: %s\n" (Dynlink.error_message e); flush stdout; exit 2 | e -> Printf.printf "Error: %s\n" (Printexc.to_string e); flush stdout; exit 2