diff --git a/alib2algo/src/automaton/FSMSingleInitialState.cpp b/alib2algo/src/automaton/FSMSingleInitialState.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e967cb5247efbc23ba17e1ac485b490327e6a09 --- /dev/null +++ b/alib2algo/src/automaton/FSMSingleInitialState.cpp @@ -0,0 +1,171 @@ +/* + * FSMSingleInitialState.cpp + * + * Created on: 20. 9. 2014 + * Author: Tomas Pecka + */ + +#include "FSMSingleInitialState.h" + +#include <algorithm> +#include <set> + +#include <exception/AlibException.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/CompactNFA.h> + +namespace automaton { + +automaton::Automaton FSMSingleInitialState::convert(const Automaton& automaton) { + automaton::Automaton* out = NULL; + automaton.getData().Accept((void*) &out, FSMSingleInitialState::FSM_SINGLE_INITIAL_STATE); + automaton::Automaton res = std::move(*out); + delete out; + return res; +} + +template<class T> +T FSMSingleInitialState::convert(const T& automaton) { + if(automaton.getInitialStates().size() <= 1) { + return automaton; + } + + // copy the automaton, remove all initial state flags + T res(automaton); + for(const auto& q : automaton.getInitialStates()) { + res.removeInitialState(q); + } + + // step 3 + automaton::State q0 = automaton::createUniqueState(automaton::State("q0"), res.getStates()); + res.addState(q0); + res.addInitialState(q0); + + // step 2 + for(const auto& q : automaton.getInitialStates()) { + for(const auto& kv: automaton.getTransitionsFromState(q)) { + for(const auto& to : kv.second) { + res.addTransition(q0, kv.first.second, to); + } + } + } + + // step 4, 5 + std::set<automaton::State> intersection; + std::set_intersection(res.getFinalStates().begin(), res.getFinalStates().end(), automaton.getInitialStates().begin(), automaton.getInitialStates().end(), std::inserter(intersection, intersection.begin())); + + res.setFinalStates(automaton.getFinalStates()); + if(intersection.size() != 0) { + res.addFinalState(q0); + } + + return res; +} +/* +template automaton::NFA convert(const automaton::NFA& automaton); +template automaton::ExtendedNFA convert(const automaton::ExtendedNFA& automaton); +template automaton::CompactNFA convert(const automaton::CompactNFA& automaton); +template automaton::EpsilonNFA convert(const automaton::EpsilonNFA& automaton); +*/ +/* +template<> +automaton::EpsilonNFA convert(const automaton::EpsilonNFA& automaton) { + if(automaton.getInitialStates().size() <= 1) { + return automaton; + } + + // copy the automaton, remove all initial state flags + automaton::T res(automaton); + for(const auto& q : automaton.getInitialStates()) { + res.removeInitialState(q); + } + + // step 3 + automaton::State q0 = automaton::createUniqueState(automaton::State("q0"), res.getStates()); + res.addState(q0); + res.addInitialState(q0); + + // step 2 + for(const auto& q : automaton.getInitialStates()) { + for(const auto& kv: automaton.getTransitionsFromState(q)) { + for(const auto& to : kv.second) { + res.addTransition(q0, kv.first.second, to); + } + } + } + + // step 4, 5 + std::set<automaton::State> intersection; + std::set_intersection(res.getFinalStates().begin(), res.getFinalStates().end(), automaton.getInitialStates().begin(), automaton.getInitialStates().end(), std::inserter(intersection, intersection.begin())); + + res.setFinalStates(automaton.getFinalStates()); + if(intersection.size() != 0) { + res.addFinalState(q0); + } + + return res; +} +*/ + +void FSMSingleInitialState::Visit(void*, const UnknownAutomaton&) const { + throw exception::AlibException("Unsupported automaton type UnknownAutomaton"); +} + +void FSMSingleInitialState::Visit(void* data, const EpsilonNFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->convert(automaton)); +} + +void FSMSingleInitialState::Visit(void* data, const NFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->convert(automaton)); +} + +void FSMSingleInitialState::Visit(void*, const DFA&) const { + throw exception::AlibException("Unsupported automaton type DFA"); +} + +void FSMSingleInitialState::Visit(void* data, const ExtendedNFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->convert(automaton)); +} + +void FSMSingleInitialState::Visit(void* data, const CompactNFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->convert(automaton)); +} + +void FSMSingleInitialState::Visit(void*, const DPDA&) const { + throw exception::AlibException("Unsupported automaton type UnknownAutomaton"); +} + +void FSMSingleInitialState::Visit(void*, const SinglePopDPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); +} + +void FSMSingleInitialState::Visit(void*, const InputDrivenNPDA&) const { + throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); +} + +void FSMSingleInitialState::Visit(void*, const VisiblyPushdownNPDA&) const { + throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); +} + +void FSMSingleInitialState::Visit(void*, const NPDA&) const { + throw exception::AlibException("Unsupported automaton type NPDA"); +} + +void FSMSingleInitialState::Visit(void*, const SinglePopNPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); +} + +void FSMSingleInitialState::Visit(void*, const OneTapeDTM&) const { + throw exception::AlibException("Unsupported automaton type OneTapeDTM"); +} + +const FSMSingleInitialState FSMSingleInitialState::FSM_SINGLE_INITIAL_STATE; + +} + diff --git a/alib2algo/src/automaton/FSMSingleInitialState.h b/alib2algo/src/automaton/FSMSingleInitialState.h new file mode 100644 index 0000000000000000000000000000000000000000..09b67a5f84ac3b0db60f74c86b84510a65d31f64 --- /dev/null +++ b/alib2algo/src/automaton/FSMSingleInitialState.h @@ -0,0 +1,55 @@ +/* + * FSMSingleInitialState.h + * + * Created on: 20. 9. 2014 + * Author: Tomas Pecka + */ + +#ifndef FSM_SINGLE_INITIAL_STATE_H +#define FSM_SINGLE_INITIAL_STATE_H + +#include <automaton/Automaton.h> +#include <automaton/common/State.h> + +namespace automaton { + +/** + * Makes finite automaton's transition function convert. + * Source: Melichar: Algorithm 2.22 + */ +class FSMSingleInitialState : public VisitableAutomatonBase::const_visitor_type { +public: + /** + * Computes epsilon closure of a state in epsilon nonfree automaton + */ + static automaton::Automaton convert(const automaton::Automaton& automaton); + + template<class T> + static T convert(const T& automaton); + + //static automaton::NFA convert(const automaton::NFA& automaton); + //static automaton::EpsilonNFA convert(const automaton::EpsilonNFA& automaton); + //static automaton::ExtendedNFA convert(const automaton::ExtendedNFA& automaton); + //static automaton::CompactNFA convert(const automaton::CompactNFA& automaton); + +private: + void Visit(void*, const UnknownAutomaton& automaton) const; + void Visit(void*, const EpsilonNFA& 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 InputDrivenNPDA& automaton) const; + void Visit(void*, const VisiblyPushdownNPDA& 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 FSMSingleInitialState FSM_SINGLE_INITIAL_STATE; +}; + +} + +#endif /* FSM_SINGLE_INITIAL_STATE_H_ */ diff --git a/alib2algo/test-src/automaton/FSMSingleInitialStateTest.cpp b/alib2algo/test-src/automaton/FSMSingleInitialStateTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8388eb19a8959de7ff2a6fa2725f97ad14e29d58 --- /dev/null +++ b/alib2algo/test-src/automaton/FSMSingleInitialStateTest.cpp @@ -0,0 +1,58 @@ +#include "FSMSingleInitialStateTest.h" + +#include <alphabet/LabeledSymbol.h> +#include <label/Label.h> +#include <label/CharacterLabel.h> + +#include "automaton/FSMSingleInitialState.h" +#include "determinize/nfa/NFADeterminizer.h" +#include "normalize/dfa/NormalizeDFA.h" + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( FSMSingleInitialStateTest ); + +void FSMSingleInitialStateTest::setUp() { +} + +void FSMSingleInitialStateTest::tearDown() { +} + +void FSMSingleInitialStateTest::testSingleInitialState() { + automaton::State q("q"); + automaton::State q0("q0"); + automaton::State q1("q1"); + automaton::State q2("q2"); + automaton::State q3("q3"); + + alphabet::Symbol a(alphabet::LabeledSymbol(label::Label(label::CharacterLabel('a')))); + alphabet::Symbol b(alphabet::LabeledSymbol(label::Label(label::CharacterLabel('b')))); + + automaton::NFA automaton1; + automaton1.setStates({q0, q1, q2, q3}); + automaton1.setInitialStates({q0, q1, q2}); + automaton1.setFinalStates({q3}); + automaton1.setInputSymbols({a, b}); + automaton1.addTransition(q0, a, q1); + automaton1.addTransition(q1, b, q2); + automaton1.addTransition(q2, a, q3); + + automaton::NFA automaton2 = automaton::FSMSingleInitialState::convert(automaton1); + CPPUNIT_ASSERT(automaton2.getInitialStates().size() == 1); + + automaton::NFA automaton3; + automaton3.setStates({q, q1, q2, q3}); + automaton3.setInitialStates({q}); + automaton3.setFinalStates({q3}); + automaton3.setInputSymbols({a, b}); + automaton3.addTransition(q, a, q3); + automaton3.addTransition(q, b, q2); + automaton3.addTransition(q, a, q1); + automaton3.addTransition(q1, b, q2); + automaton3.addTransition(q2, a, q3); + + automaton::DFA dfa2 = determinize::NFADeterminizer::determinize(automaton2); + automaton::DFA dfa3 = determinize::NFADeterminizer::determinize(automaton3); + + CPPUNIT_ASSERT(normalize::NormalizeDFA::normalize(dfa3) == normalize::NormalizeDFA::normalize(dfa3)); +} diff --git a/alib2algo/test-src/automaton/FSMSingleInitialStateTest.h b/alib2algo/test-src/automaton/FSMSingleInitialStateTest.h new file mode 100644 index 0000000000000000000000000000000000000000..fee9a58ef397311fbc268e6089a69f701592d295 --- /dev/null +++ b/alib2algo/test-src/automaton/FSMSingleInitialStateTest.h @@ -0,0 +1,19 @@ +#ifndef FSM_SINGLE_INITIAL_STATE_TEST_H_ +#define FSM_SINGLE_INITIAL_STATE_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class FSMSingleInitialStateTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( FSMSingleInitialStateTest ); + CPPUNIT_TEST( testSingleInitialState ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testSingleInitialState(); +}; + +#endif /* FSM_SINGLE_INITIAL_STATE_TEST_H_ */