From 67c133850039bc686767ec305711618894e16440 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Fri, 29 Mar 2019 15:02:02 +0100 Subject: [PATCH] use multimap in EpsilonNFA --- .../src/automaton/convert/ToRegExpAlgebraic.h | 6 +- .../automaton/generate/RandomizeAutomaton.h | 5 +- .../automaton/properties/AllEpsilonClosure.h | 5 +- .../src/automaton/properties/EpsilonClosure.h | 11 +- .../automaton/properties/ReachableStates.h | 40 ++++ alib2algo/src/automaton/run/Run.h | 7 +- .../simplify/EpsilonRemoverIncoming.h | 10 +- .../simplify/EpsilonRemoverOutgoing.h | 2 +- .../simplify/UnreachableStatesRemover.h | 34 +++ .../automaton/simplify/UselessStatesRemover.h | 36 +++ .../AutomataConcatenationEpsilonTransition.h | 6 +- .../AutomataUnionEpsilonTransition.h | 6 +- alib2aux/src/convert/DotConverter.h | 24 +- alib2aux/src/convert/GasTexConverter.h | 26 +-- alib2aux/src/convert/TikZConverter.h | 28 ++- alib2data/src/automaton/FSM/CompactNFA.h | 4 +- alib2data/src/automaton/FSM/EpsilonNFA.h | 221 ++++++++---------- alib2data/src/automaton/FSM/ExtendedNFA.h | 4 +- .../FSM/MultiInitialStateEpsilonNFA.h | 2 +- alib2data/src/automaton/FSM/NFA.h | 26 +-- alib2data/src/automaton/xml/FSM/EpsilonNFA.h | 15 +- .../test-src/automaton/AutomatonTest.cpp | 6 + .../properties/efficient/AllEpsilonClosure.h | 27 ++- .../properties/efficient/ReachableStates.h | 24 ++ .../properties/efficient/UsefulStates.h | 24 ++ .../efficient/EpsilonRemoverIncoming.h | 10 +- .../efficient/EpsilonRemoverOutgoing.h | 9 +- .../efficient/UnreachableStatesRemover.h | 28 +++ .../simplify/efficient/UselessStatesRemover.h | 30 +++ .../src/automaton/string/FSM/EpsilonNFA.h | 20 +- 30 files changed, 436 insertions(+), 260 deletions(-) diff --git a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h index a10f3f6917..8144e092f4 100644 --- a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h +++ b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h @@ -86,12 +86,10 @@ regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert ( const automa solver.addEquation ( q, regexp::UnboundedRegExpEpsilon < SymbolType > { } ); for ( const auto & p : automaton.getSymbolTransitions ( ) ) - for ( const StateType & q : p.second ) - solver.addEquation ( p.first.first, q, regexp::UnboundedRegExpSymbol < SymbolType > { p.first.second } ); + solver.addEquation ( p.first.first, p.second, regexp::UnboundedRegExpSymbol < SymbolType > { p.first.second } ); for( const auto & p : automaton.getEpsilonTransitions ( ) ) - for ( const StateType & q : p.second ) - solver.addEquation ( p.first, q, regexp::UnboundedRegExpEpsilon < SymbolType > { } ); + solver.addEquation ( p.first, p.second, regexp::UnboundedRegExpEpsilon < SymbolType > { } ); return solver.solve ( automaton.getInitialState ( ) ); } diff --git a/alib2algo/src/automaton/generate/RandomizeAutomaton.h b/alib2algo/src/automaton/generate/RandomizeAutomaton.h index 51815ffc2b..d57f6a5014 100644 --- a/alib2algo/src/automaton/generate/RandomizeAutomaton.h +++ b/alib2algo/src/automaton/generate/RandomizeAutomaton.h @@ -141,9 +141,8 @@ automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > RandomizeAutomaton: for ( const StateType & finalState : origFSM.getFinalStates ( ) ) res.addFinalState ( statePermutationMap.find ( finalState )->second ); - for ( const std::pair < std::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : origFSM.getTransitions ( ) ) - for ( const StateType & target : transition.second ) - res.addTransition ( statePermutationMap.find ( transition.first.first )->second, transition.first.second, statePermutationMap.find ( target )->second ); + for ( const std::pair < std::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : origFSM.getTransitions ( ) ) + res.addTransition ( statePermutationMap.find ( transition.first.first )->second, transition.first.second, statePermutationMap.find ( transition.second )->second ); return res; } diff --git a/alib2algo/src/automaton/properties/AllEpsilonClosure.h b/alib2algo/src/automaton/properties/AllEpsilonClosure.h index 4be71a1226..9e6a851b8d 100644 --- a/alib2algo/src/automaton/properties/AllEpsilonClosure.h +++ b/alib2algo/src/automaton/properties/AllEpsilonClosure.h @@ -145,9 +145,8 @@ ext::map<StateType, ext::set<StateType>> AllEpsilonClosure::allEpsilonClosure( c for( const std::pair<const StateType, ext::set<StateType>> & p : Qi.at( i - 1 ) ) for(const StateType& pclosure : p.second ) - for(const auto& transition : fsm.getEpsilonTransitionsFromState(pclosure)) { - Qi.at( i )[p.first].insert(transition.second.begin(), transition.second.end()); - } + for(const auto& transition : fsm.getEpsilonTransitionsFromState(pclosure)) + Qi.at( i )[p.first].insert(transition.second); if( Qi.at( i ) == Qi.at( i - 1 ) ) break; diff --git a/alib2algo/src/automaton/properties/EpsilonClosure.h b/alib2algo/src/automaton/properties/EpsilonClosure.h index 4f8e21138d..dffce792e6 100644 --- a/alib2algo/src/automaton/properties/EpsilonClosure.h +++ b/alib2algo/src/automaton/properties/EpsilonClosure.h @@ -151,12 +151,13 @@ ext::set<StateType> EpsilonClosure::epsilonClosure( const automaton::EpsilonNFA visited[ p ] = true; closure.insert( p ); - auto tos = fsm.getTransitions( ).find(ext::make_pair ( p, ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ) ) ); - if(tos == fsm.getTransitions().end()) continue; + auto tos = fsm.getTransitions( ).equal_range(ext::make_pair ( p, ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ) ) ); + if ( tos.empty ( ) ) + continue; - for( const auto & to : tos->second ) - if( visited [ to ] == false ) - queue.push( to ); + for( const auto & transition : tos ) + if( visited [ transition.second ] == false ) + queue.push( transition.second ); } return closure; diff --git a/alib2algo/src/automaton/properties/ReachableStates.h b/alib2algo/src/automaton/properties/ReachableStates.h index 96c81bf68c..cac879d6dc 100644 --- a/alib2algo/src/automaton/properties/ReachableStates.h +++ b/alib2algo/src/automaton/properties/ReachableStates.h @@ -74,6 +74,20 @@ public: template < class SymbolType, class StateType > static ext::set<StateType> reachableStates( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm ); + /** + * Finds all reachable states of a nondeterministic finite automaton. + * Using closure implementation of the BFS algorithm. + * + * @overload + * + * @tparam SymbolType Type for the input symbols. + * @tparam StateType Type for the states. + * @param fsm nondeterministic finite automaton + * @return set of reachable states from the initial state of @p fsm + */ + template < class SymbolType, class EpsilonType, class StateType > + static ext::set<StateType> reachableStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); + /** * Finds all reachable states of a nondeterministic finite automaton. * Using closure implementation of the BFS algorithm. @@ -185,6 +199,32 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::MultiInit return Qi.at( i ); } +template < class SymbolType, class EpsilonType, class StateType > +ext::set<StateType> ReachableStates::reachableStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + // 1a + ext::deque<ext::set<StateType>> Qi; + Qi.push_back( ext::set<StateType>( ) ); + Qi.at( 0 ). insert( fsm.getInitialState( ) ); + + int i = 1; + + // 1bc + while( true ) { + Qi.push_back( Qi.at( i - 1 ) ); + + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & transition : fsm.getTransitionsFromState( p ) ) + Qi.at( i ).insert( transition.second ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i = i + 1; + } + + return Qi.at( i ); +} + template < class SymbolType, class StateType > ext::set<StateType> ReachableStates::reachableStates( const automaton::NFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2algo/src/automaton/run/Run.h b/alib2algo/src/automaton/run/Run.h index e2cfd634a7..86a44ff88c 100644 --- a/alib2algo/src/automaton/run/Run.h +++ b/alib2algo/src/automaton/run/Run.h @@ -379,11 +379,12 @@ ext::tuple < bool, ext::set < StateType >, ext::set < unsigned > > Run::calculat ext::set < StateType > next; for ( const StateType & state : states ) { - auto transitions = automaton.getTransitions ( ).find ( ext::make_pair ( state, ext::variant < EpsilonType, SymbolType > ( symbol ) ) ); + auto transitions = automaton.getTransitions ( ).equal_range ( ext::make_pair ( state, ext::variant < EpsilonType, SymbolType > ( symbol ) ) ); - if ( transitions == automaton.getTransitions ( ).end ( ) ) continue; + if ( transitions.empty ( ) ) continue; - next.insert ( transitions->second.begin ( ), transitions->second.end ( ) ); + for ( const auto & transition : transitions ) + next.insert ( transition.second ); } ext::set < StateType > epsilonNext; diff --git a/alib2algo/src/automaton/simplify/EpsilonRemoverIncoming.h b/alib2algo/src/automaton/simplify/EpsilonRemoverIncoming.h index ad84682d41..15b51b38e2 100644 --- a/alib2algo/src/automaton/simplify/EpsilonRemoverIncoming.h +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverIncoming.h @@ -101,7 +101,7 @@ automaton::NFA < SymbolType, StateType > EpsilonRemoverIncoming::remove( const a fsm.setStates( origFSM.getStates() ); fsm.setInputAlphabet( origFSM.getInputAlphabet() ); - ext::map<ext::pair<StateType, SymbolType>, ext::set<StateType>> origTransitions = origFSM.getSymbolTransitions(); + ext::multimap < ext::pair < StateType, SymbolType >, StateType > origTransitions = origFSM.getSymbolTransitions(); /** * Step 1 from Melichar 2.41 @@ -109,11 +109,11 @@ automaton::NFA < SymbolType, StateType > EpsilonRemoverIncoming::remove( const a for( const auto & from : origFSM.getStates( ) ) for( const auto & fromClosure : automaton::properties::EpsilonClosure::epsilonClosure( origFSM, from ) ) for( const auto & symbol : origFSM.getInputAlphabet() ) { - auto transitions = origTransitions.find(ext::make_pair(fromClosure, symbol)); - if(transitions == origTransitions.end()) continue; + auto transitions = origTransitions.equal_range(ext::make_pair(fromClosure, symbol)); + if(transitions.empty ( ) ) continue; - for( const auto & to : transitions->second ) - fsm.addTransition( from, symbol, to ); + for( const auto & transition : transitions ) + fsm.addTransition( from, symbol, transition.second ); } /** diff --git a/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h index eaf6006268..d3619e3f80 100644 --- a/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h @@ -110,7 +110,7 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > EpsilonRemoverOutgoing for( const auto & symbol : origFSM.getInputAlphabet() ) { for( const auto& transition : origFSM.getTransitions( ) ) { - if(transition.second.find(middle) == transition.second.end()) continue; + if(transition.second == middle ) continue; if(transition.first.second != symbol) continue; for( const auto & to : middleClosure ) diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h index 943e853256..f68721155d 100644 --- a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h +++ b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h @@ -63,6 +63,14 @@ public: template < class T > static T remove( const T & automaton ); + /** + * @overload + * @tparam SymbolType Type for input symbols. + * @tparam StateType Type for states. + */ + template < class SymbolType, class EpsilonType, class StateType > + static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); + /** * @overload * @tparam SymbolType Type for input symbols. @@ -149,6 +157,32 @@ T UnreachableStatesRemover::remove ( const T & fsm ) { return M; } +template < class SymbolType, class EpsilonType, class StateType > +automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > UnreachableStatesRemover::remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + // 1a + ext::set<StateType> Qa = automaton::properties::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > M(fsm.getInitialState() ); + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + M.addTransition( transition.first.first, transition.first.second, transition.second ); + + ext::set<StateType> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + return M; +} + template < class SymbolType, class StateType > automaton::NFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.h b/alib2algo/src/automaton/simplify/UselessStatesRemover.h index 168eeb7c0f..b6810fd5e1 100644 --- a/alib2algo/src/automaton/simplify/UselessStatesRemover.h +++ b/alib2algo/src/automaton/simplify/UselessStatesRemover.h @@ -59,6 +59,14 @@ public: template < class T > static T remove( const T & automaton ); + /** + * @overload + * @tparam SymbolType Type for input symbols. + * @tparam StateType Type for states. + */ + template < class SymbolType, class EpsilonType, class StateType > + static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); + /** * @overload * @tparam SymbolType Type for input symbols. @@ -141,6 +149,34 @@ T UselessStatesRemover::remove( const T & fsm ) { return M; } +template < class SymbolType, class EpsilonType, class StateType > +automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > UselessStatesRemover::remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + // 1. + ext::set<StateType> Qu = automaton::properties::UsefulStates::usefulStates( fsm ); + + // 2. + automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > M ( fsm.getInitialState () ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + if(Qu.size() == 0) { + return M; + } + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & t : fsm.getTransitions( ) ) + if( /* this part is not needed Qu.count( t.first.first ) && */ Qu.count( t.second ) ) + M.addTransition( t.first.first, t.first.second, t.second ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + return M; +} + template < class SymbolType, class StateType > automaton::NFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { // 1. diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h index 33daa73c1f..b32a4e0396 100644 --- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h +++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h @@ -141,12 +141,10 @@ automaton::EpsilonNFA < SymbolType, EpsilonType, ext::pair < StateType, unsigned res.addFinalState ( ext::make_pair ( q, secondDefault ) ); for ( const auto & t : first.getTransitions ( ) ) - for ( const StateType & q : t.second ) - res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( q, firstDefault ) ); + res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( t.second, firstDefault ) ); for ( const auto & t : second.getTransitions ( ) ) - for ( const StateType & q : t.second ) - res.addTransition ( ext::make_pair ( t.first.first, secondDefault ), t.first.second, ext::make_pair ( q, secondDefault ) ); + res.addTransition ( ext::make_pair ( t.first.first, secondDefault ), t.first.second, ext::make_pair ( t.second, secondDefault ) ); for ( const StateType & q : first.getFinalStates ( ) ) res.addTransition ( ext::make_pair ( q, firstDefault ), ext::make_pair ( second.getInitialState ( ), secondDefault ) ); diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h index bca0bab6cb..e99aa1d7bd 100644 --- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h +++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h @@ -90,12 +90,10 @@ automaton::EpsilonNFA < SymbolType, EpsilonType, ext::pair < StateType, unsigned res.addTransition ( q0, ext::make_pair ( second.getInitialState ( ), secondDefault ) ); for(const auto& t : first.getTransitions()) - for(const auto& q : t.second) - res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( q, firstDefault ) ); + res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( t.second, firstDefault ) ); for(const auto& t : second.getTransitions()) - for(const auto& q : t.second) - res.addTransition ( ext::make_pair ( t.first.first, secondDefault ), t.first.second, ext::make_pair ( q, secondDefault ) ); + res.addTransition ( ext::make_pair ( t.first.first, secondDefault ), t.first.second, ext::make_pair ( t.second, secondDefault ) ); return res; } diff --git a/alib2aux/src/convert/DotConverter.h b/alib2aux/src/convert/DotConverter.h index 490df13249..b5ec4af8ba 100644 --- a/alib2aux/src/convert/DotConverter.h +++ b/alib2aux/src/convert/DotConverter.h @@ -789,22 +789,20 @@ void DotConverter::transitions(const automaton::EpsilonNFA < SymbolType, Epsilon symbol = replace ( factory::StringDataFactory::toString ( std::get<1>(transition.first ).template get<SymbolType>()), "\"", "\\\"" ); } - for(const StateType& to : transition.second) { - std::pair<int, int> key(states.find(transition.first.first)->second, states.find(to)->second); - ext::map<std::pair<int, int>, std::string>::iterator mapit = transitions.find(key); + std::pair<int, int> key(states.find(transition.first.first)->second, states.find(transition.second)->second); + ext::map<std::pair<int, int>, std::string>::iterator mapit = transitions.find(key); - if (mapit == transitions.end()) { - transitions.insert(std::make_pair(key, symbol)); - } else { - mapit->second += ","; + if (mapit == transitions.end()) { + transitions.insert(std::make_pair(key, symbol)); + } else { + mapit->second += ","; - size_t pos = mapit->second.find_last_of("\n"); - if(pos == std::string::npos) pos = 0; - if(mapit->second.size() - pos > 100) mapit->second += "\n"; - else mapit->second += " "; + size_t pos = mapit->second.find_last_of("\n"); + if(pos == std::string::npos) pos = 0; + if(mapit->second.size() - pos > 100) mapit->second += "\n"; + else mapit->second += " "; - mapit->second += symbol; - } + mapit->second += symbol; } } diff --git a/alib2aux/src/convert/GasTexConverter.h b/alib2aux/src/convert/GasTexConverter.h index 9b6e108d8d..57d3324fab 100644 --- a/alib2aux/src/convert/GasTexConverter.h +++ b/alib2aux/src/convert/GasTexConverter.h @@ -885,22 +885,20 @@ template<class SymbolType, class EpsilonType, class StateType> void GasTexConverter::transitions(const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm, std::ostream& out) { ext::map<std::pair<std::string, std::string>, std::string> transitionMap; for (const auto& transition : fsm.getTransitions()) { - for(const auto& to : transition.second) { - std::pair<std::string, std::string> key(replace ( factory::StringDataFactory::toString ( transition.first.first ), "\"", "\\\"" ), replace ( factory::StringDataFactory::toString ( to ), "\"", "\\\"" ) ); + std::pair<std::string, std::string> key(replace ( factory::StringDataFactory::toString ( transition.first.first ), "\"", "\\\"" ), replace ( factory::StringDataFactory::toString ( transition.second ), "\"", "\\\"" ) ); - std::string symbol; - if (transition.first.second.template is<EpsilonType>()) { - symbol = "$\\varepsilon$"; - } else { - symbol = replace ( factory::StringDataFactory::toString ( transition.first.second.template get<SymbolType>( ) ), "\"", "\\\"" ); - } + std::string symbol; + if (transition.first.second.template is<EpsilonType>()) { + symbol = "$\\varepsilon$"; + } else { + symbol = replace ( factory::StringDataFactory::toString ( transition.first.second.template get<SymbolType>( ) ), "\"", "\\\"" ); + } - auto mapIterator = transitionMap.find(key); - if (mapIterator == transitionMap.end()) { - transitionMap.insert(make_pair(key, symbol)); - } else { - mapIterator->second += ", " + symbol; - } + auto mapIterator = transitionMap.find(key); + if (mapIterator == transitionMap.end()) { + transitionMap.insert(make_pair(key, symbol)); + } else { + mapIterator->second += ", " + symbol; } } printTransitionMap(transitionMap, out); diff --git a/alib2aux/src/convert/TikZConverter.h b/alib2aux/src/convert/TikZConverter.h index 329695a7ea..bb13e2937f 100644 --- a/alib2aux/src/convert/TikZConverter.h +++ b/alib2aux/src/convert/TikZConverter.h @@ -734,26 +734,24 @@ void TikZConverter::transitions ( const automaton::EpsilonNFA < SymbolType, Epsi else symbol = replace ( factory::StringDataFactory::toString ( std::get < 1 > ( transition.first ).template get < SymbolType > ( ) ), "\"", "\\\"" ); - for ( const StateType & to : transition.second ) { - std::pair < int, int > key ( states.find ( transition.first.first )->second, states.find ( to )->second ); - ext::map < std::pair < int, int >, std::string >::iterator mapit = transitions.find ( key ); + std::pair < int, int > key ( states.find ( transition.first.first )->second, states.find ( transition.second )->second ); + ext::map < std::pair < int, int >, std::string >::iterator mapit = transitions.find ( key ); - if ( mapit == transitions.end ( ) ) { - transitions.insert ( std::make_pair ( key, symbol ) ); - } else { - mapit->second += ","; + if ( mapit == transitions.end ( ) ) { + transitions.insert ( std::make_pair ( key, symbol ) ); + } else { + mapit->second += ","; - size_t pos = mapit->second.find_last_of ( "\n" ); + size_t pos = mapit->second.find_last_of ( "\n" ); - if ( pos == std::string::npos ) pos = 0; + if ( pos == std::string::npos ) pos = 0; - if ( mapit->second.size ( ) - pos > 100 ) - mapit->second += "\n"; - else - mapit->second += " "; + if ( mapit->second.size ( ) - pos > 100 ) + mapit->second += "\n"; + else + mapit->second += " "; - mapit->second += symbol; - } + mapit->second += symbol; } } diff --git a/alib2data/src/automaton/FSM/CompactNFA.h b/alib2data/src/automaton/FSM/CompactNFA.h index 87b45b1d08..5c01a3e8cc 100644 --- a/alib2data/src/automaton/FSM/CompactNFA.h +++ b/alib2data/src/automaton/FSM/CompactNFA.h @@ -467,9 +467,9 @@ template < class EpsilonType > CompactNFA < SymbolType, StateType >::CompactNFA ( const EpsilonNFA < SymbolType, EpsilonType, StateType > & other ) : CompactNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) if ( transition.first.second.template is < EpsilonType > ( ) ) - transitions.insert ( ext::make_pair ( transition.first.first, ext::vector < SymbolType > { } ), transition.second ); + transitions [ ext::make_pair ( transition.first.first, ext::vector < SymbolType > { } ) ].insert ( transition.second ); else - transitions.insert ( ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second.template get < SymbolType > ( ) } ), transition.second ); + transitions [ ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second.template get < SymbolType > ( ) } ) ].insert ( transition.second ); } template < class SymbolType, class StateType > diff --git a/alib2data/src/automaton/FSM/EpsilonNFA.h b/alib2data/src/automaton/FSM/EpsilonNFA.h index dd0b4eb113..47dbf65d03 100644 --- a/alib2data/src/automaton/FSM/EpsilonNFA.h +++ b/alib2data/src/automaton/FSM/EpsilonNFA.h @@ -27,7 +27,7 @@ #include <ostream> #include <sstream> -#include <alib/map> +#include <alib/multimap> #include <alib/set> #include <alib/variant> @@ -79,7 +79,7 @@ class EpsilonNFA final : public ext::CompareOperators < EpsilonNFA < SymbolType, /** * Transition function as mapping from a state times an input symbol or epsilon on the left hand side to a set of states. */ - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > transitions; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > transitions; public: /** @@ -350,42 +350,19 @@ public: bool addTransition ( StateType from, StateType to ); /** - * \brief Add a transitions to the automaton. + * \brief Removes a transition to the automaton. * - * \details The transition is in a form A \times a -> P(Q), where A \in Q, a \in T \cup \{\epsilon\}, P(Q) is a powerset of states. + * \details The transition is in a form A \times a -> B, where A, B \in Q and a \in T \cup \{\epsilon\} * * \param current the source state (A) * \param input the input symbol or epsilon (a) - * \param next the target states (P(Q)) - * - * \throws AutomatonException when transitions contain states or symbols not present in the automaton components - */ - void addTransitions ( StateType from, ext::variant < EpsilonType, SymbolType > input, ext::set < StateType > to ); - - /** - * \brief Add a transitions to the automaton. - * - * \details The transition is in a form A \times a -> P(Q), where A \in Q, a \in T, P(Q) is a powerset of states. - * - * \param current the source state (A) - * \param input the input symbol (a) - * \param next the target states (P(Q)) - * - * \throws AutomatonException when transitions contain states or symbols not present in the automaton components - */ - void addTransitions ( StateType from, SymbolType input, ext::set < StateType > to ); - - /** - * \brief Add a transitions to the automaton. - * - * \details The transition is in a form A \times \epsilon -> P(Q), where A \in Q, P(Q) is a powerset of states. + * \param next the target state (B) * - * \param current the source state (A) - * \param next the target states (P(Q)) + * \throws AutomatonException when transition contains state or symbol not present in the automaton components * - * \throws AutomatonException when transitions contain states or symbols not present in the automaton components + * \returns true if the transition was indeed added */ - void addTransitions ( StateType from, ext::set < StateType > to ); + bool removeTransition ( StateType from, ext::variant < EpsilonType, SymbolType > input, StateType to ); /** * \brief Removes a transition from the automaton. @@ -417,28 +394,28 @@ public: * * \returns transition function of the automaton */ - const ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & getTransitions ( ) const &; + const ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & getTransitions ( ) const &; /** * Get the transition function of the automaton in its natural form. * * \returns transition function of the automaton */ - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > && getTransitions ( ) &&; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > && getTransitions ( ) &&; /** * Get the epsilon transitions of the automaton * * \returns epsilon transitions of the automaton */ - ext::map < StateType, ext::set < StateType > > getEpsilonTransitions ( ) const; + ext::multimap < StateType, StateType > getEpsilonTransitions ( ) const; /** * Get the non-epsilon transitions of the automaton * * \returns non-epsilon transitions of the automaton */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > getSymbolTransitions ( ) const; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > getSymbolTransitions ( ) const; /** * Get a subset of the transition function of the automaton, with the source state fixed in the transitions natural representation. @@ -447,7 +424,7 @@ public: * * \returns a subset of the transition function of the automaton with the source state fixed */ - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > getTransitionsFromState ( const StateType & from ) const; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > getTransitionsFromState ( const StateType & from ) const; /** * Get a subset of epsilon transitions of the automaton, with the source state fixed in the transitions natural representation. @@ -456,7 +433,7 @@ public: * * \returns a subset of epsilon transitions of the automaton with the source state fixed */ - ext::map < StateType, ext::set < StateType > > getEpsilonTransitionsFromState ( const StateType & from ) const; + ext::multimap < StateType, StateType > getEpsilonTransitionsFromState ( const StateType & from ) const; /** * Get a subset of non-epsilon transitions of the automaton, with the source state fixed in the transitions natural representation. @@ -465,7 +442,7 @@ public: * * \returns a subset of non-epsilon transitions of the automaton with the source state fixed */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > getSymbolTransitionsFromState ( const StateType & from ) const; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > getSymbolTransitionsFromState ( const StateType & from ) const; /** * Get a subset of the transition function of the automaton, with the target state fixed in the transitions natural representation. @@ -474,7 +451,7 @@ public: * * \returns a subset of the transition function of the automaton with the target state fixed */ - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > getTransitionsToState ( const StateType & from ) const; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > getTransitionsToState ( const StateType & from ) const; /** * Get a subset of epsilon transitions of the automaton, with the target state fixed in the transitions natural representation. @@ -483,7 +460,7 @@ public: * * \returns a subset of epsilon transitions of the automaton with the target state fixed */ - ext::map < StateType, ext::set < StateType > > getEpsilonTransitionsToState ( const StateType & to ) const; + ext::multimap < StateType, StateType > getEpsilonTransitionsToState ( const StateType & to ) const; /** * Get a subset of non-epsilon transitions of the automaton, with the target state fixed in the transitions natural representation. @@ -492,7 +469,7 @@ public: * * \returns a subset of non-epsilon transitions of the automaton with the target state fixed */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > getSymbolTransitionsToState ( const StateType & to ) const; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > getSymbolTransitionsToState ( const StateType & to ) const; /** * \brief Determines whether the automaton is without epsilon transitions. @@ -570,22 +547,24 @@ EpsilonNFA < SymbolType, EpsilonType, StateType >::EpsilonNFA ( StateType initia template<class SymbolType, class EpsilonType, class StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::EpsilonNFA ( const MultiInitialStateNFA < SymbolType, StateType > & other ) : EpsilonNFA ( other.getStates ( ) + ext::set < StateType > { common::createUnique ( label::InitialStateLabel::instance < StateType > ( ), other.getStates ( ) ) }, other.getInputAlphabet ( ), common::createUnique ( label::InitialStateLabel::instance < StateType > ( ), other.getStates ( ) ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), transition.second ); + for ( const auto & toState : transition.second ) + transitions.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), toState ); - transitions.insert ( ext::make_pair ( getInitialState ( ), ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ) ), other.getInitialStates ( ) ); + for ( const auto & initialState : other.getInitialStates ( ) ) + transitions.insert ( ext::make_pair ( getInitialState ( ), ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ) ), initialState ); } template<class SymbolType, class EpsilonType, class StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::EpsilonNFA ( const NFA < SymbolType, StateType > & other ) : EpsilonNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions [ ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ) ].insert ( transition.second ); + transitions.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), transition.second ); } template<class SymbolType, class EpsilonType, class StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::EpsilonNFA ( const DFA < SymbolType, StateType > & other ) : EpsilonNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions [ ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ) ].insert ( transition.second ); + transitions.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), transition.second ); } template<class SymbolType, class EpsilonType, class StateType > @@ -593,15 +572,21 @@ bool EpsilonNFA < SymbolType, EpsilonType, StateType >::addTransition ( StateTyp if ( !getStates ( ).count ( from ) ) throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist." ); - if ( input.template is < SymbolType > ( ) && !getInputAlphabet ( ).count ( input.template get < SymbolType > ( ) ) ) + if ( ! input.template is < EpsilonType > ( ) && !getInputAlphabet ( ).count ( input ) ) throw AutomatonException ( "Input symbol \"" + ext::to_string ( input ) + "\" doesn't exist." ); if ( !getStates ( ).count ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist." ); - ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); + auto upper_bound = transitions.upper_bound ( ext::tie ( from, input ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( from, input ) ); + auto iter = std::lower_bound ( lower_bound, upper_bound, to, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } ); + if ( iter != upper_bound && to >= iter->second ) + return false; - return transitions[std::move ( key )].insert ( std::move ( to ) ).second; + ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); + transitions.insert ( iter, std::make_pair ( std::move ( key ), std::move ( to ) ) ); + return true; } template<class SymbolType, class EpsilonType, class StateType > @@ -618,173 +603,150 @@ bool EpsilonNFA < SymbolType, EpsilonType, StateType >::addTransition ( StateTyp return addTransition ( std::move ( from ), std::move ( inputVariant ), std::move ( to ) ); } -template < class SymbolType, class EpsilonType, class StateType > -void EpsilonNFA < SymbolType, EpsilonType, StateType >::addTransitions ( StateType from, ext::variant < EpsilonType, SymbolType > input, ext::set < StateType > to ) { - if ( !getStates ( ).count ( from ) ) - throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist." ); - - if ( input.template is < SymbolType > ( ) && !getInputAlphabet ( ).count ( input.template get < SymbolType > ( ) ) ) - throw AutomatonException ( "Input symbol \"" + ext::to_string ( input ) + "\" doesn't exist." ); - - if ( !std::includes ( getStates ( ).begin ( ), getStates ( ).end ( ), to.begin ( ), to.end ( ) ) ) - throw AutomatonException ( "Some target states don't exist." ); - - ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); - - transitions [ std::move ( key ) ].insert ( ext::make_mover ( to ).begin ( ), ext::make_mover ( to ).end ( ) ); -} - template<class SymbolType, class EpsilonType, class StateType > -void EpsilonNFA < SymbolType, EpsilonType, StateType >::addTransitions ( StateType from, SymbolType input, ext::set < StateType > to ) { - ext::variant < EpsilonType, SymbolType > inputVariant ( std::move ( input ) ); - - addTransitions ( std::move ( from ), std::move ( inputVariant ), std::move ( to ) ); -} - -template<class SymbolType, class EpsilonType, class StateType > -void EpsilonNFA < SymbolType, EpsilonType, StateType >::addTransitions ( StateType from, ext::set < StateType > to ) { - auto inputVariant = ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ); +bool EpsilonNFA < SymbolType, EpsilonType, StateType >::removeTransition ( StateType from, ext::variant < EpsilonType, SymbolType > input, StateType to ) { + auto upper_bound = transitions.upper_bound ( ext::tie ( from, input ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( from, input ) ); + auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == to; } ); + if ( iter == upper_bound ) + return false; - addTransitions ( std::move ( from ), std::move ( inputVariant ), std::move ( to ) ); + transitions.erase ( iter ); + return true; } template<class SymbolType, class EpsilonType, class StateType > bool EpsilonNFA < SymbolType, EpsilonType, StateType >::removeTransition ( const StateType & from, const SymbolType & input, const StateType & to ) { - ext::variant < EpsilonType, SymbolType > inputVariant ( input ); - ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( from, inputVariant ); + ext::variant < EpsilonType, SymbolType > inputVariant ( std::move ( input ) ); - return transitions[key].erase ( to ); + return addTransition ( std::move ( from ), std::move ( inputVariant ), std::move ( to ) ); } template<class SymbolType, class EpsilonType, class StateType > bool EpsilonNFA < SymbolType, EpsilonType, StateType >::removeTransition ( const StateType & from, const StateType & to ) { auto inputVariant = ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ); - ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( from, inputVariant ); - - return transitions[key].erase ( to ); + return addTransition ( std::move ( from ), std::move ( inputVariant ), std::move ( to ) ); } template<class SymbolType, class EpsilonType, class StateType > -const ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitions ( ) const & { +const ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitions ( ) const & { return transitions; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > && EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitions ( ) && { +ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > && EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitions ( ) && { return std::move ( transitions ); } template<class SymbolType, class EpsilonType, class StateType > -ext::map < StateType, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitions ( ) const { - ext::map < StateType, ext::set < StateType > > result; +ext::multimap < StateType, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitions ( ) const { + ext::multimap < StateType, StateType > result; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) if ( transition.first.second.template is < EpsilonType > ( ) ) - result[transition.first.first].insert ( transition.second.begin ( ), transition.second.end ( ) ); + result.insert ( transition.first.first, transition.second ); return result; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitions ( ) const { - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > result; +ext::multimap < ext::pair < StateType, SymbolType >, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitions ( ) const { + ext::multimap < ext::pair < StateType, SymbolType >, StateType > result; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) if ( transition.first.second.template is < SymbolType > ( ) ) - result[ext::pair < StateType, SymbolType > ( transition.first.first, transition.first.second.template get < SymbolType > ( ) )].insert ( transition.second.begin ( ), transition.second.end ( ) ); + result.insert ( ext::make_pair ( transition.first.first, transition.first.second.template get < SymbolType > ( ) ), transition.second ); return result; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitionsFromState ( const StateType & from ) const { +ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitionsFromState ( const StateType & from ) const { if ( !getStates ( ).count ( from ) ) throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist" ); - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > transitionsFromState; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > transitionsFromState; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) if ( transition.first.first == from ) - transitionsFromState[transition.first].insert ( transition.second.begin ( ), transition.second.end ( ) ); + transitionsFromState.insert ( transition ); return transitionsFromState; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < StateType, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitionsFromState ( const StateType & from ) const { +ext::multimap < StateType, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitionsFromState ( const StateType & from ) const { if ( !getStates ( ).count ( from ) ) throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist" ); ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key ( from, ext::variant < EpsilonType, SymbolType >::template from < EpsilonType > ( ) ); - ext::map < StateType, ext::set < StateType > > res; - auto transition = transitions.find ( key ); - - if ( transition != transitions.end ( ) ) - res.insert ( from, transition->second ); + ext::multimap < StateType, StateType > res; + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions.equal_range ( key ) ) + res.insert ( transition.first.first, transition.second ); return res; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitionsFromState ( const StateType & from ) const { +ext::multimap < ext::pair < StateType, SymbolType >, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitionsFromState ( const StateType & from ) const { if ( !getStates ( ).count ( from ) ) throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist" ); - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > transitionsFromState; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > transitionsFromState; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) if ( ( transition.first.first == from ) && transition.first.second.template is < SymbolType > ( ) ) - transitionsFromState[ext::pair < StateType, SymbolType > ( transition.first.first, transition.first.second.template get < SymbolType > ( ) )].insert ( transition.second.begin ( ), transition.second.end ( ) ); + transitionsFromState.insert ( std::make_pair ( ext::make_pair ( transition.first.first, transition.first.second.template get < SymbolType > ( ) ), transition.second ) ); return transitionsFromState; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitionsToState ( const StateType & to ) const { +ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getTransitionsToState ( const StateType & to ) const { if ( !getStates ( ).count ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist" ); - ext::map < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > transitionsToState; + ext::multimap < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > transitionsToState; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) - if ( transition.second.find ( to ) != transition.second.end ( ) ) - transitionsToState[transition.first].insert ( to ); + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) + if ( transition.second == to ) + transitionsToState.insert ( transition ); return transitionsToState; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < StateType, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitionsToState ( const StateType & to ) const { +ext::multimap < StateType, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getEpsilonTransitionsToState ( const StateType & to ) const { if ( !getStates ( ).count ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist" ); - ext::map < StateType, ext::set < StateType > > transitionsToState; + ext::multimap < StateType, StateType > transitionsToState; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) - if ( ( transition.second.find ( to ) != transition.second.end ( ) ) && transition.first.second.template is < EpsilonType > ( ) ) - transitionsToState[transition.first.first].insert ( to ); + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) + if ( transition.second == to && transition.first.second.template is < EpsilonType > ( ) ) + transitionsToState.insert ( transition.first.first, to ); return transitionsToState; } template<class SymbolType, class EpsilonType, class StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitionsToState ( const StateType & to ) const { +ext::multimap < ext::pair < StateType, SymbolType >, StateType > EpsilonNFA < SymbolType, EpsilonType, StateType >::getSymbolTransitionsToState ( const StateType & to ) const { if ( !getStates ( ).count ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist" ); - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > transitionsToState; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > transitionsToState; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) - if ( ( transition.second.find ( to ) != transition.second.end ( ) ) && transition.first.second.template is < SymbolType > ( ) ) - transitionsToState[ext::pair < StateType, SymbolType > ( transition.first.first, transition.first.second.template get < SymbolType > ( ) )].insert ( to ); + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) + if ( transition.second == to && transition.first.second.template is < SymbolType > ( ) ) + transitionsToState.insert ( ext::pair < StateType, SymbolType > ( transition.first.first, transition.first.second.template get < SymbolType > ( ) ), to ); return transitionsToState; } template<class SymbolType, class EpsilonType, class StateType > bool EpsilonNFA < SymbolType, EpsilonType, StateType >::isEpsilonFree ( ) const { - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : transitions ) if ( transition.first.second.template is < EpsilonType > ( ) ) return false; @@ -793,8 +755,11 @@ bool EpsilonNFA < SymbolType, EpsilonType, StateType >::isEpsilonFree ( ) const template<class SymbolType, class EpsilonType, class StateType > bool EpsilonNFA < SymbolType, EpsilonType, StateType >::isDeterministic ( ) const { - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : transitions ) - if ( transition.second.size ( ) > 1 ) + 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 ( ); @@ -845,7 +810,7 @@ public: * \returns true if the symbol is used, false othervise */ static bool used ( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & automaton, const SymbolType & symbol ) { - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : automaton.getTransitions ( ) ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : automaton.getTransitions ( ) ) if ( transition.first.second.template is < SymbolType > ( ) && ( transition.first.second.template get < SymbolType > ( ) == symbol ) ) return true; @@ -899,8 +864,8 @@ public: if ( automaton.getFinalStates ( ).count ( state ) ) return true; - for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > & transition : automaton.getTransitions ( ) ) - if ( ( transition.first.first == state ) || transition.second.count ( state ) ) + for ( const std::pair < const ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > & transition : automaton.getTransitions ( ) ) + if ( transition.first.first == state || transition.second == state ) return true; return false; @@ -1019,12 +984,12 @@ struct normalize < automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > automaton::EpsilonNFA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( initialState ), std::move ( finalStates ) ); - for ( std::pair < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, ext::set < StateType > > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { + for ( std::pair < ext::pair < StateType, ext::variant < EpsilonType, SymbolType > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { DefaultStateType from = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.first.first ) ); ext::variant < DefaultEpsilonType, DefaultSymbolType > input = automaton::AutomatonNormalize::normalizeSymbolEpsilon ( std::move ( transition.first.second ) ); - ext::set < DefaultStateType > targets = automaton::AutomatonNormalize::normalizeStates ( std::move ( transition.second ) ); + DefaultStateType target = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) ); - res.addTransitions ( std::move ( from ), std::move ( input ), std::move ( targets ) ); + res.addTransition ( std::move ( from ), std::move ( input ), std::move ( target ) ); } return res; diff --git a/alib2data/src/automaton/FSM/ExtendedNFA.h b/alib2data/src/automaton/FSM/ExtendedNFA.h index 49f2e64230..23dbea22f7 100644 --- a/alib2data/src/automaton/FSM/ExtendedNFA.h +++ b/alib2data/src/automaton/FSM/ExtendedNFA.h @@ -488,10 +488,10 @@ ExtendedNFA < SymbolType, StateType >::ExtendedNFA ( const EpsilonNFA < SymbolTy for ( const auto & transition : other.getTransitions ( ) ) { if ( transition.first.second.template is < EpsilonType > ( ) ) { ext::pair < StateType, regexp::UnboundedRegExpStructure < SymbolType > > key = ext::make_pair ( transition.first.first, regexp::UnboundedRegExpStructure < SymbolType > ( regexp::UnboundedRegExpEpsilon < SymbolType > ( ) ) ); - transitions[key] = transition.second; + transitions[key].insert ( transition.second ); } else { ext::pair < StateType, regexp::UnboundedRegExpStructure < SymbolType > > key = ext::make_pair ( transition.first.first, regexp::UnboundedRegExpStructure < SymbolType > ( regexp::UnboundedRegExpSymbol < SymbolType > ( transition.first.second.template get < SymbolType > ( ) ) ) ); - transitions[key] = transition.second; + transitions[key].insert ( transition.second ); } } } diff --git a/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h b/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h index 17f1b01dfe..3bfa3cbe2a 100644 --- a/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h +++ b/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h @@ -608,7 +608,7 @@ template<class SymbolType, class EpsilonType, class StateType > MultiInitialStateEpsilonNFA < SymbolType, EpsilonType, StateType >::MultiInitialStateEpsilonNFA ( const EpsilonNFA < SymbolType, EpsilonType, StateType > & other ) : MultiInitialStateEpsilonNFA ( other.getStates ( ), other.getInputAlphabet ( ), { other.getInitialState ( ) }, other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) { ext::pair < StateType, ext::variant < EpsilonType, SymbolType > > key = ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ); - transitions[key] = transition.second; + transitions[key].insert ( transition.second ); } } diff --git a/alib2data/src/automaton/FSM/NFA.h b/alib2data/src/automaton/FSM/NFA.h index 59c894082a..f26025c801 100644 --- a/alib2data/src/automaton/FSM/NFA.h +++ b/alib2data/src/automaton/FSM/NFA.h @@ -422,27 +422,27 @@ bool NFA < SymbolType, StateType >::addTransition ( StateType from, SymbolType i if ( !getStates ( ).count ( to ) ) throw AutomatonException ( "State \"" + ext::to_string ( to ) + "\" doesn't exist." ); - ext::pair < StateType, SymbolType > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); - - auto upper_bound = transitions.upper_bound ( key ); - auto lower_bound = transitions.lower_bound ( key ); - if ( std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == to; } ) != upper_bound ) + auto upper_bound = transitions.upper_bound ( ext::tie ( from, input ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( from, input ) ); + auto iter = std::lower_bound ( lower_bound, upper_bound, to, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } ); + if ( iter != upper_bound && to >= iter->second ) return false; - lower_bound = std::lower_bound ( lower_bound, upper_bound, to, [] ( const std::pair < ext::pair < StateType, SymbolType >, StateType > & first, const StateType & second ) { return first.second < second; } ); - - transitions.insert ( lower_bound, std::make_pair ( std::move ( key ), std::move ( to ) ) ); + ext::pair < StateType, SymbolType > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); + transitions.insert ( iter, std::make_pair ( std::move ( key ), std::move ( to ) ) ); return true; } template<class SymbolType, class StateType > bool NFA < SymbolType, StateType >::removeTransition ( const StateType & from, const SymbolType & input, const StateType & to ) { - auto iter = std::binary_search ( transitions.begin ( ), transitions.end ( ), ext::tie ( from, input, to ), [ & ] ( const std::pair < ext::pair < StateType, SymbolType >, StateType > & transition, const auto & second ) { - return ext::tie ( transition.first.first, transition.first.second, transition.second ) < second; - } ); - ext::pair < StateType, SymbolType > key = ext::make_pair ( from, input ); + auto upper_bound = transitions.upper_bound ( ext::tie ( from, input ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( from, input ) ); + auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == to; } ); + if ( iter == upper_bound ) + return false; - return transitions[key].erase ( to ); + transitions.erase ( iter ); + return true; } template<class SymbolType, class StateType > diff --git a/alib2data/src/automaton/xml/FSM/EpsilonNFA.h b/alib2data/src/automaton/xml/FSM/EpsilonNFA.h index 97e7dd4e4c..a4fe1d4c21 100644 --- a/alib2data/src/automaton/xml/FSM/EpsilonNFA.h +++ b/alib2data/src/automaton/xml/FSM/EpsilonNFA.h @@ -138,16 +138,15 @@ template < class SymbolType, class EpsilonType, class StateType > void xmlApi < automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > >::composeTransitions ( ext::deque < sax::Token > & out, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & automaton ) { out.emplace_back ( "transitions", sax::Token::TokenType::START_ELEMENT ); - for ( const auto & transition : automaton.getTransitions ( ) ) - for ( const auto & targetState : transition.second ) { - out.emplace_back ( "transition", sax::Token::TokenType::START_ELEMENT ); + for ( const auto & transition : automaton.getTransitions ( ) ) { + out.emplace_back ( "transition", sax::Token::TokenType::START_ELEMENT ); - automaton::AutomatonToXMLComposer::composeTransitionFrom ( out, transition.first.first ); - automaton::AutomatonToXMLComposer::composeTransitionInputEpsilonSymbol ( out, transition.first.second ); - automaton::AutomatonToXMLComposer::composeTransitionTo ( out, targetState ); + automaton::AutomatonToXMLComposer::composeTransitionFrom ( out, transition.first.first ); + automaton::AutomatonToXMLComposer::composeTransitionInputEpsilonSymbol ( out, transition.first.second ); + automaton::AutomatonToXMLComposer::composeTransitionTo ( out, transition.second ); - out.emplace_back ( "transition", sax::Token::TokenType::END_ELEMENT ); - } + out.emplace_back ( "transition", sax::Token::TokenType::END_ELEMENT ); + } out.emplace_back ( "transitions", sax::Token::TokenType::END_ELEMENT ); } diff --git a/alib2data/test-src/automaton/AutomatonTest.cpp b/alib2data/test-src/automaton/AutomatonTest.cpp index d7af0b8495..0ed5a75295 100644 --- a/alib2data/test-src/automaton/AutomatonTest.cpp +++ b/alib2data/test-src/automaton/AutomatonTest.cpp @@ -92,6 +92,12 @@ SECTION ( "NFA Insert transitions" ) { automaton2.addFinalState ( 3 ); CHECK ( automaton == automaton2 ); + + automaton.removeTransition ( 2, 'b', 3 ); + automaton2.removeTransition ( 2, 'b', 3 ); + + CHECK ( automaton == automaton2 ); + CHECK ( automaton.getTransitions ( ).size ( ) == 3 ); } SECTION ( "SinglePopDPDA Transitions" ) { diff --git a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h index 38a70bf568..31f7548068 100644 --- a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h +++ b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h @@ -28,7 +28,7 @@ namespace efficient { class AllEpsilonClosure { template < class StateType > - static void process(const ext::map<StateType, ext::set<StateType>>& epsilonTransitions, const StateType * state, ext::map<StateType, ext::set<StateType>>& closures, ext::set<StateType>& visited, ext::set<StateType>& nonvisited); + static void process(const ext::multimap<StateType, StateType>& epsilonTransitions, const StateType * state, ext::map<StateType, ext::set<StateType>>& closures, ext::set<StateType>& visited, ext::set<StateType>& nonvisited); public: /** * Computes allEpsilon closure of a state in allEpsilon nonfree automaton @@ -48,18 +48,19 @@ public: }; template < class StateType > -void AllEpsilonClosure::process(const ext::map<StateType, ext::set<StateType>>& epsilonTransitions, const StateType * state, ext::map<StateType, ext::set<StateType>>& closures, ext::set<StateType>& visited, ext::set<StateType>& nonvisited) { +void AllEpsilonClosure::process(const ext::multimap<StateType, StateType>& epsilonTransitions, const StateType * state, ext::map<StateType, ext::set<StateType>>& closures, ext::set<StateType>& visited, ext::set<StateType>& nonvisited) { if(visited.count(*state)) return; state = &*visited.insert(*state).first; nonvisited.erase(*state); - auto tos = epsilonTransitions.find(*state); - if(tos == epsilonTransitions.end()) return; + auto tos = epsilonTransitions.equal_range ( * state ); + if ( tos.empty ( ) ) + return; - for(const StateType& to : tos->second) { - process(epsilonTransitions, &to, closures, visited, nonvisited); - closures[*state].insert(closures[to].begin(), closures[to].end()); + for ( const auto & transition : tos ) { + process(epsilonTransitions, &transition.second, closures, visited, nonvisited); + closures[*state].insert(closures[transition.second].begin(), closures[transition.second].end()); } } @@ -73,7 +74,7 @@ ext::map<StateType, ext::set<StateType>> AllEpsilonClosure::allEpsilonClosure( c ext::set<StateType> visited; ext::set<StateType> nonvisited = fsm.getStates(); - ext::map<StateType, ext::set<StateType>> epsilonTransitions = fsm.getEpsilonTransitions(); + ext::multimap<StateType, StateType> epsilonTransitions = fsm.getEpsilonTransitions(); while(nonvisited.size()) { process(epsilonTransitions, &*nonvisited.begin(), res, visited, nonvisited); @@ -122,10 +123,11 @@ ext::map<StateType, ext::set<StateType>> AllEpsilonClosure::allEpsilonClosure( c ext::set<StateType> visited; ext::set<StateType> nonvisited = fsm.getStates(); - ext::map<StateType, ext::set<StateType>> epsilonTransitions; + ext::multimap<StateType, StateType> epsilonTransitions; for(const std::pair<const ext::pair<StateType, regexp::UnboundedRegExpStructure < SymbolType > >, ext::set<StateType> >& transition : fsm.getTransitions() ) if( regexp::properties::RegExpEpsilon::languageContainsEpsilon( transition.first.second ) ) - epsilonTransitions[transition.first.first].insert(transition.second.begin(), transition.second.end()); + for ( const auto & to : transition.second ) + epsilonTransitions.insert ( transition.first.first, to ); while(nonvisited.size()) { process(epsilonTransitions, &*nonvisited.begin(), res, visited, nonvisited); @@ -150,10 +152,11 @@ ext::map<StateType, ext::set<StateType>> AllEpsilonClosure::allEpsilonClosure( c ext::set<StateType> visited; ext::set<StateType> nonvisited = fsm.getStates(); - ext::map<StateType, ext::set<StateType>> epsilonTransitions; + ext::multimap<StateType, StateType > epsilonTransitions; for(const std::pair<const ext::pair<StateType, ext::vector < SymbolType > >, ext::set<StateType> >& transition : fsm.getTransitions() ) if( transition.first.second.size() == 0 ) - epsilonTransitions[transition.first.first].insert(transition.second.begin(), transition.second.end()); + for ( const auto & to : transition.second ) + epsilonTransitions.insert ( transition.first.first, to ); while(nonvisited.size()) { process(epsilonTransitions, &*nonvisited.begin(), res, visited, nonvisited); diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h index a47673c8f3..880ffd63fe 100644 --- a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h +++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h @@ -33,6 +33,8 @@ public: */ template < class T > static ext::set < typename automaton::StateTypeOfAutomaton < T > > reachableStates( const T & fsm ); + template < class SymbolType, class EpsilonType, class StateType > + static ext::set<StateType> reachableStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); template < class SymbolType, class StateType > static ext::set<StateType> reachableStates( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > @@ -87,6 +89,28 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::MultiInit return visited; } +template < class SymbolType, class EpsilonType, class StateType > +ext::set<StateType> ReachableStates::reachableStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + ext::map<StateType, ext::set<StateType>> transitions; + for(const auto& transition : fsm.getTransitions()) + transitions[transition.first.first].insert(transition.second); + + ext::deque<StateType> queue { fsm.getInitialState( ) }; + ext::set<StateType> visited { fsm.getInitialState( ) }; + + while( !queue.empty() ) { + const ext::set<StateType>& to = transitions[queue.front()]; + queue.pop_front(); + + for(const StateType& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<StateType&>(process))); + } + } + + return visited; +} + template < class SymbolType, class StateType > ext::set<StateType> ReachableStates::reachableStates( const automaton::NFA < SymbolType, StateType > & fsm ) { ext::map<StateType, ext::set<StateType>> transitions; diff --git a/alib2elgo/src/automaton/properties/efficient/UsefulStates.h b/alib2elgo/src/automaton/properties/efficient/UsefulStates.h index ee8485d79a..73507583b8 100644 --- a/alib2elgo/src/automaton/properties/efficient/UsefulStates.h +++ b/alib2elgo/src/automaton/properties/efficient/UsefulStates.h @@ -33,6 +33,8 @@ public: */ template < class T > static ext::set < typename automaton::StateTypeOfAutomaton < T > > usefulStates( const T & fsm ); + template < class SymbolType, class EpsilonType, class StateType > + static ext::set<StateType> usefulStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); template < class SymbolType, class StateType > static ext::set<StateType> usefulStates( const automaton::NFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > @@ -64,6 +66,28 @@ ext::set < typename automaton::StateTypeOfAutomaton < T > > UsefulStates::useful return visited; } +template < class SymbolType, class EpsilonType, class StateType > +ext::set<StateType> UsefulStates::usefulStates( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + ext::map<StateType, ext::set<StateType>> reversedTransitions; + for(const auto& transition : fsm.getTransitions()) + reversedTransitions[transition.second].insert(transition.first.first); + + ext::deque<StateType> queue ( fsm.getFinalStates( ).begin(), fsm.getFinalStates().end() ); + ext::set<StateType> visited = fsm.getFinalStates( ); + + while( !queue.empty() ) { + const ext::set<StateType>& to = reversedTransitions[queue.front()]; + queue.pop_front(); + + for(const StateType& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<StateType&>(process))); + } + } + + return visited; +} + template < class SymbolType, class StateType > ext::set<StateType> UsefulStates::usefulStates( const automaton::NFA < SymbolType, StateType > & fsm ) { ext::map<StateType, ext::set<StateType>> reversedTransitions; diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h index 58bbb093e7..70c05189ab 100644 --- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h +++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h @@ -63,7 +63,7 @@ automaton::NFA < SymbolType, StateType > EpsilonRemoverIncoming::remove ( const ext::map < StateType, ext::set < StateType > > closures = automaton::properties::efficient::AllEpsilonClosure::allEpsilonClosure ( origFSM ); - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > origTransitions = origFSM.getSymbolTransitions ( ); + ext::multimap < ext::pair < StateType, SymbolType >, StateType > origTransitions = origFSM.getSymbolTransitions ( ); /** * Step 1 from Melichar 2.41 @@ -71,11 +71,11 @@ automaton::NFA < SymbolType, StateType > EpsilonRemoverIncoming::remove ( const for ( const auto & from : origFSM.getStates ( ) ) for ( const auto & fromClosure : closures [ from ] ) for ( const auto & symbol : origFSM.getInputAlphabet ( ) ) { - auto transitions = origTransitions.find ( ext::make_pair ( fromClosure, symbol ) ); - if ( transitions == origTransitions.end ( ) ) continue; + auto transitions = origTransitions.equal_range ( ext::make_pair ( fromClosure, symbol ) ); + if ( transitions.empty ( ) ) continue; - for ( const auto & to : transitions->second ) - fsm.addTransition( from, symbol, to ); + for ( const auto & transition : transitions ) + fsm.addTransition( from, symbol, transition.second ); } /** diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h index 28a48477b4..5c77448301 100644 --- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h +++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h @@ -63,12 +63,11 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > EpsilonRemoverOutgoing ext::map < StateType, ext::set < StateType > > closures = automaton::properties::efficient::AllEpsilonClosure::allEpsilonClosure ( origFSM ); - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > transitions = origFSM.getSymbolTransitions ( ); + ext::multimap < ext::pair < StateType, SymbolType >, StateType > transitions = origFSM.getSymbolTransitions ( ); - for ( const std::pair < const ext::pair < StateType, SymbolType >, ext::set < StateType > > & transition : transitions ) - for ( const StateType & to : transition.second ) - for ( const StateType & toClosure : closures [ to ] ) - fsm.addTransition ( transition.first.first, transition.first.second, toClosure ); + for ( const std::pair < const ext::pair < StateType, SymbolType >, StateType > & transition : transitions ) + for ( const StateType & toClosure : closures [ transition.second ] ) + fsm.addTransition ( transition.first.first, transition.first.second, toClosure ); /** * Step 2 from Melichar 2.41 diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h index 26d75958b5..6c30a67bb3 100644 --- a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h +++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h @@ -34,6 +34,8 @@ public: */ template < class T > static T remove( const T & automaton ); + template < class SymbolType, class EpsilonType, class StateType > + static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); template < class SymbolType, class StateType > static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > @@ -71,6 +73,32 @@ T UnreachableStatesRemover::remove ( const T & fsm ) { return M; } +template < class SymbolType, class EpsilonType, class StateType > +automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > UnreachableStatesRemover::remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + // 1a + ext::set<StateType> Qa = automaton::properties::efficient::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > M(fsm.getInitialState() ); + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + M.addTransition( transition.first.first, transition.first.second, transition.second ); + + ext::set<StateType> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + return M; +} + template < class SymbolType, class StateType > automaton::NFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h index 7790915854..88ba699037 100644 --- a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h +++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h @@ -34,6 +34,8 @@ public: */ template < class T > static T remove( const T & automaton ); + template < class SymbolType, class EpsilonType, class StateType > + static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ); template < class SymbolType, class StateType > static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > @@ -73,6 +75,34 @@ T UselessStatesRemover::remove( const T & fsm ) { return M; } +template < class SymbolType, class EpsilonType, class StateType > +automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > UselessStatesRemover::remove( const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & fsm ) { + // 1. + ext::set<StateType> Qu = automaton::properties::efficient::UsefulStates::usefulStates( fsm ); + + // 2. + automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > M ( fsm.getInitialState () ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + if(Qu.size() == 0) { + return M; + } + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & t : fsm.getTransitions( ) ) + if( /* this part is not needed Qu.count( t.first.first ) && */ Qu.count( t.second ) ) + M.addTransition( t.first.first, t.first.second, t.second ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + return M; +} + template < class SymbolType, class StateType > automaton::NFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { // 1. diff --git a/alib2str/src/automaton/string/FSM/EpsilonNFA.h b/alib2str/src/automaton/string/FSM/EpsilonNFA.h index 494c431e44..1aca4d6b9d 100644 --- a/alib2str/src/automaton/string/FSM/EpsilonNFA.h +++ b/alib2str/src/automaton/string/FSM/EpsilonNFA.h @@ -171,33 +171,33 @@ void stringApi < automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > >: template < class SymbolType, class EpsilonType, class StateType > void stringApi < automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > >::composeTransitionsFromState(std::ostream& output, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & automaton, const StateType & from) { - ext::map<ext::pair<StateType, SymbolType>, ext::set<StateType> > symbolTransitionsFromState = automaton.getSymbolTransitionsFromState(from); - + ext::multimap<ext::pair<StateType, SymbolType>, StateType > symbolTransitionsFromState = automaton.getSymbolTransitionsFromState(from); for(const SymbolType& inputSymbol : automaton.getInputAlphabet()) { - const typename ext::map<ext::pair<StateType, SymbolType>, ext::set<StateType> >::iterator toStates = symbolTransitionsFromState.find(ext::make_pair(from, inputSymbol)); - if(toStates == symbolTransitionsFromState.end() || toStates->second.size() == 0) { + const auto toStates = symbolTransitionsFromState.equal_range(ext::make_pair(from, inputSymbol)); + if ( toStates.empty ( ) ) { output << " -"; } else { bool sign = false; - for(const StateType& to : toStates->second) { + for(const auto & transition : toStates ) { output << (sign ? "|" : " "); - core::stringApi < StateType >::compose ( output, to ); + core::stringApi<StateType>::compose(output, transition.second); sign = true; } } } - ext::map<StateType, ext::set<StateType> > epsilonTransitionsFromState = automaton.getEpsilonTransitionsFromState(from); - if(epsilonTransitionsFromState.size() == 0 || epsilonTransitionsFromState.begin()->second.size() == 0) { + ext::multimap<StateType, StateType > epsilonTransitionsFromState = automaton.getEpsilonTransitionsFromState(from); + if ( epsilonTransitionsFromState.empty ( ) ) { output << " -"; } else { bool sign = false; - for(const StateType& to : epsilonTransitionsFromState.begin()->second) { + for(const auto & transition : epsilonTransitionsFromState ) { output << (sign ? "|" : " "); - core::stringApi < StateType >::compose ( output, to ); + core::stringApi<StateType>::compose(output, transition.second); sign = true; } } + } } /* namespace core */ -- GitLab