From 27e4b72fd5e1fb4bff6eecf27fba77558491532c Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sun, 29 May 2016 22:52:13 +0200
Subject: [PATCH] Tree automata use components

---
 .../exact/ExactPatternMatchingAutomaton.cpp   |   2 +-
 .../exact/ExactSubtreeMatchingAutomaton.cpp   |   2 +-
 .../determinize/DeterminizeNFTAPart.cxx       |   2 +-
 .../automaton/determinize/determinizeTest.cpp |   2 +-
 alib2data/src/automaton/TA/DFTA.cpp           | 135 ++++++++++++------
 alib2data/src/automaton/TA/DFTA.h             |  78 +++++++---
 alib2data/src/automaton/TA/NFTA.cpp           | 128 +++++++++++------
 alib2data/src/automaton/TA/NFTA.h             |  78 +++++++---
 .../test-src/automaton/AutomatonTest.cpp      |   8 +-
 9 files changed, 295 insertions(+), 140 deletions(-)

diff --git a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
index a0cb96c0bb..e79c62ad0d 100644
--- a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
+++ b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp
@@ -232,7 +232,7 @@ automaton::NFTA ExactPatternMatchingAutomaton::construct ( const tree::RankedPat
 	alphabet.erase ( pattern.getSubtreeWildcard ( ) );
 
 	automaton::NFTA res;
-	res.setInputSymbols ( alphabet );
+	res.setInputAlphabet ( alphabet );
 
 	int nextState = 0;
 
diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp
index 432f1c1638..6a3cd905d2 100644
--- a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp
+++ b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp
@@ -100,7 +100,7 @@ automaton::State constructRecursive ( const tree::RankedNode & node, automaton::
 automaton::NFTA ExactSubtreeMatchingAutomaton::construct ( const tree::RankedTree & pattern ) {
 	automaton::NFTA res;
 
-	res.setInputSymbols ( pattern.getAlphabet ( ) );
+	res.setInputAlphabet ( pattern.getAlphabet ( ) );
 	int nextState = 0;
 	res.addFinalState ( constructRecursive ( pattern.getRoot ( ), res, nextState ) );
 	return res;
diff --git a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.cxx b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.cxx
index a76a5e00c4..fbc5d2557c 100644
--- a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.cxx
+++ b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.cxx
@@ -31,7 +31,7 @@ std::set<State> getTransitionRightSide(const NFTA & nfta, const alphabet::Ranked
 
 DFTA Determinize::determinize(const NFTA & nfta) {
 	DFTA res;
-	res.setInputSymbols(nfta.getInputAlphabet());
+	res.setInputAlphabet(nfta.getInputAlphabet());
 	for (const auto & state : nfta.getStates()) res.addState(createDFAState({state}));
 	for (const auto & state : nfta.getFinalStates()) res.addFinalState(createDFAState({state}));
 
diff --git a/alib2algo/test-src/automaton/determinize/determinizeTest.cpp b/alib2algo/test-src/automaton/determinize/determinizeTest.cpp
index 500099a10c..f3bb704b9f 100644
--- a/alib2algo/test-src/automaton/determinize/determinizeTest.cpp
+++ b/alib2algo/test-src/automaton/determinize/determinizeTest.cpp
@@ -113,7 +113,7 @@ void determinizeTest::testDeterminizeNFTA() {
   const alphabet::RankedSymbol b ('b', 1);
   const alphabet::RankedSymbol c ('c', 0);
   const std::set<alphabet::RankedSymbol> alphabet {a, b, c};
-  automaton.setInputSymbols(alphabet);
+  automaton.setInputAlphabet(alphabet);
 
   automaton.addState(automaton::State(1));
   automaton.addState(automaton::State(2));
diff --git a/alib2data/src/automaton/TA/DFTA.cpp b/alib2data/src/automaton/TA/DFTA.cpp
index 91029cc875..911d8edfae 100644
--- a/alib2data/src/automaton/TA/DFTA.cpp
+++ b/alib2data/src/automaton/TA/DFTA.cpp
@@ -19,8 +19,10 @@
 
 namespace automaton {
 
-DFTA::DFTA() {
+DFTA::DFTA ( std::set < State > states, std::set < alphabet::RankedSymbol > inputAlphabet, std::set < State > finalStates ) : std::Components < DFTA, alphabet::RankedSymbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::tuple < > ( ) ) {
+}
 
+DFTA::DFTA() : DFTA ( std::set < State > { }, std::set < alphabet::RankedSymbol > { }, std::set < State > { } ) {
 }
 
 AutomatonBase* DFTA::clone() const {
@@ -31,52 +33,27 @@ AutomatonBase* DFTA::plunder() && {
 	return new DFTA(std::move(*this));
 }
 
-bool DFTA::removeState(const State& state) {
-	if (finalStates.find(state) != finalStates.end()) {
-		throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state.");
-	}
-
-	AutomatonException ex ("State \"" + (std::string) state.getName() + "\" is used in transition.");
-	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, State>& t : transitions) {
-		const std::vector<State>& states = t . first.second;
-		for (const State& it : states) {
-			if (it == state) throw ex;
-		}
-		if (t . second == state) throw ex;
-	}
-
-	return states.erase(state);
-}
-
-bool DFTA::removeInputSymbol(const alphabet::RankedSymbol& symbol) {
-	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, State>& t : transitions) {
-		if (t . first.first == symbol)
-			throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used.");
-	}
-
-	return inputAlphabet.erase(symbol);
-}
-
 bool DFTA::addTransition(const alphabet::RankedSymbol & symbol, const std::vector<State> & prevStates, const State & next) {
-	if (prevStates.size() != symbol.getRank().getData())
+	if ( prevStates.size() != symbol.getRank().getData())
 		throw AutomatonException("Number of states doesn't match rank of the symbol");
 
-	if (inputAlphabet.find(symbol) == inputAlphabet.end())
+	if (! getInputAlphabet().count(symbol))
 		throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" doesn't exist.");
 
-	if (states.find(next) == states.end())
+	if (! getStates().count(next))
 		throw AutomatonException("State \"" + (std::string) next.getName() + "\" doesn't exist.");
 
 	for (const State& it : prevStates) {
-		if (states.find(it) == states.end())
+		if (! getStates().count(it))
 			throw AutomatonException("State \"" + (std::string) it . getName() + "\" doesn't exist.");
 	}
 
 	std::pair<alphabet::RankedSymbol, std::vector<State> > key = std::make_pair(symbol, prevStates);
-	const auto & it = transitions.find(key);
-	if (it != transitions.end()) {
-		if (it -> second == next) return false;
-		else throw AutomatonException("Transition already exists");
+	if ( transitions.find ( key ) != transitions.end ( ) ) {
+		if ( transitions.find ( key )->second == next )
+			return false;
+		else
+			throw AutomatonException("Transition already exists");
 	}
 
 	transitions.insert(std::make_pair(key, next));
@@ -85,15 +62,20 @@ bool DFTA::addTransition(const alphabet::RankedSymbol & symbol, const std::vecto
 
 bool DFTA::removeTransition(const alphabet::RankedSymbol symbol, const std::vector<State> & states, const State & next) {
 	std::pair<alphabet::RankedSymbol, std::vector<State> > key = std::make_pair(symbol, states);
-	const auto & it = transitions.find(key);
-	if (it == transitions.end()) return false;
-	if (it -> second != next) throw AutomatonException("Transition does not exist");
-	return transitions.erase(key);
+
+	if ( transitions.find ( key ) == transitions.end ( ) )
+		return false;
+
+	if ( transitions.find ( key )->second != next )
+		throw AutomatonException("Transition does not exist");
+
+	transitions.erase(key);
+	return true;
 }
 
 int DFTA::compare(const DFTA& other) const {
-	auto first = std::tie(states, inputAlphabet, finalStates, transitions);
-	auto second = std::tie(other.states, other.inputAlphabet, other.finalStates, other.transitions);
+	auto first = std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions);
+	auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions);
 
 	std::compare<decltype(first)> comp;
 	return comp(first, second);
@@ -101,9 +83,9 @@ int DFTA::compare(const DFTA& other) const {
 
 void DFTA::operator>>(std::ostream& out) const {
 	out << "(DFTA "
-		<< " states = " << states
-		<< " inputAlphabet = " << inputAlphabet
-		<< " finalStates = " << finalStates
+		<< " states = " << getStates()
+		<< " inputAlphabet = " << getInputAlphabet()
+		<< " finalStates = " << getFinalStates()
 		<< " transitions = " << transitions
 		<< ")";
 }
@@ -125,7 +107,7 @@ DFTA DFTA::parse(std::deque<sax::Token>::iterator& input) {
 
 	DFTA automaton;
 	automaton.setStates(std::move(states));
-	automaton.setInputSymbols(std::move(inputSymbols));
+	automaton.setInputAlphabet(std::move(inputSymbols));
 	automaton.setFinalStates(std::move(finalStates));
 
 	AutomatonFromXMLParser::parseTransitions<DFTA>(input, automaton);
@@ -172,6 +154,69 @@ void DFTA::composeTransitions(std::deque<sax::Token>& out) const {
 
 } /* namespace automaton */
 
+namespace std {
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::used ( const alphabet::RankedSymbol & symbol ) const {
+	const automaton::DFTA * automaton = static_cast < const automaton::DFTA * > ( this );
+
+	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<automaton::State> >, automaton::State>& t : automaton->getTransitions())
+		if (t.first.first == symbol)
+			return true;
+
+	return false;
+}
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::available ( const alphabet::RankedSymbol & ) const {
+	return true;
+}
+
+template < >
+void automaton::DFTA::Component < automaton::DFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::valid ( const alphabet::RankedSymbol & ) const {
+}
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::States >::used ( const automaton::State & state ) const {
+	const automaton::DFTA * automaton = static_cast < const automaton::DFTA * > ( this );
+
+	if ( automaton->getFinalStates ( ).count ( state ) )
+		return true;
+
+	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<automaton::State> >, automaton::State>& t : automaton->getTransitions())
+		if(std::contains(t.first.second.begin(), t.first.second.end(), state ) || t.second == state)
+			return true;
+
+	return false;
+}
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::States >::available ( const automaton::State & ) const {
+	return true;
+}
+
+template < >
+void automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::States >::valid ( const automaton::State & ) const {
+}
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const {
+	return false;
+}
+
+template < >
+bool automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const {
+	const automaton::DFTA * automaton = static_cast < const automaton::DFTA * > ( this );
+
+	return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state );
+}
+
+template < >
+void automaton::DFTA::Component < automaton::DFTA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const {
+}
+
+} /* namespace std */
+
 namespace alib {
 
 auto DFTAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::DFTA>();
diff --git a/alib2data/src/automaton/TA/DFTA.h b/alib2data/src/automaton/TA/DFTA.h
index 127e2d6796..f715de18cf 100644
--- a/alib2data/src/automaton/TA/DFTA.h
+++ b/alib2data/src/automaton/TA/DFTA.h
@@ -10,39 +10,83 @@
 
 #include <map>
 #include <vector>
+#include <core/components.hpp>
 #include "../AutomatonBase.h"
-#include "../common/States.h"
-
-// #include "../common/InputAlphabet.h"
+#include "../common/State.h"
 #include "../../alphabet/RankedSymbol.h"
 
 namespace automaton {
 
+class InputAlphabet;
+class States;
+class FinalStates;
+
 /**
  * Represents Finite Tree Automaton.
  * Can store nondeterministic finite automaton without epsilon transitions.
  */
-class DFTA : public AutomatonBase, public States {
-protected:
-	std::set < alphabet::RankedSymbol > inputAlphabet;
+class DFTA : public AutomatonBase, public std::Components < DFTA, alphabet::RankedSymbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < > > {
 	std::map < std::pair < alphabet::RankedSymbol, std::vector < State > >, State > transitions;
 
 public:
 	explicit DFTA ( );
+	explicit DFTA ( std::set < State > states, std::set < alphabet::RankedSymbol > inputAlphabet, std::set < State > finalStates );
 
 	virtual AutomatonBase * clone ( ) const;
 
 	virtual AutomatonBase * plunder ( ) &&;
 
-	/**
-	 * @copydoc Automaton::removeState(const State&)
-	 */
-	virtual bool removeState ( const State & state );
+	const std::set < State > & getStates ( ) const {
+		return accessComponent < States > ( ).get ( );
+	}
 
-	/**
-	 * @copydoc Automaton::removeInputSymbol(const Symbol&)
-	 */
-	virtual bool removeInputSymbol ( const alphabet::RankedSymbol & symbol );
+	bool addState ( State state ) {
+		return accessComponent < States > ( ).add ( std::move ( state ) );
+	}
+
+	void setStates ( std::set < State > states ) {
+		accessComponent < States > ( ).set ( std::move ( states ) );
+	}
+
+	void removeState ( const State & state ) {
+		accessComponent < States > ( ).remove ( state );
+	}
+
+	const std::set < State > & getFinalStates ( ) const {
+		return accessComponent < FinalStates > ( ).get ( );
+	}
+
+	bool addFinalState ( State state ) {
+		return accessComponent < FinalStates > ( ).add ( std::move ( state ) );
+	}
+
+	void setFinalStates ( std::set < State > states ) {
+		accessComponent < FinalStates > ( ).set ( std::move ( states ) );
+	}
+
+	void removeFinalState ( const State & state ) {
+		accessComponent < FinalStates > ( ).remove ( state );
+	}
+
+	const std::set < alphabet::RankedSymbol > & getInputAlphabet ( ) const {
+		return accessComponent < InputAlphabet > ( ).get ( );
+	}
+
+	bool addInputSymbol ( alphabet::RankedSymbol symbol ) {
+		return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) );
+	}
+
+	void addInputSymbols ( std::set < alphabet::RankedSymbol > symbols ) {
+		accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) );
+	}
+
+	void setInputAlphabet ( std::set < alphabet::RankedSymbol > symbols ) {
+		accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) );
+	}
+
+	void removeInputSymbol ( const alphabet::RankedSymbol & symbol ) {
+		accessComponent < InputAlphabet > ( ).remove ( symbol );
+	}
 
 	/**
 	 * Adds transition defined by parameters to the automaton.
@@ -68,12 +112,6 @@ public:
 
 	unsigned transitionsSize ( ) const;
 
-	const std::set < alphabet::RankedSymbol > & getInputAlphabet ( ) const { return inputAlphabet; }
-
-	void setInputSymbols ( const std::set < alphabet::RankedSymbol > & symbols ) { inputAlphabet = symbols; }
-
-	void addInputSymbol ( const alphabet::RankedSymbol & symbol ) { inputAlphabet.insert ( symbol ); }
-
 	virtual int compare ( const ObjectBase & other ) const {
 		if ( std::type_index ( typeid ( * this ) ) == std::type_index ( typeid ( other ) ) ) return this->compare ( ( decltype ( * this ) )other );
 
diff --git a/alib2data/src/automaton/TA/NFTA.cpp b/alib2data/src/automaton/TA/NFTA.cpp
index 6bc2a57280..93a6989ee8 100644
--- a/alib2data/src/automaton/TA/NFTA.cpp
+++ b/alib2data/src/automaton/TA/NFTA.cpp
@@ -19,14 +19,13 @@
 
 namespace automaton {
 
-NFTA::NFTA() {
+NFTA::NFTA ( std::set < State > states, std::set < alphabet::RankedSymbol > inputAlphabet, std::set < State > finalStates ) : std::Components < NFTA, alphabet::RankedSymbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < > > ( std::make_tuple ( std::move ( inputAlphabet ) ), std::tuple < > ( ), std::make_tuple ( std::move ( states ), std::move ( finalStates ) ), std::tuple < > ( ) ) {
+}
 
+NFTA::NFTA() : NFTA ( std::set < State > { }, std::set < alphabet::RankedSymbol > { }, std::set < State > { } ) {
 }
 
-NFTA::NFTA(const DFTA& other) {
-	inputAlphabet = other.getInputAlphabet();
-	states = other.getStates();
-	finalStates = other.getFinalStates();
+NFTA::NFTA(const DFTA& other) : NFTA ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) {
 	for(const auto& transition : other.getTransitions()) {
 		transitions[transition.first].insert(transition.second);
 	}
@@ -40,45 +39,18 @@ AutomatonBase* NFTA::plunder() && {
 	return new NFTA(std::move(*this));
 }
 
-bool NFTA::removeState(const State& state) {
-	if (finalStates.find(state) != finalStates.end()) {
-		throw AutomatonException("State \"" + (std::string) state.getName() + "\" is final state.");
-	}
-
-	AutomatonException ex ("State \"" + (std::string) state.getName() + "\" is used in transition.");
-	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, std::set<State> >& t : transitions) {
-		const std::vector<State>& states = t . first.second;
-		for (const State& it : states) {
-			if (it == state) throw ex;
-		}
-		if (t . second.find(state) != t . second.end()) throw ex;
-	}
-
-	return states.erase(state);
-}
-
-bool NFTA::removeInputSymbol(const alphabet::RankedSymbol& symbol) {
-	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, std::set<State> >& t : transitions) {
-		if (t . first.first == symbol)
-			throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" is used.");
-	}
-
-	return inputAlphabet.erase(symbol);
-}
-
 bool NFTA::addTransition(const alphabet::RankedSymbol & symbol, const std::vector<State> & prevStates, const State & next) {
-
 	if (prevStates.size() != symbol.getRank().getData())
 		throw AutomatonException("Number of states doesn't match rank of the symbol");
 
-	if (inputAlphabet.find(symbol) == inputAlphabet.end())
+	if (! getInputAlphabet().count(symbol))
 		throw AutomatonException("Input symbol \"" + (std::string) symbol + "\" doesn't exist.");
 
-	if (states.find(next) == states.end())
+	if (! getStates().count(next))
 		throw AutomatonException("State \"" + (std::string) next.getName() + "\" doesn't exist.");
 
 	for (const State& it : prevStates) {
-		if (states.find(it) == states.end())
+		if (! getStates().count(it))
 			throw AutomatonException("State \"" + (std::string) it . getName() + "\" doesn't exist.");
 	}
 
@@ -92,26 +64,25 @@ bool NFTA::removeTransition(const alphabet::RankedSymbol symbol, const std::vect
 }
 
 bool NFTA::isDeterministic() const {
-	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, std::set<State> >& t : transitions) {
-		if (t . second.size() != 1 || t . second.size() != 0) {
+	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<State> >, std::set<State> >& t : transitions)
+		if (t . second.size() != 1 || t . second.size() != 0)
 			return false;
-		}
-	}
 
 	return true;
 }
 
 unsigned NFTA::transitionsSize() const {
 	int res = 0;
-	for(const auto& transition : transitions ){
+
+	for(const auto& transition : transitions )
 		res += transition.second.size();
-	}
+
 	return res;
 }
 
 int NFTA::compare(const NFTA& other) const {
-	auto first = std::tie(states, inputAlphabet, finalStates, transitions);
-	auto second = std::tie(other.states, other.inputAlphabet, other.finalStates, other.transitions);
+	auto first = std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions);
+	auto second = std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions);
 
 	std::compare<decltype(first)> comp;
 	return comp(first, second);
@@ -119,9 +90,9 @@ int NFTA::compare(const NFTA& other) const {
 
 void NFTA::operator>>(std::ostream& out) const {
 	out << "(NFTA "
-		<< " states = " << states
-		<< " inputAlphabet = " << inputAlphabet
-		<< " finalStates = " << finalStates
+		<< " states = " << getStates()
+		<< " inputAlphabet = " << getInputAlphabet()
+		<< " finalStates = " << getFinalStates()
 		<< " transitions = " << transitions
 		<< ")";
 }
@@ -143,7 +114,7 @@ NFTA NFTA::parse(std::deque<sax::Token>::iterator& input) {
 
 	NFTA automaton;
 	automaton.setStates(std::move(states));
-	automaton.setInputSymbols(std::move(inputSymbols));
+	automaton.setInputAlphabet(std::move(inputSymbols));
 	automaton.setFinalStates(std::move(finalStates));
 
 	AutomatonFromXMLParser::parseTransitions<NFTA>(input, automaton);
@@ -192,6 +163,69 @@ void NFTA::composeTransitions(std::deque<sax::Token>& out) const {
 
 } /* namespace automaton */
 
+namespace std {
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::used ( const alphabet::RankedSymbol & symbol ) const {
+	const automaton::NFTA * automaton = static_cast < const automaton::NFTA * > ( this );
+
+	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<automaton::State> >, std::set<automaton::State>>& t : automaton->getTransitions())
+		if (t.first.first == symbol)
+			return true;
+
+	return false;
+}
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::available ( const alphabet::RankedSymbol & ) const {
+	return true;
+}
+
+template < >
+void automaton::NFTA::Component < automaton::NFTA, alphabet::RankedSymbol, automaton::InputAlphabet >::valid ( const alphabet::RankedSymbol & ) const {
+}
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::States >::used ( const automaton::State & state ) const {
+	const automaton::NFTA * automaton = static_cast < const automaton::NFTA * > ( this );
+
+	if ( automaton->getFinalStates ( ).count ( state ) )
+		return true;
+
+	for (const std::pair<const std::pair<alphabet::RankedSymbol, std::vector<automaton::State> >, std::set<automaton::State>>& t : automaton->getTransitions())
+		if(std::contains(t.first.second.begin(), t.first.second.end(), state ) || t . second.count ( state ) )
+			return true;
+
+	return false;
+}
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::States >::available ( const automaton::State & ) const {
+	return true;
+}
+
+template < >
+void automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::States >::valid ( const automaton::State & ) const {
+}
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::FinalStates >::used ( const automaton::State & ) const {
+	return false;
+}
+
+template < >
+bool automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::FinalStates >::available ( const automaton::State & state ) const {
+	const automaton::NFTA * automaton = static_cast < const automaton::NFTA * > ( this );
+
+	return automaton->accessComponent < automaton::States > ( ).get ( ).count ( state );
+}
+
+template < >
+void automaton::NFTA::Component < automaton::NFTA, automaton::State, automaton::FinalStates >::valid ( const automaton::State & ) const {
+}
+
+} /* namespace std */
+
 namespace alib {
 
 auto NFTAParserRegister = xmlApi<automaton::Automaton>::ParserRegister<automaton::NFTA>();
diff --git a/alib2data/src/automaton/TA/NFTA.h b/alib2data/src/automaton/TA/NFTA.h
index 237dc60f51..e3c906c37a 100644
--- a/alib2data/src/automaton/TA/NFTA.h
+++ b/alib2data/src/automaton/TA/NFTA.h
@@ -10,42 +10,86 @@
 
 #include <map>
 #include <vector>
+#include <core/components.hpp>
 #include "../AutomatonBase.h"
-#include "../common/States.h"
-
-// #include "../common/InputAlphabet.h"
+#include "../common/State.h"
 #include "../../alphabet/RankedSymbol.h"
 
 #include "DFTA.h"
 
 namespace automaton {
 
+class InputAlphabet;
+class States;
+class FinalStates;
+
 /**
  * Represents Finite Tree Automaton.
  * Can store nondeterministic finite tree automaton without epsilon transitions.
  */
-class NFTA : public AutomatonBase, public States {
-protected:
-	std::set < alphabet::RankedSymbol > inputAlphabet;
+class NFTA : public AutomatonBase, public std::Components < NFTA, alphabet::RankedSymbol, std::tuple < InputAlphabet >, std::tuple < >, automaton::State, std::tuple < States, FinalStates >, std::tuple < > > {
 	std::map < std::pair < alphabet::RankedSymbol, std::vector < State > >, std::set < State > > transitions;
 
 public:
 	explicit NFTA ( );
+	explicit NFTA ( std::set < State > states, std::set < alphabet::RankedSymbol > inputAlphabet, std::set < State > finalStates );
 	explicit NFTA ( const DFTA & other );
 
 	virtual AutomatonBase * clone ( ) const;
 
 	virtual AutomatonBase * plunder ( ) &&;
 
-	/**
-	 * @copydoc Automaton::removeState(const State&)
-	 */
-	virtual bool removeState ( const State & state );
+	const std::set < State > & getStates ( ) const {
+		return accessComponent < States > ( ).get ( );
+	}
 
-	/**
-	 * @copydoc Automaton::removeInputSymbol(const Symbol&)
-	 */
-	virtual bool removeInputSymbol ( const alphabet::RankedSymbol & symbol );
+	bool addState ( State state ) {
+		return accessComponent < States > ( ).add ( std::move ( state ) );
+	}
+
+	void setStates ( std::set < State > states ) {
+		accessComponent < States > ( ).set ( std::move ( states ) );
+	}
+
+	void removeState ( const State & state ) {
+		accessComponent < States > ( ).remove ( state );
+	}
+
+	const std::set < State > & getFinalStates ( ) const {
+		return accessComponent < FinalStates > ( ).get ( );
+	}
+
+	bool addFinalState ( State state ) {
+		return accessComponent < FinalStates > ( ).add ( std::move ( state ) );
+	}
+
+	void setFinalStates ( std::set < State > states ) {
+		accessComponent < FinalStates > ( ).set ( std::move ( states ) );
+	}
+
+	void removeFinalState ( const State & state ) {
+		accessComponent < FinalStates > ( ).remove ( state );
+	}
+
+	const std::set < alphabet::RankedSymbol > & getInputAlphabet ( ) const {
+		return accessComponent < InputAlphabet > ( ).get ( );
+	}
+
+	bool addInputSymbol ( alphabet::RankedSymbol symbol ) {
+		return accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) );
+	}
+
+	void addInputSymbols ( std::set < alphabet::RankedSymbol > symbols ) {
+		accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) );
+	}
+
+	void setInputAlphabet ( std::set < alphabet::RankedSymbol > symbols ) {
+		accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) );
+	}
+
+	void removeInputSymbol ( const alphabet::RankedSymbol & symbol ) {
+		accessComponent < InputAlphabet > ( ).remove ( symbol );
+	}
 
 	/**
 	 * Adds transition defined by parameters to the automaton.
@@ -80,12 +124,6 @@ public:
 
 	unsigned transitionsSize ( ) const;
 
-	const std::set < alphabet::RankedSymbol > & getInputAlphabet ( ) const { return inputAlphabet; }
-
-	void setInputSymbols ( const std::set < alphabet::RankedSymbol > & symbols ) { inputAlphabet = symbols; }
-
-	void addInputSymbol ( const alphabet::RankedSymbol & symbol ) { inputAlphabet.insert ( symbol ); }
-
 	virtual int compare ( const ObjectBase & other ) const {
 		if ( std::type_index ( typeid ( * this ) ) == std::type_index ( typeid ( other ) ) ) return this->compare ( ( decltype ( * this ) )other );
 
diff --git a/alib2data/test-src/automaton/AutomatonTest.cpp b/alib2data/test-src/automaton/AutomatonTest.cpp
index d0dc1297a2..2278c9ae97 100644
--- a/alib2data/test-src/automaton/AutomatonTest.cpp
+++ b/alib2data/test-src/automaton/AutomatonTest.cpp
@@ -309,10 +309,10 @@ void AutomatonTest::testNFTATransitions() {
 
 	automaton.addFinalState(q2);
 
-	CPPUNIT_ASSERT_THROW(automaton.removeInputSymbol(a), automaton::AutomatonException);
+	CPPUNIT_ASSERT_THROW(automaton.removeInputSymbol(a), exception::CommonException);
 	CPPUNIT_ASSERT_NO_THROW(automaton.removeInputSymbol(d));
 	CPPUNIT_ASSERT_NO_THROW(automaton.removeTransition(b, states1, q2));
-	CPPUNIT_ASSERT_THROW(automaton.addTransition(b, states1, q1), automaton::AutomatonException);
-	CPPUNIT_ASSERT_THROW(automaton.addTransition(a, states2, q1), automaton::AutomatonException);
-	CPPUNIT_ASSERT_THROW(automaton.addTransition(d, states3, q0), automaton::AutomatonException);
+	CPPUNIT_ASSERT_THROW(automaton.addTransition(b, states1, q1), exception::CommonException);
+	CPPUNIT_ASSERT_THROW(automaton.addTransition(a, states2, q1), exception::CommonException);
+	CPPUNIT_ASSERT_THROW(automaton.addTransition(d, states3, q0), exception::CommonException);
 }
-- 
GitLab