From f1513fc95bd784d5ef5f1286f241e4ed432ae3f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Wed, 16 Aug 2023 12:17:25 +0200 Subject: [PATCH 01/25] Add instance of 'Transitions' as an owned member of 'Delta' --- include/mata/nfa/delta.hh | 66 +++++++++++++++++++++++++-------------- include/mata/nfa/nfa.hh | 3 +- src/nfa/delta.cc | 5 +++ src/nfa/nfa.cc | 6 ++-- src/nfa/operations.cc | 2 +- tests/nfa/delta.cc | 2 +- tests/nfa/nfa.cc | 23 +++++++------- 7 files changed, 65 insertions(+), 42 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index c10e08edc..1c9eb8dd6 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -234,14 +234,14 @@ public: * the state number. */ class Delta { -private: - std::vector state_posts_; - public: inline static const StatePost empty_state_post; // When posts[q] is not allocated, then delta[q] returns this. - Delta() : state_posts_() {} - explicit Delta(size_t n) : state_posts_(n) {} + Delta(): state_posts_{} {} + Delta(const Delta& other): state_posts_{ other.state_posts_ } {} + explicit Delta(size_t n): state_posts_{ n } {} + + Delta& operator=(const Delta& other); void reserve(size_t n) { state_posts_.reserve(n); @@ -366,6 +366,12 @@ public: */ void add(const State state_from, const Symbol symbol, const StateSet& states); + using const_iterator = std::vector::const_iterator; + const_iterator cbegin() const { return state_posts_.cbegin(); } + const_iterator cend() const { return state_posts_.cend(); } + const_iterator begin() const { return state_posts_.begin(); } + const_iterator end() const { return state_posts_.end(); } + /** * Iterator over transitions. It iterates over triples (lhs, symbol, rhs) where lhs and rhs are states. */ @@ -405,29 +411,39 @@ public: bool operator!=(const transitions_const_iterator& other) const { return !(*this == other); }; }; // class transitions_const_iterator. - transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(state_posts_); } - transitions_const_iterator transitions_cend() const { return transitions_const_iterator(state_posts_, true); } - transitions_const_iterator transitions_begin() const { return transitions_cbegin(); } - transitions_const_iterator transitions_end() const { return transitions_cend(); } - - struct Transitions { - transitions_const_iterator begin_; - transitions_const_iterator end_; - transitions_const_iterator begin() const { return begin_; } - transitions_const_iterator end() const { return end_; } - }; + /** + * Iterator over transitions represented as 'Transition' instances. + */ + class Transitions { + private: + const Delta& delta_; + public: + explicit Transitions(const Delta& delta): delta_{ delta } {} + transitions_const_iterator begin() const { return delta_.transitions_cbegin(); } + transitions_const_iterator end() const { return delta_.transitions_cend(); } + + /** + * @brief Get a number of transitions in delta. + * + * The operation has a linear time complexity to the number of 'SymbolPost's in the delta. + */ + size_t count() const { return delta_.size(); } + + /** + * Whether there are no transitions in the delta. + */ + bool empty() const { return count() == 0; } + }; // class Transitions. /** - * Iterate over transitions represented as 'Trans' instances. - * @return Iterator over transitions. + * Iterator over transitions represented as 'Transition' instances. */ - Transitions transitions() const { return { .begin_ = transitions_begin(), .end_ = transitions_end() }; } + Transitions transitions() { return Transitions{ *this }; } - using const_iterator = std::vector::const_iterator; - const_iterator cbegin() const { return state_posts_.cbegin(); } - const_iterator cend() const { return state_posts_.cend(); } - const_iterator begin() const { return state_posts_.begin(); } - const_iterator end() const { return state_posts_.end(); } + transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(*this); } + transitions_const_iterator transitions_cend() const { return transitions_const_iterator(*this, true); } + transitions_const_iterator transitions_begin() const { return transitions_cbegin(); } + transitions_const_iterator transitions_end() const { return transitions_cend(); } /** * Iterate over @p epsilon symbol posts under the given @p state. @@ -444,6 +460,8 @@ public: * @return An iterator to @c SymbolPost with epsilon symbol. End iterator when there are no epsilon transitions. */ static StatePost::const_iterator epsilon_symbol_posts(const StatePost& state_post, Symbol epsilon = EPSILON); +private: + std::vector state_posts_; }; // struct Delta. } // namespace mata::nfa. diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 802d7cada..5b20e98df 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -229,8 +229,7 @@ public: * * The operation has constant time complexity. */ - size_t get_num_of_trans() const { return static_cast(std::distance(delta.transitions_begin(), - delta.transitions_end())); } + size_t get_num_of_trans() const { return std::distance(delta.transitions.begin(), delta.transitions.end()); } /** * Get transitions as a sequence of @c Trans. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 85318d008..b2a75a96b 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -67,6 +67,11 @@ size_t Delta::size() const { return size; } +Delta& Delta::operator=(const Delta& other) { + this->state_posts_ = other.state_posts_; + return *this; +} + void Delta::add(State source, Symbol symbol, State target) { const State max_state{ std::max(source, target) }; if (max_state >= state_posts_.size()) { diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 82ae4a0b2..5dac20aac 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -394,7 +394,7 @@ void Nfa::print_to_mata(std::ostream &output) const { output << std::endl; } - for (Transition trans : delta.transitions()) { + for (const Transition& trans: delta.transitions()) { output << "q" << trans.source << " " << trans.symbol << " q" << trans.target << std::endl; } } @@ -483,7 +483,7 @@ Nfa::const_iterator Nfa::const_iterator::for_begin(const Nfa* nfa) const_iterator result; - if (nfa->delta.transitions_begin() == nfa->delta.transitions_end()) { + if (nfa->delta.transitions.begin() == nfa->delta.transitions.end()) { result.is_end = true; return result; } @@ -546,7 +546,7 @@ Nfa::const_iterator& Nfa::const_iterator::operator++() // out of transition list ++this->trIt; - assert(this->nfa->delta.transitions_begin() != this->nfa->delta.transitions_end()); + assert(this->nfa->delta.transitions.begin() != this->nfa->delta.transitions.end()); while (this->trIt < this->nfa->delta.num_of_states() && this->nfa->delta.state_post(this->trIt).empty()) diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index 080c99cb9..bc4042f25 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -42,7 +42,7 @@ namespace { const size_t state_num = aut.size(); Simlib::ExplicitLTS LTSforSimulation(state_num); - for (const auto& transition : aut.delta.transitions()) { + for (const Transition& transition : aut.delta.transitions) { LTSforSimulation.add_transition(transition.source, transition.symbol, transition.target); if (transition.symbol > maxSymbol) { maxSymbol = transition.symbol; diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index db56e91ab..75d3e4e3c 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -234,7 +234,7 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { CHECK(iterated_transitions == expected_transitions); iterated_transitions.clear(); - for (const Transition& transition: nfa.delta.transitions()) { iterated_transitions.push_back(transition); } + for (const Transition& transition: nfa.delta.transitions) { iterated_transitions.push_back(transition); } CHECK(iterated_transitions == expected_transitions); } } diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index c1f1c8f24..c3f0e546c 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -123,7 +123,8 @@ TEST_CASE("mata::nfa::Nfa::delta.add()/delta.contains()") size_t transitions_cnt{ 0 }; std::vector expected_transitions{ t1, t2, t3, t4 }; std::vector iterated_transitions{}; - for (auto trans_it{ a.delta.transitions_begin()}; trans_it != a.delta.transitions_end(); ++trans_it) { + for (Delta::transitions_const_iterator trans_it{ a.delta.transitions.begin()}; + trans_it != a.delta.transitions.end(); ++trans_it) { iterated_transitions.push_back(*trans_it); ++transitions_cnt; } @@ -132,7 +133,7 @@ TEST_CASE("mata::nfa::Nfa::delta.add()/delta.contains()") transitions_cnt = 0; iterated_transitions.clear(); - for (const Transition& trans: a.delta.transitions()) { + for (const Transition& trans: a.delta.transitions) { iterated_transitions.push_back(trans); ++transitions_cnt; } @@ -181,25 +182,25 @@ TEST_CASE("mata::nfa::Nfa iteration") { aut.delta.add('q', 'a', 'r'); aut.delta.add('q', 'b', 'r'); - auto it = aut.delta.transitions_begin(); - auto jt = aut.delta.transitions_begin(); + auto it = aut.delta.transitions.begin(); + auto jt = aut.delta.transitions.begin(); REQUIRE(it == jt); ++it; REQUIRE(it != jt); - REQUIRE((it != aut.delta.transitions_begin() && it != aut.delta.transitions_end())); - REQUIRE(jt == aut.delta.transitions_begin()); + REQUIRE((it != aut.delta.transitions.begin() && it != aut.delta.transitions.end())); + REQUIRE(jt == aut.delta.transitions.begin()); ++jt; REQUIRE(it == jt); - REQUIRE((jt != aut.delta.transitions_begin() && jt != aut.delta.transitions_end())); + REQUIRE((jt != aut.delta.transitions.begin() && jt != aut.delta.transitions.end())); - jt = aut.delta.transitions_end(); + jt = aut.delta.transitions.end(); REQUIRE(it != jt); - REQUIRE((jt != aut.delta.transitions_begin() && jt == aut.delta.transitions_end())); + REQUIRE((jt != aut.delta.transitions.begin() && jt == aut.delta.transitions.end())); - it = aut.delta.transitions_end(); + it = aut.delta.transitions.end(); REQUIRE(it == jt); - REQUIRE((it != aut.delta.transitions_begin() && it == aut.delta.transitions_end())); + REQUIRE((it != aut.delta.transitions.begin() && it == aut.delta.transitions.end())); } } // }}} From 08595229e64e58b71c2f040a4e960fad6ee7fb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Wed, 16 Aug 2023 14:27:10 +0200 Subject: [PATCH 02/25] Move get_transitions_from_as_sequence() to Delta::Transitions::from() --- include/mata/nfa/delta.hh | 57 ++++++++++++++---- include/mata/nfa/nfa.hh | 7 --- src/nfa/delta.cc | 107 ++++++++++++++++++---------------- src/nfa/nfa.cc | 15 ----- tests/nfa/delta.cc | 19 ++++++ tests/nfa/nfa-intersection.cc | 26 ++++----- 6 files changed, 135 insertions(+), 96 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 1c9eb8dd6..efb4e352e 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -375,13 +375,13 @@ public: /** * Iterator over transitions. It iterates over triples (lhs, symbol, rhs) where lhs and rhs are states. */ - struct transitions_const_iterator { + class transitions_const_iterator { private: - const std::vector& post_; + const Delta* delta_ = nullptr; size_t current_state_; - StatePost::const_iterator post_iterator_{}; - StateSet::const_iterator targets_position_{}; - bool is_end_; + StatePost::const_iterator state_post_it_{}; + StateSet::const_iterator symbol_post_it_{}; + bool is_end_{ false }; Transition transition_{}; public: @@ -391,12 +391,12 @@ public: using pointer = Transition*; using reference = Transition&; - explicit transitions_const_iterator(const std::vector& post_p, bool ise = false); - - transitions_const_iterator(const std::vector& post_p, size_t as, - StatePost::const_iterator pi, StateSet::const_iterator ti, bool ise = false); + transitions_const_iterator() = default; + explicit transitions_const_iterator(const Delta& delta, bool is_end = false); + transitions_const_iterator(const Delta& delta, State current_state, bool is_end = false); - transitions_const_iterator(const transitions_const_iterator& other) = default; + transitions_const_iterator(const transitions_const_iterator& other) noexcept = default; + transitions_const_iterator(transitions_const_iterator&&) = default; const Transition& operator*() const { return transition_; } @@ -405,12 +405,30 @@ public: // Postfix increment const transitions_const_iterator operator++(int); - transitions_const_iterator& operator=(const transitions_const_iterator& x); + transitions_const_iterator& operator=(const transitions_const_iterator& other) noexcept = default; + transitions_const_iterator& operator=(transitions_const_iterator&&) = default; bool operator==(const transitions_const_iterator& other) const; bool operator!=(const transitions_const_iterator& other) const { return !(*this == other); }; }; // class transitions_const_iterator. + class TransitionsView { + private: + transitions_const_iterator begin_; + transitions_const_iterator end_; + public: + TransitionsView() = default; + TransitionsView(const TransitionsView&) = default; + TransitionsView(TransitionsView&&) = default; + TransitionsView(transitions_const_iterator begin, transitions_const_iterator end): begin_{ begin }, end_{ end } {} + TransitionsView& operator=(const TransitionsView&) = default; + TransitionsView& operator=(TransitionsView&&) = default; + transitions_const_iterator begin() const { return begin_; } + transitions_const_iterator end() const { return end_; } + size_t count() const { return std::distance( begin(), end() ); } + size_t empty() const { return count() == 0; } + }; + /** * Iterator over transitions represented as 'Transition' instances. */ @@ -422,6 +440,19 @@ public: transitions_const_iterator begin() const { return delta_.transitions_cbegin(); } transitions_const_iterator end() const { return delta_.transitions_cend(); } + /** + * @brief Get a number of transitions in delta. + * + * The operation has a linear time complexity to the number of transitions in the delta. + */ + size_t count() const { return std::distance(begin(), end()); } + + size_t empty() const { return count() == 0; } + + // TODO: Is 'from_source()' than 'from()'? + TransitionsView from(State source) const; + }; + /** * @brief Get a number of transitions in delta. * @@ -462,6 +493,10 @@ public: static StatePost::const_iterator epsilon_symbol_posts(const StatePost& state_post, Symbol epsilon = EPSILON); private: std::vector state_posts_; + transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(*this); } + transitions_const_iterator transitions_cend() const { return transitions_const_iterator(*this, true); } + transitions_const_iterator transitions_begin() const { return transitions_cbegin(); } + transitions_const_iterator transitions_end() const { return transitions_cend(); } }; // struct Delta. } // namespace mata::nfa. diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 5b20e98df..a394fd2ff 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -237,13 +237,6 @@ public: */ std::vector get_trans_as_sequence() const; - /** - * Get transitions from @p state_from as a sequence of @c Trans. - * @param state_from[in] Source state_from of transitions to get. - * @return Sequence of transitions as @c Trans from @p state_from. - */ - std::vector get_trans_from_as_sequence(State state_from) const; - /** * Get transitions leading to @p state_to. * @param state_to[in] Target state for transitions to get. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index b2a75a96b..20e3cdc8c 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -72,6 +72,12 @@ Delta& Delta::operator=(const Delta& other) { return *this; } +Delta::TransitionsView Delta::Transitions::from(const State source) const { + transitions_const_iterator begin_it{ delta_, source }; + transitions_const_iterator end_it{ delta_, source + 1 }; + return TransitionsView{ begin_it, end_it }; +} + void Delta::add(State source, Symbol symbol, State target) { const State max_state{ std::max(source, target) }; if (max_state >= state_posts_.size()) { @@ -188,17 +194,17 @@ bool Delta::empty() const return this->transitions_begin() == this->transitions_end(); } -Delta::transitions_const_iterator::transitions_const_iterator(const std::vector& post_p, bool ise) - : post_(post_p), current_state_(0), is_end_{ ise } { - const size_t post_size = post_.size(); +Delta::transitions_const_iterator::transitions_const_iterator(const Delta& delta, bool is_end) + : delta_{ &delta }, current_state_{ 0 }, is_end_{ is_end } { + const size_t post_size = delta_->num_of_states(); for (size_t i = 0; i < post_size; ++i) { - if (!post_[i].empty()) { + if (!(*delta_)[i].empty()) { current_state_ = i; - post_iterator_ = post_[i].begin(); - targets_position_ = post_iterator_->targets.begin(); + state_post_it_ = (*delta_)[i].begin(); + symbol_post_it_ = state_post_it_->targets.begin(); transition_.source = current_state_; - transition_.symbol = post_iterator_->symbol; - transition_.target = *targets_position_; + transition_.symbol = state_post_it_->symbol; + transition_.target = *symbol_post_it_; return; } } @@ -208,45 +214,59 @@ Delta::transitions_const_iterator::transitions_const_iterator(const std::vector< } Delta::transitions_const_iterator::transitions_const_iterator( - const std::vector& post_p, size_t as, StatePost::const_iterator pi, StateSet::const_iterator ti, - bool ise) - : post_(post_p), current_state_(as), post_iterator_(pi), targets_position_(ti), is_end_(ise) { - transition_.source = current_state_; - transition_.symbol = post_iterator_->symbol; - transition_.target = *targets_position_; -}; + const Delta& delta, State current_state, bool is_end) + : delta_{ &delta }, current_state_{ current_state }, is_end_{ is_end } { + const size_t post_size = delta_->num_of_states(); + for (State source{ current_state_ }; source < post_size; ++source) { + const StatePost& state_post{ delta_->state_post(source) }; + if (!state_post.empty()) { + current_state_ = source; + state_post_it_ = state_post.begin(); + symbol_post_it_ = state_post_it_->targets.begin(); + transition_.source = current_state_; + transition_.symbol = state_post_it_->symbol; + transition_.target = *symbol_post_it_; + return; + } + } + + // no transition found, an empty post + is_end_ = true; +} Delta::transitions_const_iterator& Delta::transitions_const_iterator::operator++() { - assert(post_.begin() != post_.end()); + assert(delta_->begin() != delta_->end()); - ++targets_position_; - if (targets_position_ != post_iterator_->targets.end()) { - transition_.target = *targets_position_; + ++symbol_post_it_; + if (symbol_post_it_ != state_post_it_->targets.end()) { + transition_.target = *symbol_post_it_; return *this; } - ++post_iterator_; - if (post_iterator_ != post_[current_state_].cend()) { - targets_position_ = post_iterator_->targets.begin(); - transition_.symbol = post_iterator_->symbol; - transition_.target = *targets_position_; + ++state_post_it_; + if (state_post_it_ != (*delta_)[current_state_].cend()) { + symbol_post_it_ = state_post_it_->targets.begin(); + transition_.symbol = state_post_it_->symbol; + transition_.target = *symbol_post_it_; return *this; } - ++current_state_; - while (current_state_ < post_.size() && post_[current_state_].empty()) // skip empty posts - current_state_++; - - if (current_state_ >= post_.size()) + const size_t state_posts_size{ delta_->num_of_states() }; + do { // Skip empty posts. + ++current_state_; + } while (current_state_ < state_posts_size && (*delta_)[current_state_].empty()); + if (current_state_ >= state_posts_size) { is_end_ = true; - else { - post_iterator_ = post_[current_state_].begin(); - targets_position_ = post_iterator_->targets.begin(); + return *this; } + const StatePost& state_post{ (*delta_)[current_state_] }; + state_post_it_ = state_post.begin(); + symbol_post_it_ = state_post_it_->targets.begin(); + transition_.source = current_state_; - transition_.symbol = post_iterator_->symbol; - transition_.target = *targets_position_; + transition_.symbol = state_post_it_->symbol; + transition_.target = *symbol_post_it_; return *this; } @@ -257,27 +277,14 @@ const Delta::transitions_const_iterator Delta::transitions_const_iterator::opera return tmp; } -Delta::transitions_const_iterator& Delta::transitions_const_iterator::operator=(const Delta::transitions_const_iterator& x) { - // FIXME: this->post is never updated, because it is a const reference to std::vector which does not have assignment - // operator defined. - this->post_iterator_ = x.post_iterator_; - this->targets_position_ = x.targets_position_; - this->current_state_ = x.current_state_; - this->is_end_ = x.is_end_; - transition_.source = x.transition_.source; - transition_.symbol = x.transition_.symbol; - transition_.target = x.transition_.target; - return *this; -} - -bool mata::nfa::Delta::transitions_const_iterator::operator==(const Delta::transitions_const_iterator& other) const { +bool Mata::Nfa::Delta::transitions_const_iterator::operator==(const Delta::transitions_const_iterator& other) const { if (is_end_ && other.is_end_) { return true; } else if ((is_end_ && !other.is_end_) || (!is_end_ && other.is_end_)) { return false; } else { - return current_state_ == other.current_state_ && post_iterator_ == other.post_iterator_ - && targets_position_ == other.targets_position_; + return current_state_ == other.current_state_ && state_post_it_ == other.state_post_it_ + && symbol_post_it_ == other.symbol_post_it_; } } diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 5dac20aac..6c1f1ff65 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -417,21 +417,6 @@ std::vector Nfa::get_trans_as_sequence() const return trans_sequence; } -std::vector Nfa::get_trans_from_as_sequence(State state_from) const -{ - std::vector trans_sequence{}; - - for (const auto& transition_from_state: delta[state_from]) - { - for (State state_to: transition_from_state.targets) - { - trans_sequence.emplace_back(state_from, transition_from_state.symbol, state_to); - } - } - - return trans_sequence; -} - Nfa Nfa::get_one_letter_aut(Symbol abstract_symbol) const { Nfa digraph{size(), StateSet(initial), StateSet(final) }; // Add directed transitions for digraph. diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 75d3e4e3c..34298b28a 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -238,3 +238,22 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { CHECK(iterated_transitions == expected_transitions); } } +TEST_CASE("Mata::Nfa::Delta::TransitionsView") { + Nfa nfa{}; + nfa.initial.insert(0); + nfa.final.insert(5); + nfa.delta.add(0, 'a', 1); + nfa.delta.add(1, 'b', 2); + nfa.delta.add(1, 'c', 2); + nfa.delta.add(1, 'd', 2); + nfa.delta.add(2, 'e', 3); + nfa.delta.add(3, 'e', 4); + nfa.delta.add(4, 'f', 5); + Delta::TransitionsView transitions_from_source{ nfa.delta.transitions.from(0) }; + CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() } == std::vector{ { 0, 'a', 1 }}); + transitions_from_source = nfa.delta.transitions.from(1); + CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() } == + std::vector{ { 1, 'b', 2 }, { 1, 'c', 2 }, { 1, 'd', 2 } }); + transitions_from_source = nfa.delta.transitions.from(12); + CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() }.empty()); +} diff --git a/tests/nfa/nfa-intersection.cc b/tests/nfa/nfa-intersection.cc index 5737d99f5..63085b194 100644 --- a/tests/nfa/nfa-intersection.cc +++ b/tests/nfa/nfa-intersection.cc @@ -246,45 +246,45 @@ TEST_CASE("mata::nfa::intersection() with preserving epsilon transitions") CHECK(result.get_num_of_trans() == 15); CHECK(result.delta.contains(prod_map[{0, 0}], EPSILON, prod_map[{1, 0}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 0, 0 }]).size() == 1); + CHECK(result.delta.transitions.from(prod_map[{ 0, 0 }]).count() == 1); CHECK(result.delta.contains(prod_map[{1, 0}], 'b', prod_map[{1, 1}])); CHECK(result.delta.contains(prod_map[{1, 0}], 'a', prod_map[{1, 2}])); CHECK(result.delta.contains(prod_map[{1, 0}], 'c', prod_map[{2, 5}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 1, 0 }]).size() == 3); + CHECK(result.delta.transitions.from(prod_map[{ 1, 0 }]).count() == 3); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 1, 1 }]).empty()); + CHECK(result.delta.transitions.from(prod_map[{ 1, 1 }]).empty()); CHECK(result.delta.contains(prod_map[{1, 2}], EPSILON, prod_map[{1, 3}])); CHECK(result.delta.contains(prod_map[{1, 2}], 'a', prod_map[{1, 4}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 1, 2 }]).size() == 2); + CHECK(result.delta.transitions.from(prod_map[{ 1, 2 }]).count() == 2); CHECK(result.delta.contains(prod_map[{1, 3}], 'b', prod_map[{1, 4}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 1, 3 }]).size() == 1); + CHECK(result.delta.transitions.from(prod_map[{ 1, 3 }]).count() == 1); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 1, 4 }]).empty()); + CHECK(result.delta.transitions.from(prod_map[{ 1, 4 }]).empty()); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{3, 5}])); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{2, 6}])); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{3, 6}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 2, 5 }]).size() == 3); + CHECK(result.delta.transitions.from(prod_map[{ 2, 5 }]).count() == 3); CHECK(result.delta.contains(prod_map[{3, 5}], 'a', prod_map[{5, 8}])); CHECK(result.delta.contains(prod_map[{3, 5}], EPSILON, prod_map[{3, 6}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 3, 5 }]).size() == 2); + CHECK(result.delta.transitions.from(prod_map[{ 3, 5 }]).count() == 2); CHECK(result.delta.contains(prod_map[{2, 6}], 'b', prod_map[{4, 7}])); CHECK(result.delta.contains(prod_map[{2, 6}], EPSILON, prod_map[{3, 6}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 2, 6 }]).size() == 2); + CHECK(result.delta.transitions.from(prod_map[{ 2, 6 }]).count() == 2); CHECK(result.delta.contains(prod_map[{3, 6}], 'a', prod_map[{5, 9}])); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 3, 6 }]).size() == 1); + CHECK(result.delta.transitions.from(prod_map[{ 3, 6 }]).count() == 1); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 4, 7 }]).empty()); + CHECK(result.delta.transitions.from(prod_map[{ 4, 7 }]).empty()); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 5, 9 }]).empty()); + CHECK(result.delta.transitions.from(prod_map[{ 5, 9 }]).empty()); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 5, 8 }]).empty()); + CHECK(result.delta.transitions.from(prod_map[{ 5, 8 }]).empty()); } TEST_CASE("mata::nfa::intersection() for profiling", "[.profiling],[intersection]") From b192bc9226523e6765dcab5c1cc5e2a6434e26dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 17 Aug 2023 09:16:52 +0200 Subject: [PATCH 03/25] Update Python binding to use transitions iterators --- bindings/python/libmata/nfa/nfa.pxd | 27 ++++++++++++++++++++++----- bindings/python/libmata/nfa/nfa.pyx | 22 +++++++++++++++++----- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index 5d7966475..b439ab34f 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -51,8 +51,24 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[CSymbolPost].const_iterator cbegin() COrdVector[CSymbolPost].const_iterator cend() - cdef cppclass CDelta "mata::nfa::Delta": - vector[CStatePost] post + cdef cppclass Ctransitions_const_iterator "Mata::Nfa::Delta::transitions_const_iterator": + bool operator==(Ctransitions_const_iterator&) + bool operator!=(Ctransitions_const_iterator&) + CTrans& operator*() + Ctransitions_const_iterator& operator++() + + cdef cppclass CTransitionsView "Mata::Nfa::Delta::TransitionsView": + Ctransitions_const_iterator begin() + Ctransitions_const_iterator end() + + cdef cppclass CTransitions "Mata::Nfa::Delta::Transitions": + Ctransitions_const_iterator begin() + Ctransitions_const_iterator end() + size_t count() + + cdef cppclass CDelta "Mata::Nfa::Delta": + vector[CStatePost] state_posts + CTransitions transitions void reserve(size_t) CStatePost& state_post(State) @@ -109,7 +125,10 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": bool operator>(CSymbolPost) bool operator>=(CSymbolPost) - cdef cppclass CNfa "mata::nfa::Nfa": + COrdVector[State].const_iterator begin() + COrdVector[State].const_iterator end() + + cdef cppclass CNfa "Mata::Nfa::Nfa": # Nested iterator cppclass const_iterator: const_iterator() @@ -146,7 +165,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": void unify_final() COrdVector[Symbol] get_used_symbols() bool is_state(State) - size_t get_num_of_trans() StateSet post(StateSet&, Symbol) CNfa.const_iterator begin() CNfa.const_iterator end() @@ -155,7 +173,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": void print_to_DOT(ostream) vector[CTrans] get_transitions_to(State) vector[CTrans] get_trans_as_sequence() - vector[CTrans] get_trans_from_as_sequence(State) CNfa& trim(StateRenaming*) void get_one_letter_aut(CNfa&) bool is_epsilon(Symbol) diff --git a/bindings/python/libmata/nfa/nfa.pyx b/bindings/python/libmata/nfa/nfa.pyx index 348c7a97d..9e61f63db 100644 --- a/bindings/python/libmata/nfa/nfa.pyx +++ b/bindings/python/libmata/nfa/nfa.pyx @@ -384,7 +384,7 @@ cdef class Nfa: :return: number of transitions in automaton """ - return self.thisptr.get().get_num_of_trans() + return self.thisptr.get().delta.transitions.count() def clear(self): """Clears all of the internals in the automaton""" @@ -444,6 +444,8 @@ cdef class Nfa: def get_trans_as_sequence(self): """Get automaton transitions as a sequence. + TODO: Refactor into a generator. + :return: List of automaton transitions. """ cdef vector[CTrans] c_transitions = self.thisptr.get().get_trans_as_sequence() @@ -452,15 +454,25 @@ cdef class Nfa: transitions.append(Transition(c_transition.source, c_transition.symbol, c_transition.target)) return transitions - def get_trans_from_state_as_sequence(self, State state_from): + def get_trans_from_state_as_sequence(self, State source) -> list[Transition]: """Get automaton transitions from state_from as a sequence. + TODO: Refactor into a generator. + :return: List of automaton transitions. """ - cdef vector[CTrans] c_transitions = self.thisptr.get().get_trans_from_as_sequence(state_from) transitions = [] - for c_transition in c_transitions: - transitions.append(Transition(c_transition.source, c_transition.symbol, c_transition.target)) + cdef CStatePost c_state_post = self.thisptr.get().delta[source] + cdef COrdVector[CSymbolPost].const_iterator c_state_post_it = c_state_post.cbegin() + cdef CSymbolPost c_symbol_post + cdef COrdVector[State].const_iterator c_symbol_post_it + while c_state_post_it != c_state_post.cend(): + c_symbol_post = dereference(c_state_post_it) + c_symbol_post_it = c_symbol_post.begin() + while c_symbol_post_it != c_symbol_post.end(): + transitions.append(Transition(source, c_symbol_post.symbol, dereference(c_symbol_post_it))) + preinc(c_symbol_post_it) + preinc(c_state_post_it) return transitions def get_useful_states(self): From 04898da027c6238a27f974381b7ab4f84e7cdb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 17 Aug 2023 10:03:19 +0200 Subject: [PATCH 04/25] Check corrent functionality of Delta::operator= --- tests/nfa/delta.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 34298b28a..8634f7d42 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -238,6 +238,19 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { CHECK(iterated_transitions == expected_transitions); } } + +TEST_CASE("Mata::Nfa::Delta::operator=()") { + Nfa nfa{}; + nfa.initial.insert(0); + nfa.final.insert(1); + nfa.delta.add(0, 'a', 1); + + Nfa copied_nfa{ nfa }; + nfa.delta.add(1, 'b', 0); + CHECK(nfa.delta.transitions.count() == 2); + CHECK(copied_nfa.delta.transitions.count() == 1); +} + TEST_CASE("Mata::Nfa::Delta::TransitionsView") { Nfa nfa{}; nfa.initial.insert(0); From 0f23367ba23283ed00bb73f046eece950ad12b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 17 Aug 2023 12:14:55 +0200 Subject: [PATCH 05/25] Remove iterator over Delta --- bindings/python/libmata/nfa/nfa.pxd | 11 --- bindings/python/libmata/nfa/nfa.pyx | 4 +- include/mata/nfa/nfa.hh | 27 ------- src/nfa/nfa.cc | 108 +--------------------------- tests/nfa/delta.cc | 32 +++++++++ tests/nfa/nfa.cc | 41 +---------- 6 files changed, 36 insertions(+), 187 deletions(-) diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index b439ab34f..28a9153a6 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -129,15 +129,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[State].const_iterator end() cdef cppclass CNfa "Mata::Nfa::Nfa": - # Nested iterator - cppclass const_iterator: - const_iterator() - CTrans operator*() - const_iterator& operator++() - bool operator==(const_iterator&) - bool operator!=(const_iterator&) - void refresh_trans() - # Public Attributes CSparseSet[State] initial CSparseSet[State] final @@ -166,8 +157,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[Symbol] get_used_symbols() bool is_state(State) StateSet post(StateSet&, Symbol) - CNfa.const_iterator begin() - CNfa.const_iterator end() State add_state() State add_state(State) void print_to_DOT(ostream) diff --git a/bindings/python/libmata/nfa/nfa.pyx b/bindings/python/libmata/nfa/nfa.pyx index 9e61f63db..32480cfef 100644 --- a/bindings/python/libmata/nfa/nfa.pyx +++ b/bindings/python/libmata/nfa/nfa.pyx @@ -401,8 +401,8 @@ cdef class Nfa: :return: stream of transitions """ - iterator = self.thisptr.get().begin() - while iterator != self.thisptr.get().end(): + iterator = self.thisptr.get().delta.transitions.begin() + while iterator != self.thisptr.get().delta.transitions.end(): trans = Transition() lhs = dereference(iterator) trans.copy_from(lhs) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index a394fd2ff..13b8f028a 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -303,33 +303,6 @@ public: // TODO: Relict from VATA. What to do with inclusion/ universality/ this post function? Revise all of them. StateSet post(const StateSet& states, const Symbol& symbol) const; - struct const_iterator { - const Nfa* nfa; - size_t trIt; - StatePost::const_iterator tlIt; - StateSet::const_iterator ssIt; - Transition trans; - bool is_end = { false }; - - const_iterator() : nfa(), trIt(0), tlIt(), ssIt(), trans() { }; - static const_iterator for_begin(const Nfa* nfa); - static const_iterator for_end(const Nfa* nfa); - - // FIXME: He, what is this? Some comment would help. - // I am thinking about that removing everything having to do with Transition might be a good thing. Transition - // adds clutter and makes people write inefficient code. - void refresh_trans() { this->trans = {trIt, this->tlIt->symbol, *(this->ssIt)}; } - - const Transition& operator*() const { return this->trans; } - - bool operator==(const const_iterator& rhs) const; - bool operator!=(const const_iterator& rhs) const { return !(*this == rhs);} - const_iterator& operator++(); - }; // }}} - - const_iterator begin() const { return const_iterator::for_begin(this); } - const_iterator end() const { return const_iterator::for_end(this); } - /** * @brief Expand alphabet by symbols from this automaton to given alphabet * diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 6c1f1ff65..e17b310d4 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -462,107 +462,6 @@ StateSet Nfa::post(const StateSet& states, const Symbol& symbol) const { return res; } -Nfa::const_iterator Nfa::const_iterator::for_begin(const Nfa* nfa) -{ // {{{ - assert(nullptr != nfa); - - const_iterator result; - - if (nfa->delta.transitions.begin() == nfa->delta.transitions.end()) { - result.is_end = true; - return result; - } - - result.nfa = nfa; - - for (size_t trIt{ 0 }; trIt < nfa->delta.num_of_states(); ++trIt) { - auto& moves{ nfa->delta.state_post(trIt) }; - if (!moves.empty()) { - auto move{ moves.begin() }; - while (move != moves.end()) { - if (!move->targets.empty()) { - result.trIt = trIt; - result.tlIt = moves.begin(); - result.ssIt = result.tlIt->targets.begin(); - break; - } - ++move; - } - break; - } - } - - result.refresh_trans(); - - return result; -} // for_begin }}} - -Nfa::const_iterator Nfa::const_iterator::for_end(const Nfa* /* nfa*/) -{ // {{{ - const_iterator result; - result.is_end = true; - return result; -} // for_end }}} - -Nfa::const_iterator& Nfa::const_iterator::operator++() -{ // {{{ - assert(nullptr != nfa); - - ++(this->ssIt); - const StateSet& state_set = this->tlIt->targets; - assert(!state_set.empty()); - if (this->ssIt != state_set.end()) - { - this->refresh_trans(); - return *this; - } - - // out of state set - ++(this->tlIt); - const StatePost& tlist = this->nfa->delta.state_post(this->trIt); - assert(!tlist.empty()); - if (this->tlIt != tlist.end()) - { - this->ssIt = this->tlIt->targets.begin(); - - this->refresh_trans(); - return *this; - } - - // out of transition list - ++this->trIt; - assert(this->nfa->delta.transitions.begin() != this->nfa->delta.transitions.end()); - - while (this->trIt < this->nfa->delta.num_of_states() && - this->nfa->delta.state_post(this->trIt).empty()) - { - ++this->trIt; - } - - if (this->trIt < this->nfa->delta.num_of_states()) - { - this->tlIt = this->nfa->delta.state_post(this->trIt).begin(); - assert(!this->nfa->delta.state_post(this->trIt).empty()); - const StateSet& new_state_set = this->tlIt->targets; - assert(!new_state_set.empty()); - this->ssIt = new_state_set.begin(); - - this->refresh_trans(); - return *this; - } - - // out of transitions - this->is_end = true; - - return *this; -} - -bool Nfa::const_iterator::operator==(const Nfa::const_iterator& rhs) const { - if (this->is_end && rhs.is_end) { return true; } - if ((this->is_end && !rhs.is_end) || (!this->is_end && rhs.is_end)) { return false; } - return ssIt == rhs.ssIt && tlIt == rhs.tlIt && trIt == rhs.trIt; -} - // Other versions, maybe an interesting experiment with speed of data structures. // Returns symbols appearing in Delta, pushes back to vector and then sorts mata::utils::OrdVector Nfa::get_used_symbols_vec() const { @@ -772,12 +671,7 @@ bool Nfa::is_identical(const Nfa& aut) { if (utils::OrdVector(final) != utils::OrdVector(aut.final)) { return false; } - - std::vector this_trans; - for (auto trans: *this) { this_trans.push_back(trans); } - std::vector aut_trans; - for (auto trans: aut) { aut_trans.push_back(trans); } - return this_trans == aut_trans; + return delta == aut.delta; } OrdVector Nfa::get_used_symbols() const { diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 8634f7d42..454c5dcad 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -209,6 +209,11 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { std::vector iterated_transitions{}; std::vector expected_transitions{}; + SECTION("empty automaton") { + Mata::Nfa::Delta::transitions_const_iterator it = nfa.delta.transitions.begin(); + REQUIRE(it == nfa.delta.transitions.end()); + } + SECTION("Simple NFA") { nfa.initial.insert(0); nfa.final.insert(3); @@ -237,6 +242,33 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { for (const Transition& transition: nfa.delta.transitions) { iterated_transitions.push_back(transition); } CHECK(iterated_transitions == expected_transitions); } + + SECTION("Sparse automaton") { + const size_t state_num = 'r'+1; + nfa.delta.increase_size(state_num); + + nfa.delta.add('q', 'a', 'r'); + nfa.delta.add('q', 'b', 'r'); + Delta::transitions_const_iterator it = nfa.delta.transitions.begin(); + Delta::transitions_const_iterator jt = nfa.delta.transitions.begin(); + CHECK(it == jt); + ++it; + CHECK(it != jt); + CHECK((it != nfa.delta.transitions.begin() && it != nfa.delta.transitions.end())); + CHECK(jt == nfa.delta.transitions.begin()); + + ++jt; + CHECK(it == jt); + CHECK((jt != nfa.delta.transitions.begin() && jt != nfa.delta.transitions.end())); + + jt = nfa.delta.transitions.end(); + CHECK(it != jt); + CHECK((jt != nfa.delta.transitions.begin() && jt == nfa.delta.transitions.end())); + + it = nfa.delta.transitions.end(); + CHECK(it == jt); + CHECK((it != nfa.delta.transitions.begin() && it == nfa.delta.transitions.end())); + } } TEST_CASE("Mata::Nfa::Delta::operator=()") { diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index c3f0e546c..f9c65906d 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -165,46 +165,7 @@ TEST_CASE("mata::nfa::Delta.transform/append") } // }}} -TEST_CASE("mata::nfa::Nfa iteration") -{ // {{{ - Nfa aut; - - SECTION("empty automaton") - { - auto it = aut.begin(); - REQUIRE(it == aut.end()); - } - - const size_t state_num = 'r'+1; - aut.delta.increase_size(state_num); - - SECTION("a non-empty automaton") - { - aut.delta.add('q', 'a', 'r'); - aut.delta.add('q', 'b', 'r'); - auto it = aut.delta.transitions.begin(); - auto jt = aut.delta.transitions.begin(); - REQUIRE(it == jt); - ++it; - REQUIRE(it != jt); - REQUIRE((it != aut.delta.transitions.begin() && it != aut.delta.transitions.end())); - REQUIRE(jt == aut.delta.transitions.begin()); - - ++jt; - REQUIRE(it == jt); - REQUIRE((jt != aut.delta.transitions.begin() && jt != aut.delta.transitions.end())); - - jt = aut.delta.transitions.end(); - REQUIRE(it != jt); - REQUIRE((jt != aut.delta.transitions.begin() && jt == aut.delta.transitions.end())); - - it = aut.delta.transitions.end(); - REQUIRE(it == jt); - REQUIRE((it != aut.delta.transitions.begin() && it == aut.delta.transitions.end())); - } -} // }}} - -TEST_CASE("mata::nfa::is_lang_empty()") +TEST_CASE("Mata::Nfa::is_lang_empty()") { // {{{ Nfa aut(14); Run cex; From ed9e0dc402d86ee7cf3a36699610eef0768bd7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 17 Aug 2023 12:15:22 +0200 Subject: [PATCH 06/25] Compare Delta by their transitions as 'Transition' --- include/mata/nfa/delta.hh | 2 ++ src/nfa/delta.cc | 15 +++++++++++++++ tests/nfa/delta.cc | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index efb4e352e..32cb67a33 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -243,6 +243,8 @@ public: Delta& operator=(const Delta& other); + bool operator==(const Delta& other) const; + void reserve(size_t n) { state_posts_.reserve(n); }; diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 20e3cdc8c..340bb97bd 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -431,3 +431,18 @@ bool mata::nfa::StatePost::moves_const_iterator::operator==(const StatePost::mov return symbol_post_it_ == other.symbol_post_it_ && target_states_it_ == other.target_states_it_; } } + +bool Delta::operator==(const Delta& other) const { + transitions_const_iterator this_transitions_it{ transitions_begin() }; + const transitions_const_iterator this_transitions_end{ transitions_end() }; + transitions_const_iterator other_transitions_it{ other.transitions_begin() }; + const transitions_const_iterator other_transitions_end{ other.transitions_end() }; + while (this_transitions_it != this_transitions_end) { + if (other_transitions_it == other_transitions_end || *this_transitions_it != *other_transitions_it) { + return false; + } + ++this_transitions_it; + ++other_transitions_it; + } + return other_transitions_it == other_transitions_end; +} diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 454c5dcad..3e1b69115 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -302,3 +302,24 @@ TEST_CASE("Mata::Nfa::Delta::TransitionsView") { transitions_from_source = nfa.delta.transitions.from(12); CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() }.empty()); } + +TEST_CASE("Mata::Nfa::Delta::operator==()") { + Delta delta{}; + Delta delta2{}; + CHECK(delta == delta2); + delta.add(0, 0, 0); + CHECK(delta != delta2); + delta2.add(0, 0, 0); + CHECK(delta == delta2); + delta.add(0, 0, 1); + delta2.add(0, 0, 2); + CHECK(delta != delta2); + delta2.add(0, 0, 1); + CHECK(delta != delta2); + delta.add(0, 0, 2); + CHECK(delta == delta2); + delta2.add(0, 0, 3); + CHECK(delta != delta2); + delta.add(0, 0, 3); + CHECK(delta == delta2); +} From f48dba2a3eb66c9fe5de701582a4757272e7b6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 08:02:32 +0200 Subject: [PATCH 07/25] Refactor moves --- include/mata/nfa/delta.hh | 24 ++++++++++------- src/nfa/delta.cc | 55 +++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 32cb67a33..3323069b8 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -126,8 +126,8 @@ public: */ struct moves_const_iterator { private: - const std::vector& symbol_posts_{}; - std::vector::const_iterator symbol_post_it_{}; + const StatePost* state_post_{}; + StatePost::const_iterator state_post_it_{}; StateSet::const_iterator target_states_it_{}; bool is_end_{ false }; Move move_{}; @@ -139,10 +139,11 @@ public: using pointer = Move*; using reference = Move&; - explicit moves_const_iterator(const std::vector& symbol_posts, bool is_end = false); + moves_const_iterator() = default; + explicit moves_const_iterator(const StatePost* const state_post, bool is_end = false); - moves_const_iterator(const std::vector& symbol_posts, - std::vector::const_iterator symbol_posts_it, + moves_const_iterator(const StatePost* const symbol_posts, + StatePost::const_iterator state_post_it, StateSet::const_iterator target_states_it, bool is_end = false); moves_const_iterator(const moves_const_iterator& other) = default; @@ -154,14 +155,14 @@ public: // Postfix increment const moves_const_iterator operator++(int); - moves_const_iterator& operator=(const moves_const_iterator& x); + moves_const_iterator& operator=(const moves_const_iterator& other); bool operator==(const moves_const_iterator& other) const; bool operator!=(const moves_const_iterator& other) const { return !(*this == other); }; }; - moves_const_iterator moves_cbegin() const { return moves_const_iterator(ToVector()); } - moves_const_iterator moves_cend() const { return moves_const_iterator(ToVector(), true); } + moves_const_iterator moves_cbegin() const { return moves_const_iterator(this); } + moves_const_iterator moves_cend() const { return moves_const_iterator(this, true); } moves_const_iterator moves_begin() const { return moves_cbegin(); } moves_const_iterator moves_end() const { return moves_cend(); } @@ -316,6 +317,11 @@ public: */ size_t num_of_states() const { return state_posts_.size(); } + /** + * @return Number of transitions in Delta. + */ + size_t num_of_transitions() const; + void add(State state_from, Symbol symbol, State state_to); void add(const Transition& trans) { add(trans.source, trans.symbol, trans.target); } void remove(State src, Symbol symb, State tgt); @@ -471,7 +477,7 @@ public: /** * Iterator over transitions represented as 'Transition' instances. */ - Transitions transitions() { return Transitions{ *this }; } + Transitions transitions() const { return Transitions{ *this }; } transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(*this); } transitions_const_iterator transitions_cend() const { return transitions_const_iterator(*this, true); } diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 340bb97bd..d8cae6b9b 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -352,30 +352,30 @@ void Delta::defragment(const BoolVector& is_staying, const std::vector& r } } -StatePost::moves_const_iterator::moves_const_iterator(const std::vector& symbol_posts, bool is_end) - : symbol_posts_{ symbol_posts }, symbol_post_it_{ symbol_posts_.cbegin() }, is_end_{ is_end } { - while (symbol_post_it_ != symbol_posts_.cend()) { - if (!symbol_post_it_->empty()) { - target_states_it_ = symbol_post_it_->targets.begin(); - move_.symbol = symbol_post_it_->symbol; +StatePost::moves_const_iterator::moves_const_iterator(const StatePost* state_post, bool is_end) + : state_post_{ state_post }, state_post_it_{ state_post_->cbegin() }, is_end_{ is_end } { + while (state_post_it_ != state_post_->cend()) { + if (!state_post_it_->empty()) { + target_states_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; move_.target = *target_states_it_; return; } - ++symbol_post_it_; + ++state_post_it_; } // No move found. We are at the end of moves. is_end_ = true; } StatePost::moves_const_iterator::moves_const_iterator( - const std::vector& symbol_posts, std::vector::const_iterator symbol_posts_it, + const StatePost* const symbol_posts, std::vector::const_iterator symbol_posts_it, StateSet::const_iterator target_states_it, bool is_end) - : symbol_posts_{ symbol_posts }, symbol_post_it_{ symbol_posts_it }, target_states_it_{ target_states_it }, + : state_post_{ symbol_posts }, state_post_it_{ symbol_posts_it }, target_states_it_{ target_states_it }, is_end_{ is_end } { - while (symbol_post_it_ != symbol_posts_.cend()) { - if (!symbol_post_it_->empty()) { - target_states_it_ = symbol_post_it_->targets.begin(); - move_.symbol = symbol_post_it_->symbol; + while (state_post_it_ != state_post_->cend()) { + if (!state_post_it_->empty()) { + target_states_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; move_.target = *target_states_it_; return; } @@ -385,18 +385,18 @@ StatePost::moves_const_iterator::moves_const_iterator( } StatePost::moves_const_iterator& StatePost::moves_const_iterator::operator++() { - assert(symbol_posts_.begin() != symbol_posts_.end()); + assert(state_post_->begin() != state_post_->end()); ++target_states_it_; - if (target_states_it_ != symbol_post_it_->targets.end()) { + if (target_states_it_ != state_post_it_->targets.end()) { move_.target = *target_states_it_; return *this; } - ++symbol_post_it_; - if (symbol_post_it_ != symbol_posts_.cend()) { - target_states_it_ = symbol_post_it_->targets.begin(); - move_.symbol = symbol_post_it_->symbol; + ++state_post_it_; + if (state_post_it_ != state_post_->cend()) { + target_states_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; move_.target = *target_states_it_; return *this; } @@ -411,14 +411,13 @@ const StatePost::moves_const_iterator StatePost::moves_const_iterator::operator+ return tmp; } -StatePost::moves_const_iterator& StatePost::moves_const_iterator::operator=(const StatePost::moves_const_iterator& x) { - // FIXME: this->symbol_posts is never updated, because it is a const reference to std::vector which does not have - // assignment operator defined. - is_end_ = x.is_end_; - move_.symbol = x.move_.symbol; - move_.target = x.move_.target; - symbol_post_it_ = x.symbol_post_it_; - target_states_it_ = x.target_states_it_; +StatePost::moves_const_iterator& StatePost::moves_const_iterator::operator=(const StatePost::moves_const_iterator& other) { + state_post_ = other.state_post_; + is_end_ = other.is_end_; + move_.symbol = other.move_.symbol; + move_.target = other.move_.target; + state_post_it_ = other.state_post_it_; + target_states_it_ = other.target_states_it_; return *this; } @@ -428,7 +427,7 @@ bool mata::nfa::StatePost::moves_const_iterator::operator==(const StatePost::mov } else if ((is_end_ && !other.is_end_) || (!is_end_ && other.is_end_)) { return false; } else { - return symbol_post_it_ == other.symbol_post_it_ && target_states_it_ == other.target_states_it_; + return state_post_it_ == other.state_post_it_ && target_states_it_ == other.target_states_it_; } } From be57b0e93745a1c90cc425653e5ec39c82d03842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 09:07:31 +0200 Subject: [PATCH 08/25] Move getting number of transitions to Delta --- include/mata/nfa/delta.hh | 5 ----- include/mata/nfa/nfa.hh | 7 ------- src/nfa/delta.cc | 28 +++++++++++++++------------- src/strings/nfa-noodlification.cc | 6 +++--- tests/nfa/nfa-concatenation.cc | 12 ++++++------ tests/nfa/nfa-intersection.cc | 2 +- tests/nfa/nfa.cc | 25 +++++++++++++------------ tests/parser.cc | 2 +- 8 files changed, 39 insertions(+), 48 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 3323069b8..d55e5bf28 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -250,11 +250,6 @@ public: state_posts_.reserve(n); }; - /** - * Size of delta is number of all transitions, i.e. triples of form (state, symbol, state) - */ - size_t size() const; - /** * @brief Get constant reference to the state post of @p src_state. * diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 13b8f028a..61943bdc4 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -224,13 +224,6 @@ public: */ Nfa& concatenate(const Nfa& aut); - /** - * @brief Get a number of transitions in the whole automaton. - * - * The operation has constant time complexity. - */ - size_t get_num_of_trans() const { return std::distance(delta.transitions.begin(), delta.transitions.end()); } - /** * Get transitions as a sequence of @c Trans. * @return Sequence of transitions as @c Trans. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index d8cae6b9b..e92161d04 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -59,14 +59,6 @@ StatePost::const_iterator Delta::epsilon_symbol_posts(const StatePost& state_pos return state_post.end(); } -size_t Delta::size() const { - size_t size = 0; - for (State q = 0; q < num_of_states(); ++q) { - for (const SymbolPost & m: (*this)[q]) { size = size + m.size(); } - } - return size; -} - Delta& Delta::operator=(const Delta& other) { this->state_posts_ = other.state_posts_; return *this; @@ -189,13 +181,23 @@ bool Delta::contains(const Transition& transition) const { return contains(transition.source, transition.symbol, transition.target); } -bool Delta::empty() const -{ - return this->transitions_begin() == this->transitions_end(); +size_t Delta::num_of_transitions() const { + size_t number_of_transitions{ 0 }; + for (const StatePost& state_post: state_posts_) { + for (const SymbolPost& symbol_post: state_post) { + number_of_transitions += symbol_post.size(); + } + } + return number_of_transitions; +} + +bool Delta::empty() const { + for (const StatePost& state_post: state_posts_) { + if (!state_post.empty()) { return false; } + } + return true; } -Delta::transitions_const_iterator::transitions_const_iterator(const Delta& delta, bool is_end) - : delta_{ &delta }, current_state_{ 0 }, is_end_{ is_end } { const size_t post_size = delta_->num_of_states(); for (size_t i = 0; i < post_size; ++i) { if (!(*delta_)[i].empty()) { diff --git a/src/strings/nfa-noodlification.cc b/src/strings/nfa-noodlification.cc index 8a174e5b9..81b621618 100644 --- a/src/strings/nfa-noodlification.cc +++ b/src/strings/nfa-noodlification.cc @@ -206,8 +206,8 @@ std::vector seg_nfa::noodlify_mult_eps(const for(const State& fn : segments[0].final) { SegItem new_item; - std::shared_ptr seg = segments_one_initial_final[{ unused_state, fn}]; - if(seg->final.size() != 1 || seg->get_num_of_trans() > 0) { // L(seg_iter) != {epsilon} + std::shared_ptr seg = segments_one_initial_final[{unused_state, fn}]; + if(seg->final.size() != 1 || seg->delta.num_of_transitions() > 0) { // L(seg_iter) != {epsilon} new_item.noodle.emplace_back(seg, def_eps_vector); } new_item.seg_id = 0; @@ -247,7 +247,7 @@ std::vector seg_nfa::noodlify_mult_eps(const SegItem new_item = item; // deep copy new_item.seg_id++; // do not include segmets with trivial epsilon language - if(seg_iter->second->final.size() != 1 || seg_iter->second->get_num_of_trans() > 0) { // L(seg_iter) != {epsilon} + if(seg_iter->second->final.size() != 1 || seg_iter->second->delta.num_of_transitions() > 0) { // L(seg_iter) != {epsilon} new_item.noodle.emplace_back(seg_iter->second, process_eps_map(visited_eps[tr.target])); } new_item.fin = fn; diff --git a/tests/nfa/nfa-concatenation.cc b/tests/nfa/nfa-concatenation.cc index b0a5aa270..a7a3d4bbf 100644 --- a/tests/nfa/nfa-concatenation.cc +++ b/tests/nfa/nfa-concatenation.cc @@ -419,7 +419,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[1]); CHECK(result.size() == 2); - CHECK(result.get_num_of_trans() == 1); + CHECK(result.delta.num_of_transitions() == 1); CHECK(result.delta.contains(0, EPSILON, 1)); } @@ -437,7 +437,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[2]); CHECK(result.size() == 3); - CHECK(result.get_num_of_trans() == 1); + CHECK(result.delta.num_of_transitions() == 1); CHECK(result.delta.contains(0, EPSILON, 1)); } @@ -456,7 +456,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[2]); CHECK(result.size() == 3); - CHECK(result.get_num_of_trans() == 2); + CHECK(result.delta.num_of_transitions() == 2); CHECK(result.delta.contains(1, 'a', 2)); CHECK(result.delta.contains(0, EPSILON, 1)); } @@ -477,7 +477,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[3]); CHECK(result.size() == 4); - CHECK(result.get_num_of_trans() == 3); + CHECK(result.delta.num_of_transitions() == 3); CHECK(result.delta.contains(0, 'b', 1)); CHECK(result.delta.contains(2, 'a', 3)); CHECK(result.delta.contains(1, EPSILON, 2)); @@ -504,7 +504,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[3]); CHECK(result.size() == 6); - CHECK(result.get_num_of_trans() == 4); + CHECK(result.delta.num_of_transitions() == 4); CHECK(result.delta.contains(0, 'b', 1)); CHECK(result.delta.contains(2, 'a', 3)); CHECK(result.delta.contains(2, 'c', 5)); @@ -535,7 +535,7 @@ TEST_CASE("mata::nfa::concatenate() over epsilon symbol") { CHECK(result.initial[0]); CHECK(result.final[2]); CHECK(result.size() == 3); - CHECK(result.get_num_of_trans() == 3); + CHECK(result.delta.num_of_transitions() == 3); CHECK(result.delta.contains(0, 'b', 1)); CHECK(result.delta.contains(2, 'a', 2)); CHECK(result.delta.contains(1, EPSILON, 2)); diff --git a/tests/nfa/nfa-intersection.cc b/tests/nfa/nfa-intersection.cc index 63085b194..ef6e73b5a 100644 --- a/tests/nfa/nfa-intersection.cc +++ b/tests/nfa/nfa-intersection.cc @@ -243,7 +243,7 @@ TEST_CASE("mata::nfa::intersection() with preserving epsilon transitions") CHECK(result.final.size() == 4); // Check transitions. - CHECK(result.get_num_of_trans() == 15); + CHECK(result.delta.num_of_transitions() == 15); CHECK(result.delta.contains(prod_map[{0, 0}], EPSILON, prod_map[{1, 0}])); CHECK(result.delta.transitions.from(prod_map[{ 0, 0 }]).count() == 1); diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index f9c65906d..0a2b38072 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -4,7 +4,8 @@ #include -#include "utils.hh" +#include "mata/nfa/delta.hh" +#include "nfa-util.hh" #include "mata/utils/sparse-set.hh" #include "mata/nfa/nfa.hh" @@ -972,7 +973,7 @@ TEST_CASE("mata::nfa::complement()") REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["b"], alph["b"], alph["a"]}, {}})); REQUIRE(cmpl.initial.size() == 1); REQUIRE(cmpl.final.size() == 1); - REQUIRE(cmpl.get_num_of_trans() == 4); + REQUIRE(cmpl.delta.num_of_transitions() == 4); } SECTION("non-empty automaton accepting a*b*") @@ -998,7 +999,7 @@ TEST_CASE("mata::nfa::complement()") REQUIRE(cmpl.initial.size() == 1); REQUIRE(cmpl.final.size() == 1); - REQUIRE(cmpl.get_num_of_trans() == 6); + REQUIRE(cmpl.delta.num_of_transitions() == 6); } SECTION("empty automaton, empty alphabet, minimization") @@ -1675,7 +1676,7 @@ TEST_CASE("mata::nfa::revert()") REQUIRE(result.initial[2]); REQUIRE(result.final[1]); REQUIRE(result.delta.contains(2, 'a', 1)); - REQUIRE(result.delta.size() == aut.delta.size()); + REQUIRE(result.delta.num_of_transitions() == aut.delta.num_of_transitions()); } SECTION("bigger automaton") @@ -1716,7 +1717,7 @@ TEST_CASE("mata::nfa::revert()") CHECK(res.initial[5]); CHECK(res.final[1]); CHECK(res.final[3]); - CHECK(res.get_num_of_trans() == 15); + CHECK(res.delta.num_of_transitions() == 15); CHECK(res.delta.contains(5, 'a', 5)); CHECK(res.delta.contains(5, 'a', 7)); CHECK(res.delta.contains(9, 'a', 9)); @@ -1741,7 +1742,7 @@ TEST_CASE("mata::nfa::revert()") CHECK(res.initial[2]); CHECK(res.initial[12]); CHECK(res.final[4]); - CHECK(res.get_num_of_trans() == 12); + CHECK(res.delta.num_of_transitions() == 12); CHECK(res.delta.contains(8, 'a', 4)); CHECK(res.delta.contains(8, 'c', 4)); CHECK(res.delta.contains(4, 'b', 8)); @@ -2086,9 +2087,9 @@ TEST_CASE("mata::nfa::reduce_size_by_simulation()") result = reduce(aut.trim(), &state_renaming); CHECK(result.size() == 3); - CHECK(result.initial == SparseSet{ 0, 1 }); - CHECK(result.final == SparseSet{ 2 }); - CHECK(result.delta.size() == 6); + CHECK(result.initial == SparseSet{ 0, 1 }); + CHECK(result.final == SparseSet{ 2 }); + CHECK(result.delta.num_of_transitions() == 6); CHECK(result.delta.contains(state_renaming[0], 'a', state_renaming[2])); CHECK(result.delta.contains(state_renaming[0], 'a', state_renaming[1])); CHECK(result.delta.contains(state_renaming[1], 'a', state_renaming[1])); @@ -2245,7 +2246,7 @@ TEST_CASE("mata::nfa::get_num_of_trans()") { Nfa aut{20}; FILL_WITH_AUT_A(aut); - REQUIRE(aut.get_num_of_trans() == 15); + REQUIRE(aut.delta.num_of_transitions() == 15); } TEST_CASE("mata::nfa::get_one_letter_aut()") @@ -2257,7 +2258,7 @@ TEST_CASE("mata::nfa::get_one_letter_aut()") Nfa digraph{aut.get_one_letter_aut() }; REQUIRE(digraph.size() == aut.size()); - REQUIRE(digraph.get_num_of_trans() == 12); + REQUIRE(digraph.delta.num_of_transitions() == 12); REQUIRE(digraph.delta.contains(1, abstract_symbol, 10)); REQUIRE(digraph.delta.contains(10, abstract_symbol, 7)); REQUIRE(!digraph.delta.contains(10, 'a', 7)); @@ -2466,7 +2467,7 @@ TEST_CASE("mata::nfa::delta.operator[]") { Nfa aut{20}; FILL_WITH_AUT_A(aut); - REQUIRE(aut.get_num_of_trans() == 15); + REQUIRE(aut.delta.num_of_transitions() == 15); aut.delta[25]; REQUIRE(aut.size() == 20); diff --git a/tests/parser.cc b/tests/parser.cc index 11246aa7b..849f80710 100644 --- a/tests/parser.cc +++ b/tests/parser.cc @@ -436,7 +436,7 @@ TEST_CASE("correct use of mata::Parser::parse_mf_section()") CHECK(aut.final.size() == 1); CHECK(aut.initial.contains(0)); CHECK(aut.delta.contains(0, 0, 0) == 1); - CHECK(aut.delta.size() == 1); + CHECK(aut.delta.num_of_transitions() == 1); } } // parse_mf_section correct }}} From 18c362ec4168d4b6714b16ea63f8c9aa3ba0fab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 09:09:40 +0200 Subject: [PATCH 09/25] Move const iterator over transitions into Transitions class --- include/mata/nfa/delta.hh | 150 +++++++++++------------------- src/nfa/delta.cc | 32 +++---- src/nfa/operations.cc | 2 +- tests/nfa/delta.cc | 50 +++++----- tests/strings/nfa-segmentation.cc | 6 +- 5 files changed, 98 insertions(+), 142 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index d55e5bf28..2e095019a 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -376,108 +376,68 @@ public: const_iterator end() const { return state_posts_.end(); } /** - * Iterator over transitions. It iterates over triples (lhs, symbol, rhs) where lhs and rhs are states. - */ - class transitions_const_iterator { - private: - const Delta* delta_ = nullptr; - size_t current_state_; - StatePost::const_iterator state_post_it_{}; - StateSet::const_iterator symbol_post_it_{}; - bool is_end_{ false }; - Transition transition_{}; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = Transition; - using difference_type = unsigned; - using pointer = Transition*; - using reference = Transition&; - - transitions_const_iterator() = default; - explicit transitions_const_iterator(const Delta& delta, bool is_end = false); - transitions_const_iterator(const Delta& delta, State current_state, bool is_end = false); - - transitions_const_iterator(const transitions_const_iterator& other) noexcept = default; - transitions_const_iterator(transitions_const_iterator&&) = default; - - const Transition& operator*() const { return transition_; } - - // Prefix increment - transitions_const_iterator& operator++(); - // Postfix increment - const transitions_const_iterator operator++(int); - - transitions_const_iterator& operator=(const transitions_const_iterator& other) noexcept = default; - transitions_const_iterator& operator=(transitions_const_iterator&&) = default; - - bool operator==(const transitions_const_iterator& other) const; - bool operator!=(const transitions_const_iterator& other) const { return !(*this == other); }; - }; // class transitions_const_iterator. - - class TransitionsView { - private: - transitions_const_iterator begin_; - transitions_const_iterator end_; - public: - TransitionsView() = default; - TransitionsView(const TransitionsView&) = default; - TransitionsView(TransitionsView&&) = default; - TransitionsView(transitions_const_iterator begin, transitions_const_iterator end): begin_{ begin }, end_{ end } {} - TransitionsView& operator=(const TransitionsView&) = default; - TransitionsView& operator=(TransitionsView&&) = default; - transitions_const_iterator begin() const { return begin_; } - transitions_const_iterator end() const { return end_; } - size_t count() const { return std::distance( begin(), end() ); } - size_t empty() const { return count() == 0; } - }; - - /** - * Iterator over transitions represented as 'Transition' instances. + * @brief Iterator over transitions represented as @c Transition instances. + * + * It iterates over triples (source, symbol, target). */ class Transitions { - private: - const Delta& delta_; public: - explicit Transitions(const Delta& delta): delta_{ delta } {} - transitions_const_iterator begin() const { return delta_.transitions_cbegin(); } - transitions_const_iterator end() const { return delta_.transitions_cend(); } - - /** - * @brief Get a number of transitions in delta. - * - * The operation has a linear time complexity to the number of transitions in the delta. - */ - size_t count() const { return std::distance(begin(), end()); } - - size_t empty() const { return count() == 0; } - - // TODO: Is 'from_source()' than 'from()'? - TransitionsView from(State source) const; - }; - /** - * @brief Get a number of transitions in delta. - * - * The operation has a linear time complexity to the number of 'SymbolPost's in the delta. + * Iterator over transitions. */ - size_t count() const { return delta_.size(); } - - /** - * Whether there are no transitions in the delta. - */ - bool empty() const { return count() == 0; } + class const_iterator { + private: + const Delta* delta_ = nullptr; + size_t current_state_; + StatePost::const_iterator state_post_it_{}; + StateSet::const_iterator symbol_post_it_{}; + bool is_end_{ false }; + Transition transition_{}; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = Transition; + using difference_type = unsigned; + using pointer = Transition*; + using reference = Transition&; + + const_iterator() = default; + explicit const_iterator(const Delta* delta, bool is_end = false); + const_iterator(const Delta* delta, State current_state, bool is_end = false); + + const_iterator(const const_iterator& other) noexcept = default; + const_iterator(const_iterator&&) = default; + + const Transition& operator*() const { return transition_; } + + // Prefix increment + const_iterator& operator++(); + // Postfix increment + const const_iterator operator++(int); + + const_iterator& operator=(const const_iterator& other) noexcept = default; + const_iterator& operator=(const_iterator&&) = default; + + bool operator==(const const_iterator& other) const; + bool operator!=(const const_iterator& other) const { return !(*this == other); }; + }; // class const_const_iterator. + + explicit Transitions(const Delta* delta): delta_{ delta } {} + Transitions(Transitions&&) = default; + Transitions(Transitions&) = default; + Transitions& operator=(Transitions&&) = default; + Transitions& operator=(Transitions&) = default; + + const_iterator begin() const { return const_iterator{ delta_ }; }; + const_iterator end() const { return const_iterator{ delta_, true}; }; + private: + const Delta* delta_; }; // class Transitions. /** * Iterator over transitions represented as 'Transition' instances. */ - Transitions transitions() const { return Transitions{ *this }; } - - transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(*this); } - transitions_const_iterator transitions_cend() const { return transitions_const_iterator(*this, true); } - transitions_const_iterator transitions_begin() const { return transitions_cbegin(); } - transitions_const_iterator transitions_end() const { return transitions_cend(); } + Transitions transitions() const { return Transitions{ this }; } /** * Iterate over @p epsilon symbol posts under the given @p state. @@ -496,11 +456,7 @@ public: static StatePost::const_iterator epsilon_symbol_posts(const StatePost& state_post, Symbol epsilon = EPSILON); private: std::vector state_posts_; - transitions_const_iterator transitions_cbegin() const { return transitions_const_iterator(*this); } - transitions_const_iterator transitions_cend() const { return transitions_const_iterator(*this, true); } - transitions_const_iterator transitions_begin() const { return transitions_cbegin(); } - transitions_const_iterator transitions_end() const { return transitions_cend(); } -}; // struct Delta. +}; // class Delta. } // namespace mata::nfa. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index e92161d04..53ff503fb 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -64,12 +64,6 @@ Delta& Delta::operator=(const Delta& other) { return *this; } -Delta::TransitionsView Delta::Transitions::from(const State source) const { - transitions_const_iterator begin_it{ delta_, source }; - transitions_const_iterator end_it{ delta_, source + 1 }; - return TransitionsView{ begin_it, end_it }; -} - void Delta::add(State source, Symbol symbol, State target) { const State max_state{ std::max(source, target) }; if (max_state >= state_posts_.size()) { @@ -198,6 +192,8 @@ bool Delta::empty() const { return true; } +Delta::Transitions::const_iterator::const_iterator(const Delta* delta, bool is_end) + : delta_{ delta }, current_state_{ 0 }, is_end_{ is_end } { const size_t post_size = delta_->num_of_states(); for (size_t i = 0; i < post_size; ++i) { if (!(*delta_)[i].empty()) { @@ -215,9 +211,9 @@ bool Delta::empty() const { is_end_ = true; } -Delta::transitions_const_iterator::transitions_const_iterator( - const Delta& delta, State current_state, bool is_end) - : delta_{ &delta }, current_state_{ current_state }, is_end_{ is_end } { +Delta::Transitions::const_iterator::const_iterator( + const Delta* delta, State current_state, bool is_end) + : delta_{ delta }, current_state_{ current_state }, is_end_{ is_end } { const size_t post_size = delta_->num_of_states(); for (State source{ current_state_ }; source < post_size; ++source) { const StatePost& state_post{ delta_->state_post(source) }; @@ -236,7 +232,7 @@ Delta::transitions_const_iterator::transitions_const_iterator( is_end_ = true; } -Delta::transitions_const_iterator& Delta::transitions_const_iterator::operator++() { +Delta::Transitions::const_iterator& Delta::Transitions::const_iterator::operator++() { assert(delta_->begin() != delta_->end()); ++symbol_post_it_; @@ -273,13 +269,13 @@ Delta::transitions_const_iterator& Delta::transitions_const_iterator::operator++ return *this; } -const Delta::transitions_const_iterator Delta::transitions_const_iterator::operator++(int) { - const transitions_const_iterator tmp = *this; +const Delta::Transitions::const_iterator Delta::Transitions::const_iterator::operator++(int) { + const Delta::Transitions::const_iterator tmp{ *this }; ++(*this); return tmp; } -bool Mata::Nfa::Delta::transitions_const_iterator::operator==(const Delta::transitions_const_iterator& other) const { +bool Delta::Transitions::const_iterator::operator==(const Delta::Transitions::const_iterator& other) const { if (is_end_ && other.is_end_) { return true; } else if ((is_end_ && !other.is_end_) || (!is_end_ && other.is_end_)) { @@ -434,10 +430,12 @@ bool mata::nfa::StatePost::moves_const_iterator::operator==(const StatePost::mov } bool Delta::operator==(const Delta& other) const { - transitions_const_iterator this_transitions_it{ transitions_begin() }; - const transitions_const_iterator this_transitions_end{ transitions_end() }; - transitions_const_iterator other_transitions_it{ other.transitions_begin() }; - const transitions_const_iterator other_transitions_end{ other.transitions_end() }; + Delta::Transitions this_transitions{ transitions() }; + Delta::Transitions::const_iterator this_transitions_it{ this_transitions.begin() }; + const Delta::Transitions::const_iterator this_transitions_end{ this_transitions.end() }; + Delta::Transitions other_transitions{ other.transitions() }; + Delta::Transitions::const_iterator other_transitions_it{ other_transitions.begin() }; + const Delta::Transitions::const_iterator other_transitions_end{ other_transitions.end() }; while (this_transitions_it != this_transitions_end) { if (other_transitions_it == other_transitions_end || *this_transitions_it != *other_transitions_it) { return false; diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index bc4042f25..a0aabbd8a 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -42,7 +42,7 @@ namespace { const size_t state_num = aut.size(); Simlib::ExplicitLTS LTSforSimulation(state_num); - for (const Transition& transition : aut.delta.transitions) { + for (const Transition& transition : aut.delta.transitions()) { LTSforSimulation.add_transition(transition.source, transition.symbol, transition.target); if (transition.symbol > maxSymbol) { maxSymbol = transition.symbol; diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 3e1b69115..fd5c0f4fb 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -73,7 +73,7 @@ TEST_CASE("Mata::nfa::Delta::state_post()") { CHECK_NOTHROW(aut.delta.add(0, 1, { 3, 4, 5, 6 })); CHECK_NOTHROW(aut.delta.add(26, 1, StateSet{})); CHECK_NOTHROW(aut.delta.add(42, 1, StateSet{ 43 })); - CHECK(aut.get_num_of_trans() == 5); + CHECK(aut.delta.num_of_transitions() == 5); } } @@ -210,8 +210,8 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { std::vector expected_transitions{}; SECTION("empty automaton") { - Mata::Nfa::Delta::transitions_const_iterator it = nfa.delta.transitions.begin(); - REQUIRE(it == nfa.delta.transitions.end()); + Mata::Nfa::Delta::Transitions transitions{ nfa.delta.transitions() }; + REQUIRE(transitions.begin() == transitions.end()); } SECTION("Simple NFA") { @@ -224,7 +224,7 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { nfa.delta.add(2, 0, 1); nfa.delta.add(2, 0, 3); - mata::nfa::Delta::Transitions transitions{ nfa.delta.transitions() }; + Mata::Nfa::Delta::Transitions transitions{ nfa.delta.transitions() }; iterated_transitions.clear(); for (auto transitions_it{ transitions.begin() }; transitions_it != transitions.end(); ++transitions_it) { @@ -239,7 +239,7 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { CHECK(iterated_transitions == expected_transitions); iterated_transitions.clear(); - for (const Transition& transition: nfa.delta.transitions) { iterated_transitions.push_back(transition); } + for (const Transition& transition: nfa.delta.transitions()) { iterated_transitions.push_back(transition); } CHECK(iterated_transitions == expected_transitions); } @@ -249,25 +249,26 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { nfa.delta.add('q', 'a', 'r'); nfa.delta.add('q', 'b', 'r'); - Delta::transitions_const_iterator it = nfa.delta.transitions.begin(); - Delta::transitions_const_iterator jt = nfa.delta.transitions.begin(); + const Delta::Transitions transitions{ nfa.delta.transitions() }; + Delta::Transitions::const_iterator it{ transitions.begin() }; + Delta::Transitions::const_iterator jt{ transitions.begin() }; CHECK(it == jt); ++it; CHECK(it != jt); - CHECK((it != nfa.delta.transitions.begin() && it != nfa.delta.transitions.end())); - CHECK(jt == nfa.delta.transitions.begin()); + CHECK((it != transitions.begin() && it != transitions.end())); + CHECK(jt == transitions.begin()); ++jt; CHECK(it == jt); - CHECK((jt != nfa.delta.transitions.begin() && jt != nfa.delta.transitions.end())); + CHECK((jt != transitions.begin() && jt != transitions.end())); - jt = nfa.delta.transitions.end(); + jt = transitions.end(); CHECK(it != jt); - CHECK((jt != nfa.delta.transitions.begin() && jt == nfa.delta.transitions.end())); + CHECK((jt != transitions.begin() && jt == transitions.end())); - it = nfa.delta.transitions.end(); + it = transitions.end(); CHECK(it == jt); - CHECK((it != nfa.delta.transitions.begin() && it == nfa.delta.transitions.end())); + CHECK((it != transitions.begin() && it == transitions.end())); } } @@ -279,11 +280,11 @@ TEST_CASE("Mata::Nfa::Delta::operator=()") { Nfa copied_nfa{ nfa }; nfa.delta.add(1, 'b', 0); - CHECK(nfa.delta.transitions.count() == 2); - CHECK(copied_nfa.delta.transitions.count() == 1); + CHECK(nfa.delta.num_of_transitions() == 2); + CHECK(copied_nfa.delta.num_of_transitions() == 1); } -TEST_CASE("Mata::Nfa::Delta::TransitionsView") { +TEST_CASE("Mata::Nfa::StatePost::Moves") { Nfa nfa{}; nfa.initial.insert(0); nfa.final.insert(5); @@ -294,13 +295,14 @@ TEST_CASE("Mata::Nfa::Delta::TransitionsView") { nfa.delta.add(2, 'e', 3); nfa.delta.add(3, 'e', 4); nfa.delta.add(4, 'f', 5); - Delta::TransitionsView transitions_from_source{ nfa.delta.transitions.from(0) }; - CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() } == std::vector{ { 0, 'a', 1 }}); - transitions_from_source = nfa.delta.transitions.from(1); - CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() } == - std::vector{ { 1, 'b', 2 }, { 1, 'c', 2 }, { 1, 'd', 2 } }); - transitions_from_source = nfa.delta.transitions.from(12); - CHECK(std::vector{ transitions_from_source.begin(), transitions_from_source.end() }.empty()); + // TODO: rewrite in a check of moves. + StatePost::Moves moves_from_source{ nfa.delta[0].moves() }; + CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() } == std::vector{ { 'a', 1 }}); + moves_from_source = nfa.delta[1].moves(); + CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() } == + std::vector{ { 'b', 2 }, { 'c', 2 }, { 'd', 2 } }); + moves_from_source = nfa.delta[12].moves(); + CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() }.empty()); } TEST_CASE("Mata::Nfa::Delta::operator==()") { diff --git a/tests/strings/nfa-segmentation.cc b/tests/strings/nfa-segmentation.cc index 0ed7ec9d3..78916b379 100644 --- a/tests/strings/nfa-segmentation.cc +++ b/tests/strings/nfa-segmentation.cc @@ -180,7 +180,7 @@ TEST_CASE("mata::nfa::Segmentation::split_segment_automaton()") { CHECK(segments[0].final.size() == 2); CHECK(segments[0].final[0]); CHECK(segments[0].final[1]); - CHECK(segments[0].get_num_of_trans() == 1); + CHECK(segments[0].delta.num_of_transitions() == 1); CHECK(segments[0].delta.contains(0, 'a', 1)); CHECK(segments[1].initial.size() == 2); @@ -189,7 +189,7 @@ TEST_CASE("mata::nfa::Segmentation::split_segment_automaton()") { CHECK(segments[1].final.size() == 2); CHECK(segments[1].final[0]); CHECK(segments[1].final[2]); - CHECK(segments[1].get_num_of_trans() == 1); + CHECK(segments[1].delta.num_of_transitions() == 1); CHECK(segments[1].delta.contains(1, 'b', 2)); CHECK(segments[2].initial.size() == 2); @@ -198,6 +198,6 @@ TEST_CASE("mata::nfa::Segmentation::split_segment_automaton()") { CHECK(segments[2].final.size() == 2); CHECK(segments[2].final[0]); CHECK(segments[2].final[1]); - CHECK(segments[2].get_num_of_trans() == 0); + CHECK(segments[2].delta.num_of_transitions() == 0); } } From 1c83d5a29d7bff50e59425d3e36913a306260593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 09:10:14 +0200 Subject: [PATCH 10/25] Remove getting transtions as sequence --- include/mata/nfa/nfa.hh | 6 ------ src/nfa/nfa.cc | 18 ------------------ tests/nfa/nfa.cc | 10 ++++++---- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 61943bdc4..d3bdab7c3 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -224,12 +224,6 @@ public: */ Nfa& concatenate(const Nfa& aut); - /** - * Get transitions as a sequence of @c Trans. - * @return Sequence of transitions as @c Trans. - */ - std::vector get_trans_as_sequence() const; - /** * Get transitions leading to @p state_to. * @param state_to[in] Target state for transitions to get. diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index e17b310d4..e1c24b5c0 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -399,24 +399,6 @@ void Nfa::print_to_mata(std::ostream &output) const { } } -std::vector Nfa::get_trans_as_sequence() const -{ - std::vector trans_sequence{}; - - for (State state_from{ 0 }; state_from < delta.num_of_states(); ++state_from) - { - for (const auto& transition_from_state: delta[state_from]) - { - for (State state_to: transition_from_state.targets) - { - trans_sequence.push_back(Transition{ state_from, transition_from_state.symbol, state_to }); - } - } - } - - return trans_sequence; -} - Nfa Nfa::get_one_letter_aut(Symbol abstract_symbol) const { Nfa digraph{size(), StateSet(initial), StateSet(final) }; // Add directed transitions for digraph. diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index 0a2b38072..6e8f0fc8a 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -124,8 +124,9 @@ TEST_CASE("mata::nfa::Nfa::delta.add()/delta.contains()") size_t transitions_cnt{ 0 }; std::vector expected_transitions{ t1, t2, t3, t4 }; std::vector iterated_transitions{}; - for (Delta::transitions_const_iterator trans_it{ a.delta.transitions.begin()}; - trans_it != a.delta.transitions.end(); ++trans_it) { + const Delta::Transitions transitions{ a.delta.transitions() }; + const Delta::Transitions::const_iterator transitions_end{ transitions.end() }; + for (Delta::Transitions::const_iterator trans_it{ transitions.begin()}; trans_it != transitions_end; ++trans_it) { iterated_transitions.push_back(*trans_it); ++transitions_cnt; } @@ -134,7 +135,7 @@ TEST_CASE("mata::nfa::Nfa::delta.add()/delta.contains()") transitions_cnt = 0; iterated_transitions.clear(); - for (const Transition& trans: a.delta.transitions) { + for (const Transition& trans: a.delta.transitions()) { iterated_transitions.push_back(trans); ++transitions_cnt; } @@ -2212,7 +2213,8 @@ TEST_CASE("mata::nfa::get_trans_as_sequence(}") { expected.emplace_back(2, 3, 4); - REQUIRE(aut.get_trans_as_sequence() == expected); + const Delta::Transitions transitions{ aut.delta.transitions() }; + REQUIRE(std::vector{ transitions.begin(), transitions.end() } == expected); } TEST_CASE("mata::nfa::remove_epsilon()") From ebba47762ebdbb9a57e747d61de2a7aedc6e7559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 10:53:36 +0200 Subject: [PATCH 11/25] Refactor Moves to reflect structure of Transitions --- include/mata/nfa/delta.hh | 101 +++++++++++++++++---------------- src/nfa/delta.cc | 104 +++++++++++++--------------------- tests/nfa/nfa-intersection.cc | 26 ++++----- 3 files changed, 106 insertions(+), 125 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 2e095019a..31cfd5ea9 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -121,65 +121,70 @@ public: const_iterator find(const Symbol symbol) const { return super::find({ symbol, {} }); } /** - * Iterator over moves. It iterates over pairs (symbol, target state) for a current source state whose state post - * we iterate. + * @brief Iterator over moves represented as @c Move instances. + * + * It iterates over pairs (symbol, target) for the given @c StatePost. */ - struct moves_const_iterator { - private: - const StatePost* state_post_{}; - StatePost::const_iterator state_post_it_{}; - StateSet::const_iterator target_states_it_{}; - bool is_end_{ false }; - Move move_{}; - + class Moves { public: - using iterator_category = std::forward_iterator_tag; - using value_type = Move; - using difference_type = unsigned; - using pointer = Move*; - using reference = Move&; + /** + * Iterator over moves. + */ + class const_iterator { + private: + const StatePost* state_post_ = nullptr; + StatePost::const_iterator state_post_it_{}; + StateSet::const_iterator symbol_post_it_{}; + bool is_end_{ false }; + Move move_{}; - moves_const_iterator() = default; - explicit moves_const_iterator(const StatePost* const state_post, bool is_end = false); + public: + using iterator_category = std::forward_iterator_tag; + using value_type = Move; + using difference_type = unsigned; + using pointer = Move*; + using reference = Move&; - moves_const_iterator(const StatePost* const symbol_posts, - StatePost::const_iterator state_post_it, - StateSet::const_iterator target_states_it, bool is_end = false); + const_iterator(): is_end_{ true } {} + const_iterator(const StatePost* state_post); + const_iterator(const const_iterator& other) noexcept = default; + const_iterator(const_iterator&&) = default; - moves_const_iterator(const moves_const_iterator& other) = default; + const Move& operator*() const { return move_; } - const Move& operator*() const { return move_; } + // Prefix increment + const_iterator& operator++(); + // Postfix increment + const const_iterator operator++(int); - // Prefix increment - moves_const_iterator& operator++(); - // Postfix increment - const moves_const_iterator operator++(int); + const_iterator& operator=(const const_iterator& other) noexcept = default; + const_iterator& operator=(const_iterator&&) = default; - moves_const_iterator& operator=(const moves_const_iterator& other); + bool operator==(const const_iterator& other) const; + }; // class const_iterator. - bool operator==(const moves_const_iterator& other) const; - bool operator!=(const moves_const_iterator& other) const { return !(*this == other); }; - }; + explicit Moves(const StatePost* state_post): state_post_{ state_post } {} + Moves(Moves&&) = default; + Moves(Moves&) = default; + Moves& operator=(Moves&&) = default; + Moves& operator=(Moves&) = default; - moves_const_iterator moves_cbegin() const { return moves_const_iterator(this); } - moves_const_iterator moves_cend() const { return moves_const_iterator(this, true); } - moves_const_iterator moves_begin() const { return moves_cbegin(); } - moves_const_iterator moves_end() const { return moves_cend(); } + const_iterator begin() const { return const_iterator{ state_post_ }; }; + const_iterator end() const { return const_iterator{}; }; + private: + const StatePost* state_post_; + }; // class Moves. - class Moves { - public: - moves_const_iterator begin_; - moves_const_iterator end_; - moves_const_iterator begin() const { return begin_; } - moves_const_iterator end() const { return end_; } - }; + /** + * Iterator over transitions represented as 'Transition' instances. + */ + Moves moves() const { return Moves{ this }; } /** - * Iterate over moves represented as 'Move' instances. - * @return Iterator over moves. + * Count the number of moves in StatePost. */ - Moves moves() const { return { .begin_ = moves_begin(), .end_ = moves_end() }; } -}; // struct Post. + size_t num_of_moves() const; +}; // class StatePost. /** * @brief Specialization of utils::SynchronizedExistentialIterator for iterating over SymbolPosts. @@ -383,7 +388,7 @@ public: class Transitions { public: /** - * Iterator over transitions. + * Iterator over transitions. */ class const_iterator { private: @@ -420,7 +425,7 @@ public: bool operator==(const const_iterator& other) const; bool operator!=(const const_iterator& other) const { return !(*this == other); }; - }; // class const_const_iterator. + }; // class Transitions::const_iterator. explicit Transitions(const Delta* delta): delta_{ delta } {} Transitions(Transitions&&) = default; @@ -437,7 +442,7 @@ public: /** * Iterator over transitions represented as 'Transition' instances. */ - Transitions transitions() const { return Transitions{ this }; } + Transitions transitions() const { return Transitions{ this }; } /** * Iterate over @p epsilon symbol posts under the given @p state. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 53ff503fb..faa6ac981 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -350,98 +350,74 @@ void Delta::defragment(const BoolVector& is_staying, const std::vector& r } } -StatePost::moves_const_iterator::moves_const_iterator(const StatePost* state_post, bool is_end) - : state_post_{ state_post }, state_post_it_{ state_post_->cbegin() }, is_end_{ is_end } { - while (state_post_it_ != state_post_->cend()) { - if (!state_post_it_->empty()) { - target_states_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *target_states_it_; - return; +bool Delta::operator==(const Delta& other) const { + Delta::Transitions this_transitions{ transitions() }; + Delta::Transitions::const_iterator this_transitions_it{ this_transitions.begin() }; + const Delta::Transitions::const_iterator this_transitions_end{ this_transitions.end() }; + Delta::Transitions other_transitions{ other.transitions() }; + Delta::Transitions::const_iterator other_transitions_it{ other_transitions.begin() }; + const Delta::Transitions::const_iterator other_transitions_end{ other_transitions.end() }; + while (this_transitions_it != this_transitions_end) { + if (other_transitions_it == other_transitions_end || *this_transitions_it != *other_transitions_it) { + return false; } - ++state_post_it_; + ++this_transitions_it; + ++other_transitions_it; } - // No move found. We are at the end of moves. - is_end_ = true; + return other_transitions_it == other_transitions_end; } -StatePost::moves_const_iterator::moves_const_iterator( - const StatePost* const symbol_posts, std::vector::const_iterator symbol_posts_it, - StateSet::const_iterator target_states_it, bool is_end) - : state_post_{ symbol_posts }, state_post_it_{ symbol_posts_it }, target_states_it_{ target_states_it }, - is_end_{ is_end } { - while (state_post_it_ != state_post_->cend()) { - if (!state_post_it_->empty()) { - target_states_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *target_states_it_; - return; - } - } - // No move found. We are at the end of moves. - is_end_ = true; -} +StatePost::Moves::const_iterator::const_iterator(const StatePost* state_post, bool is_end) + : state_post_{ state_post }, is_end_{ is_end } { + if (!state_post_->empty()) { + state_post_it_ = state_post_->begin(); + symbol_post_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; + move_.target = *symbol_post_it_; + return; + } -StatePost::moves_const_iterator& StatePost::moves_const_iterator::operator++() { - assert(state_post_->begin() != state_post_->end()); + // No transition found, 'state_post' is an empty state post. + is_end_ = true; +} - ++target_states_it_; - if (target_states_it_ != state_post_it_->targets.end()) { - move_.target = *target_states_it_; +StatePost::Moves::const_iterator& StatePost::Moves::const_iterator::operator++() { + ++symbol_post_it_; + if (symbol_post_it_ != state_post_it_->targets.end()) { + move_.target = *symbol_post_it_; return *this; } ++state_post_it_; if (state_post_it_ != state_post_->cend()) { - target_states_it_ = state_post_it_->targets.begin(); + symbol_post_it_ = state_post_it_->targets.begin(); move_.symbol = state_post_it_->symbol; - move_.target = *target_states_it_; + move_.target = *symbol_post_it_; return *this; } - is_end_ = true; return *this; } -const StatePost::moves_const_iterator StatePost::moves_const_iterator::operator++(int) { - const moves_const_iterator tmp = *this; +const StatePost::Moves::const_iterator StatePost::Moves::const_iterator::operator++(int) { + const StatePost::Moves::const_iterator tmp{ *this }; ++(*this); return tmp; } -StatePost::moves_const_iterator& StatePost::moves_const_iterator::operator=(const StatePost::moves_const_iterator& other) { - state_post_ = other.state_post_; - is_end_ = other.is_end_; - move_.symbol = other.move_.symbol; - move_.target = other.move_.target; - state_post_it_ = other.state_post_it_; - target_states_it_ = other.target_states_it_; - return *this; -} - -bool mata::nfa::StatePost::moves_const_iterator::operator==(const StatePost::moves_const_iterator& other) const { +bool StatePost::Moves::const_iterator::operator==(const StatePost::Moves::const_iterator& other) const { if (is_end_ && other.is_end_) { return true; } else if ((is_end_ && !other.is_end_) || (!is_end_ && other.is_end_)) { return false; - } else { - return state_post_it_ == other.state_post_it_ && target_states_it_ == other.target_states_it_; } + return state_post_it_ == other.state_post_it_ && symbol_post_it_ == other.symbol_post_it_; } -bool Delta::operator==(const Delta& other) const { - Delta::Transitions this_transitions{ transitions() }; - Delta::Transitions::const_iterator this_transitions_it{ this_transitions.begin() }; - const Delta::Transitions::const_iterator this_transitions_end{ this_transitions.end() }; - Delta::Transitions other_transitions{ other.transitions() }; - Delta::Transitions::const_iterator other_transitions_it{ other_transitions.begin() }; - const Delta::Transitions::const_iterator other_transitions_end{ other_transitions.end() }; - while (this_transitions_it != this_transitions_end) { - if (other_transitions_it == other_transitions_end || *this_transitions_it != *other_transitions_it) { - return false; - } - ++this_transitions_it; - ++other_transitions_it; +size_t StatePost::num_of_moves() const { + size_t counter{ 0 }; + for (const SymbolPost& symbol_post: *this) { + counter += symbol_post.size(); } - return other_transitions_it == other_transitions_end; + return counter; } diff --git a/tests/nfa/nfa-intersection.cc b/tests/nfa/nfa-intersection.cc index ef6e73b5a..0e096e2b8 100644 --- a/tests/nfa/nfa-intersection.cc +++ b/tests/nfa/nfa-intersection.cc @@ -246,45 +246,45 @@ TEST_CASE("mata::nfa::intersection() with preserving epsilon transitions") CHECK(result.delta.num_of_transitions() == 15); CHECK(result.delta.contains(prod_map[{0, 0}], EPSILON, prod_map[{1, 0}])); - CHECK(result.delta.transitions.from(prod_map[{ 0, 0 }]).count() == 1); + CHECK(result.delta.state_post(prod_map[{ 0, 0 }]).num_of_moves() == 1); CHECK(result.delta.contains(prod_map[{1, 0}], 'b', prod_map[{1, 1}])); CHECK(result.delta.contains(prod_map[{1, 0}], 'a', prod_map[{1, 2}])); CHECK(result.delta.contains(prod_map[{1, 0}], 'c', prod_map[{2, 5}])); - CHECK(result.delta.transitions.from(prod_map[{ 1, 0 }]).count() == 3); + CHECK(result.delta.state_post(prod_map[{ 1, 0 }]).num_of_moves() == 3); - CHECK(result.delta.transitions.from(prod_map[{ 1, 1 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 1, 1 }]).empty()); CHECK(result.delta.contains(prod_map[{1, 2}], EPSILON, prod_map[{1, 3}])); CHECK(result.delta.contains(prod_map[{1, 2}], 'a', prod_map[{1, 4}])); - CHECK(result.delta.transitions.from(prod_map[{ 1, 2 }]).count() == 2); + CHECK(result.delta.state_post(prod_map[{ 1, 2 }]).num_of_moves() == 2); CHECK(result.delta.contains(prod_map[{1, 3}], 'b', prod_map[{1, 4}])); - CHECK(result.delta.transitions.from(prod_map[{ 1, 3 }]).count() == 1); + CHECK(result.delta.state_post(prod_map[{ 1, 3 }]).num_of_moves() == 1); - CHECK(result.delta.transitions.from(prod_map[{ 1, 4 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 1, 4 }]).empty()); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{3, 5}])); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{2, 6}])); CHECK(result.delta.contains(prod_map[{2, 5}], EPSILON, prod_map[{3, 6}])); - CHECK(result.delta.transitions.from(prod_map[{ 2, 5 }]).count() == 3); + CHECK(result.delta.state_post(prod_map[{ 2, 5 }]).num_of_moves() == 3); CHECK(result.delta.contains(prod_map[{3, 5}], 'a', prod_map[{5, 8}])); CHECK(result.delta.contains(prod_map[{3, 5}], EPSILON, prod_map[{3, 6}])); - CHECK(result.delta.transitions.from(prod_map[{ 3, 5 }]).count() == 2); + CHECK(result.delta.state_post(prod_map[{ 3, 5 }]).num_of_moves() == 2); CHECK(result.delta.contains(prod_map[{2, 6}], 'b', prod_map[{4, 7}])); CHECK(result.delta.contains(prod_map[{2, 6}], EPSILON, prod_map[{3, 6}])); - CHECK(result.delta.transitions.from(prod_map[{ 2, 6 }]).count() == 2); + CHECK(result.delta.state_post(prod_map[{ 2, 6 }]).num_of_moves() == 2); CHECK(result.delta.contains(prod_map[{3, 6}], 'a', prod_map[{5, 9}])); - CHECK(result.delta.transitions.from(prod_map[{ 3, 6 }]).count() == 1); + CHECK(result.delta.state_post(prod_map[{ 3, 6 }]).num_of_moves() == 1); - CHECK(result.delta.transitions.from(prod_map[{ 4, 7 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 4, 7 }]).empty()); - CHECK(result.delta.transitions.from(prod_map[{ 5, 9 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 5, 9 }]).empty()); - CHECK(result.delta.transitions.from(prod_map[{ 5, 8 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 5, 8 }]).empty()); } TEST_CASE("mata::nfa::intersection() for profiling", "[.profiling],[intersection]") From 54995002983f2cf6fc13058b9ad6cfcf4923123d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 11:05:14 +0200 Subject: [PATCH 12/25] Update Python binding to new moves and transitions implemenentation --- bindings/python/libmata/nfa/nfa.pxd | 23 ++++++++++------------- bindings/python/libmata/nfa/nfa.pyx | 11 ++++++----- bindings/python/tests/test_nfa.py | 22 +++++++++++----------- bindings/python/tests/test_trans.py | 10 +++++----- include/mata/nfa/delta.hh | 2 ++ 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index 28a9153a6..74f9a7297 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -51,20 +51,16 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[CSymbolPost].const_iterator cbegin() COrdVector[CSymbolPost].const_iterator cend() - cdef cppclass Ctransitions_const_iterator "Mata::Nfa::Delta::transitions_const_iterator": - bool operator==(Ctransitions_const_iterator&) - bool operator!=(Ctransitions_const_iterator&) + cdef cppclass CTransitions "Mata::Nfa::Delta::Transitions": + cppclass const_iterator: + bool operator==(const_iterator&) + bool operator!=(const_iterator&) CTrans& operator*() - Ctransitions_const_iterator& operator++() - - cdef cppclass CTransitionsView "Mata::Nfa::Delta::TransitionsView": - Ctransitions_const_iterator begin() - Ctransitions_const_iterator end() + const_iterator& operator++() + const_iterator begin() + const_iterator end() + CTransitions() - cdef cppclass CTransitions "Mata::Nfa::Delta::Transitions": - Ctransitions_const_iterator begin() - Ctransitions_const_iterator end() - size_t count() cdef cppclass CDelta "Mata::Nfa::Delta": vector[CStatePost] state_posts @@ -86,6 +82,8 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": bool contains(State, Symbol, State) COrdVector[CSymbolPost].const_iterator epsilon_symbol_posts(State state, Symbol epsilon) COrdVector[CSymbolPost].const_iterator epsilon_symbol_posts(CStatePost& post, Symbol epsilon) + size_t num_of_transitions() + CTransitions transitions() cdef cppclass CRun "mata::nfa::Run": # Public Attributes @@ -161,7 +159,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": State add_state(State) void print_to_DOT(ostream) vector[CTrans] get_transitions_to(State) - vector[CTrans] get_trans_as_sequence() CNfa& trim(StateRenaming*) void get_one_letter_aut(CNfa&) bool is_epsilon(Symbol) diff --git a/bindings/python/libmata/nfa/nfa.pyx b/bindings/python/libmata/nfa/nfa.pyx index 32480cfef..5f2e4fecb 100644 --- a/bindings/python/libmata/nfa/nfa.pyx +++ b/bindings/python/libmata/nfa/nfa.pyx @@ -379,12 +379,12 @@ cdef class Nfa: """ return self.thisptr.get().delta.contains(source, symbol, target) - def get_num_of_trans(self): + def get_num_of_transitions(self): """Returns number of transitions in automaton :return: number of transitions in automaton """ - return self.thisptr.get().delta.transitions.count() + return self.thisptr.get().delta.num_of_transitions() def clear(self): """Clears all of the internals in the automaton""" @@ -401,8 +401,9 @@ cdef class Nfa: :return: stream of transitions """ - iterator = self.thisptr.get().delta.transitions.begin() - while iterator != self.thisptr.get().delta.transitions.end(): + cdef CTransitions transitions = self.thisptr.get().delta.transitions() + cdef CTransitions.const_iterator iterator = transitions.begin() + while iterator != transitions.end(): trans = Transition() lhs = dereference(iterator) trans.copy_from(lhs) @@ -448,7 +449,7 @@ cdef class Nfa: :return: List of automaton transitions. """ - cdef vector[CTrans] c_transitions = self.thisptr.get().get_trans_as_sequence() + cdef CTransitions c_transitions = self.thisptr.get().delta.transitions() transitions = [] for c_transition in c_transitions: transitions.append(Transition(c_transition.source, c_transition.symbol, c_transition.target)) diff --git a/bindings/python/tests/test_nfa.py b/bindings/python/tests/test_nfa.py index d9c367df8..818f4c07b 100644 --- a/bindings/python/tests/test_nfa.py +++ b/bindings/python/tests/test_nfa.py @@ -502,7 +502,7 @@ def test_intersection_preserving_epsilon_transitions(): assert len(result.final_states) == 4 # Check transitions. - assert result.get_num_of_trans() == 15 + assert result.get_num_of_transitions() == 15 assert result.has_transition(product_map[(0, 0)], mata_nfa.epsilon(), product_map[(1, 0)]) assert len(result.get_trans_from_state_as_sequence(product_map[(0, 0)])) == 1 @@ -591,11 +591,11 @@ def test_minimize( fa_one_divisible_by_two, fa_one_divisible_by_four, fa_one_divisible_by_eight ): minimized = mata_nfa.minimize(fa_one_divisible_by_two) - assert minimized.get_num_of_trans() <= fa_one_divisible_by_two.get_num_of_trans() + assert minimized.get_num_of_transitions() <= fa_one_divisible_by_two.get_num_of_transitions() minimized = mata_nfa.minimize(fa_one_divisible_by_four) - assert minimized.get_num_of_trans() <= fa_one_divisible_by_four.get_num_of_trans() + assert minimized.get_num_of_transitions() <= fa_one_divisible_by_four.get_num_of_transitions() minimized = mata_nfa.minimize(fa_one_divisible_by_eight) - assert minimized.get_num_of_trans() <= fa_one_divisible_by_eight.get_num_of_trans() + assert minimized.get_num_of_transitions() <= fa_one_divisible_by_eight.get_num_of_transitions() lhs = mata_nfa.Nfa(11) lhs.make_initial_state(0) @@ -604,10 +604,10 @@ def test_minimize( lhs.make_final_state(i) lhs.add_transition(10, 0, 10) lhs.make_final_state(10) - assert lhs.get_num_of_trans() == 11 + assert lhs.get_num_of_transitions() == 11 minimized = mata_nfa.minimize(lhs) - assert minimized.get_num_of_trans() == 1 + assert minimized.get_num_of_transitions() == 1 def test_to_dot(): @@ -665,7 +665,7 @@ def test_trim(prepare_automaton_a): nfa.remove_final_state(2) # '2' is the new final state in the earlier trimmed automaton. nfa.trim() - assert nfa.get_num_of_trans() == 0 + assert nfa.get_num_of_transitions() == 0 assert nfa.size() == 0 @@ -677,7 +677,7 @@ def test_get_one_letter_automaton(prepare_automaton_a): one_letter_automaton = nfa.get_one_letter_aut() assert one_letter_automaton.size() == nfa.size() - assert one_letter_automaton.get_num_of_trans() == 12 + assert one_letter_automaton.get_num_of_transitions() == 12 assert one_letter_automaton.has_transition(1, abstract_symbol, 10) assert one_letter_automaton.has_transition(10, abstract_symbol, 7) assert not one_letter_automaton.has_transition(10, ord('a'), 7) @@ -896,7 +896,7 @@ def test_reduce(): # Test the reduction of an empty automaton. result, state_map = mata_nfa.reduce_with_state_map(nfa) - assert result.get_num_of_trans() == 0 + assert result.get_num_of_transitions() == 0 assert len(result.initial_states) == 0 assert len(result.final_states) == 0 @@ -905,7 +905,7 @@ def test_reduce(): nfa.make_initial_state(1) nfa.make_final_state(2) result, state_map = mata_nfa.reduce_with_state_map(nfa) - assert result.get_num_of_trans() == 0 + assert result.get_num_of_transitions() == 0 assert result.size() == 2 assert result.has_initial_state(state_map[1]) assert result.has_final_state(state_map[2]) @@ -913,7 +913,7 @@ def test_reduce(): assert state_map[2] != state_map[0] result, state_map = mata_nfa.reduce_with_state_map(nfa.trim()) - assert result.get_num_of_trans() == 0 + assert result.get_num_of_transitions() == 0 assert result.size() == 0 # Test the reduction of a bigger automaton. diff --git a/bindings/python/tests/test_trans.py b/bindings/python/tests/test_trans.py index 26db86436..4e68ce4d1 100644 --- a/bindings/python/tests/test_trans.py +++ b/bindings/python/tests/test_trans.py @@ -98,22 +98,22 @@ def test_transitions(): t4 = mata_nfa.Transition(2, 2, 2) # Test adding transition. - assert lhs.get_num_of_trans() == 0 + assert lhs.get_num_of_transitions() == 0 lhs.add_transition(0, 0, 0) - assert lhs.get_num_of_trans() == 1 + assert lhs.get_num_of_transitions() == 1 assert lhs.has_transition(t1.source, t1.symbol, t1.target) lhs.add_transition_object(t2) - assert lhs.get_num_of_trans() == 2 + assert lhs.get_num_of_transitions() == 2 assert lhs.has_transition(t2.source, t2.symbol, t2.target) # Test adding add-hoc transition. lhs.add_transition(1, 1, 1) - assert lhs.get_num_of_trans() == 3 + assert lhs.get_num_of_transitions() == 3 assert lhs.has_transition(t3.source, t3.symbol, t3.target) assert not lhs.has_transition(2, 2, 2) lhs.add_transition_object(t4) - assert lhs.get_num_of_trans() == 4 + assert lhs.get_num_of_transitions() == 4 assert lhs.has_transition(2, 2, 2) # Test that transitions are not duplicated. diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 31cfd5ea9..b87944265 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -163,6 +163,7 @@ public: bool operator==(const const_iterator& other) const; }; // class const_iterator. + Moves() = default; explicit Moves(const StatePost* state_post): state_post_{ state_post } {} Moves(Moves&&) = default; Moves(Moves&) = default; @@ -427,6 +428,7 @@ public: bool operator!=(const const_iterator& other) const { return !(*this == other); }; }; // class Transitions::const_iterator. + Transitions() = default; explicit Transitions(const Delta* delta): delta_{ delta } {} Transitions(Transitions&&) = default; Transitions(Transitions&) = default; From 630e5b89d10e2f7693f358eb8de404d1ba6fdc9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 21 Aug 2023 12:59:58 +0200 Subject: [PATCH 13/25] Set end to true for default const iterators over moves and transitions --- include/mata/nfa/delta.hh | 11 +++++------ src/nfa/delta.cc | 16 +++++++--------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index b87944265..9715891cc 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -394,7 +394,7 @@ public: class const_iterator { private: const Delta* delta_ = nullptr; - size_t current_state_; + size_t current_state_{}; StatePost::const_iterator state_post_it_{}; StateSet::const_iterator symbol_post_it_{}; bool is_end_{ false }; @@ -407,9 +407,9 @@ public: using pointer = Transition*; using reference = Transition&; - const_iterator() = default; - explicit const_iterator(const Delta* delta, bool is_end = false); - const_iterator(const Delta* delta, State current_state, bool is_end = false); + const_iterator(): is_end_{ true } {} + explicit const_iterator(const Delta* delta); + const_iterator(const Delta* delta, State current_state); const_iterator(const const_iterator& other) noexcept = default; const_iterator(const_iterator&&) = default; @@ -425,7 +425,6 @@ public: const_iterator& operator=(const_iterator&&) = default; bool operator==(const const_iterator& other) const; - bool operator!=(const const_iterator& other) const { return !(*this == other); }; }; // class Transitions::const_iterator. Transitions() = default; @@ -436,7 +435,7 @@ public: Transitions& operator=(Transitions&) = default; const_iterator begin() const { return const_iterator{ delta_ }; }; - const_iterator end() const { return const_iterator{ delta_, true}; }; + const_iterator end() const { return const_iterator{}; }; private: const Delta* delta_; }; // class Transitions. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index faa6ac981..1f2434539 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -192,8 +192,7 @@ bool Delta::empty() const { return true; } -Delta::Transitions::const_iterator::const_iterator(const Delta* delta, bool is_end) - : delta_{ delta }, current_state_{ 0 }, is_end_{ is_end } { +Delta::Transitions::const_iterator::const_iterator(const Delta* delta): delta_{ delta }, current_state_{ 0 } { const size_t post_size = delta_->num_of_states(); for (size_t i = 0; i < post_size; ++i) { if (!(*delta_)[i].empty()) { @@ -207,13 +206,12 @@ Delta::Transitions::const_iterator::const_iterator(const Delta* delta, bool is_e } } - // no transition found, an empty post + // No transition found, delta contains only empty state posts. is_end_ = true; } -Delta::Transitions::const_iterator::const_iterator( - const Delta* delta, State current_state, bool is_end) - : delta_{ delta }, current_state_{ current_state }, is_end_{ is_end } { +Delta::Transitions::const_iterator::const_iterator(const Delta* delta, State current_state) + : delta_{ delta }, current_state_{ current_state } { const size_t post_size = delta_->num_of_states(); for (State source{ current_state_ }; source < post_size; ++source) { const StatePost& state_post{ delta_->state_post(source) }; @@ -228,7 +226,7 @@ Delta::Transitions::const_iterator::const_iterator( } } - // no transition found, an empty post + // No transition found, delta from the current state contains only empty state posts. is_end_ = true; } @@ -367,8 +365,8 @@ bool Delta::operator==(const Delta& other) const { return other_transitions_it == other_transitions_end; } -StatePost::Moves::const_iterator::const_iterator(const StatePost* state_post, bool is_end) - : state_post_{ state_post }, is_end_{ is_end } { +StatePost::Moves::const_iterator::const_iterator(const StatePost* state_post) + : state_post_{ state_post } { if (!state_post_->empty()) { state_post_it_ = state_post_->begin(); symbol_post_it_ = state_post_it_->targets.begin(); From 524aa9d4ee17e1731751c78f655e2e1232ac3bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Tue, 22 Aug 2023 13:08:54 +0200 Subject: [PATCH 14/25] Add support for iterating over epsilon moves and symbol (non-epsilon) moves --- include/mata/nfa/delta.hh | 66 +++++++++++++++++++------- src/nfa/delta.cc | 99 ++++++++++++++++++++++++++++++++------- tests/nfa/delta.cc | 90 ++++++++++++++++++++++++++++++++++- 3 files changed, 219 insertions(+), 36 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 9715891cc..3adcdc760 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -127,26 +127,44 @@ public: */ class Moves { public: + /** + * @brief Whether to look up first symbol to iterate over from the beginning or from the end of @c StatePost + * iterator. + + * Iterates over symbol posts with symbols in interval [first_symbol_, last_symbol_]. + */ + enum class FirstSymbolLookupDiretion { + Forward, ///< Lookup from the beginning to the end. + Backward ///< Lookup from the end to the beginning. + }; + /** * Iterator over moves. */ class const_iterator { private: - const StatePost* state_post_ = nullptr; + const StatePost* state_post_{ nullptr }; StatePost::const_iterator state_post_it_{}; StateSet::const_iterator symbol_post_it_{}; + Symbol last_symbol_{ Limits::max_symbol }; bool is_end_{ false }; + /// Internal allocated instance of @c Move which is set for the move currently iterated over and returned as + /// a reference with @c operator*(). Move move_{}; public: using iterator_category = std::forward_iterator_tag; using value_type = Move; - using difference_type = unsigned; + using difference_type = size_t; using pointer = Move*; using reference = Move&; + /// Construct end iterator. const_iterator(): is_end_{ true } {} - const_iterator(const StatePost* state_post); + /// Construct all moves iterator, epsilon moves iterator or normal symbols moves iterator (excluding epsilons). + const_iterator(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol, + const FirstSymbolLookupDiretion firest_symbol_lookup_direction = FirstSymbolLookupDiretion::Forward); const_iterator(const const_iterator& other) noexcept = default; const_iterator(const_iterator&&) = default; @@ -164,25 +182,41 @@ public: }; // class const_iterator. Moves() = default; - explicit Moves(const StatePost* state_post): state_post_{ state_post } {} + Moves( + const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol, + FirstSymbolLookupDiretion lookup_first_symbol_side = FirstSymbolLookupDiretion::Forward) + : state_post_{ &state_post }, first_symbol_{ first_symbol }, last_symbol_{ last_symbol }, + first_symbol_lookup_direction_{ lookup_first_symbol_side } {} Moves(Moves&&) = default; Moves(Moves&) = default; - Moves& operator=(Moves&&) = default; - Moves& operator=(Moves&) = default; + Moves& operator=(Moves&& other) noexcept; + Moves& operator=(const Moves& other) noexcept; - const_iterator begin() const { return const_iterator{ state_post_ }; }; - const_iterator end() const { return const_iterator{}; }; + const_iterator begin() const; + const_iterator end() const { return const_iterator{}; } private: const StatePost* state_post_; + Symbol first_symbol_{ Limits::min_symbol }; ///< First symbol (included) to iterate over. + Symbol last_symbol_{ Limits::max_symbol }; ///< Last symbol (included) to iterate over. + FirstSymbolLookupDiretion first_symbol_lookup_direction_{ FirstSymbolLookupDiretion::Forward }; }; // class Moves. /** - * Iterator over transitions represented as 'Transition' instances. + * Iterator over all moves in @c StatePost represented as @c Move instances. + */ + Moves moves() const { return { *this }; } + /** + * Iterator over epsilon moves in @c StatePost represented as @c Move instances. + */ + Moves epsilon_moves(const Symbol first_epsilon = EPSILON) const; + /** + * Iterator over normal symbols (not over epsilons) in @c StatePost represented as @c Move instances. */ - Moves moves() const { return Moves{ this }; } + Moves symbol_moves(const Symbol last_symbol = EPSILON - 1) const; /** - * Count the number of moves in StatePost. + * Count the number of all moves in @c StatePost. */ size_t num_of_moves() const; }; // class StatePost. @@ -403,13 +437,13 @@ public: public: using iterator_category = std::forward_iterator_tag; using value_type = Transition; - using difference_type = unsigned; + using difference_type = size_t; using pointer = Transition*; using reference = Transition&; const_iterator(): is_end_{ true } {} - explicit const_iterator(const Delta* delta); - const_iterator(const Delta* delta, State current_state); + explicit const_iterator(const Delta& delta); + const_iterator(const Delta& delta, State current_state); const_iterator(const const_iterator& other) noexcept = default; const_iterator(const_iterator&&) = default; @@ -434,8 +468,8 @@ public: Transitions& operator=(Transitions&&) = default; Transitions& operator=(Transitions&) = default; - const_iterator begin() const { return const_iterator{ delta_ }; }; - const_iterator end() const { return const_iterator{}; }; + const_iterator begin() const { return const_iterator{ *delta_ }; } + const_iterator end() const { return const_iterator{}; } private: const Delta* delta_; }; // class Transitions. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 1f2434539..5e3cef278 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -192,7 +192,7 @@ bool Delta::empty() const { return true; } -Delta::Transitions::const_iterator::const_iterator(const Delta* delta): delta_{ delta }, current_state_{ 0 } { +Delta::Transitions::const_iterator::const_iterator(const Delta& delta): delta_{ &delta }, current_state_{ 0 } { const size_t post_size = delta_->num_of_states(); for (size_t i = 0; i < post_size; ++i) { if (!(*delta_)[i].empty()) { @@ -210,8 +210,8 @@ Delta::Transitions::const_iterator::const_iterator(const Delta* delta): delta_{ is_end_ = true; } -Delta::Transitions::const_iterator::const_iterator(const Delta* delta, State current_state) - : delta_{ delta }, current_state_{ current_state } { +Delta::Transitions::const_iterator::const_iterator(const Delta& delta, State current_state) + : delta_{ &delta }, current_state_{ current_state } { const size_t post_size = delta_->num_of_states(); for (State source{ current_state_ }; source < post_size; ++source) { const StatePost& state_post{ delta_->state_post(source) }; @@ -365,18 +365,40 @@ bool Delta::operator==(const Delta& other) const { return other_transitions_it == other_transitions_end; } -StatePost::Moves::const_iterator::const_iterator(const StatePost* state_post) - : state_post_{ state_post } { - if (!state_post_->empty()) { - state_post_it_ = state_post_->begin(); - symbol_post_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *symbol_post_it_; +StatePost::Moves::const_iterator::const_iterator( + const StatePost& state_post, const Symbol first_symbol, const Symbol last_symbol, + const Moves::FirstSymbolLookupDiretion first_symbol_lookup_direction) + : state_post_{ &state_post }, last_symbol_{ last_symbol } { + if (state_post_->empty()) { + is_end_ = true; return; } - - // No transition found, 'state_post' is an empty state post. - is_end_ = true; + const StatePost::const_iterator state_post_begin{ state_post_->begin() }; + const StatePost::const_iterator state_post_end{ state_post_->end() }; + if (first_symbol_lookup_direction == Moves::FirstSymbolLookupDiretion::Forward) { + state_post_it_ = state_post_begin; + while (state_post_it_ != state_post_end && first_symbol > state_post_it_->symbol) { ++state_post_it_; } + if (state_post_it_ == state_post_end || state_post_it_->symbol > last_symbol_) { + is_end_ = true; + return; + } + } else { // first_symbol_lookup_direction == Moves::FirstSymbolLookupDiretion::Backward. + auto previous_state_post_it = state_post_end; + do { + state_post_it_ = previous_state_post_it; + --previous_state_post_it; + } while (previous_state_post_it != state_post_begin && first_symbol < previous_state_post_it->symbol); + if (previous_state_post_it == state_post_begin || first_symbol == previous_state_post_it->symbol) { + state_post_it_ = previous_state_post_it; + } + if (state_post_it_->symbol < first_symbol) { + is_end_ = true; + return; + } + } + symbol_post_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; + move_.target = *symbol_post_it_; } StatePost::Moves::const_iterator& StatePost::Moves::const_iterator::operator++() { @@ -386,14 +408,23 @@ StatePost::Moves::const_iterator& StatePost::Moves::const_iterator::operator++() return *this; } + if (state_post_it_->symbol >= last_symbol_) { + // Last symbol symbol post was reached and fully iterated over. We would now iterate to the next symbol, but + // that would already be over the iteration end specified by 'last_symbol_'. + is_end_ = true; + return *this; + } + // Iterate over to the next symbol post, which can be either an end iterator, or symbol post whose + // symbol <= last_symbol_. ++state_post_it_; - if (state_post_it_ != state_post_->cend()) { - symbol_post_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *symbol_post_it_; + if (state_post_it_ == state_post_->cend() || state_post_it_->symbol > last_symbol_) { + is_end_ = true; return *this; } - is_end_ = true; + // The current symbol post is valid (not end iterator and symbol <= last_symbol_). + symbol_post_it_ = state_post_it_->targets.begin(); + move_.symbol = state_post_it_->symbol; + move_.target = *symbol_post_it_; return *this; } @@ -419,3 +450,35 @@ size_t StatePost::num_of_moves() const { } return counter; } + +StatePost::Moves& StatePost::Moves::operator=(StatePost::Moves&& other) noexcept { + if (&other != this) { + state_post_ = other.state_post_; + first_symbol_ = other.first_symbol_; + last_symbol_ = other.last_symbol_; + first_symbol_lookup_direction_ = other.first_symbol_lookup_direction_; + } + return *this; +} + +StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { + if (&other != this) { + state_post_ = other.state_post_; + first_symbol_ = other.first_symbol_; + last_symbol_ = other.last_symbol_; + first_symbol_lookup_direction_ = other.first_symbol_lookup_direction_; + } + return *this; +} + +StatePost::Moves StatePost::epsilon_moves(const Symbol first_epsilon) const { + return { *this, first_epsilon, Limits::max_symbol, Moves::FirstSymbolLookupDiretion::Backward}; +} + +StatePost::Moves StatePost::symbol_moves(const Symbol last_symbol) const { + return { *this, Limits::min_symbol, last_symbol }; +} + +StatePost::Moves::const_iterator StatePost::Moves::begin() const { + return { *state_post_, first_symbol_, last_symbol_, first_symbol_lookup_direction_ }; +} diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index fd5c0f4fb..5eac46590 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -147,6 +147,9 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); + StatePost::Moves epsilon_moves{ state_post.epsilon_moves() }; + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); + state_post = nfa.delta.state_post(1); moves = state_post.moves(); @@ -161,6 +164,8 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(2); moves = state_post.moves(); @@ -175,6 +180,8 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(3); moves = state_post.moves(); @@ -188,6 +195,8 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves.empty()); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(4); moves = state_post.moves(); @@ -201,6 +210,55 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves.empty()); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); + + nfa.delta.add(0, EPSILON, 2); + state_post = nfa.delta.state_post(0); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 2 } }); + nfa.delta.add(1, EPSILON, 3); + state_post = nfa.delta.state_post(1); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 3 } }); + nfa.delta.add(4, EPSILON, 4); + state_post = nfa.delta.state_post(4); + epsilon_moves = state_post.epsilon_moves(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); + + state_post = nfa.delta.state_post(0); + epsilon_moves = state_post.epsilon_moves(3); + iterated_moves.clear(); + for (const Move& move: epsilon_moves) { + iterated_moves.push_back(move); + } + CHECK(iterated_moves == std::vector{ { 5, 1 }, { EPSILON, 2 }}); + state_post = nfa.delta.state_post(1); + epsilon_moves = state_post.epsilon_moves(3); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { 3, 2 }, { EPSILON, 3 } }); + state_post = nfa.delta.state_post(2); + epsilon_moves = state_post.epsilon_moves(3); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); + state_post = nfa.delta.state_post(4); + epsilon_moves = state_post.epsilon_moves(3); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); + + state_post = nfa.delta.state_post(0); + StatePost::Moves symbol_moves = state_post.symbol_moves(3); + iterated_moves.clear(); + for (const Move& move: symbol_moves) { + iterated_moves.push_back(move); + } + CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); + state_post = nfa.delta.state_post(1); + symbol_moves = state_post.symbol_moves(3); + CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); + state_post = nfa.delta.state_post(2); + symbol_moves = state_post.symbol_moves(3); + CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1}, { 0 , 3 } }); + state_post = nfa.delta.state_post(4); + symbol_moves = state_post.symbol_moves(3); + CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); } } @@ -241,6 +299,23 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { iterated_transitions.clear(); for (const Transition& transition: nfa.delta.transitions()) { iterated_transitions.push_back(transition); } CHECK(iterated_transitions == expected_transitions); + + Delta::Transitions::const_iterator transitions_it{ nfa.delta.transitions().begin() }; + CHECK(*transitions_it == Transition{ 0, 1, 1 }); + transitions_it++; + CHECK(*transitions_it == Transition{ 0, 2, 1 }); + transitions_it++; + transitions_it++; + CHECK(*transitions_it == Transition{ 1, 3, 2 }); + + Delta::Transitions::const_iterator transitions_from_1_to_end_it{ nfa.delta, 1 }; + iterated_transitions.clear(); + while (transitions_from_1_to_end_it != nfa.delta.transitions().end()) { + iterated_transitions.push_back(*transitions_from_1_to_end_it); + transitions_from_1_to_end_it++; + } + expected_transitions = std::vector{ { 1, 3, 2 }, { 2, 0, 1 }, { 2, 0, 3 } }; + CHECK(iterated_transitions == expected_transitions); } SECTION("Sparse automaton") { @@ -297,12 +372,23 @@ TEST_CASE("Mata::Nfa::StatePost::Moves") { nfa.delta.add(4, 'f', 5); // TODO: rewrite in a check of moves. StatePost::Moves moves_from_source{ nfa.delta[0].moves() }; + CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() } == std::vector{ { 'a', 1 }}); moves_from_source = nfa.delta[1].moves(); CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() } == std::vector{ { 'b', 2 }, { 'c', 2 }, { 'd', 2 } }); - moves_from_source = nfa.delta[12].moves(); - CHECK(std::vector{ moves_from_source.begin(), moves_from_source.end() }.empty()); + StatePost::Moves::const_iterator move_incremented_it{ moves_from_source.begin() }; + move_incremented_it++; + CHECK(*move_incremented_it == Move{ 'c', 2 }); + CHECK(*StatePost::Moves::const_iterator{ nfa.delta.state_post(1) } == Move{ 'b', 2 }); + CHECK(move_incremented_it != moves_from_source.begin()); + CHECK(move_incremented_it == ++moves_from_source.begin()); + StatePost::Moves moves_from_source_copy_constructed{ nfa.delta[12].moves() }; + CHECK( + std::vector{ moves_from_source_copy_constructed.begin(), moves_from_source_copy_constructed.end() } + .empty() + ); + } TEST_CASE("Mata::Nfa::Delta::operator==()") { From cfe41fc5b3f34d303986712cef83a8b8bb79f45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Fri, 25 Aug 2023 08:24:06 +0200 Subject: [PATCH 15/25] use snake_case namespaces for moves inplementation and tests --- bindings/python/libmata/nfa/nfa.pxd | 6 +- src/strings/nfa-noodlification.cc | 2 +- tests/nfa/delta.cc | 28 +++++----- tests/nfa/nfa.cc | 85 +++++++++++++++-------------- 4 files changed, 61 insertions(+), 60 deletions(-) diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index 74f9a7297..4b7f2c891 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -51,7 +51,7 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[CSymbolPost].const_iterator cbegin() COrdVector[CSymbolPost].const_iterator cend() - cdef cppclass CTransitions "Mata::Nfa::Delta::Transitions": + cdef cppclass CTransitions "mata::nfa::Delta::Transitions": cppclass const_iterator: bool operator==(const_iterator&) bool operator!=(const_iterator&) @@ -62,7 +62,7 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": CTransitions() - cdef cppclass CDelta "Mata::Nfa::Delta": + cdef cppclass CDelta "mata::nfa::Delta": vector[CStatePost] state_posts CTransitions transitions @@ -126,7 +126,7 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": COrdVector[State].const_iterator begin() COrdVector[State].const_iterator end() - cdef cppclass CNfa "Mata::Nfa::Nfa": + cdef cppclass CNfa "mata::nfa::Nfa": # Public Attributes CSparseSet[State] initial CSparseSet[State] final diff --git a/src/strings/nfa-noodlification.cc b/src/strings/nfa-noodlification.cc index 81b621618..e24116ab0 100644 --- a/src/strings/nfa-noodlification.cc +++ b/src/strings/nfa-noodlification.cc @@ -206,7 +206,7 @@ std::vector seg_nfa::noodlify_mult_eps(const for(const State& fn : segments[0].final) { SegItem new_item; - std::shared_ptr seg = segments_one_initial_final[{unused_state, fn}]; + std::shared_ptr seg = segments_one_initial_final[{unused_state, fn}]; if(seg->final.size() != 1 || seg->delta.num_of_transitions() > 0) { // L(seg_iter) != {epsilon} new_item.noodle.emplace_back(seg, def_eps_vector); } diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 5eac46590..04e74af3a 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -13,7 +13,7 @@ using namespace mata::nfa; using Symbol = mata::Symbol; -TEST_CASE("Mata::nfa::SymbolPost") { +TEST_CASE("mata::nfa::SymbolPost") { CHECK(SymbolPost{ 0, StateSet{} } == SymbolPost{ 0, StateSet{ 0, 1 } }); CHECK(SymbolPost{ 1, StateSet{} } != SymbolPost{ 0, StateSet{} }); CHECK(SymbolPost{ 0, StateSet{ 1 } } < SymbolPost{ 1, StateSet{} }); @@ -24,8 +24,8 @@ TEST_CASE("Mata::nfa::SymbolPost") { CHECK(SymbolPost{ 1, StateSet{ 0 } } >= SymbolPost{ 0, StateSet{ 1 } }); } -TEST_CASE("Mata::nfa::Delta::state_post()") { - mata::nfa::Nfa aut{}; +TEST_CASE("mata::nfa::Delta::state_post()") { + Nfa aut{}; SECTION("Add new states within the limit") { aut.add_state(19); @@ -77,7 +77,7 @@ TEST_CASE("Mata::nfa::Delta::state_post()") { } } -TEST_CASE("Mata::nfa::Delta::contains()") { +TEST_CASE("mata::nfa::Delta::contains()") { Nfa nfa; CHECK(!nfa.delta.contains(0, 1, 0)); CHECK(!nfa.delta.contains(Transition{ 0, 1, 0 })); @@ -86,7 +86,7 @@ TEST_CASE("Mata::nfa::Delta::contains()") { CHECK(nfa.delta.contains(Transition{ 0, 1, 0 })); } -TEST_CASE("Mata::nfa::Delta::remove()") { +TEST_CASE("mata::nfa::Delta::remove()") { Nfa nfa; SECTION("Simple remove") { @@ -99,7 +99,7 @@ TEST_CASE("Mata::nfa::Delta::remove()") { } } -TEST_CASE("Mata::nfa::Delta::mutable_post()") { +TEST_CASE("mata::nfa::Delta::mutable_post()") { Nfa nfa; SECTION("Default initialized") { @@ -115,7 +115,7 @@ TEST_CASE("Mata::nfa::Delta::mutable_post()") { } } -TEST_CASE("Mata::nfa::StatePost iteration over moves") { +TEST_CASE("mata::nfa::StatePost iteration over moves") { Nfa nfa; std::vector iterated_moves{}; std::vector expected_moves{}; @@ -133,7 +133,7 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { state_post = nfa.delta.state_post(0); expected_moves = std::vector{ { 1, 1 }, { 2, 1 }, { 5, 1 } }; - mata::nfa::StatePost::Moves moves{ state_post.moves() }; + StatePost::Moves moves{ state_post.moves() }; iterated_moves.clear(); for (auto move_it{ moves.begin() }; move_it != moves.end(); ++move_it) { iterated_moves.push_back(*move_it); @@ -262,13 +262,13 @@ TEST_CASE("Mata::nfa::StatePost iteration over moves") { } } -TEST_CASE("Mata::nfa::Delta iteration over transitions") { +TEST_CASE("mata::nfa::Delta iteration over transitions") { Nfa nfa; std::vector iterated_transitions{}; std::vector expected_transitions{}; SECTION("empty automaton") { - Mata::Nfa::Delta::Transitions transitions{ nfa.delta.transitions() }; + Delta::Transitions transitions{ nfa.delta.transitions() }; REQUIRE(transitions.begin() == transitions.end()); } @@ -282,7 +282,7 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { nfa.delta.add(2, 0, 1); nfa.delta.add(2, 0, 3); - Mata::Nfa::Delta::Transitions transitions{ nfa.delta.transitions() }; + Delta::Transitions transitions{ nfa.delta.transitions() }; iterated_transitions.clear(); for (auto transitions_it{ transitions.begin() }; transitions_it != transitions.end(); ++transitions_it) { @@ -347,7 +347,7 @@ TEST_CASE("Mata::nfa::Delta iteration over transitions") { } } -TEST_CASE("Mata::Nfa::Delta::operator=()") { +TEST_CASE("mata::nfa::Delta::operator=()") { Nfa nfa{}; nfa.initial.insert(0); nfa.final.insert(1); @@ -359,7 +359,7 @@ TEST_CASE("Mata::Nfa::Delta::operator=()") { CHECK(copied_nfa.delta.num_of_transitions() == 1); } -TEST_CASE("Mata::Nfa::StatePost::Moves") { +TEST_CASE("mata::nfa::StatePost::Moves") { Nfa nfa{}; nfa.initial.insert(0); nfa.final.insert(5); @@ -391,7 +391,7 @@ TEST_CASE("Mata::Nfa::StatePost::Moves") { } -TEST_CASE("Mata::Nfa::Delta::operator==()") { +TEST_CASE("mata::nfa::Delta::operator==()") { Delta delta{}; Delta delta2{}; CHECK(delta == delta2); diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index 6e8f0fc8a..0ebd7124c 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -4,10 +4,10 @@ #include -#include "mata/nfa/delta.hh" -#include "nfa-util.hh" +#include "utils.hh" #include "mata/utils/sparse-set.hh" +#include "mata/nfa/delta.hh" #include "mata/nfa/nfa.hh" #include "mata/nfa/strings.hh" #include "mata/nfa/builder.hh" @@ -15,6 +15,7 @@ #include "mata/nfa/algorithms.hh" #include "mata/parser/re2parser.hh" +using namespace mata; using namespace mata::nfa::algorithms; using namespace mata::nfa; using namespace mata::strings; @@ -69,8 +70,8 @@ TEST_CASE("mata::nfa::create_alphabet()") { auto symbols{alphabet.get_alphabet_symbols() }; CHECK(symbols == mata::utils::OrdVector{ 'c', 'b', 'a' }); - //mata::nfa::create_alphabet(1, 3, 4); // Will not compile: '1', '3', '4' are not of the required type. - //mata::nfa::create_alphabet(a, b, 4); // Will not compile: '4' is not of the required type. + // create_alphabet(1, 3, 4); // Will not compile: '1', '3', '4' are not of the required type. + // create_alphabet(a, b, 4); // Will not compile: '4' is not of the required type. } TEST_CASE("mata::nfa::Nfa::delta.add()/delta.contains()") @@ -167,7 +168,7 @@ TEST_CASE("mata::nfa::Delta.transform/append") } // }}} -TEST_CASE("Mata::Nfa::is_lang_empty()") +TEST_CASE("mata::nfa::is_lang_empty()") { // {{{ Nfa aut(14); Run cex; @@ -474,7 +475,7 @@ TEST_CASE("mata::nfa::construct() correct calls") SECTION("construct an empty automaton") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; aut = builder::construct(parsec); @@ -483,7 +484,7 @@ TEST_CASE("mata::nfa::construct() correct calls") SECTION("construct a simple non-empty automaton accepting the empty word") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.dict.insert({"Initial", {"q1"}}); parsec.dict.insert({"Final", {"q1"}}); @@ -494,7 +495,7 @@ TEST_CASE("mata::nfa::construct() correct calls") SECTION("construct an automaton with more than one initial/final states") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.dict.insert({"Initial", {"q1", "q2"}}); parsec.dict.insert({"Final", {"q1", "q2", "q3"}}); @@ -506,7 +507,7 @@ TEST_CASE("mata::nfa::construct() correct calls") SECTION("construct a simple non-empty automaton accepting only the word 'a'") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.dict.insert({"Initial", {"q1"}}); parsec.dict.insert({"Final", {"q2"}}); parsec.body = { {"q1", "a", "q2"} }; @@ -524,7 +525,7 @@ TEST_CASE("mata::nfa::construct() correct calls") SECTION("construct a more complicated non-empty automaton") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.dict.insert({"Initial", {"q1", "q3"}}); parsec.dict.insert({"Final", {"q5"}}); parsec.body.push_back({"q1", "a", "q3"}); @@ -572,7 +573,7 @@ TEST_CASE("mata::nfa::construct() invalid calls") SECTION("construct() call with an epsilon transition") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.body = { {"q1", "q2"} }; CHECK_THROWS_WITH(builder::construct(parsec), @@ -581,7 +582,7 @@ TEST_CASE("mata::nfa::construct() invalid calls") SECTION("construct() call with a nonsense transition") { - parsec.type = mata::nfa::TYPE_NFA; + parsec.type = nfa::TYPE_NFA; parsec.body = { {"q1", "a", "q2", "q3"} }; CHECK_THROWS_WITH(plumbing::construct(&aut, parsec), @@ -776,7 +777,7 @@ TEST_CASE("mata::nfa::construct() from IntermediateAut correct calls") const auto auts = mata::IntermediateAut::parse_from_mf(parse_mf(file)); inter_aut = auts[0]; - mata::nfa::builder::NameStateMap state_map; + nfa::builder::NameStateMap state_map; plumbing::construct(&aut, inter_aut, &alphabet, &state_map); CHECK(aut.final.size() == 9); CHECK(aut.final[state_map.at("0")]); @@ -808,7 +809,7 @@ TEST_CASE("mata::nfa::construct() from IntermediateAut correct calls") const auto auts = mata::IntermediateAut::parse_from_mf(parse_mf(file)); inter_aut = auts[0]; - mata::nfa::builder::NameStateMap state_map; + nfa::builder::NameStateMap state_map; plumbing::construct(&aut, inter_aut, &alphabet, &state_map); CHECK(aut.final.empty()); } @@ -925,8 +926,8 @@ TEST_CASE("mata::nfa::complement()") cmpl = complement(aut, alph, {{"algorithm", "classical"}, {"minimize", "false"}}); - Nfa empty_string_nfa{ mata::nfa::builder::create_sigma_star_nfa(&alph) }; - CHECK(mata::nfa::are_equivalent(cmpl, empty_string_nfa)); + Nfa empty_string_nfa{ nfa::builder::create_sigma_star_nfa(&alph) }; + CHECK(are_equivalent(cmpl, empty_string_nfa)); } SECTION("empty automaton") @@ -937,13 +938,13 @@ TEST_CASE("mata::nfa::complement()") {"minimize", "false"}}); REQUIRE(is_in_lang(cmpl, {})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"] }, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["b"] }, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["a"]}, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["b"], alph["b"], alph["a"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["b"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["a"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["b"], alph["b"], alph["a"] }, {}})); - Nfa sigma_star_nfa{ mata::nfa::builder::create_sigma_star_nfa(&alph) }; - CHECK(mata::nfa::are_equivalent(cmpl, sigma_star_nfa)); + Nfa sigma_star_nfa{ nfa::builder::create_sigma_star_nfa(&alph) }; + CHECK(are_equivalent(cmpl, sigma_star_nfa)); } SECTION("empty automaton accepting epsilon, empty alphabet") @@ -968,10 +969,10 @@ TEST_CASE("mata::nfa::complement()") {"minimize", "false"}}); REQUIRE(!is_in_lang(cmpl, { })); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"]}, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["b"]}, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["a"]}, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["b"], alph["b"], alph["a"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["b"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["a"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["b"], alph["b"], alph["a"]}, {}})); REQUIRE(cmpl.initial.size() == 1); REQUIRE(cmpl.final.size() == 1); REQUIRE(cmpl.delta.num_of_transitions() == 4); @@ -1009,8 +1010,8 @@ TEST_CASE("mata::nfa::complement()") cmpl = complement(aut, alph, {{"algorithm", "classical"}, {"minimize", "true"}}); - Nfa empty_string_nfa{ mata::nfa::builder::create_sigma_star_nfa(&alph) }; - CHECK(mata::nfa::are_equivalent(empty_string_nfa, cmpl)); + Nfa empty_string_nfa{ nfa::builder::create_sigma_star_nfa(&alph) }; + CHECK(are_equivalent(empty_string_nfa, cmpl)); } SECTION("empty automaton, minimization") @@ -1021,13 +1022,13 @@ TEST_CASE("mata::nfa::complement()") {"minimize", "true"}}); REQUIRE(is_in_lang(cmpl, {})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"] }, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["b"] }, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["a"]}, {}})); - REQUIRE(is_in_lang(cmpl, mata::nfa::Run{{ alph["a"], alph["b"], alph["b"], alph["a"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["b"] }, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["a"]}, {}})); + REQUIRE(is_in_lang(cmpl, Run{{ alph["a"], alph["b"], alph["b"], alph["a"] }, {}})); - Nfa sigma_star_nfa{ mata::nfa::builder::create_sigma_star_nfa(&alph) }; - CHECK(mata::nfa::are_equivalent(sigma_star_nfa, cmpl)); + Nfa sigma_star_nfa{ nfa::builder::create_sigma_star_nfa(&alph) }; + CHECK(are_equivalent(sigma_star_nfa, cmpl)); } SECTION("minimization vs no minimization") @@ -1570,11 +1571,11 @@ TEST_CASE("mata::nfa::are_equivalent") SECTION("a* != (a|b)*, was throwing exception") { - mata::nfa::Nfa aut; + Nfa aut; mata::parser::create_nfa(&aut, "a*"); - mata::nfa::Nfa aut2; + Nfa aut2; mata::parser::create_nfa(&aut2, "(a|b)*"); - CHECK(!mata::nfa::are_equivalent(aut, aut2)); + CHECK(!are_equivalent(aut, aut2)); } SECTION("(a+b)* !<= eps + (a+b) + (a+b)(a+b)(a* + b*)") @@ -2088,8 +2089,8 @@ TEST_CASE("mata::nfa::reduce_size_by_simulation()") result = reduce(aut.trim(), &state_renaming); CHECK(result.size() == 3); - CHECK(result.initial == SparseSet{ 0, 1 }); - CHECK(result.final == SparseSet{ 2 }); + CHECK(result.initial == SparseSet{ 0, 1 }); + CHECK(result.final == SparseSet{ 2 }); CHECK(result.delta.num_of_transitions() == 6); CHECK(result.delta.contains(state_renaming[0], 'a', state_renaming[2])); CHECK(result.delta.contains(state_renaming[0], 'a', state_renaming[1])); @@ -2104,7 +2105,7 @@ TEST_CASE("mata::nfa::reduce_size_by_simulation()") aut.delta.add(0, 'a', 1); aut.initial = { 0 }; Nfa result = reduce(aut.trim(), &state_renaming); - CHECK(mata::nfa::are_equivalent(result, aut)); + CHECK(are_equivalent(result, aut)); } } @@ -2802,14 +2803,14 @@ TEST_CASE("mata::nfa::get_useful_states_tarjan") { } SECTION("from regex (a+b*a*)") { - mata::nfa::Nfa aut; + Nfa aut; mata::parser::create_nfa(&aut, "(a+b*a*)", false, EPSILON, false); mata::BoolVector bv = aut.get_useful_states(); mata::BoolVector ref({ 1, 0, 1, 0, 1, 0, 1, 0, 0}); CHECK(bv == ref); - aut = mata::nfa::reduce(aut.trim()); + aut = reduce(aut.trim()); bv = aut.get_useful_states(); CHECK(bv == mata::BoolVector({ 1, 1, 1, 1})); } From 567cfbe18a40d25044ab5d2bc78dbdcecefd30ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Fri, 25 Aug 2023 10:12:01 +0200 Subject: [PATCH 16/25] Move Moves and Transitions and its iterators outside their parent classes --- include/mata/nfa/delta.hh | 291 +++++++++++++++++++------------------- src/nfa/delta.cc | 9 ++ 2 files changed, 158 insertions(+), 142 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 3adcdc760..c28073150 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -120,92 +120,12 @@ public: iterator find(const Symbol symbol) { return super::find({ symbol, {} }); } const_iterator find(const Symbol symbol) const { return super::find({ symbol, {} }); } - /** - * @brief Iterator over moves represented as @c Move instances. - * - * It iterates over pairs (symbol, target) for the given @c StatePost. - */ - class Moves { - public: - /** - * @brief Whether to look up first symbol to iterate over from the beginning or from the end of @c StatePost - * iterator. - - * Iterates over symbol posts with symbols in interval [first_symbol_, last_symbol_]. - */ - enum class FirstSymbolLookupDiretion { - Forward, ///< Lookup from the beginning to the end. - Backward ///< Lookup from the end to the beginning. - }; - - /** - * Iterator over moves. - */ - class const_iterator { - private: - const StatePost* state_post_{ nullptr }; - StatePost::const_iterator state_post_it_{}; - StateSet::const_iterator symbol_post_it_{}; - Symbol last_symbol_{ Limits::max_symbol }; - bool is_end_{ false }; - /// Internal allocated instance of @c Move which is set for the move currently iterated over and returned as - /// a reference with @c operator*(). - Move move_{}; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = Move; - using difference_type = size_t; - using pointer = Move*; - using reference = Move&; - - /// Construct end iterator. - const_iterator(): is_end_{ true } {} - /// Construct all moves iterator, epsilon moves iterator or normal symbols moves iterator (excluding epsilons). - const_iterator(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, - const FirstSymbolLookupDiretion firest_symbol_lookup_direction = FirstSymbolLookupDiretion::Forward); - const_iterator(const const_iterator& other) noexcept = default; - const_iterator(const_iterator&&) = default; - - const Move& operator*() const { return move_; } - - // Prefix increment - const_iterator& operator++(); - // Postfix increment - const const_iterator operator++(int); - - const_iterator& operator=(const const_iterator& other) noexcept = default; - const_iterator& operator=(const_iterator&&) = default; - - bool operator==(const const_iterator& other) const; - }; // class const_iterator. - - Moves() = default; - Moves( - const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, - FirstSymbolLookupDiretion lookup_first_symbol_side = FirstSymbolLookupDiretion::Forward) - : state_post_{ &state_post }, first_symbol_{ first_symbol }, last_symbol_{ last_symbol }, - first_symbol_lookup_direction_{ lookup_first_symbol_side } {} - Moves(Moves&&) = default; - Moves(Moves&) = default; - Moves& operator=(Moves&& other) noexcept; - Moves& operator=(const Moves& other) noexcept; - - const_iterator begin() const; - const_iterator end() const { return const_iterator{}; } - private: - const StatePost* state_post_; - Symbol first_symbol_{ Limits::min_symbol }; ///< First symbol (included) to iterate over. - Symbol last_symbol_{ Limits::max_symbol }; ///< Last symbol (included) to iterate over. - FirstSymbolLookupDiretion first_symbol_lookup_direction_{ FirstSymbolLookupDiretion::Forward }; - }; // class Moves. + class Moves; /** * Iterator over all moves in @c StatePost represented as @c Move instances. */ - Moves moves() const { return { *this }; } + Moves moves() const; /** * Iterator over epsilon moves in @c StatePost represented as @c Move instances. */ @@ -221,6 +141,90 @@ public: size_t num_of_moves() const; }; // class StatePost. +/** + * @brief Iterator over moves represented as @c Move instances. + * + * It iterates over pairs (symbol, target) for the given @c StatePost. + */ +class StatePost::Moves { +public: + /** + * @brief Whether to look up first symbol to iterate over from the beginning or from the end of @c StatePost + * iterator. + + * Iterates over symbol posts with symbols in interval [first_symbol_, last_symbol_]. + */ + enum class FirstSymbolLookupDiretion { + Forward, ///< Lookup from the beginning to the end. + Backward ///< Lookup from the end to the beginning. + }; + + class const_iterator; + + Moves() = default; + Moves( + const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol, + FirstSymbolLookupDiretion lookup_first_symbol_side = FirstSymbolLookupDiretion::Forward) + : state_post_{ &state_post }, first_symbol_{ first_symbol }, last_symbol_{ last_symbol }, + first_symbol_lookup_direction_{ lookup_first_symbol_side } {} + Moves(Moves&&) = default; + Moves(Moves&) = default; + Moves& operator=(Moves&& other) noexcept; + Moves& operator=(const Moves& other) noexcept; + + const_iterator begin() const; + const_iterator end() const; +private: + const StatePost* state_post_; + Symbol first_symbol_{ Limits::min_symbol }; ///< First symbol (included) to iterate over. + Symbol last_symbol_{ Limits::max_symbol }; ///< Last symbol (included) to iterate over. + FirstSymbolLookupDiretion first_symbol_lookup_direction_{ FirstSymbolLookupDiretion::Forward }; +}; // class Moves. + +/** + * Iterator over moves. + */ +class StatePost::Moves::const_iterator { +private: + const StatePost* state_post_{ nullptr }; + StatePost::const_iterator state_post_it_{}; + StateSet::const_iterator symbol_post_it_{}; + Symbol last_symbol_{ Limits::max_symbol }; + bool is_end_{ false }; + /// Internal allocated instance of @c Move which is set for the move currently iterated over and returned as + /// a reference with @c operator*(). + Move move_{}; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = Move; + using difference_type = size_t; + using pointer = Move*; + using reference = Move&; + + /// Construct end iterator. + const_iterator(): is_end_{ true } {} + /// Construct all moves iterator, epsilon moves iterator or normal symbols moves iterator (excluding epsilons). + const_iterator(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol, + const FirstSymbolLookupDiretion firest_symbol_lookup_direction = FirstSymbolLookupDiretion::Forward); + const_iterator(const const_iterator& other) noexcept = default; + const_iterator(const_iterator&&) = default; + + const Move& operator*() const { return move_; } + + // Prefix increment + const_iterator& operator++(); + // Postfix increment + const const_iterator operator++(int); + + const_iterator& operator=(const const_iterator& other) noexcept = default; + const_iterator& operator=(const_iterator&&) = default; + + bool operator==(const const_iterator& other) const; +}; // class const_iterator. + /** * @brief Specialization of utils::SynchronizedExistentialIterator for iterating over SymbolPosts. */ @@ -415,69 +419,12 @@ public: const_iterator begin() const { return state_posts_.begin(); } const_iterator end() const { return state_posts_.end(); } - /** - * @brief Iterator over transitions represented as @c Transition instances. - * - * It iterates over triples (source, symbol, target). - */ - class Transitions { - public: - /** - * Iterator over transitions. - */ - class const_iterator { - private: - const Delta* delta_ = nullptr; - size_t current_state_{}; - StatePost::const_iterator state_post_it_{}; - StateSet::const_iterator symbol_post_it_{}; - bool is_end_{ false }; - Transition transition_{}; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = Transition; - using difference_type = size_t; - using pointer = Transition*; - using reference = Transition&; - - const_iterator(): is_end_{ true } {} - explicit const_iterator(const Delta& delta); - const_iterator(const Delta& delta, State current_state); - - const_iterator(const const_iterator& other) noexcept = default; - const_iterator(const_iterator&&) = default; - - const Transition& operator*() const { return transition_; } - - // Prefix increment - const_iterator& operator++(); - // Postfix increment - const const_iterator operator++(int); - - const_iterator& operator=(const const_iterator& other) noexcept = default; - const_iterator& operator=(const_iterator&&) = default; - - bool operator==(const const_iterator& other) const; - }; // class Transitions::const_iterator. - - Transitions() = default; - explicit Transitions(const Delta* delta): delta_{ delta } {} - Transitions(Transitions&&) = default; - Transitions(Transitions&) = default; - Transitions& operator=(Transitions&&) = default; - Transitions& operator=(Transitions&) = default; - - const_iterator begin() const { return const_iterator{ *delta_ }; } - const_iterator end() const { return const_iterator{}; } - private: - const Delta* delta_; - }; // class Transitions. + class Transitions; /** - * Iterator over transitions represented as 'Transition' instances. + * Iterator over transitions represented as @c Transition instances. */ - Transitions transitions() const { return Transitions{ this }; } + Transitions transitions() const; /** * Iterate over @p epsilon symbol posts under the given @p state. @@ -498,6 +445,66 @@ private: std::vector state_posts_; }; // class Delta. +/** + * @brief Iterator over transitions represented as @c Transition instances. + * + * It iterates over triples (State source, Symbol symbol, State target). + */ +class Delta::Transitions { +public: + Transitions() = default; + explicit Transitions(const Delta* delta): delta_{ delta } {} + Transitions(Transitions&&) = default; + Transitions(Transitions&) = default; + Transitions& operator=(Transitions&&) = default; + Transitions& operator=(Transitions&) = default; + + class const_iterator; + const_iterator begin() const; + const_iterator end() const; +private: + const Delta* delta_; +}; // class Transitions. + +/** + * Iterator over transitions. + */ +class Delta::Transitions::const_iterator { +private: + const Delta* delta_ = nullptr; + size_t current_state_{}; + StatePost::const_iterator state_post_it_{}; + StateSet::const_iterator symbol_post_it_{}; + bool is_end_{ false }; + Transition transition_{}; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = Transition; + using difference_type = size_t; + using pointer = Transition*; + using reference = Transition&; + + const_iterator(): is_end_{ true } {} + explicit const_iterator(const Delta& delta); + const_iterator(const Delta& delta, State current_state); + + const_iterator(const const_iterator& other) noexcept = default; + const_iterator(const_iterator&&) = default; + + const Transition& operator*() const { return transition_; } + + // Prefix increment + const_iterator& operator++(); + // Postfix increment + const const_iterator operator++(int); + + const_iterator& operator=(const const_iterator& other) noexcept = default; + const_iterator& operator=(const_iterator&&) = default; + + bool operator==(const const_iterator& other) const; +}; // class Delta::Transitions::const_iterator. + } // namespace mata::nfa. #endif //MATA_DELTA_HH diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 5e3cef278..20fdf991a 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -482,3 +482,12 @@ StatePost::Moves StatePost::symbol_moves(const Symbol last_symbol) const { StatePost::Moves::const_iterator StatePost::Moves::begin() const { return { *state_post_, first_symbol_, last_symbol_, first_symbol_lookup_direction_ }; } + +Delta::Transitions Delta::transitions() const { return Transitions{ this }; } + +Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } +Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } + +StatePost::Moves StatePost::moves() const { return { *this }; } + +StatePost::Moves::const_iterator StatePost::Moves::end() const { return const_iterator{}; } From f59087336bae7adf30e359bd571057309fee7cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Fri, 25 Aug 2023 10:22:01 +0200 Subject: [PATCH 17/25] Set Delta::operator= to be default implemented again It could not be default implemented when we had transitions as a member of Delta. When we no longer have that, it can be default implemented again using the member-wise copy assignment. --- include/mata/nfa/delta.hh | 4 ++-- src/nfa/delta.cc | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index c28073150..f769ee650 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -151,7 +151,7 @@ public: /** * @brief Whether to look up first symbol to iterate over from the beginning or from the end of @c StatePost * iterator. - + * * Iterates over symbol posts with symbols in interval [first_symbol_, last_symbol_]. */ enum class FirstSymbolLookupDiretion { @@ -286,7 +286,7 @@ public: Delta(const Delta& other): state_posts_{ other.state_posts_ } {} explicit Delta(size_t n): state_posts_{ n } {} - Delta& operator=(const Delta& other); + Delta& operator=(const Delta& other) = default; bool operator==(const Delta& other) const; diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 20fdf991a..196ef0311 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -59,11 +59,6 @@ StatePost::const_iterator Delta::epsilon_symbol_posts(const StatePost& state_pos return state_post.end(); } -Delta& Delta::operator=(const Delta& other) { - this->state_posts_ = other.state_posts_; - return *this; -} - void Delta::add(State source, Symbol symbol, State target) { const State max_state{ std::max(source, target) }; if (max_state >= state_posts_.size()) { From bd3b0be5c933627710463634d166d202b95e3212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Mon, 28 Aug 2023 08:21:17 +0200 Subject: [PATCH 18/25] Group function definitions --- src/nfa/delta.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 196ef0311..a374db0a4 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -466,6 +466,8 @@ StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { return *this; } +StatePost::Moves StatePost::moves() const { return { *this }; } + StatePost::Moves StatePost::epsilon_moves(const Symbol first_epsilon) const { return { *this, first_epsilon, Limits::max_symbol, Moves::FirstSymbolLookupDiretion::Backward}; } @@ -478,11 +480,9 @@ StatePost::Moves::const_iterator StatePost::Moves::begin() const { return { *state_post_, first_symbol_, last_symbol_, first_symbol_lookup_direction_ }; } +StatePost::Moves::const_iterator StatePost::Moves::end() const { return const_iterator{}; } + Delta::Transitions Delta::transitions() const { return Transitions{ this }; } Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } - -StatePost::Moves StatePost::moves() const { return { *this }; } - -StatePost::Moves::const_iterator StatePost::Moves::end() const { return const_iterator{}; } From 4d9fced886633399704775246da089efbb81b67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Tue, 29 Aug 2023 10:39:11 +0200 Subject: [PATCH 19/25] Refactor moves public interface --- include/mata/nfa/delta.hh | 99 +++++++++++++-------------- src/nfa/delta.cc | 137 ++++++++++++++++++++++---------------- tests/nfa/delta.cc | 8 +-- 3 files changed, 132 insertions(+), 112 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index f769ee650..97a07ee8b 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -3,6 +3,7 @@ #ifndef MATA_DELTA_HH #define MATA_DELTA_HH +#include "mata/alphabet.hh" #include "mata/nfa/types.hh" #include "mata/utils/synchronized-iterator.hh" @@ -120,20 +121,54 @@ public: iterator find(const Symbol symbol) { return super::find({ symbol, {} }); } const_iterator find(const Symbol symbol) const { return super::find({ symbol, {} }); } - class Moves; + /** + * @brief Iterator over moves represented as @c Move instances. + * + * It iterates over pairs (symbol, target) for the given @c StatePost. + */ + class Moves { + public: + /** + * @brief Over which symbol posts to iterate. + */ + enum class Iterate { + All, ///< Iterate over all symbol posts including epsilons. + Symbols, ///< Iterate over only normal symbols excluding epsilons. + Epsilons ///< Iterate over only epsilons. + }; + + class const_iterator; + + Moves() = default; + Moves(const StatePost& state_post, Iterate iterate = Iterate::All, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol); + Moves(Moves&&) = default; + Moves(Moves&) = default; + Moves& operator=(Moves&& other) noexcept; + Moves& operator=(const Moves& other) noexcept; + + const_iterator begin() const; + const_iterator end() const; + private: + const StatePost* state_post_; + StatePost::const_iterator symbol_post_it_{}; ///< First symbol post (included) to iterate over. + StatePost::const_iterator symbol_post_it_end_{}; ///< Last symbol post (included) to iterate over. + Iterate iterate_{ Iterate::All }; + }; // class Moves. /** * Iterator over all moves in @c StatePost represented as @c Move instances. */ - Moves moves() const; + Moves moves(Moves::Iterate iterate = Moves::Iterate::All, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol) const; /** * Iterator over epsilon moves in @c StatePost represented as @c Move instances. */ Moves epsilon_moves(const Symbol first_epsilon = EPSILON) const; /** - * Iterator over normal symbols (not over epsilons) in @c StatePost represented as @c Move instances. + * Iterator over alphabet (normal) symbols (not over epsilons) in @c StatePost represented as @c Move instances. */ - Moves symbol_moves(const Symbol last_symbol = EPSILON - 1) const; + Moves alphabet_symbol_moves(const Symbol last_symbol = EPSILON - 1) const; /** * Count the number of all moves in @c StatePost. @@ -141,56 +176,15 @@ public: size_t num_of_moves() const; }; // class StatePost. -/** - * @brief Iterator over moves represented as @c Move instances. - * - * It iterates over pairs (symbol, target) for the given @c StatePost. - */ -class StatePost::Moves { -public: - /** - * @brief Whether to look up first symbol to iterate over from the beginning or from the end of @c StatePost - * iterator. - * - * Iterates over symbol posts with symbols in interval [first_symbol_, last_symbol_]. - */ - enum class FirstSymbolLookupDiretion { - Forward, ///< Lookup from the beginning to the end. - Backward ///< Lookup from the end to the beginning. - }; - - class const_iterator; - - Moves() = default; - Moves( - const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, - FirstSymbolLookupDiretion lookup_first_symbol_side = FirstSymbolLookupDiretion::Forward) - : state_post_{ &state_post }, first_symbol_{ first_symbol }, last_symbol_{ last_symbol }, - first_symbol_lookup_direction_{ lookup_first_symbol_side } {} - Moves(Moves&&) = default; - Moves(Moves&) = default; - Moves& operator=(Moves&& other) noexcept; - Moves& operator=(const Moves& other) noexcept; - - const_iterator begin() const; - const_iterator end() const; -private: - const StatePost* state_post_; - Symbol first_symbol_{ Limits::min_symbol }; ///< First symbol (included) to iterate over. - Symbol last_symbol_{ Limits::max_symbol }; ///< Last symbol (included) to iterate over. - FirstSymbolLookupDiretion first_symbol_lookup_direction_{ FirstSymbolLookupDiretion::Forward }; -}; // class Moves. - /** * Iterator over moves. */ class StatePost::Moves::const_iterator { private: const StatePost* state_post_{ nullptr }; - StatePost::const_iterator state_post_it_{}; - StateSet::const_iterator symbol_post_it_{}; - Symbol last_symbol_{ Limits::max_symbol }; + StatePost::const_iterator symbol_post_it_{}; + StateSet::const_iterator target_it_{}; + StatePost::const_iterator symbol_post_it_end_{}; bool is_end_{ false }; /// Internal allocated instance of @c Move which is set for the move currently iterated over and returned as /// a reference with @c operator*(). @@ -205,10 +199,11 @@ public: /// Construct end iterator. const_iterator(): is_end_{ true } {} - /// Construct all moves iterator, epsilon moves iterator or normal symbols moves iterator (excluding epsilons). - const_iterator(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, - const FirstSymbolLookupDiretion firest_symbol_lookup_direction = FirstSymbolLookupDiretion::Forward); + /// Const all moves iterator. + const_iterator(const StatePost& state_post); + /// Construct iterator from @p symbol_post_it (including) to @p symbol_post_it_end (excluding). + const_iterator(const StatePost& state_post, StatePost::const_iterator symbol_post_it, + StatePost::const_iterator symbol_post_it_end); const_iterator(const const_iterator& other) noexcept = default; const_iterator(const_iterator&&) = default; diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index a374db0a4..f78c5277f 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -361,65 +361,49 @@ bool Delta::operator==(const Delta& other) const { } StatePost::Moves::const_iterator::const_iterator( - const StatePost& state_post, const Symbol first_symbol, const Symbol last_symbol, - const Moves::FirstSymbolLookupDiretion first_symbol_lookup_direction) - : state_post_{ &state_post }, last_symbol_{ last_symbol } { - if (state_post_->empty()) { + const StatePost& state_post, const StatePost::const_iterator symbol_post_it, + const StatePost::const_iterator symbol_post_it_end) + : state_post_{ &state_post }, symbol_post_it_{ symbol_post_it }, symbol_post_it_end_{ symbol_post_it_end } { + if (symbol_post_it_ == symbol_post_it_end_) { is_end_ = true; return; } - const StatePost::const_iterator state_post_begin{ state_post_->begin() }; - const StatePost::const_iterator state_post_end{ state_post_->end() }; - if (first_symbol_lookup_direction == Moves::FirstSymbolLookupDiretion::Forward) { - state_post_it_ = state_post_begin; - while (state_post_it_ != state_post_end && first_symbol > state_post_it_->symbol) { ++state_post_it_; } - if (state_post_it_ == state_post_end || state_post_it_->symbol > last_symbol_) { - is_end_ = true; - return; - } - } else { // first_symbol_lookup_direction == Moves::FirstSymbolLookupDiretion::Backward. - auto previous_state_post_it = state_post_end; - do { - state_post_it_ = previous_state_post_it; - --previous_state_post_it; - } while (previous_state_post_it != state_post_begin && first_symbol < previous_state_post_it->symbol); - if (previous_state_post_it == state_post_begin || first_symbol == previous_state_post_it->symbol) { - state_post_it_ = previous_state_post_it; - } - if (state_post_it_->symbol < first_symbol) { - is_end_ = true; - return; - } + + move_.symbol = symbol_post_it_->symbol; + target_it_ = symbol_post_it_->targets.cbegin(); + move_.target = *target_it_; +} + +StatePost::Moves::const_iterator::const_iterator(const StatePost& state_post) + : state_post_{ &state_post }, symbol_post_it_{ state_post.begin() }, symbol_post_it_end_{ state_post.end() } { + if (symbol_post_it_ == symbol_post_it_end_) { + is_end_ = true; + return; } - symbol_post_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *symbol_post_it_; + + move_.symbol = symbol_post_it_->symbol; + target_it_ = symbol_post_it_->targets.cbegin(); + move_.target = *target_it_; } StatePost::Moves::const_iterator& StatePost::Moves::const_iterator::operator++() { - ++symbol_post_it_; - if (symbol_post_it_ != state_post_it_->targets.end()) { - move_.target = *symbol_post_it_; + ++target_it_; + if (target_it_ != symbol_post_it_->targets.end()) { + move_.target = *target_it_; return *this; } - if (state_post_it_->symbol >= last_symbol_) { - // Last symbol symbol post was reached and fully iterated over. We would now iterate to the next symbol, but - // that would already be over the iteration end specified by 'last_symbol_'. - is_end_ = true; - return *this; - } // Iterate over to the next symbol post, which can be either an end iterator, or symbol post whose // symbol <= last_symbol_. - ++state_post_it_; - if (state_post_it_ == state_post_->cend() || state_post_it_->symbol > last_symbol_) { + ++symbol_post_it_; + if (symbol_post_it_ == symbol_post_it_end_) { is_end_ = true; return *this; } - // The current symbol post is valid (not end iterator and symbol <= last_symbol_). - symbol_post_it_ = state_post_it_->targets.begin(); - move_.symbol = state_post_it_->symbol; - move_.target = *symbol_post_it_; + // The current symbol post is valid (not equal symbol_post_it_end_). + move_.symbol = symbol_post_it_->symbol; + target_it_ = symbol_post_it_->targets.begin(); + move_.target = *target_it_; return *this; } @@ -435,7 +419,8 @@ bool StatePost::Moves::const_iterator::operator==(const StatePost::Moves::const_ } else if ((is_end_ && !other.is_end_) || (!is_end_ && other.is_end_)) { return false; } - return state_post_it_ == other.state_post_it_ && symbol_post_it_ == other.symbol_post_it_; + return symbol_post_it_ == other.symbol_post_it_ && target_it_ == other.target_it_ + && symbol_post_it_end_ == other.symbol_post_it_end_; } size_t StatePost::num_of_moves() const { @@ -449,9 +434,8 @@ size_t StatePost::num_of_moves() const { StatePost::Moves& StatePost::Moves::operator=(StatePost::Moves&& other) noexcept { if (&other != this) { state_post_ = other.state_post_; - first_symbol_ = other.first_symbol_; - last_symbol_ = other.last_symbol_; - first_symbol_lookup_direction_ = other.first_symbol_lookup_direction_; + symbol_post_it_ = std::move(other.symbol_post_it_); + symbol_post_it_end_ = std::move(other.symbol_post_it_end_); } return *this; } @@ -459,25 +443,27 @@ StatePost::Moves& StatePost::Moves::operator=(StatePost::Moves&& other) noexcept StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { if (&other != this) { state_post_ = other.state_post_; - first_symbol_ = other.first_symbol_; - last_symbol_ = other.last_symbol_; - first_symbol_lookup_direction_ = other.first_symbol_lookup_direction_; + symbol_post_it_ = other.symbol_post_it_; + symbol_post_it_end_ = other.symbol_post_it_end_; } return *this; } -StatePost::Moves StatePost::moves() const { return { *this }; } +StatePost::Moves StatePost::moves( + const Moves::Iterate iterate, const Symbol first_symbol, const Symbol last_symbol) const { + return { *this, iterate, first_symbol, last_symbol }; +} StatePost::Moves StatePost::epsilon_moves(const Symbol first_epsilon) const { - return { *this, first_epsilon, Limits::max_symbol, Moves::FirstSymbolLookupDiretion::Backward}; + return { *this, Moves::Iterate::Epsilons, first_epsilon, Limits::max_symbol }; } -StatePost::Moves StatePost::symbol_moves(const Symbol last_symbol) const { - return { *this, Limits::min_symbol, last_symbol }; +StatePost::Moves StatePost::alphabet_symbol_moves(const Symbol last_symbol) const { + return { *this, Moves::Iterate::Symbols, Limits::min_symbol, last_symbol }; } StatePost::Moves::const_iterator StatePost::Moves::begin() const { - return { *state_post_, first_symbol_, last_symbol_, first_symbol_lookup_direction_ }; + return { *state_post_, symbol_post_it_, symbol_post_it_end_ }; } StatePost::Moves::const_iterator StatePost::Moves::end() const { return const_iterator{}; } @@ -486,3 +472,42 @@ Delta::Transitions Delta::transitions() const { return Transitions{ this }; } Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } + +StatePost::Moves::Moves(const StatePost& state_post, Moves::Iterate iterate, Symbol first_symbol, Symbol last_symbol) + : state_post_{ &state_post } { + const StatePost::const_iterator state_post_end{ state_post_->end() }; + if (state_post_->empty()) { + symbol_post_it_ = state_post_end; + symbol_post_it_end_ = state_post_end; + return; + } + + if (state_post_->back().symbol <= last_symbol) { symbol_post_it_end_ = state_post_end; } else { + symbol_post_it_end_ = std::upper_bound(state_post_->begin(), state_post_->end(), SymbolPost{ last_symbol }); + } + + const StatePost::const_iterator state_post_begin{ state_post_->begin() }; + StatePost::const_iterator symbol_post_it; + if (iterate == Iterate::All || iterate == Iterate::Symbols) { + symbol_post_it = state_post_begin; + while (symbol_post_it != symbol_post_it_end_ && first_symbol > symbol_post_it->symbol) { ++symbol_post_it; } + if (symbol_post_it == symbol_post_it_end_) { + symbol_post_it_ = symbol_post_it_end_; + return; + } + } else { // iterate == Iterate::Epsilons. + StatePost::const_iterator previous_symbol_post_it = state_post_end; + do { + symbol_post_it = previous_symbol_post_it; + --previous_symbol_post_it; + } while (previous_symbol_post_it != state_post_begin && first_symbol < previous_symbol_post_it->symbol); + if (previous_symbol_post_it == state_post_begin || first_symbol == previous_symbol_post_it->symbol) { + symbol_post_it = previous_symbol_post_it; + } + if (symbol_post_it->symbol < first_symbol) { + symbol_post_it_ = symbol_post_it_end_; + return; + } + } + symbol_post_it_ = symbol_post_it; +} diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 04e74af3a..7e3d59cbc 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -244,20 +244,20 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); state_post = nfa.delta.state_post(0); - StatePost::Moves symbol_moves = state_post.symbol_moves(3); + StatePost::Moves symbol_moves = state_post.alphabet_symbol_moves(3); iterated_moves.clear(); for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); state_post = nfa.delta.state_post(1); - symbol_moves = state_post.symbol_moves(3); + symbol_moves = state_post.alphabet_symbol_moves(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); state_post = nfa.delta.state_post(2); - symbol_moves = state_post.symbol_moves(3); + symbol_moves = state_post.alphabet_symbol_moves(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1}, { 0 , 3 } }); state_post = nfa.delta.state_post(4); - symbol_moves = state_post.symbol_moves(3); + symbol_moves = state_post.alphabet_symbol_moves(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); } } From 46dea3561daa5650326505ba82beee32341db6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Tue, 29 Aug 2023 11:27:06 +0200 Subject: [PATCH 20/25] Change iterate parameter to seek first symbol direction --- include/mata/nfa/delta.hh | 28 ++++++++++++++++------------ src/nfa/delta.cc | 18 +++++++++--------- tests/nfa/delta.cc | 32 ++++++++++++++++---------------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 97a07ee8b..f246b4388 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -129,19 +129,19 @@ public: class Moves { public: /** - * @brief Over which symbol posts to iterate. + * @brief From which direction to seek the first symbol in the vector. */ - enum class Iterate { - All, ///< Iterate over all symbol posts including epsilons. - Symbols, ///< Iterate over only normal symbols excluding epsilons. - Epsilons ///< Iterate over only epsilons. + enum class SeekFirstSymbolDirection { + Forward, //< Seek first symbol from the beginning of the vector. + Backward //< Seek first symbol from the end of the vector. }; class const_iterator; Moves() = default; - Moves(const StatePost& state_post, Iterate iterate = Iterate::All, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol); + Moves(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, + Symbol last_symbol = Limits::max_symbol, + SeekFirstSymbolDirection seek_first_symbol = SeekFirstSymbolDirection::Forward); Moves(Moves&&) = default; Moves(Moves&) = default; Moves& operator=(Moves&& other) noexcept; @@ -153,22 +153,26 @@ public: const StatePost* state_post_; StatePost::const_iterator symbol_post_it_{}; ///< First symbol post (included) to iterate over. StatePost::const_iterator symbol_post_it_end_{}; ///< Last symbol post (included) to iterate over. - Iterate iterate_{ Iterate::All }; + SeekFirstSymbolDirection iterate_{ SeekFirstSymbolDirection::Forward }; }; // class Moves. /** * Iterator over all moves in @c StatePost represented as @c Move instances. */ - Moves moves(Moves::Iterate iterate = Moves::Iterate::All, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol) const; + Moves moves() const { return { *this }; } + /** + * Iterator over specified moves in @c StatePost represented as @c Move instances. + */ + Moves moves(Symbol first_symbol, Symbol last_symbol, + Moves::SeekFirstSymbolDirection seek_first_symbol = Moves::SeekFirstSymbolDirection::Forward) const; /** * Iterator over epsilon moves in @c StatePost represented as @c Move instances. */ - Moves epsilon_moves(const Symbol first_epsilon = EPSILON) const; + Moves moves_epsilons(const Symbol first_epsilon = EPSILON) const; /** * Iterator over alphabet (normal) symbols (not over epsilons) in @c StatePost represented as @c Move instances. */ - Moves alphabet_symbol_moves(const Symbol last_symbol = EPSILON - 1) const; + Moves moves_alphabet_symbols(const Symbol last_symbol = EPSILON - 1) const; /** * Count the number of all moves in @c StatePost. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index f78c5277f..f8ea9f363 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -450,16 +450,16 @@ StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { } StatePost::Moves StatePost::moves( - const Moves::Iterate iterate, const Symbol first_symbol, const Symbol last_symbol) const { - return { *this, iterate, first_symbol, last_symbol }; + const Symbol first_symbol, const Symbol last_symbol, const Moves::SeekFirstSymbolDirection direction) const { + return { *this, first_symbol, last_symbol, direction }; } -StatePost::Moves StatePost::epsilon_moves(const Symbol first_epsilon) const { - return { *this, Moves::Iterate::Epsilons, first_epsilon, Limits::max_symbol }; +StatePost::Moves StatePost::moves_epsilons(const Symbol first_epsilon) const { + return { *this, first_epsilon, Limits::max_symbol, Moves::SeekFirstSymbolDirection::Backward }; } -StatePost::Moves StatePost::alphabet_symbol_moves(const Symbol last_symbol) const { - return { *this, Moves::Iterate::Symbols, Limits::min_symbol, last_symbol }; +StatePost::Moves StatePost::moves_alphabet_symbols(const Symbol last_symbol) const { + return { *this, Limits::min_symbol, last_symbol, Moves::SeekFirstSymbolDirection::Forward }; } StatePost::Moves::const_iterator StatePost::Moves::begin() const { @@ -473,7 +473,7 @@ Delta::Transitions Delta::transitions() const { return Transitions{ this }; } Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } -StatePost::Moves::Moves(const StatePost& state_post, Moves::Iterate iterate, Symbol first_symbol, Symbol last_symbol) +StatePost::Moves::Moves(const StatePost& state_post, Symbol first_symbol, Symbol last_symbol, Moves::SeekFirstSymbolDirection direction) : state_post_{ &state_post } { const StatePost::const_iterator state_post_end{ state_post_->end() }; if (state_post_->empty()) { @@ -488,14 +488,14 @@ StatePost::Moves::Moves(const StatePost& state_post, Moves::Iterate iterate, Sym const StatePost::const_iterator state_post_begin{ state_post_->begin() }; StatePost::const_iterator symbol_post_it; - if (iterate == Iterate::All || iterate == Iterate::Symbols) { + if (direction == SeekFirstSymbolDirection::Forward) { symbol_post_it = state_post_begin; while (symbol_post_it != symbol_post_it_end_ && first_symbol > symbol_post_it->symbol) { ++symbol_post_it; } if (symbol_post_it == symbol_post_it_end_) { symbol_post_it_ = symbol_post_it_end_; return; } - } else { // iterate == Iterate::Epsilons. + } else { // direction == SeekFirstSymbolDirection::Backward. StatePost::const_iterator previous_symbol_post_it = state_post_end; do { symbol_post_it = previous_symbol_post_it; diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 7e3d59cbc..43ce9e624 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -147,7 +147,7 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); - StatePost::Moves epsilon_moves{ state_post.epsilon_moves() }; + StatePost::Moves epsilon_moves{ state_post.moves_epsilons() }; CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); @@ -164,7 +164,7 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(2); @@ -180,7 +180,7 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves == expected_moves); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(3); @@ -195,7 +195,7 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves.empty()); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(4); @@ -210,54 +210,54 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves.empty()); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); nfa.delta.add(0, EPSILON, 2); state_post = nfa.delta.state_post(0); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 2 } }); nfa.delta.add(1, EPSILON, 3); state_post = nfa.delta.state_post(1); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 3 } }); nfa.delta.add(4, EPSILON, 4); state_post = nfa.delta.state_post(4); - epsilon_moves = state_post.epsilon_moves(); + epsilon_moves = state_post.moves_epsilons(); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); state_post = nfa.delta.state_post(0); - epsilon_moves = state_post.epsilon_moves(3); + epsilon_moves = state_post.moves_epsilons(3); iterated_moves.clear(); for (const Move& move: epsilon_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 5, 1 }, { EPSILON, 2 }}); state_post = nfa.delta.state_post(1); - epsilon_moves = state_post.epsilon_moves(3); + epsilon_moves = state_post.moves_epsilons(3); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { 3, 2 }, { EPSILON, 3 } }); state_post = nfa.delta.state_post(2); - epsilon_moves = state_post.epsilon_moves(3); + epsilon_moves = state_post.moves_epsilons(3); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(4); - epsilon_moves = state_post.epsilon_moves(3); + epsilon_moves = state_post.moves_epsilons(3); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); state_post = nfa.delta.state_post(0); - StatePost::Moves symbol_moves = state_post.alphabet_symbol_moves(3); + StatePost::Moves symbol_moves = state_post.moves_alphabet_symbols(3); iterated_moves.clear(); for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); state_post = nfa.delta.state_post(1); - symbol_moves = state_post.alphabet_symbol_moves(3); + symbol_moves = state_post.moves_alphabet_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); state_post = nfa.delta.state_post(2); - symbol_moves = state_post.alphabet_symbol_moves(3); + symbol_moves = state_post.moves_alphabet_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1}, { 0 , 3 } }); state_post = nfa.delta.state_post(4); - symbol_moves = state_post.alphabet_symbol_moves(3); + symbol_moves = state_post.moves_alphabet_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); } } From 8e6093b14a549e02cadc6c3e495a4af12ae75536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Wed, 30 Aug 2023 06:46:40 +0200 Subject: [PATCH 21/25] Improve comments --- include/mata/nfa/delta.hh | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index f246b4388..f36699048 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -132,16 +132,25 @@ public: * @brief From which direction to seek the first symbol in the vector. */ enum class SeekFirstSymbolDirection { - Forward, //< Seek first symbol from the beginning of the vector. - Backward //< Seek first symbol from the end of the vector. + Forward, //< Seek the first symbol from the beginning of the vector. + Backward //< Seek the first symbol from the end of the vector. }; class const_iterator; Moves() = default; + /** + * @brief construct moves iterating over a closed interval @p first_symbol and @p last_symbol. + * + * @param[in] state_post State post to iterate over. + * @param[in] first_symbol First symbol to iterate over (including the @p first_symbol). + * @param[in] last_symbol Last symbol to iterate over (including the @p last_symbol). + * @param[in] seek_first_symbol_direction Direction of how to look for the symbol post to iterate over (equal + * to or first larger than @p first_symbol) in the state post. + */ Moves(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, Symbol last_symbol = Limits::max_symbol, - SeekFirstSymbolDirection seek_first_symbol = SeekFirstSymbolDirection::Forward); + SeekFirstSymbolDirection seek_first_symbol_direction = SeekFirstSymbolDirection::Forward); Moves(Moves&&) = default; Moves(Moves&) = default; Moves& operator=(Moves&& other) noexcept; @@ -151,9 +160,11 @@ public: const_iterator end() const; private: const StatePost* state_post_; - StatePost::const_iterator symbol_post_it_{}; ///< First symbol post (included) to iterate over. - StatePost::const_iterator symbol_post_it_end_{}; ///< Last symbol post (included) to iterate over. - SeekFirstSymbolDirection iterate_{ SeekFirstSymbolDirection::Forward }; + StatePost::const_iterator symbol_post_it_{}; ///< Current symbol post iterator to iterate over. + /// Symbol post iterator end for specified @p last_symbol (one symbol post after the @c last_symbol, or 'end()'). + StatePost::const_iterator symbol_post_it_end_{}; + /// Direction of how to look up the @c first_symbol to iterate over. + SeekFirstSymbolDirection direction_{ SeekFirstSymbolDirection::Forward }; }; // class Moves. /** From 54b21deaf190103860c962141527b54bbb2996f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Wed, 30 Aug 2023 12:56:33 +0200 Subject: [PATCH 22/25] Specify iteration over only epsilons with bool flag --- include/mata/nfa/delta.hh | 22 +++++++++-------- src/nfa/delta.cc | 51 +++++++++++++++++++++++---------------- tests/nfa/delta.cc | 8 +++--- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index f36699048..81969e338 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -145,12 +145,11 @@ public: * @param[in] state_post State post to iterate over. * @param[in] first_symbol First symbol to iterate over (including the @p first_symbol). * @param[in] last_symbol Last symbol to iterate over (including the @p last_symbol). - * @param[in] seek_first_symbol_direction Direction of how to look for the symbol post to iterate over (equal - * to or first larger than @p first_symbol) in the state post. + * @param[in] iterate_only_epsilons Whether to iterate only over epsilons. Set to 'true' if you want to iterate + * only over epsilons. */ Moves(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, - SeekFirstSymbolDirection seek_first_symbol_direction = SeekFirstSymbolDirection::Forward); + Symbol last_symbol = Limits::max_symbol, bool iterate_only_epsilons = false); Moves(Moves&&) = default; Moves(Moves&) = default; Moves& operator=(Moves&& other) noexcept; @@ -163,19 +162,22 @@ public: StatePost::const_iterator symbol_post_it_{}; ///< Current symbol post iterator to iterate over. /// Symbol post iterator end for specified @p last_symbol (one symbol post after the @c last_symbol, or 'end()'). StatePost::const_iterator symbol_post_it_end_{}; - /// Direction of how to look up the @c first_symbol to iterate over. - SeekFirstSymbolDirection direction_{ SeekFirstSymbolDirection::Forward }; + bool iterate_only_epsilons_{ false }; }; // class Moves. /** - * Iterator over all moves in @c StatePost represented as @c Move instances. + * Iterator over all moves (over all labels) in @c StatePost represented as @c Move instances. */ Moves moves() const { return { *this }; } /** * Iterator over specified moves in @c StatePost represented as @c Move instances. + * + * @param[in] first_symbol First symbol to iterate over. + * @param[in] last_symbol Last symbol to iterate over. + * @param[in] iterate_only_epsilons Whether to iterate only over epsilons. Set to 'true' if you want to iterate + * over only epsilons. */ - Moves moves(Symbol first_symbol, Symbol last_symbol, - Moves::SeekFirstSymbolDirection seek_first_symbol = Moves::SeekFirstSymbolDirection::Forward) const; + Moves moves(Symbol first_symbol, Symbol last_symbol, bool iterate_only_epsilons = false) const; /** * Iterator over epsilon moves in @c StatePost represented as @c Move instances. */ @@ -183,7 +185,7 @@ public: /** * Iterator over alphabet (normal) symbols (not over epsilons) in @c StatePost represented as @c Move instances. */ - Moves moves_alphabet_symbols(const Symbol last_symbol = EPSILON - 1) const; + Moves moves_symbols(const Symbol last_symbol = EPSILON - 1) const; /** * Count the number of all moves in @c StatePost. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index f8ea9f363..3370d33ad 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -450,16 +450,16 @@ StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { } StatePost::Moves StatePost::moves( - const Symbol first_symbol, const Symbol last_symbol, const Moves::SeekFirstSymbolDirection direction) const { - return { *this, first_symbol, last_symbol, direction }; + const Symbol first_symbol, const Symbol last_symbol, const bool iterate_only_epsilons) const { + return { *this, first_symbol, last_symbol, iterate_only_epsilons }; } StatePost::Moves StatePost::moves_epsilons(const Symbol first_epsilon) const { - return { *this, first_epsilon, Limits::max_symbol, Moves::SeekFirstSymbolDirection::Backward }; + return { *this, first_epsilon, Limits::max_symbol, true }; } -StatePost::Moves StatePost::moves_alphabet_symbols(const Symbol last_symbol) const { - return { *this, Limits::min_symbol, last_symbol, Moves::SeekFirstSymbolDirection::Forward }; +StatePost::Moves StatePost::moves_symbols(const Symbol last_symbol) const { + return { *this, Limits::min_symbol, last_symbol, false }; } StatePost::Moves::const_iterator StatePost::Moves::begin() const { @@ -473,8 +473,8 @@ Delta::Transitions Delta::transitions() const { return Transitions{ this }; } Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } -StatePost::Moves::Moves(const StatePost& state_post, Symbol first_symbol, Symbol last_symbol, Moves::SeekFirstSymbolDirection direction) - : state_post_{ &state_post } { +StatePost::Moves::Moves(const StatePost& state_post, Symbol first_symbol, Symbol last_symbol, + const bool iterate_only_epsilons): state_post_{ &state_post } { const StatePost::const_iterator state_post_end{ state_post_->end() }; if (state_post_->empty()) { symbol_post_it_ = state_post_end; @@ -482,32 +482,41 @@ StatePost::Moves::Moves(const StatePost& state_post, Symbol first_symbol, Symbol return; } - if (state_post_->back().symbol <= last_symbol) { symbol_post_it_end_ = state_post_end; } else { - symbol_post_it_end_ = std::upper_bound(state_post_->begin(), state_post_->end(), SymbolPost{ last_symbol }); - } + const StatePost::const_iterator symbol_post_it_begin{ state_post_->begin() }; + + StatePost::const_iterator previous_symbol_post_it = state_post_end; + do { + symbol_post_it_end_ = previous_symbol_post_it; + --previous_symbol_post_it; + } while (previous_symbol_post_it != symbol_post_it_begin && last_symbol < previous_symbol_post_it->symbol); + if (previous_symbol_post_it == symbol_post_it_begin && last_symbol < previous_symbol_post_it->symbol) { + symbol_post_it_ = state_post_end; + symbol_post_it_end_ = state_post_end; + return; + } // Else, symbol_post_it_end_ is already set to the symbol post with symbol greater than last_symbol (it can be + // even state_post_end). - const StatePost::const_iterator state_post_begin{ state_post_->begin() }; StatePost::const_iterator symbol_post_it; - if (direction == SeekFirstSymbolDirection::Forward) { - symbol_post_it = state_post_begin; - while (symbol_post_it != symbol_post_it_end_ && first_symbol > symbol_post_it->symbol) { ++symbol_post_it; } - if (symbol_post_it == symbol_post_it_end_) { - symbol_post_it_ = symbol_post_it_end_; - return; - } - } else { // direction == SeekFirstSymbolDirection::Backward. + if (iterate_only_epsilons) { // Iterate only over epsilons. StatePost::const_iterator previous_symbol_post_it = state_post_end; do { symbol_post_it = previous_symbol_post_it; --previous_symbol_post_it; - } while (previous_symbol_post_it != state_post_begin && first_symbol < previous_symbol_post_it->symbol); - if (previous_symbol_post_it == state_post_begin || first_symbol == previous_symbol_post_it->symbol) { + } while (previous_symbol_post_it != symbol_post_it_begin && first_symbol < previous_symbol_post_it->symbol); + if (previous_symbol_post_it == symbol_post_it_begin || first_symbol == previous_symbol_post_it->symbol) { symbol_post_it = previous_symbol_post_it; } if (symbol_post_it->symbol < first_symbol) { symbol_post_it_ = symbol_post_it_end_; return; } + } else { // Iterate over all labels or over only symbols. + symbol_post_it = symbol_post_it_begin; + while (symbol_post_it != symbol_post_it_end_ && first_symbol > symbol_post_it->symbol) { ++symbol_post_it; } + if (symbol_post_it == symbol_post_it_end_) { + symbol_post_it_ = symbol_post_it_end_; + return; + } } symbol_post_it_ = symbol_post_it; } diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 43ce9e624..87a81ee49 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -244,20 +244,20 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { EPSILON, 4 } }); state_post = nfa.delta.state_post(0); - StatePost::Moves symbol_moves = state_post.moves_alphabet_symbols(3); + StatePost::Moves symbol_moves = state_post.moves_symbols(3); iterated_moves.clear(); for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); state_post = nfa.delta.state_post(1); - symbol_moves = state_post.moves_alphabet_symbols(3); + symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); state_post = nfa.delta.state_post(2); - symbol_moves = state_post.moves_alphabet_symbols(3); + symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1}, { 0 , 3 } }); state_post = nfa.delta.state_post(4); - symbol_moves = state_post.moves_alphabet_symbols(3); + symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); } } From b22596d24c32193bbda1b10ce3cdb7b9f513925a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 31 Aug 2023 08:47:43 +0200 Subject: [PATCH 23/25] Move logic getting begin and end symbol post iterators to moves_...() functions --- include/mata/nfa/delta.hh | 36 +++++--------- src/nfa/delta.cc | 101 ++++++++++++++++++-------------------- tests/nfa/delta.cc | 12 ++--- 3 files changed, 62 insertions(+), 87 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 81969e338..a0ab3de46 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -128,56 +128,42 @@ public: */ class Moves { public: - /** - * @brief From which direction to seek the first symbol in the vector. - */ - enum class SeekFirstSymbolDirection { - Forward, //< Seek the first symbol from the beginning of the vector. - Backward //< Seek the first symbol from the end of the vector. - }; - - class const_iterator; - Moves() = default; /** - * @brief construct moves iterating over a closed interval @p first_symbol and @p last_symbol. + * @brief construct moves iterating over a range @p symbol_post_it (including) to @p symbol_post_end (excluding). * * @param[in] state_post State post to iterate over. - * @param[in] first_symbol First symbol to iterate over (including the @p first_symbol). - * @param[in] last_symbol Last symbol to iterate over (including the @p last_symbol). - * @param[in] iterate_only_epsilons Whether to iterate only over epsilons. Set to 'true' if you want to iterate - * only over epsilons. + * @param[in] symbol_post_it First iterator over symbol posts to iterate over. + * @param[in] symbol_post_end End iterator over symbol posts (which functions as an sentinel, is not iterated over). */ - Moves(const StatePost& state_post, Symbol first_symbol = Limits::min_symbol, - Symbol last_symbol = Limits::max_symbol, bool iterate_only_epsilons = false); + Moves(const StatePost& state_post, StatePost::const_iterator symbol_post_it, StatePost::const_iterator symbol_post_end); Moves(Moves&&) = default; Moves(Moves&) = default; Moves& operator=(Moves&& other) noexcept; Moves& operator=(const Moves& other) noexcept; + class const_iterator; const_iterator begin() const; const_iterator end() const; + private: const StatePost* state_post_; StatePost::const_iterator symbol_post_it_{}; ///< Current symbol post iterator to iterate over. /// Symbol post iterator end for specified @p last_symbol (one symbol post after the @c last_symbol, or 'end()'). - StatePost::const_iterator symbol_post_it_end_{}; - bool iterate_only_epsilons_{ false }; + StatePost::const_iterator symbol_post_end_{}; }; // class Moves. /** * Iterator over all moves (over all labels) in @c StatePost represented as @c Move instances. */ - Moves moves() const { return { *this }; } + Moves moves() const { return { *this, this->cbegin(), this->cend() }; } /** * Iterator over specified moves in @c StatePost represented as @c Move instances. * - * @param[in] first_symbol First symbol to iterate over. - * @param[in] last_symbol Last symbol to iterate over. - * @param[in] iterate_only_epsilons Whether to iterate only over epsilons. Set to 'true' if you want to iterate - * over only epsilons. + * @param[in] symbol_post_it First iterator over symbol posts to iterate over. + * @param[in] symbol_post_end End iterator over symbol posts (which functions as an sentinel, is not iterated over). */ - Moves moves(Symbol first_symbol, Symbol last_symbol, bool iterate_only_epsilons = false) const; + Moves moves(StatePost::const_iterator symbol_post_it, StatePost::const_iterator symbol_post_end) const; /** * Iterator over epsilon moves in @c StatePost represented as @c Move instances. */ diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 3370d33ad..d9c7fea8d 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -435,7 +435,7 @@ StatePost::Moves& StatePost::Moves::operator=(StatePost::Moves&& other) noexcept if (&other != this) { state_post_ = other.state_post_; symbol_post_it_ = std::move(other.symbol_post_it_); - symbol_post_it_end_ = std::move(other.symbol_post_it_end_); + symbol_post_end_ = std::move(other.symbol_post_end_); } return *this; } @@ -444,26 +444,63 @@ StatePost::Moves& StatePost::Moves::operator=(const Moves& other) noexcept { if (&other != this) { state_post_ = other.state_post_; symbol_post_it_ = other.symbol_post_it_; - symbol_post_it_end_ = other.symbol_post_it_end_; + symbol_post_end_ = other.symbol_post_end_; } return *this; } StatePost::Moves StatePost::moves( - const Symbol first_symbol, const Symbol last_symbol, const bool iterate_only_epsilons) const { - return { *this, first_symbol, last_symbol, iterate_only_epsilons }; + const StatePost::const_iterator symbol_post_it, const StatePost::const_iterator symbol_post_end) const { + return { *this, symbol_post_it, symbol_post_end }; } StatePost::Moves StatePost::moves_epsilons(const Symbol first_epsilon) const { - return { *this, first_epsilon, Limits::max_symbol, true }; + const StatePost::const_iterator symbol_post_begin{ cbegin() }; + const StatePost::const_iterator symbol_post_end{ cend() }; + if (empty()) { + return { *this, symbol_post_end, symbol_post_end }; + } + if (symbol_post_begin->symbol >= first_epsilon) { + return { *this, symbol_post_begin, symbol_post_end }; + } + + StatePost::const_iterator previous_symbol_post_it{ std::prev(symbol_post_end) }; + StatePost::const_iterator symbol_post_it{ previous_symbol_post_it }; + while (previous_symbol_post_it != symbol_post_begin && first_epsilon < previous_symbol_post_it->symbol) { + symbol_post_it = previous_symbol_post_it; + --previous_symbol_post_it; + } + if (first_epsilon <= previous_symbol_post_it->symbol) { + return { *this, previous_symbol_post_it, symbol_post_end }; + } + if (first_epsilon <= symbol_post_it->symbol) { + return { *this, symbol_post_it, symbol_post_end }; + } + return { *this, symbol_post_end, symbol_post_end }; } StatePost::Moves StatePost::moves_symbols(const Symbol last_symbol) const { - return { *this, Limits::min_symbol, last_symbol, false }; + const StatePost::const_iterator symbol_post_end{ cend() }; + const StatePost::const_iterator symbol_post_begin{ cbegin() }; + const Symbol symbol_post_begin_symbol{ symbol_post_begin->symbol }; + if (empty() || symbol_post_begin_symbol > last_symbol) { + return { *this, symbol_post_end, symbol_post_end }; + } + + StatePost::const_iterator end_symbol_post_it { symbol_post_end }; + StatePost::const_iterator previous_end_symbol_post_it{ std::prev(symbol_post_end) }; + while (previous_end_symbol_post_it != symbol_post_begin && last_symbol < previous_end_symbol_post_it->symbol) { + end_symbol_post_it = previous_end_symbol_post_it; + --previous_end_symbol_post_it; + } + if (last_symbol >= previous_end_symbol_post_it->symbol) { + return { *this, symbol_post_begin, end_symbol_post_it }; + } + return { *this, symbol_post_end, symbol_post_end }; } StatePost::Moves::const_iterator StatePost::Moves::begin() const { - return { *state_post_, symbol_post_it_, symbol_post_it_end_ }; + return { *state_post_, symbol_post_it_, symbol_post_end_ }; } StatePost::Moves::const_iterator StatePost::Moves::end() const { return const_iterator{}; } @@ -473,50 +510,6 @@ Delta::Transitions Delta::transitions() const { return Transitions{ this }; } Delta::Transitions::const_iterator Delta::Transitions::begin() const { return const_iterator{ *delta_ }; } Delta::Transitions::const_iterator Delta::Transitions::end() const { return const_iterator{}; } -StatePost::Moves::Moves(const StatePost& state_post, Symbol first_symbol, Symbol last_symbol, - const bool iterate_only_epsilons): state_post_{ &state_post } { - const StatePost::const_iterator state_post_end{ state_post_->end() }; - if (state_post_->empty()) { - symbol_post_it_ = state_post_end; - symbol_post_it_end_ = state_post_end; - return; - } - - const StatePost::const_iterator symbol_post_it_begin{ state_post_->begin() }; - - StatePost::const_iterator previous_symbol_post_it = state_post_end; - do { - symbol_post_it_end_ = previous_symbol_post_it; - --previous_symbol_post_it; - } while (previous_symbol_post_it != symbol_post_it_begin && last_symbol < previous_symbol_post_it->symbol); - if (previous_symbol_post_it == symbol_post_it_begin && last_symbol < previous_symbol_post_it->symbol) { - symbol_post_it_ = state_post_end; - symbol_post_it_end_ = state_post_end; - return; - } // Else, symbol_post_it_end_ is already set to the symbol post with symbol greater than last_symbol (it can be - // even state_post_end). - - StatePost::const_iterator symbol_post_it; - if (iterate_only_epsilons) { // Iterate only over epsilons. - StatePost::const_iterator previous_symbol_post_it = state_post_end; - do { - symbol_post_it = previous_symbol_post_it; - --previous_symbol_post_it; - } while (previous_symbol_post_it != symbol_post_it_begin && first_symbol < previous_symbol_post_it->symbol); - if (previous_symbol_post_it == symbol_post_it_begin || first_symbol == previous_symbol_post_it->symbol) { - symbol_post_it = previous_symbol_post_it; - } - if (symbol_post_it->symbol < first_symbol) { - symbol_post_it_ = symbol_post_it_end_; - return; - } - } else { // Iterate over all labels or over only symbols. - symbol_post_it = symbol_post_it_begin; - while (symbol_post_it != symbol_post_it_end_ && first_symbol > symbol_post_it->symbol) { ++symbol_post_it; } - if (symbol_post_it == symbol_post_it_end_) { - symbol_post_it_ = symbol_post_it_end_; - return; - } - } - symbol_post_it_ = symbol_post_it; -} +StatePost::Moves::Moves( + const StatePost& state_post, StatePost::const_iterator symbol_post_it, StatePost::const_iterator symbol_post_end) + : state_post_{ &state_post }, symbol_post_it_{ symbol_post_it }, symbol_post_end_{ symbol_post_end } {} diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 87a81ee49..0795f1013 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -150,7 +150,6 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { StatePost::Moves epsilon_moves{ state_post.moves_epsilons() }; CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); - state_post = nfa.delta.state_post(1); moves = state_post.moves(); iterated_moves.clear(); @@ -229,13 +228,12 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { state_post = nfa.delta.state_post(0); epsilon_moves = state_post.moves_epsilons(3); iterated_moves.clear(); - for (const Move& move: epsilon_moves) { - iterated_moves.push_back(move); - } + for (const Move& move: epsilon_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 5, 1 }, { EPSILON, 2 }}); state_post = nfa.delta.state_post(1); epsilon_moves = state_post.moves_epsilons(3); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() } == std::vector{ { 3, 2 }, { EPSILON, 3 } }); + state_post = nfa.delta.state_post(2); epsilon_moves = state_post.moves_epsilons(3); CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); @@ -246,16 +244,14 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { state_post = nfa.delta.state_post(0); StatePost::Moves symbol_moves = state_post.moves_symbols(3); iterated_moves.clear(); - for (const Move& move: symbol_moves) { - iterated_moves.push_back(move); - } + for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); state_post = nfa.delta.state_post(1); symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); state_post = nfa.delta.state_post(2); symbol_moves = state_post.moves_symbols(3); - CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1}, { 0 , 3 } }); + CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 0, 1 }, { 0 , 3 } }); state_post = nfa.delta.state_post(4); symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); From b227d3bac7583cec572f30b6bcdbd339c6e38bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 31 Aug 2023 10:27:52 +0200 Subject: [PATCH 24/25] Simplify last symbol lookup --- include/mata/nfa/delta.hh | 5 +++-- src/nfa/delta.cc | 11 +++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index a0ab3de46..3465e5e2c 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -134,7 +134,7 @@ public: * * @param[in] state_post State post to iterate over. * @param[in] symbol_post_it First iterator over symbol posts to iterate over. - * @param[in] symbol_post_end End iterator over symbol posts (which functions as an sentinel, is not iterated over). + * @param[in] symbol_post_end End iterator over symbol posts (which functions as an sentinel; is not iterated over). */ Moves(const StatePost& state_post, StatePost::const_iterator symbol_post_it, StatePost::const_iterator symbol_post_end); Moves(Moves&&) = default; @@ -149,7 +149,8 @@ public: private: const StatePost* state_post_; StatePost::const_iterator symbol_post_it_{}; ///< Current symbol post iterator to iterate over. - /// Symbol post iterator end for specified @p last_symbol (one symbol post after the @c last_symbol, or 'end()'). + /// End symbol post iterator which is no longer iterated over (one after the last symbol post iterated over or + /// end()). StatePost::const_iterator symbol_post_end_{}; }; // class Moves. diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index d9c7fea8d..1d2652d27 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -482,8 +482,7 @@ StatePost::Moves StatePost::moves_epsilons(const Symbol first_epsilon) const { StatePost::Moves StatePost::moves_symbols(const Symbol last_symbol) const { const StatePost::const_iterator symbol_post_end{ cend() }; const StatePost::const_iterator symbol_post_begin{ cbegin() }; - const Symbol symbol_post_begin_symbol{ symbol_post_begin->symbol }; - if (empty() || symbol_post_begin_symbol > last_symbol) { + if (empty() || symbol_post_begin->symbol > last_symbol) { return { *this, symbol_post_end, symbol_post_end }; } @@ -493,10 +492,10 @@ StatePost::Moves StatePost::moves_symbols(const Symbol last_symbol) const { end_symbol_post_it = previous_end_symbol_post_it; --previous_end_symbol_post_it; } - if (last_symbol >= previous_end_symbol_post_it->symbol) { - return { *this, symbol_post_begin, end_symbol_post_it }; - } - return { *this, symbol_post_end, symbol_post_end }; + // Either previous_end_symbol_post_it is == symbol_post_begin, at which case we should iterate only over the first + // symbol post (that is, end_symbol_post_it == symbol_post_begin + 1); or, previous_end_symbol_post_it jumped over + // last_symbol and end_symbol_post_it is the first symbol post (or end()) after last symbol. + return { *this, symbol_post_begin, end_symbol_post_it }; } StatePost::Moves::const_iterator StatePost::Moves::begin() const { From 87271aa22962b6fef132bec4b1691c6260fb2f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Chocholat=C3=BD?= Date: Thu, 31 Aug 2023 10:29:00 +0200 Subject: [PATCH 25/25] Add more edge case tests --- include/mata/nfa/delta.hh | 4 ++-- src/nfa/delta.cc | 18 +++++++++--------- tests/nfa/delta.cc | 30 +++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index 3465e5e2c..6da38406e 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -147,7 +147,7 @@ public: const_iterator end() const; private: - const StatePost* state_post_; + const StatePost* state_post_{ nullptr }; StatePost::const_iterator symbol_post_it_{}; ///< Current symbol post iterator to iterate over. /// End symbol post iterator which is no longer iterated over (one after the last symbol post iterated over or /// end()). @@ -188,7 +188,7 @@ private: const StatePost* state_post_{ nullptr }; StatePost::const_iterator symbol_post_it_{}; StateSet::const_iterator target_it_{}; - StatePost::const_iterator symbol_post_it_end_{}; + StatePost::const_iterator symbol_post_end_{}; bool is_end_{ false }; /// Internal allocated instance of @c Move which is set for the move currently iterated over and returned as /// a reference with @c operator*(). diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index 1d2652d27..5bac5b16c 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -362,9 +362,9 @@ bool Delta::operator==(const Delta& other) const { StatePost::Moves::const_iterator::const_iterator( const StatePost& state_post, const StatePost::const_iterator symbol_post_it, - const StatePost::const_iterator symbol_post_it_end) - : state_post_{ &state_post }, symbol_post_it_{ symbol_post_it }, symbol_post_it_end_{ symbol_post_it_end } { - if (symbol_post_it_ == symbol_post_it_end_) { + const StatePost::const_iterator symbol_post_end) + : state_post_{ &state_post }, symbol_post_it_{ symbol_post_it }, symbol_post_end_{ symbol_post_end } { + if (symbol_post_it_ == symbol_post_end_) { is_end_ = true; return; } @@ -375,8 +375,8 @@ StatePost::Moves::const_iterator::const_iterator( } StatePost::Moves::const_iterator::const_iterator(const StatePost& state_post) - : state_post_{ &state_post }, symbol_post_it_{ state_post.begin() }, symbol_post_it_end_{ state_post.end() } { - if (symbol_post_it_ == symbol_post_it_end_) { + : state_post_{ &state_post }, symbol_post_it_{ state_post.begin() }, symbol_post_end_{ state_post.end() } { + if (symbol_post_it_ == symbol_post_end_) { is_end_ = true; return; } @@ -394,13 +394,13 @@ StatePost::Moves::const_iterator& StatePost::Moves::const_iterator::operator++() } // Iterate over to the next symbol post, which can be either an end iterator, or symbol post whose - // symbol <= last_symbol_. + // symbol <= symbol_post_end_. ++symbol_post_it_; - if (symbol_post_it_ == symbol_post_it_end_) { + if (symbol_post_it_ == symbol_post_end_) { is_end_ = true; return *this; } - // The current symbol post is valid (not equal symbol_post_it_end_). + // The current symbol post is valid (not equal symbol_post_end_). move_.symbol = symbol_post_it_->symbol; target_it_ = symbol_post_it_->targets.begin(); move_.target = *target_it_; @@ -420,7 +420,7 @@ bool StatePost::Moves::const_iterator::operator==(const StatePost::Moves::const_ return false; } return symbol_post_it_ == other.symbol_post_it_ && target_it_ == other.target_it_ - && symbol_post_it_end_ == other.symbol_post_it_end_; + && symbol_post_end_ == other.symbol_post_end_; } size_t StatePost::num_of_moves() const { diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 0795f1013..8b55b9a40 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -152,6 +152,13 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { state_post = nfa.delta.state_post(1); moves = state_post.moves(); + StatePost::Moves moves_custom; + moves_custom = moves; + CHECK(std::vector{ moves.begin(), moves.end() } + == std::vector{ moves_custom.begin(), moves_custom.end() }); + moves_custom = state_post.moves(state_post.begin(), state_post.end()); + CHECK(std::vector{ moves.begin(), moves.end() } + == std::vector{ moves_custom.begin(), moves_custom.end() }); iterated_moves.clear(); for (auto move_it{ moves.begin() }; move_it != moves.end(); ++move_it) { iterated_moves.push_back(*move_it); @@ -189,6 +196,7 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.push_back(*move_it); } CHECK(iterated_moves.empty()); + CHECK(StatePost::Moves::const_iterator{ state_post } == moves.end()); iterated_moves = { moves.begin(), moves.end() }; CHECK(iterated_moves.empty()); iterated_moves.clear(); @@ -246,6 +254,11 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { iterated_moves.clear(); for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); + symbol_moves = state_post.moves_symbols(0); + iterated_moves.clear(); + for (const Move& move: symbol_moves) { iterated_moves.push_back(move); } + CHECK(iterated_moves.empty()); + state_post = nfa.delta.state_post(1); symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() } == std::vector{ { 3, 2 } }); @@ -255,6 +268,17 @@ TEST_CASE("mata::nfa::StatePost iteration over moves") { state_post = nfa.delta.state_post(4); symbol_moves = state_post.moves_symbols(3); CHECK(std::vector{ symbol_moves.begin(), symbol_moves.end() }.empty()); + + // Create custom moves iterator. + state_post = nfa.delta[0]; + moves = { state_post, state_post.cbegin(), state_post.cbegin() + 2 }; + iterated_moves = { moves.begin(), moves.end() }; + CHECK(iterated_moves == std::vector{ { 1, 1 }, { 2, 1 } }); + + state_post = nfa.delta[20]; + moves = { state_post, state_post.cbegin(), state_post.cend() }; + iterated_moves = { moves.begin(), moves.end() }; + CHECK(iterated_moves.empty()); } } @@ -265,7 +289,11 @@ TEST_CASE("mata::nfa::Delta iteration over transitions") { SECTION("empty automaton") { Delta::Transitions transitions{ nfa.delta.transitions() }; - REQUIRE(transitions.begin() == transitions.end()); + CHECK(transitions.begin() == transitions.end()); + Delta::Transitions::const_iterator transition_it{ nfa.delta }; + CHECK(transition_it == transitions.end()); + transition_it = { nfa.delta, 0 }; + CHECK(transition_it == transitions.end()); } SECTION("Simple NFA") {