From fc93de29a680c16636e7e7dd67516ad936b16f00 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Thu, 20 Sep 2018 14:40:57 +0200
Subject: [PATCH] proper template of to CNF conversion algorithm

---
 alib2algo/src/grammar/simplify/ToCNF.cpp      | 155 +-----------
 alib2algo/src/grammar/simplify/ToCNF.h        | 221 +++++++++++++++---
 .../grammar/simplify/GrammarToCNFTest.cpp     | 113 +++++----
 3 files changed, 245 insertions(+), 244 deletions(-)

diff --git a/alib2algo/src/grammar/simplify/ToCNF.cpp b/alib2algo/src/grammar/simplify/ToCNF.cpp
index a82015413e..cc3496e996 100644
--- a/alib2algo/src/grammar/simplify/ToCNF.cpp
+++ b/alib2algo/src/grammar/simplify/ToCNF.cpp
@@ -6,160 +6,21 @@
  */
 
 #include "ToCNF.h"
-
-#include "EpsilonRemover.h"
-#include "SimpleRulesRemover.h"
-#include <common/DefaultSymbolsPairType.h>
-#include <exception/CommonException.h>
 #include <registration/AlgoRegistration.hpp>
 
-#include <grammar/RawRules.h>
-#include <grammar/AddRawRule.h>
-#include <object/ObjectFactory.h>
-
 namespace grammar {
 
 namespace simplify {
 
-void splitRule ( const DefaultSymbolType & lhs, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rhs, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > & result ) { //After templating the CNF make rhs const reference
-	switch ( rhs.size ( ) ) {
-	case 2: {
-			result.addRule ( lhs, ext::make_pair ( std::move ( rhs [ 0 ] ), std::move ( rhs [ 1 ] ) ) );
-			break;
-		}
-	case 3: {
-			ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > right ( std::make_move_iterator ( std::next ( rhs.begin ( ) ) ), std::make_move_iterator ( rhs.end ( ) ) );
-			DefaultSymbolType second = object::ObjectFactory::make ( right );
-			if ( result.addNonterminalSymbol ( second ) )
-				splitRule ( second, std::move ( right ), result );
-
-			result.addRule ( lhs, ext::make_pair ( std::move ( rhs [ 0 ] ), std::move ( second ) ) );
-			break;
-		}
-	default: {
-			ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > left;
-			for ( unsigned i = 0; i < rhs.size ( ) / 2; ++ i )
-				left.push_back ( std::move ( rhs [ i ] ) );
-
-			DefaultSymbolType first = object::ObjectFactory::make ( left );
-			if ( result.addNonterminalSymbol ( first ) )
-				splitRule ( first, std::move ( left ), result );
-
-			ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > right;
-			for ( unsigned i = rhs.size ( ) / 2; i < rhs.size ( ); ++ i )
-				right.push_back ( std::move ( rhs [ i ] ) );
-
-			DefaultSymbolType second = object::ObjectFactory::make ( right );
-			if ( result.addNonterminalSymbol ( second ) )
-				splitRule ( second, std::move ( right ), result );
-
-			result.addRule ( lhs, ext::make_pair ( std::move ( first ), std::move ( second ) ) );
-		}
-	}
-}
-
-template<class T>
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convertInternal( const T & origGrammar ) {
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > result ( origGrammar.getInitialSymbol ( ) );
-
-	for ( const DefaultSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
-		result.addNonterminalSymbol ( nonterminal );
-
-	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
-
-	ext::map < DefaultSymbolType, DefaultSymbolType > terminalToShadowNonterminal;
-	for ( const DefaultSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
-		DefaultSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
-		terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) );
-		result.addNonterminalSymbol ( shadowSymbol );
-		result.addRule ( std::move ( shadowSymbol ), symbol );
-	}
-
-	for ( const auto & rules : origGrammar.getRules ( ) ) {
-		for ( const ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > & rhs : rules.second ) {
-			if ( rhs.size ( ) == 1 ) {
-				result.addRule ( rules.first, rhs [ 0 ].get < DefaultSymbolType > ( ) );
-			} else {
-				ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rawRule;
-				for ( const ext::variant < DefaultSymbolType, DefaultSymbolType > & symbol : rhs ) {
-					if ( origGrammar.getTerminalAlphabet ( ).count ( symbol ) )
-						rawRule.push_back ( terminalToShadowNonterminal.at ( symbol.get < DefaultSymbolType > ( ) ) );
-					else
-						rawRule.push_back ( symbol );
-				}
-
-				splitRule ( rules.first, std::move ( rawRule ), result );
-			}
-		}
-	}
-
-	result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) );
-
-	return result;
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::CFG < > & origGrammar) {
-	return convert(grammar::simplify::EpsilonRemover::remove(origGrammar));
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::EpsilonFreeCFG < > & origGrammar) {
-	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(origGrammar));
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert ( const grammar::GNF < > & origGrammar ) {
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > result ( origGrammar.getInitialSymbol ( ) );
-
-	for ( const DefaultSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
-		result.addNonterminalSymbol ( nonterminal );
-
-	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
-
-	ext::map < DefaultSymbolType, DefaultSymbolType > terminalToShadowNonterminal;
-	for ( const DefaultSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
-		DefaultSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
-		terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) );
-		result.addNonterminalSymbol ( shadowSymbol );
-		result.addRule ( std::move ( shadowSymbol ), symbol );
-	}
-
-	for ( const auto & rules : origGrammar.getRules ( ) ) {
-		for ( const ext::pair < DefaultSymbolType, ext::vector < DefaultSymbolType > > & rhs : rules.second ) {
-			if ( rhs.second.size ( ) == 0 )
-				result.addRule ( rules.first, rhs.first );
-			else {
-				ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rawRule { terminalToShadowNonterminal.at ( rhs.first ) };
-				rawRule.insert ( rawRule.end ( ), rhs.second.begin ( ), rhs.second.end ( ) );
-				splitRule ( rules.first, std::move ( rawRule ), result );
-			}
-		}
-	}
-
-	result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) );
-
-	return result;
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::LG < > & origGrammar) {
-	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::LeftLG< > & origGrammar) {
-	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
-}
-
-grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::RightLG < > & origGrammar) {
-	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
-}
-
-auto ToCNFCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::CFG < > & > ( ToCNF::convert );
-auto ToCNFEpsilonFreeCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::EpsilonFreeCFG < > & > ( ToCNF::convert );
+auto ToCNFCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::CFG < > & > ( ToCNF::convert );
+auto ToCNFEpsilonFreeCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::EpsilonFreeCFG < > & > ( ToCNF::convert );
 auto ToCNFCNF = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::CNF < > & > ( ToCNF::convert );
-auto ToCNFGNF = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::GNF < > & > ( ToCNF::convert );
-auto ToCNFLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LG < > & > ( ToCNF::convert );
-auto ToCNFLeftLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LeftLG < > & > ( ToCNF::convert );
-auto ToCNFLeftRG = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::LeftRG < > & > ( ToCNF::convert );
-auto ToCNFRightLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::RightLG < > & > ( ToCNF::convert );
-auto ToCNFRightRG = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::RightRG < > & > ( ToCNF::convert );
+auto ToCNFGNF = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::GNF < > & > ( ToCNF::convert );
+auto ToCNFLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::LG < > & > ( ToCNF::convert );
+auto ToCNFLeftLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::LeftLG < > & > ( ToCNF::convert );
+auto ToCNFLeftRG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LeftRG < > & > ( ToCNF::convert );
+auto ToCNFRightLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::RightLG < > & > ( ToCNF::convert );
+auto ToCNFRightRG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::RightRG < > & > ( ToCNF::convert );
 
 } /* namespace simplify */
 
diff --git a/alib2algo/src/grammar/simplify/ToCNF.h b/alib2algo/src/grammar/simplify/ToCNF.h
index 1b58eeba81..5e233c6a58 100644
--- a/alib2algo/src/grammar/simplify/ToCNF.h
+++ b/alib2algo/src/grammar/simplify/ToCNF.h
@@ -8,6 +8,7 @@
 #ifndef TO_CNF_H_
 #define TO_CNF_H_
 
+#include <grammar/Grammar.h>
 #include <grammar/ContextFree/CFG.h>
 #include <grammar/ContextFree/EpsilonFreeCFG.h>
 #include <grammar/ContextFree/CNF.h>
@@ -20,60 +21,71 @@
 
 #include <common/createUnique.hpp>
 
+#include "EpsilonRemover.h"
+#include "SimpleRulesRemover.h"
+#include <exception/CommonException.h>
+
 namespace grammar {
 
 namespace simplify {
 
 class ToCNF {
 public:
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::CFG < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::EpsilonFreeCFG < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::GNF < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	template < class SymbolType >
-	static grammar::CNF < SymbolType > convert( const grammar::CNF < SymbolType > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, NonterminalSymbolType > convert( const grammar::CNF < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::LG < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::LeftLG < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::LeftLG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	template < class SymbolType >
-	static grammar::CNF < SymbolType > convert( const grammar::LeftRG < SymbolType > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > convert( const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::RightLG < > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::RightLG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 
-	template < class SymbolType >
-	static grammar::CNF < SymbolType > convert( const grammar::RightRG < SymbolType > & grammar );
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > convert( const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar );
 };
 
-template < class SymbolType >
-grammar::CNF < SymbolType > ToCNF::convert(const grammar::CNF < SymbolType > & origGrammar) {
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, NonterminalSymbolType > ToCNF::convert(const grammar::CNF < TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
 	return origGrammar;
 }
 
-template < class SymbolType >
-grammar::CNF < SymbolType > ToCNF::convert ( const grammar::LeftRG < SymbolType > & origGrammar ) {
-	grammar::CNF < SymbolType > result ( origGrammar.getInitialSymbol ( ) );
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType,  ext::variant < TerminalSymbolType, NonterminalSymbolType > > ToCNF::convert ( const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) {
+	grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > result ( origGrammar.getInitialSymbol ( ) );
 
-	result.setNonterminalAlphabet ( origGrammar.getNonterminalAlphabet ( ) );
+	for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
+		result.addNonterminalSymbol ( nonterminal );
 	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
 
-	ext::map < SymbolType, SymbolType > terminalToShadowNonterminal;
-	for ( const SymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
-		SymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
+	ext::map < TerminalSymbolType, TerminalSymbolType > terminalToShadowNonterminal;
+	for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
+		TerminalSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
 		terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) );
 		result.addNonterminalSymbol ( shadowSymbol );
 		result.addRule ( std::move ( shadowSymbol ), symbol );
 	}
 
-	for ( const std::pair < SymbolType, ext::set < ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > > > & rules : origGrammar.getRules ( ) ) {
-		for ( const ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > & rhs : rules.second ) {
-			if ( rhs.template is < SymbolType > ( ) ) {
-				result.addRule ( rules.first, rhs );
+	for ( const std::pair < NonterminalSymbolType, ext::set < ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, TerminalSymbolType > > > > & rules : origGrammar.getRules ( ) ) {
+		for ( const ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, TerminalSymbolType > > & rhs : rules.second ) {
+			if ( rhs.template is < TerminalSymbolType > ( ) ) {
+				result.addRule ( rules.first, rhs.template get < TerminalSymbolType > ( ) );
 			} else {
-				const ext::pair < SymbolType, SymbolType > & rhsPair = rhs.template get < ext::pair < SymbolType, SymbolType > > ( );
+				const ext::pair < NonterminalSymbolType, TerminalSymbolType > & rhsPair = rhs.template get < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( );
 				result.addRule ( rules.first, ext::make_pair ( rhsPair.first, terminalToShadowNonterminal.at ( rhsPair.second ) ) );
 			}
 		}
@@ -84,27 +96,28 @@ grammar::CNF < SymbolType > ToCNF::convert ( const grammar::LeftRG < SymbolType
 	return result;
 }
 
-template < class SymbolType >
-grammar::CNF < SymbolType > ToCNF::convert ( const grammar::RightRG < SymbolType > & origGrammar ) {
-	grammar::CNF < SymbolType > result ( origGrammar.getInitialSymbol ( ) );
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType,  ext::variant < TerminalSymbolType, NonterminalSymbolType > > ToCNF::convert ( const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) {
+	grammar::CNF < TerminalSymbolType,  ext::variant < TerminalSymbolType, NonterminalSymbolType > > result ( origGrammar.getInitialSymbol ( ) );
 
-	result.setNonterminalAlphabet ( origGrammar.getNonterminalAlphabet ( ) );
+	for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
+		result.addNonterminalSymbol ( nonterminal );
 	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
 
-	ext::map < SymbolType, SymbolType > terminalToShadowNonterminal;
-	for ( const SymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
-		SymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
+	ext::map < TerminalSymbolType, TerminalSymbolType > terminalToShadowNonterminal;
+	for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
+		TerminalSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) );
 		terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) );
 		result.addNonterminalSymbol ( shadowSymbol );
 		result.addRule ( std::move ( shadowSymbol ), symbol );
 	}
 
-	for ( const std::pair < SymbolType, ext::set < ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > > > & rules : origGrammar.getRules ( ) ) {
-		for ( const ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > & rhs : rules.second ) {
-			if ( rhs.template is < SymbolType > ( ) ) {
-				result.addRule ( rules.first, rhs );
+	for ( const std::pair < NonterminalSymbolType, ext::set < ext::variant < TerminalSymbolType, ext::pair < TerminalSymbolType, NonterminalSymbolType > > > > & rules : origGrammar.getRules ( ) ) {
+		for ( const ext::variant < TerminalSymbolType, ext::pair < TerminalSymbolType, NonterminalSymbolType > > & rhs : rules.second ) {
+			if ( rhs.template is < TerminalSymbolType > ( ) ) {
+				result.addRule ( rules.first, rhs.template get < TerminalSymbolType > ( ) );
 			} else {
-				const ext::pair < SymbolType, SymbolType > & rhsPair = rhs.template get < ext::pair < SymbolType, SymbolType > > ( );
+				const ext::pair < TerminalSymbolType, NonterminalSymbolType > & rhsPair = rhs.template get < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( );
 				result.addRule ( rules.first, ext::make_pair ( terminalToShadowNonterminal.at ( rhsPair.first ), rhsPair.second ) );
 			}
 		}
@@ -115,6 +128,138 @@ grammar::CNF < SymbolType > ToCNF::convert ( const grammar::RightRG < SymbolType
 	return result;
 }
 
+template < class TerminalSymbolType, class NonterminalSymbolType >
+void splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > lhs, const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs, grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > & result ) {
+	switch ( rhs.size ( ) ) {
+	case 2: {
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left { rhs [ 0 ] };
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right { rhs [ 1 ] };
+			result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) );
+			break;
+		}
+	case 3: {
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left { rhs [ 0 ] };
+
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right ( std::next ( rhs.begin ( ) ), rhs.end ( ) );
+			if ( result.addNonterminalSymbol ( right ) )
+				splitRule ( right, right, result );
+
+			result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) );
+			break;
+		}
+	default: {
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left;
+			for ( unsigned i = 0; i < rhs.size ( ) / 2; ++ i )
+				left.push_back ( rhs [ i ] );
+
+			if ( result.addNonterminalSymbol ( left ) )
+				splitRule ( left, left, result );
+
+			ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right;
+			for ( unsigned i = rhs.size ( ) / 2; i < rhs.size ( ); ++ i )
+				right.push_back ( rhs [ i ] );
+
+			if ( result.addNonterminalSymbol ( right ) )
+				splitRule ( right, right, result );
+
+			result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) );
+		}
+	}
+}
+
+template < class T, class TerminalSymbolType = typename grammar::TerminalSymbolTypeOfGrammar < T >, class NonterminalSymbolType = typename grammar::NonterminalSymbolTypeOfGrammar < T > >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convertInternal( const T & origGrammar ) {
+	grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > result ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { origGrammar.getInitialSymbol ( ) } );
+
+	for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
+		result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { nonterminal } );
+
+	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
+
+	for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
+		result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol } );
+		result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, symbol );
+	}
+
+	for ( const auto & rules : origGrammar.getRules ( ) ) {
+		for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : rules.second ) {
+			if ( rhs.size ( ) == 1 ) {
+				result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, rhs [ 0 ].template get < TerminalSymbolType > ( ) );
+			} else {
+				ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > rawRule;
+				for ( const ext::variant < TerminalSymbolType, NonterminalSymbolType > & symbol : rhs ) {
+					if ( origGrammar.getTerminalAlphabet ( ).count ( symbol ) )
+						rawRule.push_back ( symbol.template get < TerminalSymbolType > ( ) );
+					else
+						rawRule.push_back ( symbol );
+				}
+
+				splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, std::move ( rawRule ), result );
+			}
+		}
+	}
+
+	result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) );
+
+	return result;
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
+	return convert(grammar::simplify::EpsilonRemover::remove(origGrammar));
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
+	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(origGrammar));
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) {
+	grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > result ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { origGrammar.getInitialSymbol ( ) } );
+
+	for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) )
+		result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { nonterminal } );
+
+	result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) );
+
+	for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) {
+		result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol } );
+		result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, symbol );
+	}
+
+	for ( const auto & rules : origGrammar.getRules ( ) ) {
+		for ( const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rhs : rules.second ) {
+			if ( rhs.second.size ( ) == 0 )
+				result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, rhs.first );
+			else {
+				ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > rawRule { rhs.first };
+				rawRule.insert ( rawRule.end ( ), rhs.second.begin ( ), rhs.second.end ( ) );
+				splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, std::move ( rawRule ), result );
+			}
+		}
+	}
+
+	result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) );
+
+	return result;
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
+	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::LeftLG< TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
+	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::RightLG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) {
+	return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)));
+}
+
 } /* namespace simplify */
 
 } /* namespace grammar */
diff --git a/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp b/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp
index fa54a8ace0..adb748a320 100644
--- a/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp
+++ b/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp
@@ -21,29 +21,26 @@ void GrammarToCNFTest::tearDown() {
 }
 
 void GrammarToCNFTest::testToCNFRules1() {
-	DefaultSymbolType S = DefaultSymbolType("S");
-	DefaultSymbolType A = DefaultSymbolType("A");
-	DefaultSymbolType B = DefaultSymbolType("B");
-	DefaultSymbolType C = DefaultSymbolType("C");
-	DefaultSymbolType D = DefaultSymbolType("D");
+	std::string S = "S";
+	std::string A = "A";
+	std::string B = "B";
+	std::string C = "C";
+	std::string D = "D";
 
-	DefaultSymbolType a = DefaultSymbolType("a");
-	DefaultSymbolType b = DefaultSymbolType("b");
+	char a = 'a';
+	char b = 'b';
 
-	DefaultSymbolType aP = DefaultSymbolType("a'");
-	DefaultSymbolType bP = DefaultSymbolType("b'");
-
-	grammar::CFG < > grammar1(S);
+	grammar::CFG < char, std::string > grammar1 ( S );
 	grammar1.setNonterminalAlphabet({S, A, B, C, D});
 	grammar1.setTerminalAlphabet({a, b});
 
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar2 = grammar::simplify::ToCNF::convert(grammar1);
+	grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar2 = grammar::simplify::ToCNF::convert ( grammar1 );
 
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar3(S);
-	grammar3.setNonterminalAlphabet({S, A, B, C, D, aP, bP});
+	grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar3 ( ext::vector < ext::variant < char, std::string > > { S } );
+	grammar3.setNonterminalAlphabet({{S}, {A}, {B}, {C}, {D}, {a}, {b}});
 	grammar3.setTerminalAlphabet({a, b});
-	grammar3.addRule(aP, a);
-	grammar3.addRule(bP, b);
+	grammar3.addRule ( ext::vector < ext::variant < char, std::string > > { a }, a);
+	grammar3.addRule ( ext::vector < ext::variant < char, std::string > > { b }, b);
 
 	std::cout << grammar2 << std::endl;
 	std::cout << grammar3 << std::endl;
@@ -52,54 +49,52 @@ void GrammarToCNFTest::testToCNFRules1() {
 }
 
 void GrammarToCNFTest::testToCNFRules2() {
-	DefaultSymbolType S = DefaultSymbolType("S");
-	DefaultSymbolType X = DefaultSymbolType("X");
-	DefaultSymbolType Y = DefaultSymbolType("Y");
+	std::string S = "S";
+	std::string X = "X";
+	std::string Y = "Y";
 
-	DefaultSymbolType a = DefaultSymbolType("a");
-	DefaultSymbolType b = DefaultSymbolType("b");
-	DefaultSymbolType c = DefaultSymbolType("c");
+	char a = 'a';
+	char b = 'b';
+	char c = 'c';
 
-	grammar::CFG < > grammar1(S);
+	grammar::CFG < char, std::string > grammar1 ( S );
 	grammar1.setNonterminalAlphabet({S, X, Y});
 	grammar1.setTerminalAlphabet({a, b, c});
-	grammar1.addRule({S}, {a, X, b, X});
-	grammar1.addRule({X}, {a, Y});
-	grammar1.addRule({X}, {b, Y});
-	grammar1.addRule({X}, {});
-	grammar1.addRule({Y}, {X});
-	grammar1.addRule({Y}, {c});
-
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar2 = grammar::simplify::ToCNF::convert(grammar1);
-	DefaultSymbolType aP = DefaultSymbolType("a'");
-	DefaultSymbolType bP = DefaultSymbolType("b'");
-	DefaultSymbolType cP = DefaultSymbolType("c'");
-	DefaultSymbolType Xb = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { X, bP } );
-	DefaultSymbolType aX = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { aP, X } );
-	DefaultSymbolType bX = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { bP, X } );
-
-	grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar3(S);
-	grammar3.setNonterminalAlphabet({S, X, Y, aP, bP, cP, Xb, aX, bX});
+	grammar1.addRule(S, {a, X, b, X});
+	grammar1.addRule(X, {a, Y});
+	grammar1.addRule(X, {b, Y});
+	grammar1.addRule(X, {});
+	grammar1.addRule(Y, {X});
+	grammar1.addRule(Y, {c});
+
+	grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar2 = grammar::simplify::ToCNF::convert(grammar1);
+
+	ext::vector < ext::variant < char, std::string > > Xb { X, b };
+	ext::vector < ext::variant < char, std::string > > aX { a, X };
+	ext::vector < ext::variant < char, std::string > > bX { b, X };
+
+	grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar3 ( ext::vector < ext::variant < char, std::string > > { S } );
+	grammar3.setNonterminalAlphabet({{S}, {X}, {Y}, {a}, {b}, {c}, {Xb}, {aX}, {bX}});
 	grammar3.setTerminalAlphabet({a, b, c});
-	grammar3.addRule(S, ext::make_pair(aX, bX));
-	grammar3.addRule(S, ext::make_pair(aP, bX));
-	grammar3.addRule(S, ext::make_pair(aP, Xb));
-	grammar3.addRule(S, ext::make_pair(aP, bP));
-	grammar3.addRule(aX, ext::make_pair(aP, X));
-	grammar3.addRule(bX, ext::make_pair(bP, X));
-	grammar3.addRule(Xb, ext::make_pair(X, bP));
-	grammar3.addRule(X, ext::make_pair(aP, Y));
-	grammar3.addRule(X, ext::make_pair(bP, Y));
-	grammar3.addRule(X, a);
-	grammar3.addRule(X, b);
-	grammar3.addRule(Y, ext::make_pair(aP, Y));
-	grammar3.addRule(Y, ext::make_pair(bP, Y));
-	grammar3.addRule(Y, a);
-	grammar3.addRule(Y, b);
-	grammar3.addRule(Y, c);
-	grammar3.addRule(aP, a);
-	grammar3.addRule(bP, b);
-	grammar3.addRule(cP, c);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { aX }, ext::vector < ext::variant < char, std::string > > { bX } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { bX } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Xb } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { b } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { aX }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { X } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { bX }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { X } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Xb }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { X }, ext::vector < ext::variant < char, std::string > > { b } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Y } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { Y } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, a);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, b);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Y } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { Y } ) );
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, a);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, b);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, c);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { a }, a);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { b }, b);
+	grammar3.addRule( ext::vector < ext::variant < char, std::string > > { c }, c);
 
 	std::cout << grammar2 << std::endl;
 	std::cout << grammar3 << std::endl;
-- 
GitLab