diff --git a/alib2algo/src/automaton/FSMTotal.cpp b/alib2algo/src/automaton/FSMTotal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0d8fb324745fa1eca035e2cae207f0f86f11949 --- /dev/null +++ b/alib2algo/src/automaton/FSMTotal.cpp @@ -0,0 +1,118 @@ +/* + * FSMTotal.cpp + * + * Created on: 20. 9. 2014 + * Author: Tomas Pecka + */ + +#include "FSMTotal.h" + +#include <exception/AlibException.h> + +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +namespace automaton { + +automaton::Automaton FSMTotal::total(const Automaton& automaton) { + automaton::Automaton* out = NULL; + automaton.getData().Accept((void*) &out, FSMTotal::FSM_TOTAL); + automaton::Automaton res = std::move(*out); + delete out; + return res; +} + +automaton::NFA FSMTotal::total(const automaton::NFA& automaton) { + if(! automaton.isDeterministic()) { + throw exception::AlibException("Automaton must be deterministic to make its transition function total"); + } + + automaton::NFA res(automaton); + automaton::State nullState = automaton::createUniqueState(automaton::State("q0"), automaton.getStates()); + res.addState(nullState); + + for(const auto& q : res.getStates()) { + for(const auto& a : res.getInputAlphabet()) { + if(res.getTransitions().find(std::make_pair(q, a)) == res.getTransitions().end()) { + res.addTransition(q, a, nullState); + } + } + } + + return res; +} + +automaton::DFA FSMTotal::total(const automaton::DFA& automaton) { + automaton::DFA res(automaton); + automaton::State nullState = automaton::createUniqueState(automaton::State("q0"), automaton.getStates()); + res.addState(nullState); + + for(const auto& q : res.getStates()) { + for(const auto& a : res.getInputAlphabet()) { + if(res.getTransitions().find(std::make_pair(q, a)) == res.getTransitions().end()) { + res.addTransition(q, a, nullState); + } + } + } + + return res; +} + +void FSMTotal::Visit(void*, const UnknownAutomaton&) const { + throw exception::AlibException("Unsupported automaton type UnknownAutomaton"); +} + +void FSMTotal::Visit(void*, const EpsilonNFA&) const { + throw exception::AlibException("Unsupported automaton type EpsilonNFA"); +} + +void FSMTotal::Visit(void* data, const NFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->total(automaton)); +} + +void FSMTotal::Visit(void* data, const DFA& automaton) const { + automaton::Automaton*& out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->total(automaton)); +} + +void FSMTotal::Visit(void*, const ExtendedNFA&) const { + throw exception::AlibException("Unsupported automaton type ExtendedNFA"); +} + +void FSMTotal::Visit(void*, const CompactNFA&) const { + throw exception::AlibException("Unsupported automaton type CompactNFA"); +} + +void FSMTotal::Visit(void*, const DPDA&) const { + throw exception::AlibException("Unsupported automaton type UnknownAutomaton"); +} + +void FSMTotal::Visit(void*, const SinglePopDPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); +} + +void FSMTotal::Visit(void*, const InputDrivenNPDA&) const { + throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); +} + +void FSMTotal::Visit(void*, const VisiblyPushdownNPDA&) const { + throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); +} + +void FSMTotal::Visit(void*, const NPDA&) const { + throw exception::AlibException("Unsupported automaton type NPDA"); +} + +void FSMTotal::Visit(void*, const SinglePopNPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); +} + +void FSMTotal::Visit(void*, const OneTapeDTM&) const { + throw exception::AlibException("Unsupported automaton type OneTapeDTM"); +} + +const FSMTotal FSMTotal::FSM_TOTAL; + +} + diff --git a/alib2algo/src/automaton/FSMTotal.h b/alib2algo/src/automaton/FSMTotal.h new file mode 100644 index 0000000000000000000000000000000000000000..420abb04b34383bffd02c2b903c9249f9b9b9ca1 --- /dev/null +++ b/alib2algo/src/automaton/FSMTotal.h @@ -0,0 +1,54 @@ +/* + * FSMTotal.h + * + * Created on: 20. 9. 2014 + * Author: Tomas Pecka + */ + +#ifndef FSM_TOTAL_H_ +#define FSM_TOTAL_H_ + +#include <algorithm> +#include <deque> +#include <set> + +#include "automaton/Automaton.h" +#include <automaton/common/State.h> + +namespace automaton { + +/** + * Makes finite automaton's transition function total. + * Source: Melichar: Algorithm 2.22 + */ +class FSMTotal : public VisitableAutomatonBase::const_visitor_type { +public: + /** + * Computes epsilon closure of a state in epsilon nonfree automaton + */ + static automaton::Automaton total(const automaton::Automaton& automaton); + + static automaton::NFA total(const automaton::NFA& automaton); + static automaton::DFA total(const automaton::DFA& 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 FSMTotal FSM_TOTAL; +}; + +} + +#endif /* FSM_TOTAL_H_ */ diff --git a/alib2algo/test-src/automaton/FSMTotalTest.cpp b/alib2algo/test-src/automaton/FSMTotalTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af6566234751d340aee87535e4845f5ba5a67aa8 --- /dev/null +++ b/alib2algo/test-src/automaton/FSMTotalTest.cpp @@ -0,0 +1,48 @@ +#include "FSMTotalTest.h" + +#include <automaton/FSM/DFA.h> +#include <alphabet/LabeledSymbol.h> +#include <label/Label.h> +#include <label/CharacterLabel.h> + +#include "automaton/FSMTotal.h" +#include "normalize/dfa/NormalizeDFA.h" +#include "trim/automaton/TrimFSM.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TotalTest ); + +void TotalTest::setUp() { +} + +void TotalTest::tearDown() { +} + +void TotalTest::testTotal() { + automaton::State q0("q0"); + automaton::State q1("q1"); + automaton::State q2("q2"); + + alphabet::Symbol a(alphabet::LabeledSymbol(label::Label(label::CharacterLabel('a')))); + alphabet::Symbol b(alphabet::LabeledSymbol(label::Label(label::CharacterLabel('b')))); + alphabet::Symbol c(alphabet::LabeledSymbol(label::Label(label::CharacterLabel('c')))); + + automaton::DFA automaton(q0); + automaton.setStates({q0, q1, q2}); + automaton.setFinalStates({q0, q1, q2}); + automaton.setInputSymbols({a, b, c}); + + automaton.addTransition(q0, a, q0); + automaton.addTransition(q0, b, q1); + automaton.addTransition(q0, c, q2); + automaton.addTransition(q1, b, q1); + automaton.addTransition(q1, c, q2); + automaton.addTransition(q2, c, q2); + + automaton::DFA totalAutomaton = automaton::FSMTotal::total(automaton); + CPPUNIT_ASSERT(totalAutomaton.isTotal()); + + automaton::DFA trimmedAutomaton = trim::TrimFSM::trim(automaton); + automaton::DFA trimmedTotalAutomaton = trim::TrimFSM::trim(totalAutomaton); + + CPPUNIT_ASSERT(normalize::NormalizeDFA::normalize(trimmedAutomaton) == normalize::NormalizeDFA::normalize(trimmedTotalAutomaton)); +} diff --git a/alib2algo/test-src/automaton/FSMTotalTest.h b/alib2algo/test-src/automaton/FSMTotalTest.h new file mode 100644 index 0000000000000000000000000000000000000000..1a7b09f16db80b52d4d7dc9c932ce2fb470a9df6 --- /dev/null +++ b/alib2algo/test-src/automaton/FSMTotalTest.h @@ -0,0 +1,19 @@ +#ifndef FSM_TOTAL_TEST_H_ +#define FSM_TOTAL_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class TotalTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( TotalTest ); + CPPUNIT_TEST( testTotal ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testTotal(); +}; + +#endif /* FSM_TOTAL_TEST_H_ */