From dc65d4b1f2166ead09341989c2e148e62278a95c Mon Sep 17 00:00:00 2001
From: Jan Travnicek <jan.travnicek@.fit.cvut.cz>
Date: Wed, 27 Mar 2019 15:22:53 +0100
Subject: [PATCH] redesign trim FTA

---
 .../automaton/properties/ReachableStates.cpp  |  14 +++
 .../automaton/properties/ReachableStates.h    |  80 ++++++++++++
 .../src/automaton/properties/UsefulStates.cpp |  14 +++
 .../src/automaton/properties/UsefulStates.h   |  80 ++++++++++++
 alib2algo/src/automaton/simplify/Trim.cpp     |  12 +-
 alib2algo/src/automaton/simplify/Trim.h       |   2 +-
 .../simplify/UnreachableStatesRemover.cpp     |  10 +-
 .../simplify/UnreachableStatesRemover.h       | 117 ++++++++++--------
 .../simplify/UselessStatesRemover.cpp         |  10 +-
 .../automaton/simplify/UselessStatesRemover.h |  84 +++++++++----
 alib2data/src/automaton/TA/DFTA.h             |  28 +++++
 alib2data/src/automaton/TA/NFTA.h             |  27 ++++
 12 files changed, 392 insertions(+), 86 deletions(-)

diff --git a/alib2algo/src/automaton/properties/ReachableStates.cpp b/alib2algo/src/automaton/properties/ReachableStates.cpp
index f04c3130c9..c2c59cd948 100644
--- a/alib2algo/src/automaton/properties/ReachableStates.cpp
+++ b/alib2algo/src/automaton/properties/ReachableStates.cpp
@@ -54,6 +54,20 @@ Using closure implementation of the BFS algorithm.\n\
 @param fsm automaton\n\
 @return set of reachable states from the initial state of @p fsm" );
 
+auto ReachableStatesDFTA = registration::AbstractRegister < ReachableStates, ext::set < DefaultStateType >, const automaton::DFTA < > & > ( ReachableStates::reachableStates, "fta" ).setDocumentation (
+"Finds all reachable states of a finite tree automaton.\n\
+Using closure implementation of the BFS algorithm.\n\
+\n\
+@param fta automaton\n\
+@return set of reachable states from states that read leaves of @p fta" );
+
+auto ReachableStatesNFTA = registration::AbstractRegister < ReachableStates, ext::set < DefaultStateType >, const automaton::NFTA < > & > ( ReachableStates::reachableStates, "fta" ).setDocumentation (
+"Finds all reachable states of a finite tree automaton.\n\
+Using closure implementation of the BFS algorithm.\n\
+\n\
+@param fta automaton\n\
+@return set of reachable states from states that read leaves of @p fta" );
+
 } /* namespace properties */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/properties/ReachableStates.h b/alib2algo/src/automaton/properties/ReachableStates.h
index 215cbb3d6c..4c95a48761 100644
--- a/alib2algo/src/automaton/properties/ReachableStates.h
+++ b/alib2algo/src/automaton/properties/ReachableStates.h
@@ -34,6 +34,8 @@
 #include <automaton/FSM/EpsilonNFA.h>
 #include <automaton/FSM/NFA.h>
 #include <automaton/FSM/DFA.h>
+#include <automaton/TA/DFTA.h>
+#include <automaton/TA/NFTA.h>
 
 #include <automaton/Automaton.h>
 
@@ -85,6 +87,34 @@ public:
 	 */
 	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.
+	 * 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
+	 * @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.
+	 * 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
+	 * @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::NFTA < SymbolType, RankType, StateType > & fta );
 };
 
 template < class T >
@@ -167,6 +197,56 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::DFA < Sym
 	return Qi.at( i );
 }
 
+template < class SymbolType, class RankType, class StateType >
+ext::set<StateType> ReachableStates::reachableStates( const automaton::DFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::deque<ext::set<StateType>> Qi;
+	Qi.push_back( ext::set<StateType>( ) );
+
+	int i = 1;
+
+	// 1bc
+	while( true ) {
+		Qi.push_back( Qi.at( i - 1 ) );
+
+		for( const auto & transition : fta.getTransitions ( ) )
+			if ( std::all_of ( transition.first.second.begin ( ), transition.first.second.end ( ), [ & ] ( const StateType & state ) { return Qi.at ( i - 1 ).count ( state ); } ) )
+				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 RankType, class StateType >
+ext::set<StateType> ReachableStates::reachableStates( const automaton::NFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::deque<ext::set<StateType>> Qi;
+	Qi.push_back( ext::set<StateType>( ) );
+
+	int i = 1;
+
+	// 1bc
+	while( true ) {
+		Qi.push_back( Qi.at( i - 1 ) );
+
+		for( const auto & transition : fta.getTransitions ( ) )
+			if ( std::all_of ( transition.first.second.begin ( ), transition.first.second.end ( ), [ & ] ( const StateType & state ) { return Qi.at ( i - 1 ).count ( state ); } ) )
+				Qi.at( i ).insert ( transition.second.begin ( ), transition.second.end ( ) );
+
+		if( Qi.at( i ) == Qi.at( i - 1 ) )
+			break;
+
+		i = i + 1;
+	}
+
+	return Qi.at( i );
+}
+
 } /* namespace properties */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/properties/UsefulStates.cpp b/alib2algo/src/automaton/properties/UsefulStates.cpp
index c99e381d10..33a719d374 100644
--- a/alib2algo/src/automaton/properties/UsefulStates.cpp
+++ b/alib2algo/src/automaton/properties/UsefulStates.cpp
@@ -54,6 +54,20 @@ Using closure implementation of the BFS algorithm.\n\
 @param fsm automaton\n\
 @return set of useful states of @p fsm" );
 
+auto UsefulStatesDFTA = registration::AbstractRegister < UsefulStates, ext::set < DefaultStateType >, const automaton::DFTA < > & > ( UsefulStates::usefulStates, "fta" ).setDocumentation (
+"Finds all useful states of a finite tree automaton.\n\
+Using closure implementation of the BFS algorithm.\n\
+\n\
+@param fta automaton\n\
+@return set of useful states of @p fta" );
+
+auto UsefulStatesNFTA = registration::AbstractRegister < UsefulStates, ext::set < DefaultStateType >, const automaton::NFTA < > & > ( UsefulStates::usefulStates, "fta" ).setDocumentation (
+"Finds all useful states of a finite tree automaton.\n\
+Using closure implementation of the BFS algorithm.\n\
+\n\
+@param fta automaton\n\
+@return set of useful states of @p fta" );
+
 } /* namespace properties */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/properties/UsefulStates.h b/alib2algo/src/automaton/properties/UsefulStates.h
index a036d7a215..e5632916ee 100644
--- a/alib2algo/src/automaton/properties/UsefulStates.h
+++ b/alib2algo/src/automaton/properties/UsefulStates.h
@@ -34,6 +34,8 @@
 #include <automaton/FSM/EpsilonNFA.h>
 #include <automaton/FSM/NFA.h>
 #include <automaton/FSM/DFA.h>
+#include <automaton/TA/DFTA.h>
+#include <automaton/TA/NFTA.h>
 
 #include <automaton/Automaton.h>
 
@@ -71,6 +73,36 @@ public:
 	 */
 	template < class SymbolType, class StateType >
 	static ext::set<StateType> usefulStates( const automaton::DFA < SymbolType, StateType > & fsm );
+
+	/**
+	 * Finds all useful states of a deterministic finite tree automaton.
+	 * Using closure implementation of the BFS algorithm.
+	 *
+	 * @overload
+	 *
+	 * @tparam SymbolType Type for the input symbols.
+	 * @tparam RankType Type of ranks in the automaton.
+	 * @tparam StateType Type for the states.
+	 * @param fta automaton
+	 * @return set of useful states of @p fta
+	 */
+	template < class SymbolType, class RankType, class StateType >
+	static ext::set<StateType> usefulStates( const automaton::DFTA < SymbolType, RankType, StateType > & fta );
+
+	/**
+	 * Finds all useful states of a deterministic finite tree automaton.
+	 * Using closure implementation of the BFS algorithm.
+	 *
+	 * @overload
+	 *
+	 * @tparam SymbolType Type for the input symbols.
+	 * @tparam RankType Type of ranks in the automaton.
+	 * @tparam StateType Type for the states.
+	 * @param fta automaton
+	 * @return set of useful states of @p fta
+	 */
+	template < class SymbolType, class RankType, class StateType >
+	static ext::set<StateType> usefulStates( const automaton::NFTA < SymbolType, RankType, StateType > & fta );
 };
 
 template < class T >
@@ -123,6 +155,54 @@ ext::set<StateType> UsefulStates::usefulStates( const automaton::DFA < SymbolTyp
 	return Qi.at( i );
 }
 
+template < class SymbolType, class RankType, class StateType >
+ext::set<StateType> UsefulStates::usefulStates( const automaton::DFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::deque<ext::set<StateType>> Qi;
+	Qi.push_back( ext::set<StateType>( ) );
+	Qi.at( 0 ) = fta.getFinalStates( );
+
+	int i = 1;
+
+	// 1bc
+	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 : fta.getTransitionsToState ( p ) )
+				Qi.at( i ).insert( t.first.second.begin ( ), t.first.second.end ( ) );
+
+		if( Qi.at( i ) == Qi.at( i - 1 ) )
+			break;
+
+		i = i + 1;
+	}
+	return Qi.at( i );
+}
+
+template < class SymbolType, class RankType, class StateType >
+ext::set<StateType> UsefulStates::usefulStates( const automaton::NFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::deque<ext::set<StateType>> Qi;
+	Qi.push_back( ext::set<StateType>( ) );
+	Qi.at( 0 ) = fta.getFinalStates( );
+
+	int i = 1;
+
+	// 1bc
+	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 : fta.getTransitionsToState ( p ) )
+				Qi.at( i ).insert( t.first.second.begin ( ), t.first.second.end ( ) );
+
+		if( Qi.at( i ) == Qi.at( i - 1 ) )
+			break;
+
+		i = i + 1;
+	}
+	return Qi.at( i );
+}
+
 } /* namespace properties */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/simplify/Trim.cpp b/alib2algo/src/automaton/simplify/Trim.cpp
index a8596b6216..86cca5753d 100644
--- a/alib2algo/src/automaton/simplify/Trim.cpp
+++ b/alib2algo/src/automaton/simplify/Trim.cpp
@@ -55,11 +55,17 @@ auto TrimExtendedNFA = registration::AbstractRegister < Trim, automaton::Extende
 @param fsm finite automaton or finite tree automaton to trim\n\
 @return the trimmed automaton equivalent to @p fsm" );
 
-auto TrimDFTA = registration::AbstractRegister < Trim, automaton::DFTA < >, const automaton::DFTA < > & > ( Trim::trim, "fsm" ).setDocumentation (
+auto TrimDFTA = registration::AbstractRegister < Trim, automaton::DFTA < >, const automaton::DFTA < > & > ( Trim::trim, "fta" ).setDocumentation (
 "Removes inaccessible and useless states from the given automaton. Uses first the @sa UselessStatesRemover and next @sa UnreachableStatesRemover in the process.\n\
 \n\
-@param fsm finite automaton or finite tree automaton to trim\n\
-@return the trimmed automaton equivalent to @p fsm" );
+@param fta finite tree automaton or finite tree automaton to trim\n\
+@return the trimmed automaton equivalent to @p fta" );
+
+auto TrimNFTA = registration::AbstractRegister < Trim, automaton::NFTA < >, const automaton::NFTA < > & > ( Trim::trim, "fta" ).setDocumentation (
+"Removes inaccessible and useless states from the given automaton. Uses first the @sa UselessStatesRemover and next @sa UnreachableStatesRemover in the process.\n\
+\n\
+@param fta finite automaton or finite tree automaton to trim\n\
+@return the trimmed automaton equivalent to @p fta" );
 
 } /* namespace simplify */
 
diff --git a/alib2algo/src/automaton/simplify/Trim.h b/alib2algo/src/automaton/simplify/Trim.h
index ecbb647f72..670c0c73cb 100644
--- a/alib2algo/src/automaton/simplify/Trim.h
+++ b/alib2algo/src/automaton/simplify/Trim.h
@@ -55,7 +55,7 @@ public:
 
 template < class T >
 T Trim::trim ( const T & fsm ) {
-	return UnreachableStatesRemover::remove ( UselessStatesRemover::remove ( fsm ) );
+	return UselessStatesRemover::remove ( UnreachableStatesRemover::remove ( fsm ) );
 }
 
 } /* namespace simplify */
diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp
index bd22bba1b9..ccf9d5676b 100644
--- a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp
+++ b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp
@@ -48,10 +48,16 @@ auto UnreachableStatesRemoverMultiInitialStateNFA = registration::AbstractRegist
 @param automaton automaton to trim\n\
 @return @p automaton without unreachable states" );
 
-auto UnreachableStatesRemoverDFTA = registration::AbstractRegister < UnreachableStatesRemover, automaton::DFTA < >, const automaton::DFTA < > & > ( UnreachableStatesRemover::remove, "dfta" ).setDocumentation (
+auto UnreachableStatesRemoverDFTA = registration::AbstractRegister < UnreachableStatesRemover, automaton::DFTA < >, const automaton::DFTA < > & > ( UnreachableStatesRemover::remove, "fta" ).setDocumentation (
 "Removes unreachable states from a deterministic finite tree automaton.\n\
 \n\
-@param dfta automaton to trim\n\
+@param fta automaton to trim\n\
+@return @p autoamton without unreachable states" );
+
+auto UnreachableStatesRemoverNFTA = registration::AbstractRegister < UnreachableStatesRemover, automaton::NFTA < >, const automaton::NFTA < > & > ( UnreachableStatesRemover::remove, "fta" ).setDocumentation (
+"Removes unreachable states from a deterministic finite tree automaton.\n\
+\n\
+@param fta automaton to trim\n\
 @return @p autoamton without unreachable states" );
 
 } /* namespace simplify */
diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
index 3bbaaf48a9..f7451af96e 100644
--- a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
+++ b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
@@ -94,6 +94,22 @@ public:
 	 */
 	template < class SymbolType, class RankType, class StateType >
 	static automaton::DFTA < SymbolType, RankType, StateType > remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta );
+
+	/**
+	 * Removes unreachable states from a deterministic finite tree automaton.
+	 *
+	 * @overload
+	 *
+	 * @tparam SymbolType Type for input symbols.
+	 * @tparam RankType Type for rank (arity) in ranked alphabet.
+	 * @tparam StateType Type for states.
+	 *
+	 * @param dfta automaton to trim
+	 *
+	 * @return @p autoamton without unreachable states
+	 */
+	template < class SymbolType, class RankType, class StateType >
+	static automaton::NFTA < SymbolType, RankType, StateType > remove( const automaton::NFTA < SymbolType, RankType, StateType > & dfta );
 };
 
 template < class T >
@@ -181,58 +197,55 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > UnreachableStatesRemov
 }
 
 template < class SymbolType, class RankType, class StateType >
-automaton::DFTA < SymbolType, RankType, StateType > UnreachableStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta ) {
-	automaton::DFTA < SymbolType, RankType, StateType > res;
-	res.setInputAlphabet(dfta.getInputAlphabet());
-
-	typedef std::pair < const ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > Transition;
-	ext::vector<ext::pair<const Transition *, int>> transitionsUnreachableCount;
-	transitionsUnreachableCount.reserve(dfta.getTransitions().size());
-
-	//for a state, transitions with unreachable count (initially all unreachable) and number of occurences of this state (at least 1)
-	ext::map<StateType, ext::map<ext::pair<const Transition *, int> *, int>> stateOccurences;
-	ext::deque<StateType> queue;
-	for(const auto & transition : dfta.getTransitions()) {
-		if (transition.first.second.empty()) {
-			queue.push_back(transition.second);
-			res.addState(transition.second);
-			res.addTransition(transition.first.first, transition.first.second, transition.second);
-		} else {
-			transitionsUnreachableCount.push_back({&transition, transition.first.second.size()});
-			for (const auto & state : transition.first.second) {
-				auto & occurences = stateOccurences[state];
-				auto it = occurences.find(&transitionsUnreachableCount.back());
-				if (it == occurences.end()) occurences[&transitionsUnreachableCount.back()] = 1;
-				else it->second++;
-			}
-		}
-	}
-
-	while(!queue.empty()) {
-		const auto & occurences = stateOccurences[queue.front()];
-		queue.pop_front();
-		for (const auto & occurence : occurences) {
-			int & unreachableCount = occurence.first -> second;
-			const StateType & to = occurence.first -> first -> second;
-			unreachableCount -=  occurence.second;
-			if (unreachableCount == 0) {
-				if (res.addState(to)) {
-					queue.push_back(to);
-				}
-			}
-		}
-	}
-
-	for (const auto & state : res.getStates()) {
-		if (dfta.getFinalStates().count(state) != 0) res.addFinalState(state);
-	}
-	for (const auto & transitionUnreachableCount : transitionsUnreachableCount) {
-		if (transitionUnreachableCount.second == 0) {
-			const Transition transition = *(transitionUnreachableCount.first);
-			res.addTransition(transition.first.first, transition.first.second, transition.second);
-		}
-	}
-	return res;
+automaton::DFTA < SymbolType, RankType, StateType > UnreachableStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::set<StateType> Qa = automaton::properties::ReachableStates::reachableStates( fta );
+
+	// 2
+	automaton::DFTA < SymbolType, RankType, StateType > M;
+
+	for( const auto & q : Qa )
+		M.addState( q );
+
+	for( const auto & a : fta.getInputAlphabet( ) )
+		M.addInputSymbol( a );
+
+	for( const auto & transition : fta.getTransitions( ) )
+		if( std::all_of ( transition.first.second.begin ( ), transition.first.second.end ( ), [ & ] ( const StateType & state ) { return Qa.count ( state ); } ) )
+			M.addTransition ( transition.first.first, transition.first.second, transition.second );
+
+	ext::set<StateType> intersect;
+	std::set_intersection( fta.getFinalStates( ).begin(), fta.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 RankType, class StateType >
+automaton::NFTA < SymbolType, RankType, StateType > UnreachableStatesRemover::remove( const automaton::NFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1a
+	ext::set<StateType> Qa = automaton::properties::ReachableStates::reachableStates( fta );
+
+	// 2
+	automaton::NFTA < SymbolType, RankType, StateType > M;
+
+	for( const auto & q : Qa )
+		M.addState( q );
+
+	for( const auto & a : fta.getInputAlphabet( ) )
+		M.addInputSymbol( a );
+
+	for( const auto & transition : fta.getTransitions( ) )
+		if( std::all_of ( transition.first.second.begin ( ), transition.first.second.end ( ), [ & ] ( const StateType & state ) { return Qa.count ( state ); } ) )
+			M.addTransitions ( transition.first.first, transition.first.second, transition.second );
+
+	ext::set<StateType> intersect;
+	std::set_intersection( fta.getFinalStates( ).begin(), fta.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) );
+	for( auto const & state : intersect )
+		M.addFinalState( state );
+
+	return M;
 }
 
 } /* namespace simplify */
diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp b/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp
index 0780d0b945..c1768aa3ac 100644
--- a/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp
+++ b/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp
@@ -48,10 +48,16 @@ auto UselessStatesRemoverMultiInitialStateNFA = registration::AbstractRegister <
 @param automaton automaton to trim\n\
 @return @p automaton without useless states" );
 
-auto UselessStatesRemoverDFTA = registration::AbstractRegister < UselessStatesRemover, automaton::DFTA < >, const automaton::DFTA < > & > ( UselessStatesRemover::remove, "dfta" ).setDocumentation (
+auto UselessStatesRemoverDFTA = registration::AbstractRegister < UselessStatesRemover, automaton::DFTA < >, const automaton::DFTA < > & > ( UselessStatesRemover::remove, "fta" ).setDocumentation (
 "Removes unreachable states from a deterministic finite tree automaton.\n\
 \n\
-@param dfta automaton to trim\n\
+@param fta automaton to trim\n\
+@return @p autoamton without unreachable states" );
+
+auto UselessStatesRemoverNFTA = registration::AbstractRegister < UselessStatesRemover, automaton::NFTA < >, const automaton::NFTA < > & > ( UselessStatesRemover::remove, "fta" ).setDocumentation (
+"Removes unreachable states from a deterministic finite tree automaton.\n\
+\n\
+@param fta automaton to trim\n\
 @return @p autoamton without unreachable states" );
 
 } /* namespace simplify */
diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.h b/alib2algo/src/automaton/simplify/UselessStatesRemover.h
index d4b386b400..1e1f18c9ce 100644
--- a/alib2algo/src/automaton/simplify/UselessStatesRemover.h
+++ b/alib2algo/src/automaton/simplify/UselessStatesRemover.h
@@ -87,6 +87,19 @@ public:
 	 */
 	template < class SymbolType, class RankType, class StateType >
 	static automaton::DFTA < SymbolType, RankType, StateType > remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta );
+
+	/**
+	 * Removes unreachable states from a deterministic finite tree automaton.
+	 *
+	 * @overload
+	 * @tparam SymbolType Type for input symbols.
+	 * @tparam RankType Type for rank (arity) in ranked alphabet.
+	 * @tparam StateType Type for states.
+	 * @param dfta automaton to trim
+	 * @return @p autoamton without unreachable states
+	 */
+	template < class SymbolType, class RankType, class StateType >
+	static automaton::NFTA < SymbolType, RankType, StateType > remove( const automaton::NFTA < SymbolType, RankType, StateType > & dfta );
 };
 
 template < class T >
@@ -183,41 +196,60 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > UselessStatesRemover::
 }
 
 template < class SymbolType, class RankType, class StateType >
-automaton::DFTA < SymbolType, RankType, StateType > UselessStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta ) {
-	automaton::DFTA < SymbolType, RankType, StateType > res;
-	res.setInputAlphabet(dfta.getInputAlphabet());
-	res.setStates(dfta.getFinalStates());
-	res.setFinalStates(dfta.getFinalStates());
+automaton::DFTA < SymbolType, RankType, StateType > UselessStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1.
+	ext::set<StateType> Qu = automaton::properties::UsefulStates::usefulStates( fta );
 
-	typedef std::pair < const ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > Transition;
+	// 2.
+	automaton::DFTA < SymbolType, RankType, StateType > M;
 
-	ext::map<StateType, ext::set<const Transition *>> transitionsToState;
-	for(const auto & transition : dfta.getTransitions()) {
-		transitionsToState[transition.second].insert(&transition);
-	}
+	for( const auto & a : fta.getInputAlphabet( ) )
+		M.addInputSymbol( a );
 
-	ext::deque<StateType> queue;
-	for (const auto & state : dfta.getFinalStates()) {
-		queue.push_back(state);
+	if(Qu.size() == 0) {
+		return M;
 	}
 
-	while(!queue.empty()) {
-		ext::set<const Transition *> & transitions = transitionsToState[queue.front()];
-		queue.pop_front();
-		for (const Transition * transitionPt : transitions) {
-			const Transition &transition = *transitionPt;
+	for( const auto & q : Qu )
+		M.addState( q );
 
-			for (const auto & state : transition.first.second) {
-				if (res.addState(state)) {
-					queue.push_back(state);
-				}
-			}
+	for( const auto & t : fta.getTransitions( ) )
+		if( Qu.count( t.second ) )
+			M.addTransition( t.first.first, t.first.second, t.second );
 
-			res.addTransition(transition.first.first, transition.first.second, transition.second);
-		}
+	for( const auto & q : fta.getFinalStates( ) )
+		M.addFinalState( q );
+
+	return M;
+}
+
+template < class SymbolType, class RankType, class StateType >
+automaton::NFTA < SymbolType, RankType, StateType > UselessStatesRemover::remove( const automaton::NFTA < SymbolType, RankType, StateType > & fta ) {
+	// 1.
+	ext::set<StateType> Qu = automaton::properties::UsefulStates::usefulStates( fta );
+
+	// 2.
+	automaton::NFTA < SymbolType, RankType, StateType > M;
+
+	for( const auto & a : fta.getInputAlphabet( ) )
+		M.addInputSymbol( a );
+
+	if(Qu.size() == 0) {
+		return M;
 	}
 
-	return res;
+	for( const auto & q : Qu )
+		M.addState( q );
+
+	for( const auto & t : fta.getTransitions( ) )
+		for ( const StateType & to : t.second )
+			if( Qu.count( to ) )
+				M.addTransition( t.first.first, t.first.second, to );
+
+	for( const auto & q : fta.getFinalStates( ) )
+		M.addFinalState( q );
+
+	return M;
 }
 
 } /* namespace simplify */
diff --git a/alib2data/src/automaton/TA/DFTA.h b/alib2data/src/automaton/TA/DFTA.h
index c715f84093..8ee42d8e39 100644
--- a/alib2data/src/automaton/TA/DFTA.h
+++ b/alib2data/src/automaton/TA/DFTA.h
@@ -298,6 +298,34 @@ public:
 		return std::move ( transitions );
 	}
 
+	/**
+	 * \returns transitions to state @p q
+	 */
+	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > getTransitionsToState ( const StateType & q ) const {
+		ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > res;
+
+		for ( const auto & transition : getTransitions ( ) ) {
+			if ( transition.second == q )
+				res.insert ( std::make_pair ( transition.first, q ) );
+		}
+
+		return res;
+	}
+
+	/**
+	 * \returns transitions from state @p q
+	 */
+	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > getTransitionsFromState ( const StateType & q ) const {
+		ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > res;
+
+		for ( const auto & transition : getTransitions ( ) ) {
+			if ( std::find ( transition.first.second.begin ( ), transition.first.second.end ( ), q ) != transition.first.second.end ( ) )
+				res.insert ( transition );
+		}
+
+		return res;
+	}
+
 	/**
 	 * \brief Computes number of transitions in the automaton
 	 *
diff --git a/alib2data/src/automaton/TA/NFTA.h b/alib2data/src/automaton/TA/NFTA.h
index 8855b1ae37..8803547885 100644
--- a/alib2data/src/automaton/TA/NFTA.h
+++ b/alib2data/src/automaton/TA/NFTA.h
@@ -318,6 +318,33 @@ public:
 		return std::move ( transitions );
 	}
 
+	/**
+	 * \returns transitions to state @p q
+	 */
+	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > getTransitionsToState ( const StateType & q ) const {
+		ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > res;
+
+		for ( const auto & transition : getTransitions ( ) )
+			if ( std::find ( transition.second.begin ( ), transition.second.end ( ), q ) != transition.second.end ( ) )
+				res [ transition.first ].insert ( q );
+
+		return res;
+	}
+
+	/**
+	 * \returns transitions from state @p q
+	 */
+	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > getTransitionsFromState ( const StateType & q ) const {
+		ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > res;
+
+		for ( const auto & transition : getTransitions ( ) ) {
+			if ( std::find ( transition.first.second.begin ( ), transition.first.second.end ( ), q ) != transition.first.second.end ( ) )
+				res.insert ( transition );
+		}
+
+		return res;
+	}
+
 	/**
 	 * \brief Determines whether the automaton is deterministic.
 	 *
-- 
GitLab