#include "src/3rd-party/catch.hpp"
#include "src/mc/explo/udpor/EventSet.hpp"
+#include "src/mc/explo/udpor/History.hpp"
#include "src/mc/explo/udpor/UnfoldingEvent.hpp"
#include "src/mc/explo/udpor/udpor_tests_private.hpp"
-#include "src/mc/transition/Transition.hpp"
+#include "src/xbt/utils/iter/LazyPowerset.hpp"
+using namespace simgrid::xbt;
using namespace simgrid::mc::udpor;
TEST_CASE("simgrid::mc::udpor::EventSet: Initial conditions when creating sets")
SECTION("Initialization with one or more elements")
{
- UnfoldingEvent e1, e2, e3;
+ UnfoldingEvent e1;
+ UnfoldingEvent e2;
+ UnfoldingEvent e3;
SECTION("Set initializer")
{
TEST_CASE("simgrid::mc::udpor::EventSet: Insertions")
{
EventSet event_set;
- UnfoldingEvent e1, e2, e3;
+ UnfoldingEvent e1;
+ UnfoldingEvent e2;
+ UnfoldingEvent e3;
SECTION("Inserting unique elements")
{
UnfoldingEvent e2;
UnfoldingEvent e3;
UnfoldingEvent e4;
- EventSet A{&e1, &e2, &e3}, B{&e1, &e2, &e3}, C{&e1, &e2, &e3};
+ EventSet A{&e1, &e2, &e3};
+ EventSet B{&e1, &e2, &e3};
+ EventSet C{&e1, &e2, &e3};
SECTION("Equality implies containment")
{
TEST_CASE("simgrid::mc::udpor::EventSet: Set Union Tests")
{
- UnfoldingEvent e1, e2, e3, e4;
+ UnfoldingEvent e1;
+ UnfoldingEvent e2;
+ UnfoldingEvent e3;
+ UnfoldingEvent e4;
// C = A + B
- EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3};
+ EventSet A{&e1, &e2, &e3};
+ EventSet B{&e2, &e3, &e4};
+ EventSet C{&e1, &e2, &e3, &e4};
+ EventSet D{&e1, &e3};
SECTION("Unions with no effect")
{
{
// A = A union A
EventSet A_union = A.make_union(A);
- REQUIRE(A == A_copy);
+ REQUIRE(A == A_union);
A.form_union(A);
REQUIRE(A == A_copy);
// D is a subset of A and C
// E is a subset of B and C
// F is a subset of A, C, and D
- EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3}, E{&e4}, F{&e1};
+ EventSet A{&e1, &e2, &e3};
+ EventSet B{&e2, &e3, &e4};
+ EventSet C{&e1, &e2, &e3, &e4};
+ EventSet D{&e1, &e3};
+ EventSet E{&e4};
+ EventSet F{&e1};
SECTION("Difference with no effect")
{
TEST_CASE("simgrid::mc::udpor::EventSet: Subset Tests")
{
- UnfoldingEvent e1, e2, e3, e4;
+ UnfoldingEvent e1;
+ UnfoldingEvent e2;
+ UnfoldingEvent e3;
+ UnfoldingEvent e4;
// A is a subset of C only
// B is a subset of C only
// D is NOT a subset of B
// B is NOT a subset of D
// ...
- EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3}, E{&e2, &e3}, F{&e1, &e2, &e3};
+ EventSet A{&e1, &e2, &e3};
+ EventSet B{&e2, &e3, &e4};
+ EventSet C{&e1, &e2, &e3, &e4};
+ EventSet D{&e1, &e3};
+ EventSet E{&e2, &e3};
+ EventSet F{&e1, &e2, &e3};
SECTION("Subset operator properties")
{
// The tests enumerate all possible subsets of the events
// in the structure and test whether those subsets are
// maximal and/or valid configurations
- UnfoldingEvent e1;
- UnfoldingEvent e2{&e1};
- UnfoldingEvent e3{&e2};
- UnfoldingEvent e4{&e2};
- UnfoldingEvent e5{&e1};
- UnfoldingEvent e6{&e5};
+ UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+ UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+ UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+ UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+ UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>(4));
+ UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
SECTION("Valid Configurations")
{
SECTION("No conflicts throughout the whole structure with independent actions")
{
- UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
- UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
- UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
- UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
- UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>());
- UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+ UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+ UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+ UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+ UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>(4));
+ UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
// 6 choose 0 = 1 test
CHECK(EventSet().is_conflict_free());
SECTION("Conditional conflicts")
{
- UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
- UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>());
- UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
- UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
- UnfoldingEvent e5(EventSet({&e1}), std::make_shared<DependentAction>());
- UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+ UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>(1));
+ UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+ UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+ UnfoldingEvent e5(EventSet({&e1}), std::make_shared<DependentAction>(4));
+ UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
// 6 choose 0 = 1 test
// There are no events even to be in conflict with
// 6 choose 6 = 1 test
CHECK_FALSE(EventSet({&e1, &e2, &e3, &e4, &e5, &e6}).is_conflict_free());
}
-}
\ No newline at end of file
+}
+
+TEST_CASE("simgrid::mc::udpor::EventSet: Topological Ordering Property Observed for Every Possible Subset")
+{
+ // The following tests concern the given event structure:
+ // e1
+ // / /
+ // e2 e6
+ // / / /
+ // e3 / /
+ // / / /
+ // e4 e5 e7
+ UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
+ UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e6(EventSet({&e1}), std::make_shared<IndependentAction>());
+ UnfoldingEvent e7(EventSet({&e2, &e6}), std::make_shared<IndependentAction>());
+
+ const EventSet all_events{&e1, &e2, &e3, &e4, &e5, &e6, &e7};
+
+ for (const auto& subset_of_iterators : make_powerset_iter<EventSet>(all_events)) {
+ // Verify that the topological ordering property holds for every subset
+
+ const EventSet subset = [&subset_of_iterators]() {
+ EventSet subset_local;
+ for (const auto& iter : subset_of_iterators) {
+ subset_local.insert(*iter);
+ }
+ return subset_local;
+ }();
+
+ {
+ // To test this, we verify that at each point none of the events
+ // that follow after any particular event `e` are contained in
+ // `e`'s history
+ EventSet invalid_events = subset;
+ const auto ordered_events = subset.get_topological_ordering();
+
+ std::for_each(ordered_events.begin(), ordered_events.end(), [&](const UnfoldingEvent* e) {
+ History history(e);
+ for (auto* e_hist : history) {
+ if (e_hist == e)
+ continue;
+ REQUIRE_FALSE(invalid_events.contains(e_hist));
+ }
+ invalid_events.remove(e);
+ });
+ }
+ {
+ // To test this, we verify that at each point none of the events
+ // that we've processed in the ordering are ever seen again
+ // in anybody else's history
+ EventSet events_seen;
+ const auto ordered_events = subset.get_topological_ordering_of_reverse_graph();
+
+ std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
+ History history(e);
+
+ for (auto* e_hist : history) {
+ // Unlike the test above, we DO want to ensure
+ // that `e` itself ALSO isn't yet seen
+
+ // If this event has been "seen" before,
+ // this implies that event `e` appears later
+ // in the list than one of its ancestors
+ REQUIRE_FALSE(events_seen.contains(e_hist));
+ }
+ events_seen.insert(e);
+ });
+ }
+ }
+}