#include "src/mc/explo/udpor/History.hpp"
#include "src/mc/explo/udpor/maximal_subsets_iterator.hpp"
+#include <numeric>
#include <xbt/asserts.h>
#include <xbt/log.h>
#include <xbt/string.hpp>
// exploration would lead to a so-called
// "sleep-set blocked" trace.
if (enC.is_subset_of(D)) {
- XBT_DEBUG("en(C) is a subset of the sleep set D (size %zu); if we"
+ XBT_DEBUG("en(C) is a subset of the sleep set D (size %zu); if we "
"kept exploring, we'd hit a sleep-set blocked trace",
D.size());
XBT_DEBUG("The current configuration has %zu elements", C.get_events().size());
for (const auto& [aid, actor_state] : stateC.get_actors_list()) {
for (const auto& transition : actor_state.get_enabled_transitions()) {
+ XBT_DEBUG("\t Considering partial extension for %s", transition->to_string().c_str());
EventSet extension = ExtensionSetCalculator::partially_extend(C, &unfolding, transition);
exC.form_union(extension);
}
void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D)
{
- const EventSet C_union_D = C.get_events().make_union(D);
- const EventSet es_immediate_conflicts = this->unfolding.get_immediate_conflicts_of(e);
- const EventSet Q_CDU = C_union_D.make_union(es_immediate_conflicts.get_local_config());
-
- // Move {e} \ Q_CDU from U to G
- if (not Q_CDU.contains(e)) {
- XBT_DEBUG("Removing %s from U to G...", e->to_string().c_str());
- this->unfolding.remove(e);
- }
-
- // foreach ê in #ⁱ_U(e)
- for (const auto* e_hat : es_immediate_conflicts) {
- // Move [ê] \ Q_CDU from U to G
- const EventSet to_remove = e_hat->get_history().subtracting(Q_CDU);
- XBT_DEBUG("Removing {%s} from U to G...", to_remove.to_string().c_str());
- this->unfolding.remove(to_remove);
- }
+ // // The "clean-up set" conceptually represents
+ // // those events which will no longer be considered
+ // // by UDPOR during its exploration. The concept is
+ // // introduced to avoid modification during iteration
+ // // over the current unfolding to determine who needs to
+ // // be removed. Since sets are unordered, it's quite possible
+ // // that e.g. two events `e` and `e'` such that `e < e'`
+ // // which are determined eligible for removal are removed
+ // // in the order `e` and then `e'`. Determining that `e'`
+ // // needs to be removed requires that its history be in
+ // // tact to e.g. compute the conflicts with the event.
+ // //
+ // // Thus, we compute the set and remove all of the events
+ // // at once in lieu of removing events while iterating over them.
+ // // We can hypothesize that processing the events in reverse
+ // // topological order would prevent any issues concerning
+ // // the order in which are processed
+ // EventSet clean_up_set;
+
+ // // Q_(C, D, U) = C u D u U (complicated expression)
+ // // See page 9 of "Unfolding-based Partial Order Reduction"
+
+ // // "C u D" portion
+ // const EventSet C_union_D = C.get_events().make_union(D);
+
+ // // "U (complicated expression)" portion
+ // const EventSet conflict_union = std::accumulate(
+ // C_union_D.begin(), C_union_D.end(), EventSet(), [&](const EventSet acc, const UnfoldingEvent* e_prime) {
+ // return acc.make_union(unfolding.get_immediate_conflicts_of(e_prime));
+ // });
+
+ // const EventSet Q_CDU = C_union_D.make_union(conflict_union.get_local_config());
+
+ // XBT_DEBUG("Computed Q_CDU as '%s'", Q_CDU.to_string().c_str());
+
+ // // Move {e} \ Q_CDU from U to G
+ // if (not Q_CDU.contains(e)) {
+ // XBT_DEBUG("Moving %s from U to G...", e->to_string().c_str());
+ // clean_up_set.insert(e);
+ // }
+
+ // // foreach ê in #ⁱ_U(e)
+ // for (const auto* e_hat : this->unfolding.get_immediate_conflicts_of(e)) {
+ // // Move [ê] \ Q_CDU from U to G
+ // const EventSet to_remove = e_hat->get_history().subtracting(Q_CDU);
+ // XBT_DEBUG("Moving {%s} from U to G...", to_remove.to_string().c_str());
+ // clean_up_set.form_union(to_remove);
+ // }
+ // // this->unfolding.remove(clean_up_set);
}
RecordTrace UdporChecker::get_record_trace()
#include "src/mc/explo/udpor/udpor_forward.hpp"
+#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <unordered_set>
#include <vector>
+#include <xbt/asserts.h>
namespace simgrid::mc::udpor {
EventSet& operator=(EventSet&&) = default;
EventSet(EventSet&&) = default;
explicit EventSet(Configuration&& config);
- explicit EventSet(std::vector<const UnfoldingEvent*>&& raw_events) : events_(raw_events.begin(), raw_events.end()) {}
- explicit EventSet(std::unordered_set<const UnfoldingEvent*>&& raw_events) : events_(raw_events) {}
- explicit EventSet(std::initializer_list<const UnfoldingEvent*> event_list) : events_(std::move(event_list)) {}
+ explicit EventSet(std::vector<const UnfoldingEvent*>&& raw_events) : events_(raw_events.begin(), raw_events.end())
+ {
+ xbt_assert(std::none_of(events_.begin(), events_.end(), [](const auto* e) { return e == nullptr; }), "Oh no");
+ }
+ explicit EventSet(std::unordered_set<const UnfoldingEvent*>&& raw_events) : events_(raw_events)
+ {
+ xbt_assert(std::none_of(events_.begin(), events_.end(), [](const auto* e) { return e == nullptr; }), "Oh no");
+ }
+ explicit EventSet(std::initializer_list<const UnfoldingEvent*> event_list) : events_(std::move(event_list))
+ {
+ xbt_assert(std::none_of(events_.begin(), events_.end(), [](const auto* e) { return e == nullptr; }), "Oh no");
+ }
auto begin() const { return this->events_.begin(); }
auto end() const { return this->events_.end(); }
// in `C`. The issuer of the `CommWait` in `C` is the event in `C`
// whose transition is the `CommRecv` or `CommSend` whose resulting
// communication this `CommWait` waits on
- const auto issuer = std::find_if(C.begin(), C.end(), [=](const UnfoldingEvent* e) {
+ const auto issuer = std::find_if(C.begin(), C.end(), [&](const UnfoldingEvent* e) {
if (const CommRecvTransition* e_issuer_receive = dynamic_cast<const CommRecvTransition*>(e->get_transition());
e_issuer_receive != nullptr) {
- return wait_comm == e_issuer_receive->get_comm();
+ return e_issuer_receive->aid_ == wait_action->aid_ && wait_comm == e_issuer_receive->get_comm();
}
if (const CommSendTransition* e_issuer_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
e_issuer_send != nullptr) {
- return wait_comm == e_issuer_send->get_comm();
+ return e_issuer_send->aid_ == wait_action->aid_ && wait_comm == e_issuer_send->get_comm();
}
return false;
continue;
}
- const auto issuer_mailbox = e_issuer_send->get_mailbox();
+ const auto issuer_mailbox = e_issuer_recv->get_mailbox();
const CommSendTransition* e_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
if (e_send->get_mailbox() != issuer_mailbox) {
continue;