diff --git a/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp b/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp index 996f203d03bfdbc45b5dc9a9814db4a2d4e25975..3837b8ac91e454bb686d76cbade7bd40e1a0dcc8 100644 --- a/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp +++ b/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp @@ -121,6 +121,24 @@ grammar::EpsilonFreeCFG LeftRecursionRemover::remove(const grammar::EpsilonFreeC return step; } +grammar::EpsilonFreeCFG LeftRecursionRemover::remove(const grammar::CNF& origGrammar) { + EpsilonFreeCFG tmp(origGrammar.getInitialSymbol()); + tmp.setTerminalAlphabet(origGrammar.getTerminalAlphabet()); + tmp.setNonterminalAlphabet(origGrammar.getNonterminalAlphabet()); + tmp.setGeneratesEpsilon(origGrammar.getGeneratesEpsilon()); + for(const auto& rule : origGrammar.getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<alphabet::Symbol>()) { + tmp.addRule(rule.first, {rhs.get<alphabet::Symbol>()}); + } else { + const auto& rhsPair = rhs.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); + tmp.addRule(rule.first, {rhsPair.first, rhsPair.second}); + } + } + } + return remove(tmp); +} + grammar::GNF LeftRecursionRemover::remove(const grammar::GNF& origGrammar) { return origGrammar; } @@ -182,8 +200,9 @@ void LeftRecursionRemover::Visit(void* data, const grammar::EpsilonFreeCFG& gram out = new Grammar(std::move(this->remove(grammar))); } -void LeftRecursionRemover::Visit(void*, const grammar::CNF&) const { - throw exception::AlibException("Unsupported grammar type CNF"); +void LeftRecursionRemover::Visit(void* data, const grammar::CNF& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); } void LeftRecursionRemover::Visit(void* data, const grammar::GNF& grammar) const { diff --git a/alib2algo/src/grammar/simplify/LeftRecursionRemover.h b/alib2algo/src/grammar/simplify/LeftRecursionRemover.h index d6a08689c7b3085e3bb2c7b76ef586b7adcda488..f4877c9bb6a177adab8b9f358fbbce7ffb396ae8 100644 --- a/alib2algo/src/grammar/simplify/LeftRecursionRemover.h +++ b/alib2algo/src/grammar/simplify/LeftRecursionRemover.h @@ -33,6 +33,7 @@ public: static grammar::Grammar remove( const grammar::Grammar & grammar ); static grammar::EpsilonFreeCFG remove( const grammar::EpsilonFreeCFG & grammar ); + static grammar::EpsilonFreeCFG remove( const grammar::CNF & grammar ); static grammar::GNF remove( const grammar::GNF & grammar ); static grammar::RightRG remove( const grammar::RightRG & grammar ); static grammar::RightLG remove( const grammar::RightLG & grammar ); diff --git a/alib2algo/src/grammar/simplify/ToGNF.cpp b/alib2algo/src/grammar/simplify/ToGNF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..774d7d8ab6f1c4c11bc3d1ae3302da97849f36b3 --- /dev/null +++ b/alib2algo/src/grammar/simplify/ToGNF.cpp @@ -0,0 +1,214 @@ +/* + * ToGNF.cpp + * + * Created on: 24. 11. 2014 + * Author: Jan Travnicek + */ + +#include "ToGNF.h" + +#include "EpsilonRemover.h" +#include "SimpleRulesRemover.h" +#include "LeftRecursionRemover.h" +#include "../convert/ToGrammarRightRG.h" +#include "alphabet/LabeledSymbol.h" +#include "alphabet/SymbolPairSymbol.h" + +#include <factory/StringDataFactory.hpp> + +namespace grammar { + +namespace simplify { + +grammar::EpsilonFreeCFG assignNonterminals(const grammar::EpsilonFreeCFG& origGrammar) { + grammar::EpsilonFreeCFG res(origGrammar.getInitialSymbol()); + res.setNonterminalAlphabet(origGrammar.getNonterminalAlphabet()); + res.setTerminalAlphabet(origGrammar.getTerminalAlphabet()); + res.setGeneratesEpsilon(origGrammar.getGeneratesEpsilon()); + + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : origGrammar.getRules()) { + for(const std::vector<alphabet::Symbol>& singleRHS : rule.second) { + if(res.getTerminalAlphabet().count(singleRHS[0])) { //do not substitute terminals + res.addRule(rule.first, singleRHS); + continue; + } + const alphabet::Symbol& secondLHS = singleRHS[0]; + if(origGrammar.getRules().find(secondLHS) == origGrammar.getRules().end()) { //is there any right hand side to substitue with? + res.addRule(rule.first, singleRHS); + continue; + } + + for(const std::vector<alphabet::Symbol>& secondSingleRHS : origGrammar.getRules().find(secondLHS)->second) { // do the substitution + std::vector<alphabet::Symbol> newRHS(secondSingleRHS); + newRHS.insert(newRHS.end(), singleRHS.begin() + 1, singleRHS.end()); + res.addRule(rule.first, newRHS); + } + } + } + return res; +} + +grammar::GNF convertInternal( const grammar::EpsilonFreeCFG & origGrammar ) { + grammar::EpsilonFreeCFG step(origGrammar); + while(true) { + grammar::EpsilonFreeCFG nextStep = assignNonterminals(step); + + if(step == nextStep) break; + step = std::move(nextStep); + } + + grammar::GNF res(step.getInitialSymbol()); + res.setTerminalAlphabet(step.getTerminalAlphabet()); + res.setNonterminalAlphabet(step.getNonterminalAlphabet()); + res.setGeneratesEpsilon(step.getGeneratesEpsilon()); + std::map<alphabet::Symbol, alphabet::Symbol> terminalToPrimed; + for(const alphabet::Symbol& terminal : step.getTerminalAlphabet()) { + alphabet::Symbol primed = alphabet::createUniqueSymbol(terminal, res.getTerminalAlphabet(), res.getNonterminalAlphabet()); + terminalToPrimed.insert(std::make_pair(terminal, primed)); + res.addNonterminalSymbol(primed); + res.addRule(primed, std::make_pair(terminal, std::vector<alphabet::Symbol> {})); + } + for(const auto& rule : step.getRules()) { + for(const auto& rhs : rule.second) { + std::vector<alphabet::Symbol> convertedNonterminals; + bool first = true; + for(const alphabet::Symbol& rhsSymbol : rhs) { + if(first) { + first = false; + continue; + } + + if(res.getNonterminalAlphabet().count(rhsSymbol)) + convertedNonterminals.push_back(rhsSymbol); + else + convertedNonterminals.push_back(terminalToPrimed.find(rhsSymbol)->second); + } + res.addRule(rule.first, std::make_pair(rhs[0], convertedNonterminals)); + } + } + return res; +} + + + +grammar::GNF ToGNF::convert(const grammar::CFG& origGrammar) +{ + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::LeftRecursionRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)))); +} + +grammar::GNF ToGNF::convert(const grammar::EpsilonFreeCFG& origGrammar) +{ + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::LeftRecursionRemover::remove(origGrammar))); +} + +grammar::GNF ToGNF::convert(const grammar::CNF& origGrammar) +{ + return convertInternal(grammar::simplify::LeftRecursionRemover::remove(origGrammar)); +} + +grammar::GNF ToGNF::convert(const grammar::GNF& origGrammar) +{ + return origGrammar; +} + +grammar::GNF ToGNF::convert(const grammar::LG& origGrammar) +{ + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::LeftRecursionRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)))); +} + +grammar::GNF ToGNF::convert(const grammar::LeftLG& origGrammar) +{ + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::LeftRecursionRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)))); +} + +grammar::RightRG ToGNF::convert(const grammar::LeftRG& origGrammar) +{ + return convert::ToGrammarRightRG::convert(origGrammar); +} + +grammar::GNF ToGNF::convert(const grammar::RightLG& origGrammar) +{ + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::LeftRecursionRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar)))); +} + +grammar::RightRG ToGNF::convert(const grammar::RightRG& origGrammar) +{ + return origGrammar; +} + + + +grammar::Grammar ToGNF::convert(const grammar::Grammar& grammar) { + grammar::Grammar* out = NULL; + grammar.getData().Accept((void*) &out, ToGNF::TO_GNF); + grammar::Grammar res = std::move(*out); + delete out; + return res; +} + +void ToGNF::Visit(void* data, const grammar::LeftLG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::LeftRG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::RightLG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::RightRG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::LG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::CFG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::EpsilonFreeCFG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::CNF& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void* data, const grammar::GNF& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->convert(grammar))); +} + +void ToGNF::Visit(void*, const grammar::CSG&) const { + throw exception::AlibException("Unsupported grammar type CSG"); +} + +void ToGNF::Visit(void*, const grammar::NonContractingGrammar&) const { + throw exception::AlibException("Unsupported grammar type NonConctractingGrammar"); +} + +void ToGNF::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); +} + +void ToGNF::Visit(void*, const grammar::UnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +} + +const ToGNF ToGNF::TO_GNF; + +} /* namespace simplify */ + +} /* namespace grammar */ diff --git a/alib2algo/src/grammar/simplify/ToGNF.h b/alib2algo/src/grammar/simplify/ToGNF.h new file mode 100644 index 0000000000000000000000000000000000000000..87d9f30a2015df7972701e51591c3a01dbd8e2c8 --- /dev/null +++ b/alib2algo/src/grammar/simplify/ToGNF.h @@ -0,0 +1,67 @@ +/* + * ToGNF.h + * + * Created on: 24. 11. 2014 + * Author: Jan Travnicek + */ + +#ifndef TO_GNF_H_ +#define TO_GNF_H_ + +#include <map> +#include <algorithm> + +#include <grammar/Grammar.h> + +#include <grammar/ContextFree/CFG.h> +#include <grammar/ContextFree/EpsilonFreeCFG.h> +#include <grammar/ContextFree/GNF.h> +#include <grammar/ContextFree/GNF.h> +#include <grammar/ContextFree/LG.h> +#include <grammar/Regular/LeftLG.h> +#include <grammar/Regular/LeftRG.h> +#include <grammar/Regular/RightLG.h> +#include <grammar/Regular/RightRG.h> +#include <exception/AlibException.h> + +namespace grammar { + +namespace simplify { + +class ToGNF : public grammar::VisitableGrammarBase::const_visitor_type { +public: + static grammar::Grammar convert( const grammar::Grammar & grammar ); + + static grammar::GNF convert( const grammar::CFG & grammar ); + static grammar::GNF convert( const grammar::EpsilonFreeCFG & grammar ); + static grammar::GNF convert( const grammar::CNF & grammar ); + static grammar::GNF convert( const grammar::GNF & grammar ); + static grammar::GNF convert( const grammar::LG & grammar ); + static grammar::GNF convert( const grammar::LeftLG & grammar ); + static grammar::RightRG convert( const grammar::LeftRG & grammar ); + static grammar::GNF convert( const grammar::RightLG & grammar ); + static grammar::RightRG convert( const grammar::RightRG & grammar ); + +private: + void Visit(void*, const grammar::LeftLG& grammar) const; + void Visit(void*, const grammar::LeftRG& grammar) const; + void Visit(void*, const grammar::RightLG& grammar) const; + void Visit(void*, const grammar::RightRG& grammar) const; + void Visit(void*, const grammar::LG& grammar) const; + void Visit(void*, const grammar::CFG& grammar) const; + void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; + void Visit(void*, const grammar::CNF& grammar) const; + void Visit(void*, const grammar::GNF& grammar) const; + void Visit(void*, const grammar::CSG& grammar) const; + void Visit(void*, const grammar::NonContractingGrammar& grammar) const; + void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; + void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; + + static const ToGNF TO_GNF; +}; + +} /* namespace simplify */ + +} /* namespace grammar */ + +#endif /* TO_GNF_H_ */ diff --git a/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.cpp b/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7f68578965ebfbe0a3a6c97ce943d10458eb2a6 --- /dev/null +++ b/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.cpp @@ -0,0 +1,173 @@ +#include "GrammarToGNFTest.h" + +#include "grammar/simplify/ToGNF.h" +#include "grammar/generate/GenerateUpToLength.h" + +#include "grammar/ContextFree/GNF.h" +#include "grammar/ContextFree/EpsilonFreeCFG.h" + +#include <factory/StringDataFactory.hpp> + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( GrammarToGNFTest ); + +void GrammarToGNFTest::setUp() { +} + +void GrammarToGNFTest::tearDown() { +} + +void GrammarToGNFTest::testRemoveToGNFRules1() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + alphabet::Symbol D = alphabet::symbolFrom("D"); + + alphabet::Symbol a = alphabet::symbolFrom("a"); + alphabet::Symbol b = alphabet::symbolFrom("b"); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C, D}); + grammar1.setTerminalAlphabet({a, b}); + + alphabet::Symbol aprimed = createUniqueSymbol(a, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol bprimed = createUniqueSymbol(b, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + grammar::GNF grammar2 = grammar::simplify::ToGNF::convert(grammar1); + + grammar::GNF grammar3(S); + grammar3.setNonterminalAlphabet({S, A, B, C, D, aprimed, bprimed}); + grammar3.setTerminalAlphabet({a, b}); + grammar3.addRule(aprimed, std::make_pair(a, std::vector<alphabet::Symbol>{})); + grammar3.addRule(bprimed, std::make_pair(b, std::vector<alphabet::Symbol>{})); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarToGNFTest::testRemoveToGNFRules2() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + alphabet::Symbol D = alphabet::symbolFrom("D"); + + alphabet::Symbol a = alphabet::symbolFrom("a"); + alphabet::Symbol b = alphabet::symbolFrom("b"); + alphabet::Symbol c = alphabet::symbolFrom("c"); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C, D}); + grammar1.setTerminalAlphabet({a, b, c}); + grammar1.addRule(S, {A}); + grammar1.addRule(A, {A, a}); + grammar1.addRule(A, {A, b}); + grammar1.addRule(A, {c}); + + alphabet::Symbol Aprimed = createUniqueSymbol(A, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol aprimed = createUniqueSymbol(a, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol bprimed = createUniqueSymbol(b, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol cprimed = createUniqueSymbol(c, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar1)) << std::endl; + + grammar::GNF grammar2 = grammar::simplify::ToGNF::convert(grammar1); + + grammar::GNF grammar3(S); + grammar3.setNonterminalAlphabet({S, A, Aprimed, B, C, D, aprimed, bprimed, cprimed}); + grammar3.setTerminalAlphabet({a, b, c}); + grammar3.addRule(S, std::make_pair(c, std::vector<alphabet::Symbol>{Aprimed})); + grammar3.addRule(S, std::make_pair(c, std::vector<alphabet::Symbol>{})); + grammar3.addRule(A, std::make_pair(c, std::vector<alphabet::Symbol>{Aprimed})); + grammar3.addRule(A, std::make_pair(c, std::vector<alphabet::Symbol>{})); + grammar3.addRule(Aprimed, std::make_pair(a, std::vector<alphabet::Symbol>{Aprimed})); + grammar3.addRule(Aprimed, std::make_pair(a, std::vector<alphabet::Symbol>{})); + grammar3.addRule(Aprimed, std::make_pair(b, std::vector<alphabet::Symbol>{Aprimed})); + grammar3.addRule(Aprimed, std::make_pair(b, std::vector<alphabet::Symbol>{})); + grammar3.addRule(aprimed, std::make_pair(a, std::vector<alphabet::Symbol>{})); + grammar3.addRule(bprimed, std::make_pair(b, std::vector<alphabet::Symbol>{})); + grammar3.addRule(cprimed, std::make_pair(c, std::vector<alphabet::Symbol>{})); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarToGNFTest::testRemoveToGNFRules3() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + + alphabet::Symbol a = alphabet::symbolFrom("a"); + alphabet::Symbol b = alphabet::symbolFrom("b"); + alphabet::Symbol c = alphabet::symbolFrom("c"); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C}); + grammar1.setTerminalAlphabet({a, b, c}); + grammar1.addRule(S, {A}); + grammar1.addRule(A, {B, a}); + grammar1.addRule(B, {A, b}); + grammar1.addRule(A, {c}); + + alphabet::Symbol Bprimed = createUniqueSymbol(B, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol aprimed = createUniqueSymbol(a, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol bprimed = createUniqueSymbol(b, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol cprimed = createUniqueSymbol(c, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar1)) << std::endl; + + grammar::GNF grammar2 = grammar::simplify::ToGNF::convert(grammar1); + + grammar::GNF grammar3(S); + grammar3.setNonterminalAlphabet({S, A, B, Bprimed, C, aprimed, bprimed, cprimed}); + grammar3.setTerminalAlphabet({a, b, c}); + grammar3.addRule(S, std::make_pair(c, std::vector<alphabet::Symbol>{})); + grammar3.addRule(S, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed, Bprimed, aprimed})); + grammar3.addRule(S, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed, aprimed})); + grammar3.addRule(A, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed, aprimed})); + grammar3.addRule(A, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed, Bprimed, aprimed})); + grammar3.addRule(A, std::make_pair(c, std::vector<alphabet::Symbol>{})); + grammar3.addRule(B, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed})); + grammar3.addRule(B, std::make_pair(c, std::vector<alphabet::Symbol>{bprimed, Bprimed})); + grammar3.addRule(Bprimed, std::make_pair(a, std::vector<alphabet::Symbol>{bprimed, Bprimed})); + grammar3.addRule(Bprimed, std::make_pair(a, std::vector<alphabet::Symbol>{bprimed})); + grammar3.addRule(aprimed, std::make_pair(a, std::vector<alphabet::Symbol>{})); + grammar3.addRule(bprimed, std::make_pair(b, std::vector<alphabet::Symbol>{})); + grammar3.addRule(cprimed, std::make_pair(c, std::vector<alphabet::Symbol>{})); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarToGNFTest::testRemoveToGNFRules4() { + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + + alphabet::Symbol a = alphabet::symbolFrom("a"); + alphabet::Symbol b = alphabet::symbolFrom("b"); + + grammar::EpsilonFreeCFG grammar1(A); + grammar1.setNonterminalAlphabet({A, B, C}); + grammar1.setTerminalAlphabet({a, b}); + grammar1.addRule(A, {B, C}); + grammar1.addRule(A, {a}); + grammar1.addRule(B, {C, A}); + grammar1.addRule(B, {A, b}); + grammar1.addRule(C, {A, B}); + grammar1.addRule(C, {C, C}); + grammar1.addRule(C, {a}); + + grammar::GNF grammar2 = grammar::simplify::ToGNF::convert(grammar1); + + CPPUNIT_ASSERT(grammar::generate::GenerateUpToLength::generate(grammar1, 7) == grammar::generate::GenerateUpToLength::generate(grammar2, 7)); +} diff --git a/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.h b/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.h new file mode 100644 index 0000000000000000000000000000000000000000..d47c6f65374c3c0e0d5c7dadb6c3d7efd3952f14 --- /dev/null +++ b/alib2algo/test-src/grammar/simplify/GrammarToGNFTest.h @@ -0,0 +1,25 @@ +#ifndef GRAMMAR_TO_GNF_TEST_H_ +#define GRAMMAR_TO_GNF_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class GrammarToGNFTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( GrammarToGNFTest ); + CPPUNIT_TEST( testRemoveToGNFRules1 ); + CPPUNIT_TEST( testRemoveToGNFRules2 ); + CPPUNIT_TEST( testRemoveToGNFRules3 ); + CPPUNIT_TEST( testRemoveToGNFRules4 ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testRemoveToGNFRules1(); + void testRemoveToGNFRules2(); + void testRemoveToGNFRules3(); + void testRemoveToGNFRules4(); +}; + +#endif /* GRAMMAR_TO_GNF_TEST_H_ */