Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Intermediate commit to prove that UDPOR functions
authorMaxwell Pirtle <maxwellpirtle@gmail.com>
Tue, 28 Mar 2023 11:44:12 +0000 (13:44 +0200)
committerMaxwell Pirtle <maxwellpirtle@gmail.com>
Wed, 5 Apr 2023 08:37:20 +0000 (10:37 +0200)
This commit returns a const_cast<>-ed UnfoldingEvent
from the intersection of the sets A and ex(C) in
the Unfolding. We use this work around currently as
there is no way currently to distinguish between a
set of events and a set of constant events with
EventSet. To do so would require a number of changes
and probably a class that would be entirely duplicated
and more difficult to read without the help of e.g.
a template (which itself is not always the easiest to
read).

src/mc/api/ActorState.hpp
src/mc/api/State.cpp
src/mc/api/State.hpp
src/mc/explo/UdporChecker.cpp
src/mc/explo/UdporChecker.hpp
src/mc/explo/udpor/UnfoldingEvent.hpp

index a7fee78..315ed8a 100644 (file)
@@ -124,7 +124,7 @@ public:
     return this->pending_transitions_[times_considered].get();
   }
 
-  inline void set_transition(std::unique_ptr<Transition> t, unsigned times_considered)
+  inline void set_transition(std::shared_ptr<Transition> t, unsigned times_considered)
   {
     xbt_assert(times_considered < this->pending_transitions_.size(),
                "Actor %ld does not have a state available transition with `times_considered = %u`, "
index b5f8eba..e701c72 100644 (file)
@@ -127,7 +127,7 @@ std::pair<aid_t, int> State::next_transition_guided() const
 }
 
 // This should be done in GuidedState, or at least interact with it
-void State::execute_next(aid_t next, RemoteApp& app)
+std::shared_ptr<Transition> State::execute_next(aid_t next, RemoteApp& app)
 {
   // First, warn the guide, so it knows how to build a proper child state
   strategy_->execute_next(next, app);
@@ -162,9 +162,10 @@ void State::execute_next(aid_t next, RemoteApp& app)
   // about a transition AFTER it has executed.
   transition_ = just_executed;
 
-  auto executed_transition = std::unique_ptr<Transition>(just_executed);
-  actor_state.set_transition(std::move(executed_transition), times_considered);
-
+  const auto executed_transition = std::shared_ptr<Transition>(just_executed);
+  actor_state.set_transition(executed_transition, times_considered);
   app.wait_for_requests();
+
+  return executed_transition;
 }
 } // namespace simgrid::mc
index 6d98437..111c4af 100644 (file)
@@ -66,9 +66,11 @@ public:
    internal cost of the transition is returned */
   std::pair<aid_t, int> next_transition_guided() const;
 
-  /* Explore a new path on the remote app; the parameter 'next' must be the result of a previous call to
-   * next_transition() */
-  void execute_next(aid_t next, RemoteApp& app);
+  /**
+   * @brief Explore a new path on the remote app; the parameter 'next' must be the result of a previous call to
+   * next_transition()
+   */
+  std::shared_ptr<Transition> execute_next(aid_t next, RemoteApp& app);
 
   long get_num() const { return num_; }
   std::size_t count_todo() const;
index 15cc3ec..03b39e5 100644 (file)
@@ -61,7 +61,7 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, Event
 
   // TODO: Add verbose logging about which event is being explored
 
-  const UnfoldingEvent* e = select_next_unfolding_event(A, enC);
+  UnfoldingEvent* e = select_next_unfolding_event(A, enC);
   xbt_assert(e != nullptr, "\n\n****** INVARIANT VIOLATION ******\n"
                            "UDPOR guarantees that an event will be chosen at each point in\n"
                            "the search, yet no events were actually chosen\n"
@@ -76,7 +76,7 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, Event
   // Explore(C + {e}, D, A \ {e})
 
   // Move the application into stateCe (i.e. `state(C + {e})`) and make note of that state
-  move_to_stateCe(stateC, *e);
+  move_to_stateCe(&stateC, e);
   state_stack.push_back(record_current_state());
 
   explore(Ce, D, std::move(A), std::move(exC));
@@ -146,9 +146,9 @@ EventSet UdporChecker::compute_enC(const Configuration& C, const EventSet& exC)
   return enC;
 }
 
-void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
+void UdporChecker::move_to_stateCe(State* state, UnfoldingEvent* e)
 {
-  const aid_t next_actor = e.get_transition()->aid_;
+  const aid_t next_actor = e->get_transition()->aid_;
 
   // TODO: Add the trace if possible for reporting a bug
   xbt_assert(next_actor >= 0, "\n\n****** INVARIANT VIOLATION ******\n"
@@ -156,7 +156,28 @@ void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
                               "one transition of the state of an visited event is enabled, yet no\n"
                               "state was actually enabled. Please report this as a bug.\n"
                               "*********************************\n\n");
-  state.execute_next(next_actor, get_remote_app());
+  auto latest_transition_by_next_actor = state->execute_next(next_actor, get_remote_app());
+
+  // The transition that is associated with the event was just
+  // executed, so it's possible that the new version of the transition
+  // (i.e. the one after execution) has *more* information than
+  // that which existed *prior* to execution.
+  //
+  //
+  // ------- !!!!! UDPOR INVARIANT !!!!! -------
+  //
+  // At this point, we are leveraging the fact that
+  // UDPOR will not contain more than one copy of any
+  // transition executed by any actor for any
+  // particular step taken by that actor. That is,
+  // if transition `i` of the `j`th actor is contained in the
+  // configuration `C` currently under consideration
+  // by UDPOR, then only one and only one copy exists in `C`
+  //
+  // This means that we can referesh the transitions associated
+  // with each event lazily, i.e. only after we have chosen the
+  // event to continue our execution.
+  e->set_transition(std::move(latest_transition_by_next_actor));
 }
 
 void UdporChecker::restore_program_state_with_current_stack()
@@ -181,7 +202,7 @@ std::unique_ptr<State> UdporChecker::record_current_state()
   return next_state;
 }
 
-const UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
+UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
 {
   if (enC.empty()) {
     throw std::invalid_argument("There are no unfolding events to select. "
@@ -190,12 +211,12 @@ const UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet&
   }
 
   if (A.empty()) {
-    return *(enC.begin());
+    return const_cast<UnfoldingEvent*>(*(enC.begin()));
   }
 
   for (const auto& event : A) {
     if (enC.contains(event)) {
-      return event;
+      return const_cast<UnfoldingEvent*>(event);
     }
   }
   return nullptr;
index 6e907a3..6706d2b 100644 (file)
@@ -81,7 +81,7 @@ private:
    * by the UDPOR algorithm to select new events to search. See the original
    * paper [1] for more details
    */
-  const UnfoldingEvent* select_next_unfolding_event(const EventSet& A, const EventSet& enC);
+  UnfoldingEvent* select_next_unfolding_event(const EventSet& A, const EventSet& enC);
 
   /**
    * @brief Computes the sets `ex(C)` and `en(C)` of the given configuration
@@ -113,7 +113,7 @@ private:
   /**
    *
    */
-  void move_to_stateCe(State& stateC, const UnfoldingEvent& e);
+  void move_to_stateCe(State* stateC, UnfoldingEvent* e);
 
   /**
    * @brief Creates a new snapshot of the state of the application
index fb04db5..6532824 100644 (file)
@@ -52,6 +52,8 @@ public:
   Transition* get_transition() const { return this->associated_transition.get(); }
   aid_t get_actor() const { return get_transition()->aid_; }
 
+  void set_transition(std::shared_ptr<Transition> t) { this->associated_transition = std::move(t); }
+
   std::string to_string() const;
 
   bool operator==(const UnfoldingEvent&) const;