diff --git a/alib2algo/src/automaton/properties/UnreachableStates.cpp b/alib2algo/src/automaton/properties/ReachableStates.cpp similarity index 56% rename from alib2algo/src/automaton/properties/UnreachableStates.cpp rename to alib2algo/src/automaton/properties/ReachableStates.cpp index 6e23bae903fa31b72b5f1e670ccb6505ae4435c3..868d0b7a9ac1a3a9657d93f9a39b0de0a4783eac 100644 --- a/alib2algo/src/automaton/properties/UnreachableStates.cpp +++ b/alib2algo/src/automaton/properties/ReachableStates.cpp @@ -1,11 +1,11 @@ /* - * UnreachableStates.cpp + * ReachableStates.cpp * * Created on: 23. 3. 2014 * Author: Tomas Pecka */ -#include "UnreachableStates.h" +#include "ReachableStates.h" #include <exception/AlibException.h> #include <automaton/FSM/ExtendedNFA.h> @@ -22,14 +22,14 @@ namespace automaton { namespace properties { -std::set<automaton::State> UnreachableStates::unreachableStates(const Automaton& automaton) { +std::set<automaton::State> ReachableStates::reachableStates(const Automaton& automaton) { std::set<automaton::State> out; - automaton.getData().Accept((void*) &out, UnreachableStates::UNREACHABLE_STATES); + automaton.getData().Accept((void*) &out, ReachableStates::REACHABLE_STATES); return out; } template<class T> -std::set<automaton::State> UnreachableStates::unreachableStates( const T & fsm ) { +std::set<automaton::State> ReachableStates::reachableStates( const T & fsm ) { // 1a std::deque<std::set<automaton::State>> Qi; Qi.push_back( std::set<automaton::State>( ) ); @@ -54,13 +54,13 @@ std::set<automaton::State> UnreachableStates::unreachableStates( const T & fsm ) return Qi.at( i ); } -template std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::EpsilonNFA & fsm ); -template std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::NFA & fsm ); -template std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::CompactNFA & fsm ); -template std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::ExtendedNFA & fsm ); +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 ); template<> -std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::MultiInitialStateNFA & fsm ) { +std::set<automaton::State> ReachableStates::reachableStates( const automaton::MultiInitialStateNFA & fsm ) { // 1a std::deque<std::set<automaton::State>> Qi; Qi.push_back( std::set<automaton::State>( ) ); @@ -86,7 +86,7 @@ std::set<automaton::State> UnreachableStates::unreachableStates( const automaton } template<> -std::set<automaton::State> UnreachableStates::unreachableStates( const automaton::DFA & fsm ) { +std::set<automaton::State> ReachableStates::reachableStates( const automaton::DFA & fsm ) { // 1a std::deque<std::set<automaton::State>> Qi; Qi.push_back( std::set<automaton::State>( ) ); @@ -111,81 +111,81 @@ std::set<automaton::State> UnreachableStates::unreachableStates( const automaton return Qi.at( i ); } -void UnreachableStates::Visit(void* data, const EpsilonNFA& automaton) const { +void ReachableStates::Visit(void* data, const EpsilonNFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void* data, const MultiInitialStateNFA& automaton) const { +void ReachableStates::Visit(void* data, const MultiInitialStateNFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void* data, const NFA& automaton) const { +void ReachableStates::Visit(void* data, const NFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void* data, const DFA& automaton) const { +void ReachableStates::Visit(void* data, const DFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void* data, const ExtendedNFA& automaton) const { +void ReachableStates::Visit(void* data, const ExtendedNFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void* data, const CompactNFA& automaton) const { +void ReachableStates::Visit(void* data, const CompactNFA& automaton) const { std::set<automaton::State> & out = *((std::set<automaton::State>*) data); - out = std::move(this->unreachableStates(automaton)); + out = std::move(this->reachableStates(automaton)); } -void UnreachableStates::Visit(void*, const DPDA&) const { +void ReachableStates::Visit(void*, const DPDA&) const { throw exception::AlibException("Unsupported automaton type DPDA"); } -void UnreachableStates::Visit(void*, const SinglePopDPDA&) const { +void ReachableStates::Visit(void*, const SinglePopDPDA&) const { throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); } -void UnreachableStates::Visit(void*, const InputDrivenDPDA&) const { +void ReachableStates::Visit(void*, const InputDrivenDPDA&) const { throw exception::AlibException("Unsupported automaton type InputDrivenDPDA"); } -void UnreachableStates::Visit(void*, const InputDrivenNPDA&) const { +void ReachableStates::Visit(void*, const InputDrivenNPDA&) const { throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); } -void UnreachableStates::Visit(void*, const VisiblyPushdownDPDA&) const { +void ReachableStates::Visit(void*, const VisiblyPushdownDPDA&) const { throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA"); } -void UnreachableStates::Visit(void*, const VisiblyPushdownNPDA&) const { +void ReachableStates::Visit(void*, const VisiblyPushdownNPDA&) const { throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); } -void UnreachableStates::Visit(void*, const RealTimeHeightDeterministicDPDA&) const { +void ReachableStates::Visit(void*, const RealTimeHeightDeterministicDPDA&) const { throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA"); } -void UnreachableStates::Visit(void*, const RealTimeHeightDeterministicNPDA&) const { +void ReachableStates::Visit(void*, const RealTimeHeightDeterministicNPDA&) const { throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA"); } -void UnreachableStates::Visit(void*, const NPDA&) const { +void ReachableStates::Visit(void*, const NPDA&) const { throw exception::AlibException("Unsupported automaton type NPDA"); } -void UnreachableStates::Visit(void*, const SinglePopNPDA&) const { +void ReachableStates::Visit(void*, const SinglePopNPDA&) const { throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); } -void UnreachableStates::Visit(void*, const OneTapeDTM&) const { +void ReachableStates::Visit(void*, const OneTapeDTM&) const { throw exception::AlibException("Unsupported automaton type OneTapeDTM"); } -const UnreachableStates UnreachableStates::UNREACHABLE_STATES; +const ReachableStates ReachableStates::REACHABLE_STATES; } /* namespace properties */ diff --git a/alib2algo/src/automaton/properties/UnreachableStates.h b/alib2algo/src/automaton/properties/ReachableStates.h similarity index 77% rename from alib2algo/src/automaton/properties/UnreachableStates.h rename to alib2algo/src/automaton/properties/ReachableStates.h index bd51109cb87ea4f825fb402e2bc8b7cb711c7f2a..a3f8559c25f8806dcfddbae73fed023fdaf85220 100644 --- a/alib2algo/src/automaton/properties/UnreachableStates.h +++ b/alib2algo/src/automaton/properties/ReachableStates.h @@ -1,12 +1,12 @@ /* - * UnreachableStates.h + * ReachableStates.h * * Created on: 23. 3. 2014 * Author: Tomas Pecka */ -#ifndef UNREACHABLE_STATES_H_ -#define UNREACHABLE_STATES_H_ +#ifndef REACHABLE_STATES_H_ +#define REACHABLE_STATES_H_ #include <algorithm> #include <deque> @@ -19,15 +19,15 @@ namespace automaton { namespace properties { -class UnreachableStates : public VisitableAutomatonBase::const_visitor_type { +class ReachableStates : public VisitableAutomatonBase::const_visitor_type { public: - static std::set<automaton::State> unreachableStates( const automaton::Automaton & automaton ); + static std::set<automaton::State> reachableStates( const automaton::Automaton & automaton ); /** * Removes dead states from FSM. Melichar 2.29 */ template<class T> - static std::set<automaton::State> unreachableStates( const T & fsm ); + static std::set<automaton::State> reachableStates( const T & fsm ); private: void Visit(void*, const EpsilonNFA& automaton) const; @@ -48,11 +48,11 @@ private: void Visit(void*, const SinglePopNPDA& automaton) const; void Visit(void*, const OneTapeDTM& automaton) const; - static const UnreachableStates UNREACHABLE_STATES; + static const ReachableStates REACHABLE_STATES; }; } /* namespace properties */ } /* namespace automaton */ -#endif /* UNREACHABLE_STATES_H_ */ +#endif /* REACHABLE_STATES_H_ */ diff --git a/alib2algo/src/automaton/properties/UsefullStates.cpp b/alib2algo/src/automaton/properties/UsefullStates.cpp index 3c5f246937d1930dc1823e3c0448694dd8b8a8d9..c62908e6c58f7683577298c822ab22cf76af160b 100644 --- a/alib2algo/src/automaton/properties/UsefullStates.cpp +++ b/alib2algo/src/automaton/properties/UsefullStates.cpp @@ -56,6 +56,7 @@ template std::set<automaton::State> UsefullStates::usefullStates( const automato 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 ); template<> std::set<automaton::State> UsefullStates::usefullStates( const automaton::DFA & fsm ) { diff --git a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp index 86cdb96c93e298ff508223e26d15df51d022d24f..b6a5312dd40f37ba3e50841bbdb2a6d86efc8c01 100644 --- a/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp +++ b/alib2algo/src/automaton/simplify/UnreachableStatesRemover.cpp @@ -15,7 +15,7 @@ #include <automaton/FSM/NFA.h> #include <automaton/FSM/DFA.h> -#include "../properties/UnreachableStates.h" +#include "../properties/ReachableStates.h" #include "automaton/common/State.h" #include "automaton/Automaton.h" @@ -27,7 +27,7 @@ namespace simplify { template<class T> T UnreachableStatesRemover::remove( const T & fsm ) { // 1a - std::set<automaton::State> Qa = automaton::properties::UnreachableStates::unreachableStates( fsm ); + std::set<automaton::State> Qa = automaton::properties::ReachableStates::reachableStates( fsm ); // 2 T M(fsm.getInitialState()); @@ -59,7 +59,7 @@ template automaton::ExtendedNFA UnreachableStatesRemover::remove( const automato template<> automaton::DFA UnreachableStatesRemover::remove( const automaton::DFA & fsm ) { // 1a - std::set<automaton::State> Qa = automaton::properties::UnreachableStates::unreachableStates( fsm ); + std::set<automaton::State> Qa = automaton::properties::ReachableStates::reachableStates( fsm ); // 2 automaton::DFA M(fsm.getInitialState() ); @@ -85,7 +85,7 @@ automaton::DFA UnreachableStatesRemover::remove( const automaton::DFA & fsm ) { template<> automaton::MultiInitialStateNFA UnreachableStatesRemover::remove( const automaton::MultiInitialStateNFA & fsm ) { // 1a - std::set<automaton::State> Qa = automaton::properties::UnreachableStates::unreachableStates( fsm ); + std::set<automaton::State> Qa = automaton::properties::ReachableStates::reachableStates( fsm ); // 2 automaton::MultiInitialStateNFA M; diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp b/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3070f632768a56bd3c95e4269604cbe6f6e69f6f --- /dev/null +++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.cpp @@ -0,0 +1,185 @@ +/* + * ReachableStates.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "ReachableStates.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +#include <set> +#include <map> +#include <queue> + +namespace automaton { + +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; +} + +template<class T> +std::set<automaton::State> ReachableStates::reachableStates( const T & fsm ) { + std::map<automaton::State, std::set<automaton::State>> transitions; + for(const auto& transition : fsm.getTransitions()) + transitions[transition.first.first].insert(transition.second.begin(), transition.second.end()); + + std::deque<automaton::State> queue { fsm.getInitialState( ) }; + std::set<automaton::State> visited { fsm.getInitialState( ) }; + + while( !queue.empty() ) { + const std::set<automaton::State>& to = transitions[queue.front()]; + queue.pop_front(); + + for(const automaton::State& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<automaton::State&>(process))); + } + } + + 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 ); + +template<> +std::set<automaton::State> ReachableStates::reachableStates( const automaton::MultiInitialStateNFA & fsm ) { + std::map<automaton::State, std::set<automaton::State>> transitions; + for(const auto& transition : fsm.getTransitions()) + transitions[transition.first.first].insert(transition.second.begin(), transition.second.end()); + + std::deque<automaton::State> queue ( fsm.getInitialStates( ).begin(), fsm.getInitialStates().end() ); + std::set<automaton::State> visited = fsm.getInitialStates( ); + + while( !queue.empty() ) { + const std::set<automaton::State>& to = transitions[queue.front()]; + queue.pop_front(); + + for(const automaton::State& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<automaton::State&>(process))); + } + } + + return visited; +} + +template<> +std::set<automaton::State> ReachableStates::reachableStates( const automaton::DFA & fsm ) { + std::map<automaton::State, std::set<automaton::State>> transitions; + for(const auto& transition : fsm.getTransitions()) + transitions[transition.first.first].insert(transition.second); + + std::deque<automaton::State> queue { fsm.getInitialState( ) }; + std::set<automaton::State> visited { fsm.getInitialState( ) }; + + while( !queue.empty() ) { + const std::set<automaton::State>& to = transitions[queue.front()]; + queue.pop_front(); + + for(const automaton::State& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<automaton::State&>(process))); + } + } + + 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 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; + +} /* namespace efficient */ + +} /* namespace properties */ + +} /* namespace automaton */ + diff --git a/alib2elgo/src/automaton/properties/efficient/ReachableStates.h b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h new file mode 100644 index 0000000000000000000000000000000000000000..6b52d3990d4d7056b8f27804de7f719cb6a25dc9 --- /dev/null +++ b/alib2elgo/src/automaton/properties/efficient/ReachableStates.h @@ -0,0 +1,62 @@ +/* + * ReachableStates.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef EFFICIENT_REACHABLE_STATES_H_ +#define EFFICIENT_REACHABLE_STATES_H_ + +#include <algorithm> +#include <deque> +#include <set> + +#include <automaton/common/State.h> +#include <automaton/Automaton.h> + +namespace automaton { + +namespace properties { + +namespace efficient { + +class ReachableStates : public VisitableAutomatonBase::const_visitor_type { +public: + static std::set<automaton::State> reachableStates( const automaton::Automaton & automaton ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + 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 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; +}; + +} /* namespace efficient */ + +} /* namespace properties */ + +} /* namespace automaton */ + +#endif /* EFFICIENT_REACHABLE_STATES_H_ */ diff --git a/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp b/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp new file mode 100644 index 0000000000000000000000000000000000000000..446ee0da44f08473918b5fe14488edc2af447d34 --- /dev/null +++ b/alib2elgo/src/automaton/properties/efficient/UsefullStates.cpp @@ -0,0 +1,165 @@ +/* + * UsefullStates.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "UsefullStates.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +#include <set> +#include <map> +#include <queue> + +namespace automaton { + +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; +} + +template<class T> +std::set<automaton::State> UsefullStates::usefullStates( const T & fsm ) { + std::map<automaton::State, std::set<automaton::State>> reversedTransitions; + for(const auto& transition : fsm.getTransitions()) + for(const automaton::State& to : transition.second) + reversedTransitions[to].insert(transition.first.first); + + std::deque<automaton::State> queue ( fsm.getFinalStates( ).begin(), fsm.getFinalStates().end() ); + std::set<automaton::State> visited = fsm.getFinalStates( ); + + while( !queue.empty() ) { + const std::set<automaton::State>& to = reversedTransitions[queue.front()]; + queue.pop_front(); + + for(const automaton::State& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<automaton::State&>(process))); + } + } + + 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 ); + +template<> +std::set<automaton::State> UsefullStates::usefullStates( const automaton::DFA & fsm ) { + std::map<automaton::State, std::set<automaton::State>> reversedTransitions; + for(const auto& transition : fsm.getTransitions()) + reversedTransitions[transition.second].insert(transition.first.first); + + std::deque<automaton::State> queue ( fsm.getFinalStates( ).begin(), fsm.getFinalStates().end() ); + std::set<automaton::State> visited = fsm.getFinalStates( ); + + while( !queue.empty() ) { + const std::set<automaton::State>& to = reversedTransitions[queue.front()]; + queue.pop_front(); + + for(const automaton::State& process : to) + if(visited.insert(process).second) { + queue.push_back(std::move(const_cast<automaton::State&>(process))); + } + } + + 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 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; + +} /* namespace efficient */ + +} /* namespace properties */ + +} /* namespace automaton */ + diff --git a/alib2elgo/src/automaton/properties/efficient/UsefullStates.h b/alib2elgo/src/automaton/properties/efficient/UsefullStates.h new file mode 100644 index 0000000000000000000000000000000000000000..1a4117afcaeb63abbbd234485a06992a134ac824 --- /dev/null +++ b/alib2elgo/src/automaton/properties/efficient/UsefullStates.h @@ -0,0 +1,62 @@ +/* + * UsefullStates.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef EFFICIENT_USEFULL_STATES_H_ +#define EFFICIENT_USEFULL_STATES_H_ + +#include <algorithm> +#include <deque> +#include <set> + +#include <automaton/common/State.h> +#include <automaton/Automaton.h> + +namespace automaton { + +namespace properties { + +namespace efficient { + +class UsefullStates : public VisitableAutomatonBase::const_visitor_type { +public: + static std::set<automaton::State> usefullStates( const automaton::Automaton & automaton ); + + /** + * Removes dead states from FSM. Melichar 2.32 + */ + 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 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; +}; + +} /* namespace efficient */ + +} /* namespace properties */ + +} /* namespace automaton */ + +#endif /* EFFICIENT_USEFULL_STATES_H_ */ diff --git a/alib2elgo/src/automaton/simplify/efficient/Trim.cpp b/alib2elgo/src/automaton/simplify/efficient/Trim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..627c532b2f93f285085a0369f1509e566a51739a --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/Trim.cpp @@ -0,0 +1,129 @@ +/* + * Trim.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "Trim.h" +#include "UselessStatesRemover.h" +#include "UnreachableStatesRemover.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +#include "automaton/common/State.h" +#include "automaton/Automaton.h" + +namespace automaton { + +namespace simplify { + +namespace efficient { + +template<class T> +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 ); + +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; +} + +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 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 */ + +} /* namespace automaton */ + diff --git a/alib2elgo/src/automaton/simplify/efficient/Trim.h b/alib2elgo/src/automaton/simplify/efficient/Trim.h new file mode 100644 index 0000000000000000000000000000000000000000..8048d0cd9b6d94e2ad7e8d29db5c5f54a999430f --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/Trim.h @@ -0,0 +1,60 @@ +/* + * Trim.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef EFFICIENT_AUTOMATON_TRIM_H_ +#define EFFICIENT_AUTOMAONT_TRIM_H_ + +#include <algorithm> +#include <deque> +#include <set> +#include <automaton/Automaton.h> + +namespace automaton { + +namespace simplify { + +namespace efficient { + +class Trim : public automaton::VisitableAutomatonBase::const_visitor_type { +public: + static automaton::Automaton trim( const automaton::Automaton & automaton ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + 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::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; +}; + +} /* namespace efficient */ + +} /* namespace simplify */ + +} /* namespace automaton */ + +#endif /* EFFICIENT_AUTOMATON_TRIM_H_ */ diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0b7c582ea1f31690796251ee3cdd937eb831e1b --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.cpp @@ -0,0 +1,204 @@ +/* + * UnreachableStatesRemover.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "UnreachableStatesRemover.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/MultiInitialStateNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +#include "../../properties/efficient/ReachableStates.h" + +#include "automaton/common/State.h" +#include "automaton/Automaton.h" + +namespace automaton { + +namespace simplify { + +namespace efficient { + +template<class T> +T UnreachableStatesRemover::remove( const T & fsm ) { + // 1a + std::set<automaton::State> Qa = automaton::properties::efficient::ReachableStates::reachableStates( fsm ); + + // 2 + T M(fsm.getInitialState()); + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + for(const auto& to : transition.second ) + M.addTransition( transition.first.first, transition.first.second, to ); + + std::set<automaton::State> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + 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 ); + +template<> +automaton::DFA UnreachableStatesRemover::remove( const automaton::DFA & fsm ) { + // 1a + std::set<automaton::State> Qa = automaton::properties::efficient::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::DFA M(fsm.getInitialState() ); + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + M.addTransition( transition.first.first, transition.first.second, transition.second ); + + std::set<automaton::State> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + return M; +} + +template<> +automaton::MultiInitialStateNFA UnreachableStatesRemover::remove( const automaton::MultiInitialStateNFA & fsm ) { + // 1a + std::set<automaton::State> Qa = automaton::properties::efficient::ReachableStates::reachableStates( fsm ); + + // 2 + automaton::MultiInitialStateNFA M; + + for( const auto & q : Qa ) + M.addState( q ); + + M.setInitialStates( fsm.getInitialStates() ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + for(const auto& to : transition.second ) + M.addTransition( transition.first.first, transition.first.second, to ); + + std::set<automaton::State> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + 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 automaton::DPDA&) const { + throw exception::AlibException("Unsupported automaton type DPDA"); +} + +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"); +} + +const UnreachableStatesRemover UnreachableStatesRemover::UNREACHABLE_STATES_REMOVER; + +} /* namespace efficient */ + +} /* namespace simplify */ + +} /* namespace automaton */ diff --git a/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h new file mode 100644 index 0000000000000000000000000000000000000000..4fa148ed79672df6a2f38ef01ed4585adb2fe3db --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/UnreachableStatesRemover.h @@ -0,0 +1,60 @@ +/* + * UnreachableStatesRemover.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef EFFICIENT_UNREACHABLE_STATES_REMOVER_H_ +#define EFFICIENT_UNREACHABLE_STATES_REMOVER_H_ + +#include <algorithm> +#include <deque> +#include <set> +#include <automaton/Automaton.h> + +namespace automaton { + +namespace simplify { + +namespace efficient { + +class UnreachableStatesRemover : public automaton::VisitableAutomatonBase::const_visitor_type { +public: + static automaton::Automaton remove( const automaton::Automaton & automaton ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + 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::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; +}; + +} /* namespace efficient */ + +} /* namespace simplify */ + +} /* namespace automaton */ + +#endif /* EFFICIENT_UNREACHABLE_STATES_REMOVER_H_ */ diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp new file mode 100644 index 0000000000000000000000000000000000000000..536ed54becb0a4358eb5144e91beac3f96eb80cf --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.cpp @@ -0,0 +1,213 @@ +/* + * UselessStatesRemover.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "UselessStatesRemover.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/MultiInitialStateNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +#include "../../properties/efficient/UsefullStates.h" + +#include "automaton/common/State.h" +#include "automaton/Automaton.h" + +namespace automaton { + +namespace simplify { + +namespace efficient { + +template<class T> +T UselessStatesRemover::remove( const T & fsm ) { + // 1. + std::set<automaton::State> Qu = automaton::properties::efficient::UsefullStates::usefullStates( fsm ); + + // 2. + T M(fsm.getInitialState()); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + if(Qu.size() == 0) { + return M; + } + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & t : fsm.getTransitions( ) ) + for( const auto & to : t.second ) + if( /* this part is not needed Qu.count(t.first.first) ) && */ Qu.count(to) ) + M.addTransition( t.first.first, t.first.second, to ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + 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 ); + +template<> +automaton::DFA UselessStatesRemover::remove( const automaton::DFA & fsm ) { + // 1. + std::set<automaton::State> Qu = automaton::properties::efficient::UsefullStates::usefullStates( fsm ); + + // 2. + automaton::DFA M ( fsm.getInitialState () ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + if(Qu.size() == 0) { + return M; + } + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & t : fsm.getTransitions( ) ) + if( /* this part is not needed Qu.count( t.first.first ) && */ Qu.count( t.second ) ) + M.addTransition( t.first.first, t.first.second, t.second ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + return M; +} + +template<> +automaton::MultiInitialStateNFA UselessStatesRemover::remove( const automaton::MultiInitialStateNFA & fsm ) { + // 1. + std::set<automaton::State> Qu = automaton::properties::efficient::UsefullStates::usefullStates( fsm ); + + // 2. + automaton::MultiInitialStateNFA M; + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + if(Qu.size() == 0) { + return M; + } + + for( const auto & q : Qu ) + M.addState( q ); + + for(const auto& init : fsm.getInitialStates()) { + if( Qu.count(init) ) + M.addInitialState( init ); + } + + for( const auto & t : fsm.getTransitions( ) ) + for( const auto & to : t.second ) + if( Qu.count(to) ) + M.addTransition( t.first.first, t.first.second, to ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + 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 automaton::DPDA&) const { + throw exception::AlibException("Unsupported automaton type DPDA"); +} + +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"); +} + +const UselessStatesRemover UselessStatesRemover::USELESS_STATES_REMOVER; + +} /* namespace efficient */ + +} /* namespace simplify */ + +} /* namespace automaton */ diff --git a/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h new file mode 100644 index 0000000000000000000000000000000000000000..df0b85d6f03bf7c13d33bffd630d1a8bc032b363 --- /dev/null +++ b/alib2elgo/src/automaton/simplify/efficient/UselessStatesRemover.h @@ -0,0 +1,60 @@ +/* + * UselessStatesRemover.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef EFFICIENT_USELESS_STATES_REMOVER_H_ +#define EFFICIENT_USELESS_STATES_REMOVER_H_ + +#include <algorithm> +#include <deque> +#include <set> +#include <automaton/Automaton.h> + +namespace automaton { + +namespace simplify { + +namespace efficient { + +class UselessStatesRemover : public automaton::VisitableAutomatonBase::const_visitor_type { +public: + static automaton::Automaton remove( const automaton::Automaton & automaton ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + 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::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; +}; + +} /* namespace efficient */ + +} /* namespace simplify */ + +} /* namespace automaton */ + +#endif /* EFFICIENT_USELESS_STATES_REMOVER_H_ */ diff --git a/alib2elgo/test-src/automaton/simplify/efficient/trimTest.cpp b/alib2elgo/test-src/automaton/simplify/efficient/trimTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbc1fae5418f5760ac23e410728c0ab6889968ff --- /dev/null +++ b/alib2elgo/test-src/automaton/simplify/efficient/trimTest.cpp @@ -0,0 +1,37 @@ +#include <list> +#include "trimTest.h" + +#include "automaton/simplify/Trim.h" + +#include "automaton/FSM/DFA.h" + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( trimTest, "automaton" ); +CPPUNIT_TEST_SUITE_REGISTRATION( trimTest ); + +void trimTest::setUp() { +} + +void trimTest::tearDown() { +} + +void trimTest::testTrimAutomaton() { + automaton::DFA automaton(automaton::State(1)); + + automaton.addState(automaton::State(1)); + automaton.addState(automaton::State(2)); + automaton.addState(automaton::State(3)); + automaton.addInputSymbol(alphabet::symbolFrom("a")); + automaton.addInputSymbol(alphabet::symbolFrom("b")); + + automaton.addTransition(automaton::State(1), alphabet::symbolFrom("a"), automaton::State(2)); + automaton.addTransition(automaton::State(2), alphabet::symbolFrom("b"), automaton::State(1)); + automaton.addTransition(automaton::State(3), alphabet::symbolFrom("b"), automaton::State(1)); + + automaton.addFinalState(automaton::State(1)); + + automaton::DFA trimed = automaton::simplify::Trim::trim(automaton); + + CPPUNIT_ASSERT(trimed.getStates().size() == 2); +} diff --git a/alib2elgo/test-src/automaton/simplify/efficient/trimTest.h b/alib2elgo/test-src/automaton/simplify/efficient/trimTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5b6782294c816b11bea2f297e8708c6654536cc1 --- /dev/null +++ b/alib2elgo/test-src/automaton/simplify/efficient/trimTest.h @@ -0,0 +1,19 @@ +#ifndef TRIM_TEST_H_ +#define TRIM_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class trimTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( trimTest ); + CPPUNIT_TEST( testTrimAutomaton ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testTrimAutomaton(); +}; + +#endif // TRIM_TEST_H_ diff --git a/atrim2/src/atrim.cpp b/atrim2/src/atrim.cpp index 86cb4dd4f3ac5a0de6f4c03006f097f9dbdbf83e..927ca8a8f01fc608e99f3fadf1de7d4f3fa9eaba 100644 --- a/atrim2/src/atrim.cpp +++ b/atrim2/src/atrim.cpp @@ -14,8 +14,11 @@ #include "grammar/simplify/UnproductiveSymbolsRemover.h" #include "grammar/simplify/UnreachableSymbolsRemover.h" #include "automaton/simplify/Trim.h" +#include "automaton/simplify/efficient/Trim.h" #include "automaton/simplify/UselessStatesRemover.h" +#include "automaton/simplify/efficient/UselessStatesRemover.h" #include "automaton/simplify/UnreachableStatesRemover.h" +#include "automaton/simplify/efficient/UnreachableStatesRemover.h" #include "regexp/simplify/RegExpOptimize.h" grammar::Grammar trimGrammar(const grammar::Grammar& g, bool del_unreachable, bool del_unproductive) { @@ -38,6 +41,16 @@ automaton::Automaton trimAutomaton(const automaton::Automaton& g, bool del_unrea return automaton::simplify::Trim::trim( g ); } +automaton::Automaton efficientTrimAutomaton(const automaton::Automaton& g, bool del_unreachable, bool del_useless) { + if( del_unreachable && del_useless ) + return automaton::simplify::efficient::Trim::trim( g ); + if( del_unreachable ) + return automaton::simplify::efficient::UnreachableStatesRemover::remove( g ); + if( del_useless ) + return automaton::simplify::efficient::UselessStatesRemover::remove( g ); + return automaton::simplify::efficient::Trim::trim( g ); +} + regexp::RegExp optimizeRegExp(const regexp::RegExp& r) { return regexp::simplify::RegExpOptimize::optimize( r ); } @@ -58,6 +71,9 @@ int main(int argc, char* argv[]) { TCLAP::ValueArg<std::string> input( "i", "input", "Input to trim", false, "-", "file"); cmd.add( input ); + TCLAP::SwitchArg efficient( "e", "efficient", "Use efficient implementation", false); + cmd.add( efficient ); + cmd.parse(argc, argv); std::list<sax::Token> tokens; @@ -74,9 +90,10 @@ int main(int argc, char* argv[]) { if( alib::XmlDataFactory::first<automaton::Automaton>(tokens)) { automaton::Automaton automaton = alib::XmlDataFactory::fromTokens<automaton::Automaton>(tokens); - automaton::Automaton res = trimAutomaton(automaton, unreachable.getValue(), useless.getValue() ); - - alib::XmlDataFactory::toStdout( res ); + if(efficient.getValue()) + alib::XmlDataFactory::toStdout( efficientTrimAutomaton(automaton, unreachable.getValue(), useless.getValue() ) ); + else + alib::XmlDataFactory::toStdout( trimAutomaton(automaton, unreachable.getValue(), useless.getValue() ) ); return 0; } else if( alib::XmlDataFactory::first<grammar::Grammar>(tokens)) { grammar::Grammar grammar = alib::XmlDataFactory::fromTokens<grammar::Grammar>(tokens); diff --git a/tests.aconversion.sh b/tests.aconversion.sh index ab59217e272e181b3415e9a6d1cd7f830bf74a7d..81d042a845951e074564eb34d31891ea0f615a67 100755 --- a/tests.aconversion.sh +++ b/tests.aconversion.sh @@ -56,7 +56,7 @@ function generateNFA { # $1 = command for conversion. Output of such command must be (eps-)NFA !! # $2 = automaton function runTest2 { - MDFA="./aepsilon2 -e | ./adeterminize2 | ./atrim2 | ./aminimize2 | ./anormalize2 --labels automaton" + MDFA="./aepsilon2 -e | ./adeterminize2 | ./atrim2 -e | ./aminimize2 | ./anormalize2 --labels automaton" OUT=`timeout $TESTCASE_TIMEOUT bash -c "./acompare2 <(cat $2 | $1 | $MDFA ) <(cat $2 | $MDFA)"` RET=$?