diff --git a/alib2algo/src/automaton/simplify/Minimize.cpp b/alib2algo/src/automaton/simplify/Minimize.cpp index 7cd64184fe8b4d8ec780443c4f0f0226a7c1a378..110d208996783e91efee270b9dc182a577c6ad3c 100644 --- a/alib2algo/src/automaton/simplify/Minimize.cpp +++ b/alib2algo/src/automaton/simplify/Minimize.cpp @@ -16,6 +16,7 @@ automaton::Automaton Minimize::minimize(const automaton::Automaton& automaton) { } auto MinimizeNFA = Minimize::RegistratorWrapper<automaton::DFA<>, automaton::DFA<>>( Minimize::minimize ); +auto MinimizeNFTA = Minimize::RegistratorWrapper<automaton::DFTA<>, automaton::DFTA<>>( Minimize::minimize ); } /* namespace simplify */ diff --git a/alib2algo/src/automaton/simplify/Minimize.h b/alib2algo/src/automaton/simplify/Minimize.h index 2ad33d66d16bdea0dd074888f8ea49737176813f..bde5a7ec46b0b46f5eaaaf32c659a9a7fe5a8025 100644 --- a/alib2algo/src/automaton/simplify/Minimize.h +++ b/alib2algo/src/automaton/simplify/Minimize.h @@ -11,6 +11,7 @@ #include <core/multipleDispatch.hpp> #include <automaton/Automaton.h> #include <automaton/FSM/DFA.h> +#include <automaton/TA/DFTA.h> #include <map> #include <set> @@ -33,6 +34,9 @@ public: template < class SymbolType, class StateType > static automaton::DFA < SymbolType, StateType > minimize(const automaton::DFA < SymbolType, StateType >& dfa); + template < class SymbolType, class RankType, class StateType > + static automaton::DFTA < SymbolType, RankType, StateType > minimize(const automaton::DFTA < SymbolType, RankType, StateType >& dfta); + private: template < class SymbolType, class StateType > static void print_progress(const automaton::DFA < SymbolType, StateType >& dfa, const std::map<std::pair<StateType, std::set<std::pair<SymbolType, StateType> > >, std::set<StateType> >& minimizedTransitionFunction, size_t iter); @@ -208,6 +212,94 @@ void Minimize::print_progress(const automaton::DFA < SymbolType, StateType >& df std::clog << std::endl; } +template < class SymbolType, class RankType, class StateType > +automaton::DFTA < SymbolType, RankType, StateType > Minimize::minimize(const automaton::DFTA < SymbolType, RankType, StateType >& dfta) { + automaton::DFTA<SymbolType, RankType, StateType> result; + result.setInputAlphabet(dfta.getInputAlphabet()); + + if (dfta.getFinalStates().size() == 0) + return result; + + typedef std::pair < const std::pair < std::ranked_symbol < SymbolType, RankType >, std::vector < StateType > >, StateType > Transition; + + std::map<StateType, std::map<Transition, std::vector<int>>> stateOccurences; + + for (const auto & state : dfta.getStates()) + stateOccurences[state]; + + for(auto & transition : dfta.getTransitions()) { + const std::vector<StateType> & from = transition.first.second; + for (int i = 0; i < (int) from.size(); ++i) + stateOccurences[from[i]][transition].push_back(i); + } + + std::map <StateType, StateType> toEquivalentStates; + std::map<std::pair<StateType, std::map<std::tuple<std::ranked_symbol<SymbolType, RankType>, std::vector<StateType>, StateType >, std::set<int> > >, std::set<StateType> > minimizedTransitionFunction; //mapped to the original states + const StateType *firstFinal = NULL, *firstNonfinal = NULL; + for (const StateType &state : dfta.getStates()) { + if (dfta.getFinalStates().count(state) == 0) { // not a final state + if (!firstNonfinal) + firstNonfinal = &state; + + toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstNonfinal)); + } else { + if (!firstFinal) + firstFinal = &state; + + toEquivalentStates.insert(std::pair<StateType, StateType>(state, *firstFinal)); + } + } + + unsigned prevSize = 0; + while(true) { + for(const auto & occurencesOfState : stateOccurences) { + const StateType & state = occurencesOfState.first; + const StateType & equivalentState = toEquivalentStates.find(state) -> second; + std::map<std::tuple<std::ranked_symbol<SymbolType, RankType>, std::vector<StateType>, StateType >, std::set<int> > keyTransitionsPart; + + for(const auto & transitionOccurences : occurencesOfState.second) { + const auto & transition = transitionOccurences.first; + for (int i : transitionOccurences.second) { + std::vector<StateType> fromWithoutCurrent (transition.first.second); + fromWithoutCurrent.erase(fromWithoutCurrent.begin()+i); + keyTransitionsPart[std::make_tuple(transition.first.first, fromWithoutCurrent, toEquivalentStates.find(transition.second)->second)].insert(i); + } + } + + minimizedTransitionFunction [ std::make_pair ( equivalentState, keyTransitionsPart ) ].insert(state); + } + + if (minimizedTransitionFunction.size() == prevSize) + break; + + prevSize = minimizedTransitionFunction.size(); + toEquivalentStates.clear(); + for(const auto & transition : minimizedTransitionFunction) + for(const StateType & target : transition.second) + toEquivalentStates.insert(std::make_pair ( target, * transition.second.begin() ) ); + + minimizedTransitionFunction.clear(); + } + + for (const auto & transition : minimizedTransitionFunction) { + const auto & state = *(transition.second.begin()); + result.addState(state); + if(dfta.getFinalStates().count(state)) + result.addFinalState(state); + } + + for(const auto & transition : dfta.getTransitions()) { + std::vector<StateType> from; + from.reserve(transition.first.second.size()); + for (const StateType & state : transition.first.second) + from.push_back(toEquivalentStates.find(state)->second); + + result.addTransition(transition.first.first, from, toEquivalentStates.find(transition.second)->second); + } + + return result; +} + } /* namespace simplify */ } /* namespace automaton */ diff --git a/alib2algo/test-src/automaton/simplify/minimizeTest.cpp b/alib2algo/test-src/automaton/simplify/minimizeTest.cpp index bf891143c2e444223d1ef011ceeeedc7f933231f..60cd74c3c496665eabd60fb9e6e26cf00d43861c 100644 --- a/alib2algo/test-src/automaton/simplify/minimizeTest.cpp +++ b/alib2algo/test-src/automaton/simplify/minimizeTest.cpp @@ -2,6 +2,7 @@ #include "minimizeTest.h" #include "automaton/simplify/Minimize.h" +#include <factory/XmlDataFactory.hpp> CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( minimizeTest, "automaton" ); CPPUNIT_TEST_SUITE_REGISTRATION( minimizeTest ); @@ -12,22 +13,166 @@ void minimizeTest::setUp() { void minimizeTest::tearDown() { } -void minimizeTest::testMinimize() { - automaton::DFA < > automaton(DefaultStateType(1)); +void minimizeTest::testMinimizeDFA() { + automaton::DFA < > automaton(DefaultStateType(1)); - automaton.addState(DefaultStateType(1)); - automaton.addState(DefaultStateType(2)); - automaton.addState(DefaultStateType(3)); - automaton.addInputSymbol(DefaultSymbolType("a")); - automaton.addInputSymbol(DefaultSymbolType("b")); - - automaton.addTransition(DefaultStateType(1), DefaultSymbolType("a"), DefaultStateType(2)); - automaton.addTransition(DefaultStateType(2), DefaultSymbolType("b"), DefaultStateType(1)); + automaton.addState(DefaultStateType(1)); + automaton.addState(DefaultStateType(2)); + automaton.addState(DefaultStateType(3)); + automaton.addInputSymbol(DefaultSymbolType("a")); + automaton.addInputSymbol(DefaultSymbolType("b")); - automaton.addFinalState(DefaultStateType(3)); - - automaton::DFA<> minimized = automaton::simplify::Minimize::minimize(automaton); + automaton.addTransition(DefaultStateType(1), DefaultSymbolType("a"), DefaultStateType(2)); + automaton.addTransition(DefaultStateType(2), DefaultSymbolType("b"), DefaultStateType(1)); - CPPUNIT_ASSERT(minimized.getStates().size() == 3); + automaton.addFinalState(DefaultStateType(3)); + automaton::DFA<> minimized = automaton::simplify::Minimize::minimize(automaton); + + CPPUNIT_ASSERT(minimized.getStates().size() == 3); + +} + +void minimizeTest::testMinimizeDFTA() { + automaton::DFTA < > automaton; + + std::vector<DefaultStateType> q; + + for (int i = 0; i <= 10; ++i) { + DefaultStateType state (i); + q.push_back(state); + automaton.addState(state); + } + + automaton.addFinalState(q[9]); + automaton.addFinalState(q[10]); + + const std::ranked_symbol < > a ("a", 3); + const std::ranked_symbol < > b ("b", 2); + const std::ranked_symbol < > c ("c", 1); + const std::ranked_symbol < > d ("d", 0); + const std::ranked_symbol < > e ("e", 0); + const std::ranked_symbol < > f ("f", 0); + const std::ranked_symbol < > g ("g", 0); + + automaton.addInputSymbol(a); + automaton.addInputSymbol(b); + automaton.addInputSymbol(c); + automaton.addInputSymbol(d); + automaton.addInputSymbol(e); + automaton.addInputSymbol(f); + automaton.addInputSymbol(g); + + automaton.addTransition(d, {}, q[0]); + automaton.addTransition(e, {}, q[1]); + + for (int i = 0; i <= 1; ++i) { + for (int j = 0; j <= 1; ++j) { + automaton.addTransition(b, {q[i], q[j]}, q[2]); + } + } + + automaton.addTransition(b, {q[2], q[2]}, q[6]); + automaton.addTransition(f, {}, q[3]); + for (int i = 3; i < 5; ++i) { + automaton.addTransition(c, {q[i]}, q[i+1]); + } + + automaton.addTransition(c, {q[5]}, q[7]); + automaton.addTransition(g, {}, q[8]); + + for (int i = 6; i <= 8; ++i) { + for (int j = 6; j <= 8; ++j) { + for (int k = 6; k <= 8; ++k) { + automaton.addTransition(a, {q[i], q[j], q[k]}, q[9]); + } + } + } + + automaton.addTransition(a, {q[9], q[9], q[9]}, q[10]); + + automaton::DFTA < > minimal; + minimal.addState(q[0]); + minimal.addState(q[2]); + minimal.addState(q[3]); + minimal.addState(q[4]); + minimal.addState(q[5]); + minimal.addState(q[6]); + minimal.addState(q[9]); + minimal.addState(q[10]); + minimal.setFinalStates(automaton.getFinalStates()); + minimal.setInputAlphabet(automaton.getInputAlphabet()); + minimal.addTransition(d, {}, q[0]); + minimal.addTransition(e, {}, q[0]); + minimal.addTransition(b, {q[0], q[0]}, q[2]); + minimal.addTransition(b, {q[2], q[2]}, q[6]); + minimal.addTransition(f, {}, q[3]); + + for (int i = 3; i < 5; ++i) { + minimal.addTransition(c, {q[i]}, q[i+1]); + } + + minimal.addTransition(c, {q[5]}, q[6]); + minimal.addTransition(g, {}, q[6]); + minimal.addTransition(a, {q[6], q[6], q[6]}, q[9]); + minimal.addTransition(a, {q[9], q[9], q[9]}, q[10]); + + automaton::DFTA<> minimized = automaton::simplify::Minimize::minimize(automaton); + CPPUNIT_ASSERT(minimized == minimal); + +/* automaton::DFTA < > automaton; + + const DefaultStateType q0 ("0"); + const DefaultStateType q1 ("1"); + const DefaultStateType q00 ("00"); + const DefaultStateType q11 ("11"); + automaton.addState(q0); + automaton.addState(q1); + automaton.addState(q00); + automaton.addState(q11); + + const std::ranked_symbol < > st ("t", 0); + const std::ranked_symbol < > sf ("f", 0); + const std::ranked_symbol < > snot ("not", 1); + const std::ranked_symbol < > sor ("or", 2); + automaton.addInputSymbol(st); + automaton.addInputSymbol(sf); + automaton.addInputSymbol(snot); + automaton.addInputSymbol(sor); + + automaton.addTransition(st, {}, q1); + automaton.addTransition(sf, {}, q0); + + automaton.addTransition(snot, {q0}, q1); + automaton.addTransition(snot, {q1}, q0); + automaton.addTransition(snot, {q00}, q1); + automaton.addTransition(snot, {q11}, q0); + + automaton.addTransition(sor, {q0, q0}, q00); + automaton.addTransition(sor, {q0, q00}, q00); + automaton.addTransition(sor, {q00, q0}, q00); + automaton.addTransition(sor, {q00, q00}, q00); + automaton.addTransition(sor, {q0, q1}, q1); + automaton.addTransition(sor, {q0, q11}, q1); + automaton.addTransition(sor, {q00, q1}, q1); + automaton.addTransition(sor, {q00, q11}, q1); + automaton.addTransition(sor, {q1, q0}, q1); + automaton.addTransition(sor, {q1, q00}, q1); + automaton.addTransition(sor, {q11, q0}, q1); + automaton.addTransition(sor, {q11, q00}, q1); + automaton.addTransition(sor, {q1, q1}, q11); + automaton.addTransition(sor, {q1, q11}, q11); + automaton.addTransition(sor, {q11, q1}, q11); + automaton.addTransition(sor, {q11, q11}, q11); + + automaton.addFinalState(q1); + automaton.addFinalState(q11); + + automaton::DFTA<> minimized = automaton::simplify::Minimize::minimize(automaton); + std::cout << minimized << std::endl; + CPPUNIT_ASSERT(minimized.getStates().size() == 2); + CPPUNIT_ASSERT(minimized.getFinalStates().size() == 1); + CPPUNIT_ASSERT(minimized.getTransitions().size() == 8); + CPPUNIT_ASSERT(minimized.getInputAlphabet().size() == 4); +*/ } diff --git a/alib2algo/test-src/automaton/simplify/minimizeTest.h b/alib2algo/test-src/automaton/simplify/minimizeTest.h index 4b1f60f638835bd1ca86c227b077a1fb1aeb996a..50813dbd68c983f7b12873b98c2bb7a493aa4e01 100644 --- a/alib2algo/test-src/automaton/simplify/minimizeTest.h +++ b/alib2algo/test-src/automaton/simplify/minimizeTest.h @@ -3,17 +3,18 @@ #include <cppunit/extensions/HelperMacros.h> -class minimizeTest : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE( minimizeTest ); - CPPUNIT_TEST( testMinimize ); - CPPUNIT_TEST_SUITE_END(); +class minimizeTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE( minimizeTest ); + CPPUNIT_TEST( testMinimizeDFA ); + CPPUNIT_TEST( testMinimizeDFTA ); + CPPUNIT_TEST_SUITE_END(); public: - void setUp(); - void tearDown(); + void setUp(); + void tearDown(); - void testMinimize(); + void testMinimizeDFA(); + void testMinimizeDFTA(); }; #endif // MINIMIZE_TEST_H_