From 9853e073405f93b621fed1140722bd3aff20c618 Mon Sep 17 00:00:00 2001 From: Tomas Pecka <peckato1@fit.cvut.cz> Date: Sat, 22 Nov 2014 19:31:38 +0100 Subject: [PATCH] algo: concat, union+concat tests --- alangop2/src/alangop.cpp | 5 + .../transform/AutomataConcatenation.cpp | 207 ++++++++++++++++++ .../transform/AutomataConcatenation.h | 59 +++++ .../AutomataIntersectionCartesianProduct.cpp | 2 - .../AutomataUnionCartesianProduct.cpp | 38 +++- .../transform/AutomataConcatenationTest.cpp | 93 ++++++++ .../transform/AutomataConcatenationTest.h | 19 ++ .../automaton/transform/AutomataUnionTest.cpp | 76 +++++++ .../automaton/transform/AutomataUnionTest.h | 19 ++ 9 files changed, 506 insertions(+), 12 deletions(-) create mode 100644 alib2algo/src/automaton/transform/AutomataConcatenation.cpp create mode 100644 alib2algo/src/automaton/transform/AutomataConcatenation.h create mode 100644 alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp create mode 100644 alib2algo/test-src/automaton/transform/AutomataConcatenationTest.h create mode 100644 alib2algo/test-src/automaton/transform/AutomataUnionTest.cpp create mode 100644 alib2algo/test-src/automaton/transform/AutomataUnionTest.h diff --git a/alangop2/src/alangop.cpp b/alangop2/src/alangop.cpp index c80ef1e072..3eeb3c533b 100644 --- a/alangop2/src/alangop.cpp +++ b/alangop2/src/alangop.cpp @@ -13,6 +13,7 @@ #include <automaton/Automaton.h> #include <automaton/transform/AutomataConcatenationEpsilonTransition.h> +#include <automaton/transform/AutomataConcatenation.h> #include <automaton/transform/AutomataIntersectionCartesianProduct.h> #include <automaton/transform/AutomataUnionCartesianProduct.h> #include <automaton/transform/AutomataUnionEpsilonTransition.h> @@ -26,6 +27,7 @@ int main(int argc, char* argv[]) { allowed.push_back("unionEpsilon"); allowed.push_back("unionCartesian"); allowed.push_back("concatenationEpsilon"); + allowed.push_back("concatenation"); allowed.push_back("intersectionCartesian"); TCLAP::ValuesConstraint<std::string> allowedVals( allowed ); @@ -72,6 +74,9 @@ int main(int argc, char* argv[]) { } else if( algorithm.getValue() == "concatenationEpsilon") { alib::DataFactory::toStdout(automaton::transform::AutomataConcatenationEpsilonTransition::concatenation(automaton1, automaton2));; return 0; + } else if( algorithm.getValue() == "concatenation") { + alib::DataFactory::toStdout(automaton::transform::AutomataConcatenation::concatenation(automaton1, automaton2));; + return 0; } else if( algorithm.getValue() == "intersectionCartesian") { alib::DataFactory::toStdout(automaton::transform::AutomataIntersectionCartesianProduct::intersection(automaton1, automaton2));; return 0; diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.cpp b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp new file mode 100644 index 0000000000..c8e3cdbec3 --- /dev/null +++ b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp @@ -0,0 +1,207 @@ +/* + * AutomataConcatenation.cpp + * + * Created on: 20. 11. 2014 + * Author: Tomas Pecka + */ + +#include "AutomataConcatenation.h" +#include <exception/AlibException.h> +#include <label/Label.h> +#include "common/PairLabel.h" + +#define AUTOMATON_FIRST (label::labelFrom(1)) +#define AUTOMATON_SECOND (label::labelFrom(2)) + +namespace automaton +{ + +namespace transform +{ + +automaton::Automaton AutomataConcatenation::concatenation(const automaton::Automaton& first, const automaton::Automaton& second) +{ + AutomatonBase* out; + Accept((void*) &out, first.getData(), second.getData(), AutomataConcatenation::AUTOMATA_CONCATENATION); + automaton::Automaton res(*out); + delete out; + return res; +} + +automaton::NFA AutomataConcatenation::concatenation(const automaton::NFA& first, const automaton::NFA& second) +{ + automaton::State q01q02(pairLabel(first.getInitialState(), second.getInitialState())); + automaton::NFA res(pairLabel(AUTOMATON_FIRST, first.getInitialState())); + + for(const auto& q : first.getStates()) + res.addState(pairLabel(AUTOMATON_FIRST, q)); + for(const auto& q : second.getStates()) + res.addState(pairLabel(AUTOMATON_SECOND, q)); + res.addState(q01q02); + + for(const auto& symbol : first.getInputAlphabet()) + res.addInputSymbol(symbol); + for(const auto& symbol : second.getInputAlphabet()) + res.addInputSymbol(symbol); + + if(first.getFinalStates().count(first.getInitialState()) > 0) + res.setInitialState(q01q02); + + for(const auto& t : first.getTransitions()) + { + for(const auto& q : t.second) + { + res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_FIRST, q)); + + if(first.getFinalStates().count(q) > 0) + res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_SECOND, second.getInitialState())); + } + } + for(const auto& t : second.getTransitions()) + for(const auto& q : t.second) + res.addTransition(pairLabel(AUTOMATON_SECOND, t.first.first), t.first.second, pairLabel(AUTOMATON_SECOND, q)); + + for(const auto& t : first.getTransitionsFromState(first.getInitialState())) + for(const auto& q : t.second) + res.addTransition(q01q02, t.first.second, pairLabel(AUTOMATON_FIRST, q)); + for(const auto& t : second.getTransitionsFromState(second.getInitialState())) + for(const auto& q : t.second) + res.addTransition(q01q02, t.first.second, pairLabel(AUTOMATON_SECOND, q)); + + for(const auto& q : second.getFinalStates()) + res.addFinalState(pairLabel(AUTOMATON_SECOND, q)); + if(first.getFinalStates().count(first.getInitialState()) > 0) + res.addFinalState(q01q02); + + return res; +} + +automaton::NFA AutomataConcatenation::concatenation(const automaton::DFA& first, const automaton::DFA& second) +{ + automaton::State q01q02(pairLabel(first.getInitialState(), second.getInitialState())); + automaton::NFA res(pairLabel(AUTOMATON_FIRST, first.getInitialState())); + + for(const auto& q : first.getStates()) + res.addState(pairLabel(AUTOMATON_FIRST, q)); + for(const auto& q : second.getStates()) + res.addState(pairLabel(AUTOMATON_SECOND, q)); + res.addState(q01q02); + + for(const auto& symbol : first.getInputAlphabet()) + res.addInputSymbol(symbol); + for(const auto& symbol : second.getInputAlphabet()) + res.addInputSymbol(symbol); + + if(first.getFinalStates().count(first.getInitialState()) > 0) + res.setInitialState(q01q02); + + for(const auto& t : first.getTransitions()) + { + res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_FIRST, t.second)); + + if(first.getFinalStates().count(t.second) > 0) + res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_SECOND, second.getInitialState())); + } + for(const auto& t : second.getTransitions()) + res.addTransition(pairLabel(AUTOMATON_SECOND, t.first.first), t.first.second, pairLabel(AUTOMATON_SECOND, t.second)); + + for(const auto& t : first.getTransitionsFromState(first.getInitialState())) + res.addTransition(q01q02, t.first.second, pairLabel(AUTOMATON_FIRST, t.second)); + for(const auto& t : second.getTransitionsFromState(second.getInitialState())) + res.addTransition(q01q02, t.first.second, pairLabel(AUTOMATON_SECOND, t.second)); + + for(const auto& q : second.getFinalStates()) + res.addFinalState(pairLabel(AUTOMATON_SECOND, q)); + if(first.getFinalStates().count(first.getInitialState()) > 0) + res.addFinalState(q01q02); + + return res; +} + +void AutomataConcatenation::Visit(void*, const automaton::EpsilonNFA&, const automaton::EpsilonNFA&) const +{ + throw exception::AlibException("Unsupported automaton type EpsilonNFA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const +{ + throw exception::AlibException("Unsupported automaton type CompactNFA"); +} + +void AutomataConcatenation::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const +{ + AutomatonBase* &ret = *(AutomatonBase**) data; + ret = std::move(AutomataConcatenation::concatenation(first, second)).plunder(); +} + +void AutomataConcatenation::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const +{ + throw exception::AlibException("Unsupported automaton type ExtendedNFA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const +{ + throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA"); +} + +void AutomataConcatenation::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const +{ + AutomatonBase* &ret = *(AutomatonBase**) data; + ret = std::move(AutomataConcatenation::concatenation(first, second)).plunder(); +} + +void AutomataConcatenation::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const +{ + throw exception::AlibException("Unsupported automaton type DPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const +{ + throw exception::AlibException("Unsupported automaton type NPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const +{ + throw exception::AlibException("Unsupported automaton type InputDrivenNPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const +{ + throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const +{ + throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const +{ + throw exception::AlibException("Unsupported automaton type SinglePopNPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const +{ + throw exception::AlibException("Unsupported automaton type SinglePopDPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const +{ + throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const +{ + throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA"); +} + +void AutomataConcatenation::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const +{ + throw exception::AlibException("Unsupported automaton type OneTapeDTM"); +} + +const AutomataConcatenation AutomataConcatenation::AUTOMATA_CONCATENATION; + +} /* namespace transform */ + +} /* namespace automaton */ diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.h b/alib2algo/src/automaton/transform/AutomataConcatenation.h new file mode 100644 index 0000000000..9ee1b5523e --- /dev/null +++ b/alib2algo/src/automaton/transform/AutomataConcatenation.h @@ -0,0 +1,59 @@ +/* + * AutomataConcatenation.h + * + * Created on: 20. 11. 2014 + * Author: Tomas Pecka + */ + +#ifndef AUTOMATA_CONCATENATION_H_ +#define AUTOMATA_CONCATENATION_H_ + +#include <automaton/Automaton.h> +#include <automaton/FSM/EpsilonNFA.h> + +namespace automaton +{ + +namespace transform +{ + +/** + * Concatenates two automata. + * - For finite automata A1, A2, we create automaton L accepting L(A1).L(A2) (Melichar, 2.78) + */ +class AutomataConcatenation : public automaton::VisitableAutomatonBase::const_promoting_visitor_type +{ +public: + static automaton::Automaton concatenation(const automaton::Automaton& first, const automaton::Automaton& second); + + static automaton::NFA concatenation(const automaton::DFA& first, const automaton::DFA& second); + static automaton::NFA concatenation(const automaton::NFA& first, const automaton::NFA& second); + +private: + void Visit(void* data, const automaton::CompactNFA& first, const automaton::CompactNFA& second) const; + void Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const; + void Visit(void* data, const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) const; + void Visit(void* data, const automaton::ExtendedNFA& first, const automaton::ExtendedNFA& second) const; + void Visit(void* data, const automaton::MultiInitialStateNFA& first, const automaton::MultiInitialStateNFA& second) const; + void Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const; + + void Visit(void* data, const automaton::DPDA& first, const automaton::DPDA& second) const; + void Visit(void* data, const automaton::NPDA& first, const automaton::NPDA& second) const; + void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& second) const; + void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& first, const automaton::RealTimeHeightDeterministicDPDA& second) const; + void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& first, const automaton::RealTimeHeightDeterministicNPDA& second) const; + void Visit(void* data, const automaton::SinglePopNPDA& first, const automaton::SinglePopNPDA& second) const; + void Visit(void* data, const automaton::SinglePopDPDA& first, const automaton::SinglePopDPDA& second) const; + void Visit(void* data, const automaton::VisiblyPushdownDPDA& first, const automaton::VisiblyPushdownDPDA& second) const; + void Visit(void* data, const automaton::VisiblyPushdownNPDA& first, const automaton::VisiblyPushdownNPDA& second) const; + + void Visit(void* data, const automaton::OneTapeDTM& first, const automaton::OneTapeDTM& second) const; + + static const AutomataConcatenation AUTOMATA_CONCATENATION; +}; + +} /* namespace transform */ + +} /* namespace automaton */ + +#endif /* AUTOMATA_CONCATENATION_H_ */ diff --git a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp index 91a92f2964..a287a18b3c 100644 --- a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp +++ b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp @@ -82,8 +82,6 @@ automaton::NFA AutomataIntersectionCartesianProduct::intersection(const automato const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first; const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second; - // std::cout << label_p << ";" << label_q << std::endl; - for(const auto& tp : first.getTransitionsFromState(automaton::State(label_p))) for(const auto& tq : second.getTransitionsFromState(automaton::State(label_q))) if(tp.first.second == tq.first.second) diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp index e5db1d4b20..2a03e1e1bf 100644 --- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp +++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp @@ -29,6 +29,9 @@ automaton::Automaton AutomataUnionCartesianProduct::unification(const automaton: automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA& first, const automaton::DFA& second) { + if(!first.isTotal() || !second.isTotal()) + throw exception::AlibException("Automata must be total to unify with cartesian product"); + automaton::State q0(pairLabel(first.getInitialState(), second.getInitialState())); automaton::DFA res(q0); @@ -49,16 +52,25 @@ automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA& for(const auto& q : second.getFinalStates()) res.addFinalState(automaton::State(pairLabel(p, q))); - for(const auto& tp : first.getTransitions()) - for(const auto& tq : second.getTransitions()) - if(tp.first.second == tq.first.second) - res.addTransition(automaton::State(pairLabel(tp.first.first, tq.first.first)), tp.first.second, automaton::State(pairLabel(tp.second, tq.second))); + for(const auto& state : res.getStates()) + { + const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first; + const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second; + + for(const auto& tp : first.getTransitionsFromState(automaton::State(label_p))) + for(const auto& tq : second.getTransitionsFromState(automaton::State(label_q))) + if(tp.first.second == tq.first.second) + res.addTransition(state, tp.first.second, automaton::State(pairLabel(tp.second, tq.second))); + } return res; } automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA& first, const automaton::NFA& second) { + if(!first.isTotal() || !second.isTotal()) + throw exception::AlibException("Automata must be total to unify with cartesian product"); + automaton::State q0(pairLabel(first.getInitialState(), second.getInitialState())); automaton::NFA res(q0); @@ -79,12 +91,18 @@ automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA& for(const auto& q : second.getFinalStates()) res.addFinalState(automaton::State(pairLabel(p, q))); - for(const auto& tp : first.getTransitions()) - for(const auto& tq : second.getTransitions()) - if(tp.first.second == tq.first.second) - for(const auto& p : tp.second) - for(const auto& q : tq.second) - res.addTransition(automaton::State(pairLabel(tp.first.first, tq.first.first)), tp.first.second, automaton::State(pairLabel(p, q))); + for(const auto& state : res.getStates()) + { + const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first; + const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second; + + for(const auto& tp : first.getTransitionsFromState(automaton::State(label_p))) + for(const auto& tq : second.getTransitionsFromState(automaton::State(label_q))) + if(tp.first.second == tq.first.second) + for(const auto& p : tp.second) + for(const auto& q : tq.second) + res.addTransition(state, tp.first.second, automaton::State(pairLabel(p, q))); + } return res; } diff --git a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp new file mode 100644 index 0000000000..70d2ef29af --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp @@ -0,0 +1,93 @@ +#include <list> +#include "AutomataConcatenationTest.h" + +#include "automaton/transform/AutomataConcatenation.h" +#include "automaton/transform/AutomataConcatenationEpsilonTransition.h" + +#include "automaton/simplify/MinimizeBrzozowski.h" +#include "automaton/simplify/Normalize.h" +#include "automaton/simplify/EpsilonRemover.h" +#include "automaton/simplify/Trim.h" +#include "automaton/simplify/Total.h" +#include "automaton/determinize/Determinize.h" + +#include <factory/DataFactory.hpp> + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( AutomataConcatenationTest ); + +void AutomataConcatenationTest::setUp() { +} + +void AutomataConcatenationTest::tearDown() { +} + +void AutomataConcatenationTest::testAutomataConcatenation() { + // based on Melichar, 2.79 + + automaton::State q1a("1"), q2a("2"), q0a("0"), q1b("1'"), q2b("2'"), q0b("0'"); + automaton::State q0102("q0102"); + alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b')); + + automaton::DFA m1(q1a); + automaton::DFA m2(q1b); + automaton::NFA m3(q1a); + + m1.setInputSymbols({a, b}); + m1.setStates({q1a, q2a, q0a}); + m1.addTransition(q1a, a, q2a); + m1.addTransition(q1a, b, q0a); + m1.addTransition(q2a, a, q2a); + m1.addTransition(q2a, b, q0a); + m1.addTransition(q0a, a, q0a); + m1.addTransition(q0a, b, q0a); + m1.addFinalState(q2a); + + m2.setInputSymbols({a, b}); + m2.setStates({q1b, q2b}); + m2.addTransition(q1b, b, q2b); + m2.addTransition(q2b, b, q2b); + m2.addFinalState(q2b); + + m3.setInputSymbols({a, b}); + m3.setStates({q1a, q1b, q2a, q2b, q0a, q0b, q0102}); + m3.addTransition(q1a, a, q2a); + m3.addTransition(q1a, a, q1b); + m3.addTransition(q1a, b, q0a); + m3.addTransition(q2a, a, q2a); + m3.addTransition(q2a, a, q1b); + m3.addTransition(q2a, b, q0a); + m3.addTransition(q0a, a, q0a); + m3.addTransition(q0a, b, q0a); + m3.addTransition(q1b, a, q0b); + m3.addTransition(q1b, b, q2b); + m3.addTransition(q2b, a, q0b); + m3.addTransition(q2b, b, q2b); + m3.addTransition(q0b, a, q0b); + m3.addTransition(q0b, b, q0b); + m3.setFinalStates({q2b}); + + auto u11 = automaton::transform::AutomataConcatenationEpsilonTransition::concatenation(automaton::Automaton(automaton::DFA(m1)), automaton::Automaton(automaton::NFA(m2))); + auto u12 = automaton::transform::AutomataConcatenationEpsilonTransition::concatenation(automaton::Automaton(automaton::DFA(m1)), automaton::Automaton(automaton::DFA(m2))); + auto u21 = automaton::transform::AutomataConcatenation::concatenation(automaton::Automaton(automaton::DFA(m1)), automaton::Automaton(automaton::NFA(m2))); + auto u22 = automaton::transform::AutomataConcatenation::concatenation(automaton::Automaton(automaton::DFA(m1)), automaton::Automaton(automaton::DFA(m2))); + + automaton::Automaton umdfa (automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(m3))))); + automaton::Automaton umdfa11(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u11))))); + automaton::Automaton umdfa12(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u12))))); + automaton::Automaton umdfa21(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u21))))); + automaton::Automaton umdfa22(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u22))))); + alib::DataFactory::toStdout(umdfa); + alib::DataFactory::toStdout(umdfa11); + alib::DataFactory::toStdout(umdfa12); + alib::DataFactory::toStdout(umdfa21); + alib::DataFactory::toStdout(umdfa22); + + + //CPPUNIT_ASSERT(umdfa11 == umdfa); + CPPUNIT_ASSERT(umdfa12 == umdfa); + //CPPUNIT_ASSERT(umdfa21 == umdfa); + CPPUNIT_ASSERT(umdfa22 == umdfa); + +} diff --git a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.h b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.h new file mode 100644 index 0000000000..aa7dbecb20 --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.h @@ -0,0 +1,19 @@ +#ifndef AUTOMATA_CONCAT_TEST_H_ +#define AUTOMATA_CONCAT_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class AutomataConcatenationTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( AutomataConcatenationTest ); + CPPUNIT_TEST( testAutomataConcatenation ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testAutomataConcatenation(); +}; + +#endif /* AUTOMATA_CONCAT_TEST_H_ */ diff --git a/alib2algo/test-src/automaton/transform/AutomataUnionTest.cpp b/alib2algo/test-src/automaton/transform/AutomataUnionTest.cpp new file mode 100644 index 0000000000..fe6d35161b --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataUnionTest.cpp @@ -0,0 +1,76 @@ +#include <list> +#include "AutomataUnionTest.h" + +#include "automaton/transform/AutomataUnionCartesianProduct.h" +#include "automaton/transform/AutomataUnionEpsilonTransition.h" +#include "automaton/simplify/MinimizeBrzozowski.h" +#include "automaton/simplify/Normalize.h" +#include "automaton/simplify/EpsilonRemover.h" +#include "automaton/simplify/Trim.h" +#include "automaton/simplify/Total.h" +#include "automaton/determinize/Determinize.h" + +#include <factory/DataFactory.hpp> + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( AutomataUnionTest ); + +void AutomataUnionTest::setUp() { +} + +void AutomataUnionTest::tearDown() { +} + +void AutomataUnionTest::testAutomataUnion() { + // based on Melichar, 2.72 + + automaton::State q1a("1"), q2a("2"), q0a("0"), q1b("1'"), q2b("2'"), q0b("0'"); + automaton::State q11("11"), q20("20"), q00("00"), q02("02"); + alphabet::Symbol a(alphabet::symbolFrom('a')), b(alphabet::symbolFrom('b')); + + automaton::DFA m1(q1a); + automaton::DFA m2(q1b); + automaton::DFA m3(q11); + + m1.setInputSymbols({a, b}); + m1.setStates({q1a, q2a, q0a}); + m1.addTransition(q1a, a, q2a); + m1.addTransition(q1a, b, q0a); + m1.addTransition(q2a, a, q2a); + m1.addTransition(q2a, b, q0a); + m1.addTransition(q0a, a, q0a); + m1.addTransition(q0a, b, q0a); + m1.addFinalState(q2a); + + m2.setInputSymbols({a, b}); + m2.setStates({q1b, q2b}); + m2.addTransition(q1b, b, q2b); + m2.addTransition(q2b, b, q2b); + m2.addFinalState(q2b); + + m3.setInputSymbols({a, b}); + m3.setStates({q11, q20, q00, q02}); + m3.addTransition(q11, a, q20); + m3.addTransition(q11, b, q02); + m3.addTransition(q20, a, q20); + m3.addTransition(q20, b, q00); + m3.addTransition(q00, a, q00); + m3.addTransition(q00, b, q00); + m3.addTransition(q02, a, q00); + m3.addTransition(q02, b, q02); + m3.setFinalStates({q20, q02}); + + auto u1 = automaton::transform::AutomataUnionEpsilonTransition::unification(automaton::Automaton(m1), automaton::Automaton(m2)); + CPPUNIT_ASSERT_THROW(automaton::transform::AutomataUnionCartesianProduct::unification(automaton::Automaton(m1), automaton::Automaton(m2)), exception::AlibException); + CPPUNIT_ASSERT_THROW(automaton::transform::AutomataUnionCartesianProduct::unification(automaton::Automaton(automaton::NFA(m1)), automaton::Automaton(m2)), exception::AlibException); + auto u2 = automaton::transform::AutomataUnionEpsilonTransition::unification(automaton::Automaton(automaton::simplify::Total::total(m1)), automaton::Automaton(automaton::simplify::Total::total(m2))); + + automaton::Automaton umdfa(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(m3))))); + automaton::Automaton umdfa1(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u1))))); + automaton::Automaton umdfa2(automaton::simplify::Normalize::normalize(automaton::simplify::Trim::trim(automaton::simplify::MinimizeBrzozowski::minimize(automaton::simplify::EpsilonRemover::remove(u2))))); + + CPPUNIT_ASSERT(umdfa1 == umdfa); + CPPUNIT_ASSERT(umdfa2 == umdfa); + +} diff --git a/alib2algo/test-src/automaton/transform/AutomataUnionTest.h b/alib2algo/test-src/automaton/transform/AutomataUnionTest.h new file mode 100644 index 0000000000..d45ef404d8 --- /dev/null +++ b/alib2algo/test-src/automaton/transform/AutomataUnionTest.h @@ -0,0 +1,19 @@ +#ifndef AUTOMATA_UNION_TEST_H_ +#define AUTOMATA_UNION_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class AutomataUnionTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( AutomataUnionTest ); + CPPUNIT_TEST( testAutomataUnion ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testAutomataUnion(); +}; + +#endif /* AUTOMATA_UNION_TEST_H_ */ -- GitLab