diff --git a/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp b/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp
index b416f53ca86a457e9f18384136b3aaf2f5080e9f..8c6967b2ac9b327aae9a158b4af1f48b97378dd0 100644
--- a/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp
+++ b/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp
@@ -6,45 +6,12 @@
  */
 
 #include "ToRegExpStateElimination.h"
-
-#include <regexp/simplify/RegExpOptimize.h>
-#include <regexp/transform/RegExpAlternate.h>
-#include <regexp/transform/RegExpConcatenate.h>
-#include <regexp/transform/RegExpIterate.h>
-
-#include <common/createUnique.hpp>
-
-#include <label/FinalStateLabel.h>
 #include <registration/AlgoRegistration.hpp>
 
 namespace automaton {
 
 namespace convert {
 
-template<class T>
-regexp::UnboundedRegExp < > ToRegExpStateElimination::convert(const T& automaton) {
-	if(automaton.getFinalStates().size() == 0)
-		return regexp::UnboundedRegExp < > (regexp::UnboundedRegExpStructure < DefaultSymbolType > (regexp::UnboundedRegExpEmpty < DefaultSymbolType > ()));
-
-	// steps 1 + 2
-	automaton::ExtendedNFA < > extendedAutomaton(automaton);
-	extendExtendedNFA(extendedAutomaton);
-
-	// step 3 - Exterminate!
-	// select all states that are neither final nor initial
-	ext::set<DefaultStateType> statesToEliminate = extendedAutomaton.getStates();
-	statesToEliminate.erase(extendedAutomaton.getInitialState());
-	statesToEliminate.erase(*extendedAutomaton.getFinalStates().begin());
-
-	for(const auto& state : statesToEliminate)
-		extendedAutomaton = eliminateState(extendedAutomaton, state);
-
-	// step 4
-	regexp::UnboundedRegExpStructure < DefaultSymbolType > finalStateLoop = regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, *extendedAutomaton.getFinalStates().begin(), *extendedAutomaton.getFinalStates().begin()));
-	regexp::UnboundedRegExpStructure < DefaultSymbolType > initialToFinalState = regexp::RegExpConcatenate::concatenate ( transitionsToRegExp ( extendedAutomaton, extendedAutomaton.getInitialState(), *extendedAutomaton.getFinalStates().begin()),finalStateLoop );
-	return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(initialToFinalState));
-}
-
 auto ToRegExpStateEliminationEpsilonNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::EpsilonNFA < > & >(ToRegExpStateElimination::convert);
 auto ToRegExpStateEliminationMultiInitialStateNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::MultiInitialStateNFA < > & >(ToRegExpStateElimination::convert);
 auto ToRegExpStateEliminationNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::NFA < > & >(ToRegExpStateElimination::convert);
@@ -52,65 +19,6 @@ auto ToRegExpStateEliminationDFA = registration::AbstractRegister < ToRegExpStat
 auto ToRegExpStateEliminationExtendedNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::ExtendedNFA < > & >(ToRegExpStateElimination::convert);
 auto ToRegExpStateEliminationCompactNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::CompactNFA < > & >(ToRegExpStateElimination::convert);
 
-automaton::ExtendedNFA < > ToRegExpStateElimination::eliminateState(const automaton::ExtendedNFA < > & extendedAutomaton, const DefaultStateType& q) {
-	automaton::ExtendedNFA < > newAutomaton(extendedAutomaton.getInitialState()); // sure that q is neither initial nor final (follows from step 2 - extending ExtendedNFA)
-	newAutomaton.setStates(extendedAutomaton.getStates());
-	newAutomaton.removeState(q); // preserve all states but q (the one to eliminate)
-	newAutomaton.setInputAlphabet(extendedAutomaton.getInputAlphabet());
-	newAutomaton.setFinalStates(extendedAutomaton.getFinalStates());
-
-	for(const auto& p: newAutomaton.getStates()) {
-		for(const auto& r : newAutomaton.getStates()) {
-			regexp::UnboundedRegExpStructure < DefaultSymbolType > concat = transitionsToRegExp(extendedAutomaton, p, q);
-			concat = regexp::RegExpConcatenate::concatenate(concat, regexp::RegExpIterate::iterate(transitionsToRegExp(extendedAutomaton, q, q)));
-			concat = regexp::RegExpConcatenate::concatenate(concat, transitionsToRegExp(extendedAutomaton, q, r));
-
-			regexp::UnboundedRegExpStructure < DefaultSymbolType > alt = regexp::RegExpAlternate::alternate(concat, transitionsToRegExp(extendedAutomaton, p, r));
-
-			newAutomaton.addTransition(p, regexp::simplify::RegExpOptimize::optimize(alt), r);
-		}
-	}
-
-	return newAutomaton;
-}
-
-const regexp::UnboundedRegExpStructure < DefaultSymbolType > ToRegExpStateElimination::transitionsToRegExp(const automaton::ExtendedNFA < > & automaton, const DefaultStateType& from, const DefaultStateType& to) {
-	regexp::UnboundedRegExpStructure < DefaultSymbolType > ret(regexp::UnboundedRegExpEmpty < DefaultSymbolType > { });
-
-	for(const auto& transition: automaton.getTransitionsFromState(from))
-		if(transition.second.count(to) > 0)
-			ret = regexp::RegExpAlternate::alternate(ret, transition.first.second);
-
-	return regexp::simplify::RegExpOptimize::optimize(ret);
-}
-
-void ToRegExpStateElimination::extendExtendedNFA(automaton::ExtendedNFA < > & automaton) {
-	const DefaultStateType& initState = automaton.getInitialState();
-	if(automaton.getFinalStates().count(initState) > 0 || automaton.getTransitionsToState(initState).size() > 0 ) {
-		DefaultStateType q0 = common::createUnique(initState, automaton.getStates());
-		automaton.addState(q0);
-
-		regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > () };
-		automaton.addTransition(q0, regexp, initState);
-
-		automaton.setInitialState(q0);
-	}
-
-	if(automaton.getFinalStates().size() > 1) {
-		DefaultStateType f = common::createUnique(label::FinalStateLabel::instance < DefaultStateType > ( ), automaton.getStates());
-		automaton.addState ( f );
-
-		for(const auto &state : automaton.getFinalStates() ) {
-			regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > () };
-			automaton.addTransition(state, regexp, f);
-		}
-
-		ext::set < DefaultStateType > newFinalStates;
-		newFinalStates.insert ( f );
-		automaton.setFinalStates ( newFinalStates );
-	}
-}
-
 } /* namespace convert */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/convert/ToRegExpStateElimination.h b/alib2algo/src/automaton/convert/ToRegExpStateElimination.h
index c16bd9e58fae22e89b1e013cd9a73590c0434b42..8ffc88a6ffb68eac8ff739b542570e3c24c0ac14 100644
--- a/alib2algo/src/automaton/convert/ToRegExpStateElimination.h
+++ b/alib2algo/src/automaton/convert/ToRegExpStateElimination.h
@@ -32,6 +32,17 @@
 #include <automaton/FSM/EpsilonNFA.h>
 #include <automaton/FSM/ExtendedNFA.h>
 
+#include <automaton/Automaton.h>
+
+#include <regexp/simplify/RegExpOptimize.h>
+#include <regexp/transform/RegExpAlternate.h>
+#include <regexp/transform/RegExpConcatenate.h>
+#include <regexp/transform/RegExpIterate.h>
+
+#include <common/createUnique.hpp>
+
+#include <label/FinalStateLabel.h>
+
 namespace automaton {
 
 namespace convert {
@@ -45,38 +56,135 @@ public:
 	/**
 	 * Performs conversion.
 	 * @tparam T type of the finite automaton
+	 * @tparam SymbolType the type of input symbols of the accepted automaton
+	 * @tparam StateType the type of states of the accepted automaton
 	 * @param automaton finite automaton to convert
 	 * @return unbounded regular expression equivalent to the original automaton
 	 */
-	template<class T>
-	static regexp::UnboundedRegExp < > convert(const T& automaton);
+	template < class T, class SymbolType = typename automaton::SymbolTypeOfAutomaton < T >, class StateType = typename automaton::StateTypeOfAutomaton < T > >
+	static regexp::UnboundedRegExp < SymbolType > convert ( const T & automaton );
 
 private:
 	/**
 	 * Helper function to create new initial and final states in the automaton for the algorithm.
+	 * @tparam SymbolType the type of input symbols of the accepted automaton
+	 * @tparam StateType the type of states of the accepted automaton
 	 * @param automaton extended finite automaton
 	 */
-	static void extendExtendedNFA(automaton::ExtendedNFA < > & automaton);
+	template < class SymbolType, class StateType >
+	static void extendExtendedNFA(automaton::ExtendedNFA < SymbolType, StateType > & automaton );
 
 	/**
 	 * Helper function to create a regexp from all transitions between states @p from and @p to.
 	 * It creates the alternation regexp of all such transitions.
+	 * @tparam SymbolType the type of input symbols of the accepted automaton
+	 * @tparam StateType the type of states of the accepted automaton
 	 * @param automaton automaton to select the transitions
 	 * @param from source state in @param automaton
 	 * @param to   destination state in @param automaton
 	 * @return the regular expression node representing the transitions between states @p from and @p to
 	 */
-	static const regexp::UnboundedRegExpStructure < DefaultSymbolType > transitionsToRegExp(const automaton::ExtendedNFA < > & automaton, const DefaultStateType& from, const DefaultStateType& to);
+	template < class SymbolType, class StateType >
+	static const regexp::UnboundedRegExpStructure < SymbolType > transitionsToRegExp ( const automaton::ExtendedNFA < SymbolType, StateType > & automaton, const StateType & from, const StateType & to );
 
 	/**
 	 * Helper function for the elimination of a single state according to the algorithm.
+	 * @tparam SymbolType the type of input symbols of the accepted automaton
+	 * @tparam StateType the type of states of the accepted automaton
 	 * @param extendedAutomaton automaton for the elimination
 	 * @param state state to eliminate
 	 * @return the @p extendedAutomaton after the elimination of a state @state.
 	 */
-	static automaton::ExtendedNFA < > eliminateState(const automaton::ExtendedNFA < > & extendedAutomaton, const DefaultStateType& state);
+	template < class SymbolType, class StateType >
+	static automaton::ExtendedNFA < SymbolType, StateType > eliminateState ( const automaton::ExtendedNFA < SymbolType, StateType > & extendedAutomaton, const StateType & state );
 };
 
+template < class T, class SymbolType, class StateType >
+regexp::UnboundedRegExp < SymbolType > ToRegExpStateElimination::convert ( const T & automaton ) {
+	if ( automaton.getFinalStates ( ).size ( ) == 0 )
+		return regexp::UnboundedRegExp < SymbolType > ( regexp::UnboundedRegExpStructure < DefaultSymbolType > ( regexp::UnboundedRegExpEmpty < DefaultSymbolType > ( ) ) );
+
+	// steps 1 + 2
+	automaton::ExtendedNFA < SymbolType, StateType > extendedAutomaton ( automaton );
+	extendExtendedNFA ( extendedAutomaton );
+
+	// step 3 - Exterminate!
+	// select all states that are neither final nor initial
+	ext::set < StateType > statesToEliminate = extendedAutomaton.getStates ( );
+	statesToEliminate.erase ( extendedAutomaton.getInitialState ( ) );
+	statesToEliminate.erase ( * extendedAutomaton.getFinalStates ( ).begin ( ) );
+
+	for ( const StateType & state : statesToEliminate )
+		extendedAutomaton = eliminateState ( extendedAutomaton, state );
+
+	// step 4
+	regexp::UnboundedRegExpStructure < SymbolType > finalStateLoop = regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, * extendedAutomaton.getFinalStates ( ).begin ( ), * extendedAutomaton.getFinalStates ( ).begin ( ) ) );
+	regexp::UnboundedRegExpStructure < SymbolType > initialToFinalState = regexp::RegExpConcatenate::concatenate ( transitionsToRegExp ( extendedAutomaton, extendedAutomaton.getInitialState ( ), *extendedAutomaton.getFinalStates ( ).begin ( ) ),finalStateLoop );
+	return regexp::UnboundedRegExp < SymbolType > ( regexp::simplify::RegExpOptimize::optimize ( initialToFinalState ) );
+}
+
+template < class SymbolType, class StateType >
+automaton::ExtendedNFA < SymbolType, StateType > ToRegExpStateElimination::eliminateState ( const automaton::ExtendedNFA < SymbolType, StateType > & extendedAutomaton, const StateType & q ) {
+	automaton::ExtendedNFA < SymbolType, StateType > newAutomaton ( extendedAutomaton.getInitialState ( ) ); // sure that q is neither initial nor final (follows from step 2 - extending ExtendedNFA)
+	newAutomaton.setStates ( extendedAutomaton.getStates ( ) );
+	newAutomaton.removeState ( q ); // preserve all states but q (the one to eliminate)
+	newAutomaton.setInputAlphabet ( extendedAutomaton.getInputAlphabet ( ) );
+	newAutomaton.setFinalStates ( extendedAutomaton.getFinalStates ( ) );
+
+	for ( const StateType & p: newAutomaton.getStates ( ) ) {
+		for ( const StateType & r : newAutomaton.getStates ( ) ) {
+			regexp::UnboundedRegExpStructure < SymbolType > concat = transitionsToRegExp ( extendedAutomaton, p, q );
+			concat = regexp::RegExpConcatenate::concatenate ( concat, regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, q, q ) ) );
+			concat = regexp::RegExpConcatenate::concatenate ( concat, transitionsToRegExp ( extendedAutomaton, q, r ) );
+
+			regexp::UnboundedRegExpStructure < SymbolType > alt = regexp::RegExpAlternate::alternate ( concat, transitionsToRegExp ( extendedAutomaton, p, r ) );
+
+			newAutomaton.addTransition ( p, regexp::simplify::RegExpOptimize::optimize ( alt ), r );
+		}
+	}
+
+	return newAutomaton;
+}
+
+template < class SymbolType, class StateType >
+const regexp::UnboundedRegExpStructure < SymbolType > ToRegExpStateElimination::transitionsToRegExp ( const automaton::ExtendedNFA < SymbolType, StateType > & automaton, const StateType & from, const StateType & to ) {
+	regexp::UnboundedRegExpStructure < SymbolType > ret ( regexp::UnboundedRegExpEmpty < SymbolType > { } );
+
+	for ( const auto & transition: automaton.getTransitionsFromState ( from ) )
+		if ( transition.second.count ( to ) > 0)
+			ret = regexp::RegExpAlternate::alternate ( ret, transition.first.second );
+
+	return regexp::simplify::RegExpOptimize::optimize ( ret );
+}
+
+template < class SymbolType, class StateType >
+void ToRegExpStateElimination::extendExtendedNFA ( automaton::ExtendedNFA < SymbolType, StateType > & automaton ) {
+	const StateType & initState = automaton.getInitialState ( );
+	if ( automaton.getFinalStates ( ).count ( initState ) > 0 || automaton.getTransitionsToState ( initState ).size ( ) > 0 ) {
+		StateType q0 = common::createUnique ( initState, automaton.getStates ( ) );
+		automaton.addState ( q0 );
+
+		regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > ( ) };
+		automaton.addTransition ( q0, regexp, initState );
+
+		automaton.setInitialState ( q0 );
+	}
+
+	if ( automaton.getFinalStates ( ).size ( ) > 1 ) {
+		StateType f = common::createUnique ( label::FinalStateLabel::instance < StateType > ( ), automaton.getStates ( ) );
+		automaton.addState ( f );
+
+		for ( const StateType & state : automaton.getFinalStates ( ) ) {
+			regexp::UnboundedRegExpStructure < SymbolType > regexp { regexp::UnboundedRegExpEpsilon < SymbolType > ( ) };
+			automaton.addTransition ( state, regexp, f );
+		}
+
+		ext::set < StateType > newFinalStates;
+		newFinalStates.insert ( f );
+		automaton.setFinalStates ( newFinalStates );
+	}
+}
+
 } /* namespace convert */
 
 } /* namespace automaton */