From 77df9f57643d16a97a9e724a1ec422a2d03aee95 Mon Sep 17 00:00:00 2001
From: Tomas Pecka <peckato1@fit.cvut.cz>
Date: Sat, 29 Nov 2014 22:39:07 +0100
Subject: [PATCH] algo: automaton iteration

---
 alangop2/src/alangop.cpp                      |  28 +++-
 .../transform/AutomatonIteration.cpp          | 125 ++++++++++++++++++
 .../automaton/transform/AutomatonIteration.h  |  59 +++++++++
 .../AutomatonIterationEpsilonTransition.cpp   | 125 ++++++++++++++++++
 .../AutomatonIterationEpsilonTransition.h     |  59 +++++++++
 .../transform/AutomataConcatenationTest.cpp   |   6 -
 .../transform/AutomatonIterationTest.cpp      |  58 ++++++++
 .../transform/AutomatonIterationTest.h        |  19 +++
 8 files changed, 466 insertions(+), 13 deletions(-)
 create mode 100644 alib2algo/src/automaton/transform/AutomatonIteration.cpp
 create mode 100644 alib2algo/src/automaton/transform/AutomatonIteration.h
 create mode 100644 alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
 create mode 100644 alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
 create mode 100644 alib2algo/test-src/automaton/transform/AutomatonIterationTest.cpp
 create mode 100644 alib2algo/test-src/automaton/transform/AutomatonIterationTest.h

diff --git a/alangop2/src/alangop.cpp b/alangop2/src/alangop.cpp
index 3eeb3c533b..7c35665648 100644
--- a/alangop2/src/alangop.cpp
+++ b/alangop2/src/alangop.cpp
@@ -17,6 +17,8 @@
 #include <automaton/transform/AutomataIntersectionCartesianProduct.h>
 #include <automaton/transform/AutomataUnionCartesianProduct.h>
 #include <automaton/transform/AutomataUnionEpsilonTransition.h>
+#include <automaton/transform/AutomatonIterationEpsilonTransition.h>
+#include <automaton/transform/AutomatonIteration.h>
 
 
 int main(int argc, char* argv[]) {
@@ -29,6 +31,8 @@ int main(int argc, char* argv[]) {
 		allowed.push_back("concatenationEpsilon");
 		allowed.push_back("concatenation");
 		allowed.push_back("intersectionCartesian");
+		allowed.push_back("iterationEpsilon");
+		allowed.push_back("iteration");
 		TCLAP::ValuesConstraint<std::string> allowedVals( allowed );
 
 		TCLAP::ValueArg<std::string> algorithm(	"a",	"algorithm",	"Execute algorithm", true,	"",	&allowedVals);
@@ -58,27 +62,37 @@ int main(int argc, char* argv[]) {
 			} else {
 				sax::SaxParseInterface::parseFile(a2.getValue(), a2Tokens);
 			}
-		} else {
+		} else if(algorithm.getValue() != "iteration" && algorithm.getValue() != "iterationEpsilon") {
 			sax::SaxParseInterface::parseStdin(a2Tokens);
 		}
 
 		automaton::Automaton automaton1 = alib::DataFactory::fromTokens<automaton::Automaton>(a1Tokens);
-		automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
 
 		if( algorithm.getValue() == "unionEpsilon") {
-			alib::DataFactory::toStdout(automaton::transform::AutomataUnionEpsilonTransition::unification(automaton1, automaton2));;
+			automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
+			alib::DataFactory::toStdout(automaton::transform::AutomataUnionEpsilonTransition::unification(automaton1, automaton2));
 			return 0;
 		} else if( algorithm.getValue() == "unionCartesian") {
-			alib::DataFactory::toStdout(automaton::transform::AutomataUnionCartesianProduct::unification(automaton1, automaton2));;
+			automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
+			alib::DataFactory::toStdout(automaton::transform::AutomataUnionCartesianProduct::unification(automaton1, automaton2));
 			return 0;
 		} else if( algorithm.getValue() == "concatenationEpsilon") {
-			alib::DataFactory::toStdout(automaton::transform::AutomataConcatenationEpsilonTransition::concatenation(automaton1, automaton2));;
+			automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
+			alib::DataFactory::toStdout(automaton::transform::AutomataConcatenationEpsilonTransition::concatenation(automaton1, automaton2));
 			return 0;
 		} else if( algorithm.getValue() == "concatenation") {
-			alib::DataFactory::toStdout(automaton::transform::AutomataConcatenation::concatenation(automaton1, automaton2));;
+			automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
+			alib::DataFactory::toStdout(automaton::transform::AutomataConcatenation::concatenation(automaton1, automaton2));
 			return 0;
 		} else if( algorithm.getValue() == "intersectionCartesian") {
-			alib::DataFactory::toStdout(automaton::transform::AutomataIntersectionCartesianProduct::intersection(automaton1, automaton2));;
+			automaton::Automaton automaton2 = alib::DataFactory::fromTokens<automaton::Automaton>(a2Tokens);
+			alib::DataFactory::toStdout(automaton::transform::AutomataIntersectionCartesianProduct::intersection(automaton1, automaton2));
+			return 0;
+		} else if( algorithm.getValue() == "iteration") {
+			alib::DataFactory::toStdout(automaton::transform::AutomatonIteration::iteration(automaton1));
+			return 0;
+		} else if( algorithm.getValue() == "iterationEpsilon") {
+			alib::DataFactory::toStdout(automaton::transform::AutomatonIterationEpsilonTransition::iteration(automaton1));
 			return 0;
 		} else {
 			throw exception::AlibException( "Invalid algorithm" );
diff --git a/alib2algo/src/automaton/transform/AutomatonIteration.cpp b/alib2algo/src/automaton/transform/AutomatonIteration.cpp
new file mode 100644
index 0000000000..ad8dc7d4f1
--- /dev/null
+++ b/alib2algo/src/automaton/transform/AutomatonIteration.cpp
@@ -0,0 +1,125 @@
+/*
+ * AutomatonIteration.cpp
+ *
+ *  Created on: 29. 11. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#include "AutomatonIteration.h"
+#include <exception/AlibException.h>
+
+namespace automaton
+{
+
+namespace transform
+{
+
+automaton::Automaton AutomatonIteration::iteration(const automaton::Automaton& automaton)
+{
+	AutomatonBase* out;
+	automaton.getData().Accept((void*) &out, AutomatonIteration::AUTOMATON_ITERATION);
+	automaton::Automaton res(*out);
+	delete out;
+	return res;
+}
+
+template<class T>
+automaton::NFA AutomatonIteration::iteration(const T& automaton)
+{
+	automaton::NFA res(automaton);
+
+	for(const auto& qf : res.getFinalStates())
+		for(const auto& t : res.getTransitionsToState(qf))
+			res.addTransition(t.first.first, t.first.second, res.getInitialState());
+
+	res.addFinalState(automaton.getInitialState());
+	return res;
+}
+
+void AutomatonIteration::Visit(void*, const automaton::EpsilonNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::CompactNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type CompactNFA");
+}
+
+void AutomatonIteration::Visit(void* data, const automaton::DFA& automaton) const
+{
+	AutomatonBase* &ret = *(AutomatonBase**) data;
+	ret = std::move(AutomatonIteration::iteration(automaton)).plunder();
+}
+
+void AutomatonIteration::Visit(void*, const automaton::ExtendedNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::MultiInitialStateNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
+}
+
+void AutomatonIteration::Visit(void* data, const automaton::NFA& automaton) const
+{
+	AutomatonBase* &ret = *(AutomatonBase**) data;
+	ret = std::move(AutomatonIteration::iteration(automaton)).plunder();
+}
+
+void AutomatonIteration::Visit(void*, const automaton::DPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type DPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::NPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type NPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::InputDrivenNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::SinglePopNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::SinglePopDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::VisiblyPushdownDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::VisiblyPushdownNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
+}
+
+void AutomatonIteration::Visit(void*, const automaton::OneTapeDTM&) const
+{
+	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+}
+
+const AutomatonIteration AutomatonIteration::AUTOMATON_ITERATION;
+
+} /* namespace transform */
+
+} /* namespace automaton */
diff --git a/alib2algo/src/automaton/transform/AutomatonIteration.h b/alib2algo/src/automaton/transform/AutomatonIteration.h
new file mode 100644
index 0000000000..e19861e088
--- /dev/null
+++ b/alib2algo/src/automaton/transform/AutomatonIteration.h
@@ -0,0 +1,59 @@
+/*
+ * AutomatonIteration.h
+ *
+ *  Created on: 29. 11. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef AUTOMATON_ITERATION_H_
+#define AUTOMATON_ITERATION_H_
+
+#include <automaton/Automaton.h>
+#include <automaton/FSM/EpsilonNFA.h>
+
+namespace automaton
+{
+
+namespace transform
+{
+
+/**
+ * Iterates language given by automaton
+ *  - For finite automaton A1, we create automaton L accepting L(A1)*
+ */
+class AutomatonIteration : public automaton::VisitableAutomatonBase::const_visitor_type
+{
+public:
+	static automaton::Automaton iteration(const automaton::Automaton& automaton);
+
+	template<class T>
+	static automaton::NFA iteration(const T& automaton);
+
+private:
+	void Visit(void* data, const automaton::CompactNFA& automaton) const;
+	void Visit(void* data, const automaton::DFA& automaton) const;
+	void Visit(void* data, const automaton::EpsilonNFA& automaton) const;
+	void Visit(void* data, const automaton::ExtendedNFA& automaton) const;
+	void Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const;
+	void Visit(void* data, const automaton::NFA& automaton) const;
+
+	void Visit(void* data, const automaton::DPDA& automaton) const;
+	void Visit(void* data, const automaton::NPDA& automaton) const;
+	void Visit(void* data, const automaton::InputDrivenNPDA& automaton) const;
+	void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
+	void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
+	void Visit(void* data, const automaton::SinglePopNPDA& automaton) const;
+	void Visit(void* data, const automaton::SinglePopDPDA& automaton) const;
+	void Visit(void* data, const automaton::VisiblyPushdownDPDA& automaton) const;
+	void Visit(void* data, const automaton::VisiblyPushdownNPDA& automaton) const;
+
+	void Visit(void* data, const automaton::OneTapeDTM& automaton) const;
+
+	static const AutomatonIteration AUTOMATON_ITERATION;
+};
+
+} /* namespace transform */
+
+} /* namespace automaton */
+
+#endif /* AUTOMATON_ITERATION_H_ */
diff --git a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
new file mode 100644
index 0000000000..6cf3b6a1a9
--- /dev/null
+++ b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
@@ -0,0 +1,125 @@
+/*
+ * AutomatonIterationEpsilonTransition.cpp
+ *
+ *  Created on: 20. 11. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#include "AutomatonIterationEpsilonTransition.h"
+#include <exception/AlibException.h>
+
+namespace automaton
+{
+
+namespace transform
+{
+
+automaton::Automaton AutomatonIterationEpsilonTransition::iteration(const automaton::Automaton& automaton)
+{
+	AutomatonBase* out;
+	automaton.getData().Accept((void*) &out, AutomatonIterationEpsilonTransition::AUTOMATON_ITERATION_EPSILON_TRANSITION);
+	automaton::Automaton res(*out);
+	delete out;
+	return res;
+}
+
+template<class T>
+automaton::EpsilonNFA AutomatonIterationEpsilonTransition::iteration(const T& automaton)
+{
+	automaton::EpsilonNFA res(automaton);
+
+	for(const auto&q : automaton.getFinalStates())
+		res.addTransition(q, automaton.getInitialState());
+
+	res.addFinalState(automaton.getInitialState());
+	return res;
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::EpsilonNFA& automaton) const
+{
+	AutomatonBase* &ret = *(AutomatonBase**) data;
+	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::CompactNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type CompactNFA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::DFA& automaton) const
+{
+	AutomatonBase* &ret = *(AutomatonBase**) data;
+	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::ExtendedNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::MultiInitialStateNFA&) const
+{
+	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::NFA& automaton) const
+{
+	AutomatonBase* &ret = *(AutomatonBase**) data;
+	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::DPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type DPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::NPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type NPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::InputDrivenNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::SinglePopNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::SinglePopDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownDPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownNPDA&) const
+{
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
+}
+
+void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::OneTapeDTM&) const
+{
+	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+}
+
+const AutomatonIterationEpsilonTransition AutomatonIterationEpsilonTransition::AUTOMATON_ITERATION_EPSILON_TRANSITION;
+
+} /* namespace transform */
+
+} /* namespace automaton */
diff --git a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
new file mode 100644
index 0000000000..7329e8cfb5
--- /dev/null
+++ b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
@@ -0,0 +1,59 @@
+/*
+ * AutomatonIterationEpsilonTransition.h
+ *
+ *  Created on: 29. 11. 2014
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef AUTOMATON_ITERATION_EPSILON_TRANSITION_H_
+#define AUTOMATON_ITERATION_EPSILON_TRANSITION_H_
+
+#include <automaton/Automaton.h>
+#include <automaton/FSM/EpsilonNFA.h>
+
+namespace automaton
+{
+
+namespace transform
+{
+
+/**
+ * Iterates language given by automaton
+ *  - For finite automaton A1, we create automaton L accepting L(A1)*
+ */
+class AutomatonIterationEpsilonTransition : public automaton::VisitableAutomatonBase::const_visitor_type
+{
+public:
+	static automaton::Automaton iteration(const automaton::Automaton& automaton);
+
+	template<class T>
+	static automaton::EpsilonNFA iteration(const T& automaton);
+
+private:
+	void Visit(void* data, const automaton::CompactNFA& automaton) const;
+	void Visit(void* data, const automaton::DFA& automaton) const;
+	void Visit(void* data, const automaton::EpsilonNFA& automaton) const;
+	void Visit(void* data, const automaton::ExtendedNFA& automaton) const;
+	void Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const;
+	void Visit(void* data, const automaton::NFA& automaton) const;
+
+	void Visit(void* data, const automaton::DPDA& automaton) const;
+	void Visit(void* data, const automaton::NPDA& automaton) const;
+	void Visit(void* data, const automaton::InputDrivenNPDA& automaton) const;
+	void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
+	void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
+	void Visit(void* data, const automaton::SinglePopNPDA& automaton) const;
+	void Visit(void* data, const automaton::SinglePopDPDA& automaton) const;
+	void Visit(void* data, const automaton::VisiblyPushdownDPDA& automaton) const;
+	void Visit(void* data, const automaton::VisiblyPushdownNPDA& automaton) const;
+
+	void Visit(void* data, const automaton::OneTapeDTM& automaton) const;
+
+	static const AutomatonIterationEpsilonTransition AUTOMATON_ITERATION_EPSILON_TRANSITION;
+};
+
+} /* namespace transform */
+
+} /* namespace automaton */
+
+#endif /* AUTOMATON_ITERATION_EPSILON_H_ */
diff --git a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp
index 27cfc8e72a..4acd4ed33f 100644
--- a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp
+++ b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp
@@ -78,12 +78,6 @@ void AutomataConcatenationTest::testAutomataConcatenation() {
 	automaton::Automaton umdfa12(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u12)))));
 	automaton::Automaton umdfa21(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u21)))));
 	automaton::Automaton umdfa22(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u22)))));
-	alib::DataFactory::toStdout(umdfa);
-	alib::DataFactory::toStdout(umdfa11);
-	alib::DataFactory::toStdout(umdfa12);
-	alib::DataFactory::toStdout(umdfa21);
-	alib::DataFactory::toStdout(umdfa22);
-
 
 	CPPUNIT_ASSERT(umdfa11 == umdfa);
 	CPPUNIT_ASSERT(umdfa12 == umdfa);
diff --git a/alib2algo/test-src/automaton/transform/AutomatonIterationTest.cpp b/alib2algo/test-src/automaton/transform/AutomatonIterationTest.cpp
new file mode 100644
index 0000000000..ae36365dda
--- /dev/null
+++ b/alib2algo/test-src/automaton/transform/AutomatonIterationTest.cpp
@@ -0,0 +1,58 @@
+#include <list>
+#include "AutomatonIterationTest.h"
+
+#include "automaton/transform/AutomatonIteration.h"
+#include "automaton/transform/AutomatonIterationEpsilonTransition.h"
+
+#include "automaton/simplify/MinimizeBrzozowski.h"
+#include "automaton/simplify/Normalize.h"
+#include "automaton/simplify/EpsilonRemover.h"
+#include "automaton/simplify/Trim.h"
+#include "automaton/simplify/Total.h"
+#include "automaton/determinize/Determinize.h"
+
+#include <factory/DataFactory.hpp>
+
+#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y))
+
+CPPUNIT_TEST_SUITE_REGISTRATION( AutomatonIterationTest );
+
+void AutomatonIterationTest::setUp() {
+}
+
+void AutomatonIterationTest::tearDown() {
+}
+
+void AutomatonIterationTest::testAutomatonIteration() {
+
+	// Melichar 2.83
+	automaton::State q1(1), q2(2), q3(3);
+	alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b'));
+
+	automaton::DFA m1(q1);
+	m1.setStates({q1, q2, q3});
+	m1.addFinalState(q3);
+	m1.setInputSymbols({a, b});
+	m1.addTransition(q1, a, q2);
+	m1.addTransition(q2, b, q2);
+	m1.addTransition(q2, a, q3);
+
+	automaton::NFA res(q1);
+	res.setStates({q1, q2, q3});
+	res.setInputSymbols({a, b});
+	res.setFinalStates({q1, q3});
+	res.addTransition(q1, a, q2);
+	res.addTransition(q2, b, q2);
+	res.addTransition(q2, a, q3);
+	res.addTransition(q2, a, q1);
+
+	automaton::Automaton i2 = automaton::transform::AutomatonIterationEpsilonTransition::iteration(automaton::Automaton(m1));
+	automaton::Automaton i1 = automaton::transform::AutomatonIteration::iteration(automaton::Automaton(m1));
+
+	automaton::Automaton mdfa1 (automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(i1)))));
+	automaton::Automaton mdfa2 (automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(i2)))));
+	automaton::Automaton mdfa3 (automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(res)))));
+
+	CPPUNIT_ASSERT(mdfa1 == mdfa2);
+	CPPUNIT_ASSERT(mdfa1 == mdfa3);
+}
diff --git a/alib2algo/test-src/automaton/transform/AutomatonIterationTest.h b/alib2algo/test-src/automaton/transform/AutomatonIterationTest.h
new file mode 100644
index 0000000000..28119050ac
--- /dev/null
+++ b/alib2algo/test-src/automaton/transform/AutomatonIterationTest.h
@@ -0,0 +1,19 @@
+#ifndef AUTOMATA_ITER_TEST_H_
+#define AUTOMATA_ITER_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class AutomatonIterationTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( AutomatonIterationTest );
+  CPPUNIT_TEST( testAutomatonIteration );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testAutomatonIteration();
+};
+
+#endif /* AUTOMATA_ITER_TEST_H_ */
-- 
GitLab