From de75b2c02201e3cb7f094c4e6d375c8fd013e1c5 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 25 Sep 2018 07:35:47 +0200
Subject: [PATCH] template random automaton and grammar factory

---
 .../generate/RandomAutomatonFactory.cpp       | 144 +++-------------
 .../generate/RandomAutomatonFactory.h         | 163 ++++++++++++++++--
 .../grammar/generate/RandomGrammarFactory.cpp |  68 ++------
 .../grammar/generate/RandomGrammarFactory.h   |  56 +++++-
 alib2algo/test-src/playTest.cpp               |   2 +-
 alib2algo/test-src/playTest.h                 |   2 +-
 tests.anormalize.sh                           |   2 +-
 7 files changed, 237 insertions(+), 200 deletions(-)

diff --git a/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp b/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp
index deaedc923d..a5288b451e 100644
--- a/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp
+++ b/alib2algo/src/automaton/generate/RandomAutomatonFactory.cpp
@@ -6,151 +6,53 @@
  */
 
 #include "RandomAutomatonFactory.h"
-#include <exception/CommonException.h>
-
-#include <alib/algorithm>
-#include <alib/random>
-
 #include <registration/AlgoRegistration.hpp>
 
 namespace automaton {
 
 namespace generate {
 
-automaton::NFA < > RandomAutomatonFactory::generateNFA( size_t statesCount, const ext::set<DefaultSymbolType> & alphabet, double density ) {
-	ext::deque<DefaultSymbolType> alphabet2 ( alphabet.begin ( ), alphabet.end ( ) );
-	return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet2, density );
-}
-
-automaton::NFA < > RandomAutomatonFactory::generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ) {
+automaton::NFA < char, unsigned > RandomAutomatonFactory::generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density ) {
 	if(alphabetSize > 26)
 		throw exception::CommonException("Too big alphabet.");
 
-	ext::vector<DefaultSymbolType> symbols;
+	ext::deque < char > alphabet;
 	for(int i = 0; i < 26; i++)
-		symbols.push_back(DefaultSymbolType((char)(i + 'a')));
+		alphabet.push_back ( i + 'a' );
 
 	if(randomizedAlphabet)
-		shuffle(symbols.begin(), symbols.end(), ext::random_devices::semirandom);
+		shuffle(alphabet.begin(), alphabet.end(), ext::random_devices::semirandom);
 
-	ext::deque<DefaultSymbolType> alphabet(symbols.begin(), symbols.begin() + alphabetSize);
+	alphabet.resize ( alphabetSize );
 
 	return RandomAutomatonFactory::LeslieConnectedNFA( statesCount, alphabet, density );
 }
 
-automaton::NFA < > RandomAutomatonFactory::LeslieConnectedNFA( size_t n, const ext::deque<DefaultSymbolType> & alphabet, double density ) {
-	if( alphabet.size( ) <= 0 )
-		throw exception::CommonException( "Alphabet size must be greater than 0." );
-
-	ext::deque<bool> VStates;
-	ext::deque<DefaultStateType> Q;
-	int unvisited;
-
-	automaton::NFA < > automaton( DefaultStateType( 0 ) );
-
-	for( const auto & s : alphabet )
-		automaton.addInputSymbol( s );
-
-	for( size_t i = 0; i < n; i ++ ) {
-		VStates.push_back( false );
-		Q.push_back( DefaultStateType ( (int) i ) );
-		automaton.addState( Q[ i ] );
-	}
-
-	if( n == 0 ) {
-		return automaton;
-	} else if( n == 1 ) {
-		automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ 0 ] );
-
-		unvisited = 0;
-		VStates[ 0 ] = true;
-	} else {
-		int x = ( ext::random_devices::semirandom() % ( n - 1 ) ) + 1;
-		automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ x ] );
-		unvisited = n - 2;
-
-		VStates[ 0 ] = true;
-		VStates[ x ] = true;
-	}
-
-	while( unvisited != 0 ) {
-		size_t y = ext::random_devices::semirandom() % ( n - unvisited ) + 1;	// select y-th accessible state
-		size_t z = ext::random_devices::semirandom() % unvisited + 1;		// select z-th inaccessible state
-		int a = -1, b = -1;
+unsigned RandomAutomatonFactory::ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
+	i ++;
+	for( size_t j = 0; j < VStates.size ( ); j++ ) {
+		if( VStates[ j ] == true )
+			i --;
 
-		for( size_t i = 0, cnt = 0; i < n; i++ ) {
-			if( VStates[ i ] == true )
-				cnt ++;
-
-			if( cnt == y ) {
-				a = i;
-				break;
-			}
-		}
-		for( size_t i = 0, cnt = 0; i < n; i++ ) {
-			if( VStates[ i ] == false )
-				cnt ++;
-
-			if( cnt == z )
-			{
-				b = i;
-				break;
-			}
-		}
-
-		int c = ext::random_devices::semirandom() % alphabet.size( );
-		automaton.addTransition( Q[ a ], alphabet[ c ], Q[ b ] );
-
-
-		unvisited -= 1;
-		VStates[ b ] = true;
-
-		// ---------
-	}
-
-	for( const DefaultStateType & 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.getInitialState( ) );
-		} else {
-			for( const DefaultStateType & q : Q ) {
-				if( automaton.getTransitionsFromState( q ).size( ) == 0 ) {
-					automaton.addFinalState( q );
-					break;
-				}
-			}
-		}
+		if( i == 0 )
+			return i;
 	}
+	throw std::logic_error ( "Not enough states in deque of visited states" );
+}
 
-	double mnn100 = 100.0 / alphabet.size( ) / n / n;
-	while( automaton.transitionsSize( ) * mnn100 < density ) {
-		int y = ext::random_devices::semirandom() % n;
-		int z = ext::random_devices::semirandom() % n;
-		int a = ext::random_devices::semirandom() % alphabet.size();
+unsigned RandomAutomatonFactory::ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
+	i ++;
+	for( size_t j = 0; j < VStates.size ( ); j++ ) {
+		if( VStates[ j ] == false )
+			i --;
 
-		automaton.addTransition( Q[ y ], alphabet [ a ], Q[ z ] );
+		if( i == 0 )
+			return j;
 	}
-
-	ext::map<DefaultSymbolType, bool> alphabetUsage;
-	for( const auto & a : automaton.getInputAlphabet( ) )
-		alphabetUsage[ a ] = false;
-	for( const auto & t : automaton.getTransitions( ) )
-		alphabetUsage[ t.first.second ] = true;
-
-	for( const auto & kv : alphabetUsage )
-		if( kv.second == false )
-			automaton.removeInputSymbol( kv.first );
-
-	return automaton;
+	throw std::logic_error ( "Not enough states in deque of visited states" );
 }
 
-auto GenerateNFA = registration::AbstractRegister < RandomAutomatonFactory, automaton::NFA < >, size_t, size_t, bool, double > ( RandomAutomatonFactory::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "randomizedAlphabet", "density" );
+auto GenerateNFA = registration::AbstractRegister < RandomAutomatonFactory, automaton::NFA < char, unsigned >, size_t, size_t, bool, double > ( RandomAutomatonFactory::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "randomizedAlphabet", "density" );
 
 } /* namespace generate */
 
diff --git a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h
index 38a0427f2e..b377e3a2c8 100644
--- a/alib2algo/src/automaton/generate/RandomAutomatonFactory.h
+++ b/alib2algo/src/automaton/generate/RandomAutomatonFactory.h
@@ -26,6 +26,10 @@
 
 #include <alib/deque>
 #include <alib/set>
+#include <alib/algorithm>
+#include <alib/random>
+
+#include <exception/CommonException.h>
 
 #include <automaton/FSM/NFA.h>
 
@@ -36,42 +40,169 @@ namespace generate {
 /**
  * Generator of random automata.
  *
- * @details
+ * \details
  * The underlying generation algorithm is from Leslie, T: Efficient Approaches to Subset Construction, 1995.
  */
 class RandomAutomatonFactory {
 public:
 	/**
 	 * Generates a random finite 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
+	 * \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
 	 */
-	static automaton::NFA < > generateNFA( size_t statesCount, const ext::set<DefaultSymbolType> & alphabet, double density );
+	template < class SymbolType >
+	static automaton::NFA < SymbolType, unsigned > generateNFA ( size_t statesCount, const ext::set < SymbolType > & 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 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
+	 *
+	 * \param statesCount number of states in the generated automaton
+	 * \param alphabetSize size of the alphabet (1-26)
+	 * \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::NFA < > generateNFA( size_t statesCount, size_t alphabetSize, bool randomizedAlphabet, double density );
+	static automaton::NFA < char, unsigned > generateNFA ( size_t statesCount, size_t alphabetSize, 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 NFA algorithm
-	 * @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
+	 *
+	 * \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
 	 */
-	static automaton::NFA < > LeslieConnectedNFA( size_t n, const ext::deque<DefaultSymbolType> & alphabet, double density );
+	template < class SymbolType >
+	static automaton::NFA < SymbolType, unsigned > LeslieConnectedNFA ( size_t n, const ext::deque < SymbolType > & alphabet, double density );
 };
 
+template < class SymbolType >
+automaton::NFA < SymbolType, unsigned > RandomAutomatonFactory::generateNFA ( size_t statesCount, const ext::set < SymbolType > & alphabet, double density ) {
+	ext::deque < SymbolType > alphabet2 ( alphabet.begin ( ), alphabet.end ( ) );
+	return RandomAutomatonFactory::LeslieConnectedNFA ( statesCount, alphabet2, density );
+}
+
+template < class SymbolType >
+automaton::NFA < SymbolType, unsigned > RandomAutomatonFactory::LeslieConnectedNFA ( size_t n, const ext::deque < SymbolType > & alphabet, double density ) {
+	if( alphabet.size( ) <= 0 )
+		throw exception::CommonException( "Alphabet size must be greater than 0." );
+
+	ext::deque<bool> VStates;
+	ext::deque<unsigned> Q;
+	int unvisited;
+
+	automaton::NFA < SymbolType, unsigned > automaton( 0 );
+
+	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( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ 0 ] );
+
+		unvisited = 0;
+		VStates[ 0 ] = true;
+	} else {
+		unsigned x = ( ext::random_devices::semirandom() % ( n - 1 ) ) + 1;
+		automaton.addTransition( Q[ 0 ], alphabet[ ext::random_devices::semirandom() % alphabet.size( ) ], Q[ x ] );
+		unvisited = n - 2;
+
+		VStates[ 0 ] = true;
+		VStates[ x ] = true;
+	}
+
+	while( unvisited != 0 ) {
+		size_t a = ithAccessibleState ( VStates, ext::random_devices::semirandom() % ( n - unvisited ) );	// select y-th accessible state
+		size_t b = ithInaccessibleState ( VStates, ext::random_devices::semirandom() % unvisited );		// select z-th inaccessible state
+
+		int c = ext::random_devices::semirandom() % alphabet.size( );
+		automaton.addTransition( Q[ a ], alphabet[ c ], 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.getInitialState( ) );
+		} else {
+			for( const unsigned & q : Q ) {
+				if( automaton.getTransitionsFromState( q ).size( ) == 0 ) {
+					automaton.addFinalState( q );
+					break;
+				}
+			}
+		}
+	}
+
+	double mnn100 = 100.0 / alphabet.size( ) / n / n;
+	while( automaton.transitionsSize( ) * mnn100 < density ) {
+		int y = ext::random_devices::semirandom() % n;
+		int z = ext::random_devices::semirandom() % n;
+		int a = ext::random_devices::semirandom() % alphabet.size();
+
+		automaton.addTransition( Q[ y ], alphabet [ a ], Q[ z ] );
+	}
+
+	ext::map<SymbolType, bool> alphabetUsage;
+	for( const auto & a : automaton.getInputAlphabet( ) )
+		alphabetUsage[ a ] = false;
+	for( const auto & t : automaton.getTransitions( ) )
+		alphabetUsage[ t.first.second ] = true;
+
+	for( const auto & kv : alphabetUsage )
+		if( kv.second == false )
+			automaton.removeInputSymbol( kv.first );
+
+	return automaton;
+}
+
 } /* namespace generate */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp b/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp
index f612148ac4..9c74a5eeea 100644
--- a/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp
+++ b/alib2algo/src/grammar/generate/RandomGrammarFactory.cpp
@@ -6,81 +6,35 @@
  */
 
 #include "RandomGrammarFactory.h"
-#include <exception/CommonException.h>
-
-#include <alib/algorithm>
-#include <alib/random>
 #include <registration/AlgoRegistration.hpp>
 
 namespace grammar {
 
 namespace generate {
 
-grammar::CFG < > RandomGrammarFactory::generateCFG( ext::set<DefaultSymbolType> nonterminals, ext::set<DefaultSymbolType> terminals, double density ) {
-	ext::deque<DefaultSymbolType> terminals2(terminals.begin(), terminals.end());
-	ext::deque<DefaultSymbolType> nonterminals2(nonterminals.begin(), nonterminals.end());
-	return RandomGrammarFactory::randomCFG( nonterminals2, terminals2, density );
-}
-
 auto GenerateCFG1 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < >, ext::set < DefaultSymbolType >, ext::set < DefaultSymbolType >, double > ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminals", "terminals", "density" );
 
-grammar::CFG < > RandomGrammarFactory::generateCFG( size_t nonterminalsCount, size_t terminalsCount, bool randomizedAlphabet, double density ) {
+grammar::CFG < char, char > RandomGrammarFactory::generateCFG ( size_t nonterminalsCount, size_t terminalsCount, bool randomizedAlphabet, double density ) {
 	if(terminalsCount > 26)
 		throw exception::CommonException("Too big terminals count.");
 
-	ext::vector<DefaultSymbolType> symbols;
-	for(int i = 0; i < 26; i++) symbols.push_back(DefaultSymbolType((char)(i + 'a')));
-	if(randomizedAlphabet) shuffle(symbols.begin(), symbols.end(), ext::random_devices::semirandom);
-	ext::deque<DefaultSymbolType> terminals(symbols.begin(), symbols.begin() + terminalsCount);
+	ext::deque < char > terminals;
+	for(int i = 0; i < 26; i++) terminals.push_back ( i + 'a' );
+	if(randomizedAlphabet) shuffle ( terminals.begin ( ), terminals.end ( ), ext::random_devices::semirandom );
+	terminals.resize ( terminalsCount );
 
 	if(nonterminalsCount > 26)
 		throw exception::CommonException("Too big nonterminals count.");
 
-	ext::vector<DefaultSymbolType> symbols2;
-	for(int i = 0; i < 26; i++) symbols2.push_back(DefaultSymbolType((char)(i + 'A')));
-	if(randomizedAlphabet) shuffle(symbols2.begin(), symbols2.end(), ext::random_devices::semirandom);
-	ext::deque<DefaultSymbolType> nonterminals(symbols2.begin(), symbols2.begin() + nonterminalsCount);
+	ext::deque < char > nonterminals;
+	for(int i = 0; i < 26; i++) nonterminals.push_back ( i + 'A' );
+	if ( randomizedAlphabet ) shuffle ( nonterminals.begin ( ), nonterminals.end ( ), ext::random_devices::semirandom );
+	nonterminals.resize ( nonterminalsCount);
 
-	return RandomGrammarFactory::randomCFG( nonterminals, terminals, density );
+	return RandomGrammarFactory::randomCFG ( nonterminals, terminals, density );
 }
 
-auto GenerateCFG2 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < >, size_t, size_t, bool, double> ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminalsCount", "terminalsCount", "randomizedAlphabet", "density" );
-
-grammar::CFG < > RandomGrammarFactory::randomCFG( const ext::deque<DefaultSymbolType>& nonterminals, const ext::deque<DefaultSymbolType> & terminals, double density ) {
-	if( terminals.size( ) <= 0 )
-		throw exception::CommonException( "Terminals count must be greater than 0." );
-
-	if( nonterminals.size( ) <= 0 )
-		throw exception::CommonException( "Nonterminals count must be greater than 0." );
-
-	grammar::CFG < > grammar(nonterminals.front());
-	grammar.setTerminalAlphabet({terminals.begin(), terminals.end()});
-	grammar.setNonterminalAlphabet({nonterminals.begin(), nonterminals.end()});
-
-	if(ext::random_devices::semirandom() % 2)
-		grammar.addRule(grammar.getInitialSymbol(), {});
-
-	int rules = 0;
-	while(rules < terminals.size() * nonterminals.size() * density / 100) {
-		const DefaultSymbolType& lhs = nonterminals[ext::random_devices::semirandom() % nonterminals.size()];
-
-		int rhsSize = ext::random_devices::semirandom() % 5;
-		ext::vector<ext::variant<DefaultSymbolType, DefaultSymbolType>> rhs;
-		int nonterminalsOnRHS = 0;
-		for(int i = 0; i < rhsSize; i++) {
-			if(ext::random_devices::semirandom() % (nonterminals.size() + terminals.size()) < nonterminals.size()) {
-				rhs.push_back(ext::variant < DefaultSymbolType, DefaultSymbolType > ( nonterminals[ext::random_devices::semirandom() % nonterminals.size()]));
-				nonterminalsOnRHS++;
-			} else {
-				rhs.push_back(ext::variant < DefaultSymbolType, DefaultSymbolType > ( terminals[ext::random_devices::semirandom() % terminals.size()]));
-			}
-		}
-		rules += nonterminalsOnRHS;
-		grammar.addRule(lhs, rhs);
-	}
-
-	return grammar;
-}
+auto GenerateCFG2 = registration::AbstractRegister < RandomGrammarFactory, grammar::CFG < char, char >, size_t, size_t, bool, double> ( RandomGrammarFactory::generateCFG, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "nonterminalsCount", "terminalsCount", "randomizedAlphabet", "density" );
 
 } /* namespace generate */
 
diff --git a/alib2algo/src/grammar/generate/RandomGrammarFactory.h b/alib2algo/src/grammar/generate/RandomGrammarFactory.h
index 0c8644cfc8..bb04a85260 100644
--- a/alib2algo/src/grammar/generate/RandomGrammarFactory.h
+++ b/alib2algo/src/grammar/generate/RandomGrammarFactory.h
@@ -10,6 +10,10 @@
 
 #include <alib/deque>
 #include <alib/set>
+#include <alib/algorithm>
+#include <alib/random>
+
+#include <exception/CommonException.h>
 
 #include <grammar/ContextFree/CFG.h>
 
@@ -19,13 +23,59 @@ namespace generate {
 
 class RandomGrammarFactory {
 public:
-	static grammar::CFG < > generateCFG( ext::set<DefaultSymbolType> nonterminals, ext::set<DefaultSymbolType> terminals, double density );
-	static grammar::CFG < > generateCFG( size_t nonterminalsCount, size_t terminalsSize, bool randomizedAlphabet, double density );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > generateCFG ( ext::set < NonterminalSymbolType > nonterminals, ext::set < TerminalSymbolType > terminals, double density );
+	static grammar::CFG < char, char > generateCFG( size_t nonterminalsCount, size_t terminalsSize, bool randomizedAlphabet, double density );
 
 private:
-	static grammar::CFG < > randomCFG( const ext::deque<DefaultSymbolType> & nonterminals, const ext::deque<DefaultSymbolType> & terminals, double density );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > randomCFG ( const ext::deque < NonterminalSymbolType > & nonterminals, const ext::deque < TerminalSymbolType > & terminals, double density );
 };
 
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CFG < TerminalSymbolType, NonterminalSymbolType > RandomGrammarFactory::generateCFG ( ext::set < NonterminalSymbolType > nonterminals, ext::set < TerminalSymbolType > terminals, double density ) {
+	ext::deque < TerminalSymbolType > terminals2 ( terminals.begin ( ), terminals.end ( ) );
+	ext::deque < NonterminalSymbolType > nonterminals2 ( nonterminals.begin ( ), nonterminals.end ( ) );
+	return RandomGrammarFactory::randomCFG ( nonterminals2, terminals2, density );
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CFG < TerminalSymbolType, NonterminalSymbolType > RandomGrammarFactory::randomCFG ( const ext::deque < NonterminalSymbolType > & nonterminals, const ext::deque < TerminalSymbolType > & terminals, double density ) {
+	if( terminals.size( ) <= 0 )
+		throw exception::CommonException( "Terminals count must be greater than 0." );
+
+	if( nonterminals.size( ) <= 0 )
+		throw exception::CommonException( "Nonterminals count must be greater than 0." );
+
+	grammar::CFG < TerminalSymbolType, NonterminalSymbolType > grammar(nonterminals.front());
+	grammar.setTerminalAlphabet({terminals.begin(), terminals.end()});
+	grammar.setNonterminalAlphabet({nonterminals.begin(), nonterminals.end()});
+
+	if(ext::random_devices::semirandom() % 2)
+		grammar.addRule(grammar.getInitialSymbol(), {});
+
+	int rules = 0;
+	while(rules < terminals.size() * nonterminals.size() * density / 100) {
+		const NonterminalSymbolType& lhs = nonterminals[ext::random_devices::semirandom() % nonterminals.size()];
+
+		int rhsSize = ext::random_devices::semirandom() % 5;
+		ext::vector<ext::variant<TerminalSymbolType, NonterminalSymbolType>> rhs;
+		int nonterminalsOnRHS = 0;
+		for(int i = 0; i < rhsSize; i++) {
+			if(ext::random_devices::semirandom() % (nonterminals.size() + terminals.size()) < nonterminals.size()) {
+				rhs.push_back(ext::variant < TerminalSymbolType, NonterminalSymbolType > ( nonterminals[ext::random_devices::semirandom() % nonterminals.size()]));
+				nonterminalsOnRHS++;
+			} else {
+				rhs.push_back(ext::variant < TerminalSymbolType, NonterminalSymbolType > ( terminals[ext::random_devices::semirandom() % terminals.size()]));
+			}
+		}
+		rules += nonterminalsOnRHS;
+		grammar.addRule(lhs, rhs);
+	}
+
+	return grammar;
+}
+
 } /* namespace generate */
 
 } /* namespace grammar */
diff --git a/alib2algo/test-src/playTest.cpp b/alib2algo/test-src/playTest.cpp
index 01026b327f..edffe9234c 100644
--- a/alib2algo/test-src/playTest.cpp
+++ b/alib2algo/test-src/playTest.cpp
@@ -25,7 +25,7 @@ void playTest::setUp()
 
 void playTest::tearDown(){}
 
-automaton::NFA < >  playTest::randomNFA(void) const
+automaton::NFA < char, unsigned >  playTest::randomNFA(void) const
 {
     return automaton::generate::RandomAutomatonFactory::generateNFA(
             rand() % TEST_AUTOMATON_STATES_MAX + 1,
diff --git a/alib2algo/test-src/playTest.h b/alib2algo/test-src/playTest.h
index 635418fe82..77c48760c1 100644
--- a/alib2algo/test-src/playTest.h
+++ b/alib2algo/test-src/playTest.h
@@ -19,7 +19,7 @@ public:
   void testPlay1();
 
 private:
-    automaton::NFA < >  randomNFA(void) const;
+    automaton::NFA < char, unsigned >  randomNFA(void) const;
     automaton::DFA < DefaultSymbolType, unsigned > mDFA(const automaton::NFA < > & automaton) const;
 
     void case1a(void) const;
diff --git a/tests.anormalize.sh b/tests.anormalize.sh
index c7e7e6ea6d..3025346028 100755
--- a/tests.anormalize.sh
+++ b/tests.anormalize.sh
@@ -64,7 +64,7 @@ function generateCFG {
 # $1 = command for conversion. Output of such command must be a grammar !!
 # $2 = original grammar
 function runTest2 {
-	GENERATED_STRINGS="./agenerate2 -t upTo --upto $STRING_LENGHTS"
+	GENERATED_STRINGS="./agenerate2 -t upTo --upto $STRING_LENGHTS | ./aecho2 -n"
 
 	OUT=`timeout $TESTCASE_TIMEOUT bash -c "diff <(cat $2 | $1 | $GENERATED_STRINGS ) <(cat $2 | $GENERATED_STRINGS)"`
 	RET=$?
-- 
GitLab