diff --git a/alib2algo/src/trim/automaton/TrimFSM.cpp b/alib2algo/src/trim/automaton/TrimFSM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4827fea1362618ebdaa26882476e7a0ca610bf3a --- /dev/null +++ b/alib2algo/src/trim/automaton/TrimFSM.cpp @@ -0,0 +1,225 @@ +/* + * TrimFSM.cpp + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#include "TrimFSM.h" + +#include <exception/AlibException.h> +#include <automaton/FSM/ExtendedNFA.h> +#include <automaton/FSM/CompactNFA.h> +#include <automaton/FSM/EpsilonNFA.h> +#include <automaton/FSM/NFA.h> +#include <automaton/FSM/DFA.h> + +namespace trim { + +template<class T> +T TrimFSM::removeUselessStates( const T & fsm ) { + // 1a + std::deque<std::set<automaton::State>> Qi; + Qi.push_back( std::set<automaton::State>( ) ); + Qi.at( 0 ) = fsm.getFinalStates( ); + + int i = 1; + + // 1bc + while( true ) { + Qi.push_back( Qi.at( i - 1 ) ); // copy Qi-1 into Qi + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & t : fsm.getTransitionsToState( p ) ) + Qi.at( i ).insert( t.first.first ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i = i + 1; + } + const std::set<automaton::State>& Qu = Qi.at( i ); + + // 2. + T M; + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & t : fsm.getTransitions( ) ) + for( const auto & to : t.second ) + if( /* TODO test this Qu.count(t.first.first) ) && */ Qu.count(to) ) + M.addTransition( t.first.first, t.first.second, to ); + + for( const auto & q : fsm.getInitialStates( ) ) + M.addInitialState( q ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + return M; +} + +template automaton::EpsilonNFA TrimFSM::removeUselessStates( const automaton::EpsilonNFA & fsm ); +template automaton::NFA TrimFSM::removeUselessStates( const automaton::NFA & fsm ); +template automaton::CompactNFA TrimFSM::removeUselessStates( const automaton::CompactNFA & fsm ); +template automaton::ExtendedNFA TrimFSM::removeUselessStates( const automaton::ExtendedNFA & fsm ); + +template<> +automaton::DFA TrimFSM::removeUselessStates( const automaton::DFA & fsm ) { + // 1a + std::deque<std::set<automaton::State>> Qi; + Qi.push_back( std::set<automaton::State>( ) ); + Qi.at( 0 ) = fsm.getFinalStates( ); + + int i = 1; + + // 1bc + while( true ) { + Qi.push_back( Qi.at( i - 1 ) ); // copy Qi-1 into Qi + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & t : fsm.getTransitionsToState( p ) ) + Qi.at( i ).insert( t.first.first ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i = i + 1; + } + const std::set<automaton::State>& Qu = Qi.at( i ); + + // 2. + automaton::DFA M ( fsm.getInitialState () ); + + for( const auto & q : Qu ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & t : fsm.getTransitions( ) ) + if( /* TODO test this Qu.count( t.first.first ) && */ Qu.count( t.second ) ) + M.addTransition( t.first.first, t.first.second, t.second ); + + for( const auto & q : fsm.getFinalStates( ) ) + M.addFinalState( q ); + + return M; +} + +template<class T> +T TrimFSM::removeUnreachableStates( const T & fsm ) { + // 1a + std::deque<std::set<automaton::State>> Qi; + Qi.push_back( std::set<automaton::State>( ) ); + Qi.at( 0 ) = fsm.getInitialStates( ); + + int i = 1; + + // 1bc + while( true ) { + Qi.push_back( Qi.at( i - 1 ) ); + + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & transition : fsm.getTransitionsFromState( p ) ) + Qi.at( i ).insert( transition.second.begin(), transition.second.end() ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i = i + 1; + } + + const std::set<automaton::State> Qa = Qi.at( i ); + + // 2 + T M; + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + for(const auto& to : transition.second ) + M.addTransition( transition.first.first, transition.first.second, to ); + + for( const auto & q : fsm.getInitialStates( ) ) + M.addInitialState( q ); + + std::set<automaton::State> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + return M; +} + +template automaton::EpsilonNFA TrimFSM::removeUnreachableStates( const automaton::EpsilonNFA & fsm ); +template automaton::NFA TrimFSM::removeUnreachableStates( const automaton::NFA & fsm ); +template automaton::CompactNFA TrimFSM::removeUnreachableStates( const automaton::CompactNFA & fsm ); +template automaton::ExtendedNFA TrimFSM::removeUnreachableStates( const automaton::ExtendedNFA & fsm ); + +template<> +automaton::DFA TrimFSM::removeUnreachableStates( const automaton::DFA & fsm ) { + // 1a + std::deque<std::set<automaton::State>> Qi; + Qi.push_back( std::set<automaton::State>( ) ); + Qi.at( 0 ). insert( fsm.getInitialState( ) ); + + int i = 1; + + // 1bc + while( true ) { + Qi.push_back( Qi.at( i - 1 ) ); + + for( const auto & p : Qi.at( i - 1 ) ) + for( const auto & transition : fsm.getTransitionsFromState( p ) ) + Qi.at( i ).insert( transition.second ); + + if( Qi.at( i ) == Qi.at( i - 1 ) ) + break; + + i = i + 1; + } + + const std::set<automaton::State> Qa = Qi.at( i ); + + // 2 + automaton::DFA M(fsm.getInitialState() ); + + for( const auto & q : Qa ) + M.addState( q ); + + for( const auto & a : fsm.getInputAlphabet( ) ) + M.addInputSymbol( a ); + + for( const auto & transition : fsm.getTransitions( ) ) + if( Qa.count( transition.first.first ) ) + M.addTransition( transition.first.first, transition.first.second, transition.second ); + + std::set<automaton::State> intersect; + std::set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), std::inserter( intersect, intersect.begin( ) ) ); + for( auto const & state : intersect ) + M.addFinalState( state ); + + return M; +} + +template<class T> +T TrimFSM::trim( const T & fsm ) { + return removeUnreachableStates(removeUselessStates(fsm)); +} + +template automaton::EpsilonNFA TrimFSM::trim( const automaton::EpsilonNFA & fsm ); +template automaton::NFA TrimFSM::trim( const automaton::NFA & fsm ); +template automaton::CompactNFA TrimFSM::trim( const automaton::CompactNFA & fsm ); +template automaton::ExtendedNFA TrimFSM::trim( const automaton::ExtendedNFA & fsm ); +template automaton::DFA TrimFSM::trim( const automaton::DFA & fsm ); + +} + diff --git a/alib2algo/src/trim/automaton/TrimFSM.h b/alib2algo/src/trim/automaton/TrimFSM.h new file mode 100644 index 0000000000000000000000000000000000000000..45ba49a6d1ac6b88d4f944aa57b3bf983de7a364 --- /dev/null +++ b/alib2algo/src/trim/automaton/TrimFSM.h @@ -0,0 +1,40 @@ +/* + * TrimFSM.h + * + * Created on: 23. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef TRIM_FSM_H_ +#define TRIM_FSM_H_ + +#include <algorithm> +#include <deque> +#include <set> + +namespace trim { + +class TrimFSM { +public: + /** + * Removes dead states from FSM. Melichar 2.32 + */ + template<class T> + static T removeUselessStates( const T & fsm ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + template<class T> + static T removeUnreachableStates( const T & fsm ); + + /** + * Removes dead states from FSM. Melichar 2.29 + */ + template<class T> + static T trim( const T & fsm ); +}; + +} + +#endif /* TRIM_FSM_H_ */ diff --git a/alib2algo/src/trim/grammar/TrimCFG.cpp b/alib2algo/src/trim/grammar/TrimCFG.cpp new file mode 100644 index 0000000000000000000000000000000000000000..119e96544f2e53a6e517f472ef10c8d67242e0a8 --- /dev/null +++ b/alib2algo/src/trim/grammar/TrimCFG.cpp @@ -0,0 +1,224 @@ +/* + * TrimCFG.cpp + * + * Created on: 22. 3. 2014 + * Author: Tomas Pecka + */ + +#include "TrimCFG.h" + +#include <grammar/ContextFree/CFG.h> +#include <grammar/ContextFree/EpsilonFreeCFG.h> +#include <grammar/ContextFree/GNF.h> +#include <grammar/ContextFree/CNF.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 <std/set.hpp> + +namespace trim { + +template<class T> +std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const T & grammar ) { + // 1. + std::deque<std::set<alphabet::Symbol>> Ni; + Ni.push_back( std::set<alphabet::Symbol>( ) ); + + int i = 1; + + // 2. + while( true ) { + Ni.push_back( Ni.at( i - 1 ) ); + + for( const auto & rule : grammar.getRawRules( ) ) { + for( const auto & rhs : rule.second ) { + if( std::all_of( rhs.begin( ), rhs.end( ), [ i, Ni, grammar ]( const alphabet::Symbol & symbol ) -> bool { + return Ni.at( i - 1 ) . count( symbol ) || grammar.getTerminalAlphabet( ). count( symbol ); + } ) ) + Ni.at( i ).insert( rule.first ); + } + } + + if( Ni.at( i ) == Ni.at( i - 1 ) ) + break; + + i = i + 1; + } + + // 3. + return Ni.at( i ); +} + +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::CFG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::EpsilonFreeCFG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::GNF & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::CNF & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::LG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::LeftLG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::LeftRG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::RightLG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getProductiveNonterminals( const grammar::RightRG & grammar ); + +template<class T> +bool TrimCFG::isLanguageEmpty( const T & grammar ) { + return getProductiveNonterminals( grammar ).count( grammar.getInitialSymbol( ) ); +} + +template bool TrimCFG::isLanguageEmpty( const grammar::CFG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::EpsilonFreeCFG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::GNF & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::CNF & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::LG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::LeftLG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::LeftRG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::RightLG & grammar ); +template bool TrimCFG::isLanguageEmpty( const grammar::RightRG & grammar ); + +template<class T> +std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const T & grammar ) { + // 1 + std::deque<std::set<alphabet::Symbol>> Vi; + Vi.push_back( std::set<alphabet::Symbol>( ) ); + Vi.at( 0 ).insert( grammar.getInitialSymbol( ) ); + + int i = 1; + + // 2. + while( true ) { + Vi.push_back( Vi.at( i - 1 ) ); + + for( const auto & rule : grammar.getRawRules( ) ) { + if( Vi.at( i - 1 ).count( rule.first ) ) { + for( const auto & rhs : rule.second ) { + Vi.at( i ).insert( rhs.begin( ), rhs.end( ) ); + } + } + } + + + if( Vi.at( i ) == Vi.at( i - 1 ) ) + break; + + i = i + 1; + } + + // 3. + return Vi.at( i ); +} + +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::CFG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::EpsilonFreeCFG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::GNF & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::CNF & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::LG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::LeftLG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::LeftRG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::RightLG & grammar ); +template std::set<alphabet::Symbol> TrimCFG::getUnreachableSymbols( const grammar::RightRG & grammar ); + +template<class T> +T TrimCFG::removeUnreachableSymbols( const T & grammar) { + // 1. + std::set<alphabet::Symbol> Vt = getUnreachableSymbols( grammar ); + + T ret(grammar.getInitialSymbol( ) ); + + std::set<alphabet::Symbol> newNonTerminals, newTerminals; + + set_intersection( Vt.begin( ), Vt.end( ), grammar.getNonterminalAlphabet( ).begin( ), grammar.getNonterminalAlphabet( ).end( ), std::inserter( newNonTerminals, newNonTerminals.begin( ) ) ); + for( const auto & symbol : newNonTerminals ) + ret.addNonterminalSymbol( symbol ); + + set_intersection( Vt.begin( ), Vt.end( ), grammar.getTerminalAlphabet( ).begin( ), grammar.getTerminalAlphabet( ).end( ), std::inserter( newTerminals, newTerminals.begin( ) ) ); + for( const auto & symbol : newTerminals ) + ret.addTerminalSymbol( symbol ); + + // A->\alpha: if A \in N' and \alpha in V_i*, then A->\alpha in P + for( const auto & rule : grammar.getRawRules( ) ) { + if( newNonTerminals.count( rule.first ) ) { + for( const auto& rhs : rule.second ) { + if( all_of( rhs.begin( ), rhs.end( ), [ Vt ]( alphabet::Symbol const& symb ) -> bool { + return Vt.count( symb ); + } ) ) + ret.addRawRule( rule.first, rhs ); + } + } + } + + // 2. + return ret; +} + +template grammar::CFG TrimCFG::removeUnreachableSymbols( const grammar::CFG & grammar ); +template grammar::EpsilonFreeCFG TrimCFG::removeUnreachableSymbols( const grammar::EpsilonFreeCFG & grammar ); +template grammar::GNF TrimCFG::removeUnreachableSymbols( const grammar::GNF & grammar ); +template grammar::CNF TrimCFG::removeUnreachableSymbols( const grammar::CNF & grammar ); +template grammar::LG TrimCFG::removeUnreachableSymbols( const grammar::LG & grammar ); +template grammar::LeftLG TrimCFG::removeUnreachableSymbols( const grammar::LeftLG & grammar ); +template grammar::LeftRG TrimCFG::removeUnreachableSymbols( const grammar::LeftRG & grammar ); +template grammar::RightLG TrimCFG::removeUnreachableSymbols( const grammar::RightLG & grammar ); +template grammar::RightRG TrimCFG::removeUnreachableSymbols( const grammar::RightRG & grammar ); + +template<class T> +T TrimCFG::removeUnproductiveSymbols( const T & grammar ) { + // 1. + std::set<alphabet::Symbol> Nt = getProductiveNonterminals( grammar ); + + T ret(grammar.getInitialSymbol( ) ); + + for( const auto & symbol : Nt ) + ret.addNonterminalSymbol( symbol ); + + for( const auto & symbol : grammar.getTerminalAlphabet( ) ) + ret.addTerminalSymbol( symbol ); + + const std::set<alphabet::Symbol> & terminals = ret.getTerminalAlphabet( ); + for( const auto & rule : grammar.getRawRules( ) ) { + if( Nt.count( rule.first ) ) { + for( const auto & rhs : rule.second ) { + if( all_of( rhs.begin( ), rhs.end( ), [ Nt, terminals ]( const alphabet::Symbol & symbol ) { + return Nt.count( symbol ) || terminals.count( symbol ); + } ) ) + ret.addRawRule( rule.first, rhs ); + } + } + } + + + /* if( ! G1.getNonTerminalSymbols( ) . count( grammar.getInitialSymbol( ) ) ) + throw AlibException( "Starting symbol of grammar was marked as unproductive and therefore it was removed." ); */ + + // 2. + return ret; +} + +template grammar::CFG TrimCFG::removeUnproductiveSymbols( const grammar::CFG & grammar ); +template grammar::EpsilonFreeCFG TrimCFG::removeUnproductiveSymbols( const grammar::EpsilonFreeCFG & grammar ); +template grammar::GNF TrimCFG::removeUnproductiveSymbols( const grammar::GNF & grammar ); +template grammar::CNF TrimCFG::removeUnproductiveSymbols( const grammar::CNF & grammar ); +template grammar::LG TrimCFG::removeUnproductiveSymbols( const grammar::LG & grammar ); +template grammar::LeftLG TrimCFG::removeUnproductiveSymbols( const grammar::LeftLG & grammar ); +template grammar::LeftRG TrimCFG::removeUnproductiveSymbols( const grammar::LeftRG & grammar ); +template grammar::RightLG TrimCFG::removeUnproductiveSymbols( const grammar::RightLG & grammar ); +template grammar::RightRG TrimCFG::removeUnproductiveSymbols( const grammar::RightRG & grammar ); + +template<class T> +T TrimCFG::trim( const T & grammar ) { + return removeUnreachableSymbols( removeUnproductiveSymbols( grammar ) ); +} + +template grammar::CFG TrimCFG::trim( const grammar::CFG & grammar ); +template grammar::EpsilonFreeCFG TrimCFG::trim( const grammar::EpsilonFreeCFG & grammar ); +template grammar::GNF TrimCFG::trim( const grammar::GNF & grammar ); +template grammar::CNF TrimCFG::trim( const grammar::CNF & grammar ); +template grammar::LG TrimCFG::trim( const grammar::LG & grammar ); +template grammar::LeftLG TrimCFG::trim( const grammar::LeftLG & grammar ); +template grammar::LeftRG TrimCFG::trim( const grammar::LeftRG & grammar ); +template grammar::RightLG TrimCFG::trim( const grammar::RightLG & grammar ); +template grammar::RightRG TrimCFG::trim( const grammar::RightRG & grammar ); + +} + diff --git a/alib2algo/src/trim/grammar/TrimCFG.h b/alib2algo/src/trim/grammar/TrimCFG.h new file mode 100644 index 0000000000000000000000000000000000000000..97a0c60e8ad846c4e2f625b2ed8cef94f5e0be91 --- /dev/null +++ b/alib2algo/src/trim/grammar/TrimCFG.h @@ -0,0 +1,69 @@ +/* + * TrimCFG.h + * + * Created on: 22. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef TRIM_CFG_H_ +#define TRIM_CFG_H_ + +#include <algorithm> +#include <deque> +#include <set> + +#include <exception/AlibException.h> + +#include <alphabet/Symbol.h> + +namespace trim { + +/** + * Implements algorithms from Melichar, chapter 3.3 + */ +class TrimCFG { +public: + /* + * Melichar 3.6 - decides whether L( grammar ) = \0 + * + * Severals steps implemented in method CFGTransformations::getProductiveNonTerminals(); + * @see getProductiveNonTerminals + */ + template<class T> + static bool isLanguageEmpty( const T & grammar ); + + /* + * Removes unreachable symbols - Melichar 3.9 + */ + template<class T> + static T removeUnreachableSymbols( const T & grammar ); + + /** + * Removes unproductive (or useless - terminology) symbols - Melichar 3.12 + */ + template<class T> + static T removeUnproductiveSymbols( const T & grammar ); + + /** + * Removes unproductive and useless symbols - Melichar 3.12 + */ + template<class T> + static T trim( const T & grammar ); + +private: + /** + * Implements steps 1 through 3 in Melichar 3.6 + */ + template<class T> + static std::set<alphabet::Symbol> getProductiveNonterminals( const T & grammar ); + + /** + * Implements + */ + template<class T> + static std::set<alphabet::Symbol> getUnreachableSymbols( const T & grammar ); +}; + +} + +#endif /* TRIM_CFG_H_ */ diff --git a/alib2algo/test-src/trim/trimTest.cpp b/alib2algo/test-src/trim/trimTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e416d5ea5c3b340917d346143748fb2d755acad5 --- /dev/null +++ b/alib2algo/test-src/trim/trimTest.cpp @@ -0,0 +1,69 @@ +#include <list> +#include "trimTest.h" + +#include "label/StringLabel.h" +#include "label/IntegerLabel.h" +#include "label/Label.h" +#include "alphabet/LabeledSymbol.h" + +#include "trim/automaton/TrimFSM.h" +#include "trim/grammar/TrimCFG.h" + +#include "automaton/FSM/DFA.h" +#include "grammar/Regular/RightRG.h" + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( trimTest ); + +void trimTest::setUp() { +} + +void trimTest::tearDown() { +} + +void trimTest::testTrimAutomaton() { + automaton::DFA automaton(automaton::State(label::Label(label::IntegerLabel(1)))); + + automaton.addState(automaton::State(label::Label(label::IntegerLabel(1)))); + automaton.addState(automaton::State(label::Label(label::IntegerLabel(2)))); + automaton.addState(automaton::State(label::Label(label::IntegerLabel(3)))); + automaton.addInputSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a"))))); + automaton.addInputSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b"))))); + + automaton.addTransition(automaton::State(label::Label(label::IntegerLabel(1))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), automaton::State(label::Label(label::IntegerLabel(2)))); + automaton.addTransition(automaton::State(label::Label(label::IntegerLabel(2))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), automaton::State(label::Label(label::IntegerLabel(1)))); + automaton.addTransition(automaton::State(label::Label(label::IntegerLabel(3))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), automaton::State(label::Label(label::IntegerLabel(1)))); + + automaton.addFinalState(automaton::State(label::Label(label::IntegerLabel(1)))); + + automaton::DFA trimed = trim::TrimFSM::trim(automaton); + + CPPUNIT_ASSERT(trimed.getStates().size() == 2); +} + +void trimTest::testTrimGrammar() { + grammar::RightRG rrGrammar(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1))))); + + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1))))); + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2))))); + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3))))); + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(4))))); + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(5))))); + rrGrammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(6))))); + rrGrammar.addTerminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a"))))); + rrGrammar.addTerminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b"))))); + + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2)))))); + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2)))), std::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3)))))); + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3)))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a"))))); + + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(4)))), std::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(5)))))); + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(5)))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a"))))); + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(5)))), std::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2)))))); + rrGrammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(6)))), std::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(6)))))); + + grammar::RightRG trimed = trim::TrimCFG::trim(rrGrammar); + + CPPUNIT_ASSERT(trimed.getNonterminalAlphabet().size() == 3); +} diff --git a/alib2algo/test-src/trim/trimTest.h b/alib2algo/test-src/trim/trimTest.h new file mode 100644 index 0000000000000000000000000000000000000000..b23af79d17e8e2423e455379987f8891074d5550 --- /dev/null +++ b/alib2algo/test-src/trim/trimTest.h @@ -0,0 +1,21 @@ +#ifndef TRIM_TEST_H_ +#define TRIM_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class trimTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( trimTest ); + CPPUNIT_TEST( testTrimAutomaton ); + CPPUNIT_TEST( testTrimGrammar ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testTrimAutomaton(); + void testTrimGrammar(); +}; + +#endif // TRIM_TEST_H_ diff --git a/alib2data/src/grammar/ContextFree/CFG.cpp b/alib2data/src/grammar/ContextFree/CFG.cpp index 3ffeb0635ed48661fdda158e9107908c036e28ac..6c2eca1b20e7f4b020d25950ea44dd5df32fbaf7 100644 --- a/alib2data/src/grammar/ContextFree/CFG.cpp +++ b/alib2data/src/grammar/ContextFree/CFG.cpp @@ -69,10 +69,22 @@ bool CFG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphab return rules[leftHandSide].insert(rightHandSide).second; } -const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> CFG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> & CFG::getRules() const { return rules; } +bool CFG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + return addRule(leftHandSide, rightHandSide); +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> CFG::getRawRules() const { + return rules; +} + +bool CFG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + return removeRule(leftHandSide, rightHandSide); +} + bool CFG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { return rules[leftHandSide].erase(rightHandSide); } diff --git a/alib2data/src/grammar/ContextFree/CFG.h b/alib2data/src/grammar/ContextFree/CFG.h index 069cefbeab7cab8b1e5b7d91c96df22bddc7bade..0132bb083625aba3193a85d20adc5e5f838b0230 100644 --- a/alib2data/src/grammar/ContextFree/CFG.h +++ b/alib2data/src/grammar/ContextFree/CFG.h @@ -32,10 +32,16 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/ContextFree/CNF.cpp b/alib2data/src/grammar/ContextFree/CNF.cpp index 8e94c29d3599a0207981ad5e550dc2893edc02ad..03da6a55750dd885bef1a539ad3894e66d6a1d60 100644 --- a/alib2data/src/grammar/ContextFree/CNF.cpp +++ b/alib2data/src/grammar/ContextFree/CNF.cpp @@ -93,7 +93,7 @@ bool CNF::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet return addRule(leftHandSide, rhs); } -const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> CNF::getRules() const { +const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & CNF::getRules() const { return rules; } @@ -111,6 +111,58 @@ bool CNF::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alpha return removeRule(leftHandSide, rhs); } +bool CNF::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(true); + return !res; + } else if(rightHandSide.size() == 1) { + return addRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return addRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> CNF::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<alphabet::Symbol>()) { + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhs.get<alphabet::Symbol>()); + res[rule.first].insert(tmp); + } else { + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhs.get<std::pair<alphabet::Symbol, alphabet::Symbol>>().first); + tmp.push_back(rhs.get<std::pair<alphabet::Symbol, alphabet::Symbol>>().second); + res[rule.first].insert(tmp); + } + } + } + if(getGeneratesEpsilon()) { + res[getInitialSymbol()].insert(std::vector<alphabet::Symbol> {}); + } + return res; +} + +bool CNF::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else if(rightHandSide.size() == 1) { + return removeRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return removeRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + void CNF::setGeneratesEpsilon(bool genEps) { generatesEpsilon = genEps; } diff --git a/alib2data/src/grammar/ContextFree/CNF.h b/alib2data/src/grammar/ContextFree/CNF.h index c3f33a27efd3ea0ae23deb9fe09eff850d7c74a8..cd45d106e58eeb20fe44c2760599996841247c91 100644 --- a/alib2data/src/grammar/ContextFree/CNF.h +++ b/alib2data/src/grammar/ContextFree/CNF.h @@ -36,12 +36,18 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const alphabet::Symbol& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, alphabet::Symbol>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const alphabet::Symbol& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp index 4e23cf482fb7d008c35daeaf7ec6e6ec9e9563cc..081e3bddc4bd9721bdfbb6f080260fa388b69afa 100644 --- a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp +++ b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp @@ -76,7 +76,7 @@ bool EpsilonFreeCFG::addRule(const alphabet::Symbol& leftHandSide, const std::ve } } -const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> EpsilonFreeCFG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> & EpsilonFreeCFG::getRules() const { return rules; } @@ -84,6 +84,36 @@ bool EpsilonFreeCFG::removeRule(const alphabet::Symbol& leftHandSide, const std: return rules[leftHandSide].erase(rightHandSide); } +bool EpsilonFreeCFG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(true); + return !res; + } else { + return addRule(leftHandSide, rightHandSide); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> EpsilonFreeCFG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res(getRules().begin(), getRules().end()); + if(getGeneratesEpsilon()) { + res[getInitialSymbol()].insert(std::vector<alphabet::Symbol> {}); + } + return rules; +} + +bool EpsilonFreeCFG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else { + return removeRule(leftHandSide, rightHandSide); + } +} + void EpsilonFreeCFG::setGeneratesEpsilon(bool genEps) { generatesEpsilon = genEps; } diff --git a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h index e96e89f4d2f90ac37a4cce233a91bec001eca215..ee3b55546977cee482d1ed816da1e9fcd7a1285a 100644 --- a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h +++ b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h @@ -33,10 +33,16 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/ContextFree/GNF.cpp b/alib2data/src/grammar/ContextFree/GNF.cpp index 0f96349c419ba87bcdccca0617e33bebdfe064cc..802169e44e4e24c15011649951a5e8295d844bb5 100644 --- a/alib2data/src/grammar/ContextFree/GNF.cpp +++ b/alib2data/src/grammar/ContextFree/GNF.cpp @@ -72,7 +72,7 @@ bool GNF::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet return rules[leftHandSide].insert(rightHandSide).second; } -const std::map<alphabet::Symbol, std::set<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >> > GNF::getRules() const { +const std::map<alphabet::Symbol, std::set<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >> > & GNF::getRules() const { return rules; } @@ -80,6 +80,48 @@ bool GNF::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alpha return rules[leftHandSide].erase(rightHandSide); } +bool GNF::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(true); + return !res; + } else { + alphabet::Symbol first = rightHandSide[0]; + std::vector<alphabet::Symbol> rest(rightHandSide.begin() + 1, rightHandSide.end()); + return addRule(leftHandSide, std::make_pair(first, rest)); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> GNF::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhs.first); + tmp.insert(tmp.end(), rhs.second.begin(), rhs.second.end()); + res[rule.first].insert(tmp); + } + } + if(getGeneratesEpsilon()) { + res[getInitialSymbol()].insert(std::vector<alphabet::Symbol> {}); + } + return res; +} + +bool GNF::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else { + alphabet::Symbol first = rightHandSide[0]; + std::vector<alphabet::Symbol> rest(rightHandSide.begin() + 1, rightHandSide.end()); + return removeRule(leftHandSide, std::make_pair(first, rest)); + } +} + void GNF::setGeneratesEpsilon(bool genEps) { generatesEpsilon = genEps; } diff --git a/alib2data/src/grammar/ContextFree/GNF.h b/alib2data/src/grammar/ContextFree/GNF.h index cb63da3a7d4efc41867f9cd14ba7f1fdc6353f0d..b81535d0c15e1099cc120a18236c46f210404b7d 100644 --- a/alib2data/src/grammar/ContextFree/GNF.h +++ b/alib2data/src/grammar/ContextFree/GNF.h @@ -33,10 +33,16 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >> > getRules() const; + const std::map<alphabet::Symbol, std::set<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >> > & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol> >& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/ContextFree/LG.cpp b/alib2data/src/grammar/ContextFree/LG.cpp index 10b68bf2f3db7b532e6244b35e932dbbc77c9dff..630de907b3a57b6bc0c1d3a95de24a4a583893d5 100644 --- a/alib2data/src/grammar/ContextFree/LG.cpp +++ b/alib2data/src/grammar/ContextFree/LG.cpp @@ -117,6 +117,24 @@ bool LG::addRule(const alphabet::Symbol& leftHandSide, const std::tuple<std::vec return addRule(leftHandSide, rhs); } +const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >> > & LG::getRules() const { + return rules; +} + +bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide) { + return rules[leftHandSide].erase(rightHandSide); +} + +bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + +bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + bool LG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { std::vector<alphabet::Symbol>::const_iterator nonterminalPosition = rightHandSide.begin(); for(; nonterminalPosition != rightHandSide.end(); nonterminalPosition++) { @@ -130,22 +148,36 @@ bool LG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alph } } -const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >> > LG::getRules() const { - return rules; -} - -bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide) { - return rules[leftHandSide].erase(rightHandSide); +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> LG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<std::vector<alphabet::Symbol>>()) { + res[rule.first].insert(rhs.get<std::vector<alphabet::Symbol>>()); + } else { + const auto& rhsTuple = rhs.get<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>>(); + std::vector<alphabet::Symbol> tmp; + tmp.insert(tmp.end(), std::get<0>(rhsTuple).begin(), std::get<0>(rhsTuple).end()); + tmp.push_back(std::get<1>(rhsTuple)); + tmp.insert(tmp.end(), std::get<2>(rhsTuple).begin(), std::get<2>(rhsTuple).end()); + res[rule.first].insert(tmp); + } + } + } + return res; } -bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { - std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); - return removeRule(leftHandSide, rhs); -} +bool LG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::vector<alphabet::Symbol>::const_iterator nonterminalPosition = rightHandSide.begin(); + for(; nonterminalPosition != rightHandSide.end(); nonterminalPosition++) { + if(nonterminalAlphabet.count(*nonterminalPosition)) break; + } -bool LG::removeRule(const alphabet::Symbol& leftHandSide, const std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide) { - std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); - return removeRule(leftHandSide, rhs); + if(nonterminalPosition == rightHandSide.end()) { + return removeRule(leftHandSide, rightHandSide); + } else { + return removeRule(leftHandSide, std::make_tuple(std::vector<alphabet::Symbol>(rightHandSide.begin(), nonterminalPosition), *nonterminalPosition, std::vector<alphabet::Symbol>(nonterminalPosition + 1, rightHandSide.end()))); + } } bool LG::operator==(const ObjectBase& other) const { diff --git a/alib2data/src/grammar/ContextFree/LG.h b/alib2data/src/grammar/ContextFree/LG.h index 7660ea0dc7303e7e807d8e54b12230d01f829018..47374f1bba40581ad61528835da3028902297c1a 100644 --- a/alib2data/src/grammar/ContextFree/LG.h +++ b/alib2data/src/grammar/ContextFree/LG.h @@ -36,14 +36,18 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); - bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - - const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >> > getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >> > & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/ContextSensitive/CSG.cpp b/alib2data/src/grammar/ContextSensitive/CSG.cpp index 3271b3a505c1ee0762cfcbb39a91e2fa5d134bcf..77e48595d34ec4a8085406ec46d31b81ba5141c6 100644 --- a/alib2data/src/grammar/ContextSensitive/CSG.cpp +++ b/alib2data/src/grammar/ContextSensitive/CSG.cpp @@ -103,7 +103,7 @@ bool CSG::addRule(const std::vector<alphabet::Symbol>& lContext, const alphabet: } } -const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> CSG::getRules() const { +const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> & CSG::getRules() const { return rules; } diff --git a/alib2data/src/grammar/ContextSensitive/CSG.h b/alib2data/src/grammar/ContextSensitive/CSG.h index 34a12e508feec4702cd7fad981d157370903dfd4..0389c7ffe1ba7569ef24141bcdd7fcd2afbc5ed7 100644 --- a/alib2data/src/grammar/ContextSensitive/CSG.h +++ b/alib2data/src/grammar/ContextSensitive/CSG.h @@ -32,7 +32,7 @@ public: bool addRule(const std::vector<alphabet::Symbol>& lContext, const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rContext, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const std::vector<alphabet::Symbol>& lContext, const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rContext, const std::vector<alphabet::Symbol>& rightHandSide); diff --git a/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.cpp b/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.cpp index 5f8b2ea48f6e8a10d891ca217bd86f682c84983c..922140c3b97ea6f6a85b7c1bec4b1f877614e95f 100644 --- a/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.cpp +++ b/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.cpp @@ -84,7 +84,7 @@ bool NonContractingGrammar::addRule(const std::vector<alphabet::Symbol>& leftHan return rules[leftHandSide].insert(rightHandSide).second; } -const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> NonContractingGrammar::getRules() const { +const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> & NonContractingGrammar::getRules() const { return rules; } diff --git a/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.h b/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.h index 5cf1851fdd6cd96356b5b0485ec33a897229713a..1223f714b6ae2e28bec2e1bcbedb24a6b7ccaf9a 100644 --- a/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.h +++ b/alib2data/src/grammar/ContextSensitive/NonContractingGrammar.h @@ -32,7 +32,7 @@ public: bool addRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); diff --git a/alib2data/src/grammar/Regular/LeftLG.cpp b/alib2data/src/grammar/Regular/LeftLG.cpp index 497c488da145022d92c06306d060514834f62bcc..1c66201141b9b6c1e613e5d39439c40fec7b1296 100644 --- a/alib2data/src/grammar/Regular/LeftLG.cpp +++ b/alib2data/src/grammar/Regular/LeftLG.cpp @@ -109,17 +109,7 @@ bool LeftLG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alpha return addRule(leftHandSide, rhs); } -bool LeftLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { - if(rightHandSide.size() == 0) { - return addRule(leftHandSide, rightHandSide); - } else if(nonterminalAlphabet.count(rightHandSide[0])) { - return addRule(leftHandSide, std::make_pair(rightHandSide[0], std::vector<alphabet::Symbol>(rightHandSide.begin() + 1, rightHandSide.end()))); - } else { - return addRule(leftHandSide, rightHandSide); - } -} - -const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > LeftLG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > & LeftLG::getRules() const { return rules; } @@ -137,6 +127,44 @@ bool LeftLG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<al return removeRule(leftHandSide, rhs); } +bool LeftLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return addRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[0])) { + return addRule(leftHandSide, std::make_pair(rightHandSide[0], std::vector<alphabet::Symbol>(rightHandSide.begin() + 1, rightHandSide.end()))); + } else { + return addRule(leftHandSide, rightHandSide); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> LeftLG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<std::vector<alphabet::Symbol>>()) { + res[rule.first].insert(rhs.get<std::vector<alphabet::Symbol>>()); + } else { + const auto& rhsTuple = rhs.get<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>(); + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhsTuple.first); + tmp.insert(tmp.end(), rhsTuple.second.begin(), rhsTuple.second.end()); + res[rule.first].insert(tmp); + } + } + } + return res; +} + +bool LeftLG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return removeRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[0])) { + return removeRule(leftHandSide, std::make_pair(rightHandSide[0], std::vector<alphabet::Symbol>(rightHandSide.begin() + 1, rightHandSide.end()))); + } else { + return removeRule(leftHandSide, rightHandSide); + } +} + bool LeftLG::operator==(const ObjectBase& other) const { return other == *this; } diff --git a/alib2data/src/grammar/Regular/LeftLG.h b/alib2data/src/grammar/Regular/LeftLG.h index cf5db657e97feef8a92682e5629756d00bc9b3b6..00cc4eab633ba75073af5b36ba60c808c332acbc 100644 --- a/alib2data/src/grammar/Regular/LeftLG.h +++ b/alib2data/src/grammar/Regular/LeftLG.h @@ -34,14 +34,18 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); - bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - - const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/Regular/LeftRG.cpp b/alib2data/src/grammar/Regular/LeftRG.cpp index 2c16f35f735e17a07de4c155d788bad520d63508..3f789ea2cbbc8ee8ff7cd3b38a22518bfdcb13a3 100644 --- a/alib2data/src/grammar/Regular/LeftRG.cpp +++ b/alib2data/src/grammar/Regular/LeftRG.cpp @@ -90,7 +90,7 @@ bool LeftRG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alpha return addRule(leftHandSide, rhs); } -const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> LeftRG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & LeftRG::getRules() const { return rules; } @@ -108,6 +108,59 @@ bool LeftRG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<al return removeRule(leftHandSide, rhs); } +bool LeftRG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else if(rightHandSide.size() == 1) { + return addRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return addRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> LeftRG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<alphabet::Symbol>()) { + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhs.get<alphabet::Symbol>()); + res[rule.first].insert(tmp); + } else { + const auto& rhsPair = rhs.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhsPair.first); + tmp.push_back(rhsPair.second); + res[rule.first].insert(tmp); + } + } + } + if(getGeneratesEpsilon()) { + res[getInitialSymbol()].insert(std::vector<alphabet::Symbol> {}); + } + return res; +} + +bool LeftRG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else if(rightHandSide.size() == 1) { + return removeRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return removeRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + void LeftRG::setGeneratesEpsilon(bool genEps) { generatesEpsilon = genEps; } diff --git a/alib2data/src/grammar/Regular/LeftRG.h b/alib2data/src/grammar/Regular/LeftRG.h index 409b6aaf9756643937febd424dc3cf91e848842e..e4c5470a89f7eeecfa8759dee0d16035b0e4d25d 100644 --- a/alib2data/src/grammar/Regular/LeftRG.h +++ b/alib2data/src/grammar/Regular/LeftRG.h @@ -10,6 +10,7 @@ #include "../GrammarBase.h" #include <map> +#include <vector> #include "../../std/variant.hpp" #include "../common/TerminalNonterminalAlphabetInitialSymbol.h" @@ -76,7 +77,7 @@ public: /** * Get rules of the grammar */ - const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & getRules() const; /** * Add a new rule of a grammar in form of A -> aB or A -> a, where A, B \in N and a \in T @@ -93,6 +94,12 @@ public: */ bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + /** * @copydoc TerminalNonterminalAlphabetInitialSymbol::removeTerminalSymbol() */ diff --git a/alib2data/src/grammar/Regular/RightLG.cpp b/alib2data/src/grammar/Regular/RightLG.cpp index 48604cb83aba2c85cf3093821bb0d5c1494f2c24..08faa71a17782e29615165b2a14aa037c29fa4a0 100644 --- a/alib2data/src/grammar/Regular/RightLG.cpp +++ b/alib2data/src/grammar/Regular/RightLG.cpp @@ -109,17 +109,7 @@ bool RightLG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<std: return addRule(leftHandSide, rhs); } -bool RightLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { - if(rightHandSide.size() == 0) { - return addRule(leftHandSide, rightHandSide); - } else if(nonterminalAlphabet.count(rightHandSide[rightHandSide.size() - 1])) { - return addRule(leftHandSide, std::make_pair(std::vector<alphabet::Symbol>(rightHandSide.begin(), rightHandSide.end() - 1), rightHandSide[rightHandSide.size() - 1])); - } else { - return addRule(leftHandSide, rightHandSide); - } -} - -const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > RightLG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > & RightLG::getRules() const { return rules; } @@ -137,6 +127,44 @@ bool RightLG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<s return removeRule(leftHandSide, rhs); } +bool RightLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return addRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[rightHandSide.size() - 1])) { + return addRule(leftHandSide, std::make_pair(std::vector<alphabet::Symbol>(rightHandSide.begin(), rightHandSide.end() - 1), rightHandSide[rightHandSide.size() - 1])); + } else { + return addRule(leftHandSide, rightHandSide); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> RightLG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<std::vector<alphabet::Symbol>>()) { + res[rule.first].insert(rhs.get<std::vector<alphabet::Symbol>>()); + } else { + const auto& rhsTuple = rhs.get<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>(); + std::vector<alphabet::Symbol> tmp; + tmp.insert(tmp.end(), rhsTuple.first.begin(), rhsTuple.first.end()); + tmp.push_back(rhsTuple.second); + res[rule.first].insert(tmp); + } + } + } + return res; +} + +bool RightLG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return removeRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[rightHandSide.size() - 1])) { + return removeRule(leftHandSide, std::make_pair(std::vector<alphabet::Symbol>(rightHandSide.begin(), rightHandSide.end() - 1), rightHandSide[rightHandSide.size() - 1])); + } else { + return removeRule(leftHandSide, rightHandSide); + } +} + bool RightLG::operator==(const ObjectBase& other) const { return other == *this; } diff --git a/alib2data/src/grammar/Regular/RightLG.h b/alib2data/src/grammar/Regular/RightLG.h index 1cadeeba5788abc57efb916b056dd3a22f408952..ffe784f00c6f013cb68ea65bd27de98e28926597 100644 --- a/alib2data/src/grammar/Regular/RightLG.h +++ b/alib2data/src/grammar/Regular/RightLG.h @@ -34,14 +34,18 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide); - bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - - const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/Regular/RightRG.cpp b/alib2data/src/grammar/Regular/RightRG.cpp index c1c357de8ecc964ec30f6af14cde33d70e73a02a..07eb323a3908d02163c7e84a1ad647e5c3073a4a 100644 --- a/alib2data/src/grammar/Regular/RightRG.cpp +++ b/alib2data/src/grammar/Regular/RightRG.cpp @@ -90,7 +90,7 @@ bool RightRG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alph return addRule(leftHandSide, rhs); } -const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> RightRG::getRules() const { +const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & RightRG::getRules() const { return rules; } @@ -108,6 +108,59 @@ bool RightRG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<a return removeRule(leftHandSide, rhs); } +bool RightRG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else if(rightHandSide.size() == 1) { + return addRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return addRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + +std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> RightRG::getRawRules() const { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> res; + for(const auto& rule : getRules()) { + for(const auto& rhs : rule.second) { + if(rhs.is<alphabet::Symbol>()) { + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhs.get<alphabet::Symbol>()); + res[rule.first].insert(tmp); + } else { + const auto& rhsPair = rhs.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); + std::vector<alphabet::Symbol> tmp; + tmp.push_back(rhsPair.first); + tmp.push_back(rhsPair.second); + res[rule.first].insert(tmp); + } + } + } + if(getGeneratesEpsilon()) { + res[getInitialSymbol()].insert(std::vector<alphabet::Symbol> {}); + } + return res; +} + +bool RightRG::removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + if(leftHandSide != initialSymbol) throw exception::AlibException("Illegal left hand side of epsilon rule"); + bool res = getGeneratesEpsilon(); + setGeneratesEpsilon(false); + return res; + } else if(rightHandSide.size() == 1) { + return removeRule(leftHandSide, rightHandSide[0]); + } else if(rightHandSide.size() == 2) { + return removeRule(leftHandSide, std::make_pair(rightHandSide[0], rightHandSide[1])); + } else { + throw exception::AlibException("Invalid right hand side"); + } +} + void RightRG::setGeneratesEpsilon(bool genEps) { generatesEpsilon = genEps; } diff --git a/alib2data/src/grammar/Regular/RightRG.h b/alib2data/src/grammar/Regular/RightRG.h index 4073501e4e3bdf4cbb438275bfef6db36d6d712a..3182e4f4639caa9e8a1f518d084704480d680e13 100644 --- a/alib2data/src/grammar/Regular/RightRG.h +++ b/alib2data/src/grammar/Regular/RightRG.h @@ -10,6 +10,7 @@ #include "../GrammarBase.h" #include <map> +#include <vector> #include "../../std/variant.hpp" #include "../common/TerminalNonterminalAlphabetInitialSymbol.h" @@ -50,12 +51,18 @@ public: bool addRule(const alphabet::Symbol& leftHandSide, const alphabet::Symbol& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, alphabet::Symbol>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> getRules() const; + const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>>> & getRules() const; bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const alphabet::Symbol& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, alphabet::Symbol>& rightHandSide); + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRawRules() const; + + bool removeRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeTerminalSymbol(const alphabet::Symbol& symbol); bool removeNonterminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp b/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp index ef7b540687e55ed5ca311321f7f5c70c19dc74bc..f600000099fc42e9e1a038da0e5c9472ded5edc9 100644 --- a/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp +++ b/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp @@ -97,7 +97,7 @@ bool ContextPreservingUnrestrictedGrammar::addRule(const std::vector<alphabet::S return rules[make_tuple(lContext, leftHandSide, rContext)].insert(rightHandSide).second; } -const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> ContextPreservingUnrestrictedGrammar::getRules() const { +const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> & ContextPreservingUnrestrictedGrammar::getRules() const { return rules; } diff --git a/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h b/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h index f35bfa3d989e91e8d2811012bacc4e05a810ebb5..958478e057ff4f304e02e46d4a2d3923084f93f6 100644 --- a/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h +++ b/alib2data/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h @@ -31,7 +31,7 @@ public: bool addRule(const std::vector<alphabet::Symbol>& lContext, const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rContext, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<std::tuple<std::vector<alphabet::Symbol>, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const std::vector<alphabet::Symbol>& lContext, const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rContext, const std::vector<alphabet::Symbol>& rightHandSide); diff --git a/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.cpp b/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.cpp index f653dd48005e20aeef791fe844a08c95e052c83d..e5417bac4b0d20a7a2675d7daf821ea6b0f5c98f 100644 --- a/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.cpp +++ b/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.cpp @@ -78,7 +78,7 @@ bool UnrestrictedGrammar::addRule(const std::vector<alphabet::Symbol>& leftHandS return rules[leftHandSide].insert(rightHandSide).second; } -const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> UnrestrictedGrammar::getRules() const { +const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> & UnrestrictedGrammar::getRules() const { return rules; } diff --git a/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.h b/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.h index 9b15d7c84e38205ebb2e35fc629106ea2b716d75..bcb7f71437a0f3f3cc26cb2fbb9ada1c085544c5 100644 --- a/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.h +++ b/alib2data/src/grammar/Unrestricted/UnrestrictedGrammar.h @@ -32,7 +32,7 @@ public: bool addRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); - const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> getRules() const; + const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> & getRules() const; bool removeRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); diff --git a/atrim/makefile b/atrim/makefile index 4a13ffc8029219533110a0a29c42669a9a9db428..0ae3f4208e5e282b847681f8a2376567e36c4f77 100644 --- a/atrim/makefile +++ b/atrim/makefile @@ -1,20 +1,73 @@ -CC=g++ -EXECUTABLE=atrim -CCFLAGS= -std=c++11 -O2 -c -Wall -I../alib/src -I/usr/include/libxml2/ -LDFLAGS= -L../alib/lib -lxml2 -lalib -Wl,-rpath,. +SHELL:=/bin/bash +EXECUTABLE:=aepsilon2 -SOURCES=$(shell find src/ -name *cpp) -OBJECTS=$(patsubst src/%.cpp, obj/%.o, $(SOURCES)) +LDFLAGS= -L../alib2data/lib -L../alib2algo/lib -rdynamic -lxml2 -lalib2data -lalib2algo -Wl,-rpath,. -all: $(SOURCES) bin/$(EXECUTABLE) +OBJECTS:=$(patsubst src/%.cpp, obj/%.o, $(shell find src/ -name *cpp)) -bin/$(EXECUTABLE): $(OBJECTS) +.PHONY: all build clean + +all: build + + + +bin/$(EXECUTABLE): obj/ $(OBJECTS) mkdir -p bin - $(CC) $(OBJECTS) -o $@ $(LDFLAGS) + $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) -obj/%.o: src/%.cpp +obj/makefile: makefile mkdir -p $(dir $@) - $(CC) $(CCFLAGS) $< -o $@ + echo "SHELL:=/bin/bash" >> $@ + echo "SRCDIR:=" >> $@ + echo "DEPTH:=" >> $@ + echo "" >> $@ + echo "CXXFLAGS:= -std=c++11 -Og -g -c -Wall -pedantic -Wextra -I../../\$$(DEPTH)alib2data/src/ -I../../\$$(DEPTH)alib2algo/src -I/usr/include/libxml2/" >> $@ + echo "" >> $@ + echo "SOURCES:= \$$(shell find ../\$$(DEPTH)src/\$$(SRCDIR) -maxdepth 1 -type f -name \"*.cpp\")" >> $@ + echo "DEPENDENCIES:= \$$(patsubst ../\$$(DEPTH)src/\$$(SRCDIR)%.cpp, ../\$$(DEPTH)obj/\$$(SRCDIR)%.d, \$$(SOURCES))" >> $@ + echo "OBJECTS:= \$$(patsubst %.d, %.o, \$$(DEPENDENCIES))" >> $@ + echo "SOURCES_DIRS:= \$$(shell find ../\$$(DEPTH)src/\$$(SRCDIR) -maxdepth 1 -mindepth 1 -type d)" >> $@ + echo "OBJECTS_DIRS:= \$$(patsubst ../\$$(DEPTH)src/\$$(SRCDIR)%, %/, \$$(SOURCES_DIRS))" >> $@ + echo "OBJECTS_DIRS_MAKEFILES:= \$$(patsubst %, %makefile, \$$(OBJECTS_DIRS))" >> $@ + echo "" >> $@ + echo ".PHONY: all" >> $@ + echo ".PRECIOUS: \$$(DEPENDECIES) \$$(OBJECTS_DIRS_MAKEFILES)" >> $@ + echo "" >> $@ + echo "all: \$$(OBJECTS_DIRS) \$$(OBJECTS)" >> $@ + echo "" >> $@ + echo "%.d:" >> $@ + echo " @echo \"\$$(shell sha1sum <<< \"\$$@\" | sed \"s/ -//g\") = \\$$\$$(shell (\\$$\$$(CXX) -MM \\$$\$$(CXXFLAGS) \$$(patsubst ../\$$(DEPTH)obj/\$$(SRCDIR)%.d,../\$$(DEPTH)src/\$$(SRCDIR)%.cpp, \$$@) 2>/dev/null || echo \\\"\$$(patsubst ../\$$(DEPTH)obj/\$$(SRCDIR)%.d,../\$$(DEPTH)src/\$$(SRCDIR)%.cpp, \$$@) FORCE\\\") | sed \\\"s/.*://g;s/\\\\\\\\\\\\\\\\//g\\\")\" >> \$$@" >> $@ + echo " @echo \"\$$(patsubst %.d,%.o, \$$@): \\$$\$$(\$$(shell sha1sum <<< \"\$$@\" | sed \"s/ -//g\"))\" >> \$$@" >> $@ + echo " @echo \" \\$$\$$(CXX) \\$$\$$(CXXFLAGS) \\$$\$$< -o \$$(patsubst %.d,%.o, \$$@)\" >> \$$@" >> $@ + echo "" >> $@ + echo "%/makefile:" >> $@ + echo " mkdir -p \$$(dir \$$@)" >> $@ + echo " cp makefile \$$@" >> $@ + echo "" >> $@ + echo "%/: FORCE | %/makefile" >> $@ + echo " @accesstime=\`stat -c %Y \$$@\` && \\" >> $@ + echo " \$$(MAKE) -C \$$@ SRCDIR=\$$(SRCDIR)\$$(notdir \$$(patsubst %/, %, \$$@))/ DEPTH=\$$(DEPTH)../ && \\" >> $@ + echo " accesstime2=\`stat -c %Y \$$@\` && \\" >> $@ + echo " if [ "\$$\$$accesstime" -ne "\$$\$$accesstime2" ]; then \\" >> $@ + echo " touch .; \\" >> $@ + echo " fi" >> $@ + echo "" >> $@ + echo "FORCE:" >> $@ + echo "" >> $@ + echo "-include \$$(DEPENDENCIES)" >> $@ + +obj/: FORCE | obj/makefile + $(MAKE) -C $@ + +$(OBJECTS): obj/ + + +build: bin/$(EXECUTABLE) + + clean: - $(RM) -r *.o *.d bin obj + $(RM) -r *.o *.d bin lib obj test-bin test-obj + +FORCE: + diff --git a/atrim/src/automaton/TrimFSM.cpp b/atrim/src/automaton/TrimFSM.cpp deleted file mode 100644 index f28a1a0823b4c514caee929217faaf24c301a0fb..0000000000000000000000000000000000000000 --- a/atrim/src/automaton/TrimFSM.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * TrimFSM.cpp - * - * Created on: 23. 3. 2014 - * Author: tomas - */ - -#include "TrimFSM.h" - -using namespace alib; -using namespace automaton; -using namespace std; - -FSM TrimFSM::removeUselessStates( const FSM & fsm ) -{ - // 1a - deque<set<State>> Qi; - Qi.push_back( set<State>( ) ); - Qi.at( 0 ) = fsm.getFinalStates( ); - - int i = 1; - - // 1bc - while( true ) - { - Qi.push_back( Qi.at( i - 1 ) ); // copy Qi-1 into Qi - for( const auto & p : Qi.at( i - 1 ) ) - for( const auto & t : fsm.getTransitionsToState( p ) ) - Qi.at( i ).insert( t.getFrom( ) ); - - if( Qi.at( i ) == Qi.at( i - 1 ) ) - break; - - i = i + 1; - } - const set<State> Qu = Qi.at( i ); - - // 2. - - FSM M; - - for( const auto & q : Qu ) - M.addState( q ); - - for( const auto & a : fsm.getInputAlphabet( ) ) - M.addInputSymbol( a ); - - for( const auto & t : fsm.getTransitions( ) ) - { - if( isInSet( t.getFrom( ), Qu ) && isInSet( t.getTo( ), Qu ) ) - { - M.addTransition( t ); - } - } - - for( const auto & q : fsm.getInitialStates( ) ) - M.addInitialState( q ); - - for( const auto & q : fsm.getFinalStates( ) ) - M.addFinalState( q ); - - return M; -} - - -FSM TrimFSM::removeUnreachableStates( const FSM & fsm ) -{ - if( fsm.getInitialStates( ).size( ) != 1 ) - throw AlibException( "NFA must have exactly one initial state." ); - - // 1a - deque<set<State>> Qi; - Qi.push_back( set<State>( ) ); - Qi.at( 0 ).insert( * fsm.getInitialStates( ).begin( ) ); - - int i = 1; - - // 1bc - while( true ) - { - Qi.push_back( Qi.at( i - 1 ) ); - - for( const auto & p : Qi.at( i - 1 ) ) - { - for( const auto & transition : fsm.getTransitionsFromState( p ) ) - { - Qi.at( i ).insert( transition.getTo( ) ); - } - } - - if( Qi.at( i ) == Qi.at( i - 1 ) ) - break; - - i = i + 1; - } - - const set<State> Qa = Qi.at( i ); - - - // 2 - - FSM M; - - for( const auto & q : Qa ) - M.addState( q ); - for( const auto & a : fsm.getInputAlphabet( ) ) - M.addInputSymbol( a ); - - for( const auto & transition : fsm.getTransitions( ) ) - if( isInSet( transition.getFrom( ), Qa ) ) - M.addTransition( transition ); - - M.addInitialState( * fsm.getInitialStates( ).begin( ) ); - - set<State> intersect; - set_intersection( fsm.getFinalStates( ).begin(), fsm.getFinalStates( ).end(), Qa.begin( ), Qa.end( ), inserter( intersect, intersect.begin( ) ) ); - for( auto const & state : intersect ) - M.addFinalState( state ); - - return M; -} diff --git a/atrim/src/automaton/TrimFSM.h b/atrim/src/automaton/TrimFSM.h deleted file mode 100644 index 394104d8f5f71c7d91b230b3932d1a2888dbd60c..0000000000000000000000000000000000000000 --- a/atrim/src/automaton/TrimFSM.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * TrimFSM.h - * - * Created on: 23. 3. 2014 - * Author: tomas - */ - -#ifndef TRIMFSM_H_ -#define TRIMFSM_H_ - -#include <algorithm> -#include <deque> -#include <set> - -#include <AlibException.h> -#include <automaton/FSM/FSM.h> - -#define isInSet(x,set) ( (set).find((x)) != (set).end()) - -class TrimFSM -{ -public: - /** - * Removes dead states from FSM. Melichar 2.32 - */ - static automaton::FSM removeUselessStates( const automaton::FSM & fsm ); - - /** - * Removes dead states from FSM. Melichar 2.29 - */ - static automaton::FSM removeUnreachableStates( const automaton::FSM & fsm ); -}; - -#endif /* TRIMFSM_H_ */ diff --git a/atrim/src/grammar/ContextFreeGrammarTransformations.cpp b/atrim/src/grammar/ContextFreeGrammarTransformations.cpp deleted file mode 100644 index aa4af83dedca5e65af232ea61bec9ccf0ebc1560..0000000000000000000000000000000000000000 --- a/atrim/src/grammar/ContextFreeGrammarTransformations.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ContextFreeGrammarTransformations.cpp - * - * Created on: 22. 3. 2014 - * Author: tomas - */ - -#include "ContextFreeGrammarTransformations.h" - -using namespace alib; -using namespace grammar; -using namespace std; - -set<Symbol> ContextFreeGrammarTransformations::getProductiveNonTerminals( const ContextFreeGrammar & grammar ) -{ - // 1. - deque<set<Symbol>> Ni; - Ni.push_back( set<Symbol>( ) ); - - int i = 1; - - // 2. - while( true ) - { - Ni.push_back( Ni.at( i - 1 ) ); - - for( const auto & rule : grammar.getRules( ) ) - { - if( all_of( rule.getRightSide( ).begin( ), rule.getRightSide( ).end( ), [ i, Ni, grammar ]( Symbol const& symbol ) -> bool { - return isInSet( symbol, Ni.at( i - 1 ) ) || isInSet( symbol, grammar.getTerminalSymbols( ) ); - } ) ) - Ni.at( i ).insert( rule.getLeftSide( ).front( ) ); - } - - if( Ni.at( i ) == Ni.at( i - 1 ) ) - break; - - i = i + 1; - } - - // 3. - return Ni.at( i ); -} - -bool ContextFreeGrammarTransformations::isLanguageEmpty( const grammar::ContextFreeGrammar & grammar ) -{ - return isInSet( grammar.getStartSymbol( ), getProductiveNonTerminals( grammar ) ); -} - -ContextFreeGrammar ContextFreeGrammarTransformations::removeUnreachableSymbols( const ContextFreeGrammar & grammar ) -{ - // 1 - deque<set<Symbol>> Vi; - Vi.push_back( set<Symbol>( ) ); - Vi.at( 0 ).insert( grammar.getStartSymbol( ) ); - - int i = 1; - - // 2. - while( true ) - { - Vi.push_back( Vi.at( i - 1 ) ); - - for( const auto & rule : grammar.getRules( ) ) - { - if( isInSet( rule.getLeftSide( ).front( ), Vi.at( i - 1 ) ) ) - { - Vi.at( i ).insert( rule.getRightSide( ).begin( ), rule.getRightSide( ).end( ) ); - } - } - - - if( Vi.at( i ) == Vi.at( i - 1 ) ) - break; - - i = i + 1; - } - - // 3. - ContextFreeGrammar ret; - - set<Symbol> newNonTerminals, newTerminals; - - set_intersection( Vi.at( i ).begin( ), Vi.at( i ).end( ), grammar.getNonTerminalSymbols( ).begin( ), grammar.getNonTerminalSymbols( ).end( ), std::inserter( newNonTerminals, newNonTerminals.begin( ) ) ); - for( const auto & symbol : newNonTerminals ) - ret.addNonTerminalSymbol( symbol ); - - set_intersection( Vi.at( i ).begin( ), Vi.at( i ).end( ), grammar.getTerminalSymbols( ).begin( ), grammar.getTerminalSymbols( ).end( ), std::inserter( newTerminals, newTerminals.begin( ) ) ); - for( const auto & symbol : newTerminals ) - ret.addTerminalSymbol( symbol ); - - // A->\alpha: if A \in N' and \alpha in V_i*, then A->\alpha in P - for( const auto & rule : grammar.getRules( ) ) - { - if( isInSet( rule.getLeftSide( ).front( ) , newNonTerminals ) && all_of( rule.getRightSide( ).begin( ), rule.getRightSide( ).end( ), [ Vi, i ]( Symbol const& symb ) -> bool { - return isInSet( symb, Vi.at( i ) ); - } ) ) - { - ret.addRule( rule ); - } - } - - ret.setStartSymbol( grammar.getStartSymbol( ) ); - - return ret; -} - -ContextFreeGrammar ContextFreeGrammarTransformations::removeUnproductiveSymbols( const ContextFreeGrammar & grammar ) -{ - // 1. - set<Symbol> Nt = getProductiveNonTerminals( grammar ); - - ContextFreeGrammar G1; - - for( const auto & symbol : Nt ) - G1.addNonTerminalSymbol( symbol ); - - for( const auto & symbol : grammar.getTerminalSymbols( ) ) - G1.addTerminalSymbol( symbol ); - - const set<Symbol> & T = G1.getTerminalSymbols( ); - for( const auto & rule : grammar.getRules( ) ) - { - if( isInSet( rule.getLeftSide( ).front( ), Nt ) && - all_of( rule.getRightSide( ).begin( ), rule.getRightSide( ).end( ), [ Nt, T ]( const Symbol & symbol ){ return isInSet( symbol, Nt ) || isInSet( symbol, T ); } ) ) - { - G1.addRule( rule ); - } - } - - if( ! isInSet( grammar.getStartSymbol( ), G1.getNonTerminalSymbols( ) ) ) - throw AlibException( "Starting symbol of grammar was marked as unproductive and therefore it was removed." ); - - G1.setStartSymbol( grammar.getStartSymbol( ) ); - - // 2. - return removeUnreachableSymbols( G1 ); -} diff --git a/atrim/src/grammar/ContextFreeGrammarTransformations.h b/atrim/src/grammar/ContextFreeGrammarTransformations.h deleted file mode 100644 index 3745b0776c42290a49ffefd8b847bc7d90551b49..0000000000000000000000000000000000000000 --- a/atrim/src/grammar/ContextFreeGrammarTransformations.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ContextFreeGrammarTransformations.h - * - * Created on: 22. 3. 2014 - * Author: tomas - */ - -#ifndef CONTEXTFREEGRAMMARTRANSFORMATIONS_H_ -#define CONTEXTFREEGRAMMARTRANSFORMATIONS_H_ - -#include <algorithm> -#include <deque> -#include <set> - -#include <AlibException.h> -#include <grammar/ContextFree/ContextFreeGrammar.h> - -#define isInSet(x,set) ( (set).find((x)) != (set).end()) - -/** - * Implements algorithms from Melichar, chapter 3.3 - */ -class ContextFreeGrammarTransformations -{ -public: - /* - * Melichar 3.6 - decides whether L( grammar ) = \0 - * - * Severals steps implemented in method ContextFreeGrammarTransformations::getProductiveNonTerminals(); - * @see getProductiveNonTerminals - */ - static bool isLanguageEmpty( const grammar::ContextFreeGrammar & grammar ); - - /* - * Removes unreachable symbols - Melichar 3.9 - */ - static grammar::ContextFreeGrammar removeUnreachableSymbols( const grammar::ContextFreeGrammar & grammar ); - - /** - * Removes unproductive (or useless - terminology) symbols - Melichar 3.12 - */ - static grammar::ContextFreeGrammar removeUnproductiveSymbols( const grammar::ContextFreeGrammar & grammar ); - -private: - /** - * Implements steps 1 through 3 in Melichar 3.6 - */ - static std::set<alphabet::Symbol> getProductiveNonTerminals( const grammar::ContextFreeGrammar & grammar ); -}; - -#endif /* CONTEXTFREEGRAMMARTRANSFORMATIONS_H_ */