From fc93de29a680c16636e7e7dd67516ad936b16f00 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Thu, 20 Sep 2018 14:40:57 +0200 Subject: [PATCH] proper template of to CNF conversion algorithm --- alib2algo/src/grammar/simplify/ToCNF.cpp | 155 +----------- alib2algo/src/grammar/simplify/ToCNF.h | 221 +++++++++++++++--- .../grammar/simplify/GrammarToCNFTest.cpp | 113 +++++---- 3 files changed, 245 insertions(+), 244 deletions(-) diff --git a/alib2algo/src/grammar/simplify/ToCNF.cpp b/alib2algo/src/grammar/simplify/ToCNF.cpp index a82015413e..cc3496e996 100644 --- a/alib2algo/src/grammar/simplify/ToCNF.cpp +++ b/alib2algo/src/grammar/simplify/ToCNF.cpp @@ -6,160 +6,21 @@ */ #include "ToCNF.h" - -#include "EpsilonRemover.h" -#include "SimpleRulesRemover.h" -#include <common/DefaultSymbolsPairType.h> -#include <exception/CommonException.h> #include <registration/AlgoRegistration.hpp> -#include <grammar/RawRules.h> -#include <grammar/AddRawRule.h> -#include <object/ObjectFactory.h> - namespace grammar { namespace simplify { -void splitRule ( const DefaultSymbolType & lhs, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rhs, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > & result ) { //After templating the CNF make rhs const reference - switch ( rhs.size ( ) ) { - case 2: { - result.addRule ( lhs, ext::make_pair ( std::move ( rhs [ 0 ] ), std::move ( rhs [ 1 ] ) ) ); - break; - } - case 3: { - ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > right ( std::make_move_iterator ( std::next ( rhs.begin ( ) ) ), std::make_move_iterator ( rhs.end ( ) ) ); - DefaultSymbolType second = object::ObjectFactory::make ( right ); - if ( result.addNonterminalSymbol ( second ) ) - splitRule ( second, std::move ( right ), result ); - - result.addRule ( lhs, ext::make_pair ( std::move ( rhs [ 0 ] ), std::move ( second ) ) ); - break; - } - default: { - ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > left; - for ( unsigned i = 0; i < rhs.size ( ) / 2; ++ i ) - left.push_back ( std::move ( rhs [ i ] ) ); - - DefaultSymbolType first = object::ObjectFactory::make ( left ); - if ( result.addNonterminalSymbol ( first ) ) - splitRule ( first, std::move ( left ), result ); - - ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > right; - for ( unsigned i = rhs.size ( ) / 2; i < rhs.size ( ); ++ i ) - right.push_back ( std::move ( rhs [ i ] ) ); - - DefaultSymbolType second = object::ObjectFactory::make ( right ); - if ( result.addNonterminalSymbol ( second ) ) - splitRule ( second, std::move ( right ), result ); - - result.addRule ( lhs, ext::make_pair ( std::move ( first ), std::move ( second ) ) ); - } - } -} - -template<class T> -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convertInternal( const T & origGrammar ) { - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > result ( origGrammar.getInitialSymbol ( ) ); - - for ( const DefaultSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) - result.addNonterminalSymbol ( nonterminal ); - - result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); - - ext::map < DefaultSymbolType, DefaultSymbolType > terminalToShadowNonterminal; - for ( const DefaultSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { - DefaultSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); - terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) ); - result.addNonterminalSymbol ( shadowSymbol ); - result.addRule ( std::move ( shadowSymbol ), symbol ); - } - - for ( const auto & rules : origGrammar.getRules ( ) ) { - for ( const ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > & rhs : rules.second ) { - if ( rhs.size ( ) == 1 ) { - result.addRule ( rules.first, rhs [ 0 ].get < DefaultSymbolType > ( ) ); - } else { - ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rawRule; - for ( const ext::variant < DefaultSymbolType, DefaultSymbolType > & symbol : rhs ) { - if ( origGrammar.getTerminalAlphabet ( ).count ( symbol ) ) - rawRule.push_back ( terminalToShadowNonterminal.at ( symbol.get < DefaultSymbolType > ( ) ) ); - else - rawRule.push_back ( symbol ); - } - - splitRule ( rules.first, std::move ( rawRule ), result ); - } - } - } - - result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) ); - - return result; -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::CFG < > & origGrammar) { - return convert(grammar::simplify::EpsilonRemover::remove(origGrammar)); -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::EpsilonFreeCFG < > & origGrammar) { - return convertInternal(grammar::simplify::SimpleRulesRemover::remove(origGrammar)); -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert ( const grammar::GNF < > & origGrammar ) { - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > result ( origGrammar.getInitialSymbol ( ) ); - - for ( const DefaultSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) - result.addNonterminalSymbol ( nonterminal ); - - result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); - - ext::map < DefaultSymbolType, DefaultSymbolType > terminalToShadowNonterminal; - for ( const DefaultSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { - DefaultSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); - terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) ); - result.addNonterminalSymbol ( shadowSymbol ); - result.addRule ( std::move ( shadowSymbol ), symbol ); - } - - for ( const auto & rules : origGrammar.getRules ( ) ) { - for ( const ext::pair < DefaultSymbolType, ext::vector < DefaultSymbolType > > & rhs : rules.second ) { - if ( rhs.second.size ( ) == 0 ) - result.addRule ( rules.first, rhs.first ); - else { - ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > rawRule { terminalToShadowNonterminal.at ( rhs.first ) }; - rawRule.insert ( rawRule.end ( ), rhs.second.begin ( ), rhs.second.end ( ) ); - splitRule ( rules.first, std::move ( rawRule ), result ); - } - } - } - - result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) ); - - return result; -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::LG < > & origGrammar) { - return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::LeftLG< > & origGrammar) { - return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); -} - -grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > ToCNF::convert(const grammar::RightLG < > & origGrammar) { - return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); -} - -auto ToCNFCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::CFG < > & > ( ToCNF::convert ); -auto ToCNFEpsilonFreeCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::EpsilonFreeCFG < > & > ( ToCNF::convert ); +auto ToCNFCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::CFG < > & > ( ToCNF::convert ); +auto ToCNFEpsilonFreeCFG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::EpsilonFreeCFG < > & > ( ToCNF::convert ); auto ToCNFCNF = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::CNF < > & > ( ToCNF::convert ); -auto ToCNFGNF = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::GNF < > & > ( ToCNF::convert ); -auto ToCNFLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LG < > & > ( ToCNF::convert ); -auto ToCNFLeftLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LeftLG < > & > ( ToCNF::convert ); -auto ToCNFLeftRG = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::LeftRG < > & > ( ToCNF::convert ); -auto ToCNFRightLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::RightLG < > & > ( ToCNF::convert ); -auto ToCNFRightRG = registration::AbstractRegister < ToCNF, grammar::CNF < >, const grammar::RightRG < > & > ( ToCNF::convert ); +auto ToCNFGNF = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::GNF < > & > ( ToCNF::convert ); +auto ToCNFLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::LG < > & > ( ToCNF::convert ); +auto ToCNFLeftLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::LeftLG < > & > ( ToCNF::convert ); +auto ToCNFLeftRG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::LeftRG < > & > ( ToCNF::convert ); +auto ToCNFRightLG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > >, const grammar::RightLG < > & > ( ToCNF::convert ); +auto ToCNFRightRG = registration::AbstractRegister < ToCNF, grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > >, const grammar::RightRG < > & > ( ToCNF::convert ); } /* namespace simplify */ diff --git a/alib2algo/src/grammar/simplify/ToCNF.h b/alib2algo/src/grammar/simplify/ToCNF.h index 1b58eeba81..5e233c6a58 100644 --- a/alib2algo/src/grammar/simplify/ToCNF.h +++ b/alib2algo/src/grammar/simplify/ToCNF.h @@ -8,6 +8,7 @@ #ifndef TO_CNF_H_ #define TO_CNF_H_ +#include <grammar/Grammar.h> #include <grammar/ContextFree/CFG.h> #include <grammar/ContextFree/EpsilonFreeCFG.h> #include <grammar/ContextFree/CNF.h> @@ -20,60 +21,71 @@ #include <common/createUnique.hpp> +#include "EpsilonRemover.h" +#include "SimpleRulesRemover.h" +#include <exception/CommonException.h> + namespace grammar { namespace simplify { class ToCNF { public: - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::CFG < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::EpsilonFreeCFG < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::GNF < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar ); - template < class SymbolType > - static grammar::CNF < SymbolType > convert( const grammar::CNF < SymbolType > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, NonterminalSymbolType > convert( const grammar::CNF < TerminalSymbolType, NonterminalSymbolType > & grammar ); - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::LG < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::LeftLG < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::LeftLG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - template < class SymbolType > - static grammar::CNF < SymbolType > convert( const grammar::LeftRG < SymbolType > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > convert( const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - static grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > convert( const grammar::RightLG < > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convert( const grammar::RightLG < TerminalSymbolType, NonterminalSymbolType > & grammar ); - template < class SymbolType > - static grammar::CNF < SymbolType > convert( const grammar::RightRG < SymbolType > & grammar ); + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > convert( const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar ); }; -template < class SymbolType > -grammar::CNF < SymbolType > ToCNF::convert(const grammar::CNF < SymbolType > & origGrammar) { +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, NonterminalSymbolType > ToCNF::convert(const grammar::CNF < TerminalSymbolType, NonterminalSymbolType > & origGrammar) { return origGrammar; } -template < class SymbolType > -grammar::CNF < SymbolType > ToCNF::convert ( const grammar::LeftRG < SymbolType > & origGrammar ) { - grammar::CNF < SymbolType > result ( origGrammar.getInitialSymbol ( ) ); +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > ToCNF::convert ( const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) { + grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > result ( origGrammar.getInitialSymbol ( ) ); - result.setNonterminalAlphabet ( origGrammar.getNonterminalAlphabet ( ) ); + for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) + result.addNonterminalSymbol ( nonterminal ); result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); - ext::map < SymbolType, SymbolType > terminalToShadowNonterminal; - for ( const SymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { - SymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); + ext::map < TerminalSymbolType, TerminalSymbolType > terminalToShadowNonterminal; + for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { + TerminalSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) ); result.addNonterminalSymbol ( shadowSymbol ); result.addRule ( std::move ( shadowSymbol ), symbol ); } - for ( const std::pair < SymbolType, ext::set < ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > > > & rules : origGrammar.getRules ( ) ) { - for ( const ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > & rhs : rules.second ) { - if ( rhs.template is < SymbolType > ( ) ) { - result.addRule ( rules.first, rhs ); + for ( const std::pair < NonterminalSymbolType, ext::set < ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, TerminalSymbolType > > > > & rules : origGrammar.getRules ( ) ) { + for ( const ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, TerminalSymbolType > > & rhs : rules.second ) { + if ( rhs.template is < TerminalSymbolType > ( ) ) { + result.addRule ( rules.first, rhs.template get < TerminalSymbolType > ( ) ); } else { - const ext::pair < SymbolType, SymbolType > & rhsPair = rhs.template get < ext::pair < SymbolType, SymbolType > > ( ); + const ext::pair < NonterminalSymbolType, TerminalSymbolType > & rhsPair = rhs.template get < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( ); result.addRule ( rules.first, ext::make_pair ( rhsPair.first, terminalToShadowNonterminal.at ( rhsPair.second ) ) ); } } @@ -84,27 +96,28 @@ grammar::CNF < SymbolType > ToCNF::convert ( const grammar::LeftRG < SymbolType return result; } -template < class SymbolType > -grammar::CNF < SymbolType > ToCNF::convert ( const grammar::RightRG < SymbolType > & origGrammar ) { - grammar::CNF < SymbolType > result ( origGrammar.getInitialSymbol ( ) ); +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > ToCNF::convert ( const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) { + grammar::CNF < TerminalSymbolType, ext::variant < TerminalSymbolType, NonterminalSymbolType > > result ( origGrammar.getInitialSymbol ( ) ); - result.setNonterminalAlphabet ( origGrammar.getNonterminalAlphabet ( ) ); + for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) + result.addNonterminalSymbol ( nonterminal ); result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); - ext::map < SymbolType, SymbolType > terminalToShadowNonterminal; - for ( const SymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { - SymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); + ext::map < TerminalSymbolType, TerminalSymbolType > terminalToShadowNonterminal; + for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { + TerminalSymbolType shadowSymbol = common::createUnique ( symbol, result.getTerminalAlphabet ( ), result.getNonterminalAlphabet ( ) ); terminalToShadowNonterminal.insert ( std::make_pair ( symbol, shadowSymbol ) ); result.addNonterminalSymbol ( shadowSymbol ); result.addRule ( std::move ( shadowSymbol ), symbol ); } - for ( const std::pair < SymbolType, ext::set < ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > > > & rules : origGrammar.getRules ( ) ) { - for ( const ext::variant < SymbolType, ext::pair < SymbolType, SymbolType > > & rhs : rules.second ) { - if ( rhs.template is < SymbolType > ( ) ) { - result.addRule ( rules.first, rhs ); + for ( const std::pair < NonterminalSymbolType, ext::set < ext::variant < TerminalSymbolType, ext::pair < TerminalSymbolType, NonterminalSymbolType > > > > & rules : origGrammar.getRules ( ) ) { + for ( const ext::variant < TerminalSymbolType, ext::pair < TerminalSymbolType, NonterminalSymbolType > > & rhs : rules.second ) { + if ( rhs.template is < TerminalSymbolType > ( ) ) { + result.addRule ( rules.first, rhs.template get < TerminalSymbolType > ( ) ); } else { - const ext::pair < SymbolType, SymbolType > & rhsPair = rhs.template get < ext::pair < SymbolType, SymbolType > > ( ); + const ext::pair < TerminalSymbolType, NonterminalSymbolType > & rhsPair = rhs.template get < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( ); result.addRule ( rules.first, ext::make_pair ( terminalToShadowNonterminal.at ( rhsPair.first ), rhsPair.second ) ); } } @@ -115,6 +128,138 @@ grammar::CNF < SymbolType > ToCNF::convert ( const grammar::RightRG < SymbolType return result; } +template < class TerminalSymbolType, class NonterminalSymbolType > +void splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > lhs, const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs, grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > & result ) { + switch ( rhs.size ( ) ) { + case 2: { + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left { rhs [ 0 ] }; + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right { rhs [ 1 ] }; + result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) ); + break; + } + case 3: { + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left { rhs [ 0 ] }; + + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right ( std::next ( rhs.begin ( ) ), rhs.end ( ) ); + if ( result.addNonterminalSymbol ( right ) ) + splitRule ( right, right, result ); + + result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) ); + break; + } + default: { + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > left; + for ( unsigned i = 0; i < rhs.size ( ) / 2; ++ i ) + left.push_back ( rhs [ i ] ); + + if ( result.addNonterminalSymbol ( left ) ) + splitRule ( left, left, result ); + + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > right; + for ( unsigned i = rhs.size ( ) / 2; i < rhs.size ( ); ++ i ) + right.push_back ( rhs [ i ] ); + + if ( result.addNonterminalSymbol ( right ) ) + splitRule ( right, right, result ); + + result.addRule ( std::move ( lhs ), ext::make_pair ( std::move ( left ), std::move ( right ) ) ); + } + } +} + +template < class T, class TerminalSymbolType = typename grammar::TerminalSymbolTypeOfGrammar < T >, class NonterminalSymbolType = typename grammar::NonterminalSymbolTypeOfGrammar < T > > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > convertInternal( const T & origGrammar ) { + grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > result ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { origGrammar.getInitialSymbol ( ) } ); + + for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) + result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { nonterminal } ); + + result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); + + for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { + result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol } ); + result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, symbol ); + } + + for ( const auto & rules : origGrammar.getRules ( ) ) { + for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : rules.second ) { + if ( rhs.size ( ) == 1 ) { + result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, rhs [ 0 ].template get < TerminalSymbolType > ( ) ); + } else { + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > rawRule; + for ( const ext::variant < TerminalSymbolType, NonterminalSymbolType > & symbol : rhs ) { + if ( origGrammar.getTerminalAlphabet ( ).count ( symbol ) ) + rawRule.push_back ( symbol.template get < TerminalSymbolType > ( ) ); + else + rawRule.push_back ( symbol ); + } + + splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, std::move ( rawRule ), result ); + } + } + } + + result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) ); + + return result; +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) { + return convert(grammar::simplify::EpsilonRemover::remove(origGrammar)); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) { + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(origGrammar)); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert ( const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & origGrammar ) { + grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > result ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { origGrammar.getInitialSymbol ( ) } ); + + for ( const NonterminalSymbolType & nonterminal : origGrammar.getNonterminalAlphabet ( ) ) + result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { nonterminal } ); + + result.setTerminalAlphabet ( origGrammar.getTerminalAlphabet ( ) ); + + for ( const TerminalSymbolType & symbol : origGrammar.getTerminalAlphabet ( ) ) { + result.addNonterminalSymbol ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol } ); + result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, symbol ); + } + + for ( const auto & rules : origGrammar.getRules ( ) ) { + for ( const ext::pair < TerminalSymbolType, ext::vector < NonterminalSymbolType > > & rhs : rules.second ) { + if ( rhs.second.size ( ) == 0 ) + result.addRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, rhs.first ); + else { + ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > rawRule { rhs.first }; + rawRule.insert ( rawRule.end ( ), rhs.second.begin ( ), rhs.second.end ( ) ); + splitRule ( ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { rules.first }, std::move ( rawRule ), result ); + } + } + } + + result.setGeneratesEpsilon ( origGrammar.getGeneratesEpsilon ( ) ); + + return result; +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) { + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::LeftLG< TerminalSymbolType, NonterminalSymbolType > & origGrammar) { + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CNF < TerminalSymbolType, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > ToCNF::convert(const grammar::RightLG < TerminalSymbolType, NonterminalSymbolType > & origGrammar) { + return convertInternal(grammar::simplify::SimpleRulesRemover::remove(grammar::simplify::EpsilonRemover::remove(origGrammar))); +} + } /* namespace simplify */ } /* namespace grammar */ diff --git a/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp b/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp index fa54a8ace0..adb748a320 100644 --- a/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp +++ b/alib2algo/test-src/grammar/simplify/GrammarToCNFTest.cpp @@ -21,29 +21,26 @@ void GrammarToCNFTest::tearDown() { } void GrammarToCNFTest::testToCNFRules1() { - DefaultSymbolType S = DefaultSymbolType("S"); - DefaultSymbolType A = DefaultSymbolType("A"); - DefaultSymbolType B = DefaultSymbolType("B"); - DefaultSymbolType C = DefaultSymbolType("C"); - DefaultSymbolType D = DefaultSymbolType("D"); + std::string S = "S"; + std::string A = "A"; + std::string B = "B"; + std::string C = "C"; + std::string D = "D"; - DefaultSymbolType a = DefaultSymbolType("a"); - DefaultSymbolType b = DefaultSymbolType("b"); + char a = 'a'; + char b = 'b'; - DefaultSymbolType aP = DefaultSymbolType("a'"); - DefaultSymbolType bP = DefaultSymbolType("b'"); - - grammar::CFG < > grammar1(S); + grammar::CFG < char, std::string > grammar1 ( S ); grammar1.setNonterminalAlphabet({S, A, B, C, D}); grammar1.setTerminalAlphabet({a, b}); - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar2 = grammar::simplify::ToCNF::convert(grammar1); + grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar2 = grammar::simplify::ToCNF::convert ( grammar1 ); - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar3(S); - grammar3.setNonterminalAlphabet({S, A, B, C, D, aP, bP}); + grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar3 ( ext::vector < ext::variant < char, std::string > > { S } ); + grammar3.setNonterminalAlphabet({{S}, {A}, {B}, {C}, {D}, {a}, {b}}); grammar3.setTerminalAlphabet({a, b}); - grammar3.addRule(aP, a); - grammar3.addRule(bP, b); + grammar3.addRule ( ext::vector < ext::variant < char, std::string > > { a }, a); + grammar3.addRule ( ext::vector < ext::variant < char, std::string > > { b }, b); std::cout << grammar2 << std::endl; std::cout << grammar3 << std::endl; @@ -52,54 +49,52 @@ void GrammarToCNFTest::testToCNFRules1() { } void GrammarToCNFTest::testToCNFRules2() { - DefaultSymbolType S = DefaultSymbolType("S"); - DefaultSymbolType X = DefaultSymbolType("X"); - DefaultSymbolType Y = DefaultSymbolType("Y"); + std::string S = "S"; + std::string X = "X"; + std::string Y = "Y"; - DefaultSymbolType a = DefaultSymbolType("a"); - DefaultSymbolType b = DefaultSymbolType("b"); - DefaultSymbolType c = DefaultSymbolType("c"); + char a = 'a'; + char b = 'b'; + char c = 'c'; - grammar::CFG < > grammar1(S); + grammar::CFG < char, std::string > grammar1 ( S ); grammar1.setNonterminalAlphabet({S, X, Y}); grammar1.setTerminalAlphabet({a, b, c}); - grammar1.addRule({S}, {a, X, b, X}); - grammar1.addRule({X}, {a, Y}); - grammar1.addRule({X}, {b, Y}); - grammar1.addRule({X}, {}); - grammar1.addRule({Y}, {X}); - grammar1.addRule({Y}, {c}); - - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar2 = grammar::simplify::ToCNF::convert(grammar1); - DefaultSymbolType aP = DefaultSymbolType("a'"); - DefaultSymbolType bP = DefaultSymbolType("b'"); - DefaultSymbolType cP = DefaultSymbolType("c'"); - DefaultSymbolType Xb = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { X, bP } ); - DefaultSymbolType aX = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { aP, X } ); - DefaultSymbolType bX = object::ObjectFactory::make ( ext::vector < ext::variant < DefaultSymbolType, DefaultSymbolType > > { bP, X } ); - - grammar::CNF < DefaultSymbolType, ext::variant < DefaultSymbolType, DefaultSymbolType > > grammar3(S); - grammar3.setNonterminalAlphabet({S, X, Y, aP, bP, cP, Xb, aX, bX}); + grammar1.addRule(S, {a, X, b, X}); + grammar1.addRule(X, {a, Y}); + grammar1.addRule(X, {b, Y}); + grammar1.addRule(X, {}); + grammar1.addRule(Y, {X}); + grammar1.addRule(Y, {c}); + + grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar2 = grammar::simplify::ToCNF::convert(grammar1); + + ext::vector < ext::variant < char, std::string > > Xb { X, b }; + ext::vector < ext::variant < char, std::string > > aX { a, X }; + ext::vector < ext::variant < char, std::string > > bX { b, X }; + + grammar::CNF < char, ext::vector < ext::variant < char, std::string > > > grammar3 ( ext::vector < ext::variant < char, std::string > > { S } ); + grammar3.setNonterminalAlphabet({{S}, {X}, {Y}, {a}, {b}, {c}, {Xb}, {aX}, {bX}}); grammar3.setTerminalAlphabet({a, b, c}); - grammar3.addRule(S, ext::make_pair(aX, bX)); - grammar3.addRule(S, ext::make_pair(aP, bX)); - grammar3.addRule(S, ext::make_pair(aP, Xb)); - grammar3.addRule(S, ext::make_pair(aP, bP)); - grammar3.addRule(aX, ext::make_pair(aP, X)); - grammar3.addRule(bX, ext::make_pair(bP, X)); - grammar3.addRule(Xb, ext::make_pair(X, bP)); - grammar3.addRule(X, ext::make_pair(aP, Y)); - grammar3.addRule(X, ext::make_pair(bP, Y)); - grammar3.addRule(X, a); - grammar3.addRule(X, b); - grammar3.addRule(Y, ext::make_pair(aP, Y)); - grammar3.addRule(Y, ext::make_pair(bP, Y)); - grammar3.addRule(Y, a); - grammar3.addRule(Y, b); - grammar3.addRule(Y, c); - grammar3.addRule(aP, a); - grammar3.addRule(bP, b); - grammar3.addRule(cP, c); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { aX }, ext::vector < ext::variant < char, std::string > > { bX } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { bX } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Xb } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { S }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { b } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { aX }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { X } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { bX }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { X } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Xb }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { X }, ext::vector < ext::variant < char, std::string > > { b } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Y } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { Y } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, a); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { X }, b); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { a }, ext::vector < ext::variant < char, std::string > > { Y } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, ext::make_pair ( ext::vector < ext::variant < char, std::string > > { b }, ext::vector < ext::variant < char, std::string > > { Y } ) ); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, a); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, b); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { Y }, c); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { a }, a); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { b }, b); + grammar3.addRule( ext::vector < ext::variant < char, std::string > > { c }, c); std::cout << grammar2 << std::endl; std::cout << grammar3 << std::endl; -- GitLab