From e577a242cb1da3f20bacf6b06bdc674d066d607d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <peckato1@fit.cvut.cz> Date: Tue, 4 Mar 2014 22:24:26 +0100 Subject: [PATCH] aTrim now also removes redundant states --- atrim/src/RedundantStateRemover.cpp | 62 +++++++++++++++++++++++ atrim/src/RedundantStateRemover.h | 32 ++++++++++++ atrim/src/TrimNFA.cpp | 60 +++------------------- atrim/src/TrimNFA.h | 23 ++------- atrim/src/UnreachableStateRemover.cpp | 73 +++++++++++++++++++++++++++ atrim/src/UnreachableStateRemover.h | 38 ++++++++++++++ atrim/src/atrim.fsm.cpp | 3 +- 7 files changed, 216 insertions(+), 75 deletions(-) create mode 100644 atrim/src/RedundantStateRemover.cpp create mode 100644 atrim/src/RedundantStateRemover.h create mode 100644 atrim/src/UnreachableStateRemover.cpp create mode 100644 atrim/src/UnreachableStateRemover.h diff --git a/atrim/src/RedundantStateRemover.cpp b/atrim/src/RedundantStateRemover.cpp new file mode 100644 index 0000000000..409aee5cf7 --- /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 0000000000..3ba2e01149 --- /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 bc3c1b46c0..b6a184e831 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 11523caa52..55f21f9e9e 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 0000000000..3caf41fd80 --- /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 0000000000..0345ebbc36 --- /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 b52484255d..dd33c147fe 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; -- GitLab