Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add skeleton implementation for ex(C) for CommSend
authorMaxwell Pirtle <maxwellpirtle@gmail.com>
Tue, 21 Mar 2023 09:13:42 +0000 (10:13 +0100)
committerMaxwell Pirtle <maxwellpirtle@gmail.com>
Wed, 5 Apr 2023 08:37:20 +0000 (10:37 +0200)
src/mc/explo/UdporChecker.cpp
src/mc/explo/udpor/EventSet.cpp
src/mc/explo/udpor/EventSet.hpp
src/mc/explo/udpor/ExtensionSetCalculator.cpp
src/mc/explo/udpor/ExtensionSetCalculator.hpp
src/mc/explo/udpor/History.hpp
src/mc/explo/udpor/Unfolding.hpp
src/mc/explo/udpor/UnfoldingEvent.cpp
src/mc/explo/udpor/UnfoldingEvent.hpp

index 2ff083a..3bac813 100644 (file)
@@ -129,7 +129,7 @@ EventSet UdporChecker::compute_exC(const Configuration& C, const State& stateC,
 
   for (const auto& [aid, actor_state] : stateC.get_actors_list()) {
     for (const auto& transition : actor_state.get_enabled_transitions()) {
-      EventSet extension = ExtensionSetCalculator::partially_extend(C, unfolding, transition);
+      EventSet extension = ExtensionSetCalculator::partially_extend(C, &unfolding, transition);
       exC.form_union(extension);
     }
   }
index 09cb66b..c8b2ae2 100644 (file)
@@ -142,13 +142,18 @@ bool EventSet::intersects(const History& history) const
   return std::any_of(history.begin(), history.end(), [=](const UnfoldingEvent* e) { return this->contains(e); });
 }
 
+EventSet EventSet::get_largest_maximal_subset() const
+{
+  const History history(*this);
+  return history.get_all_maximal_events();
+}
+
 bool EventSet::is_maximal() const
 {
   // A set of events is maximal if no event from
   // the original set is ruled out when traversing
   // the history of the events
-  const History history(*this);
-  return *this == history.get_all_maximal_events();
+  return *this == this->get_largest_maximal_subset();
 }
 
 bool EventSet::is_conflict_free() const
index 54c00c8..18fb0d6 100644 (file)
@@ -104,6 +104,12 @@ public:
    */
   bool is_conflict_free() const;
 
+  /**
+   * @brief Produces the largest subset of this
+   * set of events which is maximal
+   */
+  EventSet get_largest_maximal_subset() const;
+
   /**
    * @brief Orders the events of the set such that
    * "more recent" events (i.e. those that are farther down in
index e5b9a18..c2e793a 100644 (file)
@@ -4,6 +4,9 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/explo/udpor/ExtensionSetCalculator.hpp"
+#include "src/mc/explo/udpor/Configuration.hpp"
+#include "src/mc/explo/udpor/History.hpp"
+#include "src/mc/explo/udpor/Unfolding.hpp"
 
 #include <functional>
 #include <unordered_map>
@@ -14,7 +17,7 @@ using namespace simgrid::mc;
 
 namespace simgrid::mc::udpor {
 
-EventSet ExtensionSetCalculator::partially_extend(const Configuration& C, const Unfolding& U,
+EventSet ExtensionSetCalculator::partially_extend(const Configuration& C, Unfolding* U,
                                                   const std::shared_ptr<Transition> action)
 {
   switch (action->type_) {
@@ -41,28 +44,97 @@ EventSet ExtensionSetCalculator::partially_extend(const Configuration& C, const
   }
 }
 
-EventSet ExtensionSetCalculator::partially_extend_CommSend(const Configuration& C, const Unfolding& U,
-                                                           const std::shared_ptr<CommSendTransition> action)
+EventSet ExtensionSetCalculator::partially_extend_CommSend(const Configuration& C, Unfolding* U,
+                                                           const std::shared_ptr<CommSendTransition> send_action)
 {
-  return EventSet();
+  EventSet exC;
+
+  // TODO: if this is the first action by the actor, no such previous event exists.
+  // How do we react here? Do we say we're dependent with the root event?
+  const unsigned sender_mailbox = send_action->get_mailbox();
+  const auto pre_event_a_C      = C.pre_event(send_action->aid_).value();
+
+  // 1. Create `e' := <a, config(preEvt(a, C))>` and add `e'` to `ex(C)`
+  const auto e_prime = U->discover_event(EventSet({pre_event_a_C}), send_action);
+  exC.insert(e_prime);
+
+  // 2. foreach e ∈ C s.t. λ(e) ∈ {AsyncSend(m, _), TestAny(Com)} where
+  // Com contains a matching c' = AsyncReceive(m, _) with a
+  for (const auto e : C) {
+    const bool transition_type_check = [&]() {
+      if (const auto* async_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+          e != nullptr && async_send->get_mailbox() == sender_mailbox) {
+        return true;
+      } else if (const auto* e_test_any = dynamic_cast<const CommTestTransition*>(e->get_transition());
+                 e_test_any != nullptr) {
+        // TODO: Check if there's a way to find a matching AsyncReceive -> matching when? in the history?
+        return true;
+      }
+      return false;
+    }();
+
+    if (transition_type_check) {
+      const EventSet K = EventSet({e, pre_event_a_C}).get_largest_maximal_subset();
+
+      // TODO: How do we compute D_K(a, b)? There's a specialized
+      // function for each case it appears, but I don't see where
+      // `config(K)` comes in
+      if (false) {
+        const auto e_prime = U->discover_event(std::move(K), send_action);
+        exC.insert(e_prime);
+      }
+    }
+  }
+
+  return exC;
 }
 
-EventSet ExtensionSetCalculator::partially_extend_CommRecv(const Configuration& C, const Unfolding& U,
-                                                           const std::shared_ptr<CommRecvTransition> action)
+EventSet ExtensionSetCalculator::partially_extend_CommRecv(const Configuration& C, Unfolding* U,
+                                                           const std::shared_ptr<CommRecvTransition> recv_action)
 {
   return EventSet();
 }
 
-EventSet ExtensionSetCalculator::partially_extend_CommWait(const Configuration&, const Unfolding& U,
-                                                           std::shared_ptr<CommWaitTransition>)
+EventSet ExtensionSetCalculator::partially_extend_CommWait(const Configuration&, Unfolding* U,
+                                                           std::shared_ptr<CommWaitTransition> wait_action)
 {
   return EventSet();
 }
 
-EventSet ExtensionSetCalculator::partially_extend_CommTest(const Configuration&, const Unfolding& U,
-                                                           std::shared_ptr<CommTestTransition>)
+EventSet ExtensionSetCalculator::partially_extend_CommTest(const Configuration&, Unfolding* U,
+                                                           std::shared_ptr<CommTestTransition> test_action)
 {
   return EventSet();
+  // EventSet exC;
+
+  // // TODO: if this is the first action by the actor, no such previous event exists.
+  // // How do we react here? Do we say we're dependent with the root event?
+  // const auto tested_mailbox = test_action->get_mailbox();
+  // const auto pre_event_a_C  = C.pre_event(send_action->aid_).value();
+
+  // for (const auto e : C) {
+  //   if (e == pre_event_a_C) {
+  //     const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), action);
+  //     exC.insert(e_prime);
+  //   } else {
+  //     // TODO: Check condition
+  //     const bool should_process = [&]() { return false; }();
+
+  //     EventSet K;
+  //     if (not(e < pre_event_a_C))
+  //       K.insert(e);
+  //     if (not(pre_event_a_C < e))
+  //       K.insert(pre_event_a_C);
+
+  //     // TODO: How do we compute D_K(a, b)? There's a specialized
+  //     // function for each case it appears, but I don't see where
+  //     // `config(K)` comes in
+  //     if (should_process) {
+  //       const auto e_prime = U->discover_event(std::move(K), action);
+  //       exC.insert(e_prime);
+  //     }
+  //   }
+  // }
 }
 
 } // namespace simgrid::mc::udpor
\ No newline at end of file
index 95d06fe..67303b1 100644 (file)
@@ -25,17 +25,13 @@ namespace simgrid::mc::udpor {
  */
 struct ExtensionSetCalculator final {
 private:
-  static EventSet partially_extend_CommSend(const Configuration&, const Unfolding&,
-                                            std::shared_ptr<CommSendTransition>);
-  static EventSet partially_extend_CommRecv(const Configuration&, const Unfolding&,
-                                            std::shared_ptr<CommRecvTransition>);
-  static EventSet partially_extend_CommWait(const Configuration&, const Unfolding&,
-                                            std::shared_ptr<CommWaitTransition>);
-  static EventSet partially_extend_CommTest(const Configuration&, const Unfolding&,
-                                            std::shared_ptr<CommTestTransition>);
+  static EventSet partially_extend_CommSend(const Configuration&, Unfolding*, std::shared_ptr<CommSendTransition>);
+  static EventSet partially_extend_CommRecv(const Configuration&, Unfolding*, std::shared_ptr<CommRecvTransition>);
+  static EventSet partially_extend_CommWait(const Configuration&, Unfolding*, std::shared_ptr<CommWaitTransition>);
+  static EventSet partially_extend_CommTest(const Configuration&, Unfolding*, std::shared_ptr<CommTestTransition>);
 
 public:
-  static EventSet partially_extend(const Configuration&, const Unfolding&, const std::shared_ptr<Transition>);
+  static EventSet partially_extend(const Configuration&, Unfolding*, const std::shared_ptr<Transition>);
 };
 
 } // namespace simgrid::mc::udpor
index da35244..c5e6087 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <boost/iterator/iterator_facade.hpp>
 #include <functional>
+#include <initializer_list>
 #include <optional>
 
 namespace simgrid::mc::udpor {
@@ -54,8 +55,9 @@ public:
   History& operator=(History const&) = default;
   History(History&&)                 = default;
 
-  explicit History(EventSet event_set = EventSet()) : events_(std::move(event_set)) {}
   explicit History(const UnfoldingEvent* e) : events_({e}) {}
+  explicit History(EventSet event_set = EventSet()) : events_(std::move(event_set)) {}
+  explicit History(std::initializer_list<const UnfoldingEvent*> list) : events_(std::move(list)) {}
 
   auto begin() const { return Iterator(events_); }
   auto end() const { return Iterator(EventSet()); }
index 1c6ff6c..8f58486 100644 (file)
@@ -36,7 +36,42 @@ public:
   /// in the unfolding
   const UnfoldingEvent* insert(std::unique_ptr<UnfoldingEvent> e);
 
-  /// @brief Computes "#ⁱ_U(e)" for the given event
+  /**
+   * @brief Informs the unfolding of a (potentially) new event
+   *
+   * The unfolding of a concurrent program is a well-defined
+   * structure. Given the labeled transition system (LTS) of
+   * a program, the unfolding of that program can be determined
+   * algorithmically. However, UDPOR does not a priori know the structure of the
+   * unfolding as it performs its exploration. Thus, events in the
+   * unfolding are "discovered" as they are encountered, specifically
+   * when computing the extension sets of the configurations that
+   * UDPOR decides to search.
+   *
+   * This lends itself to the following problem: the extension sets
+   * of two different configurations may overlap one another. That
+   * is, for two configurations C and C' explored by UDPOR where C != C',
+   *
+   * ex(C) - ex(C') != empty
+   *
+   * Hence, when extending both `C` and `C'`, any events contained in
+   * the intersection of ex(C) and ex(C') will be attempted to be added
+   * twice. The unfolding will notice that these events have already
+   * been added and simply return the event already added to the unfolding
+   *
+   * @tparam ...Args arguments passed to the `UnfoldingEvent` constructor
+   * @return the handle to either the newly created event OR
+   * to an equivalent event that was already noted by the unfolding
+   * at some point in the past
+   */
+  template <typename... Args> const UnfoldingEvent* discover_event(Args... args)
+  {
+    auto candidate_event = std::make_unique<UnfoldingEvent>(std::forward<Args>(args)...);
+    return insert(std::move(candidate_event));
+  }
+
+  /// @brief Computes "#ⁱ_U(e)" for the given event, where `U` is the set
+  /// of the events in this unfolding
   EventSet get_immediate_conflicts_of(const UnfoldingEvent*) const;
 
 private:
@@ -44,7 +79,7 @@ private:
    * @brief All of the events that are currently are a part of the unfolding
    *
    * @invariant Each unfolding event maps itself to the owner of that event,
-   * i.e. the unique pointer that owns the address. The Unfolding owns all
+   * i.e. the unique pointer that manages the data at the address. The Unfolding owns all
    * of the addresses that are referenced by EventSet instances and Configuration
    * instances. UDPOR guarantees that events are persisted for as long as necessary
    */
@@ -55,6 +90,8 @@ private:
    *
    * @invariant: All of the events in this set are elements of `global_events_`
    * and is kept updated at the same time as `global_events_`
+   *
+   * @note: This is for the convenience of iteration over the unfolding
    */
   EventSet event_handles;
 
index c51023b..e143e62 100644 (file)
@@ -20,6 +20,10 @@ UnfoldingEvent::UnfoldingEvent(EventSet immediate_causes, std::shared_ptr<Transi
 
 bool UnfoldingEvent::operator==(const UnfoldingEvent& other) const
 {
+  // Intrinsic identity check
+  if (this == &other) {
+    return true;
+  }
   // Two events are equivalent iff:
   // 1. they have the same action
   // 2. they have the same history
index 442aabe..ff93813 100644 (file)
@@ -28,6 +28,11 @@ public:
 
   EventSet get_history() const;
   bool in_history_of(const UnfoldingEvent* other) const;
+
+  /**
+   * @brief Whether or not the given event is a decendant
+   * of or an ancestor of the given event
+   */
   bool related_to(const UnfoldingEvent* other) const;
 
   /// @brief Whether or not this event is in conflict with