From 8beeca9417469e02245bf6050237a4a729c91946 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sat, 15 Aug 2015 20:34:28 +0200
Subject: [PATCH] continue with alib2elgo

---
 .../efficient/AllEpsilonClosure.cpp           | 100 +++--------------
 .../properties/efficient/AllEpsilonClosure.h  |  31 ++----
 .../properties/efficient/ReachableStates.cpp  |  98 ++---------------
 .../properties/efficient/ReachableStates.h    |  31 ++----
 .../properties/efficient/UsefullStates.cpp    |  98 ++---------------
 .../properties/efficient/UsefullStates.h      |  31 ++----
 .../efficient/EpsilonRemoverIncoming.cpp      |  96 ++---------------
 .../efficient/EpsilonRemoverIncoming.h        |  31 ++----
 .../efficient/EpsilonRemoverOutgoing.cpp      |  96 ++---------------
 .../efficient/EpsilonRemoverOutgoing.h        |  31 ++----
 .../src/automaton/simplify/efficient/Trim.cpp | 102 ++----------------
 .../src/automaton/simplify/efficient/Trim.h   |  31 ++----
 .../efficient/UnreachableStatesRemover.cpp    | 102 ++----------------
 .../efficient/UnreachableStatesRemover.h      |  31 ++----
 .../efficient/UselessStatesRemover.cpp        | 102 ++----------------
 .../simplify/efficient/UselessStatesRemover.h |  31 ++----
 16 files changed, 119 insertions(+), 923 deletions(-)

diff --git a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.cpp b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.cpp
index 6b6ac7f985..4de5f43716 100644
--- a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.cpp
+++ b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.cpp
@@ -67,6 +67,8 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return res;
 }
 
+auto AllEpsilonClosureEpsilonNFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::EpsilonNFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
+
 std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure( const automaton::MultiInitialStateNFA & fsm) {
 	std::map<automaton::State, std::set<automaton::State>> closure;
 	for(const automaton::State& state : fsm.getStates())
@@ -74,6 +76,8 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return closure;
 }
 
+auto AllEpsilonClosureMultiInitialStateNFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::MultiInitialStateNFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
+
 std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure( const automaton::NFA & fsm) {
 	std::map<automaton::State, std::set<automaton::State>> closure;
 	for(const automaton::State& state : fsm.getStates())
@@ -81,6 +85,8 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return closure;
 }
 
+auto AllEpsilonClosureNFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::NFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
+
 std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure( const automaton::DFA & fsm) {
 	std::map<automaton::State, std::set<automaton::State>> closure;
 	for(const automaton::State& state : fsm.getStates())
@@ -88,6 +94,8 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return closure;
 }
 
+auto AllEpsilonClosureDFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::DFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
+
 std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure( const automaton::ExtendedNFA & fsm) {
 	std::map<automaton::State, std::set<automaton::State>> res;
 
@@ -115,6 +123,8 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return res;
 }
 
+auto AllEpsilonClosureExtendedNFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::ExtendedNFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
+
 std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure( const automaton::CompactNFA & fsm) {
 	std::map<automaton::State, std::set<automaton::State>> res;
 
@@ -142,96 +152,12 @@ std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEps
 	return res;
 }
 
-std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure(const Automaton& automaton) {
-	std::map<automaton::State, std::set<automaton::State>> out;
-	automaton.getData().Accept((void*) &out, AllEpsilonClosure::ALL_EPSILON_CLOSURE);
-	return std::move(out);
-}
-
-void AllEpsilonClosure::Visit(void* data, const EpsilonNFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void* data, const MultiInitialStateNFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void* data, const NFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void* data, const DFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void* data, const ExtendedNFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void* data, const CompactNFA& automaton) const {
-	std::map<automaton::State, std::set<automaton::State>> & out = *((std::map<automaton::State, std::set<automaton::State>>*) data);
-	out = std::move(this->allEpsilonClosure(automaton));
-}
-
-void AllEpsilonClosure::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AllEpsilonClosure::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
+auto AllEpsilonClosureCompactNFA = AllEpsilonClosure::RegistratorWrapper<std::map<automaton::State, std::set<automaton::State>>, automaton::CompactNFA>(AllEpsilonClosure::getInstance(), AllEpsilonClosure::allEpsilonClosure);
 
-void AllEpsilonClosure::Visit(void*, const DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AllEpsilonClosure::Visit(void*, const OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+std::map<automaton::State, std::set<automaton::State>> AllEpsilonClosure::allEpsilonClosure(const Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const AllEpsilonClosure AllEpsilonClosure::ALL_EPSILON_CLOSURE;
-
 } /* namespace efficient */
 
 } /* namespace properties */
diff --git a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h
index 70351d85d6..e93d65b397 100644
--- a/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h
+++ b/alib2elgo/src/automaton/properties/efficient/AllEpsilonClosure.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_ALL_EPSILON_CLOSURE_H_
 #define EFFICIENT_ALL_EPSILON_CLOSURE_H_
 
+#include <common/multipleDispatch.hpp>
 #include <set>
 #include <map>
 
@@ -20,10 +21,8 @@ namespace properties {
 
 namespace efficient {
 
-class AllEpsilonClosure : public VisitableAutomatonBase::const_visitor_type {
+class AllEpsilonClosure : public std::SingleDispatch<std::map<automaton::State, std::set<automaton::State>>, automaton::AutomatonBase> {
 public:
-	AllEpsilonClosure() {}
-
 	static std::map<automaton::State, std::set<automaton::State>> allEpsilonClosure( const automaton::Automaton & automaton);
 
 	/**
@@ -36,28 +35,10 @@ public:
 	static std::map<automaton::State, std::set<automaton::State>> allEpsilonClosure( const automaton::ExtendedNFA & fsm);
 	static std::map<automaton::State, std::set<automaton::State>> allEpsilonClosure( const automaton::CompactNFA & fsm);
 
-private:
-	void Visit(void*, const EpsilonNFA& automaton) const;
-	void Visit(void*, const MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const NFA& automaton) const;
-	void Visit(void*, const DFA& automaton) const;
-	void Visit(void*, const ExtendedNFA& automaton) const;
-	void Visit(void*, const CompactNFA& automaton) const;
-	void Visit(void*, const NFTA& automaton) const;
-	void Visit(void*, const DFTA& automaton) const;
-	void Visit(void*, const DPDA& automaton) const;
-	void Visit(void*, const SinglePopDPDA& automaton) const;
-	void Visit(void*, const InputDrivenDPDA& automaton) const;
-	void Visit(void*, const InputDrivenNPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const NPDA& automaton) const;
-	void Visit(void*, const SinglePopNPDA& automaton) const;
-	void Visit(void*, const OneTapeDTM& automaton) const;
-
-	static const AllEpsilonClosure ALL_EPSILON_CLOSURE;
+	static AllEpsilonClosure& getInstance() {
+		static AllEpsilonClosure res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp b/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp
index a4ccda4742..d5cb23618f 100644
--- a/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp
+++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp
@@ -25,9 +25,7 @@ namespace properties {
 namespace efficient {
 
 std::set<automaton::State> ReachableStates::reachableStates(const Automaton& automaton) {
-	std::set<automaton::State> out;
-	automaton.getData().Accept((void*) &out, ReachableStates::REACHABLE_STATES);
-	return out;
+	return getInstance().dispatch(automaton.getData());
 }
 
 template<class T>
@@ -52,10 +50,10 @@ std::set<automaton::State> ReachableStates::reachableStates( const T & fsm ) {
 	return visited;
 }
 
-template std::set<automaton::State> ReachableStates::reachableStates( const automaton::EpsilonNFA & fsm );
-template std::set<automaton::State> ReachableStates::reachableStates( const automaton::NFA & fsm );
-template std::set<automaton::State> ReachableStates::reachableStates( const automaton::CompactNFA & fsm );
-template std::set<automaton::State> ReachableStates::reachableStates( const automaton::ExtendedNFA & fsm );
+auto ReachableStatesEpsilonNFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::EpsilonNFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
+auto ReachableStatesNFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::NFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
+auto ReachableStatesCompactNFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::CompactNFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
+auto ReachableStatesExtendedNFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::ExtendedNFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
 
 template<>
 std::set<automaton::State> ReachableStates::reachableStates( const automaton::MultiInitialStateNFA & fsm ) {
@@ -79,6 +77,8 @@ std::set<automaton::State> ReachableStates::reachableStates( const automaton::Mu
 	return visited;
 }
 
+auto ReachableStatesMultiInitialStateNFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::MultiInitialStateNFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
+
 template<>
 std::set<automaton::State> ReachableStates::reachableStates( const automaton::DFA & fsm ) {
 	std::map<automaton::State, std::set<automaton::State>> transitions;
@@ -101,89 +101,7 @@ std::set<automaton::State> ReachableStates::reachableStates( const automaton::DF
 	return visited;
 }
 
-void ReachableStates::Visit(void* data, const EpsilonNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void* data, const MultiInitialStateNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void* data, const NFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void* data, const DFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void* data, const ExtendedNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void* data, const CompactNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->reachableStates(automaton));
-}
-
-void ReachableStates::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void ReachableStates::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-void ReachableStates::Visit(void*, const DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void ReachableStates::Visit(void*, const SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void ReachableStates::Visit(void*, const InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void ReachableStates::Visit(void*, const InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void ReachableStates::Visit(void*, const VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void ReachableStates::Visit(void*, const VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void ReachableStates::Visit(void*, const RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void ReachableStates::Visit(void*, const RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void ReachableStates::Visit(void*, const NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void ReachableStates::Visit(void*, const SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void ReachableStates::Visit(void*, const OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-const ReachableStates ReachableStates::REACHABLE_STATES;
+auto ReachableStatesDFA = ReachableStates::RegistratorWrapper<std::set<automaton::State>, automaton::DFA>(ReachableStates::getInstance(), ReachableStates::reachableStates);
 
 } /* namespace efficient */
 
diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h
index b938e1e15c..29646b2ce5 100644
--- a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h
+++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_REACHABLE_STATES_H_
 #define EFFICIENT_REACHABLE_STATES_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -21,10 +22,8 @@ namespace properties {
 
 namespace efficient {
 
-class ReachableStates : public VisitableAutomatonBase::const_visitor_type {
+class ReachableStates : public std::SingleDispatch<std::set<automaton::State>, automaton::AutomatonBase> {
 public:
-	ReachableStates() {}
-
 	static std::set<automaton::State> reachableStates( const automaton::Automaton & automaton );
 
 	/**
@@ -33,28 +32,10 @@ public:
 	template<class T>
 	static std::set<automaton::State> reachableStates( const T & fsm );
 
-private:
-	void Visit(void*, const EpsilonNFA& automaton) const;
-	void Visit(void*, const MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const NFA& automaton) const;
-	void Visit(void*, const DFA& automaton) const;
-	void Visit(void*, const ExtendedNFA& automaton) const;
-	void Visit(void*, const CompactNFA& automaton) const;
-	void Visit(void*, const NFTA& automaton) const;
-	void Visit(void*, const DFTA& automaton) const;
-	void Visit(void*, const DPDA& automaton) const;
-	void Visit(void*, const SinglePopDPDA& automaton) const;
-	void Visit(void*, const InputDrivenDPDA& automaton) const;
-	void Visit(void*, const InputDrivenNPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const NPDA& automaton) const;
-	void Visit(void*, const SinglePopNPDA& automaton) const;
-	void Visit(void*, const OneTapeDTM& automaton) const;
-
-	static const ReachableStates REACHABLE_STATES;
+	static ReachableStates& getInstance() {
+		static ReachableStates res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp b/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp
index e7e6684d28..a31e341c9a 100644
--- a/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp
+++ b/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp
@@ -25,9 +25,7 @@ namespace properties {
 namespace efficient {
 
 std::set<automaton::State> UsefullStates::usefullStates(const Automaton& automaton) {
-	std::set<automaton::State> out;
-	automaton.getData().Accept((void*) &out, UsefullStates::USEFULL_STATES);
-	return out;
+	return getInstance().dispatch(automaton.getData());
 }
 
 template<class T>
@@ -53,11 +51,11 @@ std::set<automaton::State> UsefullStates::usefullStates( const T & fsm ) {
 	return visited;
 }
 
-template std::set<automaton::State> UsefullStates::usefullStates( const automaton::EpsilonNFA & fsm );
-template std::set<automaton::State> UsefullStates::usefullStates( const automaton::NFA & fsm );
-template std::set<automaton::State> UsefullStates::usefullStates( const automaton::CompactNFA & fsm );
-template std::set<automaton::State> UsefullStates::usefullStates( const automaton::ExtendedNFA & fsm );
-template std::set<automaton::State> UsefullStates::usefullStates( const automaton::MultiInitialStateNFA & fsm );
+auto UsefullStatesEpsilonNFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::EpsilonNFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
+auto UsefullStatesNFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::NFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
+auto UsefullStatesCompactNFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::CompactNFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
+auto UsefullStatesExtendedNFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::ExtendedNFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
+auto UsefullStatesMultiInitialStateNFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::MultiInitialStateNFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
 
 template<>
 std::set<automaton::State> UsefullStates::usefullStates( const automaton::DFA & fsm ) {
@@ -81,89 +79,7 @@ std::set<automaton::State> UsefullStates::usefullStates( const automaton::DFA &
 	return visited;
 }
 
-void UsefullStates::Visit(void* data, const EpsilonNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void* data, const MultiInitialStateNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void* data, const NFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void* data, const DFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void* data, const ExtendedNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void* data, const CompactNFA& automaton) const {
-	std::set<automaton::State> & out = *((std::set<automaton::State>*) data);
-	out = std::move(this->usefullStates(automaton));
-}
-
-void UsefullStates::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void UsefullStates::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-void UsefullStates::Visit(void*, const DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void UsefullStates::Visit(void*, const SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void UsefullStates::Visit(void*, const InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void UsefullStates::Visit(void*, const InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void UsefullStates::Visit(void*, const VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void UsefullStates::Visit(void*, const VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void UsefullStates::Visit(void*, const RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void UsefullStates::Visit(void*, const RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void UsefullStates::Visit(void*, const NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void UsefullStates::Visit(void*, const SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void UsefullStates::Visit(void*, const OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-const UsefullStates UsefullStates::USEFULL_STATES;
+auto UsefullStatesDFA = UsefullStates::RegistratorWrapper<std::set<automaton::State>, automaton::DFA>(UsefullStates::getInstance(), UsefullStates::usefullStates);
 
 } /* namespace efficient */
 
diff --git a/alib2elgo/src/automaton/properties/efficient/UsefullStates.h b/alib2elgo/src/automaton/properties/efficient/UsefullStates.h
index 3d2a0f85d4..eeace37e5d 100644
--- a/alib2elgo/src/automaton/properties/efficient/UsefullStates.h
+++ b/alib2elgo/src/automaton/properties/efficient/UsefullStates.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_USEFULL_STATES_H_
 #define EFFICIENT_USEFULL_STATES_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -21,10 +22,8 @@ namespace properties {
 
 namespace efficient {
 
-class UsefullStates : public VisitableAutomatonBase::const_visitor_type {
+class UsefullStates : public std::SingleDispatch<std::set<automaton::State>, automaton::AutomatonBase> {
 public:
-	UsefullStates() {}
-
 	static std::set<automaton::State> usefullStates( const automaton::Automaton & automaton );
 
 	/**
@@ -33,28 +32,10 @@ public:
 	template<class T>
 	static std::set<automaton::State> usefullStates( const T & fsm );
 
-private:
-	void Visit(void*, const EpsilonNFA& automaton) const;
-	void Visit(void*, const MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const NFA& automaton) const;
-	void Visit(void*, const DFA& automaton) const;
-	void Visit(void*, const ExtendedNFA& automaton) const;
-	void Visit(void*, const CompactNFA& automaton) const;
-	void Visit(void*, const DPDA& automaton) const;
-	void Visit(void*, const NFTA& automaton) const;
-	void Visit(void*, const DFTA& automaton) const;
-	void Visit(void*, const SinglePopDPDA& automaton) const;
-	void Visit(void*, const InputDrivenDPDA& automaton) const;
-	void Visit(void*, const InputDrivenNPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const NPDA& automaton) const;
-	void Visit(void*, const SinglePopNPDA& automaton) const;
-	void Visit(void*, const OneTapeDTM& automaton) const;
-
-	static const UsefullStates USEFULL_STATES;
+	static UsefullStates& getInstance() {
+		static UsefullStates res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.cpp b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.cpp
index 6ec1e00cd3..be269dd1ef 100644
--- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.cpp
+++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.cpp
@@ -20,16 +20,22 @@ automaton::DFA EpsilonRemoverIncoming::remove(const automaton::DFA& origFSM)
 	return origFSM;
 }
 
+auto EpsilonRemoverIncomingDFA = EpsilonRemoverIncoming::RegistratorWrapper<automaton::DFA, automaton::DFA>(EpsilonRemoverIncoming::getInstance(), EpsilonRemoverIncoming::remove);
+
 automaton::MultiInitialStateNFA EpsilonRemoverIncoming::remove(const automaton::MultiInitialStateNFA& origFSM)
 {
 	return origFSM;
 }
 
+auto EpsilonRemoverIncomingMultiInitialStateNFA = EpsilonRemoverIncoming::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(EpsilonRemoverIncoming::getInstance(), EpsilonRemoverIncoming::remove);
+
 automaton::NFA EpsilonRemoverIncoming::remove(const automaton::NFA& origFSM)
 {
 	return origFSM;
 }
 
+auto EpsilonRemoverIncomingNFA = EpsilonRemoverIncoming::RegistratorWrapper<automaton::NFA, automaton::NFA>(EpsilonRemoverIncoming::getInstance(), EpsilonRemoverIncoming::remove);
+
 automaton::NFA EpsilonRemoverIncoming::remove( const automaton::EpsilonNFA & origFSM ) {
 	automaton::NFA fsm(origFSM.getInitialState());
 
@@ -70,96 +76,12 @@ automaton::NFA EpsilonRemoverIncoming::remove( const automaton::EpsilonNFA & ori
 	return fsm;
 }
 
-automaton::Automaton EpsilonRemoverIncoming::remove(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, EpsilonRemoverIncoming::EPSILON_REMOVER_INCOMING);
-	automaton::Automaton res = std::move(*out);
-	delete out;
-	return res;
-}
-
-void EpsilonRemoverIncoming::Visit(void* data, const automaton::EpsilonNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverIncoming::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverIncoming::Visit(void* data, const automaton::NFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverIncoming::Visit(void* data, const automaton::DFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
+auto EpsilonRemoverIncomingEpsilonNFA = EpsilonRemoverIncoming::RegistratorWrapper<automaton::NFA, automaton::EpsilonNFA>(EpsilonRemoverIncoming::getInstance(), EpsilonRemoverIncoming::remove);
 
-void EpsilonRemoverIncoming::Visit(void*, const automaton::ExtendedNFA& ) const {
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::CompactNFA& ) const {
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void EpsilonRemoverIncoming::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+automaton::Automaton EpsilonRemoverIncoming::remove(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const EpsilonRemoverIncoming EpsilonRemoverIncoming::EPSILON_REMOVER_INCOMING;
-
 } /* namespace efficient */
 
 } /* namespace simplify */
diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h
index 35113669b7..5798c9c789 100644
--- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h
+++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverIncoming.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_EPSILON_REMOVER_INCOMING_H_
 #define EFFICIENT_EPSILON_REMOVER_INCOMING_H_
 
+#include <common/multipleDispatch.hpp>
 #include <map>
 #include <algorithm>
 
@@ -25,10 +26,8 @@ namespace simplify {
 
 namespace efficient {
 
-class EpsilonRemoverIncoming : public automaton::VisitableAutomatonBase::const_visitor_type {
+class EpsilonRemoverIncoming : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	EpsilonRemoverIncoming() {}
-
 	static automaton::Automaton remove( const automaton::Automaton & automaton );
 
 	/**
@@ -39,28 +38,10 @@ public:
 	static automaton::NFA remove( const automaton::NFA & fsm );
 	static automaton::DFA remove( const automaton::DFA & fsm );
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-
-	static const EpsilonRemoverIncoming EPSILON_REMOVER_INCOMING;
+	static EpsilonRemoverIncoming& getInstance() {
+		static EpsilonRemoverIncoming res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.cpp b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.cpp
index 871d1674e7..a40bc52d51 100644
--- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.cpp
+++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.cpp
@@ -20,16 +20,22 @@ automaton::DFA EpsilonRemoverOutgoing::remove(const automaton::DFA& origFSM)
 	return origFSM;
 }
 
+auto EpsilonRemoverOutgoingDFA = EpsilonRemoverOutgoing::RegistratorWrapper<automaton::DFA, automaton::DFA>(EpsilonRemoverOutgoing::getInstance(), EpsilonRemoverOutgoing::remove);
+
 automaton::MultiInitialStateNFA EpsilonRemoverOutgoing::remove(const automaton::MultiInitialStateNFA& origFSM)
 {
 	return origFSM;
 }
 
+auto EpsilonRemoverOutgoingMultiInitialStateNFA = EpsilonRemoverOutgoing::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(EpsilonRemoverOutgoing::getInstance(), EpsilonRemoverOutgoing::remove);
+
 automaton::NFA EpsilonRemoverOutgoing::remove(const automaton::NFA& origFSM)
 {
 	return origFSM;
 }
 
+auto EpsilonRemoverOutgoingNFA = EpsilonRemoverOutgoing::RegistratorWrapper<automaton::NFA, automaton::NFA>(EpsilonRemoverOutgoing::getInstance(), EpsilonRemoverOutgoing::remove);
+
 automaton::MultiInitialStateNFA EpsilonRemoverOutgoing::remove( const automaton::EpsilonNFA & origFSM ) {
 	automaton::MultiInitialStateNFA fsm;
 	fsm.setStates( origFSM.getStates() );
@@ -54,96 +60,12 @@ automaton::MultiInitialStateNFA EpsilonRemoverOutgoing::remove( const automaton:
 	return fsm;
 }
 
-automaton::Automaton EpsilonRemoverOutgoing::remove(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, EpsilonRemoverOutgoing::EPSILON_REMOVER_OUTGOING);
-	automaton::Automaton res = std::move(*out);
-	delete out;
-	return res;
-}
-
-void EpsilonRemoverOutgoing::Visit(void* data, const automaton::EpsilonNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverOutgoing::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverOutgoing::Visit(void* data, const automaton::NFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverOutgoing::Visit(void* data, const automaton::DFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
+auto EpsilonRemoverOutgoingEpsilonNFA = EpsilonRemoverOutgoing::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::EpsilonNFA>(EpsilonRemoverOutgoing::getInstance(), EpsilonRemoverOutgoing::remove);
 
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::ExtendedNFA& ) const {
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::CompactNFA& ) const {
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void EpsilonRemoverOutgoing::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+automaton::Automaton EpsilonRemoverOutgoing::remove(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const EpsilonRemoverOutgoing EpsilonRemoverOutgoing::EPSILON_REMOVER_OUTGOING;
-
 } /*namespace efficient */
 
 } /* namespace simplify */
diff --git a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h
index 0269ad611f..2a4bc93be8 100644
--- a/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h
+++ b/alib2elgo/src/automaton/simplify/efficient/EpsilonRemoverOutgoing.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_EPSILON_REMOVER_OUTGOING_H_
 #define EFFICIENT_EPSILON_REMOVER_OUTGOING_H_
 
+#include <common/multipleDispatch.hpp>
 #include <map>
 #include <algorithm>
 
@@ -25,10 +26,8 @@ namespace simplify {
 
 namespace efficient {
 
-class EpsilonRemoverOutgoing : public automaton::VisitableAutomatonBase::const_visitor_type {
+class EpsilonRemoverOutgoing : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	EpsilonRemoverOutgoing() {}
-
 	static automaton::Automaton remove( const automaton::Automaton & automaton );
 
 	/**
@@ -39,28 +38,10 @@ public:
 	static automaton::NFA remove( const automaton::NFA & fsm );
 	static automaton::DFA remove( const automaton::DFA & fsm );
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-
-	static const EpsilonRemoverOutgoing EPSILON_REMOVER_OUTGOING;
+	static EpsilonRemoverOutgoing& getInstance() {
+		static EpsilonRemoverOutgoing res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/simplify/efficient/Trim.cpp b/alib2elgo/src/automaton/simplify/efficient/Trim.cpp
index fd593234d2..7828b92ec2 100644
--- a/alib2elgo/src/automaton/simplify/efficient/Trim.cpp
+++ b/alib2elgo/src/automaton/simplify/efficient/Trim.cpp
@@ -30,105 +30,17 @@ T Trim::trim( const T & fsm ) {
 	return UnreachableStatesRemover::remove(UselessStatesRemover::remove(fsm));
 }
 
-template automaton::EpsilonNFA Trim::trim( const automaton::EpsilonNFA & fsm );
-template automaton::NFA Trim::trim( const automaton::NFA & fsm );
-template automaton::MultiInitialStateNFA Trim::trim( const automaton::MultiInitialStateNFA & fsm );
-template automaton::CompactNFA Trim::trim( const automaton::CompactNFA & fsm );
-template automaton::ExtendedNFA Trim::trim( const automaton::ExtendedNFA & fsm );
-template automaton::DFA Trim::trim( const automaton::DFA & fsm );
+auto TrimDFA = Trim::RegistratorWrapper<automaton::DFA, automaton::DFA>(Trim::getInstance(), Trim::trim);
+auto TrimNFA = Trim::RegistratorWrapper<automaton::NFA, automaton::NFA>(Trim::getInstance(), Trim::trim);
+auto TrimMultiInitialStateNFA = Trim::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(Trim::getInstance(), Trim::trim);
+auto TrimEpsilonNFA = Trim::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(Trim::getInstance(), Trim::trim);
+auto TrimCompactNFA = Trim::RegistratorWrapper<automaton::CompactNFA, automaton::CompactNFA>(Trim::getInstance(), Trim::trim);
+auto TrimExtendedNFA = Trim::RegistratorWrapper<automaton::ExtendedNFA, automaton::ExtendedNFA>(Trim::getInstance(), Trim::trim);
 
 automaton::Automaton Trim::trim(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, Trim::TRIM);
-	automaton::Automaton res = std::move(*out);
-	delete out;
-	return res;
+	return getInstance().dispatch(automaton.getData());
 }
 
-void Trim::Visit(void* data, const automaton::EpsilonNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void* data, const automaton::NFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void* data, const automaton::DFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void* data, const automaton::ExtendedNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void* data, const automaton::CompactNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->trim(automaton));
-}
-
-void Trim::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void Trim::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-void Trim::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void Trim::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void Trim::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void Trim::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void Trim::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void Trim::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void Trim::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void Trim::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void Trim::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void Trim::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void Trim::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-const Trim Trim::TRIM;
-
 } /* namespace efficient */
 
 } /* namespace simplify */
diff --git a/alib2elgo/src/automaton/simplify/efficient/Trim.h b/alib2elgo/src/automaton/simplify/efficient/Trim.h
index 9c51dc34a6..a53c080a86 100644
--- a/alib2elgo/src/automaton/simplify/efficient/Trim.h
+++ b/alib2elgo/src/automaton/simplify/efficient/Trim.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_AUTOMATON_TRIM_H_
 #define EFFICIENT_AUTOMATON_TRIM_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -19,10 +20,8 @@ namespace simplify {
 
 namespace efficient {
 
-class Trim : public automaton::VisitableAutomatonBase::const_visitor_type {
+class Trim : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	Trim() {}
-
 	static automaton::Automaton trim( const automaton::Automaton & automaton );
 
 	/**
@@ -31,28 +30,10 @@ public:
 	template<class T>
 	static T trim( const T & fsm );
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-
-	static const Trim TRIM;
+	static Trim& getInstance() {
+		static Trim res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp
index 9271cd4c59..8cb672ebba 100644
--- a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp
+++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp
@@ -53,10 +53,10 @@ T UnreachableStatesRemover::remove( const T & fsm ) {
 	return M;
 }
 
-template automaton::EpsilonNFA UnreachableStatesRemover::remove( const automaton::EpsilonNFA & fsm );
-template automaton::NFA UnreachableStatesRemover::remove( const automaton::NFA & fsm );
-template automaton::CompactNFA UnreachableStatesRemover::remove( const automaton::CompactNFA & fsm );
-template automaton::ExtendedNFA UnreachableStatesRemover::remove( const automaton::ExtendedNFA & fsm );
+auto UnreachableStatesRemoverEpsilonNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
+auto UnreachableStatesRemoverNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::NFA, automaton::NFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
+auto UnreachableStatesRemoverCompactNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::CompactNFA, automaton::CompactNFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
+auto UnreachableStatesRemoverExtendedNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::ExtendedNFA, automaton::ExtendedNFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
 
 template<>
 automaton::DFA UnreachableStatesRemover::remove( const automaton::DFA & fsm ) {
@@ -84,6 +84,8 @@ automaton::DFA UnreachableStatesRemover::remove( const automaton::DFA & fsm ) {
 	return M;
 }
 
+auto UnreachableStatesRemoverDFA = UnreachableStatesRemover::RegistratorWrapper<automaton::DFA, automaton::DFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
+
 template<>
 automaton::MultiInitialStateNFA UnreachableStatesRemover::remove( const automaton::MultiInitialStateNFA & fsm ) {
 	// 1a
@@ -113,98 +115,12 @@ automaton::MultiInitialStateNFA UnreachableStatesRemover::remove( const automato
 	return M;
 }
 
-automaton::Automaton UnreachableStatesRemover::remove(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, UnreachableStatesRemover::UNREACHABLE_STATES_REMOVER);
-	automaton::Automaton res = std::move(*out);
-	delete out;
-	return res;
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::EpsilonNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::NFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::DFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::ExtendedNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void* data, const automaton::CompactNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UnreachableStatesRemover::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
+auto UnreachableStatesRemoverMultiInitialStateNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(UnreachableStatesRemover::getInstance(), UnreachableStatesRemover::remove);
 
-void UnreachableStatesRemover::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void UnreachableStatesRemover::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+automaton::Automaton UnreachableStatesRemover::remove(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const UnreachableStatesRemover UnreachableStatesRemover::UNREACHABLE_STATES_REMOVER;
-
 } /* namespace efficient */
 
 } /* namespace simplify */
diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h
index 048cccf3e6..4d0f84ac99 100644
--- a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h
+++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_UNREACHABLE_STATES_REMOVER_H_
 #define EFFICIENT_UNREACHABLE_STATES_REMOVER_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -19,10 +20,8 @@ namespace simplify {
 
 namespace efficient {
 
-class UnreachableStatesRemover : public automaton::VisitableAutomatonBase::const_visitor_type {
+class UnreachableStatesRemover : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	UnreachableStatesRemover() {}
-
 	static automaton::Automaton remove( const automaton::Automaton & automaton );
 
 	/**
@@ -31,28 +30,10 @@ public:
 	template<class T>
 	static T remove( const T & automaton );
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-
-	static const UnreachableStatesRemover UNREACHABLE_STATES_REMOVER;
+	static UnreachableStatesRemover& getInstance() {
+		static UnreachableStatesRemover res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp
index 8299c4540a..4bf6f2b150 100644
--- a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp
+++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp
@@ -55,10 +55,10 @@ T UselessStatesRemover::remove( const T & fsm ) {
 	return M;
 }
 
-template automaton::EpsilonNFA UselessStatesRemover::remove( const automaton::EpsilonNFA & fsm );
-template automaton::NFA UselessStatesRemover::remove( const automaton::NFA & fsm );
-template automaton::CompactNFA UselessStatesRemover::remove( const automaton::CompactNFA & fsm );
-template automaton::ExtendedNFA UselessStatesRemover::remove( const automaton::ExtendedNFA & fsm );
+auto UselessStatesRemoverEpsilonNFA = UselessStatesRemover::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
+auto UselessStatesRemoverNFA = UselessStatesRemover::RegistratorWrapper<automaton::NFA, automaton::NFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
+auto UselessStatesRemoverCompactNFA = UselessStatesRemover::RegistratorWrapper<automaton::CompactNFA, automaton::CompactNFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
+auto UselessStatesRemoverExtendedNFA = UselessStatesRemover::RegistratorWrapper<automaton::ExtendedNFA, automaton::ExtendedNFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
 
 template<>
 automaton::DFA UselessStatesRemover::remove( const automaton::DFA & fsm ) {
@@ -88,6 +88,8 @@ automaton::DFA UselessStatesRemover::remove( const automaton::DFA & fsm ) {
 	return M;
 }
 
+auto UselessStatesRemoverDFA = UselessStatesRemover::RegistratorWrapper<automaton::DFA, automaton::DFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
+
 template<>
 automaton::MultiInitialStateNFA UselessStatesRemover::remove( const automaton::MultiInitialStateNFA & fsm ) {
 	// 1.
@@ -122,98 +124,12 @@ automaton::MultiInitialStateNFA UselessStatesRemover::remove( const automaton::M
 	return M;
 }
 
-automaton::Automaton UselessStatesRemover::remove(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, UselessStatesRemover::USELESS_STATES_REMOVER);
-	automaton::Automaton res = std::move(*out);
-	delete out;
-	return res;
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::EpsilonNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::NFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::DFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::ExtendedNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void* data, const automaton::CompactNFA& automaton) const {
-	automaton::Automaton* & out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->remove(automaton));
-}
-
-void UselessStatesRemover::Visit(void*, const DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void UselessStatesRemover::Visit(void*, const NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
+auto UselessStatesRemoverMultiInitialStateNFA = UselessStatesRemover::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(UselessStatesRemover::getInstance(), UselessStatesRemover::remove);
 
-void UselessStatesRemover::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void UselessStatesRemover::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+automaton::Automaton UselessStatesRemover::remove(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const UselessStatesRemover UselessStatesRemover::USELESS_STATES_REMOVER;
-
 } /* namespace efficient */
 
 } /* namespace simplify */
diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h
index dfcd19bd17..eddf1eab02 100644
--- a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h
+++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h
@@ -8,6 +8,7 @@
 #ifndef EFFICIENT_USELESS_STATES_REMOVER_H_
 #define EFFICIENT_USELESS_STATES_REMOVER_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -19,10 +20,8 @@ namespace simplify {
 
 namespace efficient {
 
-class UselessStatesRemover : public automaton::VisitableAutomatonBase::const_visitor_type {
+class UselessStatesRemover : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	UselessStatesRemover() {}
-
 	static automaton::Automaton remove( const automaton::Automaton & automaton );
 
 	/**
@@ -31,28 +30,10 @@ public:
 	template<class T>
 	static T remove( const T & automaton );
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-
-	static const UselessStatesRemover USELESS_STATES_REMOVER;
+	static UselessStatesRemover& getInstance() {
+		static UselessStatesRemover res;
+		return res;
+	}
 };
 
 } /* namespace efficient */
-- 
GitLab