diff --git a/alib2algo/src/grammar/GrammarPropertiesCFG.cpp b/alib2algo/src/grammar/GrammarPropertiesCFG.cpp index 5f1c1d55c5920d0e8e0b58931dfc3a3038522551..e72f1cb33e65ebe5bfd382b40bb131b2330fd955 100644 --- a/alib2algo/src/grammar/GrammarPropertiesCFG.cpp +++ b/alib2algo/src/grammar/GrammarPropertiesCFG.cpp @@ -104,5 +104,81 @@ template std::set<alphabet::Symbol> GrammarPropertiesCFG::getUnreachableSymbols( template std::set<alphabet::Symbol> GrammarPropertiesCFG::getUnreachableSymbols( const grammar::RightLG & grammar ); template std::set<alphabet::Symbol> GrammarPropertiesCFG::getUnreachableSymbols( const grammar::RightRG & grammar ); +template<class T> +std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals(const T& grammar) { + std::deque<std::set<alphabet::Symbol>> Ni; + + Ni.push_back(std::set<alphabet::Symbol>{ }); + int i = 1; + + while(true) { + Ni.push_back(std::set<alphabet::Symbol>{ }); + for(const auto& rule : grammar.getRawRules()) { + for(const auto& rhs : rule.second) { + if(rhs.size() == 0 || std::all_of(rhs.begin(), rhs.end(), [Ni, i](const alphabet::Symbol& symb){return Ni.at(i-1).count(symb);})) { + Ni.at(i).insert(rule.first); + } + } + } + + if(Ni.at(i) == Ni.at(i-1)) + break; + + i += 1; + } + + return Ni.at(i); +} + +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::CFG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::EpsilonFreeCFG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::GNF& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::CNF& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::LG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::LeftLG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::LeftRG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::RightLG& grammar ); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNullableNonterminals( const grammar::RightRG& grammar ); + +template<class T> +std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const T& grammar, const alphabet::Symbol& nonterminal) { + if(grammar.getNonterminalAlphabet().count(nonterminal) == 0) { + throw exception::AlibException("Nonterminal symbol \"" + (std::string) nonterminal + "\" is not present in grammar."); + } + + std::deque<std::set<alphabet::Symbol>> Ni; + Ni.push_back(std::set<alphabet::Symbol>{nonterminal}); + int i = 1; + + while(true) { + Ni.push_back(Ni.at(i-1)); + for(const auto&rule : grammar.getRawRules()) { + const alphabet::Symbol& lhs = rule.first; + + for(const auto& rhs : rule.second) { + if(Ni.at(i-1).count(lhs) && rhs.size() == 1 && grammar.getNonterminalAlphabet().count(rhs.front())) { + Ni.at(i).insert(rhs.front()); + } + } + } + + if(Ni.at(i) == Ni.at(i-1)) + break; + + i += 1; + } + + return Ni.at(i); } +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::CFG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::EpsilonFreeCFG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::GNF& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::CNF& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::LG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::LeftLG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::LeftRG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::RightLG& grammar, const alphabet::Symbol& nonterminal); +template std::set<alphabet::Symbol> GrammarPropertiesCFG::getNonterminalUnitRuleCycle(const grammar::RightRG& grammar, const alphabet::Symbol& nonterminal); + +} /* namespace grammar */ diff --git a/alib2algo/src/grammar/GrammarPropertiesCFG.h b/alib2algo/src/grammar/GrammarPropertiesCFG.h index cda0bc41c66172c0cde7dfef44135aeb90be89af..4cf05c9cce7e2373c36b3b66836f887c67904e4d 100644 --- a/alib2algo/src/grammar/GrammarPropertiesCFG.h +++ b/alib2algo/src/grammar/GrammarPropertiesCFG.h @@ -5,8 +5,8 @@ * Author: Tomas Pecka */ -#ifndef GRAMMAR_PROPERTIED_CFG_H_ -#define GRAMMAR_PROPERTIED_CFG_H_ +#ifndef GRAMMAR_PROPERTIES_CFG_H_ +#define GRAMMAR_PROPERTIES_CFG_H_ #include <algorithm> #include <deque> @@ -30,12 +30,36 @@ public: static std::set<alphabet::Symbol> getProductiveNonterminals( const T & grammar ); /** - * Implements + * Implements */ template<class T> static std::set<alphabet::Symbol> getUnreachableSymbols( const T & grammar ); + + /** + * Retrieve all nullable nonterminals from grammar + * Nullable nonterminal is such nonterminal A for which holds that A ->^* \eps + * + * Source: Melichar, algorithm 2.4, step 1 + * + * @param grammar grammar + * @return set of nullable nonterminals from grammar + */ + template<class T> + static std::set<alphabet::Symbol> getNullableNonterminals(const T& grammar); + + /** + * Retrieves set N = {B : A->^* B} for given grammar and nonterminal + * + * Source: Melichar, algorithm 2.6, step 1 + * + * @param grammar grammar + * @param nonterminal nonterminal + * @return set of nonterminals for which we can be derived from giveUnitRuleCyclen nonterminals in finite number of steps + */ + template<class T> + static std::set<alphabet::Symbol> getNonterminalUnitRuleCycle(const T& grammar, const alphabet::Symbol& nonterminal); }; -} +} /* namespace grammar */ -#endif /* GRAMMAR_PROPERTIED_CFG_H_ */ +#endif /* GRAMMAR_PROPERTIES_CFG_H_ */ diff --git a/alib2algo/test-src/grammar/GrammarPropertiesTest.cpp b/alib2algo/test-src/grammar/GrammarPropertiesTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3f8019d1bd33a7ddf3f4d824adc920517dd72c0 --- /dev/null +++ b/alib2algo/test-src/grammar/GrammarPropertiesTest.cpp @@ -0,0 +1,74 @@ +#include "GrammarPropertiesTest.h" +#include <factory/DataFactory.hpp> + +#include <label/PrimitiveLabel.h> +#include <alphabet/LabeledSymbol.h> +#include <alphabet/Symbol.h> + +#include "grammar/GrammarPropertiesCFG.h" + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( GrammarPropertiesTest ); + +void GrammarPropertiesTest::setUp() { +} + +void GrammarPropertiesTest::tearDown() { +} + +void GrammarPropertiesTest::testNullable() { + alphabet::Symbol X = alphabet::symbolFrom('X'); + alphabet::Symbol Y = alphabet::symbolFrom('Y'); + alphabet::Symbol Z = alphabet::symbolFrom('Z'); + alphabet::Symbol d = alphabet::symbolFrom('d'); + + grammar::CFG grammar(X); + grammar.setTerminalAlphabet({d}); + grammar.setNonterminalAlphabet({{X, Y, Z}}); + grammar.setInitialSymbol(X); + + grammar.addRule(X, std::vector<alphabet::Symbol>{ d }); + grammar.addRule(X, std::vector<alphabet::Symbol>{ Y }); + grammar.addRule(Y, std::vector<alphabet::Symbol>{ d }); + grammar.addRule(Y, std::vector<alphabet::Symbol>{ }); + grammar.addRule(Z, std::vector<alphabet::Symbol>{ d }); + grammar.addRule(Z, std::vector<alphabet::Symbol>{ X, Y, Z }); + + std::set<alphabet::Symbol> res = {X, Y}; + CPPUNIT_ASSERT(res == grammar::GrammarPropertiesCFG::getNullableNonterminals(grammar)); +} + +void GrammarPropertiesTest::testUnitRules() { + 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'); + + grammar::LeftLG llg(S); + llg.setTerminalAlphabet({a, b}); + llg.setNonterminalAlphabet({S, A, B, C}); + llg.setInitialSymbol(S); + + llg.addRule(S, std::make_pair(A, std::vector<alphabet::Symbol>{})); + llg.addRule(S, std::make_pair(B, std::vector<alphabet::Symbol>{})); + llg.addRule(A, std::make_pair(A, std::vector<alphabet::Symbol>{a})); + llg.addRule(A, std::make_pair(B, std::vector<alphabet::Symbol>{})); + llg.addRule(A, std::make_pair(C, std::vector<alphabet::Symbol>{})); + llg.addRule(B, std::make_pair(B, std::vector<alphabet::Symbol>{b, a})); + llg.addRule(B, std::make_pair(C, std::vector<alphabet::Symbol>{b})); + llg.addRule(C, {b}); + llg.addRule(C, std::make_pair(C, std::vector<alphabet::Symbol>{a})); + + std::set<alphabet::Symbol> N_S = {S, A, B, C}; + std::set<alphabet::Symbol> N_A = {A, B, C}; + std::set<alphabet::Symbol> N_B = {B}; + std::set<alphabet::Symbol> N_C = {C}; + + CPPUNIT_ASSERT(N_S == grammar::GrammarPropertiesCFG::getNonterminalUnitRuleCycle(llg, S)); + CPPUNIT_ASSERT(N_A == grammar::GrammarPropertiesCFG::getNonterminalUnitRuleCycle(llg, A)); + CPPUNIT_ASSERT(N_B == grammar::GrammarPropertiesCFG::getNonterminalUnitRuleCycle(llg, B)); + CPPUNIT_ASSERT(N_C == grammar::GrammarPropertiesCFG::getNonterminalUnitRuleCycle(llg, C)); +} diff --git a/alib2algo/test-src/grammar/GrammarPropertiesTest.h b/alib2algo/test-src/grammar/GrammarPropertiesTest.h new file mode 100644 index 0000000000000000000000000000000000000000..8ecbb5a5baad8711c4290ddaaa936be95ed2ba68 --- /dev/null +++ b/alib2algo/test-src/grammar/GrammarPropertiesTest.h @@ -0,0 +1,21 @@ +#ifndef GRAMMAR_PROPERTIES_TEST_H_ +#define GRAMMAR_PROPERTIES_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class GrammarPropertiesTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( GrammarPropertiesTest ); + CPPUNIT_TEST( testUnitRules ); + CPPUNIT_TEST( testNullable ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testUnitRules(); + void testNullable(); +}; + +#endif /* GRAMMAR_PROPERTIES_TEST_H_ */