From 9490756c9b8337fc84097f56880470b09592cc7a Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Thu, 7 Sep 2017 18:57:53 +0200
Subject: [PATCH] templatize construction of (Nonlinear)TreePatternAutomaton

---
 aarbology2/src/aarbology.cpp                  |  10 +-
 .../ExactNonlinearTreePatternAutomaton.cpp    | 117 +--------------
 .../ExactNonlinearTreePatternAutomaton.h      | 133 +++++++++++++++++-
 .../exact/ExactTreePatternAutomaton.cpp       |  48 +------
 .../exact/ExactTreePatternAutomaton.h         |  55 +++++++-
 5 files changed, 185 insertions(+), 178 deletions(-)

diff --git a/aarbology2/src/aarbology.cpp b/aarbology2/src/aarbology.cpp
index 58db9c350d..cb0daa0d30 100644
--- a/aarbology2/src/aarbology.cpp
+++ b/aarbology2/src/aarbology.cpp
@@ -229,8 +229,8 @@ int main ( int argc, char * argv[] ) {
 
 			alib::XmlDataFactory::toStdout ( res );
 		} else if ( algorithm.getValue ( ) == "exactTreePatternAutomaton" ) {
-			tree::Tree subject = alib::XmlDataFactory::fromTokens ( std::move ( sax::FromXMLParserHelper::parseInput(true, subjectInput).front ( ) ) );
-			DefaultSymbolType subtreeWildcard = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(subtreeWildcardInput) );
+			tree::RankedTreeWrapper subject = alib::XmlDataFactory::fromTokens ( std::move ( sax::FromXMLParserHelper::parseInput(true, subjectInput).front ( ) ) );
+			common::ranked_symbol < DefaultSymbolType, DefaultRankType > subtreeWildcard = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(subtreeWildcardInput) );
 
 			measurements::end ( );
 			measurements::start ( "Algorithm", measurements::Type::MAIN );
@@ -242,9 +242,9 @@ int main ( int argc, char * argv[] ) {
 
 			alib::XmlDataFactory::toStdout ( res );
 		} else if ( algorithm.getValue ( ) == "exactNonlinearTreePatternAutomaton" ) {
-			tree::Tree subject = alib::XmlDataFactory::fromTokens ( std::move ( sax::FromXMLParserHelper::parseInput(true, subjectInput).front ( ) ) );
-			DefaultSymbolType subtreeWildcard = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(subtreeWildcardInput) );
-			ext::set < DefaultSymbolType > nonlinearVariables = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(nonlinearVariablesInput) );
+			tree::RankedTreeWrapper subject = alib::XmlDataFactory::fromTokens ( std::move ( sax::FromXMLParserHelper::parseInput(true, subjectInput).front ( ) ) );
+			common::ranked_symbol < DefaultSymbolType, DefaultRankType > subtreeWildcard = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(subtreeWildcardInput) );
+			ext::set < common::ranked_symbol < DefaultSymbolType, DefaultRankType > > nonlinearVariables = alib::XmlDataFactory::fromTokens ( sax::FromXMLParserHelper::parseInput(nonlinearVariablesInput) );
 
 			measurements::end ( );
 			measurements::start ( "Algorithm", measurements::Type::MAIN );
diff --git a/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.cpp b/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.cpp
index 1d5e295ed8..4430015eb4 100644
--- a/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.cpp
+++ b/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.cpp
@@ -6,130 +6,17 @@
  */
 
 #include "ExactNonlinearTreePatternAutomaton.h"
-#include <tree/Tree.h>
-#include <tree/ranked/PrefixRankedTree.h>
-#include <automaton/Automaton.h>
-#include <automaton/PDA/InputDrivenNPDA.h>
-
-#include <tree/properties/ExactSubtreeRepeatsNaive.h>
-
-#include <deque>
-#include <alphabet/RankedSymbol.h>
 #include <registration/AlgoRegistration.hpp>
 
 namespace arbology {
 
 namespace exact {
 
-automaton::Automaton ExactNonlinearTreePatternAutomaton::construct ( const tree::Tree & tree, const DefaultSymbolType & subtreeWildcard, const ext::set < DefaultSymbolType > & nonlinearVariables ) {
+automaton::Automaton ExactNonlinearTreePatternAutomaton::construct ( const tree::RankedTreeWrapper & tree, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > & subtreeWildcard, const ext::set < common::ranked_symbol < DefaultSymbolType, DefaultRankType > > & nonlinearVariables ) {
 	return dispatch ( tree.getData ( ), subtreeWildcard, nonlinearVariables );
 }
 
-void ExactNonlinearTreePatternAutomaton::constructTail ( automaton::InputDrivenNPDA < > & res, const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const DefaultSymbolType & currentNonlinearVariable, const ext::set < DefaultSymbolType > & nonlinearVariables, unsigned subtreeId, ext::vector < common::ranked_symbol < > >::const_iterator rankedSymbolsIter, int i, ext::vector < common::ranked_symbol < unsigned, DefaultRankType > >::const_iterator subtreeRepeatsIter ) {
-	ext::deque < std::pair < size_t, int > > subtreeJumps;
-	ext::deque < unsigned > subtreeRepeatsStack;
-
-	for (++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++i; rankedSymbolsIter != tree.getContent ( ).end ( ); ++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++i ) {
-		DefaultSymbolType symbol ( alphabet::RankedSymbol < > { * rankedSymbolsIter } );
-		subtreeJumps.push_back ( std::make_pair ( ( size_t ) rankedSymbolsIter->getRank ( ), i - 1 ) );
-		subtreeRepeatsStack.push_back ( subtreeRepeatsIter->getSymbol ( ) );
-
-		DefaultStateType currentState = DefaultStateType ( i, subtreeId );
-		DefaultStateType previousState = DefaultStateType ( i - 1, subtreeId );
-
-		res.addState ( currentState );
-
-		res.addTransition ( previousState, symbol, currentState );
-
-		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
-			DefaultStateType jumpSource = DefaultStateType ( subtreeJumps.back ( ).second, subtreeId );
-			res.addTransition ( jumpSource, subtreeWildcard, currentState );
-
-			for ( const DefaultSymbolType & nonlinearVariable : nonlinearVariables )
-				if ( nonlinearVariable != currentNonlinearVariable || subtreeId == subtreeRepeatsStack.back ( ) )
-					res.addTransition ( jumpSource, nonlinearVariable, currentState );
-
-			if ( subtreeJumps.size ( ) ) {
-				subtreeJumps.pop_back ( );
-				subtreeRepeatsStack.pop_back ( );
-			}
-		}
-
-		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
-	}
-}
-
-automaton::InputDrivenNPDA < > ExactNonlinearTreePatternAutomaton::constructInternal ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const DefaultSymbolType & currentNonlinearVariable, const ext::set < DefaultSymbolType > & nonlinearVariables ) {
-	DefaultSymbolType S = DefaultSymbolType ( 'S' );
-	automaton::InputDrivenNPDA < > res ( DefaultStateType ( 0 ), S );
-
-	tree::PrefixRankedTree < unsigned, DefaultRankType > repeats = tree::properties::ExactSubtreeRepeatsNaive::repeats ( tree );
-
-	for ( const common::ranked_symbol < > & rankedSymbol : tree.getAlphabet ( ) ) {
-		DefaultSymbolType symbol ( alphabet::RankedSymbol < > { rankedSymbol } );
-		res.addInputSymbol ( symbol );
-		res.setPushdownStoreOperation ( symbol, ext::vector < DefaultSymbolType > ( 1, S ), ext::vector < DefaultSymbolType > ( ( size_t ) rankedSymbol.getRank ( ), S ) );
-	}
-
-	res.addInputSymbol ( subtreeWildcard );
-	res.setPushdownStoreOperation ( subtreeWildcard, ext::vector < DefaultSymbolType > ( 1, S ), ext::vector < DefaultSymbolType > { } );
-
-	for ( const DefaultSymbolType & nonlinearVariable : nonlinearVariables ) {
-		res.addInputSymbol ( nonlinearVariable );
-		res.setPushdownStoreOperation ( nonlinearVariable, ext::vector < DefaultSymbolType > ( 1, S ), ext::vector < DefaultSymbolType > { } );
-	}
-
-	int i = 1;
-	ext::deque < std::pair < size_t, int > > subtreeJumps;
-	ext::deque < unsigned > subtreeRepeatsStack;
-
-	ext::vector < common::ranked_symbol < > >::const_iterator rankedSymbolsIter;
-	ext::vector < common::ranked_symbol < unsigned, DefaultRankType > >::const_iterator subtreeRepeatsIter;
-	for ( rankedSymbolsIter = tree.getContent ( ).begin(), subtreeRepeatsIter = repeats.getContent ( ).begin ( ); rankedSymbolsIter != tree.getContent ( ).end ( ); ++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++ i ) {
-		DefaultSymbolType symbol ( alphabet::RankedSymbol < > { * rankedSymbolsIter } );
-		subtreeJumps.push_back ( std::make_pair ( ( size_t ) rankedSymbolsIter->getRank ( ), i - 1 ) );
-		subtreeRepeatsStack.push_back ( subtreeRepeatsIter->getSymbol ( ) );
-
-		DefaultStateType currentState = DefaultStateType ( i );
-		DefaultStateType previousState = DefaultStateType ( i - 1 );
-
-		res.addState ( currentState );
-
-		res.addTransition ( previousState, symbol, currentState );
-		res.addTransition ( res.getInitialState ( ), std::move ( symbol ), currentState );
-
-		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
-			DefaultStateType jumpSource = DefaultStateType ( subtreeJumps.back ( ).second );
-			res.addTransition ( jumpSource, subtreeWildcard, currentState );
-
-			for ( const DefaultSymbolType & nonlinearVariable : nonlinearVariables )
-				if ( nonlinearVariable != currentNonlinearVariable )
-					res.addTransition ( jumpSource, nonlinearVariable, currentState );
-				else {
-					unsigned subtreeId = subtreeRepeatsStack.back ( );
-					DefaultStateType targetState = DefaultStateType ( i, subtreeId );
-
-					res.addState ( targetState );
-					res.addTransition ( jumpSource, nonlinearVariable, targetState );
-
-					constructTail ( res, tree, subtreeWildcard, currentNonlinearVariable, nonlinearVariables, subtreeId, rankedSymbolsIter, i, subtreeRepeatsIter );
-				}
-
-			subtreeJumps.pop_back ( );
-			subtreeRepeatsStack.pop_back ( );
-		}
-
-		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
-	}
-
-	return res;
-}
-
-automaton::InputDrivenNPDA < > ExactNonlinearTreePatternAutomaton::construct ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const ext::set < DefaultSymbolType > & nonlinearVariables ) {
-	return constructInternal ( tree, subtreeWildcard, * nonlinearVariables.begin ( ), nonlinearVariables );
-}
-
-auto ExactNonlinearTreePatternAutomatonPrefixRankedTree = registration::OverloadRegister < ExactNonlinearTreePatternAutomaton, automaton::InputDrivenNPDA < >, tree::PrefixRankedTree < > > ( ExactNonlinearTreePatternAutomaton::construct );
+auto ExactNonlinearTreePatternAutomatonPrefixRankedTree = registration::OverloadRegister < ExactNonlinearTreePatternAutomaton, automaton::InputDrivenNPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, char, ext::pair < unsigned, unsigned > >, tree::PrefixRankedTree < > > ( ExactNonlinearTreePatternAutomaton::construct );
 
 } /* namespace exact */
 
diff --git a/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.h b/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.h
index 735a72e80f..92c81515d6 100644
--- a/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.h
+++ b/alib2algo/src/arbology/exact/ExactNonlinearTreePatternAutomaton.h
@@ -8,33 +8,152 @@
 #ifndef _EXACT_NONLINEAR_TREE_PATTERN_AUTOMATON_H__
 #define _EXACT_NONLINEAR_TREE_PATTERN_AUTOMATON_H__
 
-#include <automaton/AutomatonFeatures.h>
-#include <tree/TreeFeatures.h>
+#include <primitive/Unsigned.h>
+#include <primitive/Character.h>
+#include <container/ObjectsPair.h>
+
+#include <tree/RankedTreeWrapper.h>
 #include <core/multipleDispatch.hpp>
 #include <alphabet/Symbol.h>
 #include <alphabet/RankedSymbol.h>
 
+#include <tree/ranked/PrefixRankedTree.h>
+#include <automaton/Automaton.h>
+#include <automaton/PDA/InputDrivenNPDA.h>
+
+#include <tree/properties/ExactSubtreeRepeatsNaive.h>
+
+#include <deque>
 #include <vector>
 
 namespace arbology {
 
 namespace exact {
 
-class ExactNonlinearTreePatternAutomaton : public alib::SingleDispatch < ExactNonlinearTreePatternAutomaton, automaton::Automaton, const tree::TreeBase &, const DefaultSymbolType &, const ext::set < DefaultSymbolType > & > {
-	static automaton::InputDrivenNPDA < > constructInternal ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const DefaultSymbolType & currentNonlinearVariable, const ext::set < DefaultSymbolType > & nonlinearVariables );
+class ExactNonlinearTreePatternAutomaton : public alib::SingleDispatch < ExactNonlinearTreePatternAutomaton, automaton::Automaton, const tree::RankedTreeBase &, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > &, const ext::set < common::ranked_symbol < DefaultSymbolType, DefaultRankType > > & > {
+	template < class SymbolType, class RankType >
+	static automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > constructInternal ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const common::ranked_symbol < SymbolType, RankType > & currentNonlinearVariable, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables );
 
-	static void constructTail ( automaton::InputDrivenNPDA < > & res, const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const DefaultSymbolType & currentNonlinearVariable, const ext::set < DefaultSymbolType > & nonlinearVariables, unsigned subtreeId, ext::vector < common::ranked_symbol < > >::const_iterator rankedSymbolsIter, int i, ext::vector < common::ranked_symbol < unsigned, DefaultRankType > >::const_iterator subtreeRepeatsIter );
+	template < class SymbolType, class RankType >
+	static void constructTail ( automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > & res, const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const common::ranked_symbol < SymbolType, RankType > & currentNonlinearVariable, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables, unsigned subtreeId, typename ext::vector < common::ranked_symbol < SymbolType, RankType > >::const_iterator rankedSymbolsIter, int i, typename ext::vector < common::ranked_symbol < unsigned, RankType > >::const_iterator subtreeRepeatsIter );
 
 public:
 	/**
 	 * Performs conversion.
 	 * @return left regular grammar equivalent to source automaton.
 	 */
-	static automaton::Automaton construct ( const tree::Tree & tree, const DefaultSymbolType & subtreeWildcard, const ext::set < DefaultSymbolType > & nonlinearVariables );
+	static automaton::Automaton construct ( const tree::RankedTreeWrapper & tree, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > & subtreeWildcard, const ext::set < common::ranked_symbol < DefaultSymbolType, DefaultRankType > > & nonlinearVariables );
 
-	static automaton::InputDrivenNPDA < > construct ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard, const ext::set < DefaultSymbolType > & nonlinearVariables );
+	template < class SymbolType, class RankType >
+	static automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > construct ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables );
 };
 
+template < class SymbolType, class RankType >
+void ExactNonlinearTreePatternAutomaton::constructTail ( automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > & res, const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const common::ranked_symbol < SymbolType, RankType > & currentNonlinearVariable, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables, unsigned subtreeId, typename ext::vector < common::ranked_symbol < SymbolType, RankType > >::const_iterator rankedSymbolsIter, int i, typename ext::vector < common::ranked_symbol < unsigned, RankType > >::const_iterator subtreeRepeatsIter ) {
+	ext::deque < std::pair < size_t, int > > subtreeJumps;
+	ext::deque < unsigned > subtreeRepeatsStack;
+
+	for (++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++i; rankedSymbolsIter != tree.getContent ( ).end ( ); ++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++i ) {
+		common::ranked_symbol < SymbolType, RankType > symbol = * rankedSymbolsIter;
+		subtreeJumps.push_back ( std::make_pair ( ( size_t ) symbol.getRank ( ), i - 1 ) );
+		subtreeRepeatsStack.push_back ( subtreeRepeatsIter->getSymbol ( ) );
+
+		ext::pair < unsigned, unsigned > currentState = ext::make_pair ( i, subtreeId + 1 );
+		ext::pair < unsigned, unsigned > previousState = ext::make_pair ( i - 1, subtreeId + 1 );
+
+		res.addState ( currentState );
+
+		res.addTransition ( previousState, std::move ( symbol ), currentState );
+
+		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
+			ext::pair < unsigned, unsigned > jumpSource = ext::make_pair ( subtreeJumps.back ( ).second, subtreeId + 1 );
+			res.addTransition ( jumpSource, subtreeWildcard, currentState );
+
+			for ( const common::ranked_symbol < SymbolType, RankType > & nonlinearVariable : nonlinearVariables )
+				if ( nonlinearVariable != currentNonlinearVariable || subtreeId == subtreeRepeatsStack.back ( ) )
+					res.addTransition ( jumpSource, nonlinearVariable, currentState );
+
+			if ( subtreeJumps.size ( ) ) {
+				subtreeJumps.pop_back ( );
+				subtreeRepeatsStack.pop_back ( );
+			}
+		}
+
+		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
+	}
+}
+
+template < class SymbolType, class RankType >
+automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > ExactNonlinearTreePatternAutomaton::constructInternal ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const common::ranked_symbol < SymbolType, RankType > & currentNonlinearVariable, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables ) {
+	char S = alphabet::SubtreeWildcardSymbol::instance < char > ( );
+	automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > res ( ext::make_pair ( 0u, 0u ), S );
+
+	tree::PrefixRankedTree < unsigned, DefaultRankType > repeats = tree::properties::ExactSubtreeRepeatsNaive::repeats ( tree );
+
+	for ( const common::ranked_symbol < > & symbol : tree.getAlphabet ( ) ) {
+		res.addInputSymbol ( symbol );
+		res.setPushdownStoreOperation ( symbol, ext::vector < char > ( 1, S ), ext::vector < char > ( ( size_t ) symbol.getRank ( ), S ) );
+	}
+
+	res.addInputSymbol ( subtreeWildcard );
+	res.setPushdownStoreOperation ( subtreeWildcard, ext::vector < char > ( 1, S ), ext::vector < char > { } );
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & nonlinearVariable : nonlinearVariables ) {
+		res.addInputSymbol ( nonlinearVariable );
+		res.setPushdownStoreOperation ( nonlinearVariable, ext::vector < char > ( 1, S ), ext::vector < char > { } );
+	}
+
+	unsigned i = 1;
+	ext::deque < std::pair < size_t, int > > subtreeJumps;
+	ext::deque < unsigned > subtreeRepeatsStack;
+
+	ext::vector < common::ranked_symbol < > >::const_iterator rankedSymbolsIter;
+	ext::vector < common::ranked_symbol < unsigned, DefaultRankType > >::const_iterator subtreeRepeatsIter;
+	for ( rankedSymbolsIter = tree.getContent ( ).begin(), subtreeRepeatsIter = repeats.getContent ( ).begin ( ); rankedSymbolsIter != tree.getContent ( ).end ( ); ++ rankedSymbolsIter, ++ subtreeRepeatsIter, ++ i ) {
+		common::ranked_symbol < SymbolType, RankType > symbol = * rankedSymbolsIter;
+		subtreeJumps.push_back ( std::make_pair ( ( size_t ) symbol.getRank ( ), i - 1 ) );
+		subtreeRepeatsStack.push_back ( subtreeRepeatsIter->getSymbol ( ) );
+
+		ext::pair < unsigned, unsigned > currentState = ext::make_pair ( i, 0u );
+		ext::pair < unsigned, unsigned > previousState = ext::make_pair ( i - 1, 0u );
+
+		res.addState ( currentState );
+
+		res.addTransition ( previousState, symbol, currentState );
+		res.addTransition ( res.getInitialState ( ), std::move ( symbol ), currentState );
+
+		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
+			ext::pair < unsigned, unsigned > jumpSource = ext::make_pair ( subtreeJumps.back ( ).second, 0u );
+			res.addTransition ( jumpSource, subtreeWildcard, currentState );
+
+			for ( const common::ranked_symbol < SymbolType, RankType > & nonlinearVariable : nonlinearVariables )
+				if ( nonlinearVariable != currentNonlinearVariable )
+					res.addTransition ( jumpSource, nonlinearVariable, currentState );
+				else {
+					unsigned subtreeId = subtreeRepeatsStack.back ( );
+					ext::pair < unsigned, unsigned > targetState = ext::make_pair ( i, subtreeId + 1 );
+
+					res.addState ( targetState );
+					res.addTransition ( jumpSource, nonlinearVariable, targetState );
+
+					constructTail ( res, tree, subtreeWildcard, currentNonlinearVariable, nonlinearVariables, subtreeId, rankedSymbolsIter, i, subtreeRepeatsIter );
+				}
+
+			subtreeJumps.pop_back ( );
+			subtreeRepeatsStack.pop_back ( );
+		}
+
+		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
+	}
+
+	return res;
+}
+
+template < class SymbolType, class RankType >
+automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, ext::pair < unsigned, unsigned > > ExactNonlinearTreePatternAutomaton::construct ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard, const ext::set < common::ranked_symbol < SymbolType, RankType > > & nonlinearVariables ) {
+	return constructInternal ( tree, subtreeWildcard, * nonlinearVariables.begin ( ), nonlinearVariables );
+}
+
 } /* namespace exact */
 
 } /* namespace arbology */
diff --git a/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.cpp b/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.cpp
index 0cf2e2d03c..cf84e4d631 100644
--- a/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.cpp
+++ b/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.cpp
@@ -6,61 +6,17 @@
  */
 
 #include "ExactTreePatternAutomaton.h"
-#include <alphabet/SubtreeWildcardSymbol.h>
-#include <tree/Tree.h>
-#include <tree/ranked/PrefixRankedTree.h>
-#include <automaton/Automaton.h>
-#include <automaton/PDA/InputDrivenNPDA.h>
-
-#include <deque>
 #include <registration/AlgoRegistration.hpp>
 
 namespace arbology {
 
 namespace exact {
 
-automaton::Automaton ExactTreePatternAutomaton::construct ( const tree::Tree & tree, const DefaultSymbolType & subtreeWildcard ) {
+automaton::Automaton ExactTreePatternAutomaton::construct ( const tree::RankedTreeWrapper & tree, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > & subtreeWildcard ) {
 	return dispatch ( tree.getData ( ), subtreeWildcard );
 }
 
-automaton::InputDrivenNPDA < > ExactTreePatternAutomaton::construct ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard ) {
-	DefaultSymbolType S = DefaultSymbolType ( 'S' );
-	automaton::InputDrivenNPDA < > res ( DefaultStateType ( 0 ), S );
-
-	for ( const common::ranked_symbol < > & rankedSymbol : tree.getAlphabet ( ) ) {
-		DefaultSymbolType symbol ( alphabet::RankedSymbol < > { rankedSymbol } );
-		res.addInputSymbol ( symbol );
-		res.setPushdownStoreOperation ( symbol, ext::vector < DefaultSymbolType > ( 1, S ), ext::vector < DefaultSymbolType > ( ( size_t ) rankedSymbol.getRank ( ), S ) );
-	}
-
-	res.addInputSymbol ( subtreeWildcard );
-	res.setPushdownStoreOperation ( subtreeWildcard, ext::vector < DefaultSymbolType > ( 1, S ), ext::vector < DefaultSymbolType > { } );
-
-	int i = 1;
-	ext::deque < std::pair < size_t, int > > subtreeJumps;
-
-	for ( const common::ranked_symbol < > & rankedSymbol : tree.getContent ( ) ) {
-		DefaultSymbolType symbol ( alphabet::RankedSymbol < > { rankedSymbol } );
-		subtreeJumps.push_back ( std::make_pair ( ( size_t ) rankedSymbol.getRank ( ), i - 1 ) );
-
-		res.addState ( DefaultStateType ( i ) );
-		res.addTransition ( DefaultStateType ( i - 1 ), symbol, DefaultStateType ( i ) );
-		res.addTransition ( DefaultStateType ( 0 ), std::move ( symbol ), DefaultStateType ( i ) );
-
-		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
-			res.addTransition ( DefaultStateType ( subtreeJumps.back ( ).second ), subtreeWildcard, DefaultStateType ( i ) );
-			subtreeJumps.pop_back ( );
-		}
-
-		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
-
-		i++;
-	}
-
-	return res;
-}
-
-auto ExactTreePatternAutomatonPrefixRankedTree = registration::OverloadRegister < ExactTreePatternAutomaton, automaton::InputDrivenNPDA < >, tree::PrefixRankedTree < > > ( ExactTreePatternAutomaton::construct );
+auto ExactTreePatternAutomatonPrefixRankedTree = registration::OverloadRegister < ExactTreePatternAutomaton, automaton::InputDrivenNPDA < common::ranked_symbol < DefaultSymbolType, DefaultRankType >, char, unsigned >, tree::PrefixRankedTree < > > ( ExactTreePatternAutomaton::construct );
 
 } /* namespace exact */
 
diff --git a/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.h b/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.h
index d0db79a74b..a0d413886b 100644
--- a/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.h
+++ b/alib2algo/src/arbology/exact/ExactTreePatternAutomaton.h
@@ -8,26 +8,71 @@
 #ifndef _EXACT_TREE_PATTERN_AUTOMATON_H__
 #define _EXACT_TREE_PATTERN_AUTOMATON_H__
 
-#include <automaton/AutomatonFeatures.h>
-#include <tree/TreeFeatures.h>
+#include <alphabet/SubtreeWildcardSymbol.h>
+#include <tree/RankedTreeWrapper.h>
+#include <tree/ranked/PrefixRankedTree.h>
+#include <automaton/Automaton.h>
+#include <automaton/PDA/InputDrivenNPDA.h>
+
+#include <deque>
+#include <primitive/Character.h>
+#include <primitive/Unsigned.h>
+
 #include <core/multipleDispatch.hpp>
 
 namespace arbology {
 
 namespace exact {
 
-class ExactTreePatternAutomaton : public alib::SingleDispatch < ExactTreePatternAutomaton, automaton::Automaton, const tree::TreeBase &, const DefaultSymbolType & > {
+class ExactTreePatternAutomaton : public alib::SingleDispatch < ExactTreePatternAutomaton, automaton::Automaton, const tree::RankedTreeBase &, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > & > {
 public:
 	/**
 	 * Performs conversion.
 	 * @return left regular grammar equivalent to source automaton.
 	 */
-	static automaton::Automaton construct ( const tree::Tree & tree, const DefaultSymbolType & subtreeWildcard );
+	static automaton::Automaton construct ( const tree::RankedTreeWrapper & tree, const common::ranked_symbol < DefaultSymbolType, DefaultRankType > & subtreeWildcard );
 
-	static automaton::InputDrivenNPDA < > construct ( const tree::PrefixRankedTree < > & tree, const DefaultSymbolType & subtreeWildcard );
+	template < class SymbolType, class RankType >
+	static automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > construct ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard );
 
 };
 
+template < class SymbolType, class RankType >
+automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > ExactTreePatternAutomaton::construct ( const tree::PrefixRankedTree < SymbolType, RankType > & tree, const common::ranked_symbol < SymbolType, RankType > & subtreeWildcard ) {
+	char S = alphabet::SubtreeWildcardSymbol::instance < char > ( );
+	automaton::InputDrivenNPDA < common::ranked_symbol < SymbolType, RankType >, char, unsigned > res ( 0, S );
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : tree.getAlphabet ( ) ) {
+		res.addInputSymbol ( symbol );
+		res.setPushdownStoreOperation ( symbol, ext::vector < char > ( 1, S ), ext::vector < char > ( ( size_t ) symbol.getRank ( ), S ) );
+	}
+
+	res.addInputSymbol ( subtreeWildcard );
+	res.setPushdownStoreOperation ( subtreeWildcard, ext::vector < char > ( 1, S ), ext::vector < char > { } );
+
+	unsigned i = 1;
+	ext::deque < std::pair < size_t, unsigned > > subtreeJumps;
+
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : tree.getContent ( ) ) {
+		subtreeJumps.push_back ( std::make_pair ( ( size_t ) symbol.getRank ( ), i - 1 ) );
+
+		res.addState ( i );
+		res.addTransition ( i - 1, symbol, i );
+		res.addTransition ( 0, std::move ( symbol ), i );
+
+		while ( subtreeJumps.size ( ) && subtreeJumps.back ( ).first == 0 ) {
+			res.addTransition ( subtreeJumps.back ( ).second, subtreeWildcard, i );
+			subtreeJumps.pop_back ( );
+		}
+
+		if ( subtreeJumps.size ( ) ) subtreeJumps.back ( ).first--;
+
+		i++;
+	}
+
+	return res;
+}
+
 } /* namespace exact */
 
 } /* namespace arbology */
-- 
GitLab