From c47c5261a13dde27510fddb406be67632e7e78de Mon Sep 17 00:00:00 2001
From: Erwan Jahier <erwan.jahier@univ-grenoble-alpes.fr>
Date: Mon, 7 Jun 2021 15:03:44 +0200
Subject: [PATCH] Update: use the new RdbgStdLib.rev_cond_gen to round
 backwards (rdbg > 1.195.0)

---
 lib/sasacore/dune                 |   4 +-
 tools/rdbg4sasa/gtkgui.ml         | 141 +++++---
 tools/rdbg4sasa/sasa-rdbg-cmds.ml | 522 +++++++++++++++++-------------
 3 files changed, 387 insertions(+), 280 deletions(-)

diff --git a/lib/sasacore/dune b/lib/sasacore/dune
index 0c19b2d1..c3e52b8e 100644
--- a/lib/sasacore/dune
+++ b/lib/sasacore/dune
@@ -1,10 +1,10 @@
-;; Time-stamp: <modified the 02/05/2021 (at 13:38) by Erwan Jahier>
+;; Time-stamp: <modified the 09/06/2021 (at 15:07) by Erwan Jahier>
 
 (library
  (name     sasacore)
  (public_name  sasacore)
  (libraries dynlink ocamlgraph lutils)
- (flags -noassert)
+ ; (flags -noassert)
   ;; 
 ; (wrapped false)
  (library_flags -linkall)
diff --git a/tools/rdbg4sasa/gtkgui.ml b/tools/rdbg4sasa/gtkgui.ml
index eb21ff64..6e7810fd 100644
--- a/tools/rdbg4sasa/gtkgui.ml
+++ b/tools/rdbg4sasa/gtkgui.ml
@@ -1,4 +1,4 @@
-(* Time-stamp: <modified the 03/06/2021 (at 14:35) by Erwan Jahier> *)
+(* Time-stamp: <modified the 10/06/2021 (at 18:29) by Erwan Jahier> *)
 
 #thread
 #require "lablgtk3"
@@ -118,7 +118,8 @@ let display_event b =
 let custom_mode_ref = ref custom_mode
   
 (*  *)
-let goto_hook_call e =
+
+let goto_hook_call  e =
   if !custom_mode_ref then
     next_cond e (fun e -> e.name = "mv_hook" && e.kind = Call)
   else
@@ -135,7 +136,7 @@ let goto_top e =
     next_cond e (fun e -> e.kind = Ltop)
   else
     e
-
+  
 let init_rdbg_hook () =
   let guidaemon sl =
     if sl = [] then
@@ -149,7 +150,9 @@ let init_rdbg_hook () =
       in
       Some res
     else 
-      let sl = List.filter (fun (n,v) -> String.length n > 5 && String.sub n 0 5 = "Enab_") sl in
+      let sl = List.filter
+                 (fun (n,v) -> String.length n>5 && String.sub n 0 5 = "Enab_") sl
+      in
       let res = List.map (fun (n,enabled) ->
           (* n est de la forme Enab_node_state, enabled est un Data.v *)
           let str = String.sub n 5 ((String.length n)-5) in
@@ -186,8 +189,29 @@ let init_rdbg_hook () =
        
 let set_tooltip b = b#misc#set_tooltip_text 
 
-
-let custom_daemon p gtext vbox step_button back_step_button round_button legitimate_button =
+let start () =
+  if args.salut_mode then
+    (* In  this mode, the hook  plays first to provide  fake values to
+       sasa but the hook does not need input at this first step *)
+    e:=goto_hook_exit !e;
+  if !custom_mode_ref then e := goto_hook_call !e;
+  redos := [!e.nb];
+  ckpt_list := [!e];
+  !e.save_state !e.nb
+
+let restart p _ =
+  let seed = Seed.get dotfile in
+  Seed.set seed;
+  p (Printf.sprintf "Restarting using the seed %d" seed);
+  !e.RdbgEvent.reset();
+  e:=RdbgStdLib.run ~call_hooks:true ();
+  round_reset ();
+  start ();
+  d()
+
+
+let custom_daemon p gtext vbox step_button back_step_button round_button
+      legitimate_button undo_button =
   (* création du rdbg_mv_hook et de tout ce qu'il faut autour *)
   init_rdbg_hook ();
   
@@ -210,21 +234,18 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
   set_tooltip dk_manual (Printf.sprintf "Set the manual mode");
   set_tooltip dk_manual_central (Printf.sprintf "Set the manual central mode");
 
-  (* Necessary for salut (to perform a fake step that let sasa provide
-     the first set of enables) *)
-  if args.salut_mode then e := goto_hook_exit !e;
-  e := goto_hook_call !e;
+  start ();
   blue_add gtext#buffer (str_of_sasa_event false !e);
   d();
   let nodes_enabled = rdbg_nodes_enabled !e in
 
-  (** Met à jour le hook pour node quand le bouton ou une checkbox correspondant est activé *)
   let update_rdbg_hook node activate =
     (match !daemon_kind with
      | Distributed | Synchronous | Central | LocCentral ->
         assert false (* SNO *)
      | ManualCentral -> (
-       let txt = Printf.sprintf "ManualCentral step: %s\n\n%s" node (str_of_sasa_event false !e) in
+       let txt = Printf.sprintf "ManualCentral step: %s\n\n%s"
+                   node (str_of_sasa_event false !e) in
        (* gtext#buffer#set_text txt;  *)
        blue gtext#buffer txt;
        Hashtbl.filter_map_inplace (fun n status -> Some (n = node)) daemongui_activate;
@@ -361,6 +382,7 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
        show step_button; show checkbox_grid;
        hide back_step_button;
        hide legitimate_button;
+       hide undo_button;
        (match !oracle_button_ref with Some b -> hide b | None -> ());
        hide round_button; hide pushbox_grid;   hide counter_grid;
        let checkbox = Hashtbl.find checkbox_map node in
@@ -372,6 +394,7 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
        );
        checkbox#set_sensitive enabled
     | ManualCentral ->
+       hide undo_button;
        hide legitimate_button;
        (match !oracle_button_ref with Some b -> hide b | None -> ());
        (* hide back_step_button; *)
@@ -381,7 +404,10 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
        let pushbox = Hashtbl.find pushbox_map node in
        if enabled then show pushbox else hide pushbox;
        pushbox#set_sensitive enabled
-    | Distributed | Synchronous | Central | LocCentral ->
+       
+    | Synchronous | Distributed | Central | LocCentral ->
+       if !daemon_kind = Synchronous then show undo_button
+       else hide undo_button;
        (match !oracle_button_ref with Some b -> show b | None -> ());
        show back_step_button; show step_button; show round_button;
        show counter_grid; show legitimate_button;
@@ -424,7 +450,7 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
   (* Affichage d'informations *)
   (*   gtext#buffer#set_text !gtext_content; *)
 
-  let rec get_higher_prioriry nl =
+  let rec get_higher_priority nl =
     let prio n =
       let counter = Hashtbl.find counter_map n in
       counter#get
@@ -450,7 +476,7 @@ let custom_daemon p gtext vbox step_button back_step_button round_button legitim
      *)
     let nodes_enabled = rdbg_nodes_enabled e in
     let nodes = List.filter (fun (_,b) -> b) nodes_enabled in
-    let nodes = get_higher_prioriry nodes in
+    let nodes = get_higher_priority nodes in
     (* p ("==> gtkgui: CALL =" ^ (string_of_event e)); *)
     (match !daemon_kind with
      | Distributed -> (
@@ -545,7 +571,7 @@ let main () =
     cmd ();
     if store_flag then store !e.nb;
     if display_event_flag then display_event text_out;
-    refresh ()
+    d ()
   in
   let button_cb_string cmd () =
     let txt = Printf.sprintf "\n%s" (cmd ()) in
@@ -573,9 +599,20 @@ let main () =
   let image = GMisc.image ~file:(libui_prefix^"/chut_small.svg") () in
   legitimate_button#set_image image#coerce; 
 
+  let make_button stock lbl msg cmd =
+    let butt = button ~use_mnemonic:true ~stock:stock ~packing:bbox#add ~label:lbl () in
+    set_tooltip butt msg;
+    change_label butt lbl;
+    ignore (butt#connect#clicked ~callback:cmd);
+    butt
+  in
+  let undo_button = make_button `UNDO "_Undo" "Undo the last move"
+                      (button_cb true false (fun ()->u();d()))
+  in
   let set_daemongui_tbl = 
     if !custom_mode_ref then
-      custom_daemon p text_out w step_button back_step_button round_button legitimate_button      
+      custom_daemon p text_out w step_button back_step_button round_button
+        legitimate_button undo_button
     else
       (fun _ -> ())
   in
@@ -599,20 +636,31 @@ let main () =
       e
   in
   let back_step_gui () =
-    let lnext e = 
-      if args.salut_mode then
-        let e = goto_top e in
+    if args.salut_mode then
+      let lnext e =
         set_daemongui_tbl e;
+        let e = goto_top e in
         e
-      else 
-        let e = goto_hook_call e in
+      in
+      let ne = rev_cond_gen !e
+                 (fun ne -> ne.step = !e.step-1 && ne.kind = Ltop)
+                 lnext restore_round_nb
+      in
+      e:=ne
+    else
+      let lnext e =
         set_daemongui_tbl e;
+        if e.kind = Ltop then
+          (* Necessary for  reproductibility because set_daemongui_tbl
+             calls Random.int (via Daemon) which changes the PRGS! *)
+          e.restore_state e.nb;
+        let e = goto_hook_call e in
         e
-    in
-    let ne = rev_cond_gen !e (fun ne -> ne.step = !e.step-1) lnext in
-    if ne.kind <> !e.kind || ne.name <> !e.name then
-      e:=next_cond ne (fun ne -> ne.kind = !e.kind || ne.name = !e.name)
-    else
+      in
+      let ne = rev_cond_gen !e
+                 (fun ne -> ne.step = !e.step-1 && ne.name = "mv_hook" && ne.kind = Call)
+                 lnext restore_round_nb
+      in
       e:=ne
   in
   ignore (back_step_button#connect#clicked
@@ -633,7 +681,7 @@ let main () =
   (* indeed, in the defaut mode (manual central), it should be hided *)
   let rec next_round_gui rn =
     if is_silent !e then () else e:=a_gui_step !e;
-    if rn < !roundnb  || is_silent !e then () else (next_round_gui rn);
+    if rn < !round_st_ref.cpt  || is_silent !e then () else (next_round_gui rn);
   in
 
   set_tooltip step_button "Move FORWARD to the next STEP";
@@ -645,7 +693,7 @@ let main () =
             ~callback:(
               button_cb true true (fun () ->
                   if !custom_mode_ref then (
-                    next_round_gui !roundnb;
+                    next_round_gui !round_st_ref.cpt ;
                     if !custom_mode_ref && !e.name <> "mv_hook" && !e.kind <> Call
                        && not (is_silent !e)
                     then
@@ -658,7 +706,15 @@ let main () =
   set_tooltip back_round_button "Move BACKWARD to the previous ROUND";
   change_label back_round_button "Roun_d";
   ignore (back_round_button#connect#clicked
-            ~callback:(button_cb true true (fun () -> pr();pr(); e:=goto_hook_call !e)));
+            ~callback:(button_cb true true
+                         (fun () ->
+                           e:=goto_last_ckpt !e.nb;
+                           e:=goto_last_ckpt !e.nb;
+                           restore_round_nb !e.nb;
+                           store !e.nb;
+                           e:=goto_hook_call !e;
+                           refresh ()
+    )));
 
 
   let graph () = 
@@ -671,37 +727,18 @@ let main () =
   in
   graph ();
 
-  let make_button stock lbl msg cmd =
-    let butt = button ~use_mnemonic:true ~stock:stock ~packing:bbox#add ~label:lbl () in
-    set_tooltip butt msg;
-    change_label butt lbl;
-    ignore (butt#connect#clicked ~callback:cmd);
-    butt
-  in
   if args.oracles <> [] then (
     let oracle_button =
       make_button `OK "_Oracle" "Move FORWARD until an oracle is violated"
         (button_cb_string
-           (fun () -> let str = viol_string () in e:=goto_hook_call !e; d(); store !e.nb; str))
+           (fun () -> let str = viol_string () in
+                      e:=goto_hook_call !e; d(); store !e.nb; str))
     in
     oracle_button#misc#hide(); (* indeed, in the defaut mode (manual central), it should be hided *)
     oracle_button_ref := Some oracle_button
   );
-  let _ = make_button `UNDO "_Undo" "Undo the last move" (button_cb true false (fun ()->u();d())) in
   let _ = make_button `REFRESH "Restar_t" "Restart from the beginning"
-            (button_cb true true
-               (fun ()->
-                 let seed = Seed.get dotfile in
-                 Seed.set seed;
-                 p (Printf.sprintf "Restarting using the seed %d" seed);
-                 r();
-                 if args.salut_mode then
-                   (* in this mode, the hook plays first to provide fake values to sasa
-                      but the hook does not need input at this first step
-                    *)
-                   e:=goto_hook_exit !e;
-                 e:=goto_hook_call !e;
-                 d()))
+           (button_cb true true (restart p))
   in
   let _ = make_button `REFRESH "_New Seed" "Restart from the beginning using a New Seed"
             (button_cb true true
diff --git a/tools/rdbg4sasa/sasa-rdbg-cmds.ml b/tools/rdbg4sasa/sasa-rdbg-cmds.ml
index 627fb956..4c5c532e 100644
--- a/tools/rdbg4sasa/sasa-rdbg-cmds.ml
+++ b/tools/rdbg4sasa/sasa-rdbg-cmds.ml
@@ -23,18 +23,29 @@ let is_legitimate e =
 (**********************************************************************)
 (** Computing rounds *)
 
-let roundnb = ref (-666)
-let mask = ref [] (* nodes we look the activation of *) (* XXX use an array! *)
-let roundtbl = Hashtbl.create 10;; (* maps event nb to round + round nb *)
-(* let _ = Hashtbl.add roundtbl 1 (1,true);; *)
+module IntMap = Map.Make(Int)
+
+type round_st = {
+    cpt: int;
+    mask : string list;  (* nodes we look the activation of *) (* XXX use an array! *)
+    tbl : (int * bool * string list) IntMap.t
+                                     (* maps event nb to round, round nb, and mask *)
+  }
+
 let verbose = ref false
 
-let round_init () =
-  roundnb := 1;
-  mask := [];
-  Hashtbl.clear roundtbl
+let round_st_init = {
+    cpt = 1;
+    mask = [];
+    tbl = IntMap.empty
+  }
+
+let round_st_ref = ref round_st_init
+let round_reset () = round_st_ref := round_st_init
 
-let _ = round_init ();;
+let set_round_st_cpt n = round_st_ref := { !round_st_ref with cpt = n }
+let set_round_st_mask m = round_st_ref := { !round_st_ref with mask = m }
+let set_round_st_tbl t = round_st_ref := { !round_st_ref with tbl = t }
 
 (* a process can be removed from the mask if one action of p is triggered
   or if no action of p is enabled *)
@@ -56,130 +67,170 @@ let enabled pl = (* returns the enabled processes *)
   List.map (fun p -> p.name) el
 
 (* called at each event via the time-travel hook *)
-let (round : RdbgEvent.t -> bool) = fun e ->
-  match Hashtbl.find_opt roundtbl e.nb with
+let (round : bool -> RdbgEvent.t -> bool) =
+  fun from_past e ->
+  if from_past then set_round_st_tbl (IntMap.remove e.nb !round_st_ref.tbl);
+  match IntMap.find_opt e.nb !round_st_ref.tbl with
   | Some (croundnb, round, cmask) ->
      (*     Printf.printf "round tabulated at e.nb %d: croundnb=%d round = %b\n%!" *)
      (*       e.nb croundnb round; *)
-     roundnb := croundnb;
-     mask := cmask;
+     set_round_st_cpt croundnb;
+     set_round_st_mask cmask;
      round
   | None ->
-     if !mask = [] && is_silent e then false else
-     let round =
-       ( (* we check if a round occurs when activated processes are available *)
-         if args.salut_mode then
-           e.kind = Exit && e.name = "mv_hook" && e.step > 1
+     if !round_st_ref.mask = [] && is_silent e then false else
+       let round =
+         if not 
+              ( (* we check if a round occurs when activated processes are available *)
+                if args.salut_mode then
+                  e.kind = Exit && e.name = "mv_hook" && e.step > 1
+                else
+                  e.kind = Ltop
+              )
+         then false
          else
-           e.kind = Ltop
-       )
-       &&
-         let (pl : process list) = get_processes e in
-         if !mask = [] then mask := enabled pl; (* occurs at the first possible round *)
-         let rm_me = get_removable pl in
-         if !verbose then (
-           Printf.printf "\nMask (event %d): %s\n" e.nb (String.concat "," !mask);
-           Printf.printf "To remove from mask: %s\n%!" (String.concat "," rm_me)
-         );
-         mask := List.filter (fun pid -> not (List.mem pid rm_me)) !mask;
-         if !verbose then
-           Printf.printf "New Mask: %s\n%!" (String.concat "," !mask);
-         let res = !mask = [] in
-         if res then (
-           mask := (
-             let mask =
-               List.filter
-                 (fun p -> List.exists (fun (_,e,a) -> e && not(a)) p.actions)
-                 pl
-             in
-             let mask = List.map (fun p -> p.name) mask in
-             if !verbose then (
-               let mask = List.rev mask in
-               Printf.printf "Next mask : %s\n%!" (String.concat "," mask);
-               flush stdout
-             );
-             mask
-           )
-         );
-         res
-     in
-     if round then incr roundnb;
-     Hashtbl.add roundtbl e.nb (!roundnb, round, !mask);
-     (* Printf.printf "round computed at e.nb %d: croundnb=%d round = %b\n%!"
+           let (pl : process list) = get_processes e in
+           if !round_st_ref.mask = [] then 
+             (*  occurs  at the  first  possible  round, or  when  all
+                processes in the previous mask were the only triggered
+                processes *)
+             set_round_st_mask (enabled pl);
+           let rm_me = get_removable pl in
+           if !verbose then (
+             Printf.printf "\nMask (event %d): %s\n" e.nb
+               (String.concat "," !round_st_ref.mask);
+             Printf.printf "To remove from mask: %s\n%!" (String.concat "," rm_me)
+           );
+           set_round_st_mask
+             (List.filter (fun pid -> not (List.mem pid rm_me)) !round_st_ref.mask);
+           if !verbose then
+             Printf.printf "New Mask: %s\n%!" (String.concat "," !round_st_ref.mask);
+           let res = !round_st_ref.mask = [] in
+           if res then (
+             set_round_st_mask (
+                 let mask =
+                   List.filter
+                     (fun p -> List.exists (fun (_,e,a) -> e && not(a)) p.actions)
+                     pl
+                 in
+                 let mask = List.map (fun p -> p.name) mask in
+                 if !verbose then (
+                   let mask = List.rev mask in
+                   Printf.printf "Next mask : %s\n%!" (String.concat "," mask);
+                   flush stdout
+                 );
+                 mask
+               )
+           );
+           res
+       in
+       if round then set_round_st_cpt (!round_st_ref.cpt + 1);
+       if !verbose then
+         Printf.printf "IntMap.add e.nb=%d round_nb=%d round= %b mask=%s\n%!"
+           e.nb !round_st_ref.cpt round  (String.concat "," !round_st_ref.mask);
+       set_round_st_tbl
+         (IntMap.add e.nb (!round_st_ref.cpt, round, !round_st_ref.mask)
+            !round_st_ref.tbl);
+       (* Printf.printf "round computed at e.nb %d: croundnb=%d round = %b\n%!"
        e.nb !roundnb round; *)
-     round
+       round
 
-let update_round_nb e =
-  match Hashtbl.find_opt roundtbl e.nb with
-  | None -> ()
-  | Some (n,_, m) -> roundnb := n; mask := m
+       
+let restore_round_nb i =
+  match IntMap.find_opt i !round_st_ref.tbl with
+  | None ->
+     (*  Printf.printf "restore_round_nb: At event %d, nothing to restore\n%!" e.nb ; *)
+     ()
+  | Some (n,_, m) ->
+     (* Printf.printf "restore_round_nb: At event %d, restore the rn %d\n%!" e.nb n; *)
+     set_round_st_cpt n;
+     set_round_st_mask m;
+     ()
+
+let sasa_next e =
+  let ne = e.next () in
+  List.iter
+    (fun str -> if str<>"print_event" then (RdbgStdLib.get_hook str) ne)
+    (RdbgStdLib.list_hooks ()); 
+  ne
 
-(* go to next round *)
 let next_round e =
-  let ne = next_cond e round in
-  ne
+  next_cond_gen e (round true) sasa_next
 
+let back_step e =
+  rev_cond_gen e (fun ne -> ne.kind = e.kind && ne.name = e.name)
+    sasa_next restore_round_nb
+  
 (**********************************************************************)
 (* redefine (more meaningful) step and back-step for sasa *)
 let sasa_step e = next_cond e (fun ne -> ne.kind = e.kind && ne.name = e.name)
-let sasa_bstep e = rev_cond e (fun ne -> ne.kind = e.kind && ne.name = e.name)
 let s () = e:=sasa_step !e ; emacs_udate !e; store !e.nb;pe()
-let b () = e:=sasa_bstep !e ; emacs_udate !e; store !e.nb;pe()
+let b () =
+  let ne = back_step !e in
+  e:=ne ;
+  emacs_udate !e; store !e.nb;pe()
 
 let p =
   try Topology.read dotfile
   with _ -> failwith "This is not a sasa rdbg session!";;
 
-let d_par () = dot true !roundnb p dotfile !e;;
-let dot_par () = dot true !roundnb p dotfile !e;;
-let ne_par () = neato true !roundnb p dotfile !e;;
-let tw_par () = twopi true !roundnb p dotfile !e;;
-let ci_par () = circo true !roundnb p dotfile !e;;
-let fd_par () = fdp true !roundnb p dotfile !e;;
-let sf_par () = sfdp true !roundnb p dotfile !e;;
-let pa_par () = patchwork true !roundnb p dotfile !e;;
-let os_par () = osage true !roundnb p dotfile !e;;
-
-let dot () = dot false !roundnb p dotfile !e;;
-let ne () = neato false !roundnb p dotfile !e;;
-let tw () = twopi false !roundnb p dotfile !e;;
-let ci () = circo false !roundnb p dotfile !e;;
-let fd () = fdp false !roundnb p dotfile !e;;
-let sf () = sfdp false !roundnb p dotfile !e;;
-let pa () = patchwork false !roundnb p dotfile !e;;
-let os () = osage false !roundnb p dotfile !e;;
+let d_par () = dot true !round_st_ref.cpt p dotfile !e;;
+let dot_par () = dot true !round_st_ref.cpt p dotfile !e;;
+let ne_par () = neato true !round_st_ref.cpt p dotfile !e;;
+let tw_par () = twopi true !round_st_ref.cpt p dotfile !e;;
+let ci_par () = circo true !round_st_ref.cpt p dotfile !e;;
+let fd_par () = fdp true !round_st_ref.cpt p dotfile !e;;
+let sf_par () = sfdp true !round_st_ref.cpt p dotfile !e;;
+let pa_par () = patchwork true !round_st_ref.cpt p dotfile !e;;
+let os_par () = osage true !round_st_ref.cpt p dotfile !e;;
+
+let dot () = dot false !round_st_ref.cpt p dotfile !e;;
+let ne () = neato false !round_st_ref.cpt p dotfile !e;;
+let tw () = twopi false !round_st_ref.cpt p dotfile !e;;
+let ci () = circo false !round_st_ref.cpt p dotfile !e;;
+let fd () = fdp false !round_st_ref.cpt p dotfile !e;;
+let sf () = sfdp false !round_st_ref.cpt p dotfile !e;;
+let pa () = patchwork false !round_st_ref.cpt p dotfile !e;;
+let os () = osage false !round_st_ref.cpt p dotfile !e;;
 
 
 (* To change the default dot/graph viewer: 
    dot_view := ci;;
-*)
+ *)
 let dot_view : (unit -> unit) ref =
   ref ( (* Try to chose the most sensible default viewer *)
       if String.length dotfile > 4 && String.sub dotfile 0 4 = "ring" then ci else
-      if Algo.is_directed () then dot else ne)
-
+        if Algo.is_directed () then dot else ne)
+  
 let d () = !dot_view ()
 let sd () = s();!dot_view();;
 let bd()= e:=prev !e ; emacs_udate !e; pe();!dot_view();;
 
 
+let nr () =
+  let ne = next_round !e in
+  e := ne;
+  store !e.nb; !dot_view ();;
 
-let nr () = e:=next_round !e; store !e.nb; !dot_view ();;
 let pr () =
   e:=goto_last_ckpt !e.nb;
-  update_round_nb !e;
+  restore_round_nb !e.nb;
   !dot_view ();
   store !e.nb
-
+  
 (* I need to overrides those *)
 
-let u () = undo (); ignore (round !e);;
+(* won't work in semi-auto modes, but the buttons are hided *)
+let u () = undo (); ignore (round true !e);; 
 let r () =
-  r ();
-  round_init ();
-  ignore (round !e);
+  !e.RdbgEvent.reset();
+  e:=RdbgStdLib.run ~call_hooks:true ();
+  round_reset ();
+  redos := [1];
+  (* ignore (round false !e); *)
   (* if the first event is not a round, add it as a check_point *)
-  if !ckpt_list = [] then ckpt_list := [!e];;
+  (* if !ckpt_list = [] then *)
+  ckpt_list := [!e];;
 
 (**********************************************************************)
 (* Move forward until silence *)
@@ -188,12 +239,12 @@ let goto_silence e = next_cond e is_silent
 let silence () = e:=goto_silence !e; !dot_view ();;
 
 let _ = add_doc_entry
-    "silence" "unit -> unit" "Move forward until is_silent returns true"
-    "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry
-    "is_silent" "RdbgEvent.t -> bool"
-    "does the event correspond to a silent configuration? (i.e., no enable node)"
-    "sasa" "sasa-rdbg-cmds.ml";;
+          "silence" "unit -> unit" "Move forward until is_silent returns true"
+          "sasa" "sasa-rdbg-cmds.ml";
+        add_doc_entry
+          "is_silent" "RdbgEvent.t -> bool"
+          "does the event correspond to a silent configuration? (i.e., no enable node)"
+          "sasa" "sasa-rdbg-cmds.ml";;
 
 
 let goto_legitimate e = next_cond e is_legitimate 
@@ -216,58 +267,58 @@ let _ =
    names; ie we leave only the pid and the action name *)
 type s = (string * string * Data.v) 
 let split_data (l:Data.subst list) : s list * s list * s list = 
-    let l = List.map (fun (x,v) -> Str.split (Str.regexp "_") x, v) l in
-    let rec sortv (enab, other) (x,v) =
-      match x with 
-      | "Enab"::pid::tail -> (pid, String.concat "_" tail,v)::enab, other
-      | pid::tail -> enab, (pid,(String.concat "_" tail),v)::other
-      | [] -> assert false
-    in
-    let enab, other = List.fold_left sortv ([],[]) l in
-    let acti_names = List.map (fun (pid, n, v) -> pid, n) enab in  
-    let act, vars =
-      List.partition (fun (pid,n, _) -> List.mem (pid,n) acti_names) other
-    in
-    enab, act, vars
-
-
+  let l = List.map (fun (x,v) -> Str.split (Str.regexp "_") x, v) l in
+  let rec sortv (enab, other) (x,v) =
+    match x with 
+    | "Enab"::pid::tail -> (pid, String.concat "_" tail,v)::enab, other
+    | pid::tail -> enab, (pid,(String.concat "_" tail),v)::other
+    | [] -> assert false
+  in
+  let enab, other = List.fold_left sortv ([],[]) l in
+  let acti_names = List.map (fun (pid, n, v) -> pid, n) enab in  
+  let act, vars =
+    List.partition (fun (pid,n, _) -> List.mem (pid,n) acti_names) other
+  in
+  enab, act, vars
+  
+  
 let only_true l = List.filter (fun (_,_, v)  -> v = B true) l
 (* Only print the active process values *)
 let str_of_sasa_event short e =
-    let enab, act, vars = split_data e.data in
-    let enab = only_true enab in
-    let act = only_true act in
-    let act_pid = List.map (fun (pid,_,_) -> pid) act in
-    let vars = List.filter (fun (pid, _,_) -> List.mem pid act_pid) vars in
-    let _to_string (pid, n, _) = Printf.sprintf "%s_%s" pid n in 
-    let to_string_var (pid, n, v) =
-      Printf.sprintf "%s_%s=%s" pid n (Data.val_to_string string_of_float v)
-    in
-    let pot = match List.assoc_opt "potential" e.data with
-      | Some F f -> Printf.sprintf " => potential %.1f" f
-      | _ -> ""
-    in
-    let leg = match List.assoc_opt "legitimate" e.data with
-      | Some B true -> Printf.sprintf "The current configuration is legitimate\n" 
-      | Some B false -> ""
-      | _ -> ""
-    in
-    let silent = if enab = [] then "The current configuration is silent\n"  else "" in
-    let vars = List.rev vars in
-    update_round_nb e;
-    (if short then
-      Printf.sprintf "[round %i, step %i%s] %s %s\n" !roundnb e.step pot
-        (if e.step <> e.nb then (":" ^ (string_of_int e.nb)) else "")
-        (String.concat " " (List.map to_string_var vars))
-    else
-      Printf.sprintf "Round %i - Step %i%s%s\n%s%s\n%s%s" !roundnb e.step
-        (if e.step <> e.nb then (" - Event " ^ (string_of_int e.nb)) else "") pot
-        (RdbgStdLib.string_of_event e) 
-        (if vars = [] then "" else
-           ("Active node states: "^(String.concat " " (List.map to_string_var vars))))
-        leg silent
-   ) 
-      
+  let enab, act, vars = split_data e.data in
+  let enab = only_true enab in
+  let act = only_true act in
+  let act_pid = List.map (fun (pid,_,_) -> pid) act in
+  let vars = List.filter (fun (pid, _,_) -> List.mem pid act_pid) vars in
+  let _to_string (pid, n, _) = Printf.sprintf "%s_%s" pid n in 
+  let to_string_var (pid, n, v) =
+    Printf.sprintf "%s_%s=%s" pid n (Data.val_to_string string_of_float v)
+  in
+  let pot = match List.assoc_opt "potential" e.data with
+    | Some F f -> Printf.sprintf " => potential %.1f" f
+    | _ -> ""
+  in
+  let leg = match List.assoc_opt "legitimate" e.data with
+    | Some B true -> Printf.sprintf "The current configuration is legitimate\n" 
+    | Some B false -> ""
+    | _ -> ""
+  in
+  let silent = if enab = [] then "The current configuration is silent\n"  else "" in
+  let vars = List.rev vars in
+  (* restore_round_nb e; *)
+  (if short then
+     Printf.sprintf "[round %i, step %i%s] %s %s\n" !round_st_ref.cpt e.step pot
+       (if e.step <> e.nb then (":" ^ (string_of_int e.nb)) else "")
+       (String.concat " " (List.map to_string_var vars))
+   else
+     Printf.sprintf "Round %i - Step %i%s%s\n%s%s\n%s%s" !round_st_ref.cpt e.step
+       (if e.step <> e.nb then (" - Event " ^ (string_of_int e.nb)) else "") pot
+       (RdbgStdLib.string_of_event e) 
+       (if vars = [] then "" else
+          ("Active node states: "^(String.concat " " (List.map to_string_var vars))))
+       leg silent
+  ) 
+  
 let print_sasa_event short e =
   if e.kind <> Ltop then print_event e else
     (
@@ -288,9 +339,9 @@ let spel () = print_sasa_event false !e;;
 (* Goto to the next Lustre oracle violation *)
 let goto_next_false_oracle e =
   next_cond e (fun e -> e.kind = Exit && e.lang = "lustre" &&
-                        List.mem ("ok", Bool) e.outputs  &&
-                        not (vb "ok" e))
-
+                          List.mem ("ok", Bool) e.outputs  &&
+                            not (vb "ok" e))
+  
 let viol_string () =
   if args.oracles <> [] then (
     e:=goto_next_false_oracle !e; !dot_view (); "An oracle has been violated. Cf the .rif file"
@@ -301,8 +352,8 @@ let viol_string () =
 let viol () = Printf.printf "%s\n%!" (viol_string ())
 
 let _ = add_doc_entry
-    "viol" "unit -> unit" "Move forward until the oracle is violated"
-    "sasa" "sasa-rdbg-cmds.ml"
+          "viol" "unit -> unit" "Move forward until the oracle is violated"
+          "sasa" "sasa-rdbg-cmds.ml"
 
 (**********************************************************************)
 (* Potential  *)
@@ -315,76 +366,96 @@ let potential () =
   | _ -> None
 
 let _ = add_doc_entry
-    "potential" "unit -> float option" "returns the current potential if available"
-    "sasa" "sasa-rdbg-cmds.ml"
+          "potential" "unit -> float option" "returns the current potential if available"
+          "sasa" "sasa-rdbg-cmds.ml"
 
 
 
 (**********************************************************************)
 (* Perform the checkpointing at rounds! *)
-let _ = check_ref := fun e -> e.nb = 1 || round e;;
+let _ = check_ref := fun e -> e.nb = 1 || round true e;;
 
 (**********************************************************************)
 let _ = 
-  add_doc_entry "d" "unit -> unit" "update the current network with dot" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "ne" "unit -> unit" "update the current network with neato" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "tw" "unit -> unit" "update the current network with twopi" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "ci" "unit -> unit" "update the current network with circo" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "fd" "unit -> unit" "update the current network with fdp" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "sf" "unit -> unit" "update the current network with sfdp" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "pa" "unit -> unit" "update the current network with patchwork" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "os" "unit -> unit" "update the current network with osage" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "d"
+    "unit -> unit" "update the current network with dot" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "ne"
+    "unit -> unit" "update the current network with neato" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "tw"
+    "unit -> unit" "update the current network with twopi" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "ci"
+    "unit -> unit" "update the current network with circo" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "fd"
+    "unit -> unit" "update the current network with fdp" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "sf"
+    "unit -> unit" "update the current network with sfdp" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "pa"
+    "unit -> unit" "update the current network with patchwork" "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "os"
+    "unit -> unit" "update the current network with osage" "sasa" "sasa-rdbg-cmds.ml";
   
   add_doc_entry "sd" "unit -> unit"
-    "go to the next step and update the network with one of the GraphViz tools" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "bd" "unit -> unit" "go to the previous step and update the network" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "nr" "unit -> unit" "go to the next round and update the network" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "pr" "unit -> unit" "go to the previous round and update the network" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "d_par" "unit -> unit" "cf d (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "ne_par" "unit -> unit" "cf ne (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "tw_par" "unit -> unit" "cf tw (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "ci_par" "unit -> unit" "cf ci (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "fd_par" "unit -> unit" "cf fd (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "sf_par" "unit -> unit" "cf sf (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "pa_par" "unit -> unit" "cf pa (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
-  add_doc_entry "os_par" "unit -> unit" "cf os (for topology with a parent field)" "sasa" "sasa-rdbg-cmds.ml";
+    "go to the next step and update the network with one of the GraphViz tools" "sasa"
+    "sasa-rdbg-cmds.ml";
+  add_doc_entry "bd" "unit -> unit" "go to the previous step and update the network"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "nr" "unit -> unit" "go to the next round and update the network"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "pr" "unit -> unit" "go to the previous round and update the network"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "d_par" "unit -> unit" "cf d (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "ne_par" "unit -> unit" "cf ne (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "tw_par" "unit -> unit" "cf tw (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "ci_par" "unit -> unit" "cf ci (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "fd_par" "unit -> unit" "cf fd (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "sf_par" "unit -> unit" "cf sf (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "pa_par" "unit -> unit" "cf pa (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
+  add_doc_entry "os_par" "unit -> unit" "cf os (for topology with a parent field)"
+    "sasa" "sasa-rdbg-cmds.ml";
   ()
 
 let l () =
   l();
-  print_string ("
-- sasa commands
- + Display network with GraphViz tools
-   d: "^(RdbgMain.doc_msg "d")^"
-   ne: "^(RdbgMain.doc_msg "ne")^"
-   tw: "^(RdbgMain.doc_msg "tw")^" 
-   ci: "^(RdbgMain.doc_msg "ci")^"
-   fd: "^(RdbgMain.doc_msg "fd")^"
-   sf: "^(RdbgMain.doc_msg "sf")^"
-   pa: "^(RdbgMain.doc_msg "pa")^"
-   os: "^(RdbgMain.doc_msg "os")^"
-   
-   nb: for algorithms that have a field named 'par', you can try 
-   of the following (which only draw the parent arcs) 
- 
-   d_par: "^(RdbgMain.doc_msg "d")^" (parent arcs only)
-   ne_par: "^(RdbgMain.doc_msg "ne")^" (parent arcs only)
-   tw_par: "^(RdbgMain.doc_msg "tw")^" (parent arcs only)
-   ci_par: "^(RdbgMain.doc_msg "ci")^" (parent arcs only)
-   fd_par: "^(RdbgMain.doc_msg "fd")^" (parent arcs only)
-   sf_par: "^(RdbgMain.doc_msg "sf")^" (parent arcs only)
-   pa_par: "^(RdbgMain.doc_msg "pa")^" (parent arcs only)
-   os_par: "^(RdbgMain.doc_msg "os")^" (parent arcs only)
-
- + Moving commands [*]
-   sd: "^(RdbgMain.doc_msg "sd")^"
-   nd: "^(RdbgMain.doc_msg "nd")^"
-   bd: "^(RdbgMain.doc_msg "bd")^"
-   nr: "^(RdbgMain.doc_msg "nr")^"
-   pr: "^(RdbgMain.doc_msg "pr")^"
- [*] in order to change the current graph drawing engine, you can use
-the dot_view reference as follows:
-  dot_view := ci
+  print_string (
+      "
+       - sasa commands
+       + Display network with GraphViz tools
+       d: "^(RdbgMain.doc_msg "d")^"
+       ne: "^(RdbgMain.doc_msg "ne")^"
+       tw: "^(RdbgMain.doc_msg "tw")^"
+       ci: "^(RdbgMain.doc_msg "ci")^"
+       fd: "^(RdbgMain.doc_msg "fd")^"
+       sf: "^(RdbgMain.doc_msg "sf")^"
+       pa: "^(RdbgMain.doc_msg "pa")^"
+       os: "^(RdbgMain.doc_msg "os")^"
+                                      
+       nb: for algorithms that have a field named 'par', you can try 
+           one of the following (which only draw the parent arcs)
+       d_par: "^(RdbgMain.doc_msg "d")^" (parent arcs only)
+       ne_par: "^(RdbgMain.doc_msg "ne")^" (parent arcs only)
+       tw_par: "^(RdbgMain.doc_msg "tw")^" (parent arcs only)
+       ci_par: "^(RdbgMain.doc_msg "ci")^" (parent arcs only)
+       fd_par: "^(RdbgMain.doc_msg "fd")^" (parent arcs only)
+       sf_par: "^(RdbgMain.doc_msg "sf")^" (parent arcs only)
+       pa_par: "^(RdbgMain.doc_msg "pa")^" (parent arcs only)
+       os_par: "^(RdbgMain.doc_msg "os")^" (parent arcs only)
+       
+       + Moving commands [*]
+         sd: "^(RdbgMain.doc_msg "sd")^"
+         nd: "^(RdbgMain.doc_msg "nd")^"
+         bd: "^(RdbgMain.doc_msg "bd")^"
+         nr: "^(RdbgMain.doc_msg "nr")^"
+         pr: "^(RdbgMain.doc_msg "pr")^"
+      [*] in order to change the current graph drawing engine, you can use
+          the dot_view reference as follows:
+           dot_view := ci
 ");;
 
 
@@ -393,21 +464,20 @@ the dot_view reference as follows:
 
 let pdf_viewer =
   if Sys.command "which zathura" = 0 then "zathura" else
-  if Sys.command "which xpdf" = 0 then "xpdf" else
-  if Sys.command "which acroread" = 0 then "acroread" else
-  if Sys.command "which evince" = 0 then "evince" else (
-    Printf.printf "Warning: no pdf viewer is found to visualize %s\n%!" dotfile;
-    "ls"
-  )
-  
+    if Sys.command "which xpdf" = 0 then "xpdf" else
+      if Sys.command "which acroread" = 0 then "acroread" else
+        if Sys.command "which evince" = 0 then "evince" else (
+          Printf.printf "Warning: no pdf viewer is found to visualize %s\n%!" dotfile;
+          "ls"
+        )
+              
 let graph_view () = 
   !dot_view ();
   let cmd = Printf.sprintf "%s sasa-%s.pdf&" pdf_viewer dotfile in
   Printf.printf "%s\n!" cmd;
-  ignore(Sys.command cmd); 
-  ignore(round !e)
+  ignore(Sys.command cmd)
 
- ;;
+;;
 (* let _ = graph_view () *)
 let gv = graph_view
 
@@ -415,13 +485,13 @@ let _ =
   add_doc_entry "gv" "unit -> unit"
     "launch a pdf viewer of the current network
 
-in order to change the current graph drawing engine, you can use
-the dot_view reference as follows:
-(rdbg)  dot_view := ci;;
-or
-(rdbg)  dot_view := fd;;
+     in order to change the current graph drawing engine, you can use
+     the dot_view reference as follows:
+     (rdbg)  dot_view := ci;;
+     or
+     (rdbg)  dot_view := fd;;
 
-In order to get the list of  graph drawing engine:
-(rdbg)   h sasa
-"
+     In order to get the list of  graph drawing engine:
+     (rdbg)   h sasa
+     "
     "sasa" "sasa-rdbg-cmds.ml";
-- 
GitLab