diff --git a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..45b6f6aef4b036aa32b369c8478fe0cdc8b700f5
--- /dev/null
+++ b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.cpp
@@ -0,0 +1,93 @@
+/*
+ * RandomAutomatonFactory.cpp
+ *
+ *  Created on: 27. 3. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#include "RandomTreeAutomatonFactory.h"
+#include <registration/AlgoRegistration.hpp>
+
+namespace automaton {
+
+namespace generate {
+
+automaton::NFTA < std::string, DefaultRankType, unsigned > RandomTreeAutomatonFactory::generateNFTA( size_t statesCount, size_t alphabetSize, size_t maxRank, bool randomizedAlphabet, double density ) {
+	if(alphabetSize > 26)
+		throw exception::CommonException("Too big alphabet.");
+
+	if(alphabetSize < 1)
+		throw exception::CommonException("Too small alphabet.");
+
+	ext::deque < std::string > alphabet;
+	for(char i = 'a'; i <= 'z'; i++)
+		alphabet.push_back ( std::string ( 1, i ) );
+
+	if(randomizedAlphabet)
+		shuffle(alphabet.begin(), alphabet.end(), ext::random_devices::semirandom);
+
+	alphabet.resize ( alphabetSize );
+
+	ext::deque < common::ranked_symbol < std::string, DefaultRankType > > rankedAlphabet;
+
+	for ( std::string && symbol : ext::make_mover ( alphabet ) ) {
+		rankedAlphabet.push_back ( common::ranked_symbol < std::string, DefaultRankType > ( std::move ( symbol ), ext::random_devices::semirandom() % ( maxRank + 1 ) ) );
+	}
+
+	bool containsNullary = false;
+	for ( common::ranked_symbol < std::string, DefaultRankType > & rankedSymbol : rankedAlphabet ) {
+		containsNullary |= rankedSymbol.getRank ( ) == 0;
+	}
+
+	if ( ! containsNullary ) {
+		int c = ext::random_devices::semirandom() % rankedAlphabet.size ( );
+		rankedAlphabet [ c ] = common::ranked_symbol ( std::move ( rankedAlphabet [ c ].getSymbol ( ) ), 0u );
+	}
+
+	return RandomTreeAutomatonFactory::LeslieConnectedNFTA( statesCount, rankedAlphabet, density );
+}
+
+unsigned RandomTreeAutomatonFactory::ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
+	i ++;
+	for( size_t j = 0; j < VStates.size ( ); j++ ) {
+		if( VStates[ j ] == true )
+			i --;
+
+		if( i == 0 )
+			return i;
+	}
+	throw std::logic_error ( "Not enough states in deque of visited states" );
+}
+
+unsigned RandomTreeAutomatonFactory::ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
+	i ++;
+	for( size_t j = 0; j < VStates.size ( ); j++ ) {
+		if( VStates[ j ] == false )
+			i --;
+
+		if( i == 0 )
+			return j;
+	}
+	throw std::logic_error ( "Not enough states in deque of visited states" );
+}
+
+auto GenerateNFTA1 = registration::AbstractRegister < RandomTreeAutomatonFactory, automaton::NFTA < DefaultSymbolType, DefaultRankType, unsigned >, size_t, const ext::set < common::ranked_symbol < DefaultSymbolType, DefaultRankType > > &, double > ( RandomTreeAutomatonFactory::generateNFTA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabet", "density" ).setDocumentation (
+"Generates a random finite automaton.\n\
+@param statesCount number of states in the generated automaton\n\
+@param alphabet Input alphabet of the automaton\n\
+@param density density of the transition function\n\
+@return random nondeterministic finite automaton" );
+
+auto GenerateNFTA2 = registration::AbstractRegister < RandomTreeAutomatonFactory, automaton::NFTA < std::string, DefaultRankType, unsigned >, size_t, size_t, size_t, bool, double > ( RandomTreeAutomatonFactory::generateNFTA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "maxRank", "randomizedAlphabet", "density" ).setDocumentation (
+"Generates a random finite automaton.\n\
+\n\
+@param statesCount number of states in the generated automaton\n\
+@param alphabetSize size of the alphabet (1-26)\n\
+@param maxRank the maximum rank in the randomly generated alphabet\n\
+@param randomizedAlphabet selects random symbols from a-z range if true\n\
+@param density density of the transition function (0-1). 1 means every possible transition is created\n\
+@return random nondeterministic finite automaton" );
+
+} /* namespace generate */
+
+} /* namespace automaton */
diff --git a/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ed02081f913d193ee4d5ca501b9f9c219f9d773
--- /dev/null
+++ b/alib2algo/src/automaton/generate/RandomTreeAutomatonFactory.h
@@ -0,0 +1,233 @@
+/*
+ * RandomAutomatonFactory.h
+ *
+ * This file is part of Algorithms library toolkit.
+ * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
+
+ * Algorithms library toolkit is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * Algorithms library toolkit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Created on: 27. 3. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef RANDOM_AUTOMATON_FACTORY_H_
+#define RANDOM_AUTOMATON_FACTORY_H_
+
+#include <alib/deque>
+#include <alib/set>
+#include <alib/algorithm>
+#include <alib/random>
+#include <alib/string>
+
+#include <exception/CommonException.h>
+
+#include <automaton/TA/NFTA.h>
+
+namespace automaton {
+
+namespace generate {
+
+/**
+ * Generator of random automata.
+ *
+ * \details
+ * The underlying generation algorithm is from Leslie, T: Efficient Approaches to Subset Construction, 1995.
+ */
+class RandomTreeAutomatonFactory {
+public:
+	/**
+	 * Generates a random finite automaton.
+	 * \tparam SymbolType the type of terminal symbols of the random automaton
+	 *
+	 * \param statesCount number of states in the generated automaton
+	 * \param alphabet Input alphabet of the automaton
+	 * \param density density of the transition function
+	 *
+	 * \return random nondeterministic finite automaton
+	 */
+	template < class SymbolType, class RankType >
+	static automaton::NFTA < SymbolType, RankType, unsigned > generateNFTA ( size_t statesCount, const ext::set < common::ranked_symbol < SymbolType, RankType > > & alphabet, double density );
+
+	/**
+	 * \overload
+	 *
+	 * Generates a random finite automaton.
+	 *
+	 * \param statesCount number of states in the generated automaton
+	 * \param alphabetSize size of the alphabet (1-26)
+	 * \param maxRank the maximum rank in the randomly generated alphabet
+	 * \param randomizedAlphabet selects random symbols from a-z range if true
+	 * \param density density of the transition function (0-1). 1 means every possible transition is created
+	 *
+	 * \return random nondeterministic finite automaton
+	 */
+	static automaton::NFTA < std::string, DefaultRankType, unsigned > generateNFTA ( size_t statesCount, size_t alphabetSize, size_t maxRank, bool randomizedAlphabet, double density );
+
+private:
+	/**
+	 * Selects ith accessible state form \p VStates.
+	 *
+	 * \param VStates the states to select from
+	 * \param i the specification which accessble state to select
+	 *
+	 * \return ith accessible state based on VStates
+	 */
+	static unsigned ithAccessibleState ( const ext::deque < bool > & VStates, size_t i );
+
+	/**
+	 * Selects ith inaccessible state form \p VStates.
+	 *
+	 * \param VStates the states to select from
+	 * \param i the specification which inaccessble state to select
+	 *
+	 * \return ith inaccessible state based on VStates
+	 */
+	static unsigned ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i );
+
+	/**
+	 * Leslie's connected NFTA algorithm
+	 *
+	 * \tparam SymbolType the type of terminal symbols of the random automaton
+	 *
+	 * \param n number of states
+	 * \param alphabet input alphabet
+	 * \param density density of the transition function (0-1). 1 means every possible transition is created
+	 *
+	 * \return the actual random nondeterministic automaton
+	 */
+	template < class SymbolType, class RankType >
+	static automaton::NFTA < SymbolType, RankType, unsigned > LeslieConnectedNFTA ( size_t n, const ext::deque < common::ranked_symbol < SymbolType, RankType > > & alphabet, double density );
+};
+
+template < class SymbolType, class RankType >
+automaton::NFTA < SymbolType, RankType, unsigned > RandomTreeAutomatonFactory::generateNFTA ( size_t statesCount, const ext::set < common::ranked_symbol < SymbolType, RankType > > & alphabet, double density ) {
+	ext::deque < common::ranked_symbol < SymbolType, RankType > > alphabet2 ( alphabet.begin ( ), alphabet.end ( ) );
+	return RandomTreeAutomatonFactory::LeslieConnectedNFTA ( statesCount, alphabet2, density );
+}
+
+template < class SymbolType, class RankType >
+automaton::NFTA < SymbolType, RankType, unsigned > RandomTreeAutomatonFactory::LeslieConnectedNFTA ( size_t n, const ext::deque < common::ranked_symbol < SymbolType, RankType > > & alphabet, double density ) {
+	if( alphabet.size( ) <= 0 )
+		throw exception::CommonException( "Alphabet size must be greater than 0." );
+
+	ext::deque < common::ranked_symbol < SymbolType, RankType > > nullaryAlphabet;
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : alphabet )
+		if ( symbol.getRank ( ) == 0 )
+			nullaryAlphabet.push_back ( symbol );
+
+	if ( nullaryAlphabet.empty ( ) )
+		throw exception::CommonException ( "Alphabet does not contain a nullary symbol" );
+
+	ext::deque<bool> VStates;
+	ext::deque<unsigned> Q;
+	int unvisited;
+
+	automaton::NFTA < SymbolType, RankType, unsigned > automaton;
+
+	for( const auto & s : alphabet )
+		automaton.addInputSymbol( s );
+
+	for( size_t i = 0; i < n; i ++ ) {
+		VStates.push_back( false );
+		Q.push_back( i );
+		automaton.addState( Q[ i ] );
+	}
+
+	if( n == 0 ) {
+		return automaton;
+	} else if( n == 1 ) {
+		automaton.addTransition( nullaryAlphabet[ ext::random_devices::semirandom() % nullaryAlphabet.size( ) ], ext::vector < unsigned > { }, Q[ 0 ] );
+
+		unvisited = 0;
+		VStates[ 0 ] = true;
+	} else {
+		unsigned x = ext::random_devices::semirandom() % n;
+		automaton.addTransition( nullaryAlphabet[ ext::random_devices::semirandom() % nullaryAlphabet.size( ) ], ext::vector < unsigned > { }, Q[ x ] );
+		unvisited = n - 1;
+
+		VStates[ x ] = true;
+	}
+
+	while( unvisited != 0 ) {
+		int c = ext::random_devices::semirandom() % alphabet.size( );
+		ext::vector < unsigned > from;
+		while ( from.size ( ) < alphabet [ c ].getRank ( ) ) {
+			size_t a = ithAccessibleState ( VStates, ext::random_devices::semirandom() % ( n - unvisited ) );	// select y-th accessible state
+			from.push_back ( Q[ a ] );
+		}
+
+		size_t b = ithInaccessibleState ( VStates, ext::random_devices::semirandom() % unvisited );		// select z-th inaccessible state
+
+		automaton.addTransition( alphabet[ c ], std::move ( from ), Q[ b ] );
+
+		unvisited -= 1;
+		VStates[ b ] = true;
+	}
+
+	for( const unsigned & q : Q ) {
+		if( automaton.getTransitionsFromState( q ).size( ) == 0 && ext::random_devices::semirandom() % 100 < 90 )
+			automaton.addFinalState( q );
+		else if( automaton.getTransitionsFromState( q ).size( ) > 0 && ext::random_devices::semirandom() % 100 < 10 )
+			automaton.addFinalState( q );
+	}
+
+	if( automaton.getFinalStates( ).size( ) == 0 ) {
+		if( n == 1 ) {
+			automaton.addFinalState( * automaton.getStates( ).begin ( ) );
+		} else {
+			for( const unsigned & q : Q ) {
+				if( automaton.getTransitionsFromState( q ).size( ) == 0 ) {
+					automaton.addFinalState( q );
+					break;
+				}
+			}
+		}
+	}
+
+	size_t accSourceStates = 1;
+	for ( const common::ranked_symbol < SymbolType, RankType > & symbol : alphabet )
+		accSourceStates += symbol.getRank ( );
+
+	double mnn100 = 100.0 / alphabet.size( ) / accSourceStates / n; //FIXME check the computation of density
+	while( automaton.getTransitions ( ).size ( ) * mnn100 < density ) {
+		int a = ext::random_devices::semirandom() % alphabet.size( );
+		ext::vector < unsigned > from;
+		while ( from.size ( ) < alphabet [ a ].getRank ( ) ) {
+			int y = ext::random_devices::semirandom() % n;
+			from.push_back ( Q[ y ] );
+		}
+
+		int z = ext::random_devices::semirandom() % n;
+
+		automaton.addTransition( alphabet [ a ], std::move ( from ), Q[ z ] );
+	}
+
+	ext::map < common::ranked_symbol < SymbolType, RankType >, bool> alphabetUsage;
+	for( const auto & a : automaton.getInputAlphabet( ) )
+		alphabetUsage[ a ] = false;
+	for( const auto & t : automaton.getTransitions( ) )
+		alphabetUsage[ t.first.first ] = true;
+
+	for( const auto & kv : alphabetUsage )
+		if( kv.second == false )
+			automaton.removeInputSymbol( kv.first );
+
+	return automaton;
+}
+
+} /* namespace generate */
+
+} /* namespace automaton */
+
+#endif /* RANDOM_AUTOMATON_FACTORY_H_ */