diff --git a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
index 99fb225cacd1da62de18747b28d17f457891d90d..bf4cb98f0d50b65c24c1bcc9520c308494baec3b 100644
--- a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
+++ b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
@@ -6,183 +6,23 @@
  */
 
 #include "ExactPatternMatchingAutomaton.h"
-#include "ExactSubtreeMatchingAutomaton.h"
-#include <tree/properties/SubtreeJumpTable.h>
-
-#include <tree/ranked/RankedTree.h>
-#include <tree/ranked/RankedPattern.h>
-#include <tree/ranked/PrefixRankedTree.h>
-#include <tree/ranked/PrefixRankedPattern.h>
-#include <tree/ranked/PrefixRankedBarTree.h>
-#include <tree/ranked/PrefixRankedBarPattern.h>
-
-#include <automaton/PDA/InputDrivenNPDA.h>
-#include <automaton/PDA/VisiblyPushdownNPDA.h>
-#include <automaton/PDA/NPDA.h>
-#include <automaton/TA/NFTA.h>
-
-#include <alib/deque>
-#include <alphabet/RankedSymbol.h>
 #include <registration/AlgoRegistration.hpp>
 
 namespace arbology {
 
 namespace exact {
 
-automaton::InputDrivenNPDA < > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedTree < > & pattern ) {
-	return ExactSubtreeMatchingAutomaton::construct ( pattern );
-}
-
-auto ExactPatternMatchingAutomatonPrefixRankedTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::InputDrivenNPDA < >, const tree::PrefixRankedTree < > & > ( ExactPatternMatchingAutomaton::construct );
-
-ext::vector < DefaultSymbolType > computeRHS ( const tree::PrefixRankedPattern < > & pattern, const ext::vector < int > & patternSubtreeJumpTable, int i ) {
-	const ext::vector < common::ranked_symbol < > > & content = pattern.getContent ( );
-
-	unsigned rank = ( unsigned ) content[i].getRank ( );
-
-	i++;
-
-	ext::vector < DefaultSymbolType > res;
-
-	for ( unsigned ranki = 0; ranki < rank; ranki++ ) {
-		if ( content[i] == pattern.getSubtreeWildcard ( ) ) {
-			res.push_back ( DefaultSymbolType ( 'R' ) );
-			i++;
-		} else {
-			res.push_back ( DefaultSymbolType ( 'T' ) );
-
-			i = patternSubtreeJumpTable[i];
-		}
-	}
-
-	return res;
-}
-
-automaton::NPDA < > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedPattern < > & pattern ) {
-	automaton::NPDA < > res ( DefaultStateType ( 0 ), DefaultSymbolType ( 'T' ) );
-
-	for ( const common::ranked_symbol < > & symbol : pattern.getAlphabet ( ) ) {
-		if ( symbol == pattern.getSubtreeWildcard ( ) ) continue;
-
-		res.addInputSymbol ( DefaultSymbolType ( alphabet::RankedSymbol < > { symbol } ) );
-	}
-
-	res.setPushdownStoreAlphabet ( { DefaultSymbolType ( 'T' ), DefaultSymbolType ( 'R' ) } );
-
-	for ( const common::ranked_symbol < > & symbol : pattern.getAlphabet ( ) ) {
-		if ( symbol == pattern.getSubtreeWildcard ( ) ) continue;
-
-		res.addTransition ( DefaultStateType ( 0 ), DefaultSymbolType ( alphabet::RankedSymbol < > { symbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'T' ) ), DefaultStateType ( 0 ), ext::vector < DefaultSymbolType > ( ( size_t ) symbol.getRank ( ), DefaultSymbolType ( 'T' ) ) );
-	}
-
-	ext::vector < int > patternSubtreeJumpTable = tree::properties::SubtreeJumpTable::compute ( pattern );
-
-	int i = 1;
-
-	for ( const common::ranked_symbol < > & symbol : pattern.getContent ( ) ) {
-		res.addState ( DefaultStateType ( i ) );
-
-		if ( symbol == pattern.getSubtreeWildcard ( ) )
-			for ( const common::ranked_symbol < > & alphabetSymbol : pattern.getAlphabet ( ) ) {
-				if ( alphabetSymbol == pattern.getSubtreeWildcard ( ) ) continue;
-
-				if ( ( unsigned ) alphabetSymbol.getRank ( ) == 0 ) {
-					res.addTransition ( DefaultStateType ( i - 1 ), DefaultSymbolType ( alphabet::RankedSymbol < > { alphabetSymbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'T' ) ), DefaultStateType ( i - 1 ), ext::vector < DefaultSymbolType > { } );
-
-					res.addTransition ( DefaultStateType ( i - 1 ), DefaultSymbolType ( alphabet::RankedSymbol < > { alphabetSymbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'R' ) ), DefaultStateType ( i ), ext::vector < DefaultSymbolType > { } );
-				} else {
-					ext::vector < DefaultSymbolType > push ( ( unsigned ) alphabetSymbol.getRank ( ), DefaultSymbolType ( 'T' ) );
-					res.addTransition ( DefaultStateType ( i - 1 ), DefaultSymbolType ( alphabet::RankedSymbol < > { alphabetSymbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'T' ) ), DefaultStateType ( i - 1 ), push );
+auto ExactPatternMatchingAutomatonPrefixRankedTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::InputDrivenNPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, char, unsigned >, const tree::PrefixRankedTree < > & > ( ExactPatternMatchingAutomaton::construct );
 
-					push[ ( unsigned ) alphabetSymbol.getRank ( ) - 1] = DefaultSymbolType ( 'R' );
-					res.addTransition ( DefaultStateType ( i - 1 ), DefaultSymbolType ( alphabet::RankedSymbol < > { alphabetSymbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'R' ) ), DefaultStateType ( i - 1 ), push );
-				}
-			}
+auto ExactPatternMatchingAutomatonPrefixRankedPattern = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, DefaultEpsilonType, char, unsigned >, const tree::PrefixRankedPattern < > & > ( ExactPatternMatchingAutomaton::construct );
 
-		else
-			res.addTransition ( DefaultStateType ( i - 1 ), DefaultSymbolType ( alphabet::RankedSymbol < > { symbol } ), ext::vector < DefaultSymbolType > ( 1, DefaultSymbolType ( 'T' ) ), DefaultStateType ( i ), computeRHS ( pattern, patternSubtreeJumpTable, i - 1 ) );
-
-		i++;
-	}
-
-	res.addFinalState ( DefaultStateType ( i - 1 ) );
-	return res;
-}
-
-auto ExactPatternMatchingAutomatonPrefixRankedPattern = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NPDA < >, const tree::PrefixRankedPattern < > & > ( ExactPatternMatchingAutomaton::construct );
-
-automaton::InputDrivenNPDA < > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedBarTree < > & pattern ) {
-	return ExactSubtreeMatchingAutomaton::construct ( pattern );
-}
-
-auto ExactPatternMatchingAutomatonPrefixRankedBarTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::InputDrivenNPDA < >, const tree::PrefixRankedBarTree < > & > ( ExactPatternMatchingAutomaton::construct );
+auto ExactPatternMatchingAutomatonPrefixRankedBarTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::InputDrivenNPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, char, unsigned >, const tree::PrefixRankedBarTree < > & > ( ExactPatternMatchingAutomaton::construct );
 
 auto ExactPatternMatchingAutomatonPrefixRankedBarPattern = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::VisiblyPushdownNPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, char, unsigned >, const tree::PrefixRankedBarPattern < > & > ( ExactPatternMatchingAutomaton::construct );
 
-automaton::NFTA < > ExactPatternMatchingAutomaton::construct ( const tree::RankedTree < > & pattern ) {
-	return ExactSubtreeMatchingAutomaton::construct ( pattern );
-}
-
-auto ExactPatternMatchingAutomatonRankedTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NFTA < >, const tree::RankedTree < > & > ( ExactPatternMatchingAutomaton::construct );
-
-DefaultStateType constructRecursivePattern ( const ext::tree < common::ranked_symbol < > > & node, automaton::NFTA < > & res, const common::ranked_symbol < > & subtreeWildcard, const DefaultStateType & loopState, int & nextState ) {
-	if ( node.getData ( ) == subtreeWildcard ) {
-		DefaultStateType state = DefaultStateType ( nextState++ );
-		res.addState ( state );
-
-		for ( const common::ranked_symbol < > & symbol : res.getInputAlphabet ( ) ) {
-			ext::vector < DefaultStateType > states;
-			states.reserve ( ( size_t ) symbol.getRank ( ) );
-
-			for ( unsigned i = 0; i < ( unsigned ) symbol.getRank ( ); i++ )
-				states.push_back ( loopState );
-
-			res.addTransition ( symbol, states, state );
-		}
-
-		return state;
-	} else {
-		ext::vector < DefaultStateType > states;
-		states.reserve ( ( size_t ) node.getData ( ).getRank ( ) );
-
-		for ( const ext::tree < common::ranked_symbol < > > & child : node.getChildren ( ) )
-			states.push_back ( constructRecursivePattern ( child, res, subtreeWildcard, loopState, nextState ) );
-
-		DefaultStateType state = DefaultStateType ( nextState++ );
-		res.addState ( state );
-		res.addTransition ( node.getData ( ), states, state );
-		return state;
-	}
-}
-
-automaton::NFTA < > ExactPatternMatchingAutomaton::construct ( const tree::RankedPattern < > & pattern ) {
-	ext::set < common::ranked_symbol < > > alphabet = pattern.getAlphabet ( );
-
-	alphabet.erase ( pattern.getSubtreeWildcard ( ) );
-
-	automaton::NFTA < > res;
-	res.setInputAlphabet ( alphabet );
-
-	int nextState = 0;
-
-	DefaultStateType loopState = DefaultStateType ( nextState++ );
-	res.addState ( loopState );
-
-	for ( const common::ranked_symbol < > & symbol : res.getInputAlphabet ( ) ) {
-		ext::vector < DefaultStateType > states;
-		states.reserve ( ( size_t ) symbol.getRank ( ) );
-
-		for ( unsigned i = 0; i < ( unsigned ) symbol.getRank ( ); i++ )
-			states.push_back ( loopState );
-
-		res.addTransition ( symbol, states, loopState );
-	}
-
-	res.addFinalState ( constructRecursivePattern ( pattern.getContent ( ), res, pattern.getSubtreeWildcard ( ), loopState, nextState ) );
-	return res;
-}
+auto ExactPatternMatchingAutomatonRankedTree = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NFTA < DefaultSymbolType, DefaultRankType, unsigned >, const tree::RankedTree < > & > ( ExactPatternMatchingAutomaton::construct );
 
-auto ExactPatternMatchingAutomatonRankedPattern = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NFTA < >, const tree::RankedPattern < > & > ( ExactPatternMatchingAutomaton::construct );
+auto ExactPatternMatchingAutomatonRankedPattern = registration::AbstractRegister < ExactPatternMatchingAutomaton, automaton::NFTA < DefaultSymbolType, DefaultRankType, unsigned >, const tree::RankedPattern < > & > ( ExactPatternMatchingAutomaton::construct );
 
 } /* namespace exact */
 
diff --git a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h
index 62ef9efb8189a36c2fa315dce3bcf2dcd29a5130..fef8226221e4ce6d4fb5483e2a460feacdd771b0 100644
--- a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h
+++ b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h
@@ -8,9 +8,23 @@
 #ifndef _EXACT_PATTERN_MATCHING_AUTOMATON_H__
 #define _EXACT_PATTERN_MATCHING_AUTOMATON_H__
 
-#include <automaton/AutomatonFeatures.h>
-#include <tree/TreeFeatures.h>
+#include "ExactSubtreeMatchingAutomaton.h"
 
+#include <tree/properties/SubtreeJumpTable.h>
+
+#include <tree/ranked/RankedTree.h>
+#include <tree/ranked/RankedPattern.h>
+#include <tree/ranked/PrefixRankedTree.h>
+#include <tree/ranked/PrefixRankedPattern.h>
+#include <tree/ranked/PrefixRankedBarTree.h>
+#include <tree/ranked/PrefixRankedBarPattern.h>
+
+#include <automaton/PDA/InputDrivenNPDA.h>
+#include <automaton/PDA/VisiblyPushdownNPDA.h>
+#include <automaton/PDA/NPDA.h>
+#include <automaton/TA/NFTA.h>
+
+#include <common/ranked_symbol.hpp>
 #include <alphabet/BottomOfTheStackSymbol.h>
 
 namespace arbology {
@@ -23,16 +37,108 @@ public:
 	 * Performs conversion.
 	 * @return left regular grammar equivalent to source automaton.
 	 */
-	static automaton::NPDA < > construct ( const tree::PrefixRankedPattern < > & pattern );
-	static automaton::InputDrivenNPDA < > construct ( const tree::PrefixRankedTree < > & pattern );
+	template < class SymbolType, class RankType >
+	static automaton::NPDA < common::ranked_symbol < SymbolType, RankType >, DefaultEpsilonType, char, unsigned> construct ( const tree::PrefixRankedPattern < SymbolType, RankType > & pattern );
+
+	template < class SymbolType, class RankType >
+	static automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > construct ( const tree::PrefixRankedTree < SymbolType, RankType > & pattern );
+
 	template < class SymbolType, class RankType >
 	static automaton::VisiblyPushdownNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > construct ( const tree::PrefixRankedBarPattern < SymbolType, RankType > & pattern );
-	static automaton::InputDrivenNPDA < > construct ( const tree::PrefixRankedBarTree < > & pattern );
-	static automaton::NFTA < > construct ( const tree::RankedTree < > & pattern );
-	static automaton::NFTA < > construct ( const tree::RankedPattern < > & pattern );
+
+	template < class SymbolType, class RankType >
+	static automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > construct ( const tree::PrefixRankedBarTree < SymbolType, RankType > & pattern );
+
+	template < class SymbolType, class RankType >
+	static automaton::NFTA < SymbolType, RankType, unsigned > construct ( const tree::RankedTree < SymbolType, RankType > & pattern );
+
+	template < class SymbolType, class RankType >
+	static automaton::NFTA < SymbolType, RankType, unsigned > construct ( const tree::RankedPattern < SymbolType, RankType > & pattern );
 
 };
 
+template < class SymbolType, class RankType >
+ext::vector < char > computeRHS ( const tree::PrefixRankedPattern < SymbolType, RankType > & pattern, const ext::vector < int > & patternSubtreeJumpTable, int i ) {
+	const ext::vector < common::ranked_symbol < SymbolType, RankType > > & content = pattern.getContent ( );
+
+	unsigned rank = ( unsigned ) content [ i ].getRank ( );
+
+	i++;
+
+	ext::vector < char > res;
+
+	for ( unsigned ranki = 0; ranki < rank; ranki++ ) {
+		if ( content [ i ] == pattern.getSubtreeWildcard ( ) ) {
+			res.push_back ( 'R' );
+			i++;
+		} else {
+			res.push_back ( 'T' );
+
+			i = patternSubtreeJumpTable [ i ];
+		}
+	}
+
+	return res;
+}
+
+template < class SymbolType, class RankType >
+automaton::NPDA < common::ranked_symbol < SymbolType, RankType >, DefaultEpsilonType, char, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedPattern < SymbolType, RankType > & pattern ) {
+	automaton::NPDA < common::ranked_symbol < SymbolType, RankType >, DefaultEpsilonType, char, unsigned > res ( 0, 'T' );
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : pattern.getAlphabet ( ) ) {
+		if ( symbol == pattern.getSubtreeWildcard ( ) ) continue;
+
+		res.addInputSymbol ( symbol );
+	}
+
+	res.setPushdownStoreAlphabet ( { 'T', 'R' } );
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : pattern.getAlphabet ( ) ) {
+		if ( symbol == pattern.getSubtreeWildcard ( ) ) continue;
+
+		res.addTransition ( 0, symbol, ext::vector < char > ( 1, 'T' ), 0, ext::vector < char > ( ( size_t ) symbol.getRank ( ), 'T' ) );
+	}
+
+	ext::vector < int > patternSubtreeJumpTable = tree::properties::SubtreeJumpTable::compute ( pattern );
+
+	unsigned i = 1;
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : pattern.getContent ( ) ) {
+		res.addState ( i );
+
+		if ( symbol == pattern.getSubtreeWildcard ( ) )
+			for ( const common::ranked_symbol < SymbolType, RankType > & alphabetSymbol : pattern.getAlphabet ( ) ) {
+				if ( alphabetSymbol == pattern.getSubtreeWildcard ( ) ) continue;
+
+				if ( ( unsigned ) alphabetSymbol.getRank ( ) == 0 ) {
+					res.addTransition ( i - 1, alphabetSymbol, ext::vector < char > ( 1, 'T' ), i - 1, ext::vector < char > { } );
+
+					res.addTransition ( i - 1, alphabetSymbol, ext::vector < char > ( 1, 'R' ), i, ext::vector < char > { } );
+				} else {
+					ext::vector < char > push ( ( unsigned ) alphabetSymbol.getRank ( ), 'T' );
+					res.addTransition ( i - 1, alphabetSymbol, ext::vector < char > ( 1, 'T' ), i - 1, push );
+
+					push [ ( unsigned ) alphabetSymbol.getRank ( ) - 1 ] = 'R';
+					res.addTransition ( i - 1, alphabetSymbol, ext::vector < char > ( 1, 'R' ), i - 1, push );
+				}
+			}
+
+		else
+			res.addTransition ( i - 1, symbol, ext::vector < char > ( 1, 'T' ), i, computeRHS ( pattern, patternSubtreeJumpTable, i - 1 ) );
+
+		i++;
+	}
+
+	res.addFinalState ( i - 1 );
+
+	return res;
+}
+
+template < class SymbolType, class RankType >
+automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedTree < SymbolType, RankType > & pattern ) {
+	return ExactSubtreeMatchingAutomaton::construct ( pattern );
+}
+
 template < class SymbolType, class RankType >
 automaton::VisiblyPushdownNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedBarPattern < SymbolType, RankType > & pattern ) {
 	automaton::VisiblyPushdownNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > res ( alphabet::BottomOfTheStackSymbol::instance < char > ( ) );
@@ -99,6 +205,75 @@ automaton::VisiblyPushdownNPDA < common::ranked_symbol < SymbolType, RankType >,
 	return res;
 }
 
+template < class SymbolType, class RankType >
+automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::PrefixRankedBarTree < SymbolType, RankType > & pattern ) {
+	return ExactSubtreeMatchingAutomaton::construct ( pattern );
+}
+
+template < class SymbolType, class RankType >
+automaton::NFTA < SymbolType, RankType, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::RankedTree < SymbolType, RankType > & pattern ) {
+	return ExactSubtreeMatchingAutomaton::construct ( pattern );
+}
+
+template < class SymbolType, class RankType >
+unsigned constructRecursivePattern ( const ext::tree < common::ranked_symbol < SymbolType, RankType > > & node, automaton::NFTA < SymbolType, RankType, unsigned > & res, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, unsigned loopState, unsigned & nextState ) {
+	if ( node.getData ( ) == subtreeWildcard ) {
+		unsigned state = nextState++;
+		res.addState ( state );
+
+		for ( const common::ranked_symbol < SymbolType, RankType > & symbol : res.getInputAlphabet ( ) ) {
+			ext::vector < unsigned > states;
+			states.reserve ( ( size_t ) symbol.getRank ( ) );
+
+			for ( unsigned i = 0; i < ( unsigned ) symbol.getRank ( ); i++ )
+				states.push_back ( loopState );
+
+			res.addTransition ( symbol, states, state );
+		}
+
+		return state;
+	} else {
+		ext::vector < unsigned > states;
+		states.reserve ( ( size_t ) node.getData ( ).getRank ( ) );
+
+		for ( const ext::tree < common::ranked_symbol < SymbolType, RankType > > & child : node.getChildren ( ) )
+			states.push_back ( constructRecursivePattern ( child, res, subtreeWildcard, loopState, nextState ) );
+
+		unsigned state = nextState++;
+		res.addState ( state );
+		res.addTransition ( node.getData ( ), states, state );
+		return state;
+	}
+}
+
+template < class SymbolType, class RankType >
+automaton::NFTA < SymbolType, RankType, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::RankedPattern < SymbolType, RankType > & pattern ) {
+	ext::set < common::ranked_symbol < SymbolType, RankType> > alphabet = pattern.getAlphabet ( );
+
+	alphabet.erase ( pattern.getSubtreeWildcard ( ) );
+
+	automaton::NFTA < SymbolType, RankType, unsigned > res;
+	res.setInputAlphabet ( alphabet );
+
+	unsigned nextState = 0;
+
+	unsigned loopState = nextState++;
+	res.addState ( loopState );
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : res.getInputAlphabet ( ) ) {
+		ext::vector < unsigned > states;
+		states.reserve ( ( size_t ) symbol.getRank ( ) );
+
+		for ( unsigned i = 0; i < ( unsigned ) symbol.getRank ( ); i++ )
+			states.push_back ( loopState );
+
+		res.addTransition ( symbol, states, loopState );
+	}
+
+	res.addFinalState ( constructRecursivePattern ( pattern.getContent ( ), res, pattern.getSubtreeWildcard ( ), loopState, nextState ) );
+	return res;
+}
+
 } /* namespace exact */
 
 } /* namespace arbology */