Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add initial outline of SDPOR implementation
[simgrid.git] / src / mc / explo / odpor / Execution.hpp
index 62af981..fc75fa9 100644 (file)
@@ -7,18 +7,19 @@
 #define SIMGRID_MC_ODPOR_EXECUTION_HPP
 
 #include "src/mc/api/ClockVector.hpp"
+#include "src/mc/explo/odpor/odpor_forward.hpp"
 #include "src/mc/transition/Transition.hpp"
 
+#include <list>
+#include <optional>
 #include <unordered_set>
 #include <vector>
 
 namespace simgrid::mc::odpor {
 
-/**
- * @brief An ordered sequence of actions
- */
-class ExecutionSequence : public std::list<const Transition*> {};
-using Hypothetical = ExecutionSequence;
+using ProcessSequence   = std::list<aid_t>;
+using ExecutionSequence = std::list<const State*>;
+using Hypothetical      = ExecutionSequence;
 
 /**
  * @brief The occurrence of a transition in an execution
@@ -27,22 +28,28 @@ class Event {
   std::pair<const Transition*, ClockVector> contents_;
 
 public:
-  Event()                         = default;
-  Event(Event&&)                  = default;
-  Event(const Event&)             = default;
-  Event& operator=(const Event&)  = default;
-  Event& operator=(const Event&&) = default;
+  Event()                        = default;
+  Event(Event&&)                 = default;
+  Event(const Event&)            = default;
+  Event& operator=(const Event&) = default;
 
   explicit Event(std::pair<const Transition*, ClockVector> pair) : contents_(std::move(pair)) {}
 
-  const Transition* get_transition() const { return contents_.get<0>(); }
-  const ClockVector& get_clock_vector() const { return contents_.get<1>(); }
-}
+  const Transition* get_transition() const { return std::get<0>(contents_); }
+  const ClockVector& get_clock_vector() const { return std::get<1>(contents_); }
+};
 
 /**
  * @brief An ordered sequence of transitions which describe
  * the evolution of a process undergoing model checking
  *
+ * An execution conceptually is just a string of actors
+ * ids (e.g. "1.2.3.1.2.2.1.1"), where the `i`th occurrence
+ * of actor id `j` corresponds to the `i`th action executed
+ * by the actor with id `j` (viz. the `i`th step of actor `j`).
+ * Executions can stand alone on their own or can extend
+ * the execution of other sequences
+ *
  * Executions are conceived based on the following papers:
  * 1. "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction"
  * by Abdulla et al.
@@ -68,17 +75,21 @@ class Execution {
 private:
   /**
    * @brief The actual steps that are taken by the process
-   * during exploration.
+   * during exploration, relative to the
    */
-  std::list<Event> contents_;
+  std::vector<Event> contents_;
 
 public:
+  using Handle      = decltype(contents_)::const_iterator;
+  using EventHandle = uint32_t;
+
   Execution()                            = default;
   Execution(const Execution&)            = default;
   Execution& operator=(Execution const&) = default;
   Execution(Execution&&)                 = default;
-  explicit Execution(ExecutionSequence&& seq);
-  explicit Execution(const ExecutionSequence& seq);
+
+  Execution(ExecutionSequence&& seq, std::optional<Handle> base = {});
+  Execution(const ExecutionSequence& seq, std::optional<Handle> base = {});
 
   std::unordered_set<aid_t> get_initials_after(const Hypothetical& w) const;
   std::unordered_set<aid_t> get_weak_initials_after(const Hypothetical& w) const;
@@ -86,7 +97,65 @@ public:
   bool is_initial(aid_t p, const Hypothetical& w) const;
   bool is_weak_initial(aid_t p, const Hypothetical& w) const;
 
-  void take_action(const Transition*);
+  const Event& get_event_with_handle(EventHandle handle) const { return contents_[handle]; }
+  aid_t get_actor_with_handle(EventHandle handle) const { return get_event_with_handle(handle).get_transition()->aid_; }
+
+  /**
+   * @brief Returns a set of IDs of events which are in
+   * "immediate conflict" (according to the definition given
+   * in the ODPOR paper) with one another
+   */
+  std::unordered_set<EventHandle> get_racing_events_of(EventHandle) const;
+
+  /**
+   * @brief Returns a handle to the newest event of the execution,
+   * if such an event exists
+   */
+  std::optional<EventHandle> get_latest_event_handle() const
+  {
+    return contents_.empty() ? std::nullopt : std::optional<EventHandle>{static_cast<EventHandle>(size() - 1)};
+  }
+
+  Execution get_prefix_up_to(EventHandle);
+
+  /**
+   * @brief Whether the event represented by `e1`
+   * "happens-before" the event represented by
+   * `e2` in the context of this execution
+   *
+   * In the terminology of the ODPOR paper,
+   * this function computes
+   *
+   * `e1 --->_E e2`
+   *
+   * where `E` is this execution
+   */
+  bool happens_before(EventHandle e1, EventHandle e2) const;
+
+  /**
+   * @brief Removes the last event of the execution,
+   * if such an event exists
+   *
+   * @note: When you remove events from an execution, any views
+   * of the execution referring to those removed events
+   * become invalidated
+   */
+  void pop_latest();
+
+  /**
+   * @brief Extends the execution by one more step
+   *
+   * Intutively, pushing a transition `t` onto execution `E`
+   * is equivalent to making the execution become (using the
+   * notation of [1]) `E.proc(t)` where `proc(t)` is the
+   * actor which executed transition `t`.
+   */
+  void push_transition(const Transition*);
+
+  /**
+   * @brief The total number of steps contained in the execution
+   */
+  size_t size() const { return this->contents_.size(); }
 };
 
 } // namespace simgrid::mc::odpor