1 /* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "src/3rd-party/catch.hpp"
7 #include "src/mc/explo/udpor/Configuration.hpp"
8 #include "src/mc/explo/udpor/EventSet.hpp"
9 #include "src/mc/explo/udpor/History.hpp"
10 #include "src/mc/explo/udpor/UnfoldingEvent.hpp"
11 #include "src/mc/explo/udpor/maximal_subsets_iterator.hpp"
12 #include "src/mc/explo/udpor/udpor_tests_private.hpp"
14 #include <unordered_map>
16 using namespace simgrid::mc::udpor;
18 TEST_CASE("simgrid::mc::udpor::Configuration: Constructing Configurations")
20 // The following tests concern the given event structure:
28 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
29 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
30 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
31 UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
32 UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
34 SECTION("Creating a configuration without events")
37 REQUIRE(C.get_events().empty());
38 REQUIRE(C.get_latest_event() == nullptr);
41 SECTION("Creating a configuration with events (test violation of being causally closed)")
43 // 5 choose 0 = 1 test
44 REQUIRE_NOTHROW(Configuration({&e1}));
46 // 5 choose 1 = 5 tests
47 REQUIRE_THROWS_AS(Configuration({&e2}), std::invalid_argument);
48 REQUIRE_THROWS_AS(Configuration({&e3}), std::invalid_argument);
49 REQUIRE_THROWS_AS(Configuration({&e4}), std::invalid_argument);
50 REQUIRE_THROWS_AS(Configuration({&e5}), std::invalid_argument);
52 // 5 choose 2 = 10 tests
53 REQUIRE_NOTHROW(Configuration({&e1, &e2}));
54 REQUIRE_THROWS_AS(Configuration({&e1, &e3}), std::invalid_argument);
55 REQUIRE_THROWS_AS(Configuration({&e1, &e4}), std::invalid_argument);
56 REQUIRE_THROWS_AS(Configuration({&e1, &e5}), std::invalid_argument);
57 REQUIRE_THROWS_AS(Configuration({&e2, &e3}), std::invalid_argument);
58 REQUIRE_THROWS_AS(Configuration({&e2, &e4}), std::invalid_argument);
59 REQUIRE_THROWS_AS(Configuration({&e2, &e5}), std::invalid_argument);
60 REQUIRE_THROWS_AS(Configuration({&e3, &e4}), std::invalid_argument);
61 REQUIRE_THROWS_AS(Configuration({&e3, &e5}), std::invalid_argument);
62 REQUIRE_THROWS_AS(Configuration({&e4, &e5}), std::invalid_argument);
64 // 5 choose 3 = 10 tests
65 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3}));
66 REQUIRE_THROWS_AS(Configuration({&e1, &e2, &e4}), std::invalid_argument);
67 REQUIRE_THROWS_AS(Configuration({&e1, &e2, &e5}), std::invalid_argument);
68 REQUIRE_THROWS_AS(Configuration({&e1, &e3, &e4}), std::invalid_argument);
69 REQUIRE_THROWS_AS(Configuration({&e1, &e3, &e5}), std::invalid_argument);
70 REQUIRE_THROWS_AS(Configuration({&e1, &e4, &e5}), std::invalid_argument);
71 REQUIRE_THROWS_AS(Configuration({&e2, &e3, &e4}), std::invalid_argument);
72 REQUIRE_THROWS_AS(Configuration({&e2, &e3, &e5}), std::invalid_argument);
73 REQUIRE_THROWS_AS(Configuration({&e2, &e4, &e5}), std::invalid_argument);
74 REQUIRE_THROWS_AS(Configuration({&e3, &e4, &e5}), std::invalid_argument);
76 // 5 choose 4 = 5 tests
77 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4}));
78 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e5}));
79 REQUIRE_THROWS_AS(Configuration({&e1, &e2, &e4, &e5}), std::invalid_argument);
80 REQUIRE_THROWS_AS(Configuration({&e1, &e3, &e4, &e5}), std::invalid_argument);
81 REQUIRE_THROWS_AS(Configuration({&e2, &e3, &e4, &e5}), std::invalid_argument);
83 // 5 choose 5 = 1 test
84 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4, &e5}));
88 TEST_CASE("simgrid::mc::udpor::Configuration: Adding Events")
90 // The following tests concern the given event structure:
97 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
98 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
99 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
100 UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
102 REQUIRE_THROWS_AS(Configuration().add_event(nullptr), std::invalid_argument);
103 REQUIRE_THROWS_AS(Configuration().add_event(&e2), std::invalid_argument);
104 REQUIRE_THROWS_AS(Configuration().add_event(&e3), std::invalid_argument);
105 REQUIRE_THROWS_AS(Configuration().add_event(&e4), std::invalid_argument);
106 REQUIRE_THROWS_AS(Configuration({&e1}).add_event(&e3), std::invalid_argument);
107 REQUIRE_THROWS_AS(Configuration({&e1}).add_event(&e4), std::invalid_argument);
109 REQUIRE_NOTHROW(Configuration().add_event(&e1));
110 REQUIRE_NOTHROW(Configuration({&e1}).add_event(&e1));
111 REQUIRE_NOTHROW(Configuration({&e1}).add_event(&e2));
112 REQUIRE_NOTHROW(Configuration({&e1, &e2}).add_event(&e1));
113 REQUIRE_NOTHROW(Configuration({&e1, &e2}).add_event(&e2));
114 REQUIRE_NOTHROW(Configuration({&e1, &e2}).add_event(&e3));
115 REQUIRE_NOTHROW(Configuration({&e1, &e2}).add_event(&e4));
116 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3}).add_event(&e1));
117 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3}).add_event(&e2));
118 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3}).add_event(&e3));
119 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3}).add_event(&e4));
120 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e4}).add_event(&e1));
121 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e4}).add_event(&e2));
122 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e4}).add_event(&e3));
123 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e4}).add_event(&e4));
124 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4}).add_event(&e1));
125 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4}).add_event(&e2));
126 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4}).add_event(&e3));
127 REQUIRE_NOTHROW(Configuration({&e1, &e2, &e3, &e4}).add_event(&e4));
130 TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order")
132 // The following tests concern the given event structure:
140 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
141 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
142 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
143 UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
145 SECTION("Topological ordering for entire set")
147 Configuration C{&e1, &e2, &e3, &e4};
148 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4});
149 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
150 std::vector<const UnfoldingEvent*>{&e4, &e3, &e2, &e1});
153 SECTION("Topological ordering for subsets")
155 SECTION("No elements")
158 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{});
159 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{});
164 Configuration C{&e1};
165 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1});
166 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{&e1});
169 SECTION("e1 and e2 only")
171 Configuration C{&e1, &e2};
172 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2});
173 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{&e2, &e1});
176 SECTION("e1, e2, and e3 only")
178 Configuration C{&e1, &e2, &e3};
179 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3});
180 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
181 std::vector<const UnfoldingEvent*>{&e3, &e2, &e1});
186 TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order More Complicated")
188 // The following tests concern the given event structure:
198 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
199 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
200 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
201 UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
202 UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>());
203 UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>());
205 SECTION("Topological ordering for subsets")
207 SECTION("No elements")
210 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{});
211 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{});
216 Configuration C{&e1};
217 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1});
218 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{&e1});
221 SECTION("e1 and e2 only")
223 Configuration C{&e1, &e2};
224 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2});
225 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() == std::vector<const UnfoldingEvent*>{&e2, &e1});
228 SECTION("e1, e2, and e3 only")
230 Configuration C{&e1, &e2, &e3};
231 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3});
232 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
233 std::vector<const UnfoldingEvent*>{&e3, &e2, &e1});
236 SECTION("e1, e2, e3, and e6 only")
238 Configuration C{&e1, &e2, &e3, &e6};
239 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e6});
240 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
241 std::vector<const UnfoldingEvent*>{&e6, &e3, &e2, &e1});
244 SECTION("e1, e2, e3, and e4 only")
246 Configuration C{&e1, &e2, &e3, &e4};
247 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4});
248 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
249 std::vector<const UnfoldingEvent*>{&e4, &e3, &e2, &e1});
252 SECTION("e1, e2, e3, e4, and e5 only")
254 Configuration C{&e1, &e2, &e3, &e4, &e5};
255 REQUIRE(C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4, &e5});
256 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
257 std::vector<const UnfoldingEvent*>{&e5, &e4, &e3, &e2, &e1});
260 SECTION("e1, e2, e3, e4 and e6 only")
262 // In this case, e4 and e6 are interchangeable. Hence, we have to check
263 // if the sorting gives us *any* of the combinations
264 Configuration C{&e1, &e2, &e3, &e4, &e6};
265 REQUIRE((C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4, &e6} ||
266 C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e6, &e4}));
267 REQUIRE((C.get_topologically_sorted_events_of_reverse_graph() ==
268 std::vector<const UnfoldingEvent*>{&e6, &e4, &e3, &e2, &e1} ||
269 C.get_topologically_sorted_events_of_reverse_graph() ==
270 std::vector<const UnfoldingEvent*>{&e4, &e6, &e3, &e2, &e1}));
273 SECTION("Topological ordering for entire set")
275 // In this case, e4/e5 are both interchangeable with e6. Hence, again we have to check
276 // if the sorting gives us *any* of the combinations
277 Configuration C{&e1, &e2, &e3, &e4, &e5, &e6};
279 (C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4, &e5, &e6} ||
280 C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e4, &e6, &e5} ||
281 C.get_topologically_sorted_events() == std::vector<const UnfoldingEvent*>{&e1, &e2, &e3, &e6, &e4, &e5}));
282 REQUIRE((C.get_topologically_sorted_events_of_reverse_graph() ==
283 std::vector<const UnfoldingEvent*>{&e6, &e5, &e4, &e3, &e2, &e1} ||
284 C.get_topologically_sorted_events_of_reverse_graph() ==
285 std::vector<const UnfoldingEvent*>{&e5, &e6, &e4, &e3, &e2, &e1} ||
286 C.get_topologically_sorted_events_of_reverse_graph() ==
287 std::vector<const UnfoldingEvent*>{&e5, &e4, &e6, &e3, &e2, &e1}));
292 TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order Very Complicated")
294 // The following tests concern the given event structure:
307 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
308 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
309 UnfoldingEvent e8(EventSet({&e1}), std::make_shared<IndependentAction>());
310 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
311 UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
312 UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>());
313 UnfoldingEvent e6(EventSet({&e4}), std::make_shared<IndependentAction>());
314 UnfoldingEvent e7(EventSet({&e2, &e8}), std::make_shared<IndependentAction>());
315 UnfoldingEvent e9(EventSet({&e6, &e7}), std::make_shared<IndependentAction>());
316 UnfoldingEvent e10(EventSet({&e7}), std::make_shared<IndependentAction>());
317 UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>());
318 UnfoldingEvent e12(EventSet({&e5, &e9, &e10}), std::make_shared<IndependentAction>());
319 Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12};
321 SECTION("Test every combination of the maximal configuration (forward graph)")
323 // To test this, we ensure that for the `i`th event
324 // in `ordered_events`, each event in `ordered_events[0...<i]
325 // is contained in the history of `ordered_events[i]`.
326 EventSet events_seen;
327 const auto ordered_events = C.get_topologically_sorted_events();
329 std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
331 for (auto* e_hist : history) {
332 // In this demo, we want to make sure that
333 // we don't mark not yet seeing `e` as an error.
334 // The history of `e` traverses `e` itself. All
335 // other events in e's history are included in
339 // If this event has not been "seen" before,
340 // this implies that event `e` appears earlier
341 // in the list than one of its dependencies
342 REQUIRE(events_seen.contains(e_hist));
344 events_seen.insert(e);
348 SECTION("Test every combination of the maximal configuration (reverse graph)")
350 // To test this, we ensure that for the `i`th event
351 // in `ordered_events`, no event in `ordered_events[0...<i]
352 // is contained in the history of `ordered_events[i]`.
353 EventSet events_seen;
354 const auto ordered_events = C.get_topologically_sorted_events_of_reverse_graph();
356 std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
359 for (auto* e_hist : history) {
360 // Unlike the test above, we DO want to ensure
361 // that `e` itself ALSO isn't yet seen
363 // If this event has been "seen" before,
364 // this implies that event `e` appears later
365 // in the list than one of its ancestors
366 REQUIRE_FALSE(events_seen.contains(e_hist));
368 events_seen.insert(e);
372 SECTION("Test that the topological ordering contains only the events of the configuration")
374 const EventSet events_seen = C.get_events();
376 SECTION("Forward direction")
378 auto ordered_events = C.get_topologically_sorted_events();
379 const EventSet ordered_event_set = EventSet(std::move(ordered_events));
380 REQUIRE(events_seen == ordered_event_set);
383 SECTION("Reverse direction")
385 auto ordered_events = C.get_topologically_sorted_events_of_reverse_graph();
386 const EventSet ordered_event_set = EventSet(std::move(ordered_events));
387 REQUIRE(events_seen == ordered_event_set);
391 SECTION("Test that the topological ordering is equivalent to that of the configuration's events")
393 REQUIRE(C.get_topologically_sorted_events() == C.get_events().get_topological_ordering());
394 REQUIRE(C.get_topologically_sorted_events_of_reverse_graph() ==
395 C.get_events().get_topological_ordering_of_reverse_graph());
399 TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Basic Testing of Maximal Subsets")
401 // The following tests concern the given event structure:
409 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
410 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
411 UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
412 UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
413 UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>());
414 UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
415 UnfoldingEvent e7(EventSet({&e6}), std::make_shared<IndependentAction>());
416 UnfoldingEvent e8(EventSet({&e6}), std::make_shared<IndependentAction>());
418 SECTION("Iteration over an empty configuration yields only the empty set")
421 maximal_subsets_iterator first(C);
422 maximal_subsets_iterator last;
424 REQUIRE(*first == EventSet());
426 REQUIRE(first == last);
429 SECTION("Check counts of maximal event sets discovered")
431 std::unordered_map<int, int> maximal_subset_counts;
433 Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8};
434 maximal_subsets_iterator first(C);
435 maximal_subsets_iterator last;
437 for (; first != last; ++first) {
438 maximal_subset_counts[(*first).size()]++;
441 // First, ensure that there are only sets of size 0, 1, 2, and 3
442 CHECK(maximal_subset_counts.size() == 4);
444 // The empty set should appear only once
445 REQUIRE(maximal_subset_counts[0] == 1);
447 // 8 is the number of nodes in the graph
448 REQUIRE(maximal_subset_counts[1] == 8);
450 // 13 = 3 * 4 (each of the left branch can combine with one in the right branch) + 1 (e7 + e8)
451 REQUIRE(maximal_subset_counts[2] == 13);
453 // e7 + e8 must be included, so that means we can combine from the left branch
454 REQUIRE(maximal_subset_counts[3] == 3);
457 SECTION("Check counts of maximal event sets discovered with a filter")
459 std::unordered_map<int, int> maximal_subset_counts;
461 Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8};
463 SECTION("Filter with events part of initial maximal set")
465 EventSet interesting_bunch{&e2, &e4, &e7, &e8};
467 maximal_subsets_iterator first(C, [&](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
468 maximal_subsets_iterator last;
470 for (; first != last; ++first) {
471 const auto& event_set = *first;
472 // Only events in `interesting_bunch` can appear: thus no set
473 // should include anything else other than `interesting_bunch`
474 REQUIRE(event_set.is_subset_of(interesting_bunch));
475 REQUIRE(event_set.is_maximal());
476 maximal_subset_counts[event_set.size()]++;
479 // The empty set should (still) appear only once
480 REQUIRE(maximal_subset_counts[0] == 1);
482 // 4 is the number of nodes in the `interesting_bunch`
483 REQUIRE(maximal_subset_counts[1] == 4);
485 // 5 = 2 * 2 (each of the left branch can combine with one in the right branch) + 1 (e7 + e8)
486 REQUIRE(maximal_subset_counts[2] == 5);
488 // e7 + e8 must be included, so that means we can combine from the left branch (only e2 and e4)
489 REQUIRE(maximal_subset_counts[3] == 2);
491 // There are no subsets of size 4 (or higher, but that
492 // is tested by asserting each maximal set traversed is a subset)
493 REQUIRE(maximal_subset_counts[4] == 0);
496 SECTION("Filter with interesting subset not initially part of the maximal set")
498 EventSet interesting_bunch{&e3, &e5, &e6};
500 maximal_subsets_iterator first(C, [&](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
501 maximal_subsets_iterator last;
503 for (; first != last; ++first) {
504 const auto& event_set = *first;
505 // Only events in `interesting_bunch` can appear: thus no set
506 // should include anything else other than `interesting_bunch`
507 REQUIRE(event_set.is_subset_of(interesting_bunch));
508 REQUIRE(event_set.is_maximal());
509 maximal_subset_counts[event_set.size()]++;
512 // The empty set should (still) appear only once
513 REQUIRE(maximal_subset_counts[0] == 1);
515 // 3 is the number of nodes in the `interesting_bunch`
516 REQUIRE(maximal_subset_counts[1] == 3);
518 // 2 = e3, e5 and e3, e6
519 REQUIRE(maximal_subset_counts[2] == 2);
521 // There are no subsets of size 3 (or higher, but that
522 // is tested by asserting each maximal set traversed is a subset)
523 REQUIRE(maximal_subset_counts[3] == 0);
528 TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Stress Test for Maximal Subsets Iteration")
530 // The following tests concern the given event structure:
535 // +------* e4 *e5 e6 e7
539 // | e11 e12 e13 e14 e15
542 UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
543 UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
544 UnfoldingEvent e3(EventSet({&e1}), std::make_shared<IndependentAction>());
545 UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
546 UnfoldingEvent e5(EventSet({&e2}), std::make_shared<IndependentAction>());
547 UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>());
548 UnfoldingEvent e7(EventSet({&e3}), std::make_shared<IndependentAction>());
549 UnfoldingEvent e8(EventSet({&e4}), std::make_shared<IndependentAction>());
550 UnfoldingEvent e9(EventSet({&e4, &e5, &e6}), std::make_shared<IndependentAction>());
551 UnfoldingEvent e10(EventSet({&e6, &e7}), std::make_shared<IndependentAction>());
552 UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>());
553 UnfoldingEvent e12(EventSet({&e8}), std::make_shared<IndependentAction>());
554 UnfoldingEvent e13(EventSet({&e9}), std::make_shared<IndependentAction>());
555 UnfoldingEvent e14(EventSet({&e9}), std::make_shared<IndependentAction>());
556 UnfoldingEvent e15(EventSet({&e10}), std::make_shared<IndependentAction>());
557 UnfoldingEvent e16(EventSet({&e5, &e11}), std::make_shared<IndependentAction>());
558 UnfoldingEvent e17(EventSet({&e12, &e13, &e14}), std::make_shared<IndependentAction>());
559 UnfoldingEvent e18(EventSet({&e14, &e15}), std::make_shared<IndependentAction>());
560 Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18};
562 SECTION("Every subset iterated over is maximal")
564 maximal_subsets_iterator first(C);
565 maximal_subsets_iterator last;
567 // Make sure we actually have something to iterate over
568 REQUIRE(first != last);
570 for (; first != last; ++first) {
571 REQUIRE((*first).size() <= C.get_events().size());
572 REQUIRE((*first).is_maximal());
576 SECTION("Test that the maximal set ordering is equivalent to that of the configuration's events")
578 maximal_subsets_iterator first_config(C);
579 maximal_subsets_iterator first_events(C.get_events());
580 maximal_subsets_iterator last;
582 // Make sure we actually have something to iterate over
583 REQUIRE(first_config != last);
584 REQUIRE(first_config == first_events);
585 REQUIRE(first_events != last);
587 for (; first_config != last; ++first_config, ++first_events) {
588 // first_events and first_config should always be at the same location
589 REQUIRE(first_events != last);
590 const auto& first_config_set = *first_config;
591 const auto& first_events_set = *first_events;
593 REQUIRE(first_config_set.size() <= C.get_events().size());
594 REQUIRE(first_config_set.is_maximal());
595 REQUIRE(first_events_set == first_config_set);
598 // Iteration with events directly should now also be finished
599 REQUIRE(first_events == last);