diff --git a/aepsilon2/src/aepsilon.cpp b/aepsilon2/src/aepsilon.cpp index 900d83656ba2113ade621adb090003b61238dcfa..4c5b21530798e9a92870644c4ab4fb4955d2c2ca 100644 --- a/aepsilon2/src/aepsilon.cpp +++ b/aepsilon2/src/aepsilon.cpp @@ -10,16 +10,22 @@ #include <factory/DataFactory.hpp> #include <exception/AlibException.h> -#include "automaton/simplify/EpsilonRemover.h" +#include "automaton/simplify/EpsilonRemoverIncomming.h" +#include "automaton/simplify/EpsilonRemoverOutgoing.h" int main(int argc, char** argv) { try { TCLAP::CmdLine cmd("Automaton rename binary", ' ', "0.01"); - TCLAP::ValueArg<std::string> input( "a", "automaton", "Automaton where to remove epsilon transitions", false, "-", "file"); + TCLAP::ValueArg<std::string> input( "i", "input", "Automaton where to remove epsilon transitions", false, "-", "file"); cmd.add( input ); + std::vector<std::string> algorithms{"incomming", "outgoing", "default" }; + TCLAP::ValuesConstraint<std::string> allowedAlgorithms( algorithms ); + TCLAP::ValueArg<std::string> algorithm( "a", "algorithm", "Specifies algorithm to use", false, "default", &allowedAlgorithms); + cmd.add( algorithm ); + cmd.parse(argc, argv); std::list<sax::Token> tokens; @@ -33,7 +39,13 @@ int main(int argc, char** argv) { sax::SaxParseInterface::parseStdin(tokens); } - alib::DataFactory::toStdout(automaton::simplify::EpsilonRemover::remove(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + if(algorithm.getValue() == "outgoing") + alib::DataFactory::toStdout(automaton::simplify::EpsilonRemoverOutgoing::remove(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + else if(algorithm.getValue() == "incomming" || algorithm.getValue() == "default") { + alib::DataFactory::toStdout(automaton::simplify::EpsilonRemoverIncomming::remove(alib::DataFactory::fromTokens<automaton::Automaton>(tokens))); + } else { + throw exception::AlibException("Invalid algorithm"); + } return 0; } catch (const exception::AlibException& exception) { diff --git a/alib2algo/src/automaton/simplify/EpsilonRemover.cpp b/alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.cpp similarity index 59% rename from alib2algo/src/automaton/simplify/EpsilonRemover.cpp rename to alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.cpp index a50786e7a3293a8fa5687d3453a5b59beb631cc7..e642f9efaa80d98b6a4832255f6ac4e8a51c70ed 100644 --- a/alib2algo/src/automaton/simplify/EpsilonRemover.cpp +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.cpp @@ -1,11 +1,11 @@ /* - * EpsilonRemover.cpp + * EpsilonRemoverIncomming.cpp * - * Created on: 16. 1. 2014 - * Author: Tomas Pecka + * Created on: 24. 11. 2014 + * Author: Jan Travnicek */ -#include "EpsilonRemover.h" +#include "EpsilonRemoverIncomming.h" #include "../properties/EpsilonClosure.h" @@ -13,22 +13,22 @@ namespace automaton { namespace simplify { -automaton::DFA EpsilonRemover::remove(const automaton::DFA& origFSM) +automaton::DFA EpsilonRemoverIncomming::remove(const automaton::DFA& origFSM) { return origFSM; } -automaton::MultiInitialStateNFA EpsilonRemover::remove(const automaton::MultiInitialStateNFA& origFSM) +automaton::MultiInitialStateNFA EpsilonRemoverIncomming::remove(const automaton::MultiInitialStateNFA& origFSM) { return origFSM; } -automaton::NFA EpsilonRemover::remove(const automaton::NFA& origFSM) +automaton::NFA EpsilonRemoverIncomming::remove(const automaton::NFA& origFSM) { return origFSM; } -automaton::NFA EpsilonRemover::remove( const automaton::EpsilonNFA & origFSM ) { +automaton::NFA EpsilonRemoverIncomming::remove( const automaton::EpsilonNFA & origFSM ) { automaton::NFA fsm(origFSM.getInitialState()); for( const auto & state : origFSM.getStates() ) @@ -67,83 +67,83 @@ automaton::NFA EpsilonRemover::remove( const automaton::EpsilonNFA & origFSM ) { return fsm; } -automaton::Automaton EpsilonRemover::remove(const automaton::Automaton& automaton) { +automaton::Automaton EpsilonRemoverIncomming::remove(const automaton::Automaton& automaton) { automaton::Automaton* out = NULL; - automaton.getData().Accept((void*) &out, EpsilonRemover::EPSILON_REMOVER); + automaton.getData().Accept((void*) &out, EpsilonRemoverIncomming::EPSILON_REMOVER_INCOMMING); automaton::Automaton res = std::move(*out); delete out; return res; } -void EpsilonRemover::Visit(void* data, const automaton::EpsilonNFA& automaton) const { +void EpsilonRemoverIncomming::Visit(void* data, const automaton::EpsilonNFA& automaton) const { automaton::Automaton* & out = *((automaton::Automaton**) data); out = new automaton::Automaton(this->remove(automaton)); } -void EpsilonRemover::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const { +void EpsilonRemoverIncomming::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const { automaton::Automaton* & out = *((automaton::Automaton**) data); out = new automaton::Automaton(this->remove(automaton)); } -void EpsilonRemover::Visit(void* data, const automaton::NFA& automaton) const { +void EpsilonRemoverIncomming::Visit(void* data, const automaton::NFA& automaton) const { automaton::Automaton* & out = *((automaton::Automaton**) data); out = new automaton::Automaton(this->remove(automaton)); } -void EpsilonRemover::Visit(void* data, const automaton::DFA& automaton) const { +void EpsilonRemoverIncomming::Visit(void* data, const automaton::DFA& automaton) const { automaton::Automaton* & out = *((automaton::Automaton**) data); out = new automaton::Automaton(this->remove(automaton)); } -void EpsilonRemover::Visit(void*, const automaton::ExtendedNFA& ) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::ExtendedNFA& ) const { throw exception::AlibException("Unsupported automaton type ExtendedNFA"); } -void EpsilonRemover::Visit(void*, const automaton::CompactNFA& ) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::CompactNFA& ) const { throw exception::AlibException("Unsupported automaton type CompactNFA"); } -void EpsilonRemover::Visit(void*, const automaton::DPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::DPDA&) const { throw exception::AlibException("Unsupported automaton type DPDA"); } -void EpsilonRemover::Visit(void*, const automaton::SinglePopDPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::SinglePopDPDA&) const { throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); } -void EpsilonRemover::Visit(void*, const automaton::InputDrivenNPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::InputDrivenNPDA&) const { throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); } -void EpsilonRemover::Visit(void*, const automaton::VisiblyPushdownDPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::VisiblyPushdownDPDA&) const { throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA"); } -void EpsilonRemover::Visit(void*, const automaton::VisiblyPushdownNPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::VisiblyPushdownNPDA&) const { throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); } -void EpsilonRemover::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const { throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA"); } -void EpsilonRemover::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const { throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA"); } -void EpsilonRemover::Visit(void*, const automaton::NPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::NPDA&) const { throw exception::AlibException("Unsupported automaton type NPDA"); } -void EpsilonRemover::Visit(void*, const automaton::SinglePopNPDA&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::SinglePopNPDA&) const { throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); } -void EpsilonRemover::Visit(void*, const automaton::OneTapeDTM&) const { +void EpsilonRemoverIncomming::Visit(void*, const automaton::OneTapeDTM&) const { throw exception::AlibException("Unsupported automaton type OneTapeDTM"); } -const EpsilonRemover EpsilonRemover::EPSILON_REMOVER; +const EpsilonRemoverIncomming EpsilonRemoverIncomming::EPSILON_REMOVER_INCOMMING; } /* namespace simplify */ diff --git a/alib2algo/src/automaton/simplify/EpsilonRemover.h b/alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.h similarity index 84% rename from alib2algo/src/automaton/simplify/EpsilonRemover.h rename to alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.h index b7a336ed0fa191960e2cac5584b5b98f98dd518d..d61f976551edb5691476e34c65dbfff52d9d8a20 100644 --- a/alib2algo/src/automaton/simplify/EpsilonRemover.h +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverIncomming.h @@ -1,12 +1,12 @@ /* - * EpsilonRemover.h + * EpsilonRemoverIncomming.h * - * Created on: 16. 1. 2014 - * Author: Tomas Pecka + * Created on: 24. 11. 2014 + * Author: Jan Travnicek */ -#ifndef EPSILON_REMOVER_H_ -#define EPSILON_REMOVER_H_ +#ifndef EPSILON_REMOVER_INCOMMING_H_ +#define EPSILON_REMOVER_INCOMMING_H_ #include <map> #include <algorithm> @@ -23,7 +23,7 @@ namespace automaton { namespace simplify { -class EpsilonRemover : public automaton::VisitableAutomatonBase::const_visitor_type { +class EpsilonRemoverIncomming : public automaton::VisitableAutomatonBase::const_visitor_type { public: static automaton::Automaton remove( const automaton::Automaton & automaton ); @@ -53,11 +53,11 @@ private: void Visit(void*, const automaton::SinglePopNPDA& automaton) const; void Visit(void*, const automaton::OneTapeDTM& automaton) const; - static const EpsilonRemover EPSILON_REMOVER; + static const EpsilonRemoverIncomming EPSILON_REMOVER_INCOMMING; }; } /* namespace simplify */ } /* namespace automaton */ -#endif /* EPSILON_REMOVER_H_ */ +#endif /* EPSILON_REMOVER_INCOMMING_H_ */ diff --git a/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.cpp b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..888552a0fd240f462e409767ed8c018f66a92f01 --- /dev/null +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.cpp @@ -0,0 +1,151 @@ +/* + * EpsilonRemoverOutgoing.cpp + * + * Created on: 16. 1. 2014 + * Author: Tomas Pecka + */ + +#include "EpsilonRemoverOutgoing.h" + +#include "../properties/EpsilonClosure.h" + +namespace automaton { + +namespace simplify { + +automaton::DFA EpsilonRemoverOutgoing::remove(const automaton::DFA& origFSM) +{ + return origFSM; +} + +automaton::MultiInitialStateNFA EpsilonRemoverOutgoing::remove(const automaton::MultiInitialStateNFA& origFSM) +{ + return origFSM; +} + +automaton::NFA EpsilonRemoverOutgoing::remove(const automaton::NFA& origFSM) +{ + return origFSM; +} + +automaton::MultiInitialStateNFA EpsilonRemoverOutgoing::remove( const automaton::EpsilonNFA & origFSM ) { + automaton::MultiInitialStateNFA fsm; + + for( const auto & state : origFSM.getStates() ) + fsm.addState( state ); + + for( const auto & state : origFSM.getFinalStates() ) + fsm.addFinalState( state ); + + for( const auto & symbol : origFSM.getInputAlphabet() ) + fsm.addInputSymbol( symbol ); + + /** + * Step 1 from Melichar 2.41 + */ + for( const auto & middle : origFSM.getStates( ) ) { + const std::set<automaton::State> middleClosure = automaton::properties::EpsilonClosure::epsilonClosure( origFSM, middle ); + for( const auto & symbol : origFSM.getInputAlphabet() ) { + for( const auto& transition : origFSM.getTransitions( ) ) { + if(transition.second.find(middle) == transition.second.end()) continue; + if(transition.first.second != symbol) continue; + + for( const auto & to : middleClosure ) + fsm.addTransition(transition.first.first, symbol, to ); + } + } + } + + /** + * Step 2 from Melichar 2.41 + */ + const std::set<automaton::State> cl = automaton::properties::EpsilonClosure::epsilonClosure( origFSM, origFSM.getInitialState() ); + for( const auto & q : cl ) + { + fsm.addInitialState( q ); + } + + return fsm; +} + +automaton::Automaton EpsilonRemoverOutgoing::remove(const automaton::Automaton& automaton) { + automaton::Automaton* out = NULL; + automaton.getData().Accept((void*) &out, EpsilonRemoverOutgoing::EPSILON_REMOVER_OUTGOING); + automaton::Automaton res = std::move(*out); + delete out; + return res; +} + +void EpsilonRemoverOutgoing::Visit(void* data, const automaton::EpsilonNFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->remove(automaton)); +} + +void EpsilonRemoverOutgoing::Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->remove(automaton)); +} + +void EpsilonRemoverOutgoing::Visit(void* data, const automaton::NFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->remove(automaton)); +} + +void EpsilonRemoverOutgoing::Visit(void* data, const automaton::DFA& automaton) const { + automaton::Automaton* & out = *((automaton::Automaton**) data); + out = new automaton::Automaton(this->remove(automaton)); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::ExtendedNFA& ) const { + throw exception::AlibException("Unsupported automaton type ExtendedNFA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::CompactNFA& ) const { + throw exception::AlibException("Unsupported automaton type CompactNFA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::DPDA&) const { + throw exception::AlibException("Unsupported automaton type DPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::SinglePopDPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::InputDrivenNPDA&) const { + throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::VisiblyPushdownDPDA&) const { + throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::VisiblyPushdownNPDA&) const { + throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const { + throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const { + throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::NPDA&) const { + throw exception::AlibException("Unsupported automaton type NPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::SinglePopNPDA&) const { + throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); +} + +void EpsilonRemoverOutgoing::Visit(void*, const automaton::OneTapeDTM&) const { + throw exception::AlibException("Unsupported automaton type OneTapeDTM"); +} + +const EpsilonRemoverOutgoing EpsilonRemoverOutgoing::EPSILON_REMOVER_OUTGOING; + +} /* namespace simplify */ + +} /* namespace automaton */ diff --git a/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h new file mode 100644 index 0000000000000000000000000000000000000000..190c22288714ecf4454be4358c27d2d75b042579 --- /dev/null +++ b/alib2algo/src/automaton/simplify/EpsilonRemoverOutgoing.h @@ -0,0 +1,63 @@ +/* + * EpsilonRemoverOutgoing.h + * + * Created on: 16. 1. 2014 + * Author: Tomas Pecka + */ + +#ifndef EPSILON_REMOVER_OUTGOING_H_ +#define EPSILON_REMOVER_OUTGOING_H_ + +#include <map> +#include <algorithm> + +#include <automaton/Automaton.h> + +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/MultiInitialStateNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> +#include <exception/AlibException.h> + +namespace automaton { + +namespace simplify { + +class EpsilonRemoverOutgoing : public automaton::VisitableAutomatonBase::const_visitor_type { +public: + static automaton::Automaton remove( const automaton::Automaton & automaton ); + + /** + * Computes epsilon closure of a state in epsilon nonfree automaton + */ + static automaton::MultiInitialStateNFA remove( const automaton::EpsilonNFA & fsm ); + static automaton::MultiInitialStateNFA remove( const automaton::MultiInitialStateNFA & fsm ); + static automaton::NFA remove( const automaton::NFA & fsm ); + static automaton::DFA remove( const automaton::DFA & fsm ); + +private: + 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; + void Visit(void*, const automaton::DPDA& automaton) const; + void Visit(void*, const automaton::SinglePopDPDA& automaton) const; + void Visit(void*, const automaton::InputDrivenNPDA& automaton) const; + void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const; + void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const; + void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const; + void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const; + void Visit(void*, const automaton::NPDA& automaton) const; + void Visit(void*, const automaton::SinglePopNPDA& automaton) const; + void Visit(void*, const automaton::OneTapeDTM& automaton) const; + + static const EpsilonRemoverOutgoing EPSILON_REMOVER_OUTGOING; +}; + +} /* namespace simplify */ + +} /* namespace automaton */ + +#endif /* EPSILON_REMOVER_OUTGOING_H_ */ diff --git a/alib2algo/test-src/playTest.cpp b/alib2algo/test-src/playTest.cpp index 82c3c242baab48d1d7af6a09cd14b94ac0e26b27..a85a4a2a9da9d11c7c94c978bf38a89c3420ed4b 100644 --- a/alib2algo/test-src/playTest.cpp +++ b/alib2algo/test-src/playTest.cpp @@ -9,7 +9,7 @@ #include "automaton/simplify/Minimize.h" #include "automaton/simplify/Normalize.h" #include "automaton/simplify/Trim.h" -#include "automaton/simplify/EpsilonRemover.h" +#include "automaton/simplify/EpsilonRemoverIncomming.h" #define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) @@ -38,7 +38,7 @@ automaton::NFA playTest::randomNFA(void) const automaton::DFA playTest::mDFA(const automaton::NFA& automaton) const { - automaton::NFA nfa = automaton::simplify::EpsilonRemover::remove(automaton); + automaton::NFA nfa = automaton::simplify::EpsilonRemoverIncomming::remove(automaton); nfa = automaton::simplify::Trim::trim(nfa); automaton::DFA dfa = automaton::determinize::Determinize::determinize(nfa); dfa = automaton::simplify::Trim::trim(dfa); diff --git a/alib2algo/test-src/regexp/toAutomaton/re2faTest.cpp b/alib2algo/test-src/regexp/toAutomaton/re2faTest.cpp index d02597094105a569b0e960ce5d3ef3e6d190fa89..f02d812edb1b9e027f41216b4d8bbb9e995b83fe 100644 --- a/alib2algo/test-src/regexp/toAutomaton/re2faTest.cpp +++ b/alib2algo/test-src/regexp/toAutomaton/re2faTest.cpp @@ -8,7 +8,7 @@ #include "automaton/determinize/Determinize.h" #include "automaton/simplify/Minimize.h" #include "automaton/simplify/Normalize.h" -#include "automaton/simplify/EpsilonRemover.h" +#include "automaton/simplify/EpsilonRemoverOutgoing.h" #include "regexp/unbounded/UnboundedRegExp.h" #include "regexp/RegExpFromStringParser.h" @@ -37,8 +37,8 @@ void re2faTest::testThompson() { automaton::Automaton enfa2 = regexp::convert::ToAutomatonThompson::convert(regexp2); - automaton::Automaton nfa1 = automaton::simplify::EpsilonRemover::remove(enfa1); - automaton::Automaton nfa2 = automaton::simplify::EpsilonRemover::remove(enfa2); + automaton::Automaton nfa1 = automaton::simplify::EpsilonRemoverOutgoing::remove(enfa1); + automaton::Automaton nfa2 = automaton::simplify::EpsilonRemoverOutgoing::remove(enfa2); automaton::Automaton dfa1 = automaton::determinize::Determinize::determinize(nfa1); automaton::Automaton dfa2 = automaton::determinize::Determinize::determinize(nfa2); diff --git a/tests.aconversion.sh b/tests.aconversion.sh index e543c48fdeee3f5141f9867db3fdbcc36e906320..c779f6f97af54d1f0184bef02500826561aededd 100755 --- a/tests.aconversion.sh +++ b/tests.aconversion.sh @@ -56,7 +56,7 @@ function generateNFA { # $1 = command for conversion. Output of such command must be (eps-)NFA !! # $2 = automaton function runTest2 { - MDFA="./aepsilon2 | ./atrim2 | ./adeterminize2 | ./atrim2 | ./aminimize2 | ./anormalize2 --labels automaton" + MDFA="./aepsilon2 | ./adeterminize2 | ./atrim2 | ./aminimize2 | ./anormalize2 --labels automaton" TMPNFA="nfa.xml" echo "$2" > $TMPNFA