From bf8c9ecd108530961787908ba37340c917d10600 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Wed, 19 Sep 2018 13:13:51 +0200
Subject: [PATCH] template grammar ToAutomaton algorithm

---
 alib2algo/src/grammar/convert/ToAutomaton.cpp | 116 +-----------------
 alib2algo/src/grammar/convert/ToAutomaton.h   | 104 +++++++++++++++-
 .../grammar/convert/GrammarCFGtoPDATest.cpp   |  64 +++++-----
 3 files changed, 133 insertions(+), 151 deletions(-)

diff --git a/alib2algo/src/grammar/convert/ToAutomaton.cpp b/alib2algo/src/grammar/convert/ToAutomaton.cpp
index 84a1a70abe..80de0d939f 100644
--- a/alib2algo/src/grammar/convert/ToAutomaton.cpp
+++ b/alib2algo/src/grammar/convert/ToAutomaton.cpp
@@ -5,128 +5,16 @@
  * Author: Tomas Pecka
  */
 #include "ToAutomaton.h"
-
-#include <common/createUnique.hpp>
-
-#include <label/InitialStateLabel.h>
-#include <label/FinalStateLabel.h>
 #include <registration/AlgoRegistration.hpp>
 
 namespace grammar {
 
 namespace convert {
 
-automaton::NFA < > ToAutomaton::convert(const grammar::LeftRG < > & grammar) {
-	ext::map<DefaultSymbolType, DefaultStateType> stateMap;
-	ext::set<DefaultStateType> states;
-
-	// step 2
-	for(const auto& symbol : grammar.getNonterminalAlphabet()) {
-		DefaultStateType state ( symbol );
-		states.insert(state);
-		stateMap.insert(std::make_pair(symbol, state));
-	}
-
-	// step 1, 4
-	DefaultStateType q0 = common::createUnique(label::InitialStateLabel::instance < DefaultStateType > ( ), states);
-	states.insert(q0);
-	automaton::NFA < > automaton(q0);
-	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
-	automaton.setStates(states);
-
-	// step 3
-	for(const auto& rule : grammar.getRules()) {
-		const DefaultSymbolType& lhs = rule.first;
-		for(const auto& ruleRHS : rule.second) {
-			if(ruleRHS.is<ext::pair<DefaultSymbolType, DefaultSymbolType>>()) { // if B->Ca => \delta(C,a)=B
-				const ext::pair<DefaultSymbolType, DefaultSymbolType>& rhs = ruleRHS.get<ext::pair<DefaultSymbolType, DefaultSymbolType>>();
-				automaton.addTransition(stateMap.find(rhs.first)->second, rhs.second, stateMap.find(lhs)->second);
-			}
-			else { // if B->a => \delta(StartState,a)=B
-				const DefaultSymbolType& rhs = ruleRHS.get<DefaultSymbolType>();
-				automaton.addTransition(q0, rhs, stateMap.find(lhs)->second);
-			}
-		}
-	}
-
-	// step 5
-	automaton.addFinalState(stateMap.find(grammar.getInitialSymbol())->second);
-	if(grammar.getGeneratesEpsilon())
-		automaton.addFinalState(q0);
-
-	return automaton;
-}
-
-automaton::NFA < > ToAutomaton::convert(const grammar::RightRG < > & grammar) {
-	ext::map<DefaultSymbolType, DefaultStateType> stateMap;
-	ext::set<DefaultStateType> states;
-
-	// step2
-	for(const auto& symbol : grammar.getNonterminalAlphabet()) {
-		DefaultStateType state( symbol );
-		states.insert(state);
-		stateMap.insert(std::make_pair(symbol, state));
-	}
-
-	// step 1, 4
-	DefaultStateType AState = common::createUnique(label::FinalStateLabel::instance < DefaultStateType > ( ), states);
-	states.insert(AState);
-	automaton::NFA < > automaton(stateMap.find(grammar.getInitialSymbol())->second);
-	automaton.setStates(states);
-
-	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
-
-	// step 3
-	for(const auto& rule : grammar.getRules()) {
-		const DefaultSymbolType& lhs = rule.first;
-		for(const auto& ruleRHS : rule.second) {
-			if(ruleRHS.is<ext::pair<DefaultSymbolType, DefaultSymbolType>>()) { // if B->aC => \delta(B,a)=C
-				const ext::pair<DefaultSymbolType, DefaultSymbolType>& rhs = ruleRHS.get<ext::pair<DefaultSymbolType, DefaultSymbolType>>();
-				automaton.addTransition(stateMap.find(lhs)->second, rhs.first, stateMap.find(rhs.second)->second);
-			}
-			else { // if B->a => \delta(B,a)=AState
-				const DefaultSymbolType& rhs = ruleRHS.get<DefaultSymbolType>();
-				automaton.addTransition(stateMap.find(lhs)->second, rhs, AState);
-			}
-		}
-	}
-
-	// step 5
-	automaton.addFinalState(AState);
-	if(grammar.getGeneratesEpsilon())
-		automaton.addFinalState(automaton.getInitialState());
-
-	return automaton;
-}
-
-template <class T>
-automaton::NPDA < > ToAutomaton::convert(const T& grammar) {
-	automaton::NPDA < > automaton(label::InitialStateLabel::instance < DefaultStateType > ( ), grammar.getInitialSymbol());
-
-	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
-
-	automaton.setPushdownStoreAlphabet(grammar.getNonterminalAlphabet());
-	for(const DefaultSymbolType& symbol : grammar.getTerminalAlphabet())
-		automaton.addPushdownStoreSymbol(symbol);
-
-	for(const std::pair<const DefaultSymbolType, ext::set<ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>>>& kv : grammar.getRules())
-		for(const ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>& rhs : kv.second) {
-			ext::vector < DefaultSymbolType > tmp;
-			for ( const ext::variant < DefaultSymbolType, DefaultSymbolType > & symbol : rhs )
-				tmp.push_back ( symbol.get < DefaultSymbolType > ( ) );
-			automaton.addTransition(automaton.getInitialState(), ext::vector<DefaultSymbolType>{kv.first}, automaton.getInitialState(), tmp);
-		}
-
-	for(const DefaultSymbolType& symbol : grammar.getTerminalAlphabet())
-		automaton.addTransition(automaton.getInitialState(), symbol, ext::vector<DefaultSymbolType>{symbol}, automaton.getInitialState(), ext::vector<DefaultSymbolType>{});
-
-	return automaton;
-}
-
 auto ToAutomatonLeftRG = registration::AbstractRegister < ToAutomaton, automaton::NFA < >, const grammar::LeftRG < > & > ( ToAutomaton::convert );
 auto ToAutomatonRightRG = registration::AbstractRegister < ToAutomaton, automaton::NFA < >, const grammar::RightRG < > & > ( ToAutomaton::convert );
-auto ToAutomatonCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < >, const grammar::CFG < > & > ( ToAutomaton::convert );
-auto ToAutomatonEpsilonFreeCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < >, const grammar::EpsilonFreeCFG < > & > ( ToAutomaton::convert );
+auto ToAutomatonCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < DefaultSymbolType, DefaultEpsilonType, ext::variant < DefaultSymbolType, DefaultSymbolType >, unsigned >, const grammar::CFG < > & > ( ToAutomaton::convert );
+auto ToAutomatonEpsilonFreeCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < DefaultSymbolType, DefaultEpsilonType, ext::variant < DefaultSymbolType, DefaultSymbolType >, unsigned >, const grammar::EpsilonFreeCFG < > & > ( ToAutomaton::convert );
 
 } /* namespace convert */
 
diff --git a/alib2algo/src/grammar/convert/ToAutomaton.h b/alib2algo/src/grammar/convert/ToAutomaton.h
index 541b154f79..ee9c818337 100644
--- a/alib2algo/src/grammar/convert/ToAutomaton.h
+++ b/alib2algo/src/grammar/convert/ToAutomaton.h
@@ -8,6 +8,7 @@
 #ifndef _GRAMMAR_TO_AUTOMATON_H_
 #define _GRAMMAR_TO_AUTOMATON_H_
 
+#include <grammar/Grammar.h>
 #include <grammar/Regular/LeftRG.h>
 #include <grammar/Regular/RightRG.h>
 #include <grammar/ContextFree/CFG.h>
@@ -16,6 +17,11 @@
 #include <automaton/FSM/NFA.h>
 #include <automaton/PDA/NPDA.h>
 
+#include <common/createUnique.hpp>
+
+#include <label/InitialStateLabel.h>
+#include <label/FinalStateLabel.h>
+
 namespace grammar {
 
 namespace convert {
@@ -31,13 +37,103 @@ public:
 	 * @param grammar Regular grammar to convert.
 	 * @return FSM equivalent to source grammar.
 	 */
-	static automaton::NFA < > convert(const grammar::LeftRG < > & grammar);
-	static automaton::NFA < > convert(const grammar::RightRG < > & grammar);
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static automaton::NFA < TerminalSymbolType, NonterminalSymbolType > convert(const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar);
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static automaton::NFA < TerminalSymbolType, NonterminalSymbolType > convert(const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar);
 
-	template <class T>
-	static automaton::NPDA < > convert(const T& grammar);
+	template < class T, class TerminalSymbolType = typename grammar::TerminalSymbolTypeOfGrammar < T >, class NonterminalSymbolType = typename grammar::NonterminalSymbolTypeOfGrammar < T > >
+	static automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > convert ( const T & grammar );
 };
 
+template < class TerminalSymbolType, class NonterminalSymbolType >
+automaton::NFA < TerminalSymbolType, NonterminalSymbolType > ToAutomaton::convert(const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar) {
+	// step 1, 4
+	NonterminalSymbolType q0 = common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) );
+	automaton::NFA < TerminalSymbolType, NonterminalSymbolType > automaton ( q0 );
+	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
+	for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) )
+		automaton.addState ( nonterminal );
+
+	// step 3
+	for(const auto& rule : grammar.getRules()) {
+		const NonterminalSymbolType& lhs = rule.first;
+		for(const auto& ruleRHS : rule.second) {
+			if ( ruleRHS.template is < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( ) ) { // if B->Ca => \delta(C,a)=B
+				const ext::pair < NonterminalSymbolType, TerminalSymbolType > & rhs = ruleRHS.template get < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( );
+				automaton.addTransition(rhs.first, rhs.second, lhs);
+			}
+			else { // if B->a => \delta(StartState,a)=B
+				const TerminalSymbolType& rhs = ruleRHS.template get < TerminalSymbolType > ( );
+				automaton.addTransition(q0, rhs, lhs);
+			}
+		}
+	}
+
+	// step 5
+	automaton.addFinalState(grammar.getInitialSymbol());
+	if(grammar.getGeneratesEpsilon())
+		automaton.addFinalState(q0);
+
+	return automaton;
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+automaton::NFA < TerminalSymbolType, NonterminalSymbolType > ToAutomaton::convert(const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar) {
+	// step 1, 4
+	NonterminalSymbolType AState = common::createUnique(label::FinalStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) );
+	automaton::NFA < > automaton(grammar.getInitialSymbol());
+	for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) )
+		automaton.addState ( nonterminal );
+	automaton.addState(AState);
+
+	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
+
+	// step 3
+	for(const auto& rule : grammar.getRules()) {
+		const NonterminalSymbolType& lhs = rule.first;
+		for(const auto& ruleRHS : rule.second) {
+			if ( ruleRHS.template is < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( ) ) { // if B->aC => \delta(B,a)=C
+				const ext::pair < TerminalSymbolType, NonterminalSymbolType > & rhs = ruleRHS.template get < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( );
+				automaton.addTransition(lhs, rhs.first, rhs.second);
+			}
+			else { // if B->a => \delta(B,a)=AState
+				const TerminalSymbolType& rhs = ruleRHS.template get < TerminalSymbolType > ( );
+				automaton.addTransition(lhs, rhs, AState);
+			}
+		}
+	}
+
+	// step 5
+	automaton.addFinalState(AState);
+	if(grammar.getGeneratesEpsilon())
+		automaton.addFinalState(automaton.getInitialState());
+
+	return automaton;
+}
+
+template < class T, class TerminalSymbolType, class NonterminalSymbolType >
+automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > ToAutomaton::convert ( const T & grammar ) {
+	automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > automaton ( label::InitialStateLabel::instance < unsigned > ( ), grammar.getInitialSymbol());
+
+	automaton.setInputAlphabet(grammar.getTerminalAlphabet());
+
+	for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) )
+		automaton.addPushdownStoreSymbol ( nonterminal );
+	for ( const TerminalSymbolType & terminal : grammar.getTerminalAlphabet ( ) )
+		automaton.addPushdownStoreSymbol ( terminal );
+
+	for(const std::pair<const NonterminalSymbolType, ext::set<ext::vector<ext::variant<TerminalSymbolType,NonterminalSymbolType>>>>& kv : grammar.getRules())
+		for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : kv.second ) {
+			automaton.addTransition ( automaton.getInitialState ( ), ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { kv.first }, automaton.getInitialState ( ), rhs );
+		}
+
+	for(const TerminalSymbolType & symbol : grammar.getTerminalAlphabet())
+		automaton.addTransition ( automaton.getInitialState ( ), symbol, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, automaton.getInitialState ( ), ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { } );
+
+	return automaton;
+}
+
 } /* namespace convert */
 
 } /* namespace grammar */
diff --git a/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp b/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp
index f2aab8b5f5..cb6b6bcaa1 100644
--- a/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp
+++ b/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp
@@ -23,43 +23,41 @@ void GrammarCFGtoPDATest::tearDown() {
 void GrammarCFGtoPDATest::testTopDown()
 {
 	{
-		DefaultSymbolType nE = DefaultSymbolType('E');
-		DefaultSymbolType nT = DefaultSymbolType('T');
-		DefaultSymbolType nF = DefaultSymbolType('F');
-
-		DefaultSymbolType tP = DefaultSymbolType('+');
-		DefaultSymbolType tS = DefaultSymbolType('*');
-		DefaultSymbolType tL = DefaultSymbolType('(');
-		DefaultSymbolType tR = DefaultSymbolType(')');
-		DefaultSymbolType tA = DefaultSymbolType('a');
-
-		grammar::CFG < > grammar(nE);
-		grammar.setTerminalAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA});
-		grammar.setNonterminalAlphabet(ext::set<DefaultSymbolType>{nE, nT, nF});
-		grammar.addRule(nE, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nE, tP, nT});
-		grammar.addRule(nE, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nT});
-		grammar.addRule(nT, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nT, tS, nF});
-		grammar.addRule(nT, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nF});
-		grammar.addRule(nF, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{tL, nE, tR});
-		grammar.addRule(nF, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{tA});
+		std::string nE = "E";
+		std::string nT = "T";
+		std::string nF = "F";
+
+		char tP = '+';
+		char tS = '*';
+		char tL = '(';
+		char tR = ')';
+		char tA = 'a';
+
+		grammar::CFG < char, std::string > grammar(nE);
+		grammar.setTerminalAlphabet ( ext::set < char > { tP, tS, tL, tR, tA } );
+		grammar.setNonterminalAlphabet ( ext::set < std::string > { nE, nT, nF } );
+		grammar.addRule ( nE, ext::vector < ext::variant < char, std::string > > { nE, tP, nT } );
+		grammar.addRule ( nE, ext::vector < ext::variant < char, std::string > > { nT } );
+		grammar.addRule ( nT, ext::vector < ext::variant < char, std::string > > { nT, tS, nF } );
+		grammar.addRule ( nT, ext::vector < ext::variant < char, std::string > > { nF } );
+		grammar.addRule ( nF, ext::vector < ext::variant < char, std::string > > { tL, nE, tR } );
+		grammar.addRule ( nF, ext::vector < ext::variant < char, std::string > > { tA } );
 
+		unsigned q = label::InitialStateLabel::instance < unsigned > ( );
 
-		DefaultStateType q = label::InitialStateLabel::instance < DefaultStateType > ( );
+		automaton::NPDA < char, DefaultEpsilonType, ext::variant < char, std::string >, unsigned > pda ( q, nE );
+		pda.setInputAlphabet ( ext::set < char > { tP, tS, tL, tR, tA } );
+		pda.setPushdownStoreAlphabet ( ext::set < ext::variant < char, std::string > > { tP, tS, tL, tR, tA, nE, nT, nF } );
 
-		automaton::NPDA < > pda(q, nE);
-		pda.setStates(ext::set<DefaultStateType>{q});
-		pda.setInputAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA});
-		pda.setPushdownStoreAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA, nE, nT, nF});
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nE }, q, ext::vector < ext::variant < char, std::string > > { nE, tP, nT } );
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nE }, q, ext::vector < ext::variant < char, std::string > > { nT } );
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nT }, q, ext::vector < ext::variant < char, std::string > > { nT, tS, nF } );
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nT }, q, ext::vector < ext::variant < char, std::string > > { nF } );
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nF }, q, ext::vector < ext::variant < char, std::string > > { tL, nE, tR } );
+		pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nF }, q, ext::vector < ext::variant < char, std::string > > { tA } );
 
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nE}, q, ext::vector<DefaultSymbolType>{nE, tP, nT});
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nE}, q, ext::vector<DefaultSymbolType>{nT});
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nT}, q, ext::vector<DefaultSymbolType>{nT, tS, nF});
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nT}, q, ext::vector<DefaultSymbolType>{nF});
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nF}, q, ext::vector<DefaultSymbolType>{tL, nE, tR});
-		pda.addTransition(q, ext::vector<DefaultSymbolType>{nF}, q, ext::vector<DefaultSymbolType>{tA});
-
-		for(const auto& symbol: pda.getInputAlphabet())
-			pda.addTransition(q, symbol, ext::vector<DefaultSymbolType>{symbol}, q, ext::vector<DefaultSymbolType>{});
+		for ( char symbol : pda.getInputAlphabet ( ) )
+			pda.addTransition ( q, symbol, ext::vector<ext::variant < char, std::string >>{symbol}, q, ext::vector<ext::variant < char, std::string >>{});
 
 		CPPUNIT_ASSERT(pda == grammar::convert::ToAutomaton::convert(grammar));
 	}
-- 
GitLab