Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Move state stack management to member on UnfoldingChecker
authorMaxwell Pirtle <maxwellpirtle@gmail.com>
Thu, 23 Mar 2023 08:19:08 +0000 (09:19 +0100)
committerMaxwell Pirtle <maxwellpirtle@gmail.com>
Wed, 5 Apr 2023 08:37:20 +0000 (10:37 +0200)
Instead of passing around the variable `state_stack`
in a number of arguments in the UnfoldingChecker,
we moved the stack into a member on the class. This
also allows us to give a textual trace of what UDPOR
is searching much in the same way as is done with
DFSExplorer

src/mc/explo/UdporChecker.cpp
src/mc/explo/UdporChecker.hpp
src/mc/explo/udpor/ExtensionSetCalculator.cpp

index b452320..492b808 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <xbt/asserts.h>
 #include <xbt/log.h>
+#include <xbt/string.hpp>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to verification using UDPOR");
 
@@ -22,16 +23,13 @@ UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args, t
 void UdporChecker::run()
 {
   XBT_INFO("Starting a UDPOR exploration");
-
-  auto state_stack = std::list<std::unique_ptr<State>>();
+  state_stack.clear();
   state_stack.push_back(get_current_state());
-
-  explore(Configuration(), EventSet(), EventSet(), state_stack, EventSet());
+  explore(Configuration(), EventSet(), EventSet(), EventSet());
   XBT_INFO("UDPOR exploration terminated -- model checking completed");
 }
 
-void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A,
-                           std::list<std::unique_ptr<State>>& state_stack, EventSet prev_exC)
+void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, EventSet prev_exC)
 {
   auto& stateC   = *state_stack.back();
   auto exC       = compute_exC(C, stateC, prev_exC);
@@ -81,7 +79,7 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A,
   move_to_stateCe(stateC, *e);
   state_stack.push_back(record_current_state());
 
-  explore(Ce, D, std::move(A), state_stack, std::move(exC));
+  explore(Ce, D, std::move(A), std::move(exC));
 
   //  Prepare to move the application back one state.
   // We need only remove the state from the stack here: if we perform
@@ -101,11 +99,11 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A,
     // `state(C)` all together, the RemoteApp is currently sitting
     // at some *future* state with resepct to `state(C)` since the
     // recursive calls have moved it there.
-    restore_program_state_with_sequence(state_stack);
+    restore_program_state_with_current_stack();
 
     // Explore(C, D + {e}, J \ C)
     auto J_minus_C = J.value().get_events().subtracting(C.get_events());
-    explore(C, D, std::move(J_minus_C), state_stack, std::move(prev_exC));
+    explore(C, D, std::move(J_minus_C), std::move(prev_exC));
   }
 
   // D <-- D - {e}
@@ -189,13 +187,13 @@ void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
   state.execute_next(next_actor, get_remote_app());
 }
 
-void UdporChecker::restore_program_state_with_sequence(const std::list<std::unique_ptr<State>>& state_stack)
+void UdporChecker::restore_program_state_with_current_stack()
 {
   get_remote_app().restore_initial_state();
 
   /* Traverse the stack from the state at position start and re-execute the transitions */
   for (const std::unique_ptr<State>& state : state_stack) {
-    if (state == stack_.back()) /* If we are arrived on the target state, don't replay the outgoing transition */
+    if (state == state_stack.back()) /* If we are arrived on the target state, don't replay the outgoing transition */
       break;
     state->get_transition()->replay(get_remote_app());
   }
@@ -247,14 +245,18 @@ void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration
 RecordTrace UdporChecker::get_record_trace()
 {
   RecordTrace res;
+  for (auto const& state : state_stack)
+    res.push_back(state->get_transition());
   return res;
 }
 
 std::vector<std::string> UdporChecker::get_textual_trace()
 {
-  // TODO: Topologically sort the events of the latest configuration
-  // and iterate through that topological sorting
   std::vector<std::string> trace;
+  for (auto const& state : state_stack) {
+    const auto* t = state->get_transition();
+    trace.push_back(xbt::string_printf("%ld: %s", t->aid_, t->to_string().c_str()));
+  }
   return trace;
 }
 
index 00b39c6..d7377d1 100644 (file)
@@ -44,6 +44,10 @@ public:
 private:
   Unfolding unfolding = Unfolding();
 
+  // The current sequence of states that the checker has
+  // visited in order to reach the current configuration
+  std::list<std::unique_ptr<State>> state_stack;
+
   /**
    * @brief Explores the unfolding of the concurrent system
    * represented by the ModelChecker instance "mcmodel_checker"
@@ -59,20 +63,11 @@ private:
    * @param A the set of events to "guide" UDPOR in the correct direction
    * when it returns back to a node in the unfolding and must decide among
    * events to select from `ex(C)`. See [1] for more details
-   * @param stateSequence the sequence of states entered by the program
-   * while UDPOR explored `C`. The program is in `state(C)` (using the notation of [1]),
-   * which is the result of executing all actions in the stack
-   *
-   * TODO: We pass around the reference to the stack which is modified
-   * appropriately in each recursive call. An iterative version would not
-   * need to pass around the states in this manner: the `std::stack<...>`
-   * could be a local variable of the function
    *
    * TODO: Add the optimization where we can check if e == e_prior
    * to prevent repeated work when computing ex(C)
    */
-  void explore(const Configuration& C, EventSet D, EventSet A, std::list<std::unique_ptr<State>>& state_stack,
-               EventSet prev_exC);
+  void explore(const Configuration& C, EventSet D, EventSet A, EventSet prev_exC);
 
   /**
    * @brief Identifies the next event from the unfolding of the concurrent system
@@ -154,7 +149,7 @@ private:
    * The UDPOR implementation in SimGrid ensures that the stack is updated appropriately,
    * but the process must still be regenerated.
    */
-  void restore_program_state_with_sequence(const std::list<std::unique_ptr<State>>& state_stack);
+  void restore_program_state_with_current_stack();
 
   /**
    * @brief Perform the functionality of the `Remove(e, C, D)` function in [1]
index 2486c98..757441c 100644 (file)
@@ -25,7 +25,8 @@ EventSet ExtensionSetCalculator::partially_extend(const Configuration& C, Unfold
   using HandlerMap = std::unordered_map<Action, Handler>;
 
   const static HandlerMap handlers =
-      HandlerMap{{Action::COMM_ASYNC_RECV, &ExtensionSetCalculator::partially_extend_CommRecv}};
+      HandlerMap{{Action::COMM_ASYNC_RECV, &ExtensionSetCalculator::partially_extend_CommRecv},
+                 {Action::COMM_ASYNC_SEND, &ExtensionSetCalculator::partially_extend_CommSend}};
 
   if (const auto handler = handlers.find(action->type_); handler != handlers.end()) {
     return handler->second(C, U, std::move(action));