diff --git a/alib2algo/src/automaton/simplify/MinimizeBrzozowski.cpp b/alib2algo/src/automaton/simplify/MinimizeBrzozowski.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6352dee80f445ea6609ee03bf5965ed6c6c3f15 --- /dev/null +++ b/alib2algo/src/automaton/simplify/MinimizeBrzozowski.cpp @@ -0,0 +1,67 @@ +/* + * MinimizeBrzozowski.cpp + * + * Created on: 18. 11. 2014 + * Author: Tomas Pecka + */ + +#include "MinimizeBrzozowski.h" + +#include <exception/AlibException.h> +#include <automaton/Automaton.h> +#include <automaton/FSM/MultiInitialStateNFA.h> + +#include "../transform/ReverseFSM.h" +#include "../determinize/Determinize.h" + +namespace automaton { + +namespace simplify { + +automaton::Automaton MinimizeBrzozowski::minimize(const automaton::Automaton& automaton) { + automaton::Automaton* out = NULL; + automaton.getData().Accept((void*) &out, MinimizeBrzozowski::MINIMIZE_BRZOZOWSKI); + automaton::Automaton res = std::move(*out); + delete out; + return res; +} + +automaton::DFA MinimizeBrzozowski::minimize(const automaton::DFA& dfa) { + return automaton::determinize::Determinize::determinize(automaton::transform::ReverseFSM::convert(automaton::determinize::Determinize::determinize(automaton::transform::ReverseFSM::convert(dfa)))); +} + +automaton::DFA MinimizeBrzozowski::minimize(const automaton::NFA& nfa) { + return automaton::determinize::Determinize::determinize(automaton::transform::ReverseFSM::convert(automaton::determinize::Determinize::determinize(automaton::transform::ReverseFSM::convert(nfa)))); +} + +void MinimizeBrzozowski::Visit(void*, const automaton::EpsilonNFA&) const { + throw exception::AlibException("Unsupported automaton type EpsilonNFA"); +} + +void MinimizeBrzozowski::Visit(void* data, const automaton::DFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->minimize(automaton)); +} + +void MinimizeBrzozowski::Visit(void*, const automaton::MultiInitialStateNFA&) const { + throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA"); +} + +void MinimizeBrzozowski::Visit(void* data, const automaton::NFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->minimize(automaton)); +} + +void MinimizeBrzozowski::Visit(void*, const automaton::ExtendedNFA& ) const { + throw exception::AlibException("Unsupported automaton type ExtendedNFA"); +} + +void MinimizeBrzozowski::Visit(void*, const automaton::CompactNFA& ) const { + throw exception::AlibException("Unsupported automaton type CompactNFA"); +} + +const MinimizeBrzozowski MinimizeBrzozowski::MINIMIZE_BRZOZOWSKI; + +} /* namespace simplify */ + +} /* namespace automaton */ diff --git a/alib2algo/src/automaton/simplify/MinimizeBrzozowski.h b/alib2algo/src/automaton/simplify/MinimizeBrzozowski.h new file mode 100644 index 0000000000000000000000000000000000000000..c21dc2d49b4ea58cac444d820cf6535943f6c319 --- /dev/null +++ b/alib2algo/src/automaton/simplify/MinimizeBrzozowski.h @@ -0,0 +1,43 @@ +/* + * MinimizeBrzozowski.cpp + * + * Created on: 18. 11. 2014 + * Author: Tomas Pecka + */ + +#ifndef MINIMIZE_BRZOZOWSKI_H_ +#define MINIMIZE_BRZOZOWSKI_H_ + +#include <automaton/Automaton.h> +#include <automaton/FSM/DFA.h> + +namespace automaton { + +namespace simplify { + +class MinimizeBrzozowski : public automaton::VisitableConstFSMBase { +public: + /** + * @param dfa automaton to minimize + */ + static automaton::Automaton minimize(const automaton::Automaton& dfa); + + static automaton::DFA minimize(const automaton::DFA& dfa); + static automaton::DFA minimize(const automaton::NFA& nfa); + +protected: + 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; + + static const MinimizeBrzozowski MINIMIZE_BRZOZOWSKI; +}; + +} /* namespace simplify */ + +} /* namespace automaton */ + +#endif /* MINIMIZE_BRZOZOWSKI_H_ */ diff --git a/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp b/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp index 540d6723dfd8691e1f06e1fbc726f68783f2a017..243a0e99bd56ea25c1798282a1a51bd6be0a7e97 100644 --- a/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp +++ b/alib2algo/src/automaton/simplify/UselessStatesRemover.cpp @@ -32,6 +32,9 @@ T UselessStatesRemover::remove( const T & fsm ) { // 2. T M(fsm.getInitialState()); + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + if(Qu.size() == 0) { return M; } @@ -39,9 +42,6 @@ T UselessStatesRemover::remove( const T & fsm ) { for( const auto & q : Qu ) M.addState( q ); - for( const auto & a : fsm.getInputAlphabet( ) ) - M.addInputSymbol( a ); - 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) ) @@ -66,6 +66,9 @@ automaton::DFA UselessStatesRemover::remove( const automaton::DFA & fsm ) { // 2. automaton::DFA M ( fsm.getInitialState () ); + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + if(Qu.size() == 0) { return M; } @@ -73,9 +76,6 @@ automaton::DFA UselessStatesRemover::remove( const automaton::DFA & fsm ) { for( const auto & q : Qu ) M.addState( q ); - for( const auto & a : fsm.getInputAlphabet( ) ) - M.addInputSymbol( a ); - 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 ); @@ -94,6 +94,9 @@ automaton::MultiInitialStateNFA UselessStatesRemover::remove( const automaton::M // 2. automaton::MultiInitialStateNFA M; + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + if(Qu.size() == 0) { return M; } @@ -106,9 +109,6 @@ automaton::MultiInitialStateNFA UselessStatesRemover::remove( const automaton::M M.addInitialState( init ); } - for( const auto & a : fsm.getInputAlphabet( ) ) - M.addInputSymbol( a ); - for( const auto & t : fsm.getTransitions( ) ) for( const auto & to : t.second ) if( Qu.count(to) ) diff --git a/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.cpp b/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef1daf2b4080d49f85ff999a68f7576f902d94ad --- /dev/null +++ b/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.cpp @@ -0,0 +1,38 @@ +#include <list> +#include "minimizeBrzozowskiTest.h" + +#include "automaton/simplify/MinimizeBrzozowski.h" +#include "automaton/simplify/Minimize.h" +#include "automaton/simplify/Trim.h" +#include "automaton/simplify/Normalize.h" + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( minimizeBrzozowskiTest ); + +void minimizeBrzozowskiTest::setUp() { +} + +void minimizeBrzozowskiTest::tearDown() { +} + +void minimizeBrzozowskiTest::testMinimizeBrzozowski() { + 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.addFinalState(automaton::State(3)); + + automaton::DFA minimizedHopcroft = automaton::simplify::Minimize::minimize(automaton); + automaton::DFA minimizedBrzozowski = automaton::simplify::MinimizeBrzozowski::minimize(automaton); + + CPPUNIT_ASSERT(minimizedHopcroft.getStates().size() == 3); + CPPUNIT_ASSERT(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(minimizedHopcroft)) == automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(minimizedBrzozowski))); +} diff --git a/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.h b/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.h new file mode 100644 index 0000000000000000000000000000000000000000..0039075c8bd7e0694a142f36f6ee72a73709e47c --- /dev/null +++ b/alib2algo/test-src/automaton/simplify/minimizeBrzozowskiTest.h @@ -0,0 +1,19 @@ +#ifndef MINIMIZE_BRZOZOWSKI_TEST_H_ +#define MINIMIZE_BRZOZOWSKI_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class minimizeBrzozowskiTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( minimizeBrzozowskiTest ); + CPPUNIT_TEST( testMinimizeBrzozowski ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testMinimizeBrzozowski(); +}; + +#endif // MINIMIZE_BRZOZOWSKI_TEST_H_ diff --git a/aminimize2/src/aminimize.cpp b/aminimize2/src/aminimize.cpp index 3a6c226ecf3bbdcd479255e24d5a6e8fcaf39446..bc1790abd07195fdd849470b0d96b62a1f036226 100644 --- a/aminimize2/src/aminimize.cpp +++ b/aminimize2/src/aminimize.cpp @@ -11,6 +11,7 @@ #include <factory/DataFactory.hpp> #include "automaton/simplify/Minimize.h" +#include "automaton/simplify/MinimizeBrzozowski.h" int main(int argc, char** argv) { @@ -20,6 +21,11 @@ int main(int argc, char** argv) { TCLAP::ValueArg<std::string> input( "a", "automaton", "Automaton to minimize", false, "-", "file"); cmd.add( input ); + std::vector<std::string> algorithms {"Hopcroft", "Brzozowski" }; + TCLAP::ValuesConstraint<std::string> algorithmVals( algorithms ); + TCLAP::ValueArg<std::string> algorithm( "g", "algorithm", "Use specific algorithm. Hopcroft default.", false, "Hopcroft", &algorithmVals); + cmd.add( algorithm ); + cmd.parse(argc, argv); std::list<sax::Token> tokens; @@ -33,7 +39,15 @@ int main(int argc, char** argv) { sax::SaxParseInterface::parseStdin(tokens); } - alib::DataFactory::toStdout(automaton::simplify::Minimize::minimize(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + if(algorithm.getValue() == "Hopcroft") { + alib::DataFactory::toStdout(automaton::simplify::Minimize::minimize(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + } + else if(algorithm.getValue() == "Brzozowski") { + alib::DataFactory::toStdout(automaton::simplify::MinimizeBrzozowski::minimize(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + } else { + throw exception::AlibException("Unknown algorithm selected."); + } + return 0; } catch (const exception::AlibException& exception) {