/* * This file is part of Algorithms library toolkit. * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) * Algorithms library toolkit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * Algorithms library toolkit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <ostream> #include <sstream> #include <alib/multimap> #include <alib/set> #include <alib/vector> #include <core/components.hpp> #include <core/normalize.hpp> #include <common/DefaultStateType.h> #include <common/DefaultSymbolType.h> #include <automaton/AutomatonException.h> #include <core/normalize.hpp> #include <alphabet/common/SymbolNormalize.h> #include <automaton/common/AutomatonNormalize.h> #include "DFTA.h" #include "NFTA.h" namespace automaton { class InputAlphabet; class States; class FinalStates; /** * \brief * Epsilon nondeterministic finite tree automaton. Accepts regular tree languages. * \details * Definition is classical definition of epsilon finite tree automata. * A = (Q, T, \delta, F), * Q (States) = nonempty finite set of states, * T (TerminalAlphabet) = finite set of terminal ranked symbols - having this empty won't let automaton do much though, * \delta = transition function of the form ( (A, B, C, ...) \times a) \cup A \times \epsilon -> P(Q), where A, B, C, ... \in Q, a \in T, and P(Q) is a powerset of states, * F (FinalStates) = set of final states * * Elements of the \delta multimapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol from the non-epsilon transition. * * \tparam SymbolTypeT used for the symbol part of the ranked symbol * \tparam StateTypeT used to the states, and the initial state of the automaton. */ template < class SymbolTypeT = DefaultSymbolType, class StateTypeT = DefaultStateType > class EpsilonNFTA final : public core::Components < EpsilonNFTA < SymbolTypeT, StateTypeT >, ext::set < common::ranked_symbol < SymbolTypeT > >, component::Set, InputAlphabet, ext::set < StateTypeT >, component::Set, std::tuple < States, FinalStates > > { public: typedef SymbolTypeT SymbolType; typedef StateTypeT StateType; private: /** * Transition function as multimapping from a list of states times an input symbol or just a state on the left hand side to states on the right hand side. */ ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > transitions; public: /** * \brief Creates a new instance of the automaton. */ explicit EpsilonNFTA ( ); /** * \brief Creates a new instance of the automaton with a concrete set of states, input alphabet, and a set of final states. * * \param states the initial set of states of the automaton * \param inputAlphabet the initial input alphabet * \param finalStates the initial set of final states of the automaton */ explicit EpsilonNFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ); /* * \brief Creates a new instance of the automaton based on the Deterministic finite tree automaton. * * \param other the Deterministic finite tree automaton */ explicit EpsilonNFTA ( const NFTA < SymbolType, StateType > & other ); /* * \brief Creates a new instance of the automaton based on the Deterministic finite tree automaton. * * \param other the Deterministic finite tree automaton */ explicit EpsilonNFTA ( const DFTA < SymbolType, StateType > & other ); /** * Getter of states. * * \returns the states of the automaton */ const ext::set < StateType > & getStates ( ) const & { return this->template accessComponent < States > ( ).get ( ); } /** * Getter of states. * * \returns the states of the automaton */ ext::set < StateType > && getStates ( ) && { return std::move ( this->template accessComponent < States > ( ).get ( ) ); } /** * Adder of a state. * * \param state the new state to be added to a set of states * * \returns true if the state was indeed added */ bool addState ( StateType state ) { return this->template accessComponent < States > ( ).add ( std::move ( state ) ); } /** * Setter of states. * * \param states completely new set of states */ void setStates ( ext::set < StateType > states ) { this->template accessComponent < States > ( ).set ( std::move ( states ) ); } /** * Remover of a state. * * \param state a state to be removed from a set of states * * \returns true if the state was indeed removed */ void removeState ( const StateType & state ) { this->template accessComponent < States > ( ).remove ( state ); } /** * Getter of final states. * * \returns the final states of the automaton */ const ext::set < StateType > & getFinalStates ( ) const & { return this->template accessComponent < FinalStates > ( ).get ( ); } /** * Getter of final states. * * \returns the final states of the automaton */ ext::set < StateType > && getFinalStates ( ) && { return std::move ( this->template accessComponent < FinalStates > ( ).get ( ) ); } /** * Adder of a final state. * * \param state the new state to be added to a set of final states * * \returns true if the state was indeed added */ bool addFinalState ( StateType state ) { return this->template accessComponent < FinalStates > ( ).add ( std::move ( state ) ); } /** * Setter of final states. * * \param states completely new set of final states */ void setFinalStates ( ext::set < StateType > states ) { this->template accessComponent < FinalStates > ( ).set ( std::move ( states ) ); } /** * Remover of a final state. * * \param state a state to be removed from a set of final states * * \returns true if the state was indeed removed */ void removeFinalState ( const StateType & state ) { this->template accessComponent < FinalStates > ( ).remove ( state ); } /** * Getter of the input alphabet. * * \returns the input alphabet of the automaton */ const ext::set < common::ranked_symbol < SymbolType > > & getInputAlphabet ( ) const & { return this->template accessComponent < InputAlphabet > ( ).get ( ); } /** * Getter of the input alphabet. * * \returns the input alphabet of the automaton */ ext::set < common::ranked_symbol < SymbolType > > && getInputAlphabet ( ) && { return std::move ( this->template accessComponent < InputAlphabet > ( ).get ( ) ); } /** * Adder of a input symbol. * * \param symbol the new symbol to be added to an input alphabet * * \returns true if the symbol was indeed added */ bool addInputSymbol ( common::ranked_symbol < SymbolType > symbol ) { return this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); } /** * Adder of input symbols. * * \param symbols new symbols to be added to an input alphabet */ void addInputSymbols ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); } /** * Setter of input alphabet. * * \param symbols completely new input alphabet */ void setInputAlphabet ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { this->template accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); } /** * Remover of an input symbol. * * \param symbol a symbol to be removed from an input alphabet * * \returns true if the symbol was indeed removed */ void removeInputSymbol ( const common::ranked_symbol < SymbolType > & symbol ) { this->template accessComponent < InputAlphabet > ( ).remove ( symbol ); } /** * \brief Add a transition to the automaton. * * \details The transition is either in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T * or a form A \times \epsilon -> B, where A, B \in Q * * \param lhs the left hand side of the transitions * \param rhs the right hand side of the transitions * * \throws AutomatonException when transition contains state or symbol not present in the automaton components * * \returns true if the transition was indeed added */ bool addTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > lhs, StateType rhs ); /** * \brief Add a transition to the automaton. * * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T * * \param symbol the input symbol (a) * \param prevStates the source states (A, B, C, ...) * \param next the target state (B) * * \throws AutomatonException when transition contains state or symbol not present in the automaton components * * \returns true if the transition was indeed added */ bool addTransition ( common::ranked_symbol < SymbolType > symbol, ext::vector < StateType > prevStates, StateType next ); /** * \brief Add a transition to the automaton. * * \details The transition is in a form A \times \epsilon -> B, where A, B \in Q * * \param from the source state (A) * \param to the target state (B) * * \throws AutomatonException when transition contains state or symbol not present in the automaton components * * \returns true if the transition was indeed added */ bool addTransition ( StateType from, StateType to ); /** * \brief Removes a transition from the automaton. * * \details The transition is either in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T * or a form A \times \epsilon -> B, where A, B \in Q * * \param lhs the left hand side of the transitions * \param rhs the right hand side of the transitions * * \returns true if the transition was indeed removed */ bool removeTransition ( const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > & lhs, const StateType & rhs ); /** * \brief Removes a transition from the automaton. * * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T * * \param symbol the input symbol (a) * \param prevStates the source states (A, B, C, ...) * \param next the target state (B) * * \returns true if the transition was indeed removed */ bool removeTransition ( const common::ranked_symbol < SymbolType > & symbol, const ext::vector < StateType > & prevStates, const StateType & next ); /** * \brief Removes a transition from the automaton. * * \details The transition is in a form A \times \epsilon -> B, where A, B \in Q * * \param from the source state (A) * \param to the target state (B) * * \returns true if the transition was indeed removed */ bool removeTransition ( const StateType & from, const StateType & to ); /** * Get the transition function of the automaton in its natural form. * * \returns transition function of the automaton */ const ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & getTransitions ( ) const & { return transitions; } /** * Get the transition function of the automaton in its natural form. * * \returns transition function of the automaton */ ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > && getTransitions ( ) && { return std::move ( transitions ); } /** * Get the epsilon transitions of the automaton * * \returns epsilon transitions of the automaton */ ext::multimap < StateType, StateType > getEpsilonTransitions ( ) const; /** * Get the non-epsilon transitions of the automaton * * \returns non-epsilon transitions of the automaton */ ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > >, StateType > getSymbolTransitions ( ) const; /** * \returns transitions to state @p q */ ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > getTransitionsToState ( const StateType & q ) const { ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > res; for ( const auto & transition : getTransitions ( ) ) if ( transition.second == q ) res.insert ( transition ); return res; } /** * \returns transitions from state @p q */ ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > getTransitionsFromState ( const StateType & q ) const { ext::multimap < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > res; for ( const auto & transition : getTransitions ( ) ) { if ( transition.first.template is < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ) ) { const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = transition.first.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); if ( std::find ( source.second.begin ( ), source.second.end ( ), q ) != source.second.end ( ) ) { res.insert ( transition ); } } if ( transition.first.template is < StateType > ( ) ) { const StateType & source = transition.first.template get < StateType > ( ); if ( source == q ) { res.insert ( transition ); } } } return res; } /** * Get a subset of epsilon transitions of the automaton, with the source state fixed in the transitions natural representation. * * \param from filter the transition function based on this state as a source state * * \returns a subset of epsilon transitions of the automaton with the source state fixed */ ext::multimap < StateType, StateType > getEpsilonTransitionsFromState ( const StateType & from ) const; /** * Get a subset of epsilon transitions of the automaton, with the target state fixed in the transitions natural representation. * * \param to filter the transition function based on this state as a source state * * \returns a subset of epsilon transitions of the automaton with the target state fixed */ ext::multimap < StateType, StateType > getEpsilonTransitionsToState ( const StateType & to ) const; /** * \brief Determines whether the automaton is without epsilon transitions. * * \return true when automaton doesn't contain epsilon transitions, false otherwise */ bool isEpsilonFree ( ) const; /** * \brief Determines whether the automaton is deterministic. * * the automaton is deterministic if and only if: * \li \c size of transition function \delta (from states, input symbol) \leq 1 * * \return true if the automaton is deterministic, false otherwise */ bool isDeterministic ( ) const; /** * The three way comparison implementation * * \param other the other instance * * \returns the ordering between this object and the @p other. */ auto operator <=> ( const EpsilonNFTA & other ) const { return std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions) <=> std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions); } /** * The equality comparison implementation. * * \param other the other object to compare with. * * \returns true if this and other objects are equal, false othervise */ bool operator == ( const EpsilonNFTA & other ) const { return std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions) == std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions); } /** * Print this object as raw representation to ostream. * * \param out ostream where to print * \param instance object to print * * \returns modified output stream */ friend std::ostream & operator << ( std::ostream & out, const EpsilonNFTA & instance ) { return out << "(EpsilonNFTA " << " states = " << instance.getStates ( ) << " inputAlphabet = " << instance.getInputAlphabet ( ) << " finalStates = " << instance.getFinalStates ( ) << " transitions = " << instance.getTransitions ( ) << ")"; } /** * Casts this instance to as compact as possible string representation. * * \returns string representation of the object */ operator std::string ( ) const; }; /** * Trait to detect whether the type parameter T is or is not EpsilonNFTA. Derived from std::false_type. * * \tparam T the tested type parameter */ template < class T > class isEpsilonNFTA_impl : public std::false_type {}; /** * Trait to detect whether the type parameter T is or is not DFA. Derived from std::true_type. * * Specialisation for EpsilonNFTA. * * \tparam SymbolType used for the terminal alphabet of the automaton * \tparam StateType used for the terminal alphabet of the automaton */ template < class SymbolType, class StateType > class isEpsilonNFTA_impl < EpsilonNFTA < SymbolType, StateType > > : public std::true_type {}; /** * Constexpr true if the type parameter T is EpsilonNFTA, false otherwise. * * \tparam T the tested type parameter */ template < class T > constexpr bool isEpsilonNFTA = isEpsilonNFTA_impl < T > { }; template < class SymbolType, class StateType > EpsilonNFTA < SymbolType, StateType >::EpsilonNFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ) : core::Components < EpsilonNFTA, ext::set < common::ranked_symbol < SymbolType > >, component::Set, InputAlphabet, ext::set < StateType >, component::Set, std::tuple < States, FinalStates > > ( std::move ( inputAlphabet ), std::move ( states ), std::move ( finalStates ) ) { } template < class SymbolType, class StateType > EpsilonNFTA < SymbolType, StateType >::EpsilonNFTA() : EpsilonNFTA ( ext::set < StateType > { }, ext::set < common::ranked_symbol < SymbolType > > { }, ext::set < StateType > { } ) { } template < class SymbolType, class StateType > EpsilonNFTA < SymbolType, StateType >::EpsilonNFTA(const NFTA < SymbolType, StateType > & other) : EpsilonNFTA ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) { transitions.insert ( other.getTransitions ( ).begin ( ), other.getTransitions ( ).end ( ) ); } template < class SymbolType, class StateType > EpsilonNFTA < SymbolType, StateType >::EpsilonNFTA(const DFTA < SymbolType, StateType > & other) : EpsilonNFTA ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) { transitions.insert ( other.getTransitions ( ).begin ( ), other.getTransitions ( ).end ( ) ); } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::addTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > lhs, StateType rhs ) { if ( lhs.template is < StateType > ( ) ) { const StateType & source = lhs.template get < StateType > ( ); if ( ! getStates().contains ( source ) ) throw AutomatonException("State \"" + ext::to_string ( source ) + "\" doesn't exist."); } else { const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = lhs.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); if ( source.second.size ( ) != source.first.getRank ( ) ) throw AutomatonException("Number of states doesn't match rank of the symbol"); if ( ! getInputAlphabet ( ).contains ( source.first ) ) throw AutomatonException("Input symbol \"" + ext::to_string ( source.first ) + "\" doesn't exist."); for ( const StateType & it : source.second ) { if ( ! getStates ( ).contains ( it ) ) throw AutomatonException("State \"" + ext::to_string ( it ) + "\" doesn't exist."); } } if ( ! getStates().contains ( rhs ) ) throw AutomatonException("State \"" + ext::to_string ( rhs ) + "\" doesn't exist."); auto upper_bound = transitions.upper_bound ( lhs ); auto lower_bound = transitions.lower_bound ( lhs ); auto iter = std::lower_bound ( lower_bound, upper_bound, rhs, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } ); if ( iter != upper_bound && rhs >= iter->second ) return false; transitions.insert ( iter, std::make_pair ( std::move ( lhs ), std::move ( rhs ) ) ); return true; } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::addTransition ( common::ranked_symbol < SymbolType > symbol, ext::vector<StateType> prevStates, StateType next) { return addTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) ) ), std::move ( next ) ); } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::addTransition ( StateType from, StateType to) { return addTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( std::move ( from ) ), std::move ( to ) ); } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::removeTransition ( const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > & lhs, const StateType & rhs) { auto upper_bound = transitions.upper_bound ( lhs ); auto lower_bound = transitions.lower_bound ( lhs ); auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == rhs; } ); if ( iter == upper_bound ) return false; transitions.erase ( iter ); return true; } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::removeTransition ( const common::ranked_symbol < SymbolType > & symbol, const ext::vector < StateType > & prevStates, const StateType & next ) { return removeTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) ) ), std::move ( next ) ); } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::removeTransition ( const StateType & from, const StateType & to ) { return removeTransition ( ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( std::move ( from ) ), std::move ( to ) ); } template<class SymbolType, class StateType > ext::multimap < StateType, StateType > EpsilonNFTA < SymbolType, StateType >::getEpsilonTransitions ( ) const { ext::multimap < StateType, StateType > result; for ( const std::pair < const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & transition : transitions ) if ( transition.first.template is < StateType > ( ) ) result.insert ( transition.first.template get < StateType > ( ), transition.second ); return result; } template<class SymbolType, class StateType > ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > >, StateType > EpsilonNFTA < SymbolType, StateType >::getSymbolTransitions ( ) const { ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > >, StateType > result; for ( const std::pair < const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & transition : transitions ) { if ( transition.first.template is < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ) ) { const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = transition.first.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); result.insert ( source, transition.second ); } } return result; } template<class SymbolType, class StateType > ext::multimap < StateType, StateType > EpsilonNFTA < SymbolType, StateType >::getEpsilonTransitionsFromState ( const StateType & from ) const { if ( !getStates ( ).contains ( from ) ) throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist" ); ext::multimap < StateType, StateType > res; for ( const auto & transition : transitions.equal_range ( from ) ) res.insert ( from, transition.second ); return res; } template<class SymbolType, class StateType > ext::multimap < StateType, StateType > EpsilonNFTA < SymbolType, StateType >::getEpsilonTransitionsToState ( const StateType & to ) const { if ( !getStates ( ).contains ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist" ); ext::multimap < StateType, StateType > res; for ( const auto & transition : transitions ) if ( transition.second == to && transition.first.template is < StateType > ( ) ) res.insert ( transition.first.template get < StateType > ( ), to ); return res; } template<class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::isEpsilonFree ( ) const { for ( const std::pair < const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & transition : transitions ) if ( transition.first.template is < StateType > ( ) ) return false; return true; } template < class SymbolType, class StateType > bool EpsilonNFTA < SymbolType, StateType >::isDeterministic() const { if ( transitions.empty ( ) ) return true; for ( auto iter = transitions.begin ( ); std::next ( iter ) != transitions.end ( ); ++ iter ) if ( iter->first == std::next ( iter )->first ) return false; return isEpsilonFree ( ); } template < class SymbolType, class StateType > EpsilonNFTA < SymbolType, StateType >::operator std::string ( ) const { std::stringstream ss; ss << *this; return ss.str(); } } /* namespace automaton */ namespace core { /** * Helper class specifying constraints for the automaton's internal input alphabet component. * * \tparam SymbolType used for the symbol part of the ranked symbol * \tparam StateType used for the terminal alphabet of the automaton. */ template < class SymbolType, class StateType > class SetConstraint< automaton::EpsilonNFTA < SymbolType, StateType >, common::ranked_symbol < SymbolType >, automaton::InputAlphabet > { public: /** * Returns true if the symbol is still used in some transition of the automaton. * * \param automaton the tested automaton * \param symbol the tested symbol * * \returns true if the symbol is used, false othervise */ static bool used ( const automaton::EpsilonNFTA < SymbolType, StateType > & automaton, const common::ranked_symbol < SymbolType > & symbol ) { for ( const std::pair < const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & t : automaton.getTransitions()) if ( t.first.template is < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ) ) { const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = t.first.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); if ( source.first == symbol) return true; } return false; } /** * Returns true as all symbols are possibly available to be elements of the input alphabet. * * \param automaton the tested automaton * \param symbol the tested symbol * * \returns true */ static bool available ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { return true; } /** * All symbols are valid as input symbols. * * \param automaton the tested automaton * \param symbol the tested symbol */ static void valid ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { } }; /** * Helper class specifying constraints for the automaton's internal states component. * * \tparam SymbolType used for the symbol part of the ranked symbol * \tparam StateType used for the terminal alphabet of the automaton. */ template < class SymbolType, class StateType > class SetConstraint< automaton::EpsilonNFTA < SymbolType, StateType >, StateType, automaton::States > { public: /** * Returns true if the state is still used in some transition of the automaton. * * \param automaton the tested automaton * \param state the tested state * * \returns true if the state is used, false othervise */ static bool used ( const automaton::EpsilonNFTA < SymbolType, StateType > & automaton, const StateType & state ) { if ( automaton.getFinalStates ( ).contains ( state ) ) return true; for ( const std::pair < const ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > & t : automaton.getTransitions ( ) ) { if ( t.first.template is < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ) ) { const ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = t.first.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); if ( ext::contains ( source.second.begin ( ), source.second.end ( ), state ) ) { return true; } } if ( t.first.template is < StateType > ( ) ) { if ( t.first.template get < StateType > ( ) == state ) { return true; } } if ( t . second == state ) { return true; } } return false; } /** * Returns true as all states are possibly available to be elements of the states. * * \param automaton the tested automaton * \param state the tested state * * \returns true */ static bool available ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const StateType & ) { return true; } /** * All states are valid as a state of the automaton. * * \param automaton the tested automaton * \param state the tested state */ static void valid ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const StateType & ) { } }; /** * Helper class specifying constraints for the automaton's internal final states component. * * \tparam SymbolType used for the symbol part of the ranked symbol * \tparam StateType used for the terminal alphabet of the automaton. */ template < class SymbolType, class StateType > class SetConstraint< automaton::EpsilonNFTA < SymbolType, StateType >, StateType, automaton::FinalStates > { public: /** * Returns false. Final state is only a mark that the automaton itself does require further. * * \param automaton the tested automaton * \param state the tested state * * \returns false */ static bool used ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const StateType & ) { return false; } /** * Determines whether the state is available in the automaton's states set. * * \param automaton the tested automaton * \param state the tested state * * \returns true if the state is already in the set of states of the automaton */ static bool available ( const automaton::EpsilonNFTA < SymbolType, StateType > & automaton, const StateType & state ) { return automaton.template accessComponent < automaton::States > ( ).get ( ).contains ( state ); } /** * All states are valid as a final state of the automaton. * * \param automaton the tested automaton * \param state the tested state */ static void valid ( const automaton::EpsilonNFTA < SymbolType, StateType > &, const StateType & ) { } }; /** * Helper for normalisation of types specified by templates used as internal datatypes of symbols and states. * * \returns new instance of the automaton with default template parameters or unmodified instance if the template parameters were already the default ones */ template < class SymbolType, class StateType > struct normalize < automaton::EpsilonNFTA < SymbolType, StateType > > { static automaton::EpsilonNFTA < > eval ( automaton::EpsilonNFTA < SymbolType, StateType > && value ) { ext::set < common::ranked_symbol < > > alphabet = alphabet::SymbolNormalize::normalizeRankedAlphabet ( std::move ( value ).getInputAlphabet ( ) ); ext::set < DefaultStateType > states = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getStates ( ) ); ext::set < DefaultStateType > finalStates = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getFinalStates ( ) ); automaton::EpsilonNFTA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( finalStates ) ); for ( std::pair < ext::variant < StateType, ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) ); if ( transition.first.template is < StateType > ( ) ) { DefaultStateType from = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.first.template get < StateType > ( ) ) ); res.addTransition ( from, to ); } else { ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > & source = transition.first.template get < ext::pair < common::ranked_symbol < SymbolType >, ext::vector < StateType > > > ( ); common::ranked_symbol < DefaultSymbolType > input = alphabet::SymbolNormalize::normalizeRankedSymbol ( std::move ( source.first ) ); ext::vector < DefaultStateType > from = automaton::AutomatonNormalize::normalizeStates ( std::move ( source.second ) ); res.addTransition ( std::move ( input ), std::move ( from ), std::move ( to ) ); } } return res; } }; } /* namespace core */ extern template class automaton::EpsilonNFTA < >;