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;