diff --git a/atrim/src/RedundantStateRemover.cpp b/atrim/src/RedundantStateRemover.cpp new file mode 100644 index 0000000000000000000000000000000000000000..409aee5cf7a8f312c32d877198898369f45b76f8 --- /dev/null +++ b/atrim/src/RedundantStateRemover.cpp @@ -0,0 +1,62 @@ +/* + * RedundantStateRemover.cpp + * + * Created on: 4. 3. 2014 + * Author: tomas + */ + +#include "RedundantStateRemover.h" + +using namespace automaton; +using namespace std; + +namespace trim +{ + +FSM RedundantStateRemover::remove( const FSM & fsm ) +{ + deque<set<State>> Qi; + Qi.push_back( set<State>( ) ); + + int i = 1; + for( const auto & f : fsm.getFinalStates( ) ) + Qi.at( 0 ).insert( f ); + + while( true ) + { + Qi.push_back( Qi.at( i - 1 ) ); // copy Qi-1 into Qi + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & t : fsm.getTransitionsToState( p ) ) + Qi.at( i ).insert( t.getFrom( ) ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i += 1; + } + + FSM ret; + + for( const auto & q : Qi.at( i ) ) + ret.addState( q ); + + for( const auto & t : fsm.getTransitions( ) ) + { + if( isInSet( t.getFrom( ), ret.getStates( ) ) && isInSet( t.getTo( ), ret.getStates( ) ) ) + { + if( ! isInSet( t.getInput( ), ret.getInputAlphabet( ) ) ) + ret.addInputSymbol( t.getInput( ) ); + + ret.addTransition( t ); + } + } + + for( const auto & q : fsm.getInitialStates( ) ) + ret.addInitialState( q ); + for( const auto & q : fsm.getFinalStates( ) ) + ret.addFinalState( q ); + + return ret; +} + +} /* namespace trim */ diff --git a/atrim/src/RedundantStateRemover.h b/atrim/src/RedundantStateRemover.h new file mode 100644 index 0000000000000000000000000000000000000000..3ba2e01149f38383327cecea404b3161f06bf1a1 --- /dev/null +++ b/atrim/src/RedundantStateRemover.h @@ -0,0 +1,32 @@ +/* + * RedundantStateRemover.h + * + * Created on: 4. 3. 2014 + * Author: tomas + */ + +#ifndef REDUNDANTSTATEREMOVER_H_ +#define REDUNDANTSTATEREMOVER_H_ + +#include <deque> +#include <set> + +#include <automaton/FSM/FSM.h> + +namespace trim +{ + +#define isInSet(x,set) ( (set).find((x)) != (set).end()) + +/** + * Melichar 2.32 + */ +class RedundantStateRemover +{ +public: + static automaton::FSM remove( const automaton::FSM & fsm ); +}; + +} /* namespace trim */ + +#endif /* REDUNDANTSTATEREMOVER_H_ */ diff --git a/atrim/src/TrimNFA.cpp b/atrim/src/TrimNFA.cpp index bc3c1b46c02c37907abfc1b2b2f6702849d9c72b..b6a184e8314f4b6677db9bae33dbf334981bc2bb 100644 --- a/atrim/src/TrimNFA.cpp +++ b/atrim/src/TrimNFA.cpp @@ -1,71 +1,23 @@ /* * TrimNFA.cpp * - * Created on: 18. 1. 2014 + * Created on: 4. 3. 2014 * Author: tomas */ #include "TrimNFA.h" -using namespace alib; using namespace automaton; -using namespace std; -using namespace trim; namespace trim { -TrimNFA::TrimNFA( const FSM & fsm ) : m_origFSM( fsm ) +FSM TrimNFA::remove( const FSM & fsm ) { - if( m_origFSM.getInitialStates( ).size( ) != 1 ) - throw AlibException( "NFA must have exactly one initial state." ); -} - -const FSM TrimNFA::remove( void ) -{ - set<State> reachableStates = findReachableStates( ); - - for( auto const & q : reachableStates ) - m_FSM.addState( q ); - - for( auto const & symbol : m_origFSM.getInputAlphabet( ) ) - m_FSM.addInputSymbol( symbol ); - - for( auto const & t : m_origFSM.getTransitions( ) ) - if( isInSet( t.getFrom( ), reachableStates ) ) - m_FSM.addTransition( t ); - - - for( auto const & state : m_origFSM.getInitialStates( ) ) - m_FSM.addInitialState( state ); - - - set<State> intersect; - const set<State> & F = m_origFSM.getFinalStates( ); - set_intersection( F.begin(), F.end(), reachableStates.begin(), reachableStates.end(), inserter( intersect, intersect.begin() ) ); - - for( auto const & state : intersect ) - m_FSM.addFinalState( state ); - - return m_FSM; -} - -const set<State> TrimNFA::findReachableStates( void ) const -{ - set<State> qprev, qcurr; - qcurr.insert( * m_origFSM.getInitialStates().begin() ); - - do - { - qprev = qcurr; - - for( auto const & p : qprev ) - for( auto const & transition : m_origFSM.getTransitionsFromState( p ) ) - qcurr.insert( transition.getTo() ); - } - while( qcurr != qprev ); - - return qcurr; + FSM ret; + ret = UnreachableStateRemover::remove( fsm ); + ret = RedundantStateRemover::remove( ret ); + return ret; } } /* namespace trim */ diff --git a/atrim/src/TrimNFA.h b/atrim/src/TrimNFA.h index 11523caa526fda88a9e42c5062d43195eb6393a9..55f21f9e9ee47aa850e50f4f9ec7741ad14f183a 100644 --- a/atrim/src/TrimNFA.h +++ b/atrim/src/TrimNFA.h @@ -1,7 +1,7 @@ /* * TrimNFA.h * - * Created on: 18. 1. 2014 + * Created on: 4. 3. 2014 * Author: tomas */ @@ -9,32 +9,17 @@ #define TRIMNFA_H_ #include <automaton/FSM/FSM.h> -#include <AlibException.h> -#include <algorithm> -#include <iterator> -#include <map> -#include <set> +#include "RedundantStateRemover.h" +#include "UnreachableStateRemover.h" namespace trim { -#define isInSet(x,set) ( (set).find((x)) != (set).end()) - -/** - * Well, this is just simple BFS/DFS, but we implement Melichar, 2.29 algorithm. - */ class TrimNFA { public: - TrimNFA( const automaton::FSM & fsm ); - const automaton::FSM remove( void ); - -private: - const std::set<automaton::State> findReachableStates( void ) const; - - const automaton::FSM & m_origFSM; - automaton::FSM m_FSM; + static automaton::FSM remove( const automaton::FSM & fsm ); }; } /* namespace trim */ diff --git a/atrim/src/UnreachableStateRemover.cpp b/atrim/src/UnreachableStateRemover.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3caf41fd80954c6dc7604d168e225b648013814a --- /dev/null +++ b/atrim/src/UnreachableStateRemover.cpp @@ -0,0 +1,73 @@ +/* + * UnreachableStateRemover.cpp + * + * Created on: 18. 1. 2014 + * Author: tomas + */ + +#include "UnreachableStateRemover.h" + +using namespace alib; +using namespace automaton; +using namespace std; +using namespace trim; + +namespace trim +{ + +FSM UnreachableStateRemover::remove( const FSM & fsm ) +{ + if( fsm.getInitialStates( ).size( ) != 1 ) + throw AlibException( "NFA must have exactly one initial state." ); + + set<State> reachableStates = findReachableStates( fsm ); + + FSM ret; + + for( auto const & q : reachableStates ) + ret.addState( q ); + + for( auto const & t : fsm.getTransitions( ) ) + { + if( isInSet( t.getFrom( ), reachableStates ) ) + { + if( ! isInSet( t.getInput( ), ret.getInputAlphabet( ) ) ) + ret.addInputSymbol( t.getInput( ) ); + ret.addTransition( t ); + } + } + + + for( auto const & state : fsm.getInitialStates( ) ) + ret.addInitialState( state ); + + + set<State> intersect; + const set<State> & F = fsm.getFinalStates( ); + set_intersection( F.begin(), F.end(), reachableStates.begin(), reachableStates.end(), inserter( intersect, intersect.begin() ) ); + + for( auto const & state : intersect ) + ret.addFinalState( state ); + + return ret; +} + +set<State> UnreachableStateRemover::findReachableStates( const FSM & fsm ) +{ + set<State> qprev, qcurr; + qcurr.insert( * fsm.getInitialStates().begin() ); + + do + { + qprev = qcurr; + + for( auto const & p : qprev ) + for( auto const & transition : fsm.getTransitionsFromState( p ) ) + qcurr.insert( transition.getTo() ); + } + while( qcurr != qprev ); + + return qcurr; +} + +} /* namespace trim */ diff --git a/atrim/src/UnreachableStateRemover.h b/atrim/src/UnreachableStateRemover.h new file mode 100644 index 0000000000000000000000000000000000000000..0345ebbc36371e273ae030c66ea9bed83ee89fdc --- /dev/null +++ b/atrim/src/UnreachableStateRemover.h @@ -0,0 +1,38 @@ +/* + * UnreachableStateRemover.h + * + * Created on: 18. 1. 2014 + * Author: tomas + */ + +#ifndef UNREACHABLE_H_ +#define UNREACHABLE_H_ + +#include <automaton/FSM/FSM.h> +#include <AlibException.h> + +#include <algorithm> +#include <iterator> +#include <map> +#include <set> + +namespace trim +{ + +#define isInSet(x,set) ( (set).find((x)) != (set).end()) + +/** + * Melichar 2.29 + */ +class UnreachableStateRemover +{ +public: + static automaton::FSM remove( const automaton::FSM & fsm ); + +private: + static std::set<automaton::State> findReachableStates( const automaton::FSM & fsm ); +}; + +} /* namespace trim */ + +#endif /* UNREACHABLE_H_ */ diff --git a/atrim/src/atrim.fsm.cpp b/atrim/src/atrim.fsm.cpp index b52484255daa8048954041e2bed53af5d8186e96..dd33c147fe257544c24c1a70f091d257a189fbac 100644 --- a/atrim/src/atrim.fsm.cpp +++ b/atrim/src/atrim.fsm.cpp @@ -55,8 +55,7 @@ int main(int argc, char** argv) { UnknownAutomaton automaton = AutomatonParser::parse( tokens ); FSM fsm = AutomatonFactory::buildFSM( automaton ); - TrimNFA tr ( fsm ); - tr.remove().toXML( cout ); + TrimNFA::remove( fsm ).toXML( cout ); } catch (AlibException& e) { cout << e.what() << endl;