diff --git a/alib2algo/src/rte/convert/ToPostfixPushdownAutomatonGlushkovV3.cpp b/alib2algo/src/rte/convert/ToPostfixPushdownAutomatonGlushkovV3.cpp
index 360c13bc8970fa005b0aca10466285e3b11a4481..b3cec97de896f0344ba4f7200cd3b28ec9935e5a 100644
--- a/alib2algo/src/rte/convert/ToPostfixPushdownAutomatonGlushkovV3.cpp
+++ b/alib2algo/src/rte/convert/ToPostfixPushdownAutomatonGlushkovV3.cpp
@@ -17,6 +17,7 @@
 #include "../glushkov/GlushkovFollowV3.h"
 #include "../glushkov/GlushkovIndexate.h"
 #include "../glushkov/GlushkovFirst.h"
+#include "../glushkov/GlushkovSubstitutionMap.h"
 
 namespace rte {
 
@@ -45,10 +46,11 @@ ToPostfixPushdownAutomatonGlushkovV3::convert ( const rte::FormalRTE < > & rte )
 	const std::set < std::ranked_symbol < > > firstSet = rte::GlushkovFirst::first ( indexedRTE );
 
 	 // - follow set for every element of (non-indexed) RTE alphabet element
+	const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, std::map < std::ranked_symbol < >, std::set < std::ranked_symbol < > > > > substMapTree = GlushkovSubstitutionMap::substMap ( indexedRTE );
 	std::map < std::ranked_symbol < >, std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > > followSet;
 
 	for ( const std::ranked_symbol < > & symbol : indexedRTE.getAlphabet ( ) )
-		followSet.insert ( std::make_pair ( symbol, rte::GlushkovFollowV3::follow ( indexedRTE, symbol ) ) );
+		followSet.insert ( std::make_pair ( symbol, rte::GlushkovFollowV3::follow ( indexedRTE, symbol, substMapTree ) ) );
 
 	/* check for exceptions -> there must be NO substitution symbol in first set */
 	if ( isSubstSymbolPresent ( firstSet, rte.getSubstitutionAlphabet ( ) ) )
@@ -85,10 +87,10 @@ ToPostfixPushdownAutomatonGlushkovV3::convert ( const rte::FormalRTE < > & rte )
 		automaton.addPushdownStoreSymbol ( std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > ( { symb } ) );
 
 	// complex
-	for ( const std::pair < const std::ranked_symbol < >, std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > >& kv : followSet ) {
-		for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & followTuple : kv.second ) {
-			for ( const std::set < std::ranked_symbol < > > & symb : followTuple ) {
-				automaton.addPushdownStoreSymbol ( std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > ( symb ) );
+	for ( const std::pair < const rte::FormalRTEElement < SymbolType, RankType >* const, std::map < std::ranked_symbol < >, std::set < std::ranked_symbol < > > > > & kv : substMapTree ) {
+		if ( dynamic_cast < const rte::FormalRTESymbolSubst < SymbolType, RankType > * const > ( kv.first ) ) { 
+			for ( const std::pair < std::ranked_symbol < >, std::set < std::ranked_symbol < > > > & kv2 : kv.second ) {
+				automaton.addPushdownStoreSymbol ( kv2.second );
 			}
 		}
 	}
@@ -145,13 +147,13 @@ ToPostfixPushdownAutomatonGlushkovV3::convert ( const rte::FormalRTE < > & rte )
 			std::vector < std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > > push;
 			push.push_back( std::set < std::ranked_symbol < SymbolType, RankType > > { symb } );
 
-			automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), { }, q, push );
 			if ( common::GlobalData::verbose ) {
 				std::cerr << "Transition 3: " << rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ) << " | " << std::endl <<
 					"\t" << "[]" << std::endl <<
 					"\t ->" << std::endl <<
 					"\t" << push << std::endl << std::endl;
 			}
+			automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), { }, q, push );
 		} else {
 			for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & followTuple : followSet [ symb ] ) { //tuple = vector < set < symb > >
 				std::vector < std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > > pop, push;
@@ -159,77 +161,52 @@ ToPostfixPushdownAutomatonGlushkovV3::convert ( const rte::FormalRTE < > & rte )
 				/*
 				for ( const auto & e : symbFollowTuple )
 				   pop.push_back ( e );
-				std::reverse ( pop.begin ( ), pop.end ( ) ); // <------------ WTF. CRASHES HERE
+				std::reverse ( pop.begin ( ), pop.end ( ) ); // <------------ WTF. CRASHES HERE // FIXME
 				*/
 				for ( const auto & e : followTuple )
 					pop.insert ( pop.begin ( ), e );
 
 				push.push_back( std::set < std::ranked_symbol < SymbolType, RankType > > { symb } );
 
-				automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), pop, q, push );
 				if ( common::GlobalData::verbose ) {
 					std::cerr << "Transition 2: " << rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ) << " | " << std::endl <<
 						"\t" << pop << std::endl <<
 						"\t ->" << std::endl <<
 						"\t" << push << std::endl << std::endl;
 				}
+				automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), pop, q, push );
 			}
 		}
 	}
 
 	// Pattern 1
 	for ( const std::ranked_symbol < > & symb : indexedRTE.getAlphabet ( ) ) {
-		// 1a
-		if ( symb.getRank ( ) == primitive::Unsigned ( 0 ) ) {
-			/* If symb \in some symbolSet of followSet [ i ], then    symb | \varepsilon -> symbolSet  */
-
-			for ( const std::pair < const std::ranked_symbol < >, std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > >& kv : followSet ) {
-				for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & followTuple : kv.second ) { // TFollowTuple = vector < set < ranked_symbol > >
-					for ( const std::set < std::ranked_symbol < > > & symbolSet : followTuple ) {
-						if ( symbolSet.count ( symb ) ) {
-							std::vector < std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > > push;
-							push.push_back( symbolSet );
-							automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), { }, q, push );
-
-							if ( common::GlobalData::verbose ) {
-								std::cerr << "Transition 1a: " << rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ) << " | " << std::endl <<
-									"\t" << "[ ]" << std::endl <<
-									"\t ->" << std::endl <<
-									"\t" << push << std::endl << std::endl;
-							}
-						}
+		for ( const std::pair < const rte::FormalRTEElement < SymbolType, RankType >* const, std::map < std::ranked_symbol < >, std::set < std::ranked_symbol < > > > > & kv : substMapTree ) {
+			if ( dynamic_cast < const rte::FormalRTESymbolSubst < SymbolType, RankType > * const > ( kv.first ) == nullptr ) // not a SubstSymbol node
+				continue;
+
+			for ( const std::pair < std::ranked_symbol < >, std::set < std::ranked_symbol < > > > & kv2 : kv.second ) {
+				if ( kv2.second.count ( symb ) == 0 ) 
+					continue;
+
+				for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & symbFollowTuple : followSet [ symb ] ) {
+					std::vector < std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > > pop, push;
+
+					if ( ( size_t ) symb.getRank ( ) > 0 ) {
+						for ( const auto & e : symbFollowTuple )
+							pop.insert ( pop.begin ( ), e );
 					}
-				}
-			}
-		} else { // 1b
-			/* If symb \in some symbolSet of followSet [ i ], then    symb | followTuple -> symbolSet  */
-			for ( const std::pair < const std::ranked_symbol < >, std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > >& kv : followSet ) {
-				for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & followTuple : kv.second ) { // TFollowTuple = vector < set < ranked_symbol > >
-					for ( const std::set < std::ranked_symbol < > > & symbolSet : followTuple ) {
-						if ( symbolSet.count ( symb ) ) {
-							std::vector < std::variant < alphabet::BottomOfTheStackSymbol, std::set < std::ranked_symbol < SymbolType, RankType > > > > pop, push;
-
-							for ( const GlushkovFollowV3::TFollowTuple < SymbolType, RankType > & symbFollowTuple : followSet [ symb ] ) {
-								/*
-								for ( const auto & e : symbFollowTuple )
-									pop.push_back ( e );
-								std::reverse ( pop.begin ( ), pop.end ( ) ); // <------------ WTF. CRASHES HERE
-								*/
-								for ( const auto & e : symbFollowTuple )
-									pop.insert ( pop.begin ( ), e );
-
-								push.push_back( symbolSet );
-								automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), pop, q, push );
-
-								if ( common::GlobalData::verbose ) {
-									std::cerr << "Transition 1b: " << rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ) << " | " << std::endl <<
-										"\t" << pop << std::endl <<
-										"\t ->" << std::endl <<
-										"\t" << push << std::endl << std::endl;
-								}
-							}
-						}
+
+					push.push_back( kv2.second );
+
+					if ( common::GlobalData::verbose ) {
+						std::cerr << "Transition 1" << ( pop.empty() ? "a" : "b" ) <<  ": " << rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ) << " | " << std::endl <<
+							"\t" << pop << std::endl <<
+							"\t ->" << std::endl <<
+							"\t" << push << std::endl << std::endl;
 					}
+
+					automaton.addTransition ( q, rte::GlushkovIndexate::getSymbolFromGlushkovPair ( symb ).getSymbol ( ), pop, q, push );
 				}
 			}
 		}
@@ -242,8 +219,6 @@ ToPostfixPushdownAutomatonGlushkovV3::convert ( const rte::FormalRTE < > & rte )
 		pop.push_back ( BotS );
 		automaton.addTransition ( q, alphabet::EndSymbol::instance < DefaultSymbolType > ( ), pop, f, { } );
 	}
-
-
 	/* TRANSITIONS END */
 
 	return automaton;
diff --git a/alib2algo/src/rte/glushkov/GlushkovFollowV3.h b/alib2algo/src/rte/glushkov/GlushkovFollowV3.h
index 052e2453951eedf39da641fd240630fbdccbf318..4c33e1f33f271a5c96a9d2f21c57c3d44e21a1f2 100644
--- a/alib2algo/src/rte/glushkov/GlushkovFollowV3.h
+++ b/alib2algo/src/rte/glushkov/GlushkovFollowV3.h
@@ -44,120 +44,69 @@ private:
 	template < class SymbolType, class RankType >
 	static std::set < TFollowTuple < SymbolType, RankType > > replaceConstants ( const TAlphabet < SymbolType, RankType > & alphabetK, const std::vector < std::ranked_symbol < SymbolType, RankType > > & follow, const TSubstMap < SymbolType, RankType > & subMap2 );
 
-	template < class SymbolType, class RankType >
-	static void preprocessSubMap ( const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap );
-
-	template < class T >
-	static std::vector < std::vector < T > > cartesian ( const std::vector < std::vector < T > > & input );
-
-	template < class T >
-	static void cartesian_rec ( const std::vector < std::vector < T > > & input, std::vector < std::vector < T > > & ret, std::vector < T > & current, size_t depth );
-
 public:
 	/**
 	 * @param re rte to probe
 	 * @param symbol FormalRTESymbol for which we need the follow(), i.e., Follow(RTE, symbol)
+	 * @param substMapTree Tree substitution mapping from, rte::GlushkovSubstitutionMap::substMap
 	 * @return all symbols that can follow specific symbol in word
 	 */
 	template < class SymbolType, class RankType >
-	static std::set < TFollowTuple < SymbolType, RankType > > follow ( const rte::FormalRTE < SymbolType, RankType > & re, const std::ranked_symbol < SymbolType, RankType > & symbol );
+	static std::set < TFollowTuple < SymbolType, RankType > > follow ( const rte::FormalRTE < SymbolType, RankType > & rte, const std::ranked_symbol < SymbolType, RankType > & symbol, const std::map < const rte::FormalRTEElement < SymbolType, RankType > *, TSubstMap < SymbolType, RankType > > & substMapTree );
 
 	template < class SymbolType, class RankType >
 	class Formal {
 	public:
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEElement < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
-		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subM );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEElement < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+		static std::set < TFollowTuple < SymbolType, RankType > > visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbol, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree );
+
 	};
 
 };
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::follow ( const rte::FormalRTE < SymbolType, RankType > & rte, const std::ranked_symbol < SymbolType, RankType > & symbol ) {
-	TSubstMap < SymbolType, RankType > subMap;
-
-	 /* Init substitution map, ie \forall a \in K: sub[a] = \emptyset */
-	for ( const std::ranked_symbol < SymbolType, RankType > & ssymb : rte.getSubstitutionAlphabet ( ) )
-		subMap.insert ( std::make_pair ( ssymb, TAlphabet < SymbolType, RankType > { } ) );
-
-	 /* recursively compute follow */
-	return rte.getRTE ( ).getStructure ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbol, rte.getSubstitutionAlphabet ( ), subMap );
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::follow ( const rte::FormalRTE < SymbolType, RankType > & rte, const std::ranked_symbol < SymbolType, RankType > & symbol, const std::map < const rte::FormalRTEElement < SymbolType, RankType > *, TSubstMap < SymbolType, RankType > > & substMapTree ) {
+	return rte.getRTE ( ).getStructure ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbol, rte.getSubstitutionAlphabet ( ), substMapTree );
 }
 
 // -----------------------------------------------------------------------------
 
-/**
- * Preprocessing:
- *  - Let k1, k2 be elements of alphabet K.
- *  - If k1 is an element of substMap[k2], then copy content of substMap[k1] into substMap[k2]
- */
 template < class SymbolType, class RankType >
-void GlushkovFollowV3::preprocessSubMap ( const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap ) {
-	for ( bool change = true; change; change = false )
-		for ( std::pair < const std::ranked_symbol < SymbolType, RankType >, TAlphabet < SymbolType, RankType > > & kv : subMap ) {
-			TAlphabet < SymbolType, RankType > & substSet = kv.second;
-
-			for ( auto eIter = substSet.begin ( ); eIter != substSet.end ( ); ) {
-				if ( alphabetK.count ( * eIter ) == 0 ) {
-					++eIter;
-				} else {
-					auto it = subMap.find ( * eIter );
-					size_t oldSize = substSet.size ( );
-					substSet.insert ( it->second.begin ( ), it->second.end ( ) );
-					change = ( oldSize != substSet.size ( ) ); // something was added
-					eIter = substSet.erase ( eIter );
-				}
-			}
-		}
-}
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::replaceConstants ( const TAlphabet < SymbolType, RankType > & alphabetK, const std::vector < std::ranked_symbol < SymbolType, RankType > > & children, const TSubstMap < SymbolType, RankType > & subMap ) {
+	TFollowTuple < SymbolType, RankType > follow;
 
-template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::replaceConstants ( const TAlphabet < SymbolType, RankType > & alphabetK, const std::vector < std::ranked_symbol < SymbolType, RankType > > & follow, const TSubstMap < SymbolType, RankType > & subMap2 ) {
-	TSubstMap < SymbolType, RankType > subMap ( subMap2 );
-	preprocessSubMap ( alphabetK, subMap );
-
-	TFollowTuple < SymbolType, RankType > children_follow;
-
-	for ( const std::ranked_symbol < SymbolType, RankType > & e : follow ) {
+	for ( const std::ranked_symbol < SymbolType, RankType > & e : children ) {
 		if ( alphabetK.count ( e ) > 0 )
-			children_follow.push_back ( std::set < std::ranked_symbol < SymbolType, RankType > > ( subMap.at ( e ).begin ( ), subMap.at ( e ).end ( ) ) );
+			follow.push_back ( std::set < std::ranked_symbol < SymbolType, RankType > > ( subMap.at ( e ).begin ( ), subMap.at ( e ).end ( ) ) );
 		else
-			children_follow.push_back ( std::set < std::ranked_symbol < SymbolType, RankType > > { e } );
+			follow.push_back ( std::set < std::ranked_symbol < SymbolType, RankType > > { e } );
 	}
 
-	return { children_follow };
+	return std::set < TFollowTuple < SymbolType, RankType > > { follow };
 }
 
 // -----------------------------------------------------------------------------
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap ) {
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree ) {
 	std::set < TFollowTuple < SymbolType, RankType > > ret, tmp;
 
-	tmp = node.getLeftElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMap );
+	tmp = node.getLeftElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 	ret.insert ( tmp.begin ( ), tmp.end ( ) );
 
-	tmp = node.getRightElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMap );
+	tmp = node.getRightElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 	ret.insert ( tmp.begin ( ), tmp.end ( ) );
 
 	return ret;
 }
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap ) {
-
-	TSubstMap < SymbolType, RankType > subMapLeft ( subMap );
-	auto itMap = subMapLeft.find ( node.getSubstitutionSymbol ( ).getSymbol ( ) );
-
-	itMap->second.clear ( );
-
-	for ( const auto & s : node.getRightElement ( ).template accept < TAlphabet < SymbolType, RankType >, GlushkovFirst::Formal < SymbolType, RankType > > ( ) )
-		itMap->second.insert ( s );
-
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree ) {
 	/*
 	 * E sub F
 	 *   1. if symbolF in F subtree, then Follow(F, symbolF);
@@ -165,24 +114,18 @@ std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFol
 	 */
 
 	if ( node.getLeftElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType, RankType > > ( symbolF ) )
-		return node.getLeftElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMapLeft );
+		return node.getLeftElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 	else
-		return node.getRightElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMap );
+		return node.getRightElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 }
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap ) {
-
-	std::set < TFollowTuple < SymbolType, RankType > > ret;
-
-	for ( const auto & s : node.getElement ( ).template accept < TAlphabet < SymbolType, RankType >, GlushkovFirst::Formal < SymbolType, RankType > > ( ) )
-		subMap[node.getSubstitutionSymbol ( ).getSymbol ( )].insert ( s );
-
-	return node.getElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMap );
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree ) {
+	return node.getElement ( ).template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 }
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, TSubstMap < SymbolType, RankType > & subMap ) {
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, const std::ranked_symbol < SymbolType, RankType > & symbolF, const TAlphabet < SymbolType, RankType > & alphabetK, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & substMapTree ) {
 
 	std::set < TFollowTuple < SymbolType, RankType > > ret, tmp;
 
@@ -192,11 +135,11 @@ std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFol
 		for ( const std::smart_ptr < const rte::FormalRTESymbol < SymbolType, RankType > > & c : node.getElements ( ) )
 			children.push_back ( c->getSymbol ( ) );
 
-		return replaceConstants ( alphabetK, children, subMap );
+		return replaceConstants ( alphabetK, children, substMapTree.at( & node ));
 	}
 
 	for ( const auto & c : node.getElements ( ) ) {
-		tmp = c->template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, subMap );
+		tmp = c->template accept < std::set < TFollowTuple < SymbolType, RankType > >, GlushkovFollowV3::Formal < SymbolType, RankType > > ( symbolF, alphabetK, substMapTree );
 		ret.insert ( tmp.begin ( ), tmp.end ( ) );
 	}
 
@@ -204,12 +147,12 @@ std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFol
 }
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & /* node */, const std::ranked_symbol < SymbolType, RankType > & /* symbolF */, const TAlphabet < SymbolType, RankType > & /* alphabetK */, TSubstMap < SymbolType, RankType > & /* subMap */ ) {
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & /* node */, const std::ranked_symbol < SymbolType, RankType > & /* symbol */, const TAlphabet < SymbolType, RankType > & /* alphabetK */, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & /* substMapTree */ ) {
 	return std::set < TFollowTuple < SymbolType, RankType > > ( );
 }
 
 template < class SymbolType, class RankType >
-std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & /* node */, const std::ranked_symbol < SymbolType, RankType > & /* symbolF */, const TAlphabet < SymbolType, RankType > & /* alphabetK */, TSubstMap < SymbolType, RankType > & /* subMap */ ) {
+std::set < GlushkovFollowV3::TFollowTuple < SymbolType, RankType > > GlushkovFollowV3::Formal < SymbolType, RankType > ::visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & /* node */, const std::ranked_symbol < SymbolType, RankType > & /* symbol */, const TAlphabet < SymbolType, RankType > & /* alphabetK */, const std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > & /* substMapTree */ ) {
 	return std::set < TFollowTuple < SymbolType, RankType > > ( );
 }
 
diff --git a/alib2algo/src/rte/glushkov/GlushkovSubstitutionMap.h b/alib2algo/src/rte/glushkov/GlushkovSubstitutionMap.h
new file mode 100644
index 0000000000000000000000000000000000000000..703d279a1818c33d981720da5040c112beeeaacb
--- /dev/null
+++ b/alib2algo/src/rte/glushkov/GlushkovSubstitutionMap.h
@@ -0,0 +1,176 @@
+/*
+ * GlushkovSubstitutionMap.h
+ *
+ *  Created on: 26. 7. 2017
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef RTE_GLUSHKOV_SUBSTITUTION_MAP_H_
+#define RTE_GLUSHKOV_SUBSTITUTION_MAP_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include <rte/formal/FormalRTE.h>
+#include <rte/formal/FormalRTEElements.h>
+
+#include <alphabet/RankedSymbol.h>
+
+#include "GlushkovFirst.h"
+#include "GlushkovPos.h"
+#include <iterator>
+#include <vector>
+
+namespace rte {
+
+class GlushkovSubstitutionMap {
+
+private:
+	template < class SymbolType, class RankType >
+	using TSubstMap = std::map < std::ranked_symbol < SymbolType, RankType >, std::set < std::ranked_symbol < SymbolType, RankType > > >;
+
+	template < class SymbolType, class RankType >
+	using TSubstMapTree = std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > >;
+
+	template < class SymbolType, class RankType >
+	using TAlphabet = std::set < std::ranked_symbol < SymbolType, RankType > >;
+
+	// --------------------------------------------------------------------
+
+	template < class SymbolType, class RankType >
+	static void preprocessSubMap ( TSubstMap < SymbolType, RankType > & subMap, const TAlphabet < SymbolType, RankType > & alphabetK );
+
+	template < class SymbolType, class RankType >
+	static void subst_symbol_replaces ( std::map < const rte::FormalRTEElement < SymbolType, RankType > *, TSubstMap < SymbolType, RankType > > & substMapTree, const TAlphabet < SymbolType, RankType > & alphabetK );
+
+public:
+	/**
+	 * @param re rte to probe
+	 * @return subst map for all RTE syntax tree elements
+	 */
+	template < class SymbolType, class RankType >
+	static std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap < SymbolType, RankType > > substMap ( const rte::FormalRTE < SymbolType, RankType > & re );
+
+	template < class SymbolType, class RankType >
+	class Formal {
+	public:
+		static void visit ( const rte::FormalRTEElement < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+		static void visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subM, TSubstMapTree < SymbolType, RankType > & subMapTree );
+	};
+
+};
+
+// -----------------------------------------------------------------------------
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::subst_symbol_replaces ( std::map < const rte::FormalRTEElement < SymbolType, RankType > *, TSubstMap < SymbolType, RankType > > & substMapTree, const TAlphabet < SymbolType, RankType > & alphabetK ) {
+	for ( std::pair < const rte::FormalRTEElement < SymbolType, RankType > * const, TSubstMap < SymbolType, RankType > > & kv : substMapTree ) {
+		preprocessSubMap ( kv.second, alphabetK );
+	}
+}
+
+/**
+ * Preprocessing:
+ *  - Let k1, k2 be elements of alphabet K.
+ *  - If k1 is an element of substMap[k2], then copy content of substMap[k1] into substMap[k2]
+ */
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::preprocessSubMap ( TSubstMap < SymbolType, RankType > & subMap, const TAlphabet < SymbolType, RankType > & alphabetK ) {
+	for ( bool change = true; change; change = false )
+		for ( std::pair < const std::ranked_symbol < SymbolType, RankType >, TAlphabet < SymbolType, RankType > > & kv : subMap ) {
+			TAlphabet < SymbolType, RankType > & substSet = kv.second;
+
+			for ( auto eIter = substSet.begin ( ); eIter != substSet.end ( ); ) {
+				if ( alphabetK.count ( * eIter ) == 0 ) {
+					++eIter;
+				} else {
+					auto it = subMap.find ( * eIter );
+					size_t oldSize = substSet.size ( );
+					substSet.insert ( it->second.begin ( ), it->second.end ( ) );
+					change = ( oldSize != substSet.size ( ) ); // something was added
+					eIter = substSet.erase ( eIter );
+				}
+			}
+		}
+}
+
+// -----------------------------------------------------------------------------
+
+template < class SymbolType, class RankType >
+std::map < const rte::FormalRTEElement < SymbolType, RankType >*, GlushkovSubstitutionMap::TSubstMap < SymbolType, RankType > > GlushkovSubstitutionMap::substMap ( const rte::FormalRTE < SymbolType, RankType > & rte ) {
+	TSubstMap < SymbolType, RankType > subMap;
+	std::map < const rte::FormalRTEElement < SymbolType, RankType >*, TSubstMap  < SymbolType, RankType > > subMapTree;
+
+	/* Init substitution map, ie \forall a \in K: sub[a] = \emptyset */
+	for ( const std::ranked_symbol < SymbolType, RankType > & ssymb : rte.getSubstitutionAlphabet ( ) )
+		subMap.insert ( std::make_pair ( ssymb, TAlphabet < SymbolType, RankType > { } ) );
+
+	/* recursively compute substMap */
+	rte.getRTE ( ).getStructure ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+	subst_symbol_replaces ( subMapTree, rte.getSubstitutionAlphabet ( ) );
+	return subMapTree;
+}
+
+// -----------------------------------------------------------------------------
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEAlternation < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+	node.getLeftElement ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+	node.getRightElement ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+}
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESubstitution < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+
+	// re-init left map
+	TSubstMap < SymbolType, RankType > subMapLeft ( subMap );
+	auto itMap = subMapLeft.find ( node.getSubstitutionSymbol ( ).getSymbol ( ) );
+	itMap->second.clear ( );
+
+	for ( const auto & s : node.getRightElement ( ).template accept < std::set < std::ranked_symbol < > >, GlushkovFirst::Formal < SymbolType, RankType > > ( ) )
+		itMap->second.insert ( s );
+
+	node.getLeftElement ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMapLeft, subMapTree );
+	node.getRightElement ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+}
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEIteration < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+
+	for ( const auto & s : node.getElement ( ).template accept < TAlphabet < SymbolType, RankType >, GlushkovFirst::Formal < SymbolType, RankType > > ( ) )
+		subMap[node.getSubstitutionSymbol ( ).getSymbol ( )].insert ( s );
+
+	node.getElement ( ).template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+}
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESymbolAlphabet < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+
+	for ( const auto & c : node.getElements ( ) ) {
+		c -> template accept < void, GlushkovSubstitutionMap::Formal < SymbolType, RankType > > ( subMap, subMapTree );
+	}
+}
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTESymbolSubst < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+}
+
+template < class SymbolType, class RankType >
+void GlushkovSubstitutionMap::Formal < SymbolType, RankType >::visit ( const rte::FormalRTEEmpty < SymbolType, RankType > & node, TSubstMap < SymbolType, RankType > & subMap, TSubstMapTree < SymbolType, RankType > & subMapTree ) {
+	subMapTree.insert ( std::make_pair ( & node, subMap ) );
+}
+
+} /* namespace rte */
+
+#endif /* RTE_GLUSHKOV_SUBSTITUTION_MAP_H_ */