diff --git a/alib2algo/src/automaton/simplify/Normalize.cpp b/alib2algo/src/automaton/simplify/Normalize.cpp
index 1780efd4503954c258aee59cd8b885a7fc39b574..37bc52557b83dbb4b4df4d930ebcf01969130ea6 100644
--- a/alib2algo/src/automaton/simplify/Normalize.cpp
+++ b/alib2algo/src/automaton/simplify/Normalize.cpp
@@ -24,45 +24,53 @@ namespace automaton {
 
 namespace simplify {
 
-automaton::DFA Normalize::normalize(automaton::DFA& fsm) {
+automaton::Automaton Normalize::normalize(const automaton::Automaton& automaton) {
+	automaton::Automaton* out = NULL;
+	automaton.getData().Accept((void*) &out, Normalize::NORMALIZE);
+	automaton::Automaton res = std::move(*out);
+	delete out;
+	return res;
+}
+
+automaton::DFA Normalize::normalize(const automaton::DFA& fsm) {
 	int counter = 0;
 	std::map<automaton::State, int > normalizationData;
 	std::deque<automaton::State > processingData;
-	
-	normalizationData.insert(std::pair<automaton::State, int>(fsm.getInitialState(), counter++));
+
+	normalizationData.insert(std::make_pair(fsm.getInitialState(), counter++));
 	processingData.push_back(fsm.getInitialState());
-	
+
 	while(!processingData.empty()) {
 		automaton::State current = processingData.front();
 		processingData.pop_front();
-		
+
 		std::map<std::pair<automaton::State, alphabet::Symbol>, automaton::State> transitionsMap = fsm.getTransitionsFromState(current);
 		// Transitions are trivialy sorted by input symbol (from state is the same)
-		
-		for(auto iter = fsm.getTransitions().begin(); iter != fsm.getTransitions().end(); iter++) {
+
+		for(auto iter = transitionsMap.begin(); iter != transitionsMap.end(); iter++) {
 			if(normalizationData.find(iter->second) == normalizationData.end()) {
 				normalizationData.insert(std::pair<automaton::State, int>(iter->second, counter++));
 				processingData.push_back(iter->second);
 			}
 		}
 	}
-	
+
 	if(normalizationData.size() != fsm.getStates().size()) {
 		throw exception::AlibException("Automaton normalize require minimal deterministic finite automaton");
 	}
-	
+
 	automaton::DFA result(automaton::State(normalizationData.find(fsm.getInitialState())->second));
-	
+
 	result.setInputSymbols(fsm.getInputAlphabet());
-	
+
 	for(auto iter = fsm.getStates().begin(); iter != fsm.getStates().end(); iter++) {
 		result.addState(automaton::State(normalizationData.find(*iter)->second));
 	}
-	
+
 	for(auto iter = fsm.getFinalStates().begin(); iter != fsm.getFinalStates().end(); iter++) {
 		result.addFinalState(automaton::State(normalizationData.find(*iter)->second));
 	}
-	
+
 	for(auto iter = fsm.getTransitions().begin(); iter != fsm.getTransitions().end(); iter++) {
 		result.addTransition(automaton::State(normalizationData.find(iter->first.first)->second), iter->first.second, automaton::State(normalizationData.find(iter->second)->second));
 	}
@@ -70,6 +78,156 @@ automaton::DFA Normalize::normalize(automaton::DFA& fsm) {
 	return result;
 }
 
+automaton::DPDA Normalize::normalize(const automaton::DPDA& pda) {
+	int counterState = 0;
+	std::map<automaton::State, int > normalizationDataState;
+	int counterSymbol = 0;
+	std::map<alphabet::Symbol, int > normalizationDataSymbol;
+	std::deque< automaton::State > processingData;
+
+	normalizationDataState.insert(std::make_pair(pda.getInitialState(), counterState++));
+	normalizationDataSymbol.insert(std::make_pair(pda.getInitialSymbol(), counterSymbol++));
+	processingData.push_back(pda.getInitialState());
+
+	while(!processingData.empty()) {
+		automaton::State current = processingData.front();
+		processingData.pop_front();
+
+		std::map<std::tuple<State, std::variant<string::Epsilon, alphabet::Symbol>, std::vector<alphabet::Symbol> >, std::pair<State, std::vector<alphabet::Symbol> > > transitionsMap = pda.getTransitionsFromState(current);
+		std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set< std::pair<std::vector< alphabet::Symbol >, std::pair<State, std::vector<alphabet::Symbol > > > > > transform;
+
+		for(auto iter = transitionsMap.begin(); iter != transitionsMap.end(); iter++) {
+			transform[std::make_pair(std::get<0>(iter->first), std::get<1>(iter->first))].insert(std::make_pair(std::get<2>(iter->first), iter->second));
+		}
+		// Transitions are trivialy sorted by input symbol (from state is the same)
+
+		for(const auto& iter : transform) {
+			bool sign = false;
+			for(const auto& iter2 : iter.second) {
+				bool tmp = std::all_of(iter2.first.begin(), iter2.first.end(), [&](const alphabet::Symbol& symbol) { return normalizationDataSymbol.find(symbol) != normalizationDataSymbol.end(); });
+				if( tmp ) {
+					if( normalizationDataState.find(iter2.second.first) == normalizationDataState.end() ) {
+						normalizationDataState.insert(std::make_pair(iter2.second.first, counterState++));
+						processingData.push_back(iter2.second.first);
+					}
+					for(const auto& iter3 : iter2.second.second) {
+						if( normalizationDataSymbol.find(iter3) == normalizationDataSymbol.end() ) {
+							normalizationDataSymbol.insert(std::make_pair(iter3, counterSymbol++));
+						}
+					}
+				} else {
+					sign = true;
+				}
+			}
+			if(sign) {
+				processingData.push_back(iter.first.first);
+			}
+		}
+	}
+
+	if(normalizationDataState.size() != pda.getStates().size() || normalizationDataSymbol.size() != pda.getStackAlphabet().size()) {
+		throw exception::AlibException("Automaton normalize require connected deterministic pushdown automaton");
+	}
+
+	automaton::DPDA result(automaton::State(normalizationDataState.find(pda.getInitialState())->second), alphabet::symbolFrom(normalizationDataSymbol.find(pda.getInitialSymbol())->second));
+
+	result.setInputSymbols(pda.getInputAlphabet());
+
+	for(auto iter = pda.getStackAlphabet().begin(); iter != pda.getStackAlphabet().end(); iter++) {
+		result.addStackSymbol(alphabet::symbolFrom(normalizationDataSymbol.find(*iter)->second));
+	}
+
+	for(auto iter = pda.getStates().begin(); iter != pda.getStates().end(); iter++) {
+		result.addState(automaton::State(normalizationDataState.find(*iter)->second));
+	}
+
+	for(auto iter = pda.getFinalStates().begin(); iter != pda.getFinalStates().end(); iter++) {
+		result.addFinalState(automaton::State(normalizationDataState.find(*iter)->second));
+	}
+
+	for(auto iter = pda.getTransitions().begin(); iter != pda.getTransitions().end(); iter++) {
+		std::vector<alphabet::Symbol> pop;
+		for(const auto& elem : std::get<2>(iter->first)) {
+			pop.push_back(alphabet::symbolFrom(normalizationDataSymbol.find(elem)->second));
+		}
+		std::vector<alphabet::Symbol> push;
+		for(const auto& elem : iter->second.second) {
+			push.push_back(alphabet::symbolFrom(normalizationDataSymbol.find(elem)->second));
+		}
+		result.addTransition(automaton::State(normalizationDataState.find(std::get<0>(iter->first))->second), std::get<1>(iter->first), pop, automaton::State(normalizationDataState.find(iter->second.first)->second), push);
+	}
+
+	return result;
+}
+
+void Normalize::Visit(void*, const automaton::EpsilonNFA&) const {
+	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
+}
+
+void Normalize::Visit(void* data, const automaton::DFA& automaton) const {
+	automaton::Automaton* & out = *((automaton::Automaton**) data);
+	out = new automaton::Automaton(this->normalize(automaton));
+}
+
+void Normalize::Visit(void*, const automaton::MultiInitialStateNFA&) const {
+	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
+}
+
+void Normalize::Visit(void*, const automaton::NFA&) const {
+	throw exception::AlibException("Unsupported automaton type DFA");
+}
+
+void Normalize::Visit(void*, const automaton::ExtendedNFA& ) const {
+	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
+}
+
+void Normalize::Visit(void*, const automaton::CompactNFA& ) const {
+	throw exception::AlibException("Unsupported automaton type CompactNFA");
+}
+
+void Normalize::Visit(void* data, const automaton::DPDA& automaton) const {
+	automaton::Automaton* & out = *((automaton::Automaton**) data);
+	out = new automaton::Automaton(this->normalize(automaton));
+}
+
+void Normalize::Visit(void*, const automaton::SinglePopDPDA&) const {
+	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
+}
+
+void Normalize::Visit(void*, const automaton::InputDrivenNPDA&) const {
+	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
+}
+
+void Normalize::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
+}
+
+void Normalize::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
+	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
+}
+
+void Normalize::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
+}
+
+void Normalize::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
+	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
+}
+
+void Normalize::Visit(void*, const automaton::NPDA&) const {
+	throw exception::AlibException("Unsupported automaton type NPDA");
+}
+
+void Normalize::Visit(void*, const automaton::SinglePopNPDA&) const {
+	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
+}
+
+void Normalize::Visit(void*, const automaton::OneTapeDTM&) const {
+	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
+}
+
+const Normalize Normalize::NORMALIZE;
+
 } /* namespace simplify */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/simplify/Normalize.h b/alib2algo/src/automaton/simplify/Normalize.h
index 48a6df5a2ee60880daf391cc33fa86ed069ac8ef..79523da733cc1c1e989cdd85508c98164c6dd516 100644
--- a/alib2algo/src/automaton/simplify/Normalize.h
+++ b/alib2algo/src/automaton/simplify/Normalize.h
@@ -8,16 +8,44 @@
 #ifndef NORMALIZE_H_
 #define NORMALIZE_H_
 
-#include "automaton/FSM/DFA.h"
+#include <automaton/FSM/DFA.h>
+#include <automaton/PDA/DPDA.h>
+#include <automaton/Automaton.h>
 
 namespace automaton {
 
 namespace simplify {
 
-class Normalize {
+class Normalize : public automaton::VisitableAutomatonBase::const_visitor_type {
 public:
-	static automaton::DFA normalize(automaton::DFA& dfa);
-
+	/**
+	 * @param dfa automaton to normalize
+	 */
+	static automaton::Automaton normalize(const automaton::Automaton& dfa);
+
+	static automaton::DFA normalize(const automaton::DFA& dfa);
+	static automaton::DPDA normalize(const automaton::DPDA& dfa);
+
+
+protected:
+	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::DPDA& automaton) const;
+	void Visit(void*, const automaton::SinglePopDPDA& 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 Normalize NORMALIZE;
 };
 
 } /* namespace simplify */
diff --git a/anormalize2/src/anormalize.cpp b/anormalize2/src/anormalize.cpp
index 66763a09ae2a399e99dd394cd6db85c0ff135971..34483b8ba6ab100b61ca12df8bdd62790c85f0bc 100644
--- a/anormalize2/src/anormalize.cpp
+++ b/anormalize2/src/anormalize.cpp
@@ -14,26 +14,17 @@
 int main(int argc, char** argv) {
 
 	try {
-
-		automaton::DFA* automatonPointer = NULL;
-
 		if (argc == 2 && std::string("-h").compare(argv[1]) == 0) {
 			std::cout << "Automaton normalize." << std::endl << "Usage: anormalize automaton.xml" << std::endl;
 			return -1;
 		} else if (argc == 1 || (argc == 2 && std::string("--").compare(argv[1]) == 0)) {
-			automatonPointer = static_cast<automaton::DFA*>(std::move(alib::DataFactory::fromStdin<automaton::DFA>()).plunder());
+			alib::DataFactory::toStdout(automaton::simplify::Normalize::normalize(alib::DataFactory::fromStdin<automaton::Automaton>()));
 		} else if (argc == 2) {
-			automatonPointer = static_cast<automaton::DFA*>(std::move(alib::DataFactory::fromFile<automaton::DFA>(argv[1])).plunder());
+			alib::DataFactory::toStdout(automaton::simplify::Normalize::normalize(alib::DataFactory::fromFile<automaton::Automaton>(argv[1])));
 		} else {
-			std::cout << "Automaton normalize require deterministic finite automaton" << std::endl;
+			std::cout << "Automaton normalize require deterministic automaton" << std::endl;
 			return 1;
 		}
-		
-		automaton::DFA res = automaton::simplify::Normalize::normalize(*automatonPointer);
-		alib::DataFactory::toStdout(res);
-
-		delete automatonPointer;
-
 		return 0;
 
 	} catch (const exception::AlibException& exception) {