diff --git a/alib2data/src/automaton/FSM/CompactNFA.cpp b/alib2data/src/automaton/FSM/CompactNFA.cpp index 1643f72c75a9544370d4cd85ca64117e1d1c527b..d96f3160353eef815a5a425627c89b64a514cf88 100644 --- a/alib2data/src/automaton/FSM/CompactNFA.cpp +++ b/alib2data/src/automaton/FSM/CompactNFA.cpp @@ -25,14 +25,13 @@ namespace automaton { -CompactNFA::CompactNFA(State initialState) : SingleInitialState(std::move(initialState)) { +CompactNFA::CompactNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ) : std::Components < CompactNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::make_tuple ( std::move ( initialState ) ) ) { +} +CompactNFA::CompactNFA(State initialState) : CompactNFA( std::set<State> { initialState }, std::set < alphabet::Symbol > { }, initialState, std::set<State> {} ) { } -CompactNFA::CompactNFA(const EpsilonNFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +CompactNFA::CompactNFA(const EpsilonNFA& other) : CompactNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { if(transition.first.second.is<string::Epsilon>()) { std::pair<State, string::LinearString> key = std::make_pair(transition.first.first, string::LinearString( std::vector<alphabet::Symbol> { } )); @@ -44,10 +43,7 @@ CompactNFA::CompactNFA(const EpsilonNFA& other) : SingleInitialState(other.getIn } } -CompactNFA::CompactNFA(const MultiInitialStateNFA& other) : SingleInitialState(automaton::createUniqueState(automaton::State("q0"), other.getStates())) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +CompactNFA::CompactNFA(const MultiInitialStateNFA& other) : CompactNFA( other.getStates() + std::set < State > { automaton::createUniqueState(automaton::State("q0"), other.getStates()) }, other.getInputAlphabet(), automaton::createUniqueState(automaton::State("q0"), other.getStates()), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, string::LinearString> key = std::make_pair(transition.first.first, string::LinearString( std::vector<alphabet::Symbol> { transition.first.second} )); transitions[key] = transition.second; @@ -56,20 +52,14 @@ CompactNFA::CompactNFA(const MultiInitialStateNFA& other) : SingleInitialState(a transitions[key] = other.getInitialStates(); } -CompactNFA::CompactNFA(const NFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +CompactNFA::CompactNFA(const NFA& other) : CompactNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, string::LinearString> key = std::make_pair(transition.first.first, string::LinearString( std::vector<alphabet::Symbol> { transition.first.second} )); transitions[key] = transition.second; } } -CompactNFA::CompactNFA(const DFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +CompactNFA::CompactNFA(const DFA& other) : CompactNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, string::LinearString> key = std::make_pair(transition.first.first, string::LinearString( std::vector<alphabet::Symbol> { transition.first.second} )); transitions[key].insert(transition.second); @@ -84,43 +74,17 @@ AutomatonBase* CompactNFA::plunder() && { return new CompactNFA(std::move(*this)); } -bool CompactNFA::removeState(const State& state) { - if (initialState == state) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, string::LinearString>, std::set<State> >& t : transitions) { - if (t.first.first == state || t.second.find(state) != t.second.end()) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool CompactNFA::removeInputSymbol(const alphabet::Symbol& symbol) { - for (const std::pair<const std::pair<State, string::LinearString>, std::set<State> >& transition : transitions) { - if (transition.first.second.getAlphabet().count(symbol) == 1) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); -} - bool CompactNFA::addTransition(State from, string::LinearString input, State to) { - if (states.find(from) == states.end()) + if (!getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); const std::set<alphabet::Symbol>& inputStringAlphabet = input.getAlphabet(); // Transition regexp's alphabet must be subset of automaton's alphabet - if (inputStringAlphabet.size() > 0 && ! std::includes(inputAlphabet.begin(), inputAlphabet.end(), inputStringAlphabet.begin(), inputStringAlphabet.end())) + if (! std::includes(getInputAlphabet().begin(), getInputAlphabet().end(), inputStringAlphabet.begin(), inputStringAlphabet.end())) throw AutomatonException("Input string is over different alphabet than automaton"); - if (states.find(to) == states.end()) + if (!getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, string::LinearString> key = std::make_pair(std::move(from), std::move(input)); @@ -139,7 +103,7 @@ const std::map<std::pair<State, string::LinearString>, std::set<State>>& Compact } std::map<std::pair<State, string::LinearString>, std::set<State>> CompactNFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, string::LinearString>, std::set<State>> transitionsFromState; @@ -153,7 +117,7 @@ std::map<std::pair<State, string::LinearString>, std::set<State>> CompactNFA::ge } std::map<std::pair<State, string::LinearString>, std::set<State>> CompactNFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, string::LinearString>, std::set<State>> transitionsToState; @@ -167,8 +131,8 @@ std::map<std::pair<State, string::LinearString>, std::set<State>> CompactNFA::ge } int CompactNFA::compare(const CompactNFA& other) const { - auto first = std::tie(states, inputAlphabet, initialState, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialState, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialState(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates(), other.getTransitions()); std::compare<decltype(first)> comp; return comp(first, second); @@ -176,10 +140,10 @@ int CompactNFA::compare(const CompactNFA& other) const { void CompactNFA::operator>>(std::ostream& out) const { out << "(CompactNFA " - << "states = " << states - << "inputAlphabet = " << inputAlphabet - << "initialState = " << initialState - << "finalStates = " << finalStates + << "states = " << getStates() + << "inputAlphabet = " << getInputAlphabet() + << "initialState = " << getInitialState() + << "finalStates = " << getFinalStates() << "transitions = " << transitions << ")"; } @@ -252,6 +216,83 @@ void CompactNFA::composeTransitions(std::deque<sax::Token>& out) const { } /* namespace automaton */ +namespace std { + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::CompactNFA * automaton = static_cast < const automaton::CompactNFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, ::string::LinearString>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.second.getAlphabet().count(symbol)) + return true; + + return false; +} + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::CompactNFA::Component < automaton::CompactNFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::CompactNFA * automaton = static_cast < const automaton::CompactNFA * > ( this ); + + if (automaton->getInitialState() == state) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, ::string::LinearString>, std::set<automaton::State> >& t : automaton->getTransitions()) + if (t.first.first == state || t.second.count(state)) + return true; + + return false; +} + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::CompactNFA * automaton = static_cast < const automaton::CompactNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::CompactNFA::Component < automaton::CompactNFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::CompactNFA::Element < automaton::CompactNFA, automaton::State, automaton::InitialState >::available ( const automaton::State & state ) const { + const automaton::CompactNFA * automaton = static_cast < const automaton::CompactNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::CompactNFA::Element < automaton::CompactNFA, automaton::State, automaton::InitialState >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto compactNFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::CompactNFA>(); diff --git a/alib2data/src/automaton/FSM/CompactNFA.h b/alib2data/src/automaton/FSM/CompactNFA.h index 2db30c83de60754a5c3568b37a9d5110e8758050..ea33c4a1f8a965a9030339355bb1e287f67094ae 100644 --- a/alib2data/src/automaton/FSM/CompactNFA.h +++ b/alib2data/src/automaton/FSM/CompactNFA.h @@ -9,9 +9,10 @@ #define COMPACT_DFA_H_ #include <map> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/SingleInitialState.h" -#include "../common/InputAlphabet.h" +#include "../common/State.h" +#include "../../alphabet/Symbol.h" #include "../../string/LinearString.h" #include "EpsilonNFA.h" #include "MultiInitialStateNFA.h" @@ -24,12 +25,18 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton without epsilon transitions. */ -class CompactNFA : public AutomatonBase, public SingleInitialState, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialState; + +class CompactNFA : public AutomatonBase, public std::Components < CompactNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > { protected: std::map < std::pair < State, string::LinearString >, std::set < State > > transitions; public: explicit CompactNFA ( State initialState ); + explicit CompactNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ); explicit CompactNFA ( const EpsilonNFA & other ); explicit CompactNFA ( const MultiInitialStateNFA & other ); explicit CompactNFA ( const NFA & other ); @@ -39,15 +46,65 @@ public: virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const State & getInitialState ( ) const { + return accessElement < InitialState > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool setInitialState ( State state ) { + return accessElement < InitialState > ( ).set ( std::move ( state ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton. diff --git a/alib2data/src/automaton/FSM/DFA.cpp b/alib2data/src/automaton/FSM/DFA.cpp index 4bd23c2ca675612e720b0984113d12b0ea36f91e..f0573fdd8578cdd850fe697357ae5fd2a30727f5 100644 --- a/alib2data/src/automaton/FSM/DFA.cpp +++ b/alib2data/src/automaton/FSM/DFA.cpp @@ -19,8 +19,10 @@ namespace automaton { -DFA::DFA(State initialState) : SingleInitialState(std::move(initialState)) { +DFA::DFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ) : std::Components < DFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::make_tuple ( std::move ( initialState ) ) ) { +} +DFA::DFA(State initialState) : DFA( std::set<State> { initialState }, std::set < alphabet::Symbol > { }, initialState, std::set<State> {} ) { } AutomatonBase* DFA::clone() const { @@ -31,41 +33,14 @@ AutomatonBase* DFA::plunder() && { return new DFA(std::move(*this)); } -bool DFA::removeState(const State& state) { - if (initialState == state) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, alphabet::Symbol>, State>& t : transitions) { - if (t.first.first == state || t.second == state) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool DFA::removeInputSymbol(const alphabet::Symbol& symbol) { - for (const std::pair<const std::pair<State, alphabet::Symbol>, State>& transition : transitions) { - if (transition.first.second == symbol) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); - -} - bool DFA::addTransition(State from, alphabet::Symbol input, State to) { - if (states.find(from) == states.end()) + if (!getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); - if (inputAlphabet.find(input) == inputAlphabet.end()) + if (!getInputAlphabet().count(input)) throw AutomatonException("Input symbol \"" + (std::string) input + "\" doesn't exist."); - if (states.find(to) == states.end()) + if (!getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, alphabet::Symbol> key = std::make_pair(std::move(from), std::move(input)); @@ -103,7 +78,7 @@ const std::map<std::pair<State, alphabet::Symbol>, State>& DFA::getTransitions() } std::map<std::pair<State, alphabet::Symbol>, State> DFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, State> transitionsFromState; @@ -117,7 +92,7 @@ std::map<std::pair<State, alphabet::Symbol>, State> DFA::getTransitionsFromState } std::map<std::pair<State, alphabet::Symbol>, State> DFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, State> transitionsToState; @@ -131,12 +106,12 @@ std::map<std::pair<State, alphabet::Symbol>, State> DFA::getTransitionsToState(c } bool DFA::isTotal() const { - return transitions.size() == inputAlphabet.size() * states.size(); + return transitions.size() == getInputAlphabet().size() * getStates().size(); } int DFA::compare(const DFA& other) const { - auto first = std::tie(states, inputAlphabet, initialState, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialState, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialState(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates(), other.transitions); std::compare<decltype(first)> comp; return comp(first, second); @@ -144,10 +119,10 @@ int DFA::compare(const DFA& other) const { void DFA::operator>>(std::ostream& out) const { out << "(DFA " - << " states = " << states - << " inputAlphabet = " << inputAlphabet - << " initialState = " << initialState - << " finalStates = " << finalStates + << " states = " << getStates() + << " inputAlphabet = " << getInputAlphabet() + << " initialState = " << getInitialState() + << " finalStates = " << getFinalStates() << " transitions = " << transitions << ")"; } @@ -218,6 +193,83 @@ void DFA::composeTransitions(std::deque<sax::Token>& out) const { } /* namespace automaton */ +namespace std { + +template < > +bool automaton::DFA::Component < automaton::DFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::DFA * automaton = static_cast < const automaton::DFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, automaton::State>& transition : automaton->getTransitions()) + if (transition.first.second == symbol) + return true; + + return false; +} + +template < > +bool automaton::DFA::Component < automaton::DFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::DFA::Component < automaton::DFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::DFA::Component < automaton::DFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::DFA * automaton = static_cast < const automaton::DFA * > ( this ); + + if (automaton->getInitialState() == state) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, automaton::State>& t : automaton->getTransitions()) + if (t.first.first == state || t.second == state) + return true; + + return false; +} + +template < > +bool automaton::DFA::Component < automaton::DFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::DFA::Component < automaton::DFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::DFA::Component < automaton::DFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::DFA::Component < automaton::DFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::DFA * automaton = static_cast < const automaton::DFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::DFA::Component < automaton::DFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::DFA::Element < automaton::DFA, automaton::State, automaton::InitialState >::available ( const automaton::State & state ) const { + const automaton::DFA * automaton = static_cast < const automaton::DFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::DFA::Element < automaton::DFA, automaton::State, automaton::InitialState >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto DFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::DFA>(); diff --git a/alib2data/src/automaton/FSM/DFA.h b/alib2data/src/automaton/FSM/DFA.h index 58492d91102fe6456c78b9ca77d624308e5b1de8..7e44337a2ba1f3f94b702f351f0aa98ddd6687c5 100644 --- a/alib2data/src/automaton/FSM/DFA.h +++ b/alib2data/src/automaton/FSM/DFA.h @@ -9,9 +9,9 @@ #define DFA_H_ #include <map> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/SingleInitialState.h" -#include "../common/InputAlphabet.h" +#include "../common/State.h" #include "../../alphabet/Symbol.h" namespace automaton { @@ -20,26 +20,82 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton without epsilon transitions. */ -class DFA : public AutomatonBase, public SingleInitialState, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialState; + +class DFA : public AutomatonBase, public std::Components < DFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > { protected: std::map < std::pair < State, alphabet::Symbol >, State > transitions; public: explicit DFA ( State initialState ); + explicit DFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ); virtual AutomatonBase * clone ( ) const; virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const State & getInitialState ( ) const { + return accessElement < InitialState > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool setInitialState ( State state ) { + return accessElement < InitialState > ( ).set ( std::move ( state ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton. diff --git a/alib2data/src/automaton/FSM/EpsilonNFA.cpp b/alib2data/src/automaton/FSM/EpsilonNFA.cpp index 0b9650f32711fac3c2372a8c014b761bd76cf37e..2883e75db922250a3e099cb47712cd5a4504965b 100644 --- a/alib2data/src/automaton/FSM/EpsilonNFA.cpp +++ b/alib2data/src/automaton/FSM/EpsilonNFA.cpp @@ -24,37 +24,29 @@ namespace automaton { -EpsilonNFA::EpsilonNFA(State initialState) : SingleInitialState(std::move(initialState)) { +EpsilonNFA::EpsilonNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ) : std::Components < EpsilonNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::make_tuple ( std::move ( initialState ) ) ) { +} +EpsilonNFA::EpsilonNFA(State initialState) : EpsilonNFA( std::set<State> { initialState }, std::set < alphabet::Symbol > { }, initialState, std::set<State> {} ) { } -EpsilonNFA::EpsilonNFA(const MultiInitialStateNFA& other) : SingleInitialState(automaton::createUniqueState(automaton::State("q0"), other.getStates())) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +EpsilonNFA::EpsilonNFA(const MultiInitialStateNFA& other) : EpsilonNFA( other.getStates() + std::set < State > { automaton::createUniqueState(automaton::State("q0"), other.getStates()) }, other.getInputAlphabet(), automaton::createUniqueState(automaton::State("q0"), other.getStates()), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(transition.first.first, std::variant<string::Epsilon, alphabet::Symbol>(transition.first.second)); transitions[key] = transition.second; } std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(this->getInitialState(), std::variant<string::Epsilon, alphabet::Symbol>(string::Epsilon::EPSILON)); transitions[key] = other.getInitialStates(); - } -EpsilonNFA::EpsilonNFA(const NFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +EpsilonNFA::EpsilonNFA(const NFA& other) : EpsilonNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(transition.first.first, std::variant<string::Epsilon, alphabet::Symbol>(transition.first.second)); transitions[key] = transition.second; } } -EpsilonNFA::EpsilonNFA(const DFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +EpsilonNFA::EpsilonNFA(const DFA& other) : EpsilonNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(transition.first.first, std::variant<string::Epsilon, alphabet::Symbol>(transition.first.second)); transitions[key].insert(transition.second); @@ -69,41 +61,14 @@ AutomatonBase* EpsilonNFA::plunder() && { return new EpsilonNFA(std::move(*this)); } -bool EpsilonNFA::removeState(const State& state) { - if (initialState == state) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) { - if (transition.first.first == state || transition.second.find(state) != transition.second.end()) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool EpsilonNFA::removeInputSymbol(const alphabet::Symbol& symbol) { - std::variant<string::Epsilon, alphabet::Symbol> inputVariant(symbol); - for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) { - if (transition.first.second.is<alphabet::Symbol>() && transition.first.second.get<alphabet::Symbol>() == symbol) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); -} - bool EpsilonNFA::addTransition(State from, std::variant<string::Epsilon, alphabet::Symbol> input, State to) { - if (states.find(from) == states.end()) + if (! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); - if (input.is<alphabet::Symbol>() && inputAlphabet.find(input.get<alphabet::Symbol>()) == inputAlphabet.end()) + if (input.is<alphabet::Symbol>() && ! getInputAlphabet().count(input.get<alphabet::Symbol>())) throw AutomatonException("Input symbol \"" + (std::string) input.get<alphabet::Symbol>() + "\" doesn't exist."); - if (states.find(to) == states.end()) + if (! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(std::move(from), std::move(input)); @@ -158,7 +123,7 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > EpsilonNFA::getSy } std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> > EpsilonNFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> > transitionsFromState; @@ -171,7 +136,7 @@ std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std } std::map<State, std::set<State> > EpsilonNFA::getEpsilonTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key(from, std::variant<string::Epsilon, alphabet::Symbol>(string::Epsilon::EPSILON)); @@ -183,7 +148,7 @@ std::map<State, std::set<State> > EpsilonNFA::getEpsilonTransitionsFromState(con } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > EpsilonNFA::getSymbolTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsFromState; @@ -196,7 +161,7 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > EpsilonNFA::getSy } std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> > EpsilonNFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> > transitionsToState; @@ -209,7 +174,7 @@ std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std } std::map<State, std::set<State> > EpsilonNFA::getEpsilonTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<State, std::set<State> > transitionsToState; @@ -222,7 +187,7 @@ std::map<State, std::set<State> > EpsilonNFA::getEpsilonTransitionsToState(const } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > EpsilonNFA::getSymbolTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsToState; @@ -235,29 +200,28 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > EpsilonNFA::getSy } bool EpsilonNFA::isEpsilonFree() const { - for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) { + for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) if (transition.first.second.is<string::Epsilon>()) return false; - } + return true; } bool EpsilonNFA::isDeterministic() const { - for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) { - if (transition.second.size() != 1 || transition.second.size() != 0) + for (const std::pair<const std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >& transition : transitions) + if (transition.second.size() > 1) return false; - } - return true; + return isEpsilonFree(); } bool EpsilonNFA::isTotal() const { - return isDeterministic() && transitions.size() == inputAlphabet.size() * states.size(); + return isDeterministic() && transitions.size() == getInputAlphabet().size() * getStates().size(); } int EpsilonNFA::compare(const EpsilonNFA& other) const { - auto first = std::tie(states, inputAlphabet, initialState, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialState, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialState(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates(), other.getTransitions()); std::compare<decltype(first)> comp; return comp(first, second); @@ -265,11 +229,11 @@ int EpsilonNFA::compare(const EpsilonNFA& other) const { void EpsilonNFA::operator>>(std::ostream& out) const { out << "(EpsilonNFA " - << " states = " << states - << " inputAlphabet = " << inputAlphabet - << " initialState = " << initialState - << " finalStates = " << finalStates - << " transitions = " << transitions + << "states = " << getStates() + << "inputAlphabet = " << getInputAlphabet() + << "initialState = " << getInitialState() + << "finalStates = " << getFinalStates() + << "transitions = " << transitions << ")"; } @@ -341,6 +305,83 @@ void EpsilonNFA::composeTransitions(std::deque<sax::Token>& out) const { } /* namespace automaton */ +namespace std { + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::EpsilonNFA * automaton = static_cast < const automaton::EpsilonNFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, std::variant<::string::Epsilon, alphabet::Symbol> >, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.second.is<alphabet::Symbol>() && transition.first.second.get<alphabet::Symbol>() == symbol) + return true; + + return false; +} + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::EpsilonNFA::Component < automaton::EpsilonNFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::EpsilonNFA * automaton = static_cast < const automaton::EpsilonNFA * > ( this ); + + if (automaton->getInitialState() == state) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, std::variant<::string::Epsilon, alphabet::Symbol> >, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.first == state || transition.second.count(state)) + return true; + + return false; +} + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::EpsilonNFA * automaton = static_cast < const automaton::EpsilonNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::EpsilonNFA::Component < automaton::EpsilonNFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::EpsilonNFA::Element < automaton::EpsilonNFA, automaton::State, automaton::InitialState >::available ( const automaton::State & state ) const { + const automaton::EpsilonNFA * automaton = static_cast < const automaton::EpsilonNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::EpsilonNFA::Element < automaton::EpsilonNFA, automaton::State, automaton::InitialState >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto epsilonNFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::EpsilonNFA>(); diff --git a/alib2data/src/automaton/FSM/EpsilonNFA.h b/alib2data/src/automaton/FSM/EpsilonNFA.h index c517ff37cb4c7c2c536776ecd41ed5cf8fd6040e..86ac789ac9b819a490a11d9018905714893a29c5 100644 --- a/alib2data/src/automaton/FSM/EpsilonNFA.h +++ b/alib2data/src/automaton/FSM/EpsilonNFA.h @@ -10,9 +10,8 @@ #include <map> #include <variant> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/SingleInitialState.h" -#include "../common/InputAlphabet.h" #include "../../alphabet/Symbol.h" #include "../../string/Epsilon.h" #include "MultiInitialStateNFA.h" @@ -25,12 +24,18 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton with epsilon transitions. */ -class EpsilonNFA : public AutomatonBase, public SingleInitialState, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialState; + +class EpsilonNFA : public AutomatonBase, public std::Components < EpsilonNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > { protected: std::map < std::pair < State, std::variant < string::Epsilon, alphabet::Symbol > >, std::set < State > > transitions; public: explicit EpsilonNFA ( State initialState ); + explicit EpsilonNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ); explicit EpsilonNFA ( const MultiInitialStateNFA & other ); explicit EpsilonNFA ( const NFA & other ); explicit EpsilonNFA ( const DFA & other ); @@ -39,15 +44,65 @@ public: virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const State & getInitialState ( ) const { + return accessElement < InitialState > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool setInitialState ( State state ) { + return accessElement < InitialState > ( ).set ( std::move ( state ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton. diff --git a/alib2data/src/automaton/FSM/ExtendedNFA.cpp b/alib2data/src/automaton/FSM/ExtendedNFA.cpp index 225c48e1fd8ab450c93878c789cee47c104c8eab..a7ef321addacd0487a5c2c55da0e30eb4d496f91 100644 --- a/alib2data/src/automaton/FSM/ExtendedNFA.cpp +++ b/alib2data/src/automaton/FSM/ExtendedNFA.cpp @@ -28,24 +28,20 @@ namespace automaton { -ExtendedNFA::ExtendedNFA(State initialState) : SingleInitialState(std::move(initialState)) { +ExtendedNFA::ExtendedNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ) : std::Components < ExtendedNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::make_tuple ( std::move ( initialState ) ) ) { +} +ExtendedNFA::ExtendedNFA(State initialState) : ExtendedNFA( std::set<State> { initialState }, std::set < alphabet::Symbol > { }, initialState, std::set<State> {} ) { } -ExtendedNFA::ExtendedNFA(const CompactNFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +ExtendedNFA::ExtendedNFA(const CompactNFA& other) : ExtendedNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, regexp::RegExp> key = std::make_pair(transition.first.first, regexp::RegExp( regexp::regexpFrom ( transition.first.second ))); transitions[key] = transition.second; } } -ExtendedNFA::ExtendedNFA(const EpsilonNFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +ExtendedNFA::ExtendedNFA(const EpsilonNFA& other) : ExtendedNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { if(transition.first.second.is<string::Epsilon>()) { std::pair<State, regexp::RegExp> key = std::make_pair(transition.first.first, regexp::RegExp( regexp::regexpFrom ( string::LinearString( std::vector<alphabet::Symbol> { } ) ))); @@ -57,10 +53,7 @@ ExtendedNFA::ExtendedNFA(const EpsilonNFA& other) : SingleInitialState(other.get } } -ExtendedNFA::ExtendedNFA(const MultiInitialStateNFA& other) : SingleInitialState(automaton::createUniqueState(automaton::State("q0"), other.getStates())) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +ExtendedNFA::ExtendedNFA(const MultiInitialStateNFA& other) : ExtendedNFA( other.getStates() + std::set < State > { automaton::createUniqueState(automaton::State("q0"), other.getStates()) }, other.getInputAlphabet(), automaton::createUniqueState(automaton::State("q0"), other.getStates()), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, regexp::RegExp> key = std::make_pair(transition.first.first, regexp::RegExp( regexp::regexpFrom ( transition.first.second ))); transitions[key] = transition.second; @@ -69,20 +62,14 @@ ExtendedNFA::ExtendedNFA(const MultiInitialStateNFA& other) : SingleInitialState transitions[key] = other.getInitialStates(); } -ExtendedNFA::ExtendedNFA(const NFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +ExtendedNFA::ExtendedNFA(const NFA& other) : ExtendedNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, regexp::RegExp> key = std::make_pair(transition.first.first, regexp::RegExp( regexp::regexpFrom ( transition.first.second ))); transitions[key] = transition.second; } } -ExtendedNFA::ExtendedNFA(const DFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +ExtendedNFA::ExtendedNFA(const DFA& other) : ExtendedNFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { std::pair<State, regexp::RegExp> key = std::make_pair(transition.first.first, regexp::RegExp( regexp::regexpFrom ( transition.first.second ))); transitions[key].insert(transition.second); @@ -97,43 +84,17 @@ AutomatonBase* ExtendedNFA::plunder() && { return new ExtendedNFA(std::move(*this)); } -bool ExtendedNFA::removeState(const State& state) { - if (initialState == state) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, regexp::RegExp>, std::set<State> >& transition : transitions) { - if (transition.first.first == state || transition.second.find(state) != transition.second.end()) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool ExtendedNFA::removeInputSymbol(const alphabet::Symbol& symbol) { - for (const std::pair<const std::pair<State, regexp::RegExp>, std::set<State> >& transition : transitions) { - if (transition.first.second.getAlphabet().count(symbol) == 1) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); -} - bool ExtendedNFA::addTransition(State from, regexp::RegExp input, State to) { - if (states.find(from) == states.end()) + if ( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); const std::set<alphabet::Symbol>& inputRegExpAlphabet = input.getAlphabet(); // Transition regexp's alphabet must be subset of automaton's alphabet - if (inputRegExpAlphabet.size() > 0 && ! std::includes(inputAlphabet.begin(), inputAlphabet.end(), inputRegExpAlphabet.begin(), inputRegExpAlphabet.end())) + if (! std::includes(getInputAlphabet().begin(), getInputAlphabet().end(), inputRegExpAlphabet.begin(), inputRegExpAlphabet.end())) throw AutomatonException("Input string is over different alphabet than automaton"); - if (states.find(to) == states.end()) + if (! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, regexp::RegExp> key = std::make_pair(std::move(from), std::move(input)); @@ -152,7 +113,7 @@ const std::map<std::pair<State, regexp::RegExp>, std::set<State> >& ExtendedNFA: } std::map<std::pair<State, regexp::RegExp>, std::set<State> > ExtendedNFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, regexp::RegExp>, std::set<State>> transitionsFromState; @@ -165,7 +126,7 @@ std::map<std::pair<State, regexp::RegExp>, std::set<State> > ExtendedNFA::getTra } std::map<std::pair<State, regexp::RegExp>, std::set<State> > ExtendedNFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, regexp::RegExp>, std::set<State>> transitionsToState; @@ -178,8 +139,8 @@ std::map<std::pair<State, regexp::RegExp>, std::set<State> > ExtendedNFA::getTra } int ExtendedNFA::compare(const ExtendedNFA& other) const { - auto first = std::tie(states, inputAlphabet, initialState, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialState, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialState(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates(), other.getTransitions()); std::compare<decltype(first)> comp; return comp(first, second); @@ -187,11 +148,11 @@ int ExtendedNFA::compare(const ExtendedNFA& other) const { void ExtendedNFA::operator>>(std::ostream& out) const { out << "(ExtendedNFA " - << " states = " << states - << " inputAlphabet = " << inputAlphabet - << " initialState = " << initialState - << " finalStates = " << finalStates - << " transitions = " << transitions + << "states = " << getStates() + << "inputAlphabet = " << getInputAlphabet() + << "initialState = " << getInitialState() + << "finalStates = " << getFinalStates() + << "transitions = " << transitions << ")"; } @@ -263,6 +224,83 @@ void ExtendedNFA::composeTransitions(std::deque<sax::Token>& out) const { } /* namespace automaton */ +namespace std { + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::ExtendedNFA * automaton = static_cast < const automaton::ExtendedNFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, regexp::RegExp>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.second.getAlphabet().count(symbol) == 1) + return true; + + return false; +} + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::ExtendedNFA::Component < automaton::ExtendedNFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::ExtendedNFA * automaton = static_cast < const automaton::ExtendedNFA * > ( this ); + + if (automaton->getInitialState() == state) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, regexp::RegExp>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.first == state || transition.second.find(state) != transition.second.end()) + return true; + + return false; +} + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::ExtendedNFA * automaton = static_cast < const automaton::ExtendedNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::ExtendedNFA::Component < automaton::ExtendedNFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::ExtendedNFA::Element < automaton::ExtendedNFA, automaton::State, automaton::InitialState >::available ( const automaton::State & state ) const { + const automaton::ExtendedNFA * automaton = static_cast < const automaton::ExtendedNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::ExtendedNFA::Element < automaton::ExtendedNFA, automaton::State, automaton::InitialState >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto extendedNFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::ExtendedNFA>(); diff --git a/alib2data/src/automaton/FSM/ExtendedNFA.h b/alib2data/src/automaton/FSM/ExtendedNFA.h index 59213e0c62f076aafa4b7abf74d8690dbaa4ff0a..4417b6b799fb67c8bdefffdf973da590f51f0ec1 100644 --- a/alib2data/src/automaton/FSM/ExtendedNFA.h +++ b/alib2data/src/automaton/FSM/ExtendedNFA.h @@ -9,9 +9,9 @@ #define EXTENDED_NFA_H_ #include <map> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/SingleInitialState.h" -#include "../common/InputAlphabet.h" +#include "../common/State.h" #include "../../regexp/RegExp.h" #include "CompactNFA.h" #include "EpsilonNFA.h" @@ -25,12 +25,18 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton without epsilon transitions. */ -class ExtendedNFA : public AutomatonBase, public SingleInitialState, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialState; + +class ExtendedNFA : public AutomatonBase, public std::Components < ExtendedNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > { protected: std::map < std::pair < State, regexp::RegExp >, std::set < State > > transitions; public: explicit ExtendedNFA ( State initialState ); + explicit ExtendedNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ); explicit ExtendedNFA ( const CompactNFA & other ); explicit ExtendedNFA ( const EpsilonNFA & other ); explicit ExtendedNFA ( const MultiInitialStateNFA & other ); @@ -41,15 +47,65 @@ public: virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const State & getInitialState ( ) const { + return accessElement < InitialState > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool setInitialState ( State state ) { + return accessElement < InitialState > ( ).set ( std::move ( state ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton. diff --git a/alib2data/src/automaton/FSM/MultiInitialStateNFA.cpp b/alib2data/src/automaton/FSM/MultiInitialStateNFA.cpp index 80dcbd1b452fe1e1a3a49ecea449ba77ebe8780f..d7c1efcdefa1348f4aeea7a423a01be1c4cbae34 100644 --- a/alib2data/src/automaton/FSM/MultiInitialStateNFA.cpp +++ b/alib2data/src/automaton/FSM/MultiInitialStateNFA.cpp @@ -22,25 +22,19 @@ namespace automaton { -MultiInitialStateNFA::MultiInitialStateNFA() { +MultiInitialStateNFA::MultiInitialStateNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, std::set < State > initialStates, std::set < State > finalStates ) : std::Components < MultiInitialStateNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates, InitialStates >, std::tuple < > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ), std::move ( initialStates ) ), std::tuple < > ( ) ) { +} +MultiInitialStateNFA::MultiInitialStateNFA() : MultiInitialStateNFA( std::set<State> { }, std::set < alphabet::Symbol > { }, std::set < State > { } , std::set<State> {} ) { } -MultiInitialStateNFA::MultiInitialStateNFA(const DFA& other) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - initialStates = {other.getInitialState()}; - finalStates = other.getFinalStates(); +MultiInitialStateNFA::MultiInitialStateNFA(const DFA& other) : MultiInitialStateNFA( other.getStates(), other.getInputAlphabet(), { other.getInitialState() }, other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { transitions[transition.first].insert(transition.second); } } -MultiInitialStateNFA::MultiInitialStateNFA(const NFA& other) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - initialStates = {other.getInitialState()}; - finalStates = other.getFinalStates(); +MultiInitialStateNFA::MultiInitialStateNFA(const NFA& other) : MultiInitialStateNFA( other.getStates(), other.getInputAlphabet(), { other.getInitialState() }, other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { transitions[transition.first] = transition.second; } @@ -54,40 +48,14 @@ AutomatonBase* MultiInitialStateNFA::plunder() && { return new MultiInitialStateNFA(std::move(*this)); } -bool MultiInitialStateNFA::removeState(const State& state) { - if (initialStates.find(state) != initialStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.first.first == state || transition.second.find(state) != transition.second.end()) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool MultiInitialStateNFA::removeInputSymbol(const alphabet::Symbol& symbol) { - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.first.second == symbol) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); -} - bool MultiInitialStateNFA::addTransition(State from, alphabet::Symbol input, State to) { - if (states.find(from) == states.end()) + if (!getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); - if (inputAlphabet.find(input) == inputAlphabet.end()) + if (!getInputAlphabet().count(input)) throw AutomatonException("Input symbol \"" + (std::string) input + "\" doesn't exist."); - if (states.find(to) == states.end()) + if (!getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, alphabet::Symbol> key = std::make_pair(std::move(from), std::move(input)); @@ -106,7 +74,7 @@ const std::map<std::pair<State, alphabet::Symbol>, std::set<State> >& MultiIniti } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > MultiInitialStateNFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( ! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsFromState; @@ -119,7 +87,7 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > MultiInitialState } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > MultiInitialStateNFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( ! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsToState; @@ -132,20 +100,15 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > MultiInitialState } bool MultiInitialStateNFA::isDeterministic() const { - if (initialStates.size() != 1) { - return false; - } - - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.second.size() != 1 || transition.second.size() != 0) + for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) + if (transition.second.size() > 1) return false; - } - return true; + return getInitialStates().size() == 1; } bool MultiInitialStateNFA::isTotal() const { - return isDeterministic() && transitionsSize() == inputAlphabet.size() * states.size(); + return isDeterministic() && transitionsSize() == getInputAlphabet().size() * getStates().size(); } unsigned MultiInitialStateNFA::transitionsSize() const { @@ -157,8 +120,8 @@ unsigned MultiInitialStateNFA::transitionsSize() const { } int MultiInitialStateNFA::compare(const MultiInitialStateNFA& other) const { - auto first = std::tie(states, inputAlphabet, initialStates, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialStates, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialStates(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialStates(), other.getFinalStates(), other.getTransitions()); std::compare<decltype(first)> comp; return comp(first, second); @@ -166,11 +129,11 @@ int MultiInitialStateNFA::compare(const MultiInitialStateNFA& other) const { void MultiInitialStateNFA::operator>>(std::ostream& out) const { out << "(MultiInitialStateNFA " - << " states = " << states - << " inputAlphabet = " << inputAlphabet - << " initialStates = " << initialStates - << " finalStates = " << finalStates - << " transitions = " << transitions + << "states = " << getStates() + << "inputAlphabet = " << getInputAlphabet() + << "initialStates = " << getInitialStates() + << "finalStates = " << getFinalStates() + << "transitions = " << transitions << ")"; } @@ -243,6 +206,88 @@ void MultiInitialStateNFA::composeTransitions(std::deque<sax::Token>& out) const } /* namespace automaton */ +namespace std { + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::MultiInitialStateNFA * automaton = static_cast < const automaton::MultiInitialStateNFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.second == symbol) + return true; + + return false; +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::MultiInitialStateNFA * automaton = static_cast < const automaton::MultiInitialStateNFA * > ( this ); + + if (automaton->getInitialStates().count(state)) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.first == state || transition.second.find(state) != transition.second.end()) + return true; + + return false; +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::MultiInitialStateNFA * automaton = static_cast < const automaton::MultiInitialStateNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::InitialStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::InitialStates >::available ( const automaton::State & state ) const { + const automaton::MultiInitialStateNFA * automaton = static_cast < const automaton::MultiInitialStateNFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::MultiInitialStateNFA::Component < automaton::MultiInitialStateNFA, automaton::State, automaton::InitialStates >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto multiInitialStateNFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::MultiInitialStateNFA>(); diff --git a/alib2data/src/automaton/FSM/MultiInitialStateNFA.h b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h index 6d767fbec68138ad5305bfee54d939de0715f02f..2ab95aa0fb1478b0eea79d25dd61587aa9217547 100644 --- a/alib2data/src/automaton/FSM/MultiInitialStateNFA.h +++ b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h @@ -9,9 +9,9 @@ #define MULTI_INITIAL_STATE_NFA_H_ #include <map> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/MultiInitialStates.h" -#include "../common/InputAlphabet.h" +#include "../common/State.h" #include "../../alphabet/Symbol.h" #include "NFA.h" #include "DFA.h" @@ -22,12 +22,18 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton without epsilon transitions. */ -class MultiInitialStateNFA : public AutomatonBase, public MultiInitialStates, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialStates; + +class MultiInitialStateNFA : public AutomatonBase, public std::Components < MultiInitialStateNFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates, InitialStates >, std::tuple < > > { protected: std::map < std::pair < State, alphabet::Symbol >, std::set < State > > transitions; public: explicit MultiInitialStateNFA ( ); + explicit MultiInitialStateNFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, std::set < State > initialStates, std::set < State > finalStates ); explicit MultiInitialStateNFA ( const NFA & other ); explicit MultiInitialStateNFA ( const DFA & other ); @@ -35,15 +41,69 @@ public: virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const std::set < State > & getInitialStates ( ) const { + return accessComponent < InitialStates > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool addInitialState ( State state ) { + return accessComponent < InitialStates > ( ).add ( std::move ( state ) ); + } + + void setInitialStates ( std::set < State > states ) { + accessComponent < InitialStates > ( ).set ( std::move ( states ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton. diff --git a/alib2data/src/automaton/FSM/NFA.cpp b/alib2data/src/automaton/FSM/NFA.cpp index a1e5f0f8c37ac46cd05ff5d0e3e56cbb21c9a949..47a077665c8b56e9eee3a87d980bf3a9ab49c231 100644 --- a/alib2data/src/automaton/FSM/NFA.cpp +++ b/alib2data/src/automaton/FSM/NFA.cpp @@ -20,14 +20,13 @@ namespace automaton { -NFA::NFA(State initialState) : SingleInitialState(std::move(initialState)) { +NFA::NFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ) : std::Components < NFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::make_tuple ( std::move ( initialState ) ) ) { +} +NFA::NFA(State initialState) : NFA( std::set<State> { initialState }, std::set < alphabet::Symbol > { }, initialState, std::set<State> {} ) { } -NFA::NFA(const DFA& other) : SingleInitialState(other.getInitialState()) { - inputAlphabet = other.getInputAlphabet(); - states = other.getStates(); - finalStates = other.getFinalStates(); +NFA::NFA(const DFA& other) : NFA( other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates() ) { for(const auto& transition : other.getTransitions()) { transitions[transition.first].insert(transition.second); } @@ -41,40 +40,14 @@ AutomatonBase* NFA::plunder() && { return new NFA(std::move(*this)); } -bool NFA::removeState(const State& state) { - if (initialState == state) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is initial state."); - } - - if (finalStates.find(state) != finalStates.end()) { - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state."); - } - - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.first.first == state || transition.second.find(state) != transition.second.end()) - throw AutomatonException("State \"" + (std::string) state.getName() + "\" is used in transition."); - } - - return states.erase(state); -} - -bool NFA::removeInputSymbol(const alphabet::Symbol& symbol) { - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.first.second == symbol) - throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used."); - } - - return inputAlphabet.erase(symbol); -} - bool NFA::addTransition(State from, alphabet::Symbol input, State to) { - if (states.find(from) == states.end()) + if (! getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist."); - if (inputAlphabet.find(input) == inputAlphabet.end()) + if (! getInputAlphabet().count(input)) throw AutomatonException("Input symbol \"" + (std::string) input + "\" doesn't exist."); - if (states.find(to) == states.end()) + if (! getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist."); std::pair<State, alphabet::Symbol> key = std::make_pair(std::move(from), std::move(input)); @@ -93,7 +66,7 @@ const std::map<std::pair<State, alphabet::Symbol>, std::set<State> >& NFA::getTr } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > NFA::getTransitionsFromState(const State& from) const { - if( states.find(from) == states.end()) + if( !getStates().count(from)) throw AutomatonException("State \"" + (std::string) from.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsFromState; @@ -106,29 +79,27 @@ std::map<std::pair<State, alphabet::Symbol>, std::set<State> > NFA::getTransitio } std::map<std::pair<State, alphabet::Symbol>, std::set<State> > NFA::getTransitionsToState(const State& to) const { - if( states.find(to) == states.end()) + if( !getStates().count(to)) throw AutomatonException("State \"" + (std::string) to.getName() + "\" doesn't exist"); std::map<std::pair<State, alphabet::Symbol>, std::set<State> > transitionsToState; - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { + for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) if (transition.second.find(to) != transition.second.end()) transitionsToState[transition.first].insert(transition.second.begin(), transition.second.end()); - } return transitionsToState; } bool NFA::isDeterministic() const { - for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) { - if (transition.second.size() != 1 || transition.second.size() != 0) + for (const std::pair<const std::pair<State, alphabet::Symbol>, std::set<State> >& transition : transitions) + if (transition.second.size() > 1) return false; - } return true; } bool NFA::isTotal() const { - return isDeterministic() && transitionsSize() == inputAlphabet.size() * states.size(); + return isDeterministic() && transitionsSize() == getInputAlphabet().size() * getStates().size(); } unsigned NFA::transitionsSize() const { @@ -140,8 +111,8 @@ unsigned NFA::transitionsSize() const { } int NFA::compare(const NFA& other) const { - auto first = std::tie(states, inputAlphabet, initialState, finalStates, transitions); - auto second = std::tie(other.states, other.inputAlphabet, other.initialState, other.finalStates, other.transitions); + auto first = std::tie(getStates(), getInputAlphabet(), getInitialState(), getFinalStates(), transitions); + auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getInitialState(), other.getFinalStates(), other.getTransitions()); std::compare<decltype(first)> comp; return comp(first, second); @@ -149,11 +120,11 @@ int NFA::compare(const NFA& other) const { void NFA::operator>>(std::ostream& out) const { out << "(NFA " - << " states = " << states - << " inputAlphabet = " << inputAlphabet - << " initialState = " << initialState - << " finalStates = " << finalStates - << " transitions = " << transitions + << "states = " << getStates() + << "inputAlphabet = " << getInputAlphabet() + << "initialState = " << getInitialState() + << "finalStates = " << getFinalStates() + << "transitions = " << transitions << ")"; } @@ -225,6 +196,83 @@ void NFA::composeTransitions(std::deque<sax::Token>& out) const { } /* namespace automaton */ +namespace std { + +template < > +bool automaton::NFA::Component < automaton::NFA, alphabet::Symbol, automaton::InputAlphabet >::used ( const alphabet::Symbol & symbol ) const { + const automaton::NFA * automaton = static_cast < const automaton::NFA * > ( this ); + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.second == symbol) + return true; + + return false; +} + +template < > +bool automaton::NFA::Component < automaton::NFA, alphabet::Symbol, automaton::InputAlphabet >::available ( const alphabet::Symbol & ) const { + return true; +} + +template < > +void automaton::NFA::Component < automaton::NFA, alphabet::Symbol, automaton::InputAlphabet >::valid ( const alphabet::Symbol & ) const { +} + +template < > +bool automaton::NFA::Component < automaton::NFA, automaton::State, automaton::States >::used ( const automaton::State & state ) const { + const automaton::NFA * automaton = static_cast < const automaton::NFA * > ( this ); + + if (automaton->getInitialState() == state) + return true; + + if (automaton->getFinalStates().count(state)) + return true; + + for (const std::pair<const std::pair<automaton::State, alphabet::Symbol>, std::set<automaton::State> >& transition : automaton->getTransitions()) + if (transition.first.first == state || transition.second.find(state) != transition.second.end()) + return true; + + return false; +} + +template < > +bool automaton::NFA::Component < automaton::NFA, automaton::State, automaton::States >::available ( const automaton::State & ) const { + return true; +} + +template < > +void automaton::NFA::Component < automaton::NFA, automaton::State, automaton::States >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::NFA::Component < automaton::NFA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const { + return false; +} + +template < > +bool automaton::NFA::Component < automaton::NFA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const { + const automaton::NFA * automaton = static_cast < const automaton::NFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::NFA::Component < automaton::NFA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const { +} + +template < > +bool automaton::NFA::Element < automaton::NFA, automaton::State, automaton::InitialState >::available ( const automaton::State & state ) const { + const automaton::NFA * automaton = static_cast < const automaton::NFA * > ( this ); + + return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state ); +} + +template < > +void automaton::NFA::Element < automaton::NFA, automaton::State, automaton::InitialState >::valid ( const automaton::State & ) const { +} + +} /* namespace std */ + namespace alib { auto NFAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::NFA>(); diff --git a/alib2data/src/automaton/FSM/NFA.h b/alib2data/src/automaton/FSM/NFA.h index 6bde6a14045803f9803b0b7dd5dffc50abfa8da9..70cd5d44cb741698dbc3197c9ed1b6070098fe0d 100644 --- a/alib2data/src/automaton/FSM/NFA.h +++ b/alib2data/src/automaton/FSM/NFA.h @@ -9,9 +9,9 @@ #define NFA_H_ #include <map> +#include <core/components.hpp> #include "../AutomatonBase.h" -#include "../common/SingleInitialState.h" -#include "../common/InputAlphabet.h" +#include "../common/State.h" #include "../../alphabet/Symbol.h" #include "DFA.h" @@ -22,27 +22,83 @@ namespace automaton { * Represents Finite Automaton. * Can store nondeterministic finite automaton without epsilon transitions. */ -class NFA : public AutomatonBase, public SingleInitialState, public InputAlphabet { +class InputAlphabet; +class States; +class FinalStates; +class InitialState; + +class NFA : public AutomatonBase, public std::Components < NFA, alphabet::Symbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < InitialState > > { protected: std::map < std::pair < State, alphabet::Symbol >, std::set < State > > transitions; public: explicit NFA ( State initialState ); + explicit NFA ( std::set < State > states, std::set < alphabet::Symbol > inputAlphabet, State initialState, std::set < State > finalStates ); explicit NFA ( const DFA & other ); virtual AutomatonBase * clone ( ) const; virtual AutomatonBase * plunder ( ) &&; - /** - * @copydoc Automaton::removeState(const State&) - */ - virtual bool removeState ( const State & state ); + const State & getInitialState ( ) const { + return accessElement < InitialState > ( ).get ( ); + } - /** - * @copydoc Automaton::removeInputSymbol(const Symbol&) - */ - virtual bool removeInputSymbol ( const alphabet::Symbol & symbol ); + bool setInitialState ( State state ) { + return accessElement < InitialState > ( ).set ( std::move ( state ) ); + } + + const std::set < State > & getStates ( ) const { + return accessComponent < States > ( ).get ( ); + } + + bool addState ( State state ) { + return accessComponent < States > ( ).add ( std::move ( state ) ); + } + + void setStates ( std::set < State > states ) { + accessComponent < States > ( ).set ( std::move ( states ) ); + } + + void removeState ( const State & state ) { + accessComponent < States > ( ).remove ( state ); + } + + const std::set < State > & getFinalStates ( ) const { + return accessComponent < FinalStates > ( ).get ( ); + } + + bool addFinalState ( State state ) { + return accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + void setFinalStates ( std::set < State > states ) { + accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + void removeFinalState ( const State & state ) { + accessComponent < FinalStates > ( ).remove ( state ); + } + + const std::set < alphabet::Symbol > & getInputAlphabet ( ) const { + return accessComponent < InputAlphabet > ( ).get ( ); + } + + bool addInputSymbol ( alphabet::Symbol symbol ) { + return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + void addInputSymbols ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + void setInputAlphabet ( std::set < alphabet::Symbol > symbols ) { + accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + void removeInputSymbol ( const alphabet::Symbol & symbol ) { + accessComponent < InputAlphabet > ( ).remove ( symbol ); + } /** * Adds transition defined by parameters to the automaton.