From 6db410a71587e175d955fb2b7f6bd3530f9c1c1d Mon Sep 17 00:00:00 2001 From: Thomas Horstink Date: Sat, 19 Aug 2023 20:27:38 +0200 Subject: [PATCH] more docs wip --- Doxyfile | 10 +- docs/main.md | 3 + docs/symmetri_lib.md | 42 ++++++++- docs/symmetri_nets.md | 2 +- symmetri/model_utilities.cc | 21 ++--- symmetri/petri.cc | 149 ++++++++++++++---------------- symmetri/petri.h | 53 ++--------- symmetri/symmetri.cc | 10 +- symmetri/tests/test_bugs.cc | 14 +-- symmetri/tests/test_petri.cc | 115 +++++++++++------------ symmetri/tests/test_priorities.cc | 12 +-- 11 files changed, 201 insertions(+), 230 deletions(-) create mode 100644 docs/main.md diff --git a/Doxyfile b/Doxyfile index 721a4d9..4cfa505 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1353,7 +1353,7 @@ HTML_EXTRA_FILES = # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE = LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -2736,10 +2736,10 @@ GENERATE_LEGEND = YES DOT_CLEANUP = YES IMAGE_PATH += docs -# USE_MDFILE_AS_MAINPAGE = README.md -INPUT += README.md \ - docs/symmetri_nets.md \ - docs/symmetri_lib.md +USE_MDFILE_AS_MAINPAGE = docs/main.md +INPUT += docs/symmetri_nets.md \ + docs/symmetri_lib.md \ + docs/main.md DISABLE_INDEX = NO GENERATE_TREEVIEW = YES diff --git a/docs/main.md b/docs/main.md new file mode 100644 index 0000000..d5dce78 --- /dev/null +++ b/docs/main.md @@ -0,0 +1,3 @@ +# Symmetri, Petri Nets in C++ + +Welcome to the documentation for the Symmetri library. diff --git a/docs/symmetri_lib.md b/docs/symmetri_lib.md index 7829736..6d0b7a2 100644 --- a/docs/symmetri_lib.md +++ b/docs/symmetri_lib.md @@ -1,9 +1,47 @@ # Symmetri library -blabla - ## Build +### Vanilla CMake: + +Symmetri can be build as stand-alone CMake-project: + +```bash +git clone --recurse-submodules https://github.com/thorstink/Symmetri.git +mkdir build +cd build +cmake .. +make +``` + +### In a Colcon-workspace +It can also be build as part of a [colcon-workspace](https://colcon.readthedocs.io/en/released/user/what-is-a-workspace.html): + +```bash +mkdir ws/src +cd ws/src +git clone --recurse-submodules https://github.com/thorstink/Symmetri.git +cd .. # back to ws-directory +colcon build +``` + ## Test +Symmetri has a set of tests. There are three build configurations: + +- No sanitizers +- [ASAN](https://github.com/google/sanitizers/wiki/AddressSanitizer) + [UBSAN](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) +- [TSAN](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual) + +Each sanitizer can be enabled by setting either the 'ASAN_BUILD'- or 'TSAN_BUILD'-flag to true. They can not both be true at the same time. + +The sanitizers generally increase compiltation time quite significantly, hence they are off by default. In the CI-pipeline however they are turned on for testing. + +```bash +# from the build directory... +cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_EXAMPLES=ON -DBUILD_TESTING=ON -DASAN_BUILD=OFF -DTSAN_BUILD=OFF .. +make +make test +``` + ## Architecture diff --git a/docs/symmetri_nets.md b/docs/symmetri_nets.md index 230c845..558fd63 100644 --- a/docs/symmetri_nets.md +++ b/docs/symmetri_nets.md @@ -6,7 +6,7 @@ Transition T1 is enabled | Conflict: either T1 &tokens) { }); } -gch::small_vector possibleTransitions( +gch::small_vector possibleTransitions( const std::vector &tokens, - const std::vector &p_to_ts_n, - const std::vector &priorities) { - gch::small_vector possible_transition_list_n; + const std::vector &p_to_ts_n) { + gch::small_vector possible_transition_list_n; for (const size_t place : tokens) { for (size_t t : p_to_ts_n[place]) { if (std::find(possible_transition_list_n.begin(), @@ -29,16 +28,10 @@ gch::small_vector possibleTransitions( } } - // sort transition list according to priority - std::sort(possible_transition_list_n.begin(), - possible_transition_list_n.end(), - [&](size_t a, size_t b) { return priorities[a] > priorities[b]; }); - return possible_transition_list_n; } -Reducer createReducerForTransition(size_t t_i, const Eventlog &ev, - State result) { +Reducer createReducerForCallback(size_t t_i, const Eventlog &ev, State result) { return [=](Petri &model) { // if it is in the active transition set it means it is finished and we // should process it. @@ -56,7 +49,7 @@ Reducer createReducerForTransition(size_t t_i, const Eventlog &ev, }; } -Reducer fireTransition( +Reducer scheduleCallback( size_t t_i, const std::string &transition, const Callback &task, const std::string &case_id, const std::shared_ptr> @@ -67,9 +60,9 @@ Reducer fireTransition( {case_id, transition, State::Started, start_time}); }); - auto [ev, res] = fire(task); + auto [ev, res] = ::fire(task); ev.push_back({case_id, transition, res, Clock::now()}); - return createReducerForTransition(t_i, ev, res); + return createReducerForCallback(t_i, ev, res); } } // namespace symmetri diff --git a/symmetri/petri.cc b/symmetri/petri.cc index 881f976..ae8d998 100644 --- a/symmetri/petri.cc +++ b/symmetri/petri.cc @@ -112,75 +112,53 @@ std::vector Petri::toTokens(const Marking &marking) const noexcept { return tokens; } -std::vector Petri::getFireableTransitions() const { - auto possible_transition_list_n = - possibleTransitions(tokens, net.p_to_ts_n, net.priority); - std::vector fireable_transitions; - fireable_transitions.reserve(possible_transition_list_n.size()); - for (const size_t t_idx : possible_transition_list_n) { - const auto &pre = net.input_n[t_idx]; - if (canFire(pre, tokens)) { - fireable_transitions.push_back(net.transition[t_idx]); - } +void Petri::FireSynchronous(const size_t t) { + const auto timestamp = Clock::now(); + const auto &task = net.store[t]; + const auto &transition = net.transition[t]; + const auto &lookup_t = net.output_n[t]; + event_log.push_back({case_id, transition, State::Started, timestamp}); + auto result = std::get(::fire(task)); + event_log.push_back({case_id, transition, result, Clock::now()}); + if (result == State::Completed) { + tokens.insert(tokens.begin(), lookup_t.begin(), lookup_t.end()); } - return fireable_transitions; } -bool Petri::Fire( - const size_t t, - const std::shared_ptr> - &reducers, - const std::string &case_id) { - auto timestamp = Clock::now(); - // deduct the marking - for (const size_t place : net.input_n[t]) { +void Petri::FireAsynchronous(const size_t t) { + const auto timestamp = Clock::now(); + const auto &task = net.store[t]; + const auto &transition = net.transition[t]; + active_transitions.push_back(t); + event_log.push_back({case_id, transition, State::Scheduled, timestamp}); + pool->push([=] { + reducer_queue->enqueue( + scheduleCallback(t, transition, task, case_id, reducer_queue)); + }); +} + +void Petri::deductMarking(const SmallVector &inputs) { + for (const size_t place : inputs) { // erase one by one. using std::remove_if would remove all tokens at // a particular place. tokens.erase(std::find(tokens.begin(), tokens.end(), place)); } - - const auto &task = net.store[t]; - - // if the transition is direct, we short-circuit the - // marking mutation and do it immediately. - const auto &transition = net.transition[t]; - const auto &lookup_t = net.output_n[t]; - if (isSynchronous(task)) { - tokens.insert(tokens.begin(), lookup_t.begin(), lookup_t.end()); - event_log.push_back({case_id, transition, State::Started, timestamp}); - event_log.push_back({case_id, transition, - std::get(::fire(task)), timestamp}); - return true; - } else { - active_transitions.push_back(t); - event_log.push_back({case_id, transition, State::Scheduled, timestamp}); - pool->push([=] { - reducers->enqueue(fireTransition(t, transition, task, case_id, reducers)); - }); - return false; - } } -bool Petri::fire( - const Transition &t, - const std::shared_ptr> - &reducers, - const std::string &case_id) { +void Petri::tryFire(const Transition &t) { auto it = std::find(net.transition.begin(), net.transition.end(), t); - return it != net.transition.end() && - canFire(net.input_n[std::distance(net.transition.begin(), it)], - tokens) && - !Fire(std::distance(net.transition.begin(), it), reducers, case_id); + const auto t_idx = std::distance(net.transition.begin(), it); + if (canFire(net.input_n[t_idx], tokens)) { + deductMarking(net.input_n[t_idx]); + isSynchronous(net.store[t_idx]) ? FireSynchronous(t_idx) + : FireAsynchronous(t_idx); + } } -void Petri::fireTransitions( - const std::shared_ptr> - &reducers, - bool run_all, const std::string &case_id) { +void Petri::fireTransitions() { // find possible transitions - auto possible_transition_list_n = - possibleTransitions(tokens, net.p_to_ts_n, net.priority); - auto filter_transitions = [&](const auto &tokens) { + auto possible_transition_list_n = possibleTransitions(tokens, net.p_to_ts_n); + auto remove_inactive_transitions_predicate = [&](const auto &tokens) { possible_transition_list_n.erase( std::remove_if( possible_transition_list_n.begin(), @@ -189,22 +167,41 @@ void Petri::fireTransitions( possible_transition_list_n.end()); }; - // remove transitions that are not fireable; - filter_transitions(tokens); - - if (possible_transition_list_n.empty()) { - return; - } + // remove transitions that are not active; + remove_inactive_transitions_predicate(tokens); + + // sort transition list according to priority + std::sort( + possible_transition_list_n.begin(), possible_transition_list_n.end(), + [&](size_t a, size_t b) { return net.priority[a] > net.priority[b]; }); + + while (!possible_transition_list_n.empty()) { + const auto t_idx = possible_transition_list_n.front(); + deductMarking(net.input_n[t_idx]); + if (isSynchronous(net.store[t_idx])) { + FireSynchronous(t_idx); + // add the output places-connected transitions as new possible + // transitions: + for (const auto &p : net.output_n[t_idx]) { + for (const auto t : net.p_to_ts_n[p]) { + if (canFire(net.input_n[t], tokens)) { + possible_transition_list_n.push_back(t); + } + } + } - do { - // if Fire returns true, update the possible transition list - if (Fire(possible_transition_list_n.front(), reducers, case_id)) { - possible_transition_list_n = - possibleTransitions(tokens, net.p_to_ts_n, net.priority); + // sort again + std::sort(possible_transition_list_n.begin(), + possible_transition_list_n.end(), [&](size_t a, size_t b) { + return net.priority[a] > net.priority[b]; + }); + } else { + FireAsynchronous(t_idx); } - // remove transitions that are not fireable; - filter_transitions(tokens); - } while (run_all && !possible_transition_list_n.empty()); + // remove transitions that are not active anymore because of the marking + // mutation; + remove_inactive_transitions_predicate(tokens); + } return; } @@ -229,16 +226,4 @@ Eventlog Petri::getLog() const { return eventlog; } -std::vector Petri::getActiveTransitions() const { - std::vector transition_list; - if (active_transitions.size() > 0) { - transition_list.reserve(active_transitions.size()); - std::transform(active_transitions.cbegin(), active_transitions.cend(), - std::back_inserter(transition_list), [&](auto place_index) { - return net.transition[place_index]; - }); - } - return transition_list; -} - } // namespace symmetri diff --git a/symmetri/petri.h b/symmetri/petri.h index 082d81d..2a821ca 100644 --- a/symmetri/petri.h +++ b/symmetri/petri.h @@ -32,13 +32,11 @@ size_t toIndex(const std::vector &m, const std::string &s); * * @param tokens * @param p_to_ts_n - * @param priorities - * @return gch::small_vector + * @return gch::small_vector */ -gch::small_vector possibleTransitions( +gch::small_vector possibleTransitions( const std::vector &tokens, - const std::vector &p_to_ts_n, - const std::vector &priorities); + const std::vector &p_to_ts_n); /** * @brief Takes a vector of input places (pre-conditions) and the current token @@ -63,7 +61,7 @@ using Reducer = std::function; * @param reducers * @return Reducer */ -Reducer fireTransition( +Reducer scheduleCallback( size_t T_i, const std::string &transition, const Callback &task, const std::string &case_id, const std::shared_ptr> @@ -124,25 +122,6 @@ struct Petri { */ Eventlog getLog() const; - /** - * @brief Get a vector of transitions that are *active*. Active means that - * they are either in the transition queue or its transition has been fired. - * In all cases in the future it will produce a reducer which will be - * processed if the Petri net is not halted before the reducer is pop'd from - * the reducer queue. - * - * @return std::vector - */ - std::vector getActiveTransitions() const; - - /** - * @brief Gives a list of unique transitions that are fireable given the - * marking at the time of calling this function, sorted by priority. - * - * @return std::vector - */ - std::vector getFireableTransitions() const; - /** * @brief Try to fire a single transition. * @@ -151,13 +130,8 @@ struct Petri { * @param polymorphic_actions pointer to the threadpool, needed to dispatch * the transition payload * @param case_id the case id of the Petri instance - * @return true If the transition was fireable, it was queued - * @return false If the transition was not fireable, nothing happenend. */ - bool fire(const Transition &t, - const std::shared_ptr> - &reducers, - const std::string &case_id = "undefined_case_id"); + void tryFire(const Transition &t); /** * @brief Tries to run a transition (or all) until it 'deadlocks'. The list @@ -169,10 +143,7 @@ struct Petri { * @param run_all if true, potentially queues multiple transitions * @param case_id the case id of the Petri instance */ - void fireTransitions( - const std::shared_ptr> - &reducers, - bool run_all = true, const std::string &case_id = "undefined_case_id"); + void fireTransitions(); struct { /** @@ -238,20 +209,14 @@ struct Petri { pool; ///< A pointer to the threadpool used to defer Callbacks. private: + void deductMarking(const SmallVector &inputs); /** * @brief fires a transition. * * @param t transition as index in transition vector - * @param reducers - * @param polymorphic_actions - * @param case_id - * @return true if the transition is direct. - * @return false if it is only dispatched. */ - bool Fire(const size_t t, - const std::shared_ptr> - &reducers, - const std::string &case_id); + void FireSynchronous(const size_t t); + void FireAsynchronous(const size_t t); }; } // namespace symmetri diff --git a/symmetri/symmetri.cc b/symmetri/symmetri.cc index 0d62068..b55f0fe 100644 --- a/symmetri/symmetri.cc +++ b/symmetri/symmetri.cc @@ -79,9 +79,9 @@ std::function PetriNet::registerTransitionCallback( if (m.thread_id_.load()) { const auto t_index = toIndex(m.net.transition, transition); m.active_transitions.push_back(t_index); - m.reducer_queue->enqueue( - fireTransition(t_index, m.net.transition[t_index], - m.net.store[t_index], m.case_id, m.reducer_queue)); + m.reducer_queue->enqueue(scheduleCallback( + t_index, m.net.transition[t_index], m.net.store[t_index], + m.case_id, m.reducer_queue)); } }); } @@ -123,7 +123,7 @@ symmetri::Result fire(const PetriNet &app) { while (m.reducer_queue->try_dequeue(f)) { /* get rid of old reducers */ } // start! - m.fireTransitions(m.reducer_queue, true, m.case_id); + m.fireTransitions(); while ((m.state == State::Started || m.state == State::Paused) && m.reducer_queue->wait_dequeue_timed(f, -1)) { do { @@ -136,7 +136,7 @@ symmetri::Result fire(const PetriNet &app) { if (m.state == State::Started) { // we're firing - m.fireTransitions(m.reducer_queue, true, m.case_id); + m.fireTransitions(); // if there's nothing to fire; we deadlocked if (m.active_transitions.size() == 0) { m.state = State::Deadlock; diff --git a/symmetri/tests/test_bugs.cc b/symmetri/tests/test_bugs.cc index b69f540..54ae549 100644 --- a/symmetri/tests/test_bugs.cc +++ b/symmetri/tests/test_bugs.cc @@ -36,17 +36,14 @@ TEST_CASE("Firing the same transition before it can complete should work") { auto [net, store, priority, m0] = testNet(); auto stp = std::make_shared(2); Petri m(net, store, priority, m0, {}, "s", stp); - auto reducers = - std::make_shared>(4); REQUIRE(m.active_transitions.empty()); - m.fireTransitions(reducers, true); + m.fireTransitions(); REQUIRE(m.getMarking().empty()); - CHECK(m.getActiveTransitions() == - std::vector{"t", "t"}); REQUIRE(m.active_transitions.size() == 2); Reducer r; - while (reducers->wait_dequeue_timed(r, std::chrono::milliseconds(250))) { + while ( + m.reducer_queue->wait_dequeue_timed(r, std::chrono::milliseconds(250))) { r(m); } @@ -57,19 +54,18 @@ TEST_CASE("Firing the same transition before it can complete should work") { cv.notify_one(); - reducers->wait_dequeue_timed(r, std::chrono::milliseconds(250)); + m.reducer_queue->wait_dequeue_timed(r, std::chrono::milliseconds(250)); r(m); REQUIRE(MarkingEquality(m.getMarking(), {"Pb"})); // offending test, but fixed :-) - CHECK(m.getActiveTransitions() == std::vector{"t"}); REQUIRE(m.active_transitions.size() == 1); { std::lock_guard lk(cv_m); is_ready2 = true; } cv.notify_one(); - reducers->wait_dequeue_timed(r, std::chrono::milliseconds(250)); + m.reducer_queue->wait_dequeue_timed(r, std::chrono::milliseconds(250)); r(m); REQUIRE(MarkingEquality(m.getMarking(), {"Pb", "Pb"})); diff --git a/symmetri/tests/test_petri.cc b/symmetri/tests/test_petri.cc index 03d82fe..a68f165 100644 --- a/symmetri/tests/test_petri.cc +++ b/symmetri/tests/test_petri.cc @@ -53,30 +53,24 @@ TEST_CASE("Run one transition iteration in a petri net") { auto stp = std::make_shared(1); Petri m(net, store, priority, m0, {}, "s", stp); - auto reducers = std::make_shared>(4); // t0 is enabled. - m.fireTransitions(reducers, true, ""); + m.fireTransitions(); // t0 is dispatched but it's reducer has not yet run, so pre-conditions are // processed but post are not: - REQUIRE(m.getActiveTransitions() == - std::vector{"t0", "t0"}); REQUIRE(m.getMarking() == std::vector{"Pa", "Pa"}); // now there should be two reducers; Reducer r1, r2; - REQUIRE(reducers->wait_dequeue_timed(r1, std::chrono::seconds(1))); - REQUIRE(reducers->wait_dequeue_timed(r1, std::chrono::seconds(1))); - REQUIRE(reducers->wait_dequeue_timed(r2, std::chrono::seconds(1))); - REQUIRE(reducers->wait_dequeue_timed(r2, std::chrono::seconds(1))); + REQUIRE(m.reducer_queue->wait_dequeue_timed(r1, std::chrono::seconds(1))); + REQUIRE(m.reducer_queue->wait_dequeue_timed(r1, std::chrono::seconds(1))); + REQUIRE(m.reducer_queue->wait_dequeue_timed(r2, std::chrono::seconds(1))); + REQUIRE(m.reducer_queue->wait_dequeue_timed(r2, std::chrono::seconds(1))); // verify that t0 has actually ran twice. REQUIRE(T0_COUNTER.load() == 2); // the marking should still be the same. REQUIRE(m.getMarking() == std::vector{"Pa", "Pa"}); - CHECK(m.getActiveTransitions() == - std::vector{"t0", "t0"}); - // process the reducers r1(m); r2(m); @@ -93,16 +87,14 @@ TEST_CASE("Run until net dies") { auto stp = std::make_shared(1); Petri m(net, store, priority, m0, {}, "s", stp); - auto reducers = std::make_shared>(4); - Reducer r; Callback a([] {}); // we need to enqueue one 'no-operation' to start the live net. - reducers->enqueue([](Petri&) {}); + m.reducer_queue->enqueue([](Petri&) {}); do { - if (reducers->try_dequeue(r)) { + if (m.reducer_queue->try_dequeue(r)) { r(m); - m.fireTransitions(reducers, true); + m.fireTransitions(); } } while (m.active_transitions.size() > 0); @@ -122,16 +114,14 @@ TEST_CASE("Run until net dies with nullptr") { auto stp = std::make_shared(1); Petri m(net, store, priority, m0, {}, "s", stp); - auto reducers = std::make_shared>(4); - Reducer r; Callback a([] {}); // we need to enqueue one 'no-operation' to start the live net. - reducers->enqueue([](Petri&) {}); + m.reducer_queue->enqueue([](Petri&) {}); do { - if (reducers->try_dequeue(r)) { + if (m.reducer_queue->try_dequeue(r)) { r(m); - m.fireTransitions(reducers, true); + m.fireTransitions(); } } while (m.active_transitions.size() > 0); @@ -140,35 +130,36 @@ TEST_CASE("Run until net dies with nullptr") { m.getMarking(), std::vector{"Pb", "Pb", "Pd", "Pd"})); } -TEST_CASE( - "getFireableTransitions return a vector of unique of unique fireable " - "transitions") { - Net net = {{"a", {{"Pa"}, {}}}, - {"b", {{"Pa"}, {}}}, - {"c", {{"Pa"}, {}}}, - {"d", {{"Pa"}, {}}}, - {"e", {{"Pb"}, {}}}}; - - Store store; - for (auto [t, dm] : net) { - store.insert({t, DirectMutation{}}); - } - // with this initial marking, all but transition e are possible. - Marking m0 = {{"Pa", 1}}; - auto stp = std::make_shared(1); - - Petri m(net, store, {}, m0, {}, "s", stp); - auto fireable_transitions = m.getFireableTransitions(); - auto find = [&](auto a) { - return std::find(fireable_transitions.begin(), fireable_transitions.end(), - a); - }; - REQUIRE(find("a") != fireable_transitions.end()); - REQUIRE(find("b") != fireable_transitions.end()); - REQUIRE(find("c") != fireable_transitions.end()); - REQUIRE(find("d") != fireable_transitions.end()); - REQUIRE(find("e") == fireable_transitions.end()); -} +// TEST_CASE( +// "getFireableTransitions return a vector of unique of unique fireable " +// "transitions") { +// Net net = {{"a", {{"Pa"}, {}}}, +// {"b", {{"Pa"}, {}}}, +// {"c", {{"Pa"}, {}}}, +// {"d", {{"Pa"}, {}}}, +// {"e", {{"Pb"}, {}}}}; + +// Store store; +// for (auto [t, dm] : net) { +// store.insert({t, DirectMutation{}}); +// } +// // with this initial marking, all but transition e are possible. +// Marking m0 = {{"Pa", 1}}; +// auto stp = std::make_shared(1); + +// Petri m(net, store, {}, m0, {}, "s", stp); +// auto fireable_transitions = m.getFireableTransitions(); +// auto find = [&](auto a) { +// return std::find(fireable_transitions.begin(), +// fireable_transitions.end(), +// a); +// }; +// REQUIRE(find("a") != fireable_transitions.end()); +// REQUIRE(find("b") != fireable_transitions.end()); +// REQUIRE(find("c") != fireable_transitions.end()); +// REQUIRE(find("d") != fireable_transitions.end()); +// REQUIRE(find("e") == fireable_transitions.end()); +// } TEST_CASE("Step through transitions") { std::map hitmap; @@ -183,32 +174,34 @@ TEST_CASE("Step through transitions") { hitmap.insert({t, 0}); store.insert({t, [&, t = t] { hitmap[t] += 1; }}); } - auto reducers = std::make_shared>(5); auto stp = std::make_shared(1); // with this initial marking, all but transition e are possible. Marking m0 = {{"Pa", 4}}; Petri m(net, store, {}, m0, {}, "s", stp); - REQUIRE(m.getFireableTransitions().size() == 4); // abcd - m.fire("e", reducers); - m.fire("b", reducers); - m.fire("b", reducers); - m.fire("c", reducers); - m.fire("b", reducers); + + // auto active_transitions = m.getActiveTransitions(); + // REQUIRE(active_transitions.size() == 4); // abcd + m.tryFire("e"); + m.tryFire("b"); + m.tryFire("b"); + m.tryFire("c"); + m.tryFire("b"); // there are no reducers ran, so this doesn't update. - REQUIRE(m.getActiveTransitions().size() == 4); + REQUIRE(m.active_transitions.size() == 4); // there should be no markers left. REQUIRE(m.getMarking().size() == 0); // there should be nothing left to fire - REQUIRE(m.getFireableTransitions().size() == 0); + // active_transitions = m.getActiveTransitions(); + // REQUIRE(active_transitions.size() == 0); int j = 0; Reducer r; while (j < 2 * 4 && - reducers->wait_dequeue_timed(r, std::chrono::seconds(1))) { + m.reducer_queue->wait_dequeue_timed(r, std::chrono::seconds(1))) { j++; r(m); } // reducers update, there should be active transitions left. - REQUIRE(m.getActiveTransitions().size() == 0); + REQUIRE(m.active_transitions.size() == 0); } // validate we only ran transition 3 times b, 1 time c and none of the others. diff --git a/symmetri/tests/test_priorities.cc b/symmetri/tests/test_priorities.cc index 8788f2b..4ce18e9 100644 --- a/symmetri/tests/test_priorities.cc +++ b/symmetri/tests/test_priorities.cc @@ -15,8 +15,6 @@ TEST_CASE( std::list priorities = {{{"t0", 1}, {"t1", 0}}, {{"t0", 0}, {"t1", 1}}}; for (auto priority : priorities) { - auto reducers = std::make_shared>(4); - Net net = {{"t0", {{"Pa"}, {"Pb"}}}, {"t1", {{"Pa"}, {"Pc"}}}}; Store store = {{"t0", [] {}}, {"t1", [] {}}}; @@ -24,10 +22,11 @@ TEST_CASE( auto stp = std::make_shared(1); auto m = Petri(net, store, priority, m0, {}, "s", stp); - m.fireTransitions(reducers, true); + m.fireTransitions(); Reducer r; - while (reducers->wait_dequeue_timed(r, std::chrono::milliseconds(1))) { + while ( + m.reducer_queue->wait_dequeue_timed(r, std::chrono::milliseconds(1))) { r(m); } @@ -45,11 +44,10 @@ TEST_CASE( } } -TEST_CASE("Using nullptr does not queue reducers.") { +TEST_CASE("Using DirectMutation does not queue reducers.") { std::list priorities = {{{"t0", 1}, {"t1", 0}}, {{"t0", 0}, {"t1", 1}}}; for (auto priority : priorities) { - auto reducers = std::make_shared>(4); Net net = {{"t0", {{"Pa"}, {"Pb"}}}, {"t1", {{"Pa"}, {"Pc"}}}}; Store store = {{"t0", DirectMutation{}}, {"t1", DirectMutation{}}}; @@ -57,7 +55,7 @@ TEST_CASE("Using nullptr does not queue reducers.") { auto stp = std::make_shared(1); auto m = Petri(net, store, priority, m0, {}, "s", stp); - m.fireTransitions(reducers, true); + m.fireTransitions(); // no reducers needed, as simple transitions are handled within run all. auto prio_t0 = std::find_if(priority.begin(), priority.end(), [](auto e) { return e.first == "t0";