diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index 5d7966475..4b7f2c891 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -51,8 +51,20 @@ 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": + cppclass const_iterator: + bool operator==(const_iterator&) + bool operator!=(const_iterator&) + CTrans& operator*() + const_iterator& operator++() + const_iterator begin() + const_iterator end() + CTransitions() + + cdef cppclass CDelta "mata::nfa::Delta": - vector[CStatePost] post + vector[CStatePost] state_posts + CTransitions transitions void reserve(size_t) CStatePost& state_post(State) @@ -70,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 @@ -109,16 +123,10 @@ cdef extern from "mata/nfa/nfa.hh" namespace "mata::nfa": bool operator>(CSymbolPost) bool operator>=(CSymbolPost) - 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() + COrdVector[State].const_iterator begin() + COrdVector[State].const_iterator end() + cdef cppclass CNfa "mata::nfa::Nfa": # Public Attributes CSparseSet[State] initial CSparseSet[State] final @@ -146,16 +154,11 @@ 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() State add_state() State add_state(State) 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..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().get_num_of_trans() + 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().begin() - while iterator != self.thisptr.get().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) @@ -444,23 +445,35 @@ 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() + 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)) 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): 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 c10e08edc..6da38406e 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" @@ -121,64 +122,107 @@ 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 std::vector& symbol_posts_{}; - std::vector::const_iterator symbol_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&; - - explicit moves_const_iterator(const std::vector& symbol_posts, bool is_end = false); - - moves_const_iterator(const std::vector& symbol_posts, - std::vector::const_iterator symbol_posts_it, - StateSet::const_iterator target_states_it, bool is_end = false); - - moves_const_iterator(const moves_const_iterator& other) = default; - - const Move& operator*() const { return move_; } - - // Prefix increment - moves_const_iterator& operator++(); - // Postfix increment - const moves_const_iterator operator++(int); - - moves_const_iterator& operator=(const moves_const_iterator& x); - - bool operator==(const moves_const_iterator& other) const; - bool operator!=(const moves_const_iterator& other) const { return !(*this == other); }; - }; + Moves() = default; + /** + * @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] 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, 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; - 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_begin() const { return moves_cbegin(); } - moves_const_iterator moves_end() const { return moves_cend(); } + private: + 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()). + StatePost::const_iterator symbol_post_end_{}; + }; // 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 all moves (over all labels) in @c StatePost represented as @c Move instances. + */ + Moves moves() const { return { *this, this->cbegin(), this->cend() }; } + /** + * Iterator over specified moves in @c StatePost represented as @c Move instances. + * + * @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(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. + */ + 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 moves_symbols(const Symbol last_symbol = EPSILON - 1) const; /** - * Iterate over moves represented as 'Move' instances. - * @return Iterator over moves. + * Count the number of all moves in @c StatePost. */ - Moves moves() const { return { .begin_ = moves_begin(), .end_ = moves_end() }; } -}; // struct Post. + size_t num_of_moves() const; +}; // class StatePost. + +/** + * Iterator over moves. + */ +class StatePost::Moves::const_iterator { +private: + const StatePost* state_post_{ nullptr }; + StatePost::const_iterator symbol_post_it_{}; + StateSet::const_iterator target_it_{}; + 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*(). + 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 } {} + /// 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; + + 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. @@ -234,24 +278,21 @@ 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) = default; + + bool operator==(const Delta& other) const; void reserve(size_t n) { 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. * @@ -314,6 +355,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); @@ -366,69 +412,19 @@ public: */ void add(const State state_from, const Symbol symbol, const StateSet& states); - /** - * Iterator over transitions. It iterates over triples (lhs, symbol, rhs) where lhs and rhs are states. - */ - struct transitions_const_iterator { - private: - const std::vector& post_; - size_t current_state_; - StatePost::const_iterator post_iterator_{}; - StateSet::const_iterator targets_position_{}; - bool is_end_; - Transition transition_{}; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = Transition; - using difference_type = unsigned; - 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(const transitions_const_iterator& other) = 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& x); - - bool operator==(const transitions_const_iterator& other) const; - 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_; } - }; - - /** - * Iterate over transitions represented as 'Trans' instances. - * @return Iterator over transitions. - */ - Transitions transitions() const { return { .begin_ = transitions_begin(), .end_ = transitions_end() }; } - 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(); } + class Transitions; + + /** + * Iterator over transitions represented as @c Transition instances. + */ + Transitions transitions() const; + /** * Iterate over @p epsilon symbol posts under the given @p state. * @param[in] state State from which epsilon transitions are checked. @@ -444,7 +440,69 @@ 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); -}; // struct Delta. +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. diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 802d7cada..d3bdab7c3 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -224,27 +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 static_cast(std::distance(delta.transitions_begin(), - delta.transitions_end())); } - - /** - * Get transitions as a sequence of @c Trans. - * @return Sequence of transitions as @c Trans. - */ - 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. @@ -311,33 +290,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/delta.cc b/src/nfa/delta.cc index 85318d008..5bac5b16c 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; -} - void Delta::add(State source, Symbol symbol, State target) { const State max_state{ std::max(source, target) }; if (max_state >= state_posts_.size()) { @@ -178,101 +170,112 @@ 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 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::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 (!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; } } - // no transition found, an empty post + // No transition found, delta contains only empty state posts. is_end_ = true; } -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_; -}; +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) }; + 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; + } + } -Delta::transitions_const_iterator& Delta::transitions_const_iterator::operator++() { - assert(post_.begin() != post_.end()); + // No transition found, delta from the current state contains only empty state posts. + is_end_ = true; +} - ++targets_position_; - if (targets_position_ != post_iterator_->targets.end()) { - transition_.target = *targets_position_; +Delta::Transitions::const_iterator& Delta::Transitions::const_iterator::operator++() { + assert(delta_->begin() != delta_->end()); + + ++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; } -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; } -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 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_; } } @@ -340,82 +343,172 @@ 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; - 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; } - ++symbol_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 std::vector& 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 }, - 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; - move_.target = *target_states_it_; - return; - } - } - // No move found. We are at the end of moves. +StatePost::Moves::const_iterator::const_iterator( + const StatePost& state_post, const StatePost::const_iterator symbol_post_it, + 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; + } + + 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++() { - assert(symbol_posts_.begin() != symbol_posts_.end()); +StatePost::Moves::const_iterator::const_iterator(const StatePost& state_post) + : 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; + } - ++target_states_it_; - if (target_states_it_ != symbol_post_it_->targets.end()) { - move_.target = *target_states_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++() { + ++target_it_; + if (target_it_ != symbol_post_it_->targets.end()) { + move_.target = *target_it_; return *this; } + // Iterate over to the next symbol post, which can be either an end iterator, or symbol post whose + // symbol <= symbol_post_end_. ++symbol_post_it_; - if (symbol_post_it_ != symbol_posts_.cend()) { - target_states_it_ = symbol_post_it_->targets.begin(); - move_.symbol = symbol_post_it_->symbol; - move_.target = *target_states_it_; + if (symbol_post_it_ == symbol_post_end_) { + is_end_ = true; return *this; } - - is_end_ = true; + // 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_; 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& 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_; - 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 symbol_post_it_ == other.symbol_post_it_ && target_states_it_ == other.target_states_it_; } + return symbol_post_it_ == other.symbol_post_it_ && target_it_ == other.target_it_ + && symbol_post_end_ == other.symbol_post_end_; } + +size_t StatePost::num_of_moves() const { + size_t counter{ 0 }; + for (const SymbolPost& symbol_post: *this) { + counter += symbol_post.size(); + } + return counter; +} + +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_end_ = std::move(other.symbol_post_end_); + } + return *this; +} + +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_end_ = other.symbol_post_end_; + } + return *this; +} + +StatePost::Moves StatePost::moves( + 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 { + 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 { + const StatePost::const_iterator symbol_post_end{ cend() }; + const StatePost::const_iterator symbol_post_begin{ cbegin() }; + 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; + } + // 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 { + return { *state_post_, symbol_post_it_, symbol_post_end_ }; +} + +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::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/src/nfa/nfa.cc b/src/nfa/nfa.cc index 82ae4a0b2..e1c24b5c0 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -394,44 +394,11 @@ 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; } } -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; -} - -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. @@ -477,107 +444,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 { @@ -787,12 +653,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/src/nfa/operations.cc b/src/nfa/operations.cc index 080c99cb9..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 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/src/strings/nfa-noodlification.cc b/src/strings/nfa-noodlification.cc index 8a174e5b9..e24116ab0 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/delta.cc b/tests/nfa/delta.cc index db56e91ab..8b55b9a40 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); @@ -73,11 +73,11 @@ 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); } } -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); @@ -147,9 +147,18 @@ 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.moves_epsilons() }; + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); 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); @@ -161,6 +170,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.moves_epsilons(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(2); moves = state_post.moves(); @@ -175,6 +186,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.moves_epsilons(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(3); moves = state_post.moves(); @@ -183,11 +196,14 @@ 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(); for (const Move& move: state_post.moves()) { iterated_moves.push_back(move); } CHECK(iterated_moves.empty()); + epsilon_moves = state_post.moves_epsilons(); + CHECK(std::vector{ epsilon_moves.begin(), epsilon_moves.end() }.empty()); state_post = nfa.delta.state_post(4); moves = state_post.moves(); @@ -201,14 +217,85 @@ 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.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.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.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.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.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.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()); + state_post = nfa.delta.state_post(4); + 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.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 } }); + 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 } }); + 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 } }); + 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()); } } -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") { + Delta::Transitions transitions{ nfa.delta.transitions() }; + 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") { nfa.initial.insert(0); nfa.final.insert(3); @@ -219,7 +306,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) { @@ -236,5 +323,115 @@ 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") { + 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'); + 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 != transitions.begin() && it != transitions.end())); + CHECK(jt == transitions.begin()); + + ++jt; + CHECK(it == jt); + CHECK((jt != transitions.begin() && jt != transitions.end())); + + jt = transitions.end(); + CHECK(it != jt); + CHECK((jt != transitions.begin() && jt == transitions.end())); + + it = transitions.end(); + CHECK(it == jt); + CHECK((it != transitions.begin() && it == transitions.end())); + } +} + +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.num_of_transitions() == 2); + CHECK(copied_nfa.delta.num_of_transitions() == 1); +} + +TEST_CASE("mata::nfa::StatePost::Moves") { + 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); + // 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 } }); + 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==()") { + 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); } 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 5737d99f5..0e096e2b8 100644 --- a/tests/nfa/nfa-intersection.cc +++ b/tests/nfa/nfa-intersection.cc @@ -243,48 +243,48 @@ 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.get_trans_from_as_sequence(prod_map[{ 0, 0 }]).size() == 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.get_trans_from_as_sequence(prod_map[{ 1, 0 }]).size() == 3); + CHECK(result.delta.state_post(prod_map[{ 1, 0 }]).num_of_moves() == 3); - CHECK(result.get_trans_from_as_sequence(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.get_trans_from_as_sequence(prod_map[{ 1, 2 }]).size() == 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.get_trans_from_as_sequence(prod_map[{ 1, 3 }]).size() == 1); + CHECK(result.delta.state_post(prod_map[{ 1, 3 }]).num_of_moves() == 1); - CHECK(result.get_trans_from_as_sequence(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.get_trans_from_as_sequence(prod_map[{ 2, 5 }]).size() == 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.get_trans_from_as_sequence(prod_map[{ 3, 5 }]).size() == 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.get_trans_from_as_sequence(prod_map[{ 2, 6 }]).size() == 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.get_trans_from_as_sequence(prod_map[{ 3, 6 }]).size() == 1); + CHECK(result.delta.state_post(prod_map[{ 3, 6 }]).num_of_moves() == 1); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 4, 7 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 4, 7 }]).empty()); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 5, 9 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 5, 9 }]).empty()); - CHECK(result.get_trans_from_as_sequence(prod_map[{ 5, 8 }]).empty()); + CHECK(result.delta.state_post(prod_map[{ 5, 8 }]).empty()); } TEST_CASE("mata::nfa::intersection() for profiling", "[.profiling],[intersection]") diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index c1f1c8f24..0ebd7124c 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -7,6 +7,7 @@ #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" @@ -14,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; @@ -68,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()") @@ -123,7 +125,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 (auto 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; } @@ -164,45 +168,6 @@ 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()") { // {{{ Nfa aut(14); @@ -510,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); @@ -519,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"}}); @@ -530,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"}}); @@ -542,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"} }; @@ -560,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"}); @@ -608,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), @@ -617,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), @@ -812,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")]); @@ -844,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()); } @@ -961,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") @@ -973,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") @@ -1004,13 +969,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"]}, {}})); 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*") @@ -1036,7 +1001,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") @@ -1045,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") @@ -1057,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") @@ -1606,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*)") @@ -1713,7 +1678,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") @@ -1754,7 +1719,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)); @@ -1779,7 +1744,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)); @@ -2124,9 +2089,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])); @@ -2140,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)); } } @@ -2249,7 +2214,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()") @@ -2283,7 +2249,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()") @@ -2295,7 +2261,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)); @@ -2504,7 +2470,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); @@ -2837,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})); } 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 }}} 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); } }