diff --git a/bindings/python/libmata/nfa/nfa.pxd b/bindings/python/libmata/nfa/nfa.pxd index 292725333..927f2a937 100644 --- a/bindings/python/libmata/nfa/nfa.pxd +++ b/bindings/python/libmata/nfa/nfa.pxd @@ -33,7 +33,6 @@ cdef extern from "mata/nfa/nfa.hh" namespace "Mata::Nfa": ctypedef umap[Symbol, StateSet] PostSymb ctypedef umap[State, PostSymb] StateToPostMap ctypedef umap[string, State] StringSubsetMap - ctypedef umap[string, State] StateNameMap ctypedef umap[State, string] StateNameMap ctypedef umap[State, State] StateRenaming ctypedef umap[string, string] ParameterMap @@ -69,6 +68,8 @@ cdef extern from "mata/nfa/nfa.hh" namespace "Mata::Nfa": void remove(CTrans) except + void remove(State, Symbol, State) except + 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) cdef cppclass CRun "Mata::Nfa::Run": # Public Attributes @@ -155,15 +156,13 @@ cdef extern from "mata/nfa/nfa.hh" namespace "Mata::Nfa": vector[CTrans] get_transitions_to(State) vector[CTrans] get_trans_as_sequence() vector[CTrans] get_trans_from_as_sequence(State) - void trim(StateRenaming*) + CNfa& trim(StateRenaming*) void get_one_letter_aut(CNfa&) bool is_epsilon(Symbol) CBoolVector get_useful_states() StateSet get_reachable_states() StateSet get_terminating_states() void remove_epsilon(Symbol) except + - COrdVector[CSymbolPost].const_iterator get_epsilon_transitions(State state, Symbol epsilon) - COrdVector[CSymbolPost].const_iterator get_epsilon_transitions(CStatePost& post, Symbol epsilon) void clear() size_t size() @@ -200,7 +199,7 @@ cdef extern from "mata/nfa/plumbing.hh" namespace "Mata::Nfa::Plumbing": cdef void c_revert "Mata::Nfa::Plumbing::revert" (CNfa*, CNfa&) cdef void c_remove_epsilon "Mata::Nfa::Plumbing::remove_epsilon" (CNfa*, CNfa&, Symbol) except + cdef void c_minimize "Mata::Nfa::Plumbing::minimize" (CNfa*, CNfa&) - cdef void c_reduce "Mata::Nfa::Plumbing::reduce" (CNfa*, CNfa&, bool, StateRenaming*, ParameterMap&) + cdef void c_reduce "Mata::Nfa::Plumbing::reduce" (CNfa*, CNfa&, StateRenaming*, ParameterMap&) diff --git a/bindings/python/libmata/nfa/nfa.pyx b/bindings/python/libmata/nfa/nfa.pyx index c3fc7607d..348c7a97d 100644 --- a/bindings/python/libmata/nfa/nfa.pyx +++ b/bindings/python/libmata/nfa/nfa.pyx @@ -25,11 +25,14 @@ from libmata.nfa.nfa cimport \ from libmata.alphabets cimport CAlphabet from libmata.utils cimport COrdVector, CBinaryRelation, BinaryRelation + cdef Symbol EPSILON = CEPSILON + def epsilon(): return EPSILON + cdef class Run: """Wrapper over the run in NFA.""" cdef mata_nfa.CRun *thisptr @@ -492,8 +495,10 @@ cdef class Nfa: Remove states which are not accessible (unreachable; state is accessible when the state is the endpoint of a path starting from an initial state) or not co-accessible (non-terminating; state is co-accessible when the state is the starting point of a path ending in a final state). + :return: Self. """ self.thisptr.get().trim(NULL) + return self def trim_with_state_map(self): """Remove inaccessible (unreachable) and not co-accessible (non-terminating) states. @@ -502,11 +507,11 @@ cdef class Nfa: starting from an initial state) or not co-accessible (non-terminating; state is co-accessible when the state is the starting point of a path ending in a final state). - :return: State map of original to new states. + :return: Self, State map of original to new states. """ cdef StateRenaming state_map self.thisptr.get().trim(&state_map) - return {k: v for k, v in state_map} + return self, {k: v for k, v in state_map} def get_one_letter_aut(self) -> Nfa: """Unify transitions to create a directed graph with at most a single transition between two states (using only @@ -637,7 +642,6 @@ cdef class Nfa: return_value = self.thisptr.get().post(input_states, symbol).ToVector() return {v for v in return_value} - def remove_epsilon_inplace(self, Symbol epsilon = CEPSILON): """Removes transitions which contain epsilon symbol. @@ -647,20 +651,20 @@ cdef class Nfa: """ self.thisptr.get().remove_epsilon(epsilon) - def get_epsilon_transitions(self, State state, Symbol epsilon = CEPSILON) -> SymbolPost | None: + def epsilon_symbol_posts(self, State state, Symbol epsilon = CEPSILON) -> SymbolPost | None: """Get epsilon transitions for a state. :param state: State to get epsilon transitions for. :param epsilon: Epsilon symbol. :return: Epsilon transitions if there are any epsilon transitions for the passed state. None otherwise. """ - cdef COrdVector[CSymbolPost].const_iterator c_epsilon_transitions_iter = self.thisptr.get().get_epsilon_transitions( + cdef COrdVector[CSymbolPost].const_iterator c_epsilon_symbol_posts_iter = self.thisptr.get().delta.epsilon_symbol_posts( state, epsilon ) - if c_epsilon_transitions_iter == self.thisptr.get().delta.state_post(state).cend(): + if c_epsilon_symbol_posts_iter == self.thisptr.get().delta.state_post(state).cend(): return None - cdef CSymbolPost epsilon_transitions = dereference(c_epsilon_transitions_iter) + cdef CSymbolPost epsilon_transitions = dereference(c_epsilon_symbol_posts_iter) return SymbolPost(epsilon_transitions.symbol, epsilon_transitions.targets.ToVector()) @@ -861,11 +865,10 @@ def minimize(Nfa lhs): mata_nfa.c_minimize(result.thisptr.get(), dereference(lhs.thisptr.get())) return result -def reduce_with_state_map(Nfa aut, bool trim_input = True, params = None): +def reduce_with_state_map(Nfa aut, params = None): """Reduce the automaton. :param Nfa aut: Original automaton to reduce. - :param bool trim_input: Whether to trim the input automaton first or not. :param Dict params: Additional parameters for the reduction algorithm: - "algorithm": "simulation" :return: (Reduced automaton, state map of original to new states) @@ -873,7 +876,7 @@ def reduce_with_state_map(Nfa aut, bool trim_input = True, params = None): params = params or {"algorithm": "simulation"} cdef StateRenaming state_map result = Nfa() - mata_nfa.c_reduce(result.thisptr.get(), dereference(aut.thisptr.get()), trim_input, &state_map, + mata_nfa.c_reduce(result.thisptr.get(), dereference(aut.thisptr.get()), &state_map, { k.encode('utf-8'): v.encode('utf-8') for k, v in params.items() } @@ -881,10 +884,9 @@ def reduce_with_state_map(Nfa aut, bool trim_input = True, params = None): return result, {k: v for k, v in state_map} -def reduce(Nfa aut, bool trim_input = True, params = None): +def reduce(Nfa aut, params = None): """Reduce the automaton. - :param bool trim_input: Whether to trim the input automaton first or not. :param Nfa aut: Original automaton to reduce. :param Dict params: Additional parameters for the reduction algorithm: - "algorithm": "simulation" @@ -892,7 +894,7 @@ def reduce(Nfa aut, bool trim_input = True, params = None): """ params = params or {"algorithm": "simulation"} result = Nfa() - mata_nfa.c_reduce(result.thisptr.get(), dereference(aut.thisptr.get()), trim_input, NULL, + mata_nfa.c_reduce(result.thisptr.get(), dereference(aut.thisptr.get()), NULL, { k.encode('utf-8'): v.encode('utf-8') for k, v in params.items() } diff --git a/bindings/python/libmata/nfa/strings.pxd b/bindings/python/libmata/nfa/strings.pxd index 325981cdc..cc2458567 100644 --- a/bindings/python/libmata/nfa/strings.pxd +++ b/bindings/python/libmata/nfa/strings.pxd @@ -25,8 +25,6 @@ cdef extern from "mata/nfa/strings.hh" namespace "Mata::Strings::SegNfa": EpsilonDepthTransitions get_epsilon_depths() vector[CNfa] get_segments() - ctypedef vector[vector[shared_ptr[CNfa]]] NoodleSequence - - cdef NoodleSequence c_noodlify "Mata::Strings::SegNfa::noodlify" (CNfa&, Symbol, bool) - cdef NoodleSequence c_noodlify_for_equation "Mata::Strings::SegNfa::noodlify_for_equation" \ + cdef vector[vector[shared_ptr[CNfa]]] c_noodlify "Mata::Strings::SegNfa::noodlify" (CNfa&, Symbol, bool) + cdef vector[vector[shared_ptr[CNfa]]] c_noodlify_for_equation "Mata::Strings::SegNfa::noodlify_for_equation" \ (const vector[CNfa*]&, CNfa&, bool, ParameterMap&) diff --git a/bindings/python/libmata/nfa/strings.pyx b/bindings/python/libmata/nfa/strings.pyx index 80ce8ab96..895b6bfea 100644 --- a/bindings/python/libmata/nfa/strings.pyx +++ b/bindings/python/libmata/nfa/strings.pyx @@ -3,7 +3,7 @@ cimport libmata.nfa.strings as mata_strings from cython.operator import dereference, postincrement as postinc -from libmata.nfa.strings cimport NoodleSequence, CSegmentation +from libmata.nfa.strings cimport CSegmentation from libmata.nfa.nfa cimport CTrans cdef class Segmentation: @@ -69,7 +69,7 @@ def noodlify(mata_nfa.Nfa aut, Symbol symbol, include_empty = False): :return: List of automata: A list of all (non-empty) noodles. """ noodle_segments = [] - cdef NoodleSequence c_noodle_segments = mata_strings.c_noodlify( + cdef vector[vector[shared_ptr[CNfa]]] c_noodle_segments = mata_strings.c_noodlify( dereference(aut.thisptr.get()), symbol, include_empty ) for c_noodle in c_noodle_segments: @@ -121,7 +121,7 @@ def noodlify_for_equation(left_side_automata: list, mata_nfa.Nfa right_side_auto c_left_side_automata.push_back((lhs_aut).thisptr.get()) noodle_segments = [] params = params or {} - cdef NoodleSequence c_noodle_segments = mata_strings.c_noodlify_for_equation( + cdef vector[vector[shared_ptr[CNfa]]] c_noodle_segments = mata_strings.c_noodlify_for_equation( c_left_side_automata, dereference(right_side_automaton.thisptr.get()), include_empty, { k.encode('utf-8'): v.encode('utf-8') if isinstance(v, str) else v diff --git a/bindings/python/tests/test_nfa.py b/bindings/python/tests/test_nfa.py index 181b6697c..d9c367df8 100644 --- a/bindings/python/tests/test_nfa.py +++ b/bindings/python/tests/test_nfa.py @@ -895,7 +895,7 @@ def test_reduce(): nfa = mata_nfa.Nfa() # Test the reduction of an empty automaton. - result, state_map = mata_nfa.reduce_with_state_map(nfa, False) + result, state_map = mata_nfa.reduce_with_state_map(nfa) assert result.get_num_of_trans() == 0 assert len(result.initial_states) == 0 assert len(result.final_states) == 0 @@ -904,7 +904,7 @@ def test_reduce(): nfa.add_state(2) nfa.make_initial_state(1) nfa.make_final_state(2) - result, state_map = mata_nfa.reduce_with_state_map(nfa, False) + result, state_map = mata_nfa.reduce_with_state_map(nfa) assert result.get_num_of_trans() == 0 assert result.size() == 2 assert result.has_initial_state(state_map[1]) @@ -912,7 +912,7 @@ def test_reduce(): assert state_map[1] == state_map[0] assert state_map[2] != state_map[0] - result, state_map = mata_nfa.reduce_with_state_map(nfa, True) + result, state_map = mata_nfa.reduce_with_state_map(nfa.trim()) assert result.get_num_of_trans() == 0 assert result.size() == 0 @@ -936,7 +936,7 @@ def test_reduce(): nfa.add_transition(9, ord('c'), 0) nfa.add_transition(0, ord('a'), 4) - result, state_map = mata_nfa.reduce_with_state_map(nfa, False) + result, state_map = mata_nfa.reduce_with_state_map(nfa) assert result.size() == 6 assert result.has_initial_state(state_map[1]) assert result.has_initial_state(state_map[2]) @@ -1032,7 +1032,7 @@ def test_unify(): assert nfa.has_transition(10, 1, 2) -def test_get_epsilon_transitions(): +def test_epsilon_symbol_posts(): nfa = mata_nfa.Nfa(10) nfa.make_initial_state(0) nfa.make_final_state(1) @@ -1041,19 +1041,19 @@ def test_get_epsilon_transitions(): nfa.add_transition(1, 2, 2) nfa.add_transition(1, mata_nfa.epsilon(), 2) nfa.add_transition(1, mata_nfa.epsilon(), 3) - epsilon_transitions = nfa.get_epsilon_transitions(1) - assert epsilon_transitions.symbol == mata_nfa.epsilon() - assert epsilon_transitions.targets == [2, 3] + epsilon_symbol_posts = nfa.epsilon_symbol_posts(1) + assert epsilon_symbol_posts.symbol == mata_nfa.epsilon() + assert epsilon_symbol_posts.targets == [2, 3] nfa.add_transition(0, 1, 2) nfa.add_transition(0, 2, 2) nfa.add_transition(0, 8, 5) nfa.add_transition(0, 8, 6) - epsilon_transitions = nfa.get_epsilon_transitions(0, 8) - assert epsilon_transitions.symbol == 8 - assert epsilon_transitions.targets == [5, 6] + epsilon_symbol_posts = nfa.epsilon_symbol_posts(0, 8) + assert epsilon_symbol_posts.symbol == 8 + assert epsilon_symbol_posts.targets == [5, 6] - assert nfa.get_epsilon_transitions(5) is None + assert nfa.epsilon_symbol_posts(5) is None def test_is_epsilon(): diff --git a/include/mata/alphabet.hh b/include/mata/alphabet.hh index a85ae31b3..9027ad530 100644 --- a/include/mata/alphabet.hh +++ b/include/mata/alphabet.hh @@ -26,6 +26,8 @@ namespace Mata { using Symbol = unsigned; +using Word = std::vector; +using WordName = std::vector; /** * The abstract interface for NFA alphabets. @@ -38,8 +40,8 @@ public: /** * Translate sequence of symbol names to sequence of their respective values. */ - virtual std::vector translate_word(const std::vector& word) const { - (void)word; + virtual Word translate_word(const WordName& word_name) const { + (void)word_name; throw std::runtime_error("Unimplemented"); } @@ -180,9 +182,9 @@ public: EnumAlphabet(const EnumAlphabet& rhs) = default; EnumAlphabet(EnumAlphabet&& rhs) = default; - Util::OrdVector get_alphabet_symbols() const override { return m_symbols; } + Util::OrdVector get_alphabet_symbols() const override { return symbols_; } Util::OrdVector get_complement(const Util::OrdVector& symbols) const override { - return m_symbols.difference(symbols); + return symbols_.difference(symbols); } std::string reverse_translate_symbol(Symbol symbol) const override; @@ -197,14 +199,14 @@ public: * Adding a symbol name which already exists will throw an exception. * @param[in] symbols Vector of symbols to add. */ - void add_symbols_from(const Mata::Util::OrdVector& symbols) { m_symbols.insert(symbols); } + void add_symbols_from(const Mata::Util::OrdVector& symbols) { symbols_.insert(symbols); } /** * @brief Expand alphabet by symbols from the passed @p alphabet. * * @param[in] symbols_to_add Vector of symbols to add. */ - void add_symbols_from(const EnumAlphabet& alphabet) { m_symbols.insert(alphabet.get_alphabet_symbols()); } + void add_symbols_from(const EnumAlphabet& alphabet) { symbols_.insert(alphabet.get_alphabet_symbols()); } EnumAlphabet(std::initializer_list symbols) : EnumAlphabet(symbols.begin(), symbols.end()) {} template EnumAlphabet(InputIt first, InputIt last) : EnumAlphabet() { @@ -213,7 +215,7 @@ public: EnumAlphabet(std::initializer_list l) : EnumAlphabet(l.begin(), l.end()) {} Symbol translate_symb(const std::string& str) override; - std::vector translate_word(const std::vector& word) const override; + Word translate_word(const WordName& word_name) const override; /** * @brief Add new symbol to the alphabet with the value identical to its string representation. @@ -236,17 +238,17 @@ public: * Get the next value for a potential new symbol. * @return Next Symbol value. */ - Symbol get_next_value() const { return next_symbol_value; } + Symbol get_next_value() const { return next_symbol_value_; } /** * Get the number of existing symbols, epsilon symbols excluded. * @return The number of symbols. */ - size_t get_number_of_symbols() const { return m_symbols.size(); } + size_t get_number_of_symbols() const { return symbols_.size(); } private: - Mata::Util::OrdVector m_symbols{}; ///< Map of string transition symbols to symbol values. - Symbol next_symbol_value{ 0 }; ///< Next value to be used for a newly added symbol. + Mata::Util::OrdVector symbols_{}; ///< Map of string transition symbols to symbol values. + Symbol next_symbol_value_{ 0 }; ///< Next value to be used for a newly added symbol. public: /** @@ -270,9 +272,9 @@ public: /// Result of the insertion of a new symbol. using InsertionResult = std::pair; - explicit OnTheFlyAlphabet(Symbol init_symbol = 0) : next_symbol_value(init_symbol) {}; - OnTheFlyAlphabet(const OnTheFlyAlphabet& rhs) : symbol_map(rhs.symbol_map), next_symbol_value(rhs.next_symbol_value) {} - explicit OnTheFlyAlphabet(StringToSymbolMap str_sym_map) : symbol_map(std::move(str_sym_map)) {} + explicit OnTheFlyAlphabet(Symbol init_symbol = 0) : next_symbol_value_(init_symbol) {}; + OnTheFlyAlphabet(const OnTheFlyAlphabet& rhs) : symbol_map_(rhs.symbol_map_), next_symbol_value_(rhs.next_symbol_value_) {} + explicit OnTheFlyAlphabet(StringToSymbolMap str_sym_map) : symbol_map_(std::move(str_sym_map)) {} /** * Create alphabet from a list of symbol names. @@ -280,14 +282,14 @@ public: * @param init_symbol Start of a sequence of values to use for new symbols. */ explicit OnTheFlyAlphabet(const std::vector& symbol_names, Symbol init_symbol = 0) - : symbol_map(), next_symbol_value(init_symbol) { add_symbols_from(symbol_names); } + : symbol_map_(), next_symbol_value_(init_symbol) { add_symbols_from(symbol_names); } template OnTheFlyAlphabet(InputIt first, InputIt last) { for (; first != last; ++first) { - add_new_symbol(*first, next_symbol_value); + add_new_symbol(*first, next_symbol_value_); } } - OnTheFlyAlphabet(std::initializer_list> name_symbol_map) : symbol_map{} { + OnTheFlyAlphabet(std::initializer_list> name_symbol_map) : symbol_map_{} { for (auto&& [name, symbol]: name_symbol_map) { add_new_symbol(name, symbol); } @@ -320,7 +322,7 @@ public: Symbol translate_symb(const std::string& str) override; - virtual std::vector translate_word(const std::vector& word) const override; + virtual Word translate_word(const WordName& word_name) const override; /** * @brief Add new symbol to the alphabet with the value of @c next_symbol_value. @@ -352,29 +354,29 @@ public: * @param[in] value Number of the symbol to be used on transitions. * @return Result of the insertion as @c InsertionResult. */ - InsertionResult try_add_new_symbol(const std::string& key, Symbol value) { return symbol_map.insert({ key, value}); } + InsertionResult try_add_new_symbol(const std::string& key, Symbol value) { return symbol_map_.insert({ key, value}); } /** * Get the next value for a potential new symbol. * @return Next Symbol value. */ - Symbol get_next_value() const { return next_symbol_value; } + Symbol get_next_value() const { return next_symbol_value_; } /** * Get the number of existing symbols, epsilon symbols excluded. * @return The number of symbols. */ - size_t get_number_of_symbols() const { return next_symbol_value; } + size_t get_number_of_symbols() const { return next_symbol_value_; } /** * Get the symbol map used in the alphabet. * @return Map mapping strings to symbols used internally in Mata. */ - const StringToSymbolMap& get_symbol_map() const { return symbol_map; } + const StringToSymbolMap& get_symbol_map() const { return symbol_map_; } private: - StringToSymbolMap symbol_map{}; ///< Map of string transition symbols to symbol values. - Symbol next_symbol_value{}; ///< Next value to be used for a newly added symbol. + StringToSymbolMap symbol_map_{}; ///< Map of string transition symbols to symbol values. + Symbol next_symbol_value_{}; ///< Next value to be used for a newly added symbol. public: /** diff --git a/include/mata/nfa/delta.hh b/include/mata/nfa/delta.hh index a708b944a..3ef403141 100644 --- a/include/mata/nfa/delta.hh +++ b/include/mata/nfa/delta.hh @@ -196,16 +196,16 @@ public: */ class Delta { private: - std::vector state_posts; + 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_() {} + explicit Delta(size_t n) : state_posts_(n) {} void reserve(size_t n) { - state_posts.reserve(n); + state_posts_.reserve(n); }; /** @@ -226,7 +226,7 @@ public: if (src_state >= num_of_states()) { return empty_state_post; } - return state_posts[src_state]; + return state_posts_[src_state]; } /** @@ -261,19 +261,19 @@ public: void defragment(const BoolVector& is_staying, const std::vector& renaming); - void emplace_back() { state_posts.emplace_back(); } + void emplace_back() { state_posts_.emplace_back(); } - void clear() { state_posts.clear(); } + void clear() { state_posts_.clear(); } void increase_size(size_t n) { - assert(n >= state_posts.size()); - state_posts.resize(n); + assert(n >= state_posts_.size()); + state_posts_.resize(n); } /** * @return Number of states in the whole Delta, including both source and target states. */ - size_t num_of_states() const { return state_posts.size(); } + size_t num_of_states() const { return state_posts_.size(); } void add(State state_from, Symbol symbol, State state_to); void add(const Transition& trans) { add(trans.source, trans.symbol, trans.target); } @@ -302,7 +302,7 @@ public: */ void append(const std::vector& post_vector) { for(const StatePost& pst : post_vector) { - this->state_posts.push_back(pst); + this->state_posts_.push_back(pst); } } @@ -311,12 +311,12 @@ public: * targets. * * IMPORTANT: In order to work properly, the lambda function needs to be - * monotonic. + * monotonic, that is, the order of states in targets cannot change. * - * @param lambda Monotonic lambda function mapping states to different states + * @param target_renumberer Monotonic lambda function mapping states to different states. * @return std::vector Copied posts. */ - std::vector transform(const std::function& lambda) const; + std::vector renumber_targets(const std::function& target_renumberer) const; /** * @brief Add transitions to multiple destinations @@ -332,12 +332,12 @@ public: */ 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{}; + 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; @@ -353,7 +353,7 @@ public: transitions_const_iterator(const transitions_const_iterator& other) = default; - const Transition& operator*() const { return transition; } + const Transition& operator*() const { return transition_; } // Prefix increment transitions_const_iterator& operator++(); @@ -364,10 +364,10 @@ public: 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_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(); } @@ -385,10 +385,26 @@ public: 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(); } + 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(); } + + /** + * Iterate over @p epsilon symbol posts under the given @p state. + * @param[in] state State from which epsilon transitions are checked. + * @param[in] epsilon User can define his favourite epsilon or used default. + * @return An iterator to @c SymbolPost with epsilon symbol. End iterator when there are no epsilon transitions. + */ + StatePost::const_iterator epsilon_symbol_posts(State state, Symbol epsilon = EPSILON) const; + + /** + * Iterate over @p epsilon symbol posts under the given @p state_post. + * @param[in] state_post State post from which epsilon transitions are checked. + * @param[in] epsilon User can define his favourite epsilon or used default. + * @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. } // namespace Mata::Nfa. diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 529d52c1a..06c5eeb79 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -194,15 +194,6 @@ public: */ StateSet get_terminating_states() const; - /** - * @brief Get a set of useful states. - * - * Useful states are reachable and terminating states. - * @return Set of useful states. - * TODO: with the new get_useful_states, we can delete this probably. - */ - StateSet get_useful_states_old() const; - /** * @brief Get the useful states using a modified Tarjan's algorithm. A state * is useful if it is reachable from an initial state and can reach a final state. @@ -212,30 +203,16 @@ public: BoolVector get_useful_states() const; /** - * @brief Remove inaccessible (unreachable) and not co-accessible (non-terminating) states. + * @brief Remove inaccessible (unreachable) and not co-accessible (non-terminating) states in-place. * * Remove states which are not accessible (unreachable; state is accessible when the state is the endpoint of a path * starting from an initial state) or not co-accessible (non-terminating; state is co-accessible when the state is * the starting point of a path ending in a final state). * * @param[out] state_renaming Mapping of trimmed states to new states. - * TODO: we can probably keep just trim_reverting, much faster. But the speed difference and how it is achieved is interesting. Keeping as a demonstration for now. + * @return @c this after trimming. */ - void trim_inplace(StateRenaming* state_renaming = nullptr); - void trim_reverting(StateRenaming* state_renaming = nullptr); - void trim(StateRenaming* state_renaming = nullptr) { trim_inplace(state_renaming); } - - /** - * @brief Remove inaccessible (unreachable) and not co-accessible (non-terminating) states. - * - * Remove states which are not accessible (unreachable; state is accessible when the state is the endpoint of a path - * starting from an initial state) or not co-accessible (non-terminating; state is co-accessible when the state is - * the starting point of a path ending in a final state). - * - * @param[out] state_renaming Mapping of trimmed states to new states. - * @return Trimmed automaton. - */ - Nfa get_trimmed_automaton(StateRenaming* state_renaming = nullptr) const; + Nfa& trim(StateRenaming* state_renaming = nullptr); /** * Remove epsilon transitions from the automaton. @@ -361,24 +338,6 @@ public: const_iterator begin() const { return const_iterator::for_begin(this); } const_iterator end() const { return const_iterator::for_end(this); } - /** - * Return all epsilon transitions from epsilon symbol under a given state. - * @param[in] state State from which are epsilon transitions checked - * @param[in] epsilon User can define his favourite epsilon or used default - * @return Returns reference element of transition list with epsilon transitions or end of transition list when - * there are no epsilon transitions. - */ - StatePost::const_iterator get_epsilon_transitions(State state, Symbol epsilon = EPSILON) const; - - /** - * Return all epsilon transitions from epsilon symbol under given state transitions. - * @param[in] post Post from which are epsilon transitions checked. - * @param[in] epsilon User can define his favourite epsilon or used default - * @return Returns reference element of transition list with epsilon transitions or end of transition list when - * there are no epsilon transitions. - */ - static StatePost::const_iterator get_epsilon_transitions(const StatePost& post, Symbol epsilon = EPSILON); - /** * @brief Expand alphabet by symbols from this automaton to given alphabet * @@ -587,16 +546,15 @@ Nfa minimize(const Nfa &aut, const ParameterMap& params = {{ "algorithm", "brzoz Nfa determinize(const Nfa& aut, std::unordered_map *subset_map = nullptr); /** - * Reduce the size of the automaton. + * @brief Reduce the size of the automaton. * * @param[in] aut Automaton to reduce. - * @param[in] trim_input Whether to trim the input automaton first or not. - * @param[out] state_renaming Mapping of trimmed states to new states. + * @param[out] state_renaming Mapping of original states to reduced states. * @param[in] params Optional parameters to control the reduction algorithm: * - "algorithm": "simulation". * @return Reduced automaton. */ -Nfa reduce(const Nfa &aut, bool trim_input = true, StateRenaming *state_renaming = nullptr, +Nfa reduce(const Nfa &aut, StateRenaming *state_renaming = nullptr, const ParameterMap& params = {{ "algorithm", "simulation" } }); /// Is the language of the automaton universal? diff --git a/include/mata/nfa/plumbing.hh b/include/mata/nfa/plumbing.hh index c77bb1f77..b4b54b01d 100644 --- a/include/mata/nfa/plumbing.hh +++ b/include/mata/nfa/plumbing.hh @@ -56,9 +56,9 @@ inline void determinize(Nfa* result, const Nfa& aut, std::unordered_map get_shortest_words_from(const StateSet& states) const; /** * Gets shortest words for the given @p state. * @param[in] state State to map shortest words for. * @return Set of shortest words. */ - WordSet get_shortest_words_for(State state) const; + std::set get_shortest_words_from(State state) const; private: using WordLength = int; ///< A length of a word. /// Pair binding the length of all words in the word set and word set with words of the given length. - using LengthWordsPair = std::pair; + using LengthWordsPair = std::pair>; /// Map mapping states to the shortest words accepted by the automaton from the mapped state. std::unordered_map shortest_words_map{}; std::set processed{}; ///< Set of already processed states. @@ -89,7 +89,7 @@ private: * @return Created default shortest words map element for the given @p state. */ LengthWordsPair map_default_shortest_words(const State state) { - return shortest_words_map.emplace(state, std::make_pair(-1, WordSet{})).first->second; + return shortest_words_map.emplace(state, std::make_pair(-1, std::set{})).first->second; } /** @@ -105,7 +105,7 @@ private: * Get shortest words (regarding their length) of the automaton using BFS. * @return Set of shortest words. */ -WordSet get_shortest_words(const Mata::Nfa::Nfa& nfa); +std::set get_shortest_words(const Mata::Nfa::Nfa& nfa); /** * @brief Get the lengths of all words in the automaton @p aut. The function returns a set of pairs where for each @@ -197,8 +197,8 @@ private: const SegNfa& automaton; EpsilonDepthTransitions epsilon_depth_transitions{}; ///< Epsilon depths. EpsilonDepthTransitionMap eps_depth_trans_map{}; /// Epsilon depths with mapping of states to epsilon transitions - std::vector segments{}; ///< Segments for @p automaton. - std::vector segments_raw{}; ///< Raw segments for @p automaton. + std::vector segments{}; ///< Segments for @p automaton. + std::vector segments_raw{}; ///< Raw segments for @p automaton. VisitedEpsMap visited_eps{}; /// number of visited eps for each state /** @@ -282,12 +282,11 @@ private: /// A noodle is represented as a sequence of segments (a copy of the segment automata) created as if there was exactly /// one ε-transition between each two consecutive segments. -using Noodle = std::vector>; -using NoodleSequence = std::vector; ///< A sequence of noodles. - +using Noodle = std::vector>; +/// Segment with a counter of visited epsilons. +using SegmentWithEpsilonsCounter = std::pair, VisitedEpsilonsCounterVector>; /// Noodles as segments enriched with EpsCntMap -using NoodleSubst = std::vector, VisitedEpsilonsCounterVector>>; -using NoodleSubstSequence = std::vector; +using NoodleWithEpsilonsCounter = std::vector; /** * @brief segs_one_initial_final @@ -315,7 +314,7 @@ void segs_one_initial_final(const std::vector& segments, bool in * @param[in] include_empty Whether to also include empty noodles. * @return A list of all (non-empty) noodles. */ -NoodleSequence noodlify(const SegNfa& aut, Symbol epsilon, bool include_empty = false); +std::vector noodlify(const SegNfa& aut, Symbol epsilon, bool include_empty = false); /** * @brief Create noodles from segment automaton @p aut. @@ -329,7 +328,7 @@ NoodleSequence noodlify(const SegNfa& aut, Symbol epsilon, bool include_empty = * @param[in] include_empty Whether to also include empty noodles. * @return A list of all (non-empty) noodles. */ -NoodleSubstSequence noodlify_mult_eps(const SegNfa& aut, const std::set& epsilons, bool include_empty = false); +std::vector noodlify_mult_eps(const SegNfa& aut, const std::set& epsilons, bool include_empty = false); /** * @brief Create noodles for left and right side of equation. @@ -351,7 +350,7 @@ NoodleSubstSequence noodlify_mult_eps(const SegNfa& aut, const std::set& * minimization before noodlification. * @return A list of all (non-empty) noodles. */ -NoodleSequence noodlify_for_equation(const std::vector>& lhs_automata, +std::vector noodlify_for_equation(const std::vector>& lhs_automata, const Mata::Nfa::Nfa& rhs_automaton, bool include_empty = false, const ParameterMap& params = {{ "reduce", "false"}}); @@ -375,8 +374,9 @@ NoodleSequence noodlify_for_equation(const std::vector& lhs_automata, const Mata::Nfa::Nfa& rhs_automaton, - bool include_empty = false, const ParameterMap& params = {{ "reduce", "false"}}); +std::vector noodlify_for_equation( + const std::vector& lhs_automata, const Mata::Nfa::Nfa& rhs_automaton, bool include_empty = false, + const ParameterMap& params = {{ "reduce", "false"}}); /** * @brief Create noodles for left and right side of equation (both sides are given as a sequence of automata). @@ -389,7 +389,7 @@ NoodleSequence noodlify_for_equation(const std::vector& lhs_aut * minimization before noodlification. * @return A list of all (non-empty) noodles together with the positions reached from the beginning of left/right side. */ -NoodleSubstSequence noodlify_for_equation( +std::vector noodlify_for_equation( const std::vector>& lhs_automata, const std::vector>& rhs_automata, bool include_empty = false, const ParameterMap& params = {{ "reduce", "false"}}); diff --git a/include/mata/nfa/types.hh b/include/mata/nfa/types.hh index 184a96425..6fd5f6a92 100644 --- a/include/mata/nfa/types.hh +++ b/include/mata/nfa/types.hh @@ -15,9 +15,8 @@ extern const std::string TYPE_NFA; using State = unsigned long; using StateSet = Mata::Util::OrdVector; -using WordSet = std::set>; struct Run { - std::vector word{}; ///< A finite-length word. + Word word{}; ///< A finite-length word. std::vector path{}; ///< A finite-length path through automaton. }; diff --git a/include/mata/utils/ord-vector.hh b/include/mata/utils/ord-vector.hh index 4bb1b2187..f6684358c 100644 --- a/include/mata/utils/ord-vector.hh +++ b/include/mata/utils/ord-vector.hh @@ -253,6 +253,11 @@ public: return it; } + /** + * Check whether @p key exists in the ordered vector. + */ + bool contains(const Key& key) { return find(key) != end(); } + /** * @brief Remove @p k from sorted vector. * diff --git a/include/mata/utils/sparse-set.hh b/include/mata/utils/sparse-set.hh index 4003218e2..685eadc25 100644 --- a/include/mata/utils/sparse-set.hh +++ b/include/mata/utils/sparse-set.hh @@ -188,6 +188,10 @@ concept Iterable = requires(T t) { return *this; } + // TODO: How do we want to define equality of sparse sets? The default one is member-wise, but maybe simply + // comparing contained elements should be enough? + bool operator==(const SparseSet&) const = default; + // Things // Tests the basic invariant of the sparse set. diff --git a/include/mata/utils/util.hh b/include/mata/utils/util.hh index 1ff2a5dd7..e74f8a3d3 100644 --- a/include/mata/utils/util.hh +++ b/include/mata/utils/util.hh @@ -77,6 +77,7 @@ public: BoolVector& operator=(const BoolVector&) = default; BoolVector& operator=(BoolVector&&) = default; + /// Count the number of set elements. size_t count() const { size_t cnt{ 0 }; for (const uint8_t value : *this) { @@ -107,7 +108,7 @@ public: return element_set; } -}; +}; // class BoolVector. /// log verbosity extern unsigned LOG_VERBOSITY; diff --git a/src/alphabet.cc b/src/alphabet.cc index c1ee769cc..090d8c408 100644 --- a/src/alphabet.cc +++ b/src/alphabet.cc @@ -20,7 +20,7 @@ using Mata::OnTheFlyAlphabet; Mata::Util::OrdVector OnTheFlyAlphabet::get_alphabet_symbols() const { Util::OrdVector result; - for (const auto& str_sym_pair : symbol_map) { + for (const auto& str_sym_pair: symbol_map_) { result.insert(str_sym_pair.second); } return result; @@ -28,8 +28,8 @@ Mata::Util::OrdVector OnTheFlyAlphabet::get_alphabet_symbols() const { Mata::Util::OrdVector OnTheFlyAlphabet::get_complement(const Mata::Util::OrdVector& symbols) const { Mata::Util::OrdVector symbols_alphabet{}; - symbols_alphabet.reserve(symbol_map.size()); - for (const auto& str_sym_pair : symbol_map) { + symbols_alphabet.reserve(symbol_map_.size()); + for (const auto& str_sym_pair : symbol_map_) { symbols_alphabet.insert(str_sym_pair.second); } return symbols_alphabet.difference(symbols); @@ -43,7 +43,7 @@ void OnTheFlyAlphabet::add_symbols_from(const StringToSymbolMap& new_symbol_map) } std::string Mata::OnTheFlyAlphabet::reverse_translate_symbol(const Symbol symbol) const { - for (const auto& symbol_mapping: symbol_map) { + for (const auto& symbol_mapping: symbol_map_) { if (symbol_mapping.second == symbol) { return symbol_mapping.first; } @@ -58,9 +58,9 @@ void Mata::OnTheFlyAlphabet::add_symbols_from(const std::vector& sy } Symbol Mata::OnTheFlyAlphabet::translate_symb(const std::string& str) { - const auto it_insert_pair = symbol_map.insert({str, next_symbol_value}); + const auto it_insert_pair = symbol_map_.insert({str, next_symbol_value_}); if (it_insert_pair.second) { - return next_symbol_value++; + return next_symbol_value_++; } else { return it_insert_pair.first->second; } @@ -76,26 +76,26 @@ Symbol Mata::OnTheFlyAlphabet::translate_symb(const std::string& str) { //return it->second; } -std::vector Mata::OnTheFlyAlphabet::translate_word(const std::vector& word) const { - const size_t word_size{ word.size() }; - std::vector symbols; - symbols.reserve(word_size); +Mata::Word Mata::OnTheFlyAlphabet::translate_word(const Mata::WordName& word_name) const { + const size_t word_size{ word_name.size() }; + Word word; + word.reserve(word_size); for (size_t i{ 0 }; i < word_size; ++i) { - const auto symbol_mapping_it = symbol_map.find(word[i]); - if (symbol_mapping_it == symbol_map.end()) { - throw std::runtime_error("Unknown symbol \'" + word[i] + "\'"); + const auto symbol_mapping_it = symbol_map_.find(word_name[i]); + if (symbol_mapping_it == symbol_map_.end()) { + throw std::runtime_error("Unknown symbol \'" + word_name[i] + "\'"); } - symbols.push_back(symbol_mapping_it->second); + word.push_back(symbol_mapping_it->second); } - return symbols; + return word; } OnTheFlyAlphabet::InsertionResult Mata::OnTheFlyAlphabet::add_new_symbol(const std::string& key) { - InsertionResult insertion_result{ try_add_new_symbol(key, next_symbol_value) }; + InsertionResult insertion_result{ try_add_new_symbol(key, next_symbol_value_) }; if (!insertion_result.second) { // If the insertion of key-value pair failed. throw std::runtime_error("multiple occurrences of the same symbol"); } - ++next_symbol_value; + ++next_symbol_value_; return insertion_result; } @@ -109,8 +109,8 @@ OnTheFlyAlphabet::InsertionResult Mata::OnTheFlyAlphabet::add_new_symbol(const s } void Mata::OnTheFlyAlphabet::update_next_symbol_value(Symbol value) { - if (next_symbol_value <= value) { - next_symbol_value = value + 1; + if (next_symbol_value_ <= value) { + next_symbol_value_ = value + 1; } } @@ -129,7 +129,7 @@ Symbol Mata::IntAlphabet::translate_symb(const std::string& symb) { } std::string Mata::EnumAlphabet::reverse_translate_symbol(const Symbol symbol) const { - if (m_symbols.find(symbol) == m_symbols.end()) { + if (symbols_.find(symbol) == symbols_.end()) { throw std::runtime_error("Symbol '" + std::to_string(symbol) + "' is out of range of enumeration."); } return std::to_string(symbol); @@ -142,28 +142,28 @@ Symbol Mata::EnumAlphabet::translate_symb(const std::string& str) { if (stream.fail() || !stream.eof()) { throw std::runtime_error("Cannot translate string '" + str + "' to symbol."); } - if (m_symbols.find(symbol) == m_symbols.end()) { + if (symbols_.find(symbol) == symbols_.end()) { throw std::runtime_error("Unknown symbol'" + str + "' to be translated to Symbol."); } return symbol; } -std::vector Mata::EnumAlphabet::translate_word(const std::vector& word) const { - const size_t word_size{ word.size() }; - std::vector translated_symbols; +Mata::Word Mata::EnumAlphabet::translate_word(const Mata::WordName& word_name) const { + const size_t word_size{ word_name.size() }; + Mata::Word word; Symbol symbol; std::stringstream stream; - translated_symbols.reserve(word_size); - for (const auto& str_symbol: word) { + word.reserve(word_size); + for (const auto& str_symbol: word_name) { stream << str_symbol; stream >> symbol; - if (m_symbols.find(symbol) == m_symbols.end()) { + if (symbols_.find(symbol) == symbols_.end()) { throw std::runtime_error("Unknown symbol \'" + str_symbol + "\'"); } - translated_symbols.push_back(symbol); + word.push_back(symbol); } - return translated_symbols; + return word; } void Mata::EnumAlphabet::add_new_symbol(const std::string& symbol) { @@ -174,12 +174,12 @@ void Mata::EnumAlphabet::add_new_symbol(const std::string& symbol) { } void Mata::EnumAlphabet::add_new_symbol(Symbol symbol) { - m_symbols.insert(symbol); + symbols_.insert(symbol); update_next_symbol_value(symbol); } void Mata::EnumAlphabet::update_next_symbol_value(Symbol value) { - if (next_symbol_value <= value) { - next_symbol_value = value + 1; + if (next_symbol_value_ <= value) { + next_symbol_value_ = value + 1; } } diff --git a/src/nfa/concatenation.cc b/src/nfa/concatenation.cc index 0aa920ac9..90d04b791 100644 --- a/src/nfa/concatenation.cc +++ b/src/nfa/concatenation.cc @@ -32,7 +32,7 @@ Nfa& Nfa::concatenate(const Nfa& aut) { return st + n; }; - this->delta.append(aut.delta.transform(upd_fnc)); + this->delta.append(aut.delta.renumber_targets(upd_fnc)); // set accepting states Util::SparseSet new_fin{}; diff --git a/src/nfa/delta.cc b/src/nfa/delta.cc index c0a89e6d8..9bb9b3bcb 100644 --- a/src/nfa/delta.cc +++ b/src/nfa/delta.cc @@ -45,99 +45,91 @@ void SymbolPost::insert(const StateSet& states) { } } -StatePost::const_iterator Nfa::Nfa::get_epsilon_transitions(const State state, const Symbol epsilon) const { - assert(is_state(state)); - return get_epsilon_transitions(delta.state_post(state), epsilon); +StatePost::const_iterator Delta::epsilon_symbol_posts(const State state, const Symbol epsilon) const { + return epsilon_symbol_posts(state_post(state), epsilon); } -StatePost::const_iterator Nfa::Nfa::get_epsilon_transitions(const StatePost& state_transitions, const Symbol epsilon) { - if (!state_transitions.empty()) { +StatePost::const_iterator Delta::epsilon_symbol_posts(const StatePost& state_post, const Symbol epsilon) { + if (!state_post.empty()) { if (epsilon == EPSILON) { - const auto& back = state_transitions.back(); - if (back.symbol == epsilon) { - return std::prev(state_transitions.end()); - } - } else { - return state_transitions.find(SymbolPost(epsilon)); - } + const auto& back = state_post.back(); + if (back.symbol == epsilon) { return std::prev(state_post.end()); } + } else { return state_post.find(SymbolPost(epsilon)); } } - - return state_transitions.end(); + return state_post.end(); } -size_t Delta::size() const -{ +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(); - + 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 state_from, Symbol symbol, State state_to) { - const State max_state{ std::max(state_from, state_to) }; - if (max_state >= state_posts.size()) { - reserve_on_insert(state_posts, max_state); - state_posts.resize(max_state + 1); +void Delta::add(State source, Symbol symbol, State target) { + const State max_state{ std::max(source, target) }; + if (max_state >= state_posts_.size()) { + reserve_on_insert(state_posts_, max_state); + state_posts_.resize(max_state + 1); } - StatePost& state_transitions{ state_posts[state_from] }; + StatePost& state_transitions{ state_posts_[source] }; if (state_transitions.empty()) { - state_transitions.insert({ symbol, state_to }); + state_transitions.insert({ symbol, target }); } else if (state_transitions.back().symbol < symbol) { - state_transitions.insert({ symbol, state_to }); + state_transitions.insert({ symbol, target }); } else { const auto symbol_transitions{ state_transitions.find(SymbolPost{ symbol }) }; if (symbol_transitions != state_transitions.end()) { // Add transition with symbol already used on transitions from state_from. - symbol_transitions->insert(state_to); + symbol_transitions->insert(target); } else { // Add transition to a new Move struct with symbol yet unused on transitions from state_from. - const SymbolPost new_symbol_transitions{ symbol, state_to }; + const SymbolPost new_symbol_transitions{ symbol, target }; state_transitions.insert(new_symbol_transitions); } } } -void Delta::add(const State state_from, const Symbol symbol, const StateSet& states) { - if(states.empty()) { +void Delta::add(const State source, const Symbol symbol, const StateSet& targets) { + if(targets.empty()) { return; } - const State max_state{ std::max(state_from, states.back()) }; - if (max_state >= state_posts.size()) { - reserve_on_insert(state_posts, max_state + 1); - state_posts.resize(max_state + 1); + const State max_state{ std::max(source, targets.back()) }; + if (max_state >= state_posts_.size()) { + reserve_on_insert(state_posts_, max_state + 1); + state_posts_.resize(max_state + 1); } - StatePost& state_transitions{ state_posts[state_from] }; + StatePost& state_transitions{ state_posts_[source] }; if (state_transitions.empty()) { - state_transitions.insert({ symbol, states }); + state_transitions.insert({ symbol, targets }); } else if (state_transitions.back().symbol < symbol) { - state_transitions.insert({ symbol, states }); + state_transitions.insert({ symbol, targets }); } else { const auto symbol_transitions{ state_transitions.find(symbol) }; if (symbol_transitions != state_transitions.end()) { // Add transition with symbolOnTransition already used on transitions from state_from. - symbol_transitions->insert(states); + symbol_transitions->insert(targets); } else { // Add transition to a new Move struct with symbol yet unused on transitions from state_from. // Move new_symbol_transitions{ symbol, states }; - state_transitions.insert(SymbolPost{ symbol, states}); + state_transitions.insert(SymbolPost{ symbol, targets}); } } } void Delta::remove(State src, Symbol symb, State tgt) { - if (src >= state_posts.size()) { + if (src >= state_posts_.size()) { return; } - StatePost& state_transitions{ state_posts[src] }; + StatePost& state_transitions{ state_posts_[src] }; if (state_transitions.empty()) { throw std::invalid_argument( "Transition [" + std::to_string(src) + ", " + std::to_string(symb) + ", " + @@ -155,7 +147,7 @@ void Delta::remove(State src, Symbol symb, State tgt) { } else { symbol_transitions->remove(tgt); if (symbol_transitions->empty()) { - state_posts[src].remove(*symbol_transitions); + state_posts_[src].remove(*symbol_transitions); } } } @@ -163,14 +155,14 @@ void Delta::remove(State src, Symbol symb, State tgt) { bool Delta::contains(State src, Symbol symb, State tgt) const { // {{{ - if (state_posts.empty()) { + if (state_posts_.empty()) { return false; } - if (state_posts.size() <= src) + if (state_posts_.size() <= src) return false; - const StatePost& tl = state_posts[src]; + const StatePost& tl = state_posts_[src]; if (tl.empty()) { return false; } @@ -192,64 +184,64 @@ bool Delta::empty() const } 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(); + : post_(post_p), current_state_(0), is_end_{ ise } { + const size_t post_size = post_.size(); for (size_t i = 0; i < post_size; ++i) { - if (!post[i].empty()) { - current_state = i; - post_iterator = post[i].begin(); - targets_position = post_iterator->targets.begin(); - transition.source = current_state; - transition.symbol = post_iterator->symbol; - transition.target = *targets_position; + if (!post_[i].empty()) { + current_state_ = i; + post_iterator_ = post_[i].begin(); + targets_position_ = post_iterator_->targets.begin(); + transition_.source = current_state_; + transition_.symbol = post_iterator_->symbol; + transition_.target = *targets_position_; return; } } // no transition found, an empty post - is_end = true; + 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; + : 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& Delta::transitions_const_iterator::operator++() { - assert(post.begin() != post.end()); + assert(post_.begin() != post_.end()); - ++targets_position; - if (targets_position != post_iterator->targets.end()) { - transition.target = *targets_position; + ++targets_position_; + if (targets_position_ != post_iterator_->targets.end()) { + transition_.target = *targets_position_; 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; + ++post_iterator_; + if (post_iterator_ != post_[current_state_].cend()) { + targets_position_ = post_iterator_->targets.begin(); + transition_.symbol = post_iterator_->symbol; + transition_.target = *targets_position_; return *this; } - ++current_state; - while (current_state < post.size() && post[current_state].empty()) // skip empty posts - current_state++; + ++current_state_; + while (current_state_ < post_.size() && post_[current_state_].empty()) // skip empty posts + current_state_++; - if (current_state >= post.size()) - is_end = true; + if (current_state_ >= post_.size()) + is_end_ = true; else { - post_iterator = post[current_state].begin(); - targets_position = post_iterator->targets.begin(); + post_iterator_ = post_[current_state_].begin(); + targets_position_ = post_iterator_->targets.begin(); } - transition.source = current_state; - transition.symbol = post_iterator->symbol; - transition.target = *targets_position; + transition_.source = current_state_; + transition_.symbol = post_iterator_->symbol; + transition_.target = *targets_position_; return *this; } @@ -263,54 +255,54 @@ const Delta::transitions_const_iterator Delta::transitions_const_iterator::opera 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; + 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 { - if (is_end && other.is_end) { + if (is_end_ && other.is_end_) { return true; - } else if ((is_end && !other.is_end) || (!is_end && other.is_end)) { + } 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_ && post_iterator_ == other.post_iterator_ + && targets_position_ == other.targets_position_; } } -std::vector Delta::transform(const std::function& lambda) const { - std::vector cp_post_vector; - cp_post_vector.reserve(num_of_states()); - for(const StatePost& act_post: this->state_posts) { - StatePost cp_post; - cp_post.reserve(act_post.size()); - for(const SymbolPost& mv : act_post) { - StateSet cp_dest; - cp_dest.reserve(mv.size()); - for(const State& state : mv.targets) { - cp_dest.push_back(std::move(lambda(state))); +std::vector Delta::renumber_targets(const std::function& target_renumberer) const { + std::vector copied_state_posts; + copied_state_posts.reserve(num_of_states()); + for(const StatePost& state_post: state_posts_) { + StatePost copied_state_post; + copied_state_post.reserve(state_post.size()); + for(const SymbolPost& symbol_post: state_post) { + StateSet copied_targets; + copied_targets.reserve(symbol_post.size()); + for(const State& state: symbol_post.targets) { + copied_targets.push_back(std::move(target_renumberer(state))); } - cp_post.push_back(std::move(SymbolPost(mv.symbol, cp_dest))); + copied_state_post.push_back(std::move(SymbolPost(symbol_post.symbol, copied_targets))); } - cp_post_vector.emplace_back(cp_post); + copied_state_posts.emplace_back(copied_state_post); } - return cp_post_vector; + return copied_state_posts; } StatePost& Delta::mutable_state_post(State q) { - if (q >= state_posts.size()) { - Util::reserve_on_insert(state_posts, q); + if (q >= state_posts_.size()) { + Util::reserve_on_insert(state_posts_, q); const size_t new_size{ q + 1 }; - state_posts.resize(new_size); + state_posts_.resize(new_size); } - return state_posts[q]; + return state_posts_[q]; } void Delta::defragment(const BoolVector& is_staying, const std::vector& renaming) { @@ -318,7 +310,7 @@ void Delta::defragment(const BoolVector& is_staying, const std::vector& r //first, indexes of post are filtered (places of to be removed states are taken by states on their right) size_t move_index{ 0 }; - std::erase_if(state_posts, + std::erase_if(state_posts_, [&](StatePost&) -> bool { size_t prev{ move_index }; ++move_index; @@ -328,7 +320,7 @@ void Delta::defragment(const BoolVector& is_staying, const std::vector& r //this iterates through every post and every move, filters and renames states, //and then removes moves that became empty. - for (State q=0,size=state_posts.size(); q < size; ++q) { + for (State q=0,size=state_posts_.size(); q < size; ++q) { StatePost & p = mutable_state_post(q); for (auto move = p.begin(); move < p.end(); ++move) { move->targets.erase( diff --git a/src/nfa/nfa.cc b/src/nfa/nfa.cc index 0f57102f7..968a27a4b 100644 --- a/src/nfa/nfa.cc +++ b/src/nfa/nfa.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -29,6 +30,7 @@ using namespace Mata::Util; using namespace Mata::Nfa; using Mata::Symbol; +using Mata::Word; using Mata::BoolVector; using StateBoolArray = std::vector; ///< Bool array for states in the automaton. @@ -41,55 +43,20 @@ const Symbol Limits::min_symbol; const Symbol Limits::max_symbol; namespace { - /** - * Compute reachability of states. - * - * @param[in] nfa NFA to compute reachability for. - * @return Bool array for reachable states (from initial states): true for reachable, false for unreachable states. - */ - StateBoolArray compute_reachability(const Nfa& nfa) { - std::vector worklist{ nfa.initial.begin(),nfa.initial.end() }; - - StateBoolArray reachable(nfa.size(), false); - for (const State state: nfa.initial) - { - reachable.at(state) = true; - } - - State state{}; - while (!worklist.empty()) - { - state = worklist.back(); - worklist.pop_back(); - - for (const SymbolPost& move: nfa.delta[state]) - { - for (const State target_state: move.targets) - { - if (!reachable.at(target_state)) - { - worklist.push_back(target_state); - reachable.at(target_state) = true; - } - } - } - } - - return reachable; - } - /** * Compute reachability of states considering only specified states. * * @param[in] nfa NFA to compute reachability for. - * @param[in] states_to_consider State to consider as potentially reachable. + * @param[in] states_to_consider State to consider as potentially reachable. If @c std::nullopt is used, all states + * are considered as potentially reachable. * @return Bool array for reachable states (from initial states): true for reachable, false for unreachable states. */ - StateBoolArray compute_reachability(const Nfa& nfa, const StateBoolArray& states_to_consider) { + StateBoolArray reachable_states(const Nfa& nfa, + const std::optional& states_to_consider = std::nullopt) { std::vector worklist{}; StateBoolArray reachable(nfa.size(), false); for (const State state: nfa.initial) { - if (states_to_consider[state]) { + if (!states_to_consider.has_value() || states_to_consider.value()[state]) { worklist.push_back(state); reachable.at(state) = true; } @@ -99,98 +66,18 @@ namespace { while (!worklist.empty()) { state = worklist.back(); worklist.pop_back(); - for (const SymbolPost& move: nfa.delta[state]) { for (const State target_state: move.targets) { - if (states_to_consider[target_state] && !reachable[target_state]) { + if (!reachable[target_state] && + (!states_to_consider.has_value() || states_to_consider.value()[target_state])) { worklist.push_back(target_state); reachable[target_state] = true; } } } } - return reachable; } - - /** - * Add transitions to the trimmed automaton. - * @param[in] nfa NFA to add transitions from. - * @param[in] state_renaming Map of old states to new trimmed automaton states. - * @param[out] trimmed_aut The new trimmed automaton. - */ - void add_trimmed_transitions(const Nfa& nfa, const StateRenaming& state_renaming, Nfa& trimmed_aut) { - // For each reachable original state 's' (which means it is mapped to the state of trimmed automaton)... - for (const auto& original_state_mapping: state_renaming) - { - // ...add all transitions from 's' to some reachable state to the trimmed automaton. - for (const auto& state_transitions_with_symbol: nfa.delta[original_state_mapping.first]) - { - SymbolPost new_state_trans_with_symbol(state_transitions_with_symbol.symbol); - for (State old_state_to: state_transitions_with_symbol.targets) - { - auto iter_to_new_state_to = state_renaming.find(old_state_to); - if (iter_to_new_state_to != state_renaming.end()) - { - // We can push here, because we assume that new states follow the ordering of original states. - new_state_trans_with_symbol.insert(iter_to_new_state_to->second); - } - } - if (!new_state_trans_with_symbol.empty()) { - trimmed_aut.delta.mutable_state_post(original_state_mapping.second).insert(new_state_trans_with_symbol); - } - } - } - } - - /** - * Get a new trimmed automaton. - * @param[in] nfa NFA to trim. - * @param[in] original_to_new_state_renaming Map of old states to new trimmed automaton states (new states should follow the ordering of old states). - * @return Newly created trimmed automaton. - */ - Nfa create_trimmed_aut(const Nfa& nfa, const StateRenaming& state_renaming) { - Nfa trimmed_aut{ state_renaming.size() }; - - for (const State old_initial_state: nfa.initial) - { - if (state_renaming.find(old_initial_state) != state_renaming.end()) - { - trimmed_aut.initial.insert(state_renaming.at(old_initial_state)); - } - } - for (const State old_final_state: nfa.final) - { - if (state_renaming.find(old_final_state) != state_renaming.end()) - { - trimmed_aut.final.insert(state_renaming.at(old_final_state)); - } - } - - add_trimmed_transitions(nfa, state_renaming, trimmed_aut); - return trimmed_aut; - } - - /** - * Get directed transitions for digraph. - * @param[in] nfa NFA to get directed transitions from. - * @param[in] abstract_symbol Abstract symbol to use for transitions in digraph. - * @param[out] digraph Digraph to add computed transitions to. - */ - void collect_directed_transitions(const Nfa& nfa, const Symbol abstract_symbol, Nfa& digraph) { - const State num_of_states{nfa.size() }; - for (State src_state{ 0 }; src_state < num_of_states; ++src_state) { - for (const SymbolPost& move: nfa.delta[src_state]) { - for (const State tgt_state: move.targets) { - // Directly try to add the transition. Finding out whether the transition is already in the digraph - // only iterates through transition relation again. - digraph.delta.add(src_state, abstract_symbol, tgt_state); - } - // FIXME: Alternatively: But it is actually slower... - //digraph.add(src_state, abstract_symbol, symbol_transitions.targets); - } - } - } } void Nfa::remove_epsilon(const Symbol epsilon) @@ -198,9 +85,8 @@ void Nfa::remove_epsilon(const Symbol epsilon) *this = Mata::Nfa::remove_epsilon(*this, epsilon); } -StateSet Nfa::get_reachable_states() const -{ - StateBoolArray reachable_bool_array{ compute_reachability(*this) }; +StateSet Nfa::get_reachable_states() const { + StateBoolArray reachable_bool_array{ reachable_states(*this) }; StateSet reachable_states{}; const size_t num_of_states{size() }; @@ -220,19 +106,7 @@ StateSet Nfa::get_terminating_states() const return revert(*this).get_reachable_states(); } -//TODO: probably can be removed, trim_inplace is faster. -void Nfa::trim_reverting(StateRenaming* state_renaming) -{ - if (!state_renaming) { - StateRenaming tmp_state_renaming{}; - *this = get_trimmed_automaton(&tmp_state_renaming); - } else { - state_renaming->clear(); - *this = get_trimmed_automaton(state_renaming); - } -} - -void Nfa::trim_inplace(StateRenaming* state_renaming) { +Nfa& Nfa::trim(StateRenaming* state_renaming) { #ifdef _STATIC_STRUCTURES_ BoolVector useful_states{ useful_states() }; useful_states.clear(); @@ -268,26 +142,7 @@ void Nfa::trim_inplace(StateRenaming* state_renaming) { } } } -} - -Nfa Nfa::get_trimmed_automaton(StateRenaming* state_renaming) const { - if (initial.empty() || final.empty()) { return Nfa{}; } - - StateRenaming tmp_state_renaming{}; - if (!state_renaming) { - state_renaming = &tmp_state_renaming; - } - state_renaming->clear(); - - const StateSet original_useful_states{get_useful_states_old() }; - state_renaming->reserve(original_useful_states.size()); - - size_t new_state_num{ 0 }; - for (const State original_state: original_useful_states) { - (*state_renaming)[original_state] = new_state_num; - ++new_state_num; - } - return create_trimmed_aut(*this, *state_renaming); + return *this; } namespace { @@ -475,30 +330,9 @@ BoolVector Nfa::get_useful_states() const { // all successors have been processed, we can remove act_state from the program stack program_stack.pop_back(); } - return useful; } -StateSet Nfa::get_useful_states_old() const -{ - if (initial.empty() || final.empty()) { return StateSet{}; } - - const Nfa digraph{get_one_letter_aut() }; // Compute reachability on directed graph. - // Compute reachability from the initial states and use the reachable states to compute the reachability from the final states. - const StateBoolArray useful_states_bool_array{ compute_reachability(revert(digraph), compute_reachability(digraph)) }; - - const size_t num_of_states{size() }; - StateSet useful_states{}; - for (State original_state{ 0 }; original_state < num_of_states; ++original_state) { - if (useful_states_bool_array[original_state]) { - // We can use push_back here, because we are always increasing the value of original_state (so useful_states - // will always be ordered). - useful_states.insert(original_state); - } - } - return useful_states; -} - std::string Nfa::print_to_DOT() const { std::stringstream output; print_to_DOT(output); @@ -600,7 +434,12 @@ std::vector Nfa::get_trans_from_as_sequence(State state_from) const Nfa Nfa::get_one_letter_aut(Symbol abstract_symbol) const { Nfa digraph{size(), StateSet(initial), StateSet(final) }; - collect_directed_transitions(*this, abstract_symbol, digraph); + // Add directed transitions for digraph. + for (const Transition& transition: delta.transitions()) { + // Directly try to add the transition. Finding out whether the transition is already in the digraph + // only iterates through transition relation again. + digraph.delta.add(transition.source, abstract_symbol, transition.target); + } return digraph; } diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index c48ac7357..18710b862 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -697,24 +697,18 @@ Simlib::Util::BinaryRelation Mata::Nfa::Algorithms::compute_relation(const Nfa& } } -Nfa Mata::Nfa::reduce(const Nfa &aut, bool trim_input, StateRenaming *state_renaming, const ParameterMap& params) { +Nfa Mata::Nfa::reduce(const Nfa &aut, StateRenaming *state_renaming, const ParameterMap& params) { if (!haskey(params, "algorithm")) { throw std::runtime_error(std::to_string(__func__) + " requires setting the \"algorithm\" key in the \"params\" argument; " "received: " + std::to_string(params)); } - Nfa aut_to_reduce{ aut }; - StateRenaming trimmed_state_renaming{}; - if (trim_input) { - aut_to_reduce.trim(&trimmed_state_renaming); - } - Nfa result; std::unordered_map reduced_state_map; const std::string& algorithm = params.at("algorithm"); if ("simulation" == algorithm) { - result = reduce_size_by_simulation(aut_to_reduce, reduced_state_map); + result = reduce_size_by_simulation(aut, reduced_state_map); } else { throw std::runtime_error(std::to_string(__func__) + " received an unknown value of the \"algorithm\" key: " + algorithm); @@ -722,18 +716,8 @@ Nfa Mata::Nfa::reduce(const Nfa &aut, bool trim_input, StateRenaming *state_rena if (state_renaming) { state_renaming->clear(); - if (trim_input) { - for (const auto& trimmed_mapping : trimmed_state_renaming) { - const auto reduced_mapping{ reduced_state_map.find(trimmed_mapping.second) }; - if (reduced_mapping != reduced_state_map.end()) { - (*state_renaming)[trimmed_mapping.first] = reduced_mapping->second; - } - } - } else { // Input has not been trimmed, the reduced state map is the actual input to result state map. - *state_renaming = reduced_state_map; - } + *state_renaming = reduced_state_map; } - return result; } diff --git a/src/re2parser.cc b/src/re2parser.cc index ea1f2ad23..ebe3dba4f 100644 --- a/src/re2parser.cc +++ b/src/re2parser.cc @@ -578,7 +578,6 @@ void Mata::Parser::create_nfa(Nfa::Nfa* nfa, const std::string& pattern, bool us //TODO: in fact, maybe parser should not do trimming and reducing, maybe these operations should be done transparently. if(use_reduce) { //TODO: trimming might be unnecessary, regex->nfa construction should not produce useless states. Or does it? - nfa->trim(); - *nfa = Mata::Nfa::reduce(*nfa); + *nfa = Mata::Nfa::reduce(nfa->trim()); } } diff --git a/src/strings/nfa-noodlification.cc b/src/strings/nfa-noodlification.cc index a15a7a427..65b482cef 100644 --- a/src/strings/nfa-noodlification.cc +++ b/src/strings/nfa-noodlification.cc @@ -43,7 +43,7 @@ size_t get_num_of_permutations(const SegNfa::Segmentation::EpsilonDepthTransitio } // namespace -SegNfa::NoodleSequence SegNfa::noodlify(const SegNfa& aut, const Symbol epsilon, bool include_empty) { +std::vector SegNfa::noodlify(const SegNfa& aut, const Symbol epsilon, bool include_empty) { const std::set epsilons({epsilon}); // return noodlify_reach(aut, epsilons, include_empty); @@ -71,7 +71,7 @@ SegNfa::NoodleSequence SegNfa::noodlify(const SegNfa& aut, const Symbol epsilon, size_t num_of_permutations{ get_num_of_permutations(epsilon_depths) }; size_t epsilon_depths_size{ epsilon_depths.size() }; - NoodleSequence noodles{}; + std::vector noodles{}; // noodle of epsilon transitions (each from different depth) std::vector epsilon_noodle(epsilon_depths_size); // for each combination of ε-transitions, create the automaton. @@ -137,7 +137,7 @@ void SegNfa::segs_one_initial_final( for (const State final_state: iter->final) { Nfa::Nfa segment_one_final = *iter; segment_one_final.final = {final_state }; - segment_one_final = reduce(segment_one_final); + segment_one_final = reduce(segment_one_final.trim()); if (segment_one_final.size() > 0 || include_empty) { out[std::make_pair(unused_state, final_state)] = std::make_shared(segment_one_final); @@ -147,7 +147,7 @@ void SegNfa::segs_one_initial_final( for (const State init_state: iter->initial) { Nfa::Nfa segment_one_init = *iter; segment_one_init.initial = {init_state }; - segment_one_init = reduce(segment_one_init); + segment_one_init = reduce(segment_one_init.trim()); if (segment_one_init.size() > 0 || include_empty) { out[std::make_pair(init_state, unused_state)] = std::make_shared(segment_one_init); @@ -159,8 +159,7 @@ void SegNfa::segs_one_initial_final( Nfa::Nfa segment_one_init_final = *iter; segment_one_init_final.initial = {init_state }; segment_one_init_final.final = {final_state }; - segment_one_init_final = reduce(segment_one_init_final); - + segment_one_init_final = reduce(segment_one_init_final.trim()); if (segment_one_init_final.size() > 0 || include_empty) { out[std::make_pair(init_state, final_state)] = std::make_shared(segment_one_init_final); } @@ -170,7 +169,7 @@ void SegNfa::segs_one_initial_final( } } -SegNfa::NoodleSubstSequence SegNfa::noodlify_mult_eps(const SegNfa& aut, const std::set& epsilons, bool include_empty) { +std::vector SegNfa::noodlify_mult_eps(const SegNfa& aut, const std::set& epsilons, bool include_empty) { Segmentation segmentation{ aut, epsilons }; const auto& segments{ segmentation.get_untrimmed_segments() }; @@ -197,12 +196,12 @@ SegNfa::NoodleSubstSequence SegNfa::noodlify_mult_eps(const SegNfa& aut, const s const auto& epsilon_depths_map{ segmentation.get_epsilon_depth_trans_map() }; struct SegItem { - NoodleSubst noodle{}; + NoodleWithEpsilonsCounter noodle{}; State fin{}; size_t seg_id{}; }; - NoodleSubstSequence noodles{}; + std::vector noodles{}; std::deque lifo; for(const State& fn : segments[0].final) { @@ -225,7 +224,7 @@ SegNfa::NoodleSubstSequence SegNfa::noodlify_mult_eps(const SegNfa& aut, const s if(item.seg_id + 1 == segments.size()) { // check if the noodle is already there if(!std::any_of(noodles.begin(), noodles.end(), - [&](NoodleSubst &s) { + [&](NoodleWithEpsilonsCounter &s) { return s == item.noodle; } )) { noodles.push_back(item.noodle); @@ -259,7 +258,7 @@ SegNfa::NoodleSubstSequence SegNfa::noodlify_mult_eps(const SegNfa& aut, const s return noodles; } -SegNfa::NoodleSequence SegNfa::noodlify_for_equation(const std::vector>& lhs_automata, const Nfa::Nfa& rhs_automaton, +std::vector SegNfa::noodlify_for_equation(const std::vector>& lhs_automata, const Nfa::Nfa& rhs_automaton, bool include_empty, const ParameterMap& params) { const auto lhs_aut_begin{ lhs_automata.begin() }; const auto lhs_aut_end{ lhs_automata.end() }; @@ -269,7 +268,7 @@ SegNfa::NoodleSequence SegNfa::noodlify_for_equation(const std::vector& lhs_automata, const Nfa::Nfa& rhs_automaton, +std::vector SegNfa::noodlify_for_equation(const std::vector& lhs_automata, const Nfa::Nfa& rhs_automaton, bool include_empty, const ParameterMap& params) { const auto lhs_aut_begin{ lhs_automata.begin() }; const auto lhs_aut_end{ lhs_automata.end() }; @@ -318,7 +316,7 @@ SegNfa::NoodleSequence SegNfa::noodlify_for_equation(const std::vector>& lhs_automata, +std::vector SegNfa::noodlify_for_equation(const std::vector>& lhs_automata, const std::vector>& rhs_automata, bool include_empty, const ParameterMap& params) { - if (lhs_automata.empty() || rhs_automata.empty()) { return NoodleSubstSequence{}; } + if (lhs_automata.empty() || rhs_automata.empty()) { return {}; } const auto lhs_aut_begin{ lhs_automata.begin() }; const auto lhs_aut_end{ lhs_automata.end() }; @@ -386,11 +383,10 @@ SegNfa::NoodleSubstSequence SegNfa::noodlify_for_equation(const std::vector epsilons({EPSILON, EPSILON-1}); auto product_pres_eps_trans{ - intersection_eps(concatenated_lhs, concatenated_rhs, true, epsilons) }; + intersection_eps(concatenated_lhs, concatenated_rhs, true, epsilons).trim() }; - product_pres_eps_trans.trim(); if (is_lang_empty(product_pres_eps_trans)) { - return NoodleSubstSequence{}; + return {}; } if (Util::haskey(params, "reduce")) { const std::string& reduce_value = params.at("reduce"); diff --git a/src/strings/nfa-segmentation.cc b/src/strings/nfa-segmentation.cc index 66b4e4237..afd6cbcac 100644 --- a/src/strings/nfa-segmentation.cc +++ b/src/strings/nfa-segmentation.cc @@ -151,7 +151,7 @@ const std::vector& SegNfa::Segmentation::get_segments() { if (segments.empty()) { get_untrimmed_segments(); - for (auto& seg_aut: segments_raw) { segments.push_back(seg_aut.get_trimmed_automaton()); } + for (auto& seg_aut: segments_raw) { segments.push_back(Nfa::Nfa{ seg_aut }.trim()); } } return segments; diff --git a/src/strings/nfa-strings.cc b/src/strings/nfa-strings.cc index 4432911c3..066ec6cf2 100644 --- a/src/strings/nfa-strings.cc +++ b/src/strings/nfa-strings.cc @@ -21,15 +21,14 @@ using namespace Mata::Nfa; using namespace Mata::Strings; -WordSet Mata::Strings::get_shortest_words(const Nfa::Nfa& nfa) { +std::set Mata::Strings::get_shortest_words(const Nfa::Nfa& nfa) { // Map mapping states to a set of the shortest words accepted by the automaton from the mapped state. // Get the shortest words for all initial states accepted by the whole automaton (not just a part of the automaton). - return ShortestWordsMap{ nfa }.get_shortest_words_for(StateSet{ nfa.initial }); + return ShortestWordsMap{ nfa }.get_shortest_words_from(StateSet{ nfa.initial }); } -WordSet ShortestWordsMap::get_shortest_words_for(const StateSet& states) const -{ - WordSet result{}; +std::set ShortestWordsMap::get_shortest_words_from(const StateSet& states) const { + std::set result{}; if (!shortest_words_map.empty()) { @@ -61,9 +60,9 @@ WordSet ShortestWordsMap::get_shortest_words_for(const StateSet& states) const return result; } -WordSet ShortestWordsMap::get_shortest_words_for(State state) const +std::set ShortestWordsMap::get_shortest_words_from(State state) const { - return get_shortest_words_for(StateSet{ state }); + return get_shortest_words_from(StateSet{ state }); } void ShortestWordsMap::insert_initial_lengths() @@ -74,7 +73,7 @@ void ShortestWordsMap::insert_initial_lengths() for (const State state: initial_states) { shortest_words_map.insert(std::make_pair(state, std::make_pair(0, - WordSet{ std::vector{} }))); + std::set{ std::vector{} }))); } const auto initial_states_begin{ initial_states.begin() }; @@ -154,8 +153,7 @@ std::set> Mata::Strings::get_word_lengths(const Nfa::Nfa& au /// The lengths of @p aut are hence equivalent to lengths of the NFA taken from @p aut where all symbols on /// transitions are renamed to a single symbol (e.g., `a`). aut.get_one_letter_aut(one_letter); - one_letter = determinize(one_letter); - one_letter.trim(); + one_letter = determinize(one_letter).trim(); if(one_letter.size() == 0) { return {}; } @@ -201,7 +199,7 @@ std::set> Mata::Strings::get_word_lengths(const Nfa::Nfa& au } bool Mata::Strings::is_lang_eps(const Nfa::Nfa& aut) { - Nfa::Nfa tr_aut = aut.get_trimmed_automaton(); + Nfa::Nfa tr_aut = Nfa::Nfa{ aut }.trim(); if(tr_aut.initial.size() == 0) return false; for(const auto& ini : tr_aut.initial) { diff --git a/tests-performance/src/nfa-operations.cc b/tests-performance/src/nfa-operations.cc index dd1b83ce1..08d9eb18f 100644 --- a/tests-performance/src/nfa-operations.cc +++ b/tests-performance/src/nfa-operations.cc @@ -46,27 +46,5 @@ int main(int argc, char *argv[]) { auto end = std::chrono::system_clock::now(); std::chrono::duration elapsed = end - start; std::cout << "trim: " << elapsed.count() << "\n"; - - Nfa trimmed_aut2 = aut; - start = std::chrono::system_clock::now(); - trimmed_aut.trim_inplace(); - end = std::chrono::system_clock::now(); - elapsed = end - start; - std::cout << "trim-inplace: " << elapsed.count() << "\n"; - - Nfa trimmed_aut3 = aut; - start = std::chrono::system_clock::now(); - trimmed_aut.trim_reverting(); - end = std::chrono::system_clock::now(); - elapsed = end - start; - std::cout << "trim-reverting: " << elapsed.count() << "\n"; - - Nfa trimmed_aut4 = aut; - start = std::chrono::system_clock::now(); - trimmed_aut.get_trimmed_automaton(); - end = std::chrono::system_clock::now(); - elapsed = end - start; - std::cout << "get-trimmed-automaton: " << elapsed.count() << "\n"; - return EXIT_SUCCESS; } diff --git a/tests-performance/src/unary-operations.cc b/tests-performance/src/unary-operations.cc index e6979df4a..69a81f10b 100644 --- a/tests-performance/src/unary-operations.cc +++ b/tests-performance/src/unary-operations.cc @@ -60,7 +60,8 @@ int main(int argc, char *argv[]) { start = std::chrono::system_clock::now(); // > START OF PROFILED CODE // Only reduce and its callees will be measured - Mata::Nfa::Plumbing::reduce(&reduced_aut, aut); + Nfa trimmed{ aut }; + Mata::Nfa::Plumbing::reduce(&reduced_aut, trimmed.trim()); // > END OF PROFILED CODE end = std::chrono::system_clock::now(); elapsed = end - start; @@ -70,7 +71,7 @@ int main(int argc, char *argv[]) { start = std::chrono::system_clock::now(); // > START OF PROFILED CODE // Only reduce and its callees will be measured - Mata::Nfa::Plumbing::reduce(&untrimmed_reduced_aut, aut, false); + Mata::Nfa::Plumbing::reduce(&untrimmed_reduced_aut, aut); // > END OF PROFILED CODE end = std::chrono::system_clock::now(); elapsed = end - start; diff --git a/tests/nfa/delta.cc b/tests/nfa/delta.cc index 02c930cb3..1697462a6 100644 --- a/tests/nfa/delta.cc +++ b/tests/nfa/delta.cc @@ -68,6 +68,35 @@ TEST_CASE("Mata::Nfa::Delta::state_post()") { CHECK(aut.delta.state_post(25).empty()); CHECK(aut.delta.state_post(26).empty()); } + + SECTION("Add multiple targets at once") { + 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); + } +} + +TEST_CASE("Mata::Nfa::Delta::contains()") { + Nfa nfa; + CHECK(!nfa.delta.contains(0, 1, 0)); + CHECK(!nfa.delta.contains(Transition{ 0, 1, 0 })); + nfa.delta.add(0, 1, 0); + CHECK(nfa.delta.contains(0, 1, 0)); + CHECK(nfa.delta.contains(Transition{ 0, 1, 0 })); +} + +TEST_CASE("Mata::Nfa::Delta::remove()") { + Nfa nfa; + + SECTION("Simple remove") { + nfa.delta.add(0, 1, 0); + CHECK_NOTHROW(nfa.delta.remove(3, 5, 6)); + CHECK_NOTHROW(nfa.delta.remove(0, 1, 0)); + CHECK(nfa.delta.empty()); + nfa.delta.add(10, 1, 0); + CHECK_THROWS_AS(nfa.delta.remove(3, 5, 6), std::invalid_argument); + } } TEST_CASE("Mata::Nfa::Delta::mutable_post()") { diff --git a/tests/nfa/nfa-profiling.cc b/tests/nfa/nfa-profiling.cc index 88cf9b3ca..1d4e75349 100644 --- a/tests/nfa/nfa-profiling.cc +++ b/tests/nfa/nfa-profiling.cc @@ -63,17 +63,7 @@ TEST_CASE("Mata::Nfa::trim_inplace() speed, simple", "[.profiling]") { FILL_WITH_AUT_B(B); for (int i = 0; i < 300000; i++) { A = B; - A.trim_inplace(); - } -} - -TEST_CASE("Mata::Nfa::trim_reverting() speed, simple", "[.profiling]") { - Nfa A, B; -//this gives an interesting test case if the parser is not trimming and reducing - FILL_WITH_AUT_B(B); - for (int i = 0; i < 300000; i++) { - A = B; - A.trim_reverting(); + A.trim(); } } @@ -83,17 +73,7 @@ TEST_CASE("Mata::Nfa::trim_inplace() speed, harder", "[.profiling]") { create_nfa(&B, "((.*){10})*"); for (int i = 0; i < 200; i++) { A = B; - A.trim_inplace(); - } -} - -TEST_CASE("Mata::Nfa::trim_reverting() speed, harder", "[.profiling]") { - Nfa A, B; -//this gives an interesting test case if the parser is not trimming and reducing - create_nfa(&B, "((.*){10})*"); - for (int i = 0; i < 200; i++) { - A = B; - A.trim_reverting(); + A.trim(); } } diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index 57a9d6fec..8eb75a028 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -6,6 +6,7 @@ #include "nfa-util.hh" +#include "mata/utils/sparse-set.hh" #include "mata/nfa/nfa.hh" #include "mata/nfa/strings.hh" #include "mata/nfa/builder.hh" @@ -20,11 +21,10 @@ using namespace Mata::Nfa::Plumbing; using namespace Mata::Util; using namespace Mata::Parser; using Symbol = Mata::Symbol; +using Word = Mata::Word; using IntAlphabet = Mata::IntAlphabet; using OnTheFlyAlphabet = Mata::OnTheFlyAlphabet; -using Word = std::vector; - TEST_CASE("Mata::Nfa::size()") { Nfa nfa{}; CHECK(nfa.size() == 0); @@ -153,7 +153,7 @@ TEST_CASE("Mata::Nfa::Delta.transform/append") auto upd_fnc = [&](State st) { return st + 5; }; - std::vector state_posts = a.delta.transform(upd_fnc); + std::vector state_posts = a.delta.renumber_targets(upd_fnc); a.delta.append(state_posts); REQUIRE(a.delta.contains(4, 'a', 6)); @@ -2061,7 +2061,7 @@ TEST_CASE("Mata::Nfa::reduce_size_by_simulation()") SECTION("empty automaton") { - Nfa result = reduce(aut, false, &state_renaming); + Nfa result = reduce(aut, &state_renaming); REQUIRE(result.delta.empty()); REQUIRE(result.initial.empty()); @@ -2074,7 +2074,7 @@ TEST_CASE("Mata::Nfa::reduce_size_by_simulation()") aut.initial.insert(1); aut.final.insert(2); - Nfa result = reduce(aut, false, &state_renaming); + Nfa result = reduce(aut, &state_renaming); REQUIRE(result.delta.empty()); REQUIRE(result.initial[state_renaming[1]]); @@ -2106,7 +2106,7 @@ TEST_CASE("Mata::Nfa::reduce_size_by_simulation()") aut.final = {3, 9}; - Nfa result = reduce(aut, false, &state_renaming); + Nfa result = reduce(aut, &state_renaming); REQUIRE(result.size() == 6); REQUIRE(result.initial[state_renaming[1]]); @@ -2122,30 +2122,24 @@ TEST_CASE("Mata::Nfa::reduce_size_by_simulation()") REQUIRE(result.final[state_renaming[9]]); REQUIRE(result.final[state_renaming[3]]); - result = reduce(aut, true, &state_renaming); + result = reduce(aut.trim(), &state_renaming); CHECK(result.size() == 3); - CHECK(result.initial.size() == 2); - for (State initial : result.initial) { - CHECK(((initial == state_renaming[1]) || (initial == state_renaming[2]))); - } - REQUIRE(result.final.size() == 1); - for (State final : result.final) { - CHECK(final == state_renaming[3]); - } + CHECK(result.initial == SparseSet{ 0, 1 }); + CHECK(result.final == SparseSet{ 2 }); CHECK(result.delta.size() == 6); - CHECK(result.delta.contains(state_renaming[1], 'a', state_renaming[3])); + 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])); + CHECK(result.delta.contains(state_renaming[1], 'b', state_renaming[1])); CHECK(result.delta.contains(state_renaming[1], 'a', state_renaming[2])); - CHECK(result.delta.contains(state_renaming[2], 'a', state_renaming[2])); - CHECK(result.delta.contains(state_renaming[2], 'b', state_renaming[2])); - CHECK(result.delta.contains(state_renaming[2], 'a', state_renaming[3])); - CHECK(result.delta.contains(state_renaming[3], 'b', state_renaming[2])); + CHECK(result.delta.contains(state_renaming[2], 'b', state_renaming[1])); } SECTION("no transitions from non-final state") { aut.delta.add(0, 'a', 1); aut.initial = { 0 }; - Nfa result = reduce(aut, true, &state_renaming); + Nfa result = reduce(aut.trim(), &state_renaming); CHECK(Mata::Nfa::are_equivalent(result, aut)); } } @@ -2309,33 +2303,30 @@ TEST_CASE("Mata::Nfa::get_one_letter_aut()") REQUIRE(!digraph.delta.contains(10, 'c', 7)); } -TEST_CASE("Mata::Nfa::get_reachable_states()") -{ +TEST_CASE("Mata::Nfa::get_reachable_states()") { Nfa aut{20}; - SECTION("Automaton A") - { + SECTION("Automaton A") { FILL_WITH_AUT_A(aut); aut.delta.remove(3, 'b', 9); aut.delta.remove(5, 'c', 9); aut.delta.remove(1, 'a', 10); - auto reachable{aut.get_reachable_states()}; - CHECK(reachable.find(0) == reachable.end()); - CHECK(reachable.find(1) != reachable.end()); - CHECK(reachable.find(2) == reachable.end()); - CHECK(reachable.find(3) != reachable.end()); - CHECK(reachable.find(4) == reachable.end()); - CHECK(reachable.find(5) != reachable.end()); - CHECK(reachable.find(6) == reachable.end()); - CHECK(reachable.find(7) != reachable.end()); - CHECK(reachable.find(8) == reachable.end()); - CHECK(reachable.find(9) == reachable.end()); - CHECK(reachable.find(10) == reachable.end()); + StateSet reachable{ aut.get_reachable_states() }; + CHECK(!reachable.contains(0)); + CHECK(reachable.contains(1)); + CHECK(!reachable.contains(2)); + CHECK(reachable.contains(3)); + CHECK(!reachable.contains(4)); + CHECK(reachable.contains(5)); + CHECK(!reachable.contains(6)); + CHECK(reachable.contains(7)); + CHECK(!reachable.contains(8)); + CHECK(!reachable.contains(9)); + CHECK(!reachable.contains(10)); aut.initial.erase(1); aut.initial.erase(3); - reachable = aut.get_reachable_states(); CHECK(reachable.empty()); } @@ -2371,7 +2362,7 @@ TEST_CASE("Mata::Nfa::get_reachable_states()") CHECK(reachable.find(2) != reachable.end()); CHECK(reachable.find(4) != reachable.end()); CHECK(reachable.find(6) != reachable.end()); - CHECK(aut.get_useful_states_old().empty()); + CHECK(aut.get_useful_states().count() == 0); aut.final.insert(4); reachable = aut.get_reachable_states(); @@ -2392,14 +2383,14 @@ TEST_CASE("Mata::Nfa::trim() for profiling", "[.profiling],[trim]") } //TODO: make this a test for the new version -TEST_CASE("Mata::Nfa::get_useful_states_old() for profiling", "[.profiling],[useful_states]") +TEST_CASE("Mata::Nfa::get_useful_states() for profiling", "[.profiling],[useful_states]") { Nfa aut{20}; FILL_WITH_AUT_A(aut); aut.delta.remove(1, 'a', 10); for (size_t i{ 0 }; i < 10000; ++i) { - aut.get_useful_states_old(); + aut.get_useful_states(); } } @@ -2654,17 +2645,17 @@ TEST_CASE("Mata::Nfa::Nfa::unify_(initial/final)()") { } } -TEST_CASE("Mata::Nfa::Nfa::get_epsilon_transitions()") { +TEST_CASE("Mata::Nfa::Nfa::get_delta.epsilon_symbol_posts()") { Nfa aut{20}; FILL_WITH_AUT_A(aut); aut.delta.add(0, EPSILON, 3); aut.delta.add(3, EPSILON, 3); aut.delta.add(3, EPSILON, 4); - auto state_eps_trans{ aut.get_epsilon_transitions(0) }; + auto state_eps_trans{ aut.delta.epsilon_symbol_posts(0) }; CHECK(state_eps_trans->symbol == EPSILON); CHECK(state_eps_trans->targets == StateSet{3 }); - state_eps_trans = aut.get_epsilon_transitions(3); + state_eps_trans = aut.delta.epsilon_symbol_posts(3); CHECK(state_eps_trans->symbol == EPSILON); CHECK(state_eps_trans->targets == StateSet{3, 4 }); @@ -2672,29 +2663,29 @@ TEST_CASE("Mata::Nfa::Nfa::get_epsilon_transitions()") { aut.delta.add(8, 42, 4); aut.delta.add(8, 42, 6); - state_eps_trans = aut.get_epsilon_transitions(8, 42); + state_eps_trans = aut.delta.epsilon_symbol_posts(8, 42); CHECK(state_eps_trans->symbol == 42); CHECK(state_eps_trans->targets == StateSet{3, 4, 6 }); - CHECK(aut.get_epsilon_transitions(1) == aut.delta.state_post(1).end()); - CHECK(aut.get_epsilon_transitions(5) == aut.delta.state_post(5).end()); - CHECK(aut.get_epsilon_transitions(19) == aut.delta.state_post(19).end()); + CHECK(aut.delta.epsilon_symbol_posts(1) == aut.delta.state_post(1).end()); + CHECK(aut.delta.epsilon_symbol_posts(5) == aut.delta.state_post(5).end()); + CHECK(aut.delta.epsilon_symbol_posts(19) == aut.delta.state_post(19).end()); StatePost state_post{ aut.delta[0] }; - state_eps_trans = aut.get_epsilon_transitions(state_post); + state_eps_trans = aut.delta.epsilon_symbol_posts(state_post); CHECK(state_eps_trans->symbol == EPSILON); CHECK(state_eps_trans->targets == StateSet{3 }); state_post = aut.delta[3]; - state_eps_trans = Nfa::get_epsilon_transitions(state_post); + state_eps_trans = Delta::epsilon_symbol_posts(state_post); CHECK(state_eps_trans->symbol == EPSILON); CHECK(state_eps_trans->targets == StateSet{3, 4 }); state_post = aut.delta.state_post(1); - CHECK(aut.get_epsilon_transitions(state_post) == state_post.end()); + CHECK(aut.delta.epsilon_symbol_posts(state_post) == state_post.end()); state_post = aut.delta.state_post(5); - CHECK(aut.get_epsilon_transitions(state_post) == state_post.end()); + CHECK(aut.delta.epsilon_symbol_posts(state_post) == state_post.end()); state_post = aut.delta.state_post(19); - CHECK(aut.get_epsilon_transitions(state_post) == state_post.end()); + CHECK(aut.delta.epsilon_symbol_posts(state_post) == state_post.end()); } TEST_CASE("Mata::Nfa::Nfa::delta()") { @@ -2769,8 +2760,7 @@ TEST_CASE("Mata::Nfa::trim bug") { aut.delta.add(3, 97, 4); Nfa aut_copy {aut}; - aut.trim(); - CHECK(are_equivalent(aut_copy, aut)); + CHECK(are_equivalent(aut_copy.trim(), aut)); } TEST_CASE("Mata::Nfa::get_useful_states_tarjan") { @@ -2846,28 +2836,23 @@ TEST_CASE("Mata::Nfa::get_useful_states_tarjan") { CHECK(bv == ref); } - SECTION("from regex (a+b*a*)") { - Mata::Nfa::Nfa aut; - Mata::Parser::create_nfa(&aut, "(a+b*a*)", false, EPSILON, false); + SECTION("from regex (a+b*a*)") { + Mata::Nfa::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); + 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); - bv = aut.get_useful_states(); - CHECK(bv == Mata::BoolVector({1,1,1,1})); - } + aut = Mata::Nfa::reduce(aut.trim()); + bv = aut.get_useful_states(); + CHECK(bv == Mata::BoolVector({1,1,1,1})); + } SECTION("more initials") { - Nfa aut(4, {0, 1, 2}, {0, 3}); - aut.delta.add(1, 48, 0); + aut.delta.add(1, 48, 0); aut.delta.add(2, 53, 3); - - Mata::BoolVector bv = aut.get_useful_states(); - Mata::BoolVector ref({1, 1, 1, 1}); - CHECK(bv == ref); - } - + CHECK(aut.get_useful_states() == Mata::BoolVector{1, 1, 1, 1}); + } } diff --git a/tests/strings/nfa-noodlification.cc b/tests/strings/nfa-noodlification.cc index 24d9e2f3e..1350d7c48 100644 --- a/tests/strings/nfa-noodlification.cc +++ b/tests/strings/nfa-noodlification.cc @@ -320,7 +320,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation()") { std::vector> noodle2_segments{ std::make_shared(noodle2_segment1), std::make_shared(noodle2_segment2), std::make_shared(noodle2_segment3) }; - SegNfa::NoodleSequence expected{ noodle1_segments, noodle2_segments }; + std::vector expected{ noodle1_segments, noodle2_segments }; auto result{ SegNfa::noodlify_for_equation({ left1, left2, left3 }, right_side) }; REQUIRE(result.size() == 2); @@ -370,7 +370,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation() both sides") { auto res = std::vector>>({ {{x, {0, 0} }, {x, {0, 1} }, {y, {1, 1} }}, {{x, {0, 0} }, {y, {1, 0} }, {y, {1, 1} }} } ); - SegNfa::NoodleSubstSequence noodles = SegNfa::noodlify_for_equation( + std::vector noodles = SegNfa::noodlify_for_equation( std::vector>{std::make_shared(x), std::make_shared(y) }, std::vector>{std::make_shared(z), std::make_shared(w)}); for(size_t i = 0; i < noodles.size(); i++) { @@ -397,7 +397,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation() both sides") { {{x, {0, 0} }, {x, {0, 1} }, {z, {1, 1} }}, {{x, {0, 0} }, {z, {1, 0} }, {w, {1, 1} }}, } ); - SegNfa::NoodleSubstSequence noodles = SegNfa::noodlify_for_equation( + std::vector noodles = SegNfa::noodlify_for_equation( std::vector>{std::make_shared(x), std::make_shared(y) }, std::vector>{std::make_shared(z), std::make_shared(w)}); for(size_t i = 0; i < noodles.size(); i++) { @@ -418,7 +418,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation() both sides") { create_nfa(&w, "(a|b)*"); auto res = std::vector>>({} ); - SegNfa::NoodleSubstSequence noodles = SegNfa::noodlify_for_equation( + std::vector noodles = SegNfa::noodlify_for_equation( std::vector>{std::make_shared(x) }, std::vector>{std::make_shared(y), std::make_shared(z), std::make_shared(w)}); CHECK(noodles.size() == 1); @@ -443,7 +443,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation() both sides") { {{y, {1, 1} }}, {{y, {1, 0} }, {y, {1, 1} }}, } ); - SegNfa::NoodleSubstSequence noodles = SegNfa::noodlify_for_equation( + std::vector noodles = SegNfa::noodlify_for_equation( std::vector>{std::make_shared(x), std::make_shared(y) }, std::vector>{std::make_shared(z), std::make_shared(w)}); CHECK(noodles.size() == 2); @@ -467,7 +467,7 @@ TEST_CASE("Mata::Nfa::SegNfa::noodlify_for_equation() both sides") { auto res = std::vector>>({ {{x, {0, 0} }, {x, {1, 1} }}, } ); - SegNfa::NoodleSubstSequence noodles = SegNfa::noodlify_for_equation( + std::vector noodles = SegNfa::noodlify_for_equation( std::vector>{std::make_shared(x), std::make_shared(y) }, std::vector>{std::make_shared(z), std::make_shared(u)}); CHECK(noodles.size() == 1); diff --git a/tests/strings/nfa-string-solving.cc b/tests/strings/nfa-string-solving.cc index 9163b7cfe..1fe93157b 100644 --- a/tests/strings/nfa-string-solving.cc +++ b/tests/strings/nfa-string-solving.cc @@ -31,7 +31,7 @@ using namespace Mata::Util; using namespace Mata::Parser; using Symbol = Mata::Symbol; -using Word = std::vector; +using Word = Mata::Word; // Some common automata {{{ @@ -86,7 +86,7 @@ TEST_CASE("Mata::Nfa::get_shortest_words()") Word word{}; word.push_back('b'); word.push_back('a'); - WordSet expected{word}; + std::set expected{word}; Word word2{}; word2.push_back('a'); word2.push_back('a'); @@ -108,7 +108,7 @@ TEST_CASE("Mata::Nfa::get_shortest_words()") word.push_back('b'); word.push_back('b'); word.push_back('a'); - expected = WordSet{word}; + expected = std::set{word}; word2.clear(); word2.push_back('b'); word2.push_back('a'); @@ -131,7 +131,7 @@ TEST_CASE("Mata::Nfa::get_shortest_words()") aut.final.insert(1); REQUIRE(get_shortest_words(aut).empty()); aut.final.insert(0); - REQUIRE(get_shortest_words(aut) == WordSet{Word{}}); + REQUIRE(get_shortest_words(aut) == std::set{Word{}}); } SECTION("Automaton A") @@ -195,7 +195,7 @@ TEST_CASE("Mata::Nfa::get_shortest_words() for profiling", "[.profiling][shortes word.push_back('b'); word.push_back('b'); word.push_back('a'); - WordSet expected{ word }; + std::set expected{ word }; Word word2{}; word2.push_back('b'); word2.push_back('a');