diff --git a/alib2algo/src/automaton/transform/Compaction.cpp b/alib2algo/src/automaton/transform/Compaction.cpp index aee716ea161f81b9f810f08946fca11aff7e1633..1563cdefdd90c8703ab7a357b2940fa4979fdd3b 100644 --- a/alib2algo/src/automaton/transform/Compaction.cpp +++ b/alib2algo/src/automaton/transform/Compaction.cpp @@ -38,57 +38,43 @@ automaton::CompactNFA Compaction::convert(const automaton::DFA& automaton) automaton::CompactNFA res(automaton.getInitialState()); res.setInputAlphabet(automaton.getInputAlphabet()); - string::LinearString path; - path.setAlphabet(automaton.getInputAlphabet()); - - std::map<automaton::State, bool> visited; - for(const auto& state : automaton.getStates()) - visited.insert(std::make_pair(state, automaton.getInitialState() == state)); + std::set<automaton::State> visited; std::stack<std::tuple<automaton::State, automaton::State, alphabet::Symbol>> stack; // state x lastFork x symbol we used to go to that state for(const auto& transition: automaton.getTransitionsFromState(automaton.getInitialState())) - { stack.push(std::make_tuple(transition.second, automaton.getInitialState(), transition.first.second)); - } if(automaton.getFinalStates().count(automaton.getInitialState()) > 0) res.addFinalState(automaton.getInitialState()); - while(!stack.empty()) - { - const automaton::State q = std::get<0>(stack.top()); - const automaton::State lastFork = std::get<1>(stack.top()); - const alphabet::Symbol symbol = std::get<2>(stack.top()); + while(!stack.empty()) { + automaton::State q = std::move(std::get<0>(stack.top())); + automaton::State lastFork = std::move(std::get<1>(stack.top())); + alphabet::Symbol symbol = std::move(std::get<2>(stack.top())); stack.pop(); - path.appendSymbol(symbol); + string::LinearString path { automaton.getInputAlphabet(), { symbol } }; + std::map<std::pair<automaton::State, alphabet::Symbol>, automaton::State> transitions; // only 1 child and nonfinal - if(automaton.getTransitionsFromState(q).size() == 1 && automaton.getFinalStates().count(q) == 0 && automaton.getInitialState() != q) - { - const auto& transition = * automaton.getTransitionsFromState(q).begin(); - - stack.push(std::make_tuple(transition.second, lastFork, transition.first.second)); - } - else // fork or final state - { - res.addState(q); - - if(automaton.getFinalStates().count(q)) - res.addFinalState(q); - - res.addTransition(lastFork, path, q); - path.setContent({}); - - for(const auto& transition : automaton.getTransitionsFromState(q)) - { - if(visited.find(transition.second)->second == false) - { - stack.push(std::make_tuple(transition.second, q, transition.first.second)); - visited.find(transition.second)->second = true; - } - } + while((transitions = std::move(automaton.getTransitionsFromState(q))).size() == 1 && automaton.getFinalStates().count(q) == 0) { + const std::pair<std::pair<automaton::State, alphabet::Symbol>, automaton::State>& transition = * transitions.begin(); + path.appendSymbol(transition.first.second); + q = transition.second; } + + // fork or final state + res.addState(q); + + if(automaton.getFinalStates().count(q)) + res.addFinalState(q); + + res.addTransition(lastFork, path, q); + + for(const std::pair<std::pair<automaton::State, alphabet::Symbol>, automaton::State>& transition : automaton.getTransitionsFromState(q)) + if(visited.insert(transition.second).second) + stack.push(std::make_tuple(transition.second, q, transition.first.second)); + } return res; diff --git a/alib2algo/test-src/automaton/transform/AutomataCompactionTest.cpp b/alib2algo/test-src/automaton/transform/AutomataCompactionTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c3b80c582e8322c69c7c6edf8716a08c14481f2 --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataCompactionTest.cpp @@ -0,0 +1,111 @@ +#include <list> +#include "AutomataCompactionTest.h" + +#include "automaton/transform/Compaction.h" +#include <alphabet/Symbol.h> +#include <automaton/FSM/DFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <string/LinearString.h> + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AutomataCompactionTest, "automaton" ); +CPPUNIT_TEST_SUITE_REGISTRATION( AutomataCompactionTest ); + +void AutomataCompactionTest::setUp() { +} + +void AutomataCompactionTest::tearDown() { +} + +void AutomataCompactionTest::testAutomataCompaction1() { + automaton::State q0("0"), q1("1"), q2("2"), q3("3"), q4("4"), q5("5"); + alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b')); + + automaton::DFA m1(q0); + automaton::CompactNFA m2(q0); + + m1.setInputAlphabet({a, b}); + m1.setStates({q0, q1, q2, q3, q4, q5}); + m1.addTransition(q0, a, q1); + m1.addTransition(q1, b, q2); + m1.addTransition(q2, a, q3); + m1.addTransition(q3, b, q4); + m1.addTransition(q4, a, q5); + m1.addFinalState(q5); + + m2.setInputAlphabet({a, b}); + m2.setStates({q0, q5}); + m2.addTransition(q0, string::LinearString{ { a, b }, {a, b, a, b, a} }, q5); + m2.addFinalState(q5); + + automaton::CompactNFA c1 = automaton::transform::Compaction::convert(m1); + + CPPUNIT_ASSERT(c1 == m2); + +} + +void AutomataCompactionTest::testAutomataCompaction2() { + automaton::State q0("0"), q1("1"), q2("2"), q3("3"), q4("4"), q5("5"); + alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b')); + + automaton::DFA m1(q0); + automaton::CompactNFA m2(q0); + + m1.setInputAlphabet({a, b}); + m1.setStates({q0, q1, q2, q3, q4, q5}); + m1.addTransition(q0, a, q1); + m1.addTransition(q1, b, q2); + m1.addTransition(q2, a, q3); + m1.addTransition(q3, b, q4); + m1.addTransition(q4, a, q5); + m1.addTransition(q5, a, q1); + m1.addFinalState(q5); + + m2.setInputAlphabet({a, b}); + m2.setStates({q0, q5}); + m2.addTransition(q0, string::LinearString{ { a, b }, {a, b, a, b, a} }, q5); + m2.addTransition(q5, string::LinearString{ { a, b }, {a, b, a, b, a} }, q5); + m2.addFinalState(q5); + + automaton::CompactNFA c1 = automaton::transform::Compaction::convert(m1); + + CPPUNIT_ASSERT(c1 == m2); + +} + +void AutomataCompactionTest::testAutomataCompaction3() { + automaton::State q0("0"), q1("1"), q2("2"), q3("3"), q4("4"), q5("5"), q6("6"); + alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b')); + + automaton::DFA m1(q0); + automaton::CompactNFA m2(q0); + + m1.setInputAlphabet({a, b}); + m1.setStates({q0, q1, q2, q3, q4, q5, q6}); + m1.addTransition(q0, a, q1); + m1.addTransition(q1, a, q2); + m1.addTransition(q2, a, q3); + m1.addTransition(q3, a, q4); + m1.addTransition(q4, a, q2); + m1.addTransition(q1, b, q5); + m1.addTransition(q5, b, q6); + m1.addTransition(q6, a, q0); + m1.addFinalState(q3); + m1.addFinalState(q5); + + m2.setInputAlphabet({a, b}); + m2.setStates({q0, q1, q3, q5}); + m2.addTransition(q0, string::LinearString{ { a, b }, {a} }, q1); + m2.addTransition(q1, string::LinearString{ { a, b }, {a, a} }, q3); + m2.addTransition(q3, string::LinearString{ { a, b }, {a, a, a} }, q3); + m2.addTransition(q1, string::LinearString{ { a, b }, {b} }, q5); + m2.addTransition(q5, string::LinearString{ { a, b }, {b, a, a} }, q1); + m2.addFinalState(q3); + m2.addFinalState(q5); + + automaton::CompactNFA c1 = automaton::transform::Compaction::convert(m1); + + CPPUNIT_ASSERT(c1 == m2); + +} diff --git a/alib2algo/test-src/automaton/transform/AutomataCompactionTest.h b/alib2algo/test-src/automaton/transform/AutomataCompactionTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5f739feed395a5bf8e97ecdfd85c18a25918bf18 --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataCompactionTest.h @@ -0,0 +1,23 @@ +#ifndef AUTOMATA_COMPACTION_TEST_H_ +#define AUTOMATA_COMPACTION_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class AutomataCompactionTest : public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE( AutomataCompactionTest ); + CPPUNIT_TEST( testAutomataCompaction1 ); + CPPUNIT_TEST( testAutomataCompaction2 ); + CPPUNIT_TEST( testAutomataCompaction3 ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testAutomataCompaction1(); + void testAutomataCompaction2(); + void testAutomataCompaction3(); +}; + +#endif /* AUTOMATA_COMPACTION_TEST_H_ */