From 11e167e7e86094906c675ac7331f8c2c22e3ae16 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 6 Dec 2016 08:42:26 +0100
Subject: [PATCH] template Equations solver

---
 .../automaton/convert/ToRegExpAlgebraic.cpp   |   8 +-
 .../equations/LeftRegularEquationSolver.cpp   |  85 ---------
 .../src/equations/LeftRegularEquationSolver.h |  85 ++++++++-
 .../src/equations/RegularEquationSolver.cpp   | 134 --------------
 .../src/equations/RegularEquationSolver.h     | 168 +++++++++++++++---
 .../equations/RightRegularEquationSolver.cpp  |  85 ---------
 .../equations/RightRegularEquationSolver.h    |  85 ++++++++-
 .../src/grammar/convert/ToRegExpAlgebraic.cpp |  61 +------
 .../src/grammar/convert/ToRegExpAlgebraic.h   |  64 ++++++-
 9 files changed, 376 insertions(+), 399 deletions(-)
 delete mode 100644 alib2algo/src/equations/LeftRegularEquationSolver.cpp
 delete mode 100644 alib2algo/src/equations/RegularEquationSolver.cpp
 delete mode 100644 alib2algo/src/equations/RightRegularEquationSolver.cpp

diff --git a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp
index f1da7bc1aa..5c2afe0dd6 100644
--- a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp
+++ b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp
@@ -27,7 +27,7 @@ regexp::RegExp ToRegExpAlgebraic::convert(const automaton::Automaton& automaton)
 }
 
 regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::EpsilonNFA < > & automaton ) {
-	equations::RightRegularEquationSolver solver;
+	equations::RightRegularEquationSolver < alphabet::Symbol > solver;
 
 	// initialize equations
 	for( const auto & q : automaton.getStates( ) )
@@ -56,7 +56,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::Epsilon
 auto ToRegExpAlgebraicEpsilonNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::EpsilonNFA < > >(ToRegExpAlgebraic::convert);
 
 regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::MultiInitialStateNFA < > & automaton ) {
-	equations::RightRegularEquationSolver solver;
+	equations::RightRegularEquationSolver < alphabet::Symbol > solver;
 
 	// initialize equations
 	for( const auto & q : automaton.getStates( ) )
@@ -87,7 +87,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::MultiIn
 auto ToRegExpAlgebraicMultiInitialStateNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::MultiInitialStateNFA < > >(ToRegExpAlgebraic::convert);
 
 regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::NFA < > & automaton ) {
-	equations::RightRegularEquationSolver solver;
+	equations::RightRegularEquationSolver < alphabet::Symbol > solver;
 
 	// initialize equations
 	for( const auto & q : automaton.getStates( ) )
@@ -110,7 +110,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::NFA < >
 auto ToRegExpAlgebraicNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::NFA < > >(ToRegExpAlgebraic::convert);
 
 regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::DFA < > & automaton ) {
-	equations::RightRegularEquationSolver solver;
+	equations::RightRegularEquationSolver < alphabet::Symbol > solver;
 
 	// initialize equations
 	for( const auto & q : automaton.getStates( ) )
diff --git a/alib2algo/src/equations/LeftRegularEquationSolver.cpp b/alib2algo/src/equations/LeftRegularEquationSolver.cpp
deleted file mode 100644
index 6e1eff9147..0000000000
--- a/alib2algo/src/equations/LeftRegularEquationSolver.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * LeftRegularEquationSolver.cpp
- *
- *  Created on: 4. 3. 2014
- *	  Author: Tomas Pecka
- */
-
-#include "LeftRegularEquationSolver.h"
-#include "regexp/unbounded/UnboundedRegExpElements.h"
-
-#include "../regexp/simplify/RegExpOptimize.h"
-
-namespace equations {
-
-regexp::UnboundedRegExp < > LeftRegularEquationSolver::eliminate(void) {
-	for(auto itA = nonterminalSymbolsByDepth.rbegin(); itA != nonterminalSymbolsByDepth.rend(); ++ itA) {
-		const alphabet::Symbol& a = * itA;
-
-		/*
-		 * Apply Arden's Lemma
-		 * A = A0 + B1 + C2
-		 * => A = 10*B + 20*C
-		 */
-		regexp::UnboundedRegExpIteration < alphabet::Symbol > loop(std::move(equationTransition.find(std::make_pair(a, a))->second));
-		regexp::simplify::RegExpOptimize::optimize(loop);
-
-		// for all transitions from A apply Arden's Lemma
-		for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); ++ itB) {
-			const alphabet::Symbol& b = * itB;
-			regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-			concat.appendElement(std::move(equationTransition.find(std::make_pair(a, b))->second));
-			concat.appendElement(loop);
-			regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-			alt.appendElement(std::move(concat));
-			equationTransition.find(std::make_pair(a, b))->second = std::move(alt);
-			regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(a, b))->second);
-		}
-
-		{
-			regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-			concat.appendElement(std::move(equationFinal.find(a)->second));
-			concat.appendElement(std::move(loop));
-			regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-			alt.appendElement(std::move(concat));
-			equationFinal.find(a)->second = std::move(alt);
-			regexp::simplify::RegExpOptimize::optimize(equationFinal.find(a)->second);
-		}
-
-		/*
-		 * eliminate A from rest of the equations using this pattern:
-		 * B->C = B->C + concatenate(B->A, A->C)
-		 */
-		for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); ++ itB) {
-			const alphabet::Symbol& b = * itB;
-
-			for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); ++ itC) {
-				const alphabet::Symbol& c = * itC;
-
-				regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-				concat.appendElement(equationTransition.find(std::make_pair(a, c))->second);
-				concat.appendElement(equationTransition.find(std::make_pair(b, a))->second);
-				regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-				alt.appendElement(std::move(equationTransition.find(std::make_pair(b, c))->second));
-				alt.appendElement(std::move(concat));
-				equationTransition.find(std::make_pair(b, c))->second = std::move(alt);
-				regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(b, c))->second);
-			}
-
-			{
-				regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-				concat.appendElement(equationFinal.find(a)->second);
-				concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second));
-				regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-				alt.appendElement(std::move(equationFinal.find(b)->second));
-				alt.appendElement(std::move(concat));
-				equationFinal.find(b)->second = std::move(alt);
-				regexp::simplify::RegExpOptimize::optimize(equationFinal.find(b)->second);
-			}
-		}
-	}
-
-	return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < alphabet::Symbol > (std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second))));
-}
-
-} /* namespace equations */
diff --git a/alib2algo/src/equations/LeftRegularEquationSolver.h b/alib2algo/src/equations/LeftRegularEquationSolver.h
index a4de207c74..fdb18f60af 100644
--- a/alib2algo/src/equations/LeftRegularEquationSolver.h
+++ b/alib2algo/src/equations/LeftRegularEquationSolver.h
@@ -5,21 +5,96 @@ LeftghtRegularEquationSolver.h
  *	  Author: Tomas Pecka
  */
 
-#ifndef LEFTREGULAREQUATIONSOLVER_H_
-#define LEFTREGULAREQUATIONSOLVER_H_
+#ifndef LEFT_REGULAR_EQUATIONS_SOLVER_H_
+#define LEFT_REGULAR_EQUATIONS_SOLVER_H_
 
 #include "RegularEquationSolver.h"
+#include "regexp/unbounded/UnboundedRegExpElements.h"
+
+#include <regexp/simplify/RegExpOptimize.h>
 
 namespace equations {
 
-class LeftRegularEquationSolver : public RegularEquationSolver {
+template < class SymbolType >
+class LeftRegularEquationSolver : public RegularEquationSolver < SymbolType > {
 	/**
 	 * @copydoc RegularEquationSolver::eliminate(void)
 	 */
-	virtual regexp::UnboundedRegExp < > eliminate( void );
+	virtual regexp::UnboundedRegExp < SymbolType > eliminate( void );
 
 };
 
+template < class SymbolType >
+regexp::UnboundedRegExp < SymbolType > LeftRegularEquationSolver < SymbolType >::eliminate(void) {
+	for(auto itA = this->nonterminalSymbolsByDepth.rbegin(); itA != this->nonterminalSymbolsByDepth.rend(); ++ itA) {
+		const SymbolType& a = * itA;
+
+		/*
+		 * Apply Arden's Lemma
+		 * A = A0 + B1 + C2
+		 * => A = 10*B + 20*C
+		 */
+		regexp::UnboundedRegExpIteration < SymbolType > loop(std::move(this->equationTransition.find(std::make_pair(a, a))->second));
+		regexp::simplify::RegExpOptimize::optimize(loop);
+
+		// for all transitions from A apply Arden's Lemma
+		for(auto itB = std::next(itA) ; itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) {
+			const SymbolType& b = * itB;
+			regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+			concat.appendElement(std::move(this->equationTransition.find(std::make_pair(a, b))->second));
+			concat.appendElement(loop);
+			regexp::UnboundedRegExpAlternation < SymbolType > alt;
+			alt.appendElement(std::move(concat));
+			this->equationTransition.find(std::make_pair(a, b))->second = std::move(alt);
+			regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(a, b))->second);
+		}
+
+		{
+			regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+			concat.appendElement(std::move(this->equationFinal.find(a)->second));
+			concat.appendElement(std::move(loop));
+			regexp::UnboundedRegExpAlternation < SymbolType > alt;
+			alt.appendElement(std::move(concat));
+			this->equationFinal.find(a)->second = std::move(alt);
+			regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(a)->second);
+		}
+
+		/*
+		 * eliminate A from rest of the equations using this pattern:
+		 * B->C = B->C + concatenate(B->A, A->C)
+		 */
+		for(auto itB = std::next(itA); itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) {
+			const SymbolType& b = * itB;
+
+			for(auto itC = std::next(itA); itC != this->nonterminalSymbolsByDepth.rend(); ++ itC) {
+				const SymbolType& c = * itC;
+
+				regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+				concat.appendElement(this->equationTransition.find(std::make_pair(a, c))->second);
+				concat.appendElement(this->equationTransition.find(std::make_pair(b, a))->second);
+				regexp::UnboundedRegExpAlternation < SymbolType > alt;
+				alt.appendElement(std::move(this->equationTransition.find(std::make_pair(b, c))->second));
+				alt.appendElement(std::move(concat));
+				this->equationTransition.find(std::make_pair(b, c))->second = std::move(alt);
+				regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(b, c))->second);
+			}
+
+			{
+				regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+				concat.appendElement(this->equationFinal.find(a)->second);
+				concat.appendElement(std::move(this->equationTransition.find(std::make_pair(b, a))->second));
+				regexp::UnboundedRegExpAlternation < SymbolType > alt;
+				alt.appendElement(std::move(this->equationFinal.find(b)->second));
+				alt.appendElement(std::move(concat));
+				this->equationFinal.find(b)->second = std::move(alt);
+				regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(b)->second);
+			}
+		}
+	}
+
+	return regexp::UnboundedRegExp < SymbolType > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < SymbolType > (std::move( this->equationFinal.find(*this->nonterminalSymbolsByDepth.begin())->second))));
+}
+
 } /* namespace equations */
 
-#endif /* LEFTREGULAREQUATIONSOLVER_H_ */
+#endif /* LEFT_REGULAR_EQUATIONS_SOLVER_H_ */
diff --git a/alib2algo/src/equations/RegularEquationSolver.cpp b/alib2algo/src/equations/RegularEquationSolver.cpp
deleted file mode 100644
index 25bb443842..0000000000
--- a/alib2algo/src/equations/RegularEquationSolver.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * RegularEquationSolver.cpp
- *
- *  Created on: 4. 3. 2014
- *	  Author: Tomas Pecka
- */
-
-#include "RegularEquationSolver.h"
-#include <regexp/unbounded/UnboundedRegExpElements.h>
-
-#include <exception/CommonException.h>
-#include <algorithm>
-
-namespace equations {
-
-void RegularEquationSolver::setSymbols(const std::set<alphabet::Symbol>& newSymbols) {
-	std::set<alphabet::Symbol> removed, added;
-	
-	std::set_difference(nonterminalSymbols.begin(), nonterminalSymbols.end(), newSymbols.begin(), newSymbols.end(), std::inserter(removed, removed.end()));
-	std::set_difference(newSymbols.begin(), newSymbols.end(), nonterminalSymbols.begin(), nonterminalSymbols.end(), std::inserter(added, added.end()));
-
-	for(const auto& symb : removed) {
-		removeSymbol(symb);
-	}
-
-	for(const auto& symb : added) {
-		addSymbol(symb);
-	}
-}
-
-void RegularEquationSolver::removeSymbol(const alphabet::Symbol& symb) {
-	for(const auto& kv : equationTransition) {
-		const alphabet::Symbol& from = kv.first.first;
-		const alphabet::Symbol& to = kv.first.second;
-		const regexp::UnboundedRegExpAlternation < alphabet::Symbol > & alt = kv.second;
-
-		if((from == symb || to == symb) && alt.getElements().size() != 0) {
-			throw exception::CommonException("Symbol '" + (std::string) symb + "' is in use.");
-		}
-	}
-
-	for(const auto& kv : equationFinal) {
-		const alphabet::Symbol& from = kv.first;
-		const regexp::UnboundedRegExpAlternation < alphabet::Symbol > & alt = kv.second;
-
-		if(from == symb && alt.getElements().size() != 0) {
-			throw exception::CommonException("Symbol '" + (std::string) from + "' is in use.");
-		}
-	}
-
-
-	nonterminalSymbols.erase(nonterminalSymbols.find(symb));
-	equationFinal.erase(equationFinal.find(symb));
-
-	for(const auto& s : nonterminalSymbols) {
-		equationTransition.erase(equationTransition.find(std::make_pair(s, symb)));
-		equationTransition.erase(equationTransition.find(std::make_pair(symb, s)));
-	}
-	equationTransition.erase(equationTransition.find(std::make_pair(symb, symb)));
-}
-
-void RegularEquationSolver::addSymbol(const alphabet::Symbol& symb) {
-	for(const auto& s : nonterminalSymbols) {
-		equationTransition.insert(std::make_pair(std::make_pair(symb, s), regexp::UnboundedRegExpAlternation < alphabet::Symbol >  { }));
-		equationTransition.insert(std::make_pair(std::make_pair(s, symb), regexp::UnboundedRegExpAlternation < alphabet::Symbol >  { }));
-	}
-	equationTransition.insert(std::make_pair(std::make_pair(symb, symb), regexp::UnboundedRegExpAlternation < alphabet::Symbol >  { }));
-
-	nonterminalSymbols.insert(symb);
-	equationFinal.insert(std::make_pair(symb, regexp::UnboundedRegExpAlternation < alphabet::Symbol >  { }));
-}
-
-void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq) {
-	if(nonterminalSymbols.count(from) == 0) {
-		throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system.");
-	}
-
-	if(nonterminalSymbols.count(to) == 0) {
-		throw exception::CommonException("Symbol to ('" + (std::string) to + "') is not in equation system.");
-	}
-
-	equationTransition.find(std::make_pair(from, to))->second.appendElement(eq);
-}
-
-void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq) {
-	if(nonterminalSymbols.count(from) == 0) {
-		throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system.");
-	}
-
-	equationFinal.find(from)->second.appendElement(eq);
-}
-
-void RegularEquationSolver::sortSymbolsByDepth(const alphabet::Symbol& solveFor) {
-	std::map<alphabet::Symbol, bool> visited;
-	std::queue<alphabet::Symbol> queue;
-
-	for(const auto& symbol : nonterminalSymbols) {
-		visited[symbol] = false;
-	}
-
-	visited[solveFor] = true;
-	queue.push(solveFor);
-
-	while(! queue.empty()) {
-		alphabet::Symbol s = queue.front();
-		queue.pop();
-
-		nonterminalSymbolsByDepth.push_back(s);
-
-		for(const auto& kv : equationTransition) {
-			// find all transitions from current symbol that are non-empty, enqueue transition's target symbol
-			if(kv.first.first == s && visited[ kv.first.second ] == false && kv.second.getElements().size() > 0) {
-				visited[kv.first.second] = true;
-				queue.push(kv.first.second);
-			}
-		}
-	}
-}
-
-regexp::UnboundedRegExp < > RegularEquationSolver::solve(const alphabet::Symbol& solveFor) {
-	if(nonterminalSymbols.count(solveFor) == 0) {
-		throw exception::CommonException("Symbol solveFor ('" + (std::string) solveFor + "') is not in equation system.");
-	}
-
-	/*
-	 * Firstly, organize states by depth so we can output better looking
-	 * expressions. We need to solve equation system for automaton's initial state,
-	 * so lets start with the deepest ones and walk towards the initial one.
-	 */
-	sortSymbolsByDepth(solveFor);
-	return eliminate();
-}
-
-} /* namespace equations */
diff --git a/alib2algo/src/equations/RegularEquationSolver.h b/alib2algo/src/equations/RegularEquationSolver.h
index 2efe44f826..e23a332e3d 100644
--- a/alib2algo/src/equations/RegularEquationSolver.h
+++ b/alib2algo/src/equations/RegularEquationSolver.h
@@ -5,31 +5,34 @@
  *	  Author: Tomas Pecka
  */
 
-#ifndef REGULAREQUATIONSOLVER_H_
-#define REGULAREQUATIONSOLVER_H_
-
-#include <regexp/unbounded/UnboundedRegExp.h>
-#include <regexp/unbounded/UnboundedRegExpElement.h>
-#include <alphabet/Symbol.h>
+#ifndef REGULAR_EQUATIONS_SOLVER_H_
+#define REGULAR_EQUATIONS_SOLVER_H_
 
+#include <algorithm>
 #include <map>
 #include <deque>
 #include <queue>
 
+#include <exception/CommonException.h>
+
+#include <regexp/unbounded/UnboundedRegExp.h>
+#include <regexp/unbounded/UnboundedRegExpElement.h>
+#include <regexp/unbounded/UnboundedRegExpElements.h>
+
 namespace equations {
 
 /**
  * Base class for regular equations solvers.
  */
+template < class SymbolType >
 class RegularEquationSolver {
 public:
 	/**
 	 * Adds nonterminal symbol into system.
 	 *
 	 * @param symb given symbol
-	 * @
 	 */
-	void addSymbol(const alphabet::Symbol& symbol);
+	void addSymbol(const SymbolType& symbol);
 
 	/**
 	 * Removes nonterminal symbol from equation system.
@@ -37,14 +40,14 @@ public:
 	 * @param symb given symbol
 	 * @throws CommonException when symbol is in use
 	 */
-	void removeSymbol(const alphabet::Symbol& symbol);
+	void removeSymbol(const SymbolType& symbol);
 
 	/**
 	 * Sets nonterminal symbols of the equation system.
 	 * @param symbol Symbols to set
 	 * @throws CommonException
 	 */
-	void setSymbols(const std::set<alphabet::Symbol>& symbols);
+	void setSymbols(const std::set<SymbolType>& symbols);
 
 	/**
 	 * Adds equation in form FROM = eq TO
@@ -53,7 +56,7 @@ public:
 	 * @param to symbol
 	 * @param eq equation
 	 */
-	void addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq);
+	void addEquation(const SymbolType& from, const SymbolType& to, const regexp::UnboundedRegExpElement < SymbolType > & eq);
 
 	/**
 	 * Adds equation in form: FROM = eq
@@ -61,7 +64,7 @@ public:
 	 * @param from
 	 * @param eq
 	 */
-	void addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq);
+	void addEquation(const SymbolType& from, const regexp::UnboundedRegExpElement < SymbolType > & eq);
 
 	/**
 	 * Solve expression system
@@ -69,42 +72,167 @@ public:
 	 * @param solveFor will solve equation system for given symbol
 	 * @return regexp
 	 */
-	regexp::UnboundedRegExp < > solve(const alphabet::Symbol& solveFor);
+	regexp::UnboundedRegExp < SymbolType > solve(const SymbolType& solveFor);
 
 protected:
 	/**
 	 * actual equations elimination
 	 * @return pointer to solutions RegExp tree root
 	 */
-	virtual regexp::UnboundedRegExp < > eliminate(void) = 0;
+	virtual regexp::UnboundedRegExp < SymbolType > eliminate(void) = 0;
 
 	/**
 	 * Runs BFS to determine depth of symbols in equation system and stores it in nonterminalSymbolsByDepth;
 	 * @see nonterminalSymbolsByDepth
 	 */
-	void sortSymbolsByDepth(const alphabet::Symbol& solveFor);
+	void sortSymbolsByDepth(const SymbolType& solveFor);
 
 	/**
 	 * @see symbolsByDepth
 	 */
-	std::deque<alphabet::Symbol> nonterminalSymbolsByDepth;
+	std::deque<SymbolType> nonterminalSymbolsByDepth;
 
 	/**
 	 * Stores transitions from nonterminal to nonterminal, eg A = 2A + 2B + 1C
 	 */
-	std::map<std::pair<alphabet::Symbol, alphabet::Symbol>, regexp::UnboundedRegExpAlternation < alphabet::Symbol > > equationTransition;
+	std::map<std::pair<SymbolType, SymbolType>, regexp::UnboundedRegExpAlternation < SymbolType > > equationTransition;
 
 	/**
 	 * Stores equation not going to particular nonterminal, eg A = 01*
 	 */
-	std::map<alphabet::Symbol, regexp::UnboundedRegExpAlternation < alphabet::Symbol > > equationFinal;
+	std::map<SymbolType, regexp::UnboundedRegExpAlternation < SymbolType > > equationFinal;
 
 	/**
 	 * Set of symbols
 	 */
-	std::set<alphabet::Symbol> nonterminalSymbols;
+	std::set<SymbolType> nonterminalSymbols;
 };
 
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::setSymbols(const std::set<SymbolType>& newSymbols) {
+	std::set<SymbolType> removed, added;
+
+	std::set_difference(nonterminalSymbols.begin(), nonterminalSymbols.end(), newSymbols.begin(), newSymbols.end(), std::inserter(removed, removed.end()));
+	std::set_difference(newSymbols.begin(), newSymbols.end(), nonterminalSymbols.begin(), nonterminalSymbols.end(), std::inserter(added, added.end()));
+
+	for(const auto& symb : removed) {
+		removeSymbol(symb);
+	}
+
+	for(const auto& symb : added) {
+		addSymbol(symb);
+	}
+}
+
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::removeSymbol(const SymbolType& symb) {
+	for(const auto& kv : equationTransition) {
+		const SymbolType& from = kv.first.first;
+		const SymbolType& to = kv.first.second;
+		const regexp::UnboundedRegExpAlternation < SymbolType > & alt = kv.second;
+
+		if((from == symb || to == symb) && alt.getElements().size() != 0) {
+			throw exception::CommonException("Symbol '" + (std::string) symb + "' is in use.");
+		}
+	}
+
+	for(const auto& kv : equationFinal) {
+		const SymbolType& from = kv.first;
+		const regexp::UnboundedRegExpAlternation < SymbolType > & alt = kv.second;
+
+		if(from == symb && alt.getElements().size() != 0) {
+			throw exception::CommonException("Symbol '" + (std::string) from + "' is in use.");
+		}
+	}
+
+
+	nonterminalSymbols.erase(nonterminalSymbols.find(symb));
+	equationFinal.erase(equationFinal.find(symb));
+
+	for(const auto& s : nonterminalSymbols) {
+		equationTransition.erase(equationTransition.find(std::make_pair(s, symb)));
+		equationTransition.erase(equationTransition.find(std::make_pair(symb, s)));
+	}
+	equationTransition.erase(equationTransition.find(std::make_pair(symb, symb)));
+}
+
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::addSymbol(const SymbolType& symb) {
+	for(const auto& s : nonterminalSymbols) {
+		equationTransition.insert(std::make_pair(std::make_pair(symb, s), regexp::UnboundedRegExpAlternation < SymbolType >  { }));
+		equationTransition.insert(std::make_pair(std::make_pair(s, symb), regexp::UnboundedRegExpAlternation < SymbolType >  { }));
+	}
+	equationTransition.insert(std::make_pair(std::make_pair(symb, symb), regexp::UnboundedRegExpAlternation < SymbolType >  { }));
+
+	nonterminalSymbols.insert(symb);
+	equationFinal.insert(std::make_pair(symb, regexp::UnboundedRegExpAlternation < SymbolType >  { }));
+}
+
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::addEquation(const SymbolType& from, const SymbolType& to, const regexp::UnboundedRegExpElement < SymbolType > & eq) {
+	if(nonterminalSymbols.count(from) == 0) {
+		throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system.");
+	}
+
+	if(nonterminalSymbols.count(to) == 0) {
+		throw exception::CommonException("Symbol to ('" + (std::string) to + "') is not in equation system.");
+	}
+
+	equationTransition.find(std::make_pair(from, to))->second.appendElement(eq);
+}
+
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::addEquation(const SymbolType& from, const regexp::UnboundedRegExpElement < SymbolType > & eq) {
+	if(nonterminalSymbols.count(from) == 0) {
+		throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system.");
+	}
+
+	equationFinal.find(from)->second.appendElement(eq);
+}
+
+template < class SymbolType >
+void RegularEquationSolver < SymbolType >::sortSymbolsByDepth(const SymbolType& solveFor) {
+	std::map<SymbolType, bool> visited;
+	std::queue<SymbolType> queue;
+
+	for(const auto& symbol : nonterminalSymbols) {
+		visited[symbol] = false;
+	}
+
+	visited[solveFor] = true;
+	queue.push(solveFor);
+
+	while(! queue.empty()) {
+		SymbolType s = queue.front();
+		queue.pop();
+
+		nonterminalSymbolsByDepth.push_back(s);
+
+		for(const auto& kv : equationTransition) {
+			// find all transitions from current symbol that are non-empty, enqueue transition's target symbol
+			if(kv.first.first == s && visited[ kv.first.second ] == false && kv.second.getElements().size() > 0) {
+				visited[kv.first.second] = true;
+				queue.push(kv.first.second);
+			}
+		}
+	}
+}
+
+template < class SymbolType >
+regexp::UnboundedRegExp < SymbolType > RegularEquationSolver < SymbolType >::solve(const SymbolType& solveFor) {
+	if(nonterminalSymbols.count(solveFor) == 0) {
+		throw exception::CommonException("Symbol solveFor ('" + (std::string) solveFor + "') is not in equation system.");
+	}
+
+	/*
+	 * Firstly, organize states by depth so we can output better looking
+	 * expressions. We need to solve equation system for automaton's initial state,
+	 * so lets start with the deepest ones and walk towards the initial one.
+	 */
+	sortSymbolsByDepth(solveFor);
+	return eliminate();
+}
+
 } /* namespace equations */
 
-#endif /* REGULAREQUATIONSOLVER_H_ */
+#endif /* REGULAR_EQUATIONS_SOLVER_H_ */
diff --git a/alib2algo/src/equations/RightRegularEquationSolver.cpp b/alib2algo/src/equations/RightRegularEquationSolver.cpp
deleted file mode 100644
index aa32ad7b38..0000000000
--- a/alib2algo/src/equations/RightRegularEquationSolver.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * RightRegularEquationSolver.cpp
- *
- *  Created on: 4. 3. 2014
- *	  Author: Tomas Pecka
- */
-
-#include "RightRegularEquationSolver.h"
-#include "regexp/unbounded/UnboundedRegExpElements.h"
-
-#include "../regexp/simplify/RegExpOptimize.h"
-
-namespace equations {
-
-regexp::UnboundedRegExp < > RightRegularEquationSolver::eliminate(void) {
-	for(auto itA = nonterminalSymbolsByDepth.rbegin(); itA != nonterminalSymbolsByDepth.rend(); ++ itA) {
-		const alphabet::Symbol& a = * itA;
-
-		/*
-		 * Apply Arden's Lemma
-		 * A = 0A + 1B + 2C
-		 * => A = 0*1B + 0*2C
-		 */
-		regexp::UnboundedRegExpIteration < alphabet::Symbol > loop(std::move(equationTransition.find(std::make_pair(a, a))->second));
-		regexp::simplify::RegExpOptimize::optimize(loop);
-
-		// for all transitions from A apply Arden's Lemma
-		for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); ++ itB) {
-			const alphabet::Symbol& b = * itB;
-			regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-			concat.appendElement(loop);
-			concat.appendElement(std::move(equationTransition.find(std::make_pair(a,b))->second));
-			regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-			alt.appendElement(std::move(concat));
-			equationTransition.find(std::make_pair(a, b))->second = std::move(alt);
-			regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(a, b))->second);
-		}
-
-		{
-			regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-			concat.appendElement(std::move(loop));
-			concat.appendElement(std::move(equationFinal.find(a)->second));
-			regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-			alt.appendElement(std::move(concat));
-			equationFinal.find(a)->second = std::move(alt);
-			regexp::simplify::RegExpOptimize::optimize(equationFinal.find(a)->second);
-		}
-
-		/*
-		 * eliminate A from rest of the equations using this pattern:
-		 * B->C = B->C + concatenate(B->A, A->C)
-		 */
-		for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); ++ itB) {
-			const alphabet::Symbol& b = * itB;
-
-			for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); ++ itC) {
-				const alphabet::Symbol& c = * itC;
-
-				regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-				concat.appendElement(equationTransition.find(std::make_pair(b, a))->second);
-				concat.appendElement(equationTransition.find(std::make_pair(a, c))->second);
-				regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-				alt.appendElement(std::move(equationTransition.find(std::make_pair(b, c))->second));
-				alt.appendElement(std::move(concat));
-				equationTransition.find(std::make_pair(b, c))->second = std::move(alt);
-				regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(b, c))->second);
-			}
-
-			{
-				regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat;
-				concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second));
-				concat.appendElement(equationFinal.find(a)->second);
-				regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt;
-				alt.appendElement(std::move(equationFinal.find(b)->second));
-				alt.appendElement(std::move(concat));
-				equationFinal.find(b)->second = std::move(alt);
-				regexp::simplify::RegExpOptimize::optimize(equationFinal.find(b)->second);
-			}
-		}
-	}
-
-	return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < alphabet::Symbol > (std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second))));
-}
-
-} /* namespace equations */
diff --git a/alib2algo/src/equations/RightRegularEquationSolver.h b/alib2algo/src/equations/RightRegularEquationSolver.h
index 1a4cf23cb7..bcbec40f44 100644
--- a/alib2algo/src/equations/RightRegularEquationSolver.h
+++ b/alib2algo/src/equations/RightRegularEquationSolver.h
@@ -5,21 +5,96 @@
  *	  Author: Tomas Pecka
  */
 
-#ifndef RIGHTREGULAREQUATIONSOLVER_H_
-#define RIGHTREGULAREQUATIONSOLVER_H_
+#ifndef RIGHT_REGULAR_EQUATIONS_SOLVER_H_
+#define RIGHT_REGULAR_EQUATIONS_SOLVER_H_
 
 #include "RegularEquationSolver.h"
+#include "regexp/unbounded/UnboundedRegExpElements.h"
+
+#include <regexp/simplify/RegExpOptimize.h>
 
 namespace equations {
 
-class RightRegularEquationSolver : public RegularEquationSolver {
+template < class SymbolType >
+class RightRegularEquationSolver : public RegularEquationSolver < SymbolType > {
 	/**
 	 * @copydoc RegularEquationSolver::eliminate(void)
 	 */
-	virtual regexp::UnboundedRegExp < > eliminate( void );
+	virtual regexp::UnboundedRegExp < SymbolType > eliminate( void );
 
 };
 
+template < class SymbolType >
+regexp::UnboundedRegExp < SymbolType > RightRegularEquationSolver < SymbolType >::eliminate(void) {
+	for(auto itA = this->nonterminalSymbolsByDepth.rbegin(); itA != this->nonterminalSymbolsByDepth.rend(); ++ itA) {
+		const SymbolType& a = * itA;
+
+		/*
+		 * Apply Arden's Lemma
+		 * A = 0A + 1B + 2C
+		 * => A = 0*1B + 0*2C
+		 */
+		regexp::UnboundedRegExpIteration < SymbolType > loop(std::move(this->equationTransition.find(std::make_pair(a, a))->second));
+		regexp::simplify::RegExpOptimize::optimize(loop);
+
+		// for all transitions from A apply Arden's Lemma
+		for(auto itB = std::next(itA) ; itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) {
+			const SymbolType& b = * itB;
+			regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+			concat.appendElement(loop);
+			concat.appendElement(std::move(this->equationTransition.find(std::make_pair(a,b))->second));
+			regexp::UnboundedRegExpAlternation < SymbolType > alt;
+			alt.appendElement(std::move(concat));
+			this->equationTransition.find(std::make_pair(a, b))->second = std::move(alt);
+			regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(a, b))->second);
+		}
+
+		{
+			regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+			concat.appendElement(std::move(loop));
+			concat.appendElement(std::move(this->equationFinal.find(a)->second));
+			regexp::UnboundedRegExpAlternation < SymbolType > alt;
+			alt.appendElement(std::move(concat));
+			this->equationFinal.find(a)->second = std::move(alt);
+			regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(a)->second);
+		}
+
+		/*
+		 * eliminate A from rest of the equations using this pattern:
+		 * B->C = B->C + concatenate(B->A, A->C)
+		 */
+		for(auto itB = std::next(itA); itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) {
+			const SymbolType& b = * itB;
+
+			for(auto itC = std::next(itA); itC != this->nonterminalSymbolsByDepth.rend(); ++ itC) {
+				const SymbolType& c = * itC;
+
+				regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+				concat.appendElement(this->equationTransition.find(std::make_pair(b, a))->second);
+				concat.appendElement(this->equationTransition.find(std::make_pair(a, c))->second);
+				regexp::UnboundedRegExpAlternation < SymbolType > alt;
+				alt.appendElement(std::move(this->equationTransition.find(std::make_pair(b, c))->second));
+				alt.appendElement(std::move(concat));
+				this->equationTransition.find(std::make_pair(b, c))->second = std::move(alt);
+				regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(b, c))->second);
+			}
+
+			{
+				regexp::UnboundedRegExpConcatenation < SymbolType > concat;
+				concat.appendElement(std::move(this->equationTransition.find(std::make_pair(b, a))->second));
+				concat.appendElement(this->equationFinal.find(a)->second);
+				regexp::UnboundedRegExpAlternation < SymbolType > alt;
+				alt.appendElement(std::move(this->equationFinal.find(b)->second));
+				alt.appendElement(std::move(concat));
+				this->equationFinal.find(b)->second = std::move(alt);
+				regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(b)->second);
+			}
+		}
+	}
+
+	return regexp::UnboundedRegExp < SymbolType > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < SymbolType > (std::move( this->equationFinal.find(*this->nonterminalSymbolsByDepth.begin())->second))));
+}
+
 } /* namespace equations */
 
-#endif /* RIGHTREGULAREQUATIONSOLVER_H_ */
+#endif /* RIGHT_REGULAR_EQUATIONS_SOLVER_H_ */
diff --git a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp
index a424fb484c..a1203f3896 100644
--- a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp
+++ b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp
@@ -7,12 +7,6 @@
 
 #include "ToRegExpAlgebraic.h"
 
-#include "../../equations/LeftRegularEquationSolver.h"
-#include "../../equations/RightRegularEquationSolver.h"
-
-#include <regexp/unbounded/UnboundedRegExp.h>
-#include <regexp/unbounded/UnboundedRegExpElements.h>
-
 namespace grammar {
 
 namespace convert {
@@ -21,59 +15,8 @@ regexp::RegExp ToRegExpAlgebraic::convert(const grammar::Grammar& grammar) {
 	return dispatch(grammar.getData());
 }
 
-regexp::RegExp ToRegExpAlgebraic::convert(const grammar::LeftRG < > & grammar) {
-	equations::LeftRegularEquationSolver solver;
-
-	for(const auto& symbol : grammar.getNonterminalAlphabet())
-		solver.addSymbol(symbol);
-
-	for(const auto & rule : grammar.getRules()) {
-		const alphabet::Symbol& lhs = rule.first;
-
-		for(const auto& ruleRHS : rule.second) {
-			if(ruleRHS.is<alphabet::Symbol>()) {
-				const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>();
-				solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs));
-			} else {
-				const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>();
-				solver.addEquation(lhs, rhs.first, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs.second));
-			}
-		}
-	}
-	if(grammar.getGeneratesEpsilon())
-		solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < alphabet::Symbol > ());
-
-	return regexp::RegExp{solver.solve(grammar.getInitialSymbol())};
-}
-
-auto ToRegExpAlgebraicLeftRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::RegExp, grammar::LeftRG < > >(ToRegExpAlgebraic::convert);
-
-regexp::RegExp ToRegExpAlgebraic::convert(const grammar::RightRG < > & grammar) {
-	equations::RightRegularEquationSolver solver;
-
-	for(const auto& symbol : grammar.getNonterminalAlphabet())
-		solver.addSymbol(symbol);
-
-	for(const auto & rule : grammar.getRules()) {
-		const alphabet::Symbol& lhs = rule.first;
-
-		for(const auto& ruleRHS : rule.second) {
-			if(ruleRHS.is<alphabet::Symbol>()) {
-				const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>();
-				solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs));
-			} else {
-				const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>();
-				solver.addEquation(lhs, rhs.second, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs.first));
-			}
-		}
-	}
-	if(grammar.getGeneratesEpsilon())
-		solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < alphabet::Symbol > ());
-
-	return regexp::RegExp{solver.solve(grammar.getInitialSymbol())};
-}
-
-auto ToRegExpAlgebraicRightRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::RegExp, grammar::RightRG < > >(ToRegExpAlgebraic::convert);
+auto ToRegExpAlgebraicLeftRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, grammar::LeftRG < > >(ToRegExpAlgebraic::convert);
+auto ToRegExpAlgebraicRightRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, grammar::RightRG < > >(ToRegExpAlgebraic::convert);
 
 } /* namespace convert */
 
diff --git a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h
index a2db458e5f..51d2da4c64 100644
--- a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h
+++ b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h
@@ -16,6 +16,12 @@
 
 #include <regexp/RegExp.h>
 
+#include <equations/LeftRegularEquationSolver.h>
+#include <equations/RightRegularEquationSolver.h>
+
+#include <regexp/unbounded/UnboundedRegExp.h>
+#include <regexp/unbounded/UnboundedRegExpElements.h>
+
 namespace grammar {
 
 namespace convert {
@@ -28,10 +34,64 @@ public:
 	 */
 	static regexp::RegExp convert(const grammar::Grammar& grammar);
 
-	static regexp::RegExp convert(const grammar::RightRG < > & grammar);
-	static regexp::RegExp convert(const grammar::LeftRG < > & grammar);
+	template < class SymbolType >
+	static regexp::UnboundedRegExp < SymbolType > convert(const grammar::RightRG < SymbolType > & grammar);
+	template < class SymbolType >
+	static regexp::UnboundedRegExp < SymbolType > convert(const grammar::LeftRG < SymbolType > & grammar);
 };
 
+template < class SymbolType >
+regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert(const grammar::LeftRG < SymbolType > & grammar) {
+	equations::LeftRegularEquationSolver < SymbolType > solver;
+
+	for(const auto& symbol : grammar.getNonterminalAlphabet())
+		solver.addSymbol(symbol);
+
+	for(const auto & rule : grammar.getRules()) {
+		const SymbolType& lhs = rule.first;
+
+		for(const auto& ruleRHS : rule.second) {
+			if(ruleRHS.template is<SymbolType>()) {
+				const SymbolType& rhs = ruleRHS.template get<SymbolType>();
+				solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < SymbolType > (rhs));
+			} else {
+				const std::pair<SymbolType, SymbolType>& rhs = ruleRHS.template get<std::pair<SymbolType, SymbolType>>();
+				solver.addEquation(lhs, rhs.first, regexp::UnboundedRegExpSymbol < SymbolType > (rhs.second));
+			}
+		}
+	}
+	if(grammar.getGeneratesEpsilon())
+		solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < SymbolType > ());
+
+	return solver.solve(grammar.getInitialSymbol());
+}
+
+template < class SymbolType >
+regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert(const grammar::RightRG < SymbolType > & grammar) {
+	equations::RightRegularEquationSolver < SymbolType > solver;
+
+	for(const auto& symbol : grammar.getNonterminalAlphabet())
+		solver.addSymbol(symbol);
+
+	for(const auto & rule : grammar.getRules()) {
+		const SymbolType& lhs = rule.first;
+
+		for(const auto& ruleRHS : rule.second) {
+			if(ruleRHS.template is<SymbolType>()) {
+				const SymbolType& rhs = ruleRHS.template get<SymbolType>();
+				solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < SymbolType > (rhs));
+			} else {
+				const std::pair<SymbolType, SymbolType>& rhs = ruleRHS.template get<std::pair<SymbolType, SymbolType>>();
+				solver.addEquation(lhs, rhs.second, regexp::UnboundedRegExpSymbol < SymbolType > (rhs.first));
+			}
+		}
+	}
+	if(grammar.getGeneratesEpsilon())
+		solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < SymbolType > ());
+
+	return solver.solve(grammar.getInitialSymbol());
+}
+
 } /* namespace covert */
 
 } /* namespace grammar */
-- 
GitLab