diff --git a/alib2algo/src/automaton/convert/ToGrammarLeftRG.h b/alib2algo/src/automaton/convert/ToGrammarLeftRG.h index afdeea729cf411b2215927dd95a28dd8e4c817c4..52b78b2a2edfbb1a8c87ad3289a55d77eb8a3f2e 100644 --- a/alib2algo/src/automaton/convert/ToGrammarLeftRG.h +++ b/alib2algo/src/automaton/convert/ToGrammarLeftRG.h @@ -79,21 +79,20 @@ grammar::LeftRG < SymbolType, StateType > ToGrammarLeftRG::convert(const automat for(const auto& transition : automaton.getTransitions()) { const StateType& from = transition.first.first; const SymbolType& input = transition.first.second; + const StateType& to = transition.second; - for(const auto& to : transition.second) { - // 3a - grammar.addRule ( to, ext::make_pair ( from, input ) ); + // 3a + grammar.addRule ( to, ext::make_pair ( from, input ) ); - if ( automaton.getFinalStates ( ).count ( to ) > 0) - grammar.addRule ( grammar.getInitialSymbol ( ), ext::make_pair ( from, input ) ); + if ( automaton.getFinalStates ( ).count ( to ) > 0) + grammar.addRule ( grammar.getInitialSymbol ( ), ext::make_pair ( from, input ) ); - if ( automaton.getInitialState ( ) == from ) { - grammar.addRule ( to, input ); + if ( automaton.getInitialState ( ) == from ) { + grammar.addRule ( to, input ); - if ( automaton.getFinalStates ( ).count ( to ) > 0 ) - grammar.addRule ( grammar.getInitialSymbol ( ), input ); - } + if ( automaton.getFinalStates ( ).count ( to ) > 0 ) + grammar.addRule ( grammar.getInitialSymbol ( ), input ); } } diff --git a/alib2algo/src/automaton/convert/ToGrammarRightRG.h b/alib2algo/src/automaton/convert/ToGrammarRightRG.h index b09d393262e8332d7ceef49a650d34416130d5e5..619b3bf2cd4ef71326af565170985a3bae15311a 100644 --- a/alib2algo/src/automaton/convert/ToGrammarRightRG.h +++ b/alib2algo/src/automaton/convert/ToGrammarRightRG.h @@ -73,12 +73,11 @@ grammar::RightRG < SymbolType, StateType > ToGrammarRightRG::convert ( const aut for(const auto& transition : automaton.getTransitions()) { const auto & from = transition.first.first; const auto & input = transition.first.second; + const auto & to = transition.second; - for(const auto& to : transition.second) { - grammar.addRule ( from, ext::make_pair ( input, to ) ); // 2a - if(automaton.getFinalStates().count(to)) // 2b - grammar.addRule(transition.first.first, transition.first.second ); - } + grammar.addRule ( from, ext::make_pair ( input, to ) ); // 2a + if(automaton.getFinalStates().count(to)) // 2b + grammar.addRule(transition.first.first, transition.first.second ); } // step 4 diff --git a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h index 4b15fe66341148e6183ddf9fae3d17ea9ae7a5e0..a10f3f69173043dabf074e06d177fb7411946bd4 100644 --- a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h +++ b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.h @@ -128,8 +128,7 @@ regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert ( const automa solver.addEquation ( q, regexp::UnboundedRegExpEpsilon < SymbolType > { } ); for ( const auto & p : automaton.getTransitions ( ) ) - 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 } ); return solver.solve ( automaton.getInitialState ( ) ); } diff --git a/alib2algo/src/automaton/determinize/DeterminizeNFAPart.hxx b/alib2algo/src/automaton/determinize/DeterminizeNFAPart.hxx index 9ccbb2cd8f2c15dd31492bceaea6a6a805b6b701..29b98a5507ae3d9d2585c89f5c0c2f3bb1e622b5 100644 --- a/alib2algo/src/automaton/determinize/DeterminizeNFAPart.hxx +++ b/alib2algo/src/automaton/determinize/DeterminizeNFAPart.hxx @@ -85,10 +85,10 @@ automaton::DFA < SymbolType, ext::set < StateType > > Determinize::determinize ( ext::set < StateType > dfaState; for ( StateType nfaState : state ) { - auto iter = nfa.getTransitions ( ).find ( ext::make_pair ( std::move ( nfaState ), input ) ); + auto range = nfa.getTransitions ( ).equal_range ( ext::make_pair ( std::move ( nfaState ), input ) ); - if ( iter != nfa.getTransitions ( ).end ( ) ) - dfaState.insert ( iter->second.begin ( ), iter->second.end ( ) ); + for ( auto & transition : range ) + dfaState.insert ( transition.second ); } // 4 diff --git a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h index 87f3861dada2b9662e14f341efc6e879b88ef417..b995df80ce0dc6bb47652ef8ae0dfed6ccae33f9 100644 --- a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h +++ b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h @@ -183,7 +183,7 @@ automaton::NFA < SymbolType, unsigned > RandomAutomatonFactory::LeslieConnectedN } double mnn100 = 100.0 / alphabet.size( ) / n / n; - while( automaton.transitionsSize( ) * mnn100 < density ) { + while( automaton.getTransitions ( ).size ( ) * mnn100 < density ) { int y = ext::random_devices::semirandom() % n; int z = ext::random_devices::semirandom() % n; int a = ext::random_devices::semirandom() % alphabet.size(); diff --git a/alib2algo/src/automaton/generate/RandomizeAutomaton.h b/alib2algo/src/automaton/generate/RandomizeAutomaton.h index 3ade0f2d9d9c2aac8011e40914f6104f90c354e3..51815ffc2b2843abf99f1e52206aed8de5d4f9f4 100644 --- a/alib2algo/src/automaton/generate/RandomizeAutomaton.h +++ b/alib2algo/src/automaton/generate/RandomizeAutomaton.h @@ -97,7 +97,7 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > RandomizeAutomaton::ra res.setStates ( origFSM.getStates ( ) ); res.setInputAlphabet ( origFSM.getInputAlphabet ( ) ); - + for ( const StateType & initialState : origFSM.getInitialStates ( ) ) res.addInitialState ( statePermutationMap.find ( initialState )->second ); @@ -123,9 +123,8 @@ automaton::NFA < SymbolType, StateType > RandomizeAutomaton::randomize(const aut for ( const StateType & finalState : origFSM.getFinalStates ( ) ) res.addFinalState ( statePermutationMap.find ( finalState )->second ); - for ( const std::pair < std::pair < StateType, 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, 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/ReachableStates.h b/alib2algo/src/automaton/properties/ReachableStates.h index 4c95a48761fa917896709b878b7551358002f5e5..96c81bf68c05160fab56a3598b48a25944a9c555 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 StateType > + static ext::set<StateType> reachableStates( const automaton::NFA < SymbolType, StateType > & fsm ); + /** * Finds all reachable states of a deterministic finite automaton. * Using closure implementation of the BFS algorithm. @@ -82,35 +96,35 @@ public: * * @tparam SymbolType Type for the input symbols. * @tparam StateType Type for the states. - * @param fsm nondeterministic automaton with multiple initial states + * @param fsm deterministic finite automaton * @return set of reachable states from the initial state of @p fsm */ template < class SymbolType, class StateType > static ext::set<StateType> reachableStates( const automaton::DFA < SymbolType, StateType > & fsm ); /** - * Finds all reachable states of a deterministic finite automaton. + * Finds all reachable states of a deterministic tree 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 automaton with multiple initial states + * @param fsm deterministic tree automaton * @return set of reachable states from the initial state of @p fsm */ template < class SymbolType, class RankType, class StateType > static ext::set<StateType> reachableStates( const automaton::DFTA < SymbolType, RankType, StateType > & fta ); /** - * Finds all reachable states of a deterministic finite automaton. + * Finds all reachable states of a nondeterministic tree 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 automaton with multiple initial states + * @param fsm nondeterministic tree automaton * @return set of reachable states from the initial state of @p fsm */ template < class SymbolType, class RankType, class StateType > @@ -171,6 +185,32 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::MultiInit return Qi.at( i ); } +template < class SymbolType, class StateType > +ext::set<StateType> ReachableStates::reachableStates( const automaton::NFA < SymbolType, 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::DFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2algo/src/automaton/run/Run.h b/alib2algo/src/automaton/run/Run.h index 2919ec748e51a68b45442f76a1567a75d617be8e..e2cfd634a7d7bf74fffdaaf7625ecf58fe0aa35d 100644 --- a/alib2algo/src/automaton/run/Run.h +++ b/alib2algo/src/automaton/run/Run.h @@ -337,11 +337,10 @@ 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, symbol ) ); + auto transitions = automaton.getTransitions ( ).equal_range ( ext::make_pair ( state, symbol ) ); - if ( transitions == automaton.getTransitions ( ).end ( ) ) continue; - - next.insert ( transitions->second.begin ( ), transitions->second.end ( ) ); + for ( const auto & transition : transitions ) + next.insert ( transition.second ); } i++; diff --git a/alib2algo/src/automaton/simplify/Rename.h b/alib2algo/src/automaton/simplify/Rename.h index 6c29385c58fc66169145dc7aee47d9579ef282af..195ee09c82ccf4a87da078b6625e0fac50ed69d5 100644 --- a/alib2algo/src/automaton/simplify/Rename.h +++ b/alib2algo/src/automaton/simplify/Rename.h @@ -217,8 +217,7 @@ automaton::NFA < SymbolType, unsigned > Rename::rename ( const automaton::NFA < result.addFinalState ( renamingData.at ( state ) ); for ( const auto & transition : fsm.getTransitions ( ) ) - for ( const auto & toState : transition.second ) - result.addTransition ( renamingData.at ( transition.first.first ), transition.first.second, renamingData.at ( toState ) ); + result.addTransition ( renamingData.at ( transition.first.first ), transition.first.second, renamingData.at ( transition.second ) ); return result; } diff --git a/alib2algo/src/automaton/simplify/Total.h b/alib2algo/src/automaton/simplify/Total.h index 99cad48f19148f84498b068ed0d1cf60cc5bfb84..faf5a6d843425b7ceefd76049a9d6b28916780b7 100644 --- a/alib2algo/src/automaton/simplify/Total.h +++ b/alib2algo/src/automaton/simplify/Total.h @@ -67,7 +67,7 @@ automaton::NFA < SymbolType, StateType > Total::total(const automaton::NFA < Sym for(const auto& q : res.getStates()) { for(const auto& a : res.getInputAlphabet()) { - if ( res.getTransitions ( ).find ( ext::make_pair ( q, a ) ) == res.getTransitions ( ).end ( ) || res.getTransitions ( ).at ( ext::make_pair ( q, a ) ).size ( ) == 0 ) { + if ( res.getTransitions ( ).find ( ext::make_pair ( q, a ) ) == res.getTransitions ( ).end ( ) ) { res.addTransition ( q, a, nullState ); } } diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h index f7451af96e882bb4a454ff0812fd9ffcc030d1a3..943e8532567bd3cd9a01424ee4a2a2393f74fd64 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 StateType > + static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); + /** * @overload * @tparam SymbolType Type for input symbols. @@ -141,6 +149,32 @@ T UnreachableStatesRemover::remove ( const T & fsm ) { return M; } +template < class SymbolType, class StateType > +automaton::NFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { + // 1a + ext::set<StateType> Qa = automaton::properties::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::NFA < SymbolType, 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::DFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::DFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.h b/alib2algo/src/automaton/simplify/UselessStatesRemover.h index 1e1f18c9ce17aba232d8aa28b77b0e95ca92aecb..168eeb7c0f5f64b851ae0536795712005896261a 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 StateType > + static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); + /** * @overload * @tparam SymbolType Type for input symbols. @@ -133,6 +141,34 @@ T UselessStatesRemover::remove( const T & fsm ) { return M; } +template < class SymbolType, class StateType > +automaton::NFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { + // 1. + ext::set<StateType> Qu = automaton::properties::UsefulStates::usefulStates( fsm ); + + // 2. + automaton::NFA < SymbolType, 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::DFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::DFA < SymbolType, StateType > & fsm ) { // 1. diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.h b/alib2algo/src/automaton/transform/AutomataConcatenation.h index 6fcac5d91af9a0646e535395d0ecbc92804b7fc6..e3c538f3b59169f238e14c1ad4b23118d60df0d2 100644 --- a/alib2algo/src/automaton/transform/AutomataConcatenation.h +++ b/alib2algo/src/automaton/transform/AutomataConcatenation.h @@ -74,17 +74,14 @@ automaton::NFA < SymbolType, ext::pair < StateType, unsigned > > AutomataConcate res.addInputSymbols ( second.getInputAlphabet ( ) ); 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 ) ); - if(first.getFinalStates().count(q) > 0) - res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( second.getInitialState ( ), secondDefault ) ); - } + if(first.getFinalStates().count(t.second) > 0) + res.addTransition ( ext::make_pair ( t.first.first, firstDefault ), t.first.second, ext::make_pair ( second.getInitialState ( ), secondDefault ) ); } 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 : second.getFinalStates ( ) ) res.addFinalState ( ext::make_pair ( q, secondDefault ) ); @@ -97,12 +94,10 @@ automaton::NFA < SymbolType, ext::pair < StateType, unsigned > > AutomataConcate res.setInitialState ( q01q02 ); for ( const auto & t : first.getTransitionsFromState ( first.getInitialState ( ) ) ) - for ( const StateType & q : t.second ) - res.addTransition ( q01q02, t.first.second, ext::make_pair ( q, firstDefault ) ); + res.addTransition ( q01q02, t.first.second, ext::make_pair ( t.second, firstDefault ) ); for ( const auto & t : second.getTransitionsFromState ( second.getInitialState ( ) ) ) - for ( const StateType & q : t.second ) - res.addTransition ( q01q02, t.first.second, ext::make_pair ( q, secondDefault ) ); + res.addTransition ( q01q02, t.first.second, ext::make_pair ( t.second, secondDefault ) ); res.addFinalState ( q01q02 ); } diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h index 9683015704925924960456839faa8268383a046f..33daa73c1f6eae1cdd7e1866c1ae9085a9bb4fb5 100644 --- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h +++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h @@ -111,12 +111,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 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 ) ); 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/AutomataIntersectionCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h index 9265e2e5bd98f87beaab3f1f99439426d7ba6487..bca707e125d8f31dfde1950c36181a73c2beef8d 100644 --- a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h +++ b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h @@ -105,9 +105,7 @@ automaton::NFA < SymbolType, ext::pair < StateType1, StateType2 > > AutomataInte for(const auto & tp : first.getTransitionsFromState ( state.first ) ) for(const auto & tq : second.getTransitionsFromState ( state.second ) ) if(tp.first.second == tq.first.second) - for(const auto & p : tp.second) - for(const auto & q : tq.second) - res.addTransition ( state, tp.first.second, ext::make_pair ( p, q ) ); + res.addTransition ( state, tp.first.second, ext::make_pair ( tp.second, tq.second ) ); return res; } diff --git a/alib2algo/src/automaton/transform/AutomataLeftQuotientCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataLeftQuotientCartesianProduct.h index 1c448d82cbacbf8023573732e6c2d8814a1b302b..ae61c00efd4417437e31953b8711c76f141c838a 100644 --- a/alib2algo/src/automaton/transform/AutomataLeftQuotientCartesianProduct.h +++ b/alib2algo/src/automaton/transform/AutomataLeftQuotientCartesianProduct.h @@ -77,14 +77,12 @@ automaton::MultiInitialStateNFA < SymbolType, ext::pair < StateType1, StateType2 for(const auto & tp : first.getTransitionsFromState ( state.first ) ) for(const auto & tq : second.getTransitionsFromState ( state.second ) ) - if(tp.first.second == tq.first.second) - for(const auto & p : tp.second) - for(const auto & q : tq.second) { - if ( ! full || ! first.getFinalStates ( ).count ( p ) ) - delta [ ext::make_pair ( state, tp.first.second ) ].insert ( ext::make_pair ( p, q ) ); - - queue.push ( ext::make_pair ( p, q ) ); // Note: the original paper kept this queue push statement included in body of the above condition. That is not correct. - } + if(tp.first.second == tq.first.second) { + if ( ! full || ! first.getFinalStates ( ).count ( tp.second ) ) + delta [ ext::make_pair ( state, tp.first.second ) ].insert ( ext::make_pair ( tp.second, tq.second ) ); + + queue.push ( ext::make_pair ( tp.second, tq.second ) ); // Note: the original paper kept this queue push statement included in body of the above condition. That is not correct. + } } } diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h index 6adbe5936f3c5a4b4f9bc3e85b5d956fa6679e51..87b51bfb43eac8bc71deceabd2546b3ba0514f00 100644 --- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h +++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h @@ -120,9 +120,7 @@ automaton::NFA < SymbolType, ext::pair < StateType1, StateType2 > > AutomataUnio for(const auto& tp : first.getTransitionsFromState(state.first)) for(const auto& tq : second.getTransitionsFromState(state.second)) if(tp.first.second == tq.first.second) - for(const auto& p : tp.second) - for(const auto& q : tq.second) - res.addTransition(state, tp.first.second, ext::make_pair(p, q)); + res.addTransition(state, tp.first.second, ext::make_pair(tp.second, tq.second)); return res; } diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h index fc9c144f09f7909107522f1babda92f62abef738..bca0bab6cba8a03c9f4c373dcf984ce7b3ffd8e2 100644 --- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h +++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h @@ -127,12 +127,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/alib2algo/src/automaton/transform/AutomatonIteration.h b/alib2algo/src/automaton/transform/AutomatonIteration.h index bedd5fb8c5d7eef96a659822b7a250c565ed708a..6615cfb4daf8d9a44f9bb1016fcc743c1a7f0771 100644 --- a/alib2algo/src/automaton/transform/AutomatonIteration.h +++ b/alib2algo/src/automaton/transform/AutomatonIteration.h @@ -87,8 +87,7 @@ automaton::NFA < SymbolType, StateType > AutomatonIteration::iteration(const aut res.addFinalState(newInitialState); for(const auto& t : automaton.getTransitionsFromState(automaton.getInitialState())) - for (const StateType & toState : t.second ) - res.addTransition(newInitialState, t.first.second, toState); + res.addTransition(newInitialState, t.first.second, t.second); return res; } diff --git a/alib2algo/src/automaton/transform/Reverse.h b/alib2algo/src/automaton/transform/Reverse.h index 6780899024063c9883a5c018d1250357974e3472..532cb2de17496fe74b8ac00577964597e838cb0c 100644 --- a/alib2algo/src/automaton/transform/Reverse.h +++ b/alib2algo/src/automaton/transform/Reverse.h @@ -86,8 +86,7 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > Reverse::convert(const res.setInputAlphabet(automaton.getInputAlphabet()); for(const auto& t : automaton.getTransitions()) - for(const auto& q : t.second) - res.addTransition(q, t.first.second, t.first.first); + res.addTransition(t.second, t.first.second, t.first.first); return res; } diff --git a/alib2aux/src/compare/DiffAux.h b/alib2aux/src/compare/DiffAux.h index bda970ef39b6062ca6ba2750f8075ba574fedc32..3b44798b1b3d9e55f02c351d1f96d382060435a6 100644 --- a/alib2aux/src/compare/DiffAux.h +++ b/alib2aux/src/compare/DiffAux.h @@ -11,6 +11,7 @@ #include <alib/set> #include <alib/list> #include <alib/map> +#include <alib/multimap> #include <alib/vector> #include <alib/algorithm> @@ -26,6 +27,8 @@ public: static void listDiff ( std::ostream & out, const ext::list < T > & a, const ext::list < T > & b ); template < class T, class R > static void mapDiff ( std::ostream & out, const ext::map < T, R > & a, const ext::map < T, R > & b ); + template < class T, class R > + static void mapDiff ( std::ostream & out, const ext::multimap < T, R > & a, const ext::multimap < T, R > & b ); }; template <class T> @@ -96,6 +99,23 @@ void DiffAux::mapDiff(std::ostream & out, const ext::map<T, R> &a, const ext::ma out << "> " << iter->first << ", " << iter->second << std::endl; } +template <class T, class R> +void DiffAux::mapDiff(std::ostream & out, const ext::multimap<T, R> &a, const ext::multimap<T, R> &b) { + ext::map<T, R> aMinusB; + std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(aMinusB, aMinusB.begin())); + + ext::map<T, R> bMinusA; + std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::inserter(bMinusA, bMinusA.begin())); + + for(typename ext::map<T, R>::const_iterator iter = aMinusB.begin(); iter != aMinusB.end(); iter++) + out << "< " << iter->first << ", " << iter->second << std::endl; + + out << "---" << std::endl; + + for(typename ext::map<T, R>::const_iterator iter = bMinusA.begin(); iter != bMinusA.end(); iter++) + out << "> " << iter->first << ", " << iter->second << std::endl; +} + } /* namespace compare */ #endif /* _DIFF_AUX_H_ */ diff --git a/alib2aux/src/convert/DotConverter.h b/alib2aux/src/convert/DotConverter.h index fd0ad794ee35e6b5e109a8aff43353b06acf82ac..490df1324918cb511bd21e11fc0e2f0e87f21858 100644 --- a/alib2aux/src/convert/DotConverter.h +++ b/alib2aux/src/convert/DotConverter.h @@ -859,22 +859,20 @@ void DotConverter::transitions(const automaton::NFA < SymbolType, StateType > & for (const auto& transition : fsm.getTransitions()) { std::string symbol = replace ( factory::StringDataFactory::toString ( transition.first.second ), "\"", "\\\"" ); - 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 4012398807db137d64178615aacc33dee4b43826..9b6e108d8dba2c435f689f82cf03d5c103ee45ff 100644 --- a/alib2aux/src/convert/GasTexConverter.h +++ b/alib2aux/src/convert/GasTexConverter.h @@ -930,17 +930,15 @@ template<class SymbolType, class StateType> void GasTexConverter::transitions(const automaton::NFA < SymbolType, 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 = replace ( factory::StringDataFactory::toString ( transition.first.second ), "\"", "\\\"" ); + std::string symbol = replace ( factory::StringDataFactory::toString ( transition.first.second ), "\"", "\\\"" ); - 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 f0d3a74b7b1bf3abefa97cdce699b09e8c2e2a81..329695a7eaca613869b052516cf0ac7c90e590c7 100644 --- a/alib2aux/src/convert/TikZConverter.h +++ b/alib2aux/src/convert/TikZConverter.h @@ -820,26 +820,24 @@ void TikZConverter::transitions ( const automaton::NFA < SymbolType, StateType > for ( const auto & transition : fsm.getTransitions ( ) ) { std::string symbol = replace ( factory::StringDataFactory::toString ( transition.first.second ), "\"", "\\\"" ); - 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 a92a892137fea0f914185a9921c24b2b9e4a1deb..87b45b1d08f04a1244f49da95d93d5122f41e5e8 100644 --- a/alib2data/src/automaton/FSM/CompactNFA.h +++ b/alib2data/src/automaton/FSM/CompactNFA.h @@ -483,7 +483,7 @@ CompactNFA < SymbolType, StateType >::CompactNFA ( const MultiInitialStateNFA < template < class SymbolType, class StateType > CompactNFA < SymbolType, StateType >::CompactNFA ( const NFA < SymbolType, StateType > & other ) : CompactNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions.insert ( ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second } ), transition.second ); + transitions [ ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second } ) ].insert ( transition.second ); } template < class SymbolType, class StateType > @@ -495,7 +495,7 @@ CompactNFA < SymbolType, StateType >::CompactNFA ( const CompactDFA < SymbolType template < class SymbolType, class StateType > CompactNFA < SymbolType, StateType >::CompactNFA ( const DFA < SymbolType, StateType > & other ) : CompactNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions.insert ( ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second } ), ext::set < StateType > { transition.second } ); + transitions [ ext::make_pair ( transition.first.first, ext::vector < SymbolType > { transition.first.second } ) ].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 8fe6191a6da3851606632091cc447bf1e1affc1e..dd0b4eb11390053891bf3e2fa6cd1d84faac29b2 100644 --- a/alib2data/src/automaton/FSM/EpsilonNFA.h +++ b/alib2data/src/automaton/FSM/EpsilonNFA.h @@ -579,13 +579,13 @@ EpsilonNFA < SymbolType, EpsilonType, StateType >::EpsilonNFA ( const MultiIniti 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.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), transition.second ); + transitions [ ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ) ].insert ( 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.insert ( ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ), ext::set < StateType > { transition.second } ); + transitions [ ext::make_pair ( transition.first.first, ext::variant < EpsilonType, SymbolType > ( transition.first.second ) ) ].insert ( transition.second ); } template<class SymbolType, class EpsilonType, class StateType > diff --git a/alib2data/src/automaton/FSM/ExtendedNFA.h b/alib2data/src/automaton/FSM/ExtendedNFA.h index d54dc2ed458941334963ae89deccf2688db13bbe..49f2e64230690c4f5257b2a366e6c9d03d1fe5c2 100644 --- a/alib2data/src/automaton/FSM/ExtendedNFA.h +++ b/alib2data/src/automaton/FSM/ExtendedNFA.h @@ -511,7 +511,7 @@ template<class SymbolType, class StateType > ExtendedNFA < SymbolType, StateType >::ExtendedNFA ( const NFA < SymbolType, StateType > & other ) : ExtendedNFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) { ext::pair < StateType, regexp::UnboundedRegExpStructure < SymbolType > > key = ext::make_pair ( transition.first.first, regexp::UnboundedRegExpStructure < SymbolType > ( regexp::UnboundedRegExpSymbol < SymbolType > ( transition.first.second ) ) ); - 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 e3778c132d1cf7e4220518a55b3e5168cc6a3d81..17f1b01dfe99326e4c2e2ca7fd44a783ed8c1841 100644 --- a/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h +++ b/alib2data/src/automaton/FSM/MultiInitialStateEpsilonNFA.h @@ -624,7 +624,7 @@ template<class SymbolType, class EpsilonType, class StateType > MultiInitialStateEpsilonNFA < SymbolType, EpsilonType, StateType >::MultiInitialStateEpsilonNFA ( const NFA < SymbolType, 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/MultiInitialStateNFA.h b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h index c7f9594ecd69535345d695f976bffc75e46bd43f..16cf9c9972189f3f8a39e1fbcaee6cbf4dfa0b26 100644 --- a/alib2data/src/automaton/FSM/MultiInitialStateNFA.h +++ b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h @@ -466,7 +466,7 @@ MultiInitialStateNFA < SymbolType, StateType >::MultiInitialStateNFA ( const DFA template < class SymbolType, class StateType > MultiInitialStateNFA < SymbolType, StateType >::MultiInitialStateNFA ( const NFA < SymbolType, StateType > & other ) : MultiInitialStateNFA ( other.getStates ( ), other.getInputAlphabet ( ), { other.getInitialState ( ) }, other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions[transition.first] = transition.second; + transitions[transition.first].insert ( transition.second ); } template < class SymbolType, class StateType > diff --git a/alib2data/src/automaton/FSM/NFA.h b/alib2data/src/automaton/FSM/NFA.h index e7e1091b61f8da0bd2fd1ea857098d73484f62e8..59c894082aa73799472d54ffa69a8e0b0ec9570b 100644 --- a/alib2data/src/automaton/FSM/NFA.h +++ b/alib2data/src/automaton/FSM/NFA.h @@ -24,7 +24,7 @@ #ifndef NFA_H_ #define NFA_H_ -#include <alib/map> +#include <alib/multimap> #include <alib/set> #include <alib/compare> @@ -69,7 +69,7 @@ class NFA final : public ext::CompareOperators < NFA < SymbolType, StateType > > /** * Transition function as mapping from a state times an input symbol on the left hand side to a set of states. */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > transitions; + ext::multimap < ext::pair < StateType, SymbolType >, StateType> transitions; public: /** @@ -296,19 +296,6 @@ public: */ bool addTransition ( StateType current, SymbolType input, StateType next ); - /** - * \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 current, SymbolType input, ext::set < StateType > next ); - /** * \brief Removes a transition from the automaton. * @@ -327,14 +314,14 @@ public: * * \returns transition function of the automaton */ - const ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > & getTransitions ( ) const &; + const ext::multimap < ext::pair < StateType, 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, SymbolType >, ext::set < StateType > > && getTransitions ( ) &&; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > && getTransitions ( ) &&; /** * Get a subset of the transition function of the automaton, with the source state fixed in the transitions natural representation. @@ -343,7 +330,7 @@ public: * * \returns a subset of the transition function of the automaton with the source state fixed */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > getTransitionsFromState ( const StateType & from ) const; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > getTransitionsFromState ( const StateType & from ) const; /** * Get a subset of the transition function of the automaton, with the target state fixed in the transitions natural representation. @@ -352,7 +339,7 @@ public: * * \returns a subset of the transition function of the automaton with the target state fixed */ - ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > getTransitionsToState ( const StateType & from ) const; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > getTransitionsToState ( const StateType & from ) const; /** * \brief Determines whether the automaton is deterministic. @@ -375,13 +362,6 @@ public: */ bool isTotal ( ) const; - /** - * \brief Computes number of transitions in the automaton - * - * \return number of transitions in the automaton - */ - unsigned transitionsSize ( ) const; - /** * The actual compare method * @@ -428,7 +408,7 @@ NFA < SymbolType, StateType >::NFA ( StateType initialState ) : NFA ( ext::set < template<class SymbolType, class StateType > NFA < SymbolType, StateType >::NFA ( const DFA < SymbolType, StateType > & other ) : NFA ( other.getStates ( ), other.getInputAlphabet ( ), other.getInitialState ( ), other.getFinalStates ( ) ) { for ( const auto & transition : other.getTransitions ( ) ) - transitions[transition.first].insert ( transition.second ); + transitions.insert ( transition ); } template<class SymbolType, class StateType > @@ -444,74 +424,72 @@ bool NFA < SymbolType, StateType >::addTransition ( StateType from, SymbolType i ext::pair < StateType, SymbolType > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); - return transitions[std::move ( key )].insert ( std::move ( to ) ).second; -} - -template < class SymbolType, class StateType > -void NFA < SymbolType, StateType >::addTransitions ( StateType from, SymbolType input, ext::set < StateType > to ) { - if ( !getStates ( ).count ( from ) ) - throw AutomatonException ( "State \"" + ext::to_string ( from ) + "\" doesn't exist." ); - - if ( !getInputAlphabet ( ).count ( input ) ) - 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." ); + 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 ) + return false; - ext::pair < StateType, SymbolType > key = ext::make_pair ( std::move ( from ), std::move ( input ) ); + 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 [ std::move ( key ) ].insert ( ext::make_mover ( to ).begin ( ), ext::make_mover ( to ).end ( ) ); + transitions.insert ( lower_bound, 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 ); return transitions[key].erase ( to ); } template<class SymbolType, class StateType > -const ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > & NFA < SymbolType, StateType >::getTransitions ( ) const & { +const ext::multimap < ext::pair < StateType, SymbolType >, StateType > & NFA < SymbolType, StateType >::getTransitions ( ) const & { return transitions; } template<class SymbolType, class StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > && NFA < SymbolType, StateType >::getTransitions ( ) && { +ext::multimap < ext::pair < StateType, SymbolType >, StateType > && NFA < SymbolType, StateType >::getTransitions ( ) && { return std::move ( transitions ); } template<class SymbolType, class StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > NFA < SymbolType, StateType >::getTransitionsFromState ( const StateType & from ) const { +ext::multimap < ext::pair < StateType, SymbolType >, StateType > NFA < SymbolType, 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, SymbolType >, ext::set < StateType > > transitionsFromState; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > transitionsFromState; - for ( const std::pair < const ext::pair < StateType, SymbolType >, ext::set < StateType > > & transition : transitions ) + for ( const std::pair < const ext::pair < StateType, 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 StateType > -ext::map < ext::pair < StateType, SymbolType >, ext::set < StateType > > NFA < SymbolType, StateType >::getTransitionsToState ( const StateType & to ) const { +ext::multimap < ext::pair < StateType, SymbolType >, StateType > NFA < SymbolType, 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, SymbolType >, ext::set < StateType > > transitionsToState; + ext::multimap < ext::pair < StateType, SymbolType >, StateType > transitionsToState; - for ( const std::pair < const ext::pair < StateType, 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, SymbolType >, StateType > & transition : transitions ) + if ( transition.second == to ) + transitionsToState.insert ( transition ); return transitionsToState; } template<class SymbolType, class StateType > bool NFA < SymbolType, StateType >::isDeterministic ( ) const { - for ( const std::pair < const ext::pair < StateType, 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 true; @@ -519,17 +497,7 @@ bool NFA < SymbolType, StateType >::isDeterministic ( ) const { template<class SymbolType, class StateType > bool NFA < SymbolType, StateType >::isTotal ( ) const { - return isDeterministic ( ) && transitionsSize ( ) == getInputAlphabet ( ).size ( ) * getStates ( ).size ( ); -} - -template<class SymbolType, class StateType > -unsigned NFA < SymbolType, StateType >::transitionsSize ( ) const { - int res = 0; - - for ( const auto & transition : transitions ) - res += transition.second.size ( ); - - return res; + return isDeterministic ( ) && transitions.size ( ) == getInputAlphabet ( ).size ( ) * getStates ( ).size ( ); } template<class SymbolType, class StateType > @@ -571,7 +539,7 @@ public: * \returns true if the symbol is used, false othervise */ static bool used ( const automaton::NFA < SymbolType, StateType > & automaton, const SymbolType & symbol ) { - for ( const std::pair < const ext::pair < StateType, SymbolType >, ext::set < StateType > > & transition : automaton.getTransitions ( ) ) + for ( const std::pair < const ext::pair < StateType, SymbolType >, StateType > & transition : automaton.getTransitions ( ) ) if ( transition.first.second == symbol ) return true; @@ -624,8 +592,8 @@ public: if ( automaton.getFinalStates ( ).count ( state ) ) return true; - for ( const std::pair < const ext::pair < StateType, SymbolType >, ext::set < StateType > > & transition : automaton.getTransitions ( ) ) - if ( ( transition.first.first == state ) || ( transition.second.find ( state ) != transition.second.end ( ) ) ) + for ( const std::pair < const ext::pair < StateType, SymbolType >, StateType > & transition : automaton.getTransitions ( ) ) + if ( ( transition.first.first == state ) || transition.second == state ) return true; return false; @@ -742,12 +710,12 @@ struct normalize < automaton::NFA < SymbolType, StateType > > { automaton::NFA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( initialState ), std::move ( finalStates ) ); - for ( std::pair < ext::pair < StateType, SymbolType >, ext::set < StateType > > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { + for ( std::pair < ext::pair < StateType, SymbolType >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { DefaultStateType from = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.first.first ) ); DefaultSymbolType input = alphabet::SymbolNormalize::normalizeSymbol ( 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/xml/FSM/NFA.h b/alib2data/src/automaton/xml/FSM/NFA.h index 37e1e52a58a410057a3ad38f479e5ec2776e0948..71a0df1bfe206953fde63b4d4c4c07e06deef4d9 100644 --- a/alib2data/src/automaton/xml/FSM/NFA.h +++ b/alib2data/src/automaton/xml/FSM/NFA.h @@ -138,16 +138,15 @@ template<class SymbolType, class StateType > void xmlApi < automaton::NFA < SymbolType, StateType > >::composeTransitions ( ext::deque < sax::Token > & out, const automaton::NFA < SymbolType, 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::composeTransitionInputSymbol ( out, transition.first.second ); - automaton::AutomatonToXMLComposer::composeTransitionTo ( out, targetState ); + automaton::AutomatonToXMLComposer::composeTransitionFrom ( out, transition.first.first ); + automaton::AutomatonToXMLComposer::composeTransitionInputSymbol ( 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 7bc59427584215cb30625c41f72b36226e79f0e8..d7af0b8495ce5a57d98b940c52a49e0319251245 100644 --- a/alib2data/test-src/automaton/AutomatonTest.cpp +++ b/alib2data/test-src/automaton/AutomatonTest.cpp @@ -84,8 +84,10 @@ SECTION ( "NFA Insert transitions" ) { automaton2.addInputSymbol ( 'a' ); automaton2.addInputSymbol ( 'b' ); - automaton2.addTransitions ( 1, 'a', ext::set < int > ( { 1, 2 } ) ); - automaton2.addTransitions ( 2, 'b', ext::set < int > ( { 2, 3 } ) ); + automaton2.addTransition ( 1, 'a', 1 ); + automaton2.addTransition ( 1, 'a', 2 ); + automaton2.addTransition ( 2, 'b', 2 ); + automaton2.addTransition ( 2, 'b', 3 ); automaton2.addFinalState ( 3 ); diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h index 941f33fb18f954c0c2ad2054949c32046f427b32..a47673c8f3321adfe38f2901cea2590ee6ae2257 100644 --- a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h +++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h @@ -36,6 +36,8 @@ public: template < class SymbolType, class StateType > static ext::set<StateType> reachableStates( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > + static ext::set<StateType> reachableStates( const automaton::NFA < SymbolType, StateType > & fsm ); + template < class SymbolType, class StateType > static ext::set<StateType> reachableStates( const automaton::DFA < SymbolType, StateType > & fsm ); }; @@ -85,6 +87,28 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::MultiInit 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; + 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::DFA < 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 f262e217e13f8d886002e4b0ea073854e9de2368..ee8485d79abb17abe336e90ba8dcffe802373d0a 100644 --- a/alib2elgo/src/automaton/properties/efficient/UsefulStates.h +++ b/alib2elgo/src/automaton/properties/efficient/UsefulStates.h @@ -34,6 +34,8 @@ public: template < class T > static ext::set < typename automaton::StateTypeOfAutomaton < T > > usefulStates( const T & fsm ); template < class SymbolType, class StateType > + static ext::set<StateType> usefulStates( const automaton::NFA < SymbolType, StateType > & fsm ); + template < class SymbolType, class StateType > static ext::set<StateType> usefulStates( const automaton::DFA < SymbolType, StateType > & fsm ); }; @@ -62,6 +64,28 @@ ext::set < typename automaton::StateTypeOfAutomaton < T > > UsefulStates::useful 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; + 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::DFA < SymbolType, StateType > & fsm ) { ext::map<StateType, ext::set<StateType>> reversedTransitions; diff --git a/alib2elgo/src/automaton/simplify/efficient/Trim.h b/alib2elgo/src/automaton/simplify/efficient/Trim.h index 005b7c04424245176e6dbb8df425fff3dd5b1791..bdad084ad716223e6d21bc6a75a14ae092bf5700 100644 --- a/alib2elgo/src/automaton/simplify/efficient/Trim.h +++ b/alib2elgo/src/automaton/simplify/efficient/Trim.h @@ -32,7 +32,7 @@ public: template<class T> T Trim::trim( const T & fsm ) { - return UnreachableStatesRemover::remove(UselessStatesRemover::remove(fsm)); + return UselessStatesRemover::remove ( UnreachableStatesRemover::remove( fsm ) ); } } /* namespace efficient */ diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h index 4a93bd1dd9212e257c8a5198ffa884cc525a359d..26d75958b5710e66095540cade8706090d71e3b8 100644 --- a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h +++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h @@ -35,6 +35,8 @@ public: template < class T > static T remove( const T & automaton ); template < class SymbolType, class StateType > + static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); + template < class SymbolType, class StateType > static automaton::DFA < SymbolType, StateType > remove( const automaton::DFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > static automaton::MultiInitialStateNFA < SymbolType, StateType > remove( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm ); @@ -69,6 +71,32 @@ T UnreachableStatesRemover::remove ( const T & fsm ) { return M; } +template < class SymbolType, class StateType > +automaton::NFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { + // 1a + ext::set<StateType> Qa = automaton::properties::efficient::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::NFA < SymbolType, 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::DFA < SymbolType, StateType > UnreachableStatesRemover::remove( const automaton::DFA < SymbolType, StateType > & fsm ) { // 1a diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h index ef96549104cf81171af4ce20806c89e4b9009b74..77909158541f9523f7644c87c40e1099774a015a 100644 --- a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h +++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h @@ -35,6 +35,8 @@ public: template < class T > static T remove( const T & automaton ); template < class SymbolType, class StateType > + static automaton::NFA < SymbolType, StateType > remove( const automaton::NFA < SymbolType, StateType > & fsm ); + template < class SymbolType, class StateType > static automaton::DFA < SymbolType, StateType > remove( const automaton::DFA < SymbolType, StateType > & fsm ); template < class SymbolType, class StateType > static automaton::MultiInitialStateNFA < SymbolType, StateType > remove( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm ); @@ -71,6 +73,34 @@ T UselessStatesRemover::remove( const T & fsm ) { return M; } +template < class SymbolType, class StateType > +automaton::NFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::NFA < SymbolType, StateType > & fsm ) { + // 1. + ext::set<StateType> Qu = automaton::properties::efficient::UsefulStates::usefulStates( fsm ); + + // 2. + automaton::NFA < SymbolType, 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::DFA < SymbolType, StateType > UselessStatesRemover::remove( const automaton::DFA < SymbolType, StateType > & fsm ) { // 1. diff --git a/alib2str/src/automaton/string/FSM/NFA.h b/alib2str/src/automaton/string/FSM/NFA.h index d852ec6d0ece4e9e3f834f54ab5b3ca97b5d0a0f..75076830587525b7a93544c5cb13ea340dfe6c8c 100644 --- a/alib2str/src/automaton/string/FSM/NFA.h +++ b/alib2str/src/automaton/string/FSM/NFA.h @@ -162,17 +162,17 @@ void stringApi < automaton::NFA < SymbolType, StateType > >::compose ( std::ostr template < class SymbolType, class StateType > void stringApi < automaton::NFA < SymbolType, StateType > >::composeTransitionsFromState(std::ostream& output, const automaton::NFA < SymbolType, StateType > & automaton, const StateType & from) { - ext::map<ext::pair<StateType, SymbolType>, ext::set<StateType> > symbolTransitionsFromState = automaton.getTransitionsFromState(from); + ext::multimap<ext::pair<StateType, SymbolType>, StateType > symbolTransitionsFromState = automaton.getTransitionsFromState(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; } }