From 2ceabadbfde8324092790aaeef681e7987890ea5 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 9 Apr 2019 14:57:35 +0200
Subject: [PATCH] use multimap in NFTA

---
 .../convert/ToPostfixPushdownAutomaton.h      |   8 +-
 .../determinize/DeterminizeNFTAPart.hxx       |   6 +-
 .../automaton/properties/ReachableStates.h    |   2 +-
 .../src/automaton/properties/UsefulStates.h   |   4 +-
 alib2algo/src/automaton/run/Run.h             |   2 +-
 alib2algo/src/automaton/simplify/Rename.h     |   3 +-
 .../simplify/UnreachableStatesRemover.h       |   2 +-
 .../automaton/simplify/UselessStatesRemover.h |   5 +-
 alib2aux/src/convert/DotConverter.h           |  30 +++--
 alib2aux/src/convert/TikZConverter.h          |  32 +++--
 alib2data/src/automaton/TA/DFTA.h             |   7 --
 alib2data/src/automaton/TA/NFTA.h             | 118 ++++++------------
 alib2data/src/automaton/xml/TA/NFTA.h         |  12 +-
 13 files changed, 88 insertions(+), 143 deletions(-)

diff --git a/alib2algo/src/automaton/convert/ToPostfixPushdownAutomaton.h b/alib2algo/src/automaton/convert/ToPostfixPushdownAutomaton.h
index 9a01c617f2..1d68b23036 100644
--- a/alib2algo/src/automaton/convert/ToPostfixPushdownAutomaton.h
+++ b/alib2algo/src/automaton/convert/ToPostfixPushdownAutomaton.h
@@ -104,11 +104,9 @@ automaton::NPDA < ext::variant < common::ranked_symbol < SymbolType, RankType >,
 	}
 
 	for ( const auto & transition : nfta.getTransitions ( ) ) {
-		for ( const StateType & toState : transition.second ) {
-			ext::vector < ext::variant < StateType, alphabet::BottomOfTheStackSymbol > > pop ( transition.first.second.rbegin ( ), transition.first.second.rend ( ) );
-			ext::vector < ext::variant < StateType, alphabet::BottomOfTheStackSymbol > > push ( 1, toState );
-			automaton.addTransition (automaton.getInitialState ( ), transition.first.first, pop, automaton.getInitialState ( ), push );
-		}
+		ext::vector < ext::variant < StateType, alphabet::BottomOfTheStackSymbol > > pop ( transition.first.second.rbegin ( ), transition.first.second.rend ( ) );
+		ext::vector < ext::variant < StateType, alphabet::BottomOfTheStackSymbol > > push ( 1, transition.second );
+		automaton.addTransition (automaton.getInitialState ( ), transition.first.first, pop, automaton.getInitialState ( ), push );
 	}
 
 	char finalPDAState = 'r';
diff --git a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx
index ca666b5829..b98ef7c875 100644
--- a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx
+++ b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx
@@ -14,9 +14,9 @@ namespace automaton {
 namespace determinize {
 
 template < class SymbolType, class RankType, class StateType >
-void constructTransitions ( const std::pair < const ext::pair < common::ranked_symbol < SymbolType, RankType > , ext::vector < StateType > >, ext::set < StateType > > & transition, unsigned i, const ext::multimap < StateType, ext::set < StateType > > & nftaStateToDftaStates, ext::vector < ext::set < StateType > > & transitionLHS, ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < ext::set < StateType > > >, ext::set < StateType > > & resultTransition ) {
+void constructTransitions ( const std::pair < const ext::pair < common::ranked_symbol < SymbolType, RankType > , ext::vector < StateType > >, StateType > & transition, unsigned i, const ext::multimap < StateType, ext::set < StateType > > & nftaStateToDftaStates, ext::vector < ext::set < StateType > > & transitionLHS, ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < ext::set < StateType > > >, ext::set < StateType > > & resultTransition ) {
 	if ( i == transition.first.second.size ( ) ) {
-		resultTransition [ ext::make_pair ( transition.first.first, transitionLHS ) ].insert ( transition.second.begin ( ), transition.second.end ( ) );
+		resultTransition [ ext::make_pair ( transition.first.first, transitionLHS ) ].insert ( transition.second );
 	} else {
 		const StateType & nftaState = transition.first.second [ i ];
 
@@ -43,7 +43,7 @@ automaton::DFTA < SymbolType, RankType, ext::set < StateType > > Determinize::de
 		ext::set < StateType > dftaState;
 		ext::vector < StateType > source { };
 		for ( const auto & transition : nfta.getTransitions ( ).equal_range ( ext::tie ( symbol, source ) ) )
-			dftaState.insert ( transition.second.begin ( ), transition.second.end ( ) );
+			dftaState.insert ( transition.second );
 
 		for ( const auto & state : dftaState )
 			nftaStateToDftaStates.insert ( state, dftaState );
diff --git a/alib2algo/src/automaton/properties/ReachableStates.h b/alib2algo/src/automaton/properties/ReachableStates.h
index d75ab8aef6..452a2f0942 100644
--- a/alib2algo/src/automaton/properties/ReachableStates.h
+++ b/alib2algo/src/automaton/properties/ReachableStates.h
@@ -194,7 +194,7 @@ ext::set<StateType> ReachableStates::reachableStates( const automaton::NFTA < Sy
 
 		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 ( ) );
+				Qi.at( i ).insert ( transition.second );
 
 		if( Qi.at( i ) == Qi.at( i - 1 ) )
 			break;
diff --git a/alib2algo/src/automaton/properties/UsefulStates.h b/alib2algo/src/automaton/properties/UsefulStates.h
index 3d37e96858..da3610dac3 100644
--- a/alib2algo/src/automaton/properties/UsefulStates.h
+++ b/alib2algo/src/automaton/properties/UsefulStates.h
@@ -56,7 +56,7 @@ public:
 	 * @return set of useful states of @p fsm
 	 */
 	template < class T >
-	static ext::set < typename T::StateType > usefulStates( const T & fsm );
+	static ext::require < isDFA < T > || isNFA < T > || isEpsilonNFA < T > || isMultiInitialStateNFA < T > || isMultiInitialStateEpsilonNFA < T > || isCompactNFA < T > || isExtendedNFA < T >, ext::set < typename T::StateType > > usefulStates( const T & fsm );
 
 	/**
 	 * Finds all useful states of a deterministic finite tree automaton.
@@ -90,7 +90,7 @@ public:
 };
 
 template < class T >
-ext::set < typename T::StateType > UsefulStates::usefulStates( const T & fsm ) {
+ext::require < isDFA < T > || isNFA < T > || isEpsilonNFA < T > || isMultiInitialStateNFA < T > || isMultiInitialStateEpsilonNFA < T > || isCompactNFA < T > || isExtendedNFA < T >, ext::set < typename T::StateType > > UsefulStates::usefulStates( const T & fsm ) {
 	using StateType = typename T::StateType;
 
 	// 1a
diff --git a/alib2algo/src/automaton/run/Run.h b/alib2algo/src/automaton/run/Run.h
index 86a44ff88c..2303ffab6f 100644
--- a/alib2algo/src/automaton/run/Run.h
+++ b/alib2algo/src/automaton/run/Run.h
@@ -491,7 +491,7 @@ ext::pair < bool, ext::set < StateType > > Run::calculateStates ( const automato
 				break;
 
 		if ( j == rank )
-			states.insert ( transition.second.begin ( ), transition.second.end ( ) );
+			states.insert ( transition.second );
 	}
 
 	for ( const StateType & state : states )
diff --git a/alib2algo/src/automaton/simplify/Rename.h b/alib2algo/src/automaton/simplify/Rename.h
index 27c00907c4..f0f107a30f 100644
--- a/alib2algo/src/automaton/simplify/Rename.h
+++ b/alib2algo/src/automaton/simplify/Rename.h
@@ -289,8 +289,7 @@ NFTA < SymbolType, RankType, unsigned > Rename::rename ( const NFTA < SymbolType
 		for ( const StateType & source : transition.first.second )
 			sourceStates.push_back ( renamingData.at ( source ) );
 
-		for ( const StateType & target : transition.second )
-			result.addTransition ( transition.first.first, sourceStates, renamingData.at ( target ) );
+		result.addTransition ( transition.first.first, sourceStates, renamingData.at ( transition.second ) );
 	}
 
 	return result;
diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
index eee5c059d0..0fe329100b 100644
--- a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
+++ b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.h
@@ -202,7 +202,7 @@ automaton::NFTA < SymbolType, RankType, StateType > UnreachableStatesRemover::re
 
 	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 );
+			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( ) ) );
diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.h b/alib2algo/src/automaton/simplify/UselessStatesRemover.h
index 68a4fd8d93..6b9ce0fe4f 100644
--- a/alib2algo/src/automaton/simplify/UselessStatesRemover.h
+++ b/alib2algo/src/automaton/simplify/UselessStatesRemover.h
@@ -204,9 +204,8 @@ automaton::NFTA < SymbolType, RankType, StateType > UselessStatesRemover::remove
 		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 );
+		if( Qu.count( t.second ) )
+			M.addTransition( t.first.first, t.first.second, t.second );
 
 	for( const auto & q : fta.getFinalStates( ) )
 		M.addFinalState( q );
diff --git a/alib2aux/src/convert/DotConverter.h b/alib2aux/src/convert/DotConverter.h
index faaed8bde4..77252e2acb 100644
--- a/alib2aux/src/convert/DotConverter.h
+++ b/alib2aux/src/convert/DotConverter.h
@@ -988,25 +988,23 @@ void DotConverter::transitions(const automaton::NFTA < SymbolType, RankType, Sta
 		std::string symbol = replace ( factory::StringDataFactory::toString ( transition.first.first.getSymbol( )), "\"", "\\\"" );
 		symbol += ext::to_string(transition.first.first.getRank());
 
-		for(const StateType& to : transition.second) {
-			std::pair<int, ext::vector<int>> key(states.find(to)->second, {});
-			for(const StateType& state : transition.first.second) {
-				key.second.push_back(states.find(state)->second);
-			}
-			ext::map<std::pair<int, ext::vector<int>>, std::string>::iterator mapit = transitions.find(key);
+		std::pair<int, ext::vector<int>> key(states.find(transition.second)->second, {});
+		for(const StateType& state : transition.first.second) {
+			key.second.push_back(states.find(state)->second);
+		}
+		ext::map<std::pair<int, ext::vector<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/TikZConverter.h b/alib2aux/src/convert/TikZConverter.h
index 88e5214e45..dd3cdf0bc9 100644
--- a/alib2aux/src/convert/TikZConverter.h
+++ b/alib2aux/src/convert/TikZConverter.h
@@ -981,30 +981,28 @@ void TikZConverter::transitions ( const automaton::NFTA < SymbolType, RankType,
 		std::string symbol = replace ( factory::StringDataFactory::toString (  transition.first.first.getSymbol (  ) ), "\"", "\\\"" );
 		symbol += ext::to_string ( transition.first.first.getRank ( ) );
 
-		for ( const StateType & to : transition.second ) {
-			std::pair < int, ext::vector < int > > key ( states.find ( to )->second, { } );
+		std::pair < int, ext::vector < int > > key ( states.find ( transition.second )->second, { } );
 
-			for ( const StateType & state : transition.first.second )
-				key.second.push_back ( states.find ( state )->second );
+		for ( const StateType & state : transition.first.second )
+			key.second.push_back ( states.find ( state )->second );
 
-			ext::map < std::pair < int, ext::vector < int > >, std::string >::iterator mapit = transitions.find ( key );
+		ext::map < std::pair < int, ext::vector < 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/TA/DFTA.h b/alib2data/src/automaton/TA/DFTA.h
index 7fdbb9fe94..230d5dcdf4 100644
--- a/alib2data/src/automaton/TA/DFTA.h
+++ b/alib2data/src/automaton/TA/DFTA.h
@@ -332,13 +332,6 @@ public:
 		return res;
 	}
 
-	/**
-	 * \brief Computes number of transitions in the automaton
-	 *
-	 * \return number of transitions in the automaton
-	 */
-	unsigned transitionsSize ( ) const;
-
 	/**
 	 * The actual compare method
 	 *
diff --git a/alib2data/src/automaton/TA/NFTA.h b/alib2data/src/automaton/TA/NFTA.h
index 598d622d93..d40a3776c7 100644
--- a/alib2data/src/automaton/TA/NFTA.h
+++ b/alib2data/src/automaton/TA/NFTA.h
@@ -27,7 +27,7 @@
 #include <ostream>
 #include <sstream>
 
-#include <alib/map>
+#include <alib/multimap>
 #include <alib/set>
 #include <alib/vector>
 #include <alib/compare>
@@ -66,7 +66,7 @@ class FinalStates;
  * \delta = transition function of the form (A, B, C, ...) \times a -> P(Q), where A, B, C, ... \in Q, a \in T, and P(Q) is a powerset of states,
  * F (FinalStates) = set of final states
  *
- * Elements of the \delta mapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol.
+ * Elements of the \delta multimapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol.
  *
  * \tparam SymbolTypeT used for the symbol part of the ranked symbol
  * \tparam RankTypeT used for the rank part of the ranked symbol
@@ -81,9 +81,9 @@ public:
 
 private:
 	/**
-	 * Transition function as mapping from a list of states times an input symbol on the left hand side to a set of states.
+	 * Transition function as multimapping from a list of states times an input symbol on the left hand side to a set of states.
 	 */
-	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > transitions;
+	ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > transitions;
 
 public:
 	/**
@@ -278,21 +278,6 @@ public:
 	 */
 	bool addTransition ( common::ranked_symbol < SymbolType, RankType > current, ext::vector < StateType > children, StateType next );
 
-	/**
-	 * \brief Add a transition to the automaton.
-	 *
-	 * \details The transition is in a form ( A, B, C, ... ) \times a -> P(Q), where A, B, C, ... \in Q and a \in T, P(Q) is a powerset of states
-	 *
-	 * \param children the source states (A, B, C, ...)
-	 * \param current the input symbol (a)
-	 * \param next the target states (P(Q))
-	 *
-	 * \throws AutomatonException when transition contains state or symbol not present in the automaton components
-	 *
-	 * \returns true if the transition was indeed added
-	 */
-	void addTransitions ( common::ranked_symbol < SymbolType, RankType > current, ext::vector < StateType > children, ext::set < StateType > next );
-
 	/**
 	 * \brief Removes a transition from the automaton.
 	 *
@@ -311,7 +296,7 @@ public:
 	 *
 	 * \returns transition function of the automaton
 	 */
-	const ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > & getTransitions ( ) const & {
+	const ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > & getTransitions ( ) const & {
 		return transitions;
 	}
 
@@ -320,19 +305,19 @@ public:
 	 *
 	 * \returns transition function of the automaton
 	 */
-	ext::map < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > && getTransitions ( ) && {
+	ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > && getTransitions ( ) && {
 		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;
+	ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > getTransitionsToState ( const StateType & q ) const {
+		ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, 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 );
+			if ( transition.second == q )
+				res.insert ( transition );
 
 		return res;
 	}
@@ -340,8 +325,8 @@ public:
 	/**
 	 * \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;
+	ext::multimap < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > getTransitionsFromState ( const StateType & q ) const {
+		ext::multimap < 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 ( ) )
@@ -361,13 +346,6 @@ public:
 	 */
 	bool isDeterministic ( ) const;
 
-	/**
-	 * \brief Computes number of transitions in the automaton
-	 *
-	 * \return number of transitions in the automaton
-	 */
-	unsigned transitionsSize ( ) const;
-
 	/**
 	 * The actual compare method
 	 *
@@ -412,9 +390,7 @@ NFTA < SymbolType, RankType, StateType >::NFTA() : NFTA ( ext::set < StateType >
 
 template < class SymbolType, class RankType, class StateType >
 NFTA < SymbolType, RankType, StateType >::NFTA(const DFTA < SymbolType, RankType, StateType > & other) : NFTA ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) {
-	for(const auto& transition : other.getTransitions()) {
-		transitions[transition.first].insert(transition.second);
-	}
+	transitions = other.getTransitions ( );
 }
 
 template < class SymbolType, class RankType, class StateType >
@@ -433,53 +409,39 @@ bool NFTA < SymbolType, RankType, StateType >::addTransition ( common::ranked_sy
 			throw AutomatonException("State \"" + ext::to_string ( it ) + "\" doesn't exist.");
 	}
 
-	ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > > key = ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) );
-	return transitions [ std::move ( key ) ].insert ( std::move ( next ) ).second;
-}
-
-template < class SymbolType, class RankType, class StateType >
-void NFTA < SymbolType, RankType, StateType >::addTransitions ( common::ranked_symbol < SymbolType, RankType > symbol, ext::vector<StateType> prevStates, ext::set < StateType > next) {
-	if (prevStates.size() != ( size_t ) symbol.getRank() )
-		throw AutomatonException("Number of states doesn't match rank of the symbol");
-
-	if (! getInputAlphabet().count(symbol))
-		throw AutomatonException("Input symbol \"" + ext::to_string ( symbol ) + "\" doesn't exist.");
-
-	if ( !std::includes ( getStates ( ).begin ( ), getStates ( ).end ( ), next.begin ( ), next.end ( ) ) )
-		throw AutomatonException ( "Some target states don't exist." );
-
-	for (const StateType& it : prevStates) {
-		if (! getStates().count(it))
-			throw AutomatonException("State \"" + ext::to_string ( it ) + "\" doesn't exist.");
-	}
+	auto upper_bound = transitions.upper_bound ( ext::tie ( symbol, prevStates ) );
+	auto lower_bound = transitions.lower_bound ( ext::tie ( symbol, prevStates ) );
+	auto iter = std::lower_bound ( lower_bound, upper_bound, next, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } );
+	if ( iter != upper_bound && next >= iter->second )
+		return false;
 
-	ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > > key = ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) );
-	transitions [ std::move ( key ) ].insert ( ext::make_mover ( next ).begin ( ), ext::make_mover ( next ).end ( ) );
+	ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > > key = ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) );
+	transitions.insert ( iter, std::make_pair ( std::move ( key ), std::move ( next ) ) );
+	return true;
 }
 
 template < class SymbolType, class RankType, class StateType >
 bool NFTA < SymbolType, RankType, StateType >::removeTransition(const common::ranked_symbol < SymbolType, RankType > symbol, const ext::vector<StateType> & states, const StateType & next) {
-	ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> > key = ext::make_pair(symbol, states);
-	return transitions[key].erase(next);
-}
-
-template < class SymbolType, class RankType, class StateType >
-bool NFTA < SymbolType, RankType, StateType >::isDeterministic() const {
-	for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> >, ext::set<StateType> >& t : transitions)
-		if (t . second.size() != 1 || t . second.size() != 0)
-			return false;
+	auto upper_bound = transitions.upper_bound ( ext::tie ( symbol, states ) );
+	auto lower_bound = transitions.lower_bound ( ext::tie ( symbol, states ) );
+	auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == next; } );
+	if ( iter == upper_bound )
+		return false;
 
+	transitions.erase ( iter );
 	return true;
 }
 
 template < class SymbolType, class RankType, class StateType >
-unsigned NFTA < SymbolType, RankType, StateType >::transitionsSize() const {
-	int res = 0;
+bool NFTA < SymbolType, RankType, StateType >::isDeterministic() const {
+	if ( transitions.empty ( ) )
+		return true;
 
-	for(const auto& transition : transitions )
-		res += transition.second.size();
+	for ( auto iter = transitions.begin ( ); std::next ( iter ) != transitions.end ( ); ++ iter )
+		if ( iter->first == std::next ( iter )->first )
+			return false;
 
-	return res;
+	return true;
 }
 
 template < class SymbolType, class RankType, class StateType >
@@ -521,7 +483,7 @@ public:
 	 * \returns true if the symbol is used, false othervise
 	 */
 	static bool used ( const automaton::NFTA < SymbolType, RankType, StateType > & automaton, const common::ranked_symbol < SymbolType, RankType > & symbol ) {
-		for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> >, ext::set<StateType>>& t : automaton.getTransitions())
+		for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> >, StateType > & t : automaton.getTransitions())
 			if (t.first.first == symbol)
 				return true;
 
@@ -572,8 +534,8 @@ public:
 		if ( automaton.getFinalStates ( ).count ( state ) )
 			return true;
 
-		for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> >, ext::set<StateType>>& t : automaton.getTransitions())
-			if(ext::contains(t.first.second.begin(), t.first.second.end(), state ) || t . second.count ( state ) )
+		for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType, RankType >, ext::vector<StateType> >, StateType >& t : automaton.getTransitions())
+			if(ext::contains(t.first.second.begin(), t.first.second.end(), state ) || t . second == state )
 				return true;
 
 		return false;
@@ -659,12 +621,12 @@ struct normalize < automaton::NFTA < SymbolType, RankType, StateType > > {
 
 		automaton::NFTA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( finalStates ) );
 
-		for ( std::pair < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, ext::set < StateType > > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) {
+		for ( std::pair < ext::pair < common::ranked_symbol < SymbolType, RankType >, ext::vector < StateType > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) {
 			common::ranked_symbol < DefaultSymbolType, DefaultRankType > input = alphabet::SymbolNormalize::normalizeRankedSymbol ( std::move ( transition.first.first ) );
 			ext::vector < DefaultStateType > from = automaton::AutomatonNormalize::normalizeStates ( std::move ( transition.first.second ) );
-			ext::set < DefaultStateType > to = automaton::AutomatonNormalize::normalizeStates ( std::move ( transition.second ) );
+			DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) );
 
-			res.addTransitions ( std::move ( input ), std::move ( from ), std::move ( to ) );
+			res.addTransition ( std::move ( input ), std::move ( from ), std::move ( to ) );
 		}
 
 		return res;
diff --git a/alib2data/src/automaton/xml/TA/NFTA.h b/alib2data/src/automaton/xml/TA/NFTA.h
index 3a5b6b540b..3f0c483a9c 100644
--- a/alib2data/src/automaton/xml/TA/NFTA.h
+++ b/alib2data/src/automaton/xml/TA/NFTA.h
@@ -135,15 +135,13 @@ template < class SymbolType, class RankType, class StateType >
 void xmlApi < automaton::NFTA < SymbolType, RankType, StateType > >::composeTransitions(ext::deque<sax::Token>& out, const automaton::NFTA < SymbolType, RankType, StateType > & automaton ) {
 	out.emplace_back(sax::Token("transitions", sax::Token::TokenType::START_ELEMENT));
 	for(const auto& transition : automaton.getTransitions()) {
-		for(const auto& targetState: transition.second) {
-			out.emplace_back(sax::Token("transition", sax::Token::TokenType::START_ELEMENT));
+		out.emplace_back(sax::Token("transition", sax::Token::TokenType::START_ELEMENT));
 
-			automaton::AutomatonToXMLComposer::composeTransitionInputSymbol(out, transition.first.first);
-			automaton::AutomatonToXMLComposer::composeTransitionFrom(out, transition.first.second);
-			automaton::AutomatonToXMLComposer::composeTransitionTo(out, targetState);
+		automaton::AutomatonToXMLComposer::composeTransitionInputSymbol(out, transition.first.first);
+		automaton::AutomatonToXMLComposer::composeTransitionFrom(out, transition.first.second);
+		automaton::AutomatonToXMLComposer::composeTransitionTo(out, transition.second);
 
-			out.emplace_back(sax::Token("transition", sax::Token::TokenType::END_ELEMENT));
-		}
+		out.emplace_back(sax::Token("transition", sax::Token::TokenType::END_ELEMENT));
 	}
 
 	out.emplace_back(sax::Token("transitions", sax::Token::TokenType::END_ELEMENT));
-- 
GitLab