From bc250a225f172d3102d46801452f7d08865e3e73 Mon Sep 17 00:00:00 2001
From: Tomas Pecka <tomas.pecka@fit.cvut.cz>
Date: Tue, 5 Nov 2019 21:33:59 +0100
Subject: [PATCH] Algo: CFG alternation/concatenation/iteration (#171)

---
 .../grammar/transform/GrammarAlternation.cpp  | 23 ++++++
 .../grammar/transform/GrammarAlternation.h    | 82 +++++++++++++++++++
 .../transform/GrammarConcatenation.cpp        | 23 ++++++
 .../grammar/transform/GrammarConcatenation.h  | 76 +++++++++++++++++
 .../grammar/transform/GrammarIteration.cpp    | 21 +++++
 .../src/grammar/transform/GrammarIteration.h  | 68 +++++++++++++++
 .../transform/GrammarTransformCommon.h        | 55 +++++++++++++
 .../transform/GrammarAlternationTest.cpp      | 56 +++++++++++++
 .../transform/GrammarConcatenationTest.cpp    | 55 +++++++++++++
 .../transform/GrammarIterationTest.cpp        | 39 +++++++++
 10 files changed, 498 insertions(+)
 create mode 100644 alib2algo/src/grammar/transform/GrammarAlternation.cpp
 create mode 100644 alib2algo/src/grammar/transform/GrammarAlternation.h
 create mode 100644 alib2algo/src/grammar/transform/GrammarConcatenation.cpp
 create mode 100644 alib2algo/src/grammar/transform/GrammarConcatenation.h
 create mode 100644 alib2algo/src/grammar/transform/GrammarIteration.cpp
 create mode 100644 alib2algo/src/grammar/transform/GrammarIteration.h
 create mode 100644 alib2algo/src/grammar/transform/GrammarTransformCommon.h
 create mode 100644 alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp
 create mode 100644 alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp
 create mode 100644 alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp

diff --git a/alib2algo/src/grammar/transform/GrammarAlternation.cpp b/alib2algo/src/grammar/transform/GrammarAlternation.cpp
new file mode 100644
index 0000000000..66e6d2649e
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarAlternation.cpp
@@ -0,0 +1,23 @@
+/*
+ * GrammarAlternation.cpp
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#include "GrammarAlternation.h"
+#include <registration/AlgoRegistration.hpp>
+
+namespace {
+
+auto GrammarAlternationCFG = registration::AbstractRegister < grammar::transform::GrammarAlternation,
+	grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > >,
+	const grammar::CFG < DefaultSymbolType, DefaultSymbolType > &,
+	const grammar::CFG < DefaultSymbolType, DefaultSymbolType > & > ( grammar::transform::GrammarAlternation::alternation, "first", "second" ).setDocumentation (
+"Alternates two context-free grammars.\n\
+\n\
+@param first First grammar (G1)\n\
+@param second Second grammar (G2)\n\
+@return context-free grammar G where L(G) = L(G1) \\cup L(G2)" );
+
+} /* namespace */
diff --git a/alib2algo/src/grammar/transform/GrammarAlternation.h b/alib2algo/src/grammar/transform/GrammarAlternation.h
new file mode 100644
index 0000000000..5f3aca18dd
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarAlternation.h
@@ -0,0 +1,82 @@
+/*
+ * GrammarAlternation.h
+ *
+ * This file is part of Algorithms library toolkit.
+ * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
+
+ * Algorithms library toolkit is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * Algorithms library toolkit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef GRAMMAR_ALTERNATION_H_
+#define GRAMMAR_ALTERNATION_H_
+
+#include "GrammarTransformCommon.h"
+
+#include <grammar/ContextFree/CFG.h>
+#include <common/createUnique.hpp>
+
+#include <label/InitialStateLabel.h>
+
+namespace grammar::transform {
+
+/**
+ * Alternation of two grammars.
+ * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1) \cup L(G2).
+ * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1) \cup L(G2).
+ * Source:
+ */
+class GrammarAlternation {
+public:
+	/**
+	 * Alternates two grammars.
+	 * @tparam TerminalSymbolType Type for terminal symbols.
+	 * @tparam NonterminalSymbolType Type for nonterminal symbols.
+	 * @param first First grammar (G1)
+	 * @param second Second grammar (G2)
+	 * @return CFG grammar for alternation of two CFG or RightRG for alternation of two RightRG.
+	 */
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > alternation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second );
+
+private:
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static void addRulesRenameNonterminals ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & grammar, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & g, const unsigned id );
+};
+
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > GrammarAlternation::alternation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ) {
+	ext::pair < NonterminalSymbolType, unsigned > S = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), first.getNonterminalAlphabet ( ), second.getNonterminalAlphabet ( ) ), 0 );
+	grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > res ( S );
+
+	res.setTerminalAlphabet ( first.getTerminalAlphabet ( ) + second.getTerminalAlphabet ( ) );
+
+	copyNonterminalsRename ( res, first, 1 );
+	copyNonterminalsRename ( res, first, 2 );
+
+	copyRulesRenameNonterminals ( res, first, 1 );
+	copyRulesRenameNonterminals ( res, second, 2 );
+
+	res.addRule ( S, { ext::make_pair ( first.getInitialSymbol ( ), 1 ) } );
+	res.addRule ( S, { ext::make_pair ( second.getInitialSymbol ( ), 2 ) } );
+
+	return res;
+}
+
+} /* namespace grammar::transform */
+
+#endif /* GRAMMAR_ALTERNATION_H_ */
diff --git a/alib2algo/src/grammar/transform/GrammarConcatenation.cpp b/alib2algo/src/grammar/transform/GrammarConcatenation.cpp
new file mode 100644
index 0000000000..0e57a5a61c
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarConcatenation.cpp
@@ -0,0 +1,23 @@
+/*
+ * GrammarConcatenation.cpp
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#include "GrammarConcatenation.h"
+#include <registration/AlgoRegistration.hpp>
+
+namespace {
+
+auto GrammarConcatenationCFG = registration::AbstractRegister < grammar::transform::GrammarConcatenation,
+	grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > >,
+	const grammar::CFG < > &,
+	const grammar::CFG < > & > ( grammar::transform::GrammarConcatenation::concatenation, "first", "second" ).setDocumentation (
+"Concatenates two context-free grammars.\n\
+\n\
+@param first First grammar (G1)\n\
+@param second Second grammar (G2)\n\
+@return context-free grammar G where L(G) = L(G1).L(G2)" );
+
+} /* namespace */
diff --git a/alib2algo/src/grammar/transform/GrammarConcatenation.h b/alib2algo/src/grammar/transform/GrammarConcatenation.h
new file mode 100644
index 0000000000..193cd8d068
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarConcatenation.h
@@ -0,0 +1,76 @@
+/*
+ * GrammarConcatenation.h
+ *
+ * This file is part of Algorithms library toolkit.
+ * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
+
+ * Algorithms library toolkit is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * Algorithms library toolkit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef GRAMMAR_CONCATENATION_H_
+#define GRAMMAR_CONCATENATION_H_
+
+#include "GrammarTransformCommon.h"
+
+#include <grammar/ContextFree/CFG.h>
+#include <common/createUnique.hpp>
+
+#include <label/InitialStateLabel.h>
+
+namespace grammar::transform {
+
+/**
+ * Concatenation of two grammars.
+ * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1).L(G2).
+ * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1).(G2).
+ * Source:
+ */
+class GrammarConcatenation {
+public:
+	/**
+	 * Concatenates two grammars.
+	 * @tparam TerminalSymbolType Type for terminal symbols.
+	 * @tparam NonterminalSymbolType Type for nonterminal symbols.
+	 * @param first First grammar (G1)
+	 * @param second Second grammar (G2)
+	 * @return CFG grammar for concatenation of two CFG or RightRG for concatenation of two RightRG.
+	 */
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > concatenation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second );
+};
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > GrammarConcatenation::concatenation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ) {
+	ext::pair < NonterminalSymbolType, unsigned > S = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), first.getNonterminalAlphabet ( ), second.getNonterminalAlphabet ( ) ), 0 );
+	grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > res ( S );
+
+	res.setTerminalAlphabet ( first.getTerminalAlphabet ( ) + second.getTerminalAlphabet ( ) );
+
+	copyNonterminalsRename ( res, first, 1 );
+	copyNonterminalsRename ( res, first, 2 );
+
+	copyRulesRenameNonterminals ( res, first, 1 );
+	copyRulesRenameNonterminals ( res, second, 2 );
+
+	res.addRule ( S, { ext::make_pair ( first.getInitialSymbol ( ), 1 ), ext::make_pair ( second.getInitialSymbol ( ), 2 ) } );
+
+	return res;
+}
+
+} /* namespace grammar::transform */
+
+#endif /* GRAMMAR_CONCATENATION_H_ */
diff --git a/alib2algo/src/grammar/transform/GrammarIteration.cpp b/alib2algo/src/grammar/transform/GrammarIteration.cpp
new file mode 100644
index 0000000000..72ba20b3c6
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarIteration.cpp
@@ -0,0 +1,21 @@
+/*
+ * GrammarIteration.cpp
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#include "GrammarIteration.h"
+#include <registration/AlgoRegistration.hpp>
+
+namespace {
+
+auto GrammarIterationCFG = registration::AbstractRegister < grammar::transform::GrammarIteration,
+	grammar::CFG < >,
+	const grammar::CFG < > & > ( grammar::transform::GrammarIteration::iteration, "first" ).setDocumentation (
+"Iterates a context-free grammars.\n\
+\n\
+@param grammar CFG grammar (G1)\n\
+@return context-free grammar G where L(G) = L(G1)*" );
+
+} /* namespace */
diff --git a/alib2algo/src/grammar/transform/GrammarIteration.h b/alib2algo/src/grammar/transform/GrammarIteration.h
new file mode 100644
index 0000000000..4c5fd15cbc
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarIteration.h
@@ -0,0 +1,68 @@
+/*
+ * GrammarIteration.h
+ *
+ * This file is part of Algorithms library toolkit.
+ * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
+
+ * Algorithms library toolkit is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * Algorithms library toolkit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef GRAMMAR_ITERATION_H_
+#define GRAMMAR_ITERATION_H_
+
+#include <grammar/ContextFree/CFG.h>
+#include <common/createUnique.hpp>
+
+#include <label/InitialStateLabel.h>
+
+namespace grammar::transform {
+
+/**
+ * Iteration of two grammars.
+ * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1) \cup L(G2).
+ * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1) \cup L(G2).
+ * Source:
+ */
+class GrammarIteration {
+public:
+	/**
+	 * Iterates a grammar.
+	 * @tparam TerminalSymbolType Type for terminal symbols.
+	 * @tparam NonterminalSymbolType Type for nonterminal symbols.
+	 * @param grammar grammar
+	 * @return CFG grammar for iteartion of a CFG grammar
+	 */
+	template < class TerminalSymbolType, class NonterminalSymbolType >
+	static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar );
+};
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+grammar::CFG < TerminalSymbolType, NonterminalSymbolType > GrammarIteration::iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar ) {
+	NonterminalSymbolType S = common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) );
+	grammar::CFG < TerminalSymbolType, NonterminalSymbolType > res = grammar;
+
+	res.addNonterminalSymbol ( S );
+	res.setInitialSymbol ( S );
+	res.addRule ( S, { } );
+	res.addRule ( S, { grammar.getInitialSymbol ( ), S } );
+
+	return res;
+}
+
+} /* namespace grammar::transform */
+
+#endif /* GRAMMAR_ITERATION_H_ */
diff --git a/alib2algo/src/grammar/transform/GrammarTransformCommon.h b/alib2algo/src/grammar/transform/GrammarTransformCommon.h
new file mode 100644
index 0000000000..164480250e
--- /dev/null
+++ b/alib2algo/src/grammar/transform/GrammarTransformCommon.h
@@ -0,0 +1,55 @@
+/*
+ * GrammarTransformCommon.h
+ *
+ * This file is part of Algorithms library toolkit.
+ * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
+
+ * Algorithms library toolkit is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * Algorithms library toolkit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Created on: 05. 11. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#include <grammar/ContextFree/CFG.h>
+
+#ifndef GRAMMAR_TRANSFORM_COMMON_H_
+#define GRAMMAR_TRANSFORM_COMMON_H_
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+void copyNonterminalsRename ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & dst, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & src, const unsigned suffix ) {
+	for ( const NonterminalSymbolType & symb : src.getNonterminalAlphabet ( ) )
+		dst.addNonterminalSymbol ( ext::make_pair ( symb, suffix ) );
+}
+
+template < class TerminalSymbolType, class NonterminalSymbolType >
+void copyRulesRenameNonterminals ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & dst, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & src, const unsigned suffix ) {
+	for ( const std::pair < const NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > & kv : src.getRules ( ) ) {
+		const NonterminalSymbolType & lhs = kv.first;
+
+		for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : kv.second ) {
+			ext::vector < ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > > newRhs;
+
+			for ( const ext::variant < TerminalSymbolType, NonterminalSymbolType > & symb : rhs ) {
+				if ( symb.template is < TerminalSymbolType > ( ) && src.getTerminalAlphabet ( ).count ( symb.template get < TerminalSymbolType > ( ) ) )
+					newRhs.push_back ( symb.template get < TerminalSymbolType > ( ) );
+				else
+					newRhs.push_back ( ext::make_pair ( symb.template get < NonterminalSymbolType > ( ), suffix ) );
+			}
+
+			dst.addRule ( ext::make_pair ( lhs, suffix ), newRhs );
+		}
+	}
+}
+
+#endif /* GRAMMAR_TRANSFORM_COMMON_H_ */
diff --git a/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp
new file mode 100644
index 0000000000..0f95a059e5
--- /dev/null
+++ b/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp
@@ -0,0 +1,56 @@
+#include <catch2/catch.hpp>
+#include <common/createUnique.hpp>
+
+#include "grammar/ContextFree/CFG.h"
+#include "grammar/transform/GrammarAlternation.h"
+
+TEST_CASE ( "Grammar Alternation", "[unit][algo][grammar][transform]" ) {
+	SECTION ( "Test CFG" ) {
+		{
+			ext::pair < DefaultSymbolType, unsigned > S1 = ext::make_pair ( DefaultSymbolType ( "S" ), 1 );
+			ext::pair < DefaultSymbolType, unsigned > A1 = ext::make_pair ( DefaultSymbolType ( "A" ), 1 );
+			ext::pair < DefaultSymbolType, unsigned > S2 = ext::make_pair ( DefaultSymbolType ( "S" ), 2 );
+			ext::pair < DefaultSymbolType, unsigned > A2 = ext::make_pair ( DefaultSymbolType ( "A" ), 2 );
+			DefaultSymbolType S = DefaultSymbolType ( "S" );
+			DefaultSymbolType A = DefaultSymbolType ( "A" );
+
+			DefaultSymbolType a = DefaultSymbolType ( 'a' );
+			DefaultSymbolType b = DefaultSymbolType ( 'b' );
+
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S );
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar2 ( { S, A }, { a, b }, S );
+
+			ext::pair < DefaultSymbolType, unsigned > S0 = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ), grammar2.getNonterminalAlphabet ( ) ), 0 );
+			grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > > grammar3 ( { S0, S1, A1, S2, A2 }, { a, b }, S0 );
+
+			grammar1.addRule ( S, { } );
+			grammar1.addRule ( S, { a, A } );
+			grammar1.addRule ( S, { a, S } );
+			grammar1.addRule ( A, { a, A } );
+			grammar1.addRule ( A, { } );
+
+			grammar2.addRule ( S, { } );
+			grammar2.addRule ( S, { a, A } );
+			grammar2.addRule ( S, { a, S } );
+			grammar2.addRule ( A, { a, A } );
+			grammar2.addRule ( A, { } );
+
+			grammar3.addRule ( S0, { S1 } );
+			grammar3.addRule ( S0, { S2 } );
+
+			grammar3.addRule ( S1, { } );
+			grammar3.addRule ( S1, { a, A1 } );
+			grammar3.addRule ( S1, { a, S1 } );
+			grammar3.addRule ( A1, { a, A1 } );
+			grammar3.addRule ( A1, { } );
+
+			grammar3.addRule ( S2, { } );
+			grammar3.addRule ( S2, { a, A2 } );
+			grammar3.addRule ( S2, { a, S2 } );
+			grammar3.addRule ( A2, { a, A2 } );
+			grammar3.addRule ( A2, { } );
+
+			CHECK ( grammar3 == grammar::transform::GrammarAlternation::alternation ( grammar1, grammar2 ) );
+		}
+	}
+}
diff --git a/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp
new file mode 100644
index 0000000000..efb220771f
--- /dev/null
+++ b/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp
@@ -0,0 +1,55 @@
+#include <catch2/catch.hpp>
+#include <common/createUnique.hpp>
+
+#include "grammar/ContextFree/CFG.h"
+#include "grammar/transform/GrammarConcatenation.h"
+
+TEST_CASE ( "Grammar Concatenation", "[unit][algo][grammar][transform]" ) {
+	SECTION ( "Test CFG" ) {
+		{
+			ext::pair < DefaultSymbolType, unsigned > S1 = ext::make_pair ( DefaultSymbolType ( "S" ), 1 );
+			ext::pair < DefaultSymbolType, unsigned > A1 = ext::make_pair ( DefaultSymbolType ( "A" ), 1 );
+			ext::pair < DefaultSymbolType, unsigned > S2 = ext::make_pair ( DefaultSymbolType ( "S" ), 2 );
+			ext::pair < DefaultSymbolType, unsigned > A2 = ext::make_pair ( DefaultSymbolType ( "A" ), 2 );
+			DefaultSymbolType S = DefaultSymbolType ( "S" );
+			DefaultSymbolType A = DefaultSymbolType ( "A" );
+
+			DefaultSymbolType a = DefaultSymbolType ( 'a' );
+			DefaultSymbolType b = DefaultSymbolType ( 'b' );
+
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S );
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar2 ( { S, A }, { a, b }, S );
+
+			ext::pair < DefaultSymbolType, unsigned > S0 = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ), grammar2.getNonterminalAlphabet ( ) ), 0 );
+			grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > > grammar3 ( { S0, S1, A1, S2, A2 }, { a, b }, S0 );
+
+			grammar1.addRule ( S, { } );
+			grammar1.addRule ( S, { a, A } );
+			grammar1.addRule ( S, { a, S } );
+			grammar1.addRule ( A, { a, A } );
+			grammar1.addRule ( A, { } );
+
+			grammar2.addRule ( S, { } );
+			grammar2.addRule ( S, { a, A } );
+			grammar2.addRule ( S, { a, S } );
+			grammar2.addRule ( A, { a, A } );
+			grammar2.addRule ( A, { } );
+
+			grammar3.addRule ( S0, { S1, S2 } );
+
+			grammar3.addRule ( S1, { } );
+			grammar3.addRule ( S1, { a, A1 } );
+			grammar3.addRule ( S1, { a, S1 } );
+			grammar3.addRule ( A1, { a, A1 } );
+			grammar3.addRule ( A1, { } );
+
+			grammar3.addRule ( S2, { } );
+			grammar3.addRule ( S2, { a, A2 } );
+			grammar3.addRule ( S2, { a, S2 } );
+			grammar3.addRule ( A2, { a, A2 } );
+			grammar3.addRule ( A2, { } );
+
+			CHECK ( grammar3 == grammar::transform::GrammarConcatenation::concatenation ( grammar1, grammar2 ) );
+		}
+	}
+}
diff --git a/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp
new file mode 100644
index 0000000000..b96852f02b
--- /dev/null
+++ b/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp
@@ -0,0 +1,39 @@
+#include <catch2/catch.hpp>
+#include <common/createUnique.hpp>
+
+#include "grammar/ContextFree/CFG.h"
+#include "grammar/transform/GrammarIteration.h"
+
+TEST_CASE ( "Grammar Iteration", "[unit][algo][grammar][transform]" ) {
+	SECTION ( "Test CFG" ) {
+		{
+			DefaultSymbolType S = DefaultSymbolType ( "S" );
+			DefaultSymbolType A = DefaultSymbolType ( "A" );
+
+			DefaultSymbolType a = DefaultSymbolType ( 'a' );
+			DefaultSymbolType b = DefaultSymbolType ( 'b' );
+
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S );
+
+			DefaultSymbolType S0 = common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ) );
+			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar3 ( { S0, S, A }, { a, b }, S0 );
+
+			grammar1.addRule ( S, { } );
+			grammar1.addRule ( S, { a, A } );
+			grammar1.addRule ( S, { a, S } );
+			grammar1.addRule ( A, { a, A } );
+			grammar1.addRule ( A, { } );
+
+			grammar3.addRule ( S0, { } );
+			grammar3.addRule ( S0, { S, S0 } );
+
+			grammar3.addRule ( S, { } );
+			grammar3.addRule ( S, { a, A } );
+			grammar3.addRule ( S, { a, S } );
+			grammar3.addRule ( A, { a, A } );
+			grammar3.addRule ( A, { } );
+
+			CHECK ( grammar3 == grammar::transform::GrammarIteration::iteration ( grammar1 ) );
+		}
+	}
+}
-- 
GitLab