diff --git a/aconversions2/src/ConversionHandler.cpp b/aconversions2/src/ConversionHandler.cpp index b458ad7842459dba96b0960e7d865ef083cf9e24..dec0494d0b499e7ac8414581a6b967566c72247e 100644 --- a/aconversions2/src/ConversionHandler.cpp +++ b/aconversions2/src/ConversionHandler.cpp @@ -25,8 +25,8 @@ #include "conversions/re2rg/re2rrg/GlushkovNFA.h" #include "conversions/re2rg/re2rrg/BrzozowskiDerivation.h" -#include "conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.h" -#include "conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.h" +#include "conversions/rg2rg/LeftToRightRegularGrammar.h" +#include "conversions/rg2rg/RightToLeftRegularGrammar.h" using namespace alib; @@ -213,8 +213,7 @@ void ConversionHandler::convertREtoFSM( void ) } case GLUSHKOV_NFA: default: { - conversions::re2fa::GlushkovNFA conv; - alib::DataFactory::toStdout(conv.convert(regexp)); + alib::DataFactory::toStdout(conversions::re2fa::GlushkovNFA::convert(regexp)); break; } } @@ -289,8 +288,7 @@ void ConversionHandler::convertLRGtoRRG( void ) switch( m_algorithm ) { default: - conversions::rg2rg::LeftToRightRegularGrammar conv; - alib::DataFactory::toStdout(conv.convert(lrg)); + alib::DataFactory::toStdout(conversions::rg2rg::LeftToRightRegularGrammar::convert(lrg)); break; } } @@ -302,8 +300,7 @@ void ConversionHandler::convertRRGtoLRG( void ) switch( m_algorithm ) { default: - conversions::rg2rg::RightToLeftRegularGrammar conv; - alib::DataFactory::toStdout(conv.convert(rrg)); + alib::DataFactory::toStdout(conversions::rg2rg::RightToLeftRegularGrammar::convert(rrg)); break; } } diff --git a/alib2algo/src/conversions/re2fa/GlushkovNFA.cpp b/alib2algo/src/conversions/re2fa/GlushkovNFA.cpp index ad614b9a75cb07dfc7fd57db87f1901140c45f9d..471db6e083a777db341ea28cfd7e77cc7e450f02 100644 --- a/alib2algo/src/conversions/re2fa/GlushkovNFA.cpp +++ b/alib2algo/src/conversions/re2fa/GlushkovNFA.cpp @@ -6,12 +6,17 @@ */ #include "GlushkovNFA.h" + #include "label/Label.h" #include "label/StringLabel.h" #include "label/CharacterLabel.h" #include "label/IntegerLabel.h" #include "label/LabelPairLabel.h" +#include "../../regexp/GlushkovTraversal.h" +#include "../../regexp/GlushkovPair.h" +#include "../../regexp/GlushkovSymbol.h" + #include "../../regexp/RegExpEpsilon.h" namespace conversions{ @@ -19,79 +24,87 @@ namespace conversions{ namespace re2fa { automaton::NFA GlushkovNFA::convert(const regexp::RegExp& regexp) { - automaton::NFA out; - regexp.getData().Accept((void*) &out, *this); - return out; -} -void GlushkovNFA::Visit(void* userData, const regexp::FormalRegExp& regexp) { - automaton::NFA& out = *(automaton::NFA*) userData; - out = this->convert(regexp); -} - -void GlushkovNFA::Visit(void* userData, const regexp::UnboundedRegExp& regexp) { - automaton::NFA& out = *(automaton::NFA*) userData; - out = this->convert(regexp); + automaton::NFA* out = nullptr; + regexp.getData().Accept((void*) &out, GlushkovNFA::GLUSHKOV_NFA); + automaton::NFA res = std::move(*out); + delete out; + return res; } -automaton::NFA GlushkovNFA::convert( const regexp::UnboundedRegExp & re ) { +automaton::NFA GlushkovNFA::convert(const regexp::UnboundedRegExp& regexp) +{ automaton::NFA automaton; // step 1 - for( auto const& symbol : re.getAlphabet( ) ) + for( auto const& symbol : regexp.getAlphabet( ) ) automaton.addInputSymbol( symbol ); // steps 2, 3, 4 - m_first = regexp::GlushkovTraversal::first( re ); - m_last = regexp::GlushkovTraversal::last( re ); - for( auto const& x : regexp::GlushkovTraversal::getSymbols( re ) ) - for( auto const& f : regexp::GlushkovTraversal::follow( re, x ) ) { - m_pairs.insert( regexp::GlushkovPair( x, f ) ); - //std::cout << x.getSymbolPtr() << "|" << x.getSymbol() << "|" << x.getId() << " + "; - //std::cout << f.getSymbolPtr() << "|" << f.getSymbol() << "|" << f.getId() << std::endl; + std::set<regexp::GlushkovPair> pairs; + const std::set<regexp::GlushkovSymbol> first = regexp::GlushkovTraversal::first(regexp); + const std::set<regexp::GlushkovSymbol> last = regexp::GlushkovTraversal::last(regexp); + for( auto const& x : regexp::GlushkovTraversal::getSymbols( regexp ) ) + for( auto const& f : regexp::GlushkovTraversal::follow( regexp, x ) ) { + pairs.insert( regexp::GlushkovPair( x, f ) ); } // \e in q0 check is in step 7 // step 5 + std::map<regexp::GlushkovSymbol, automaton::State> stateMap; + automaton::State q0( label::Label( label::LabelPairLabel( std::make_pair( label::Label( label::CharacterLabel( 'q' ) ), label::Label( label::IntegerLabel ( 0 ) ) ) ) ) ); automaton.addState( q0 ); automaton.addInitialState( q0 ); - for( auto const& symbol : regexp::GlushkovTraversal::getSymbols( re ) ) { + for( auto const& symbol : regexp::GlushkovTraversal::getSymbols( regexp ) ) { automaton::State q( label::Label( label::LabelPairLabel( std::make_pair( label::Label( label::StringLabel( symbol.getInputSymbol( ) ) ), label::Label( label::IntegerLabel ( symbol.getId( ) ) ) ) ) ) ); - m_stateMap.insert( std::make_pair( symbol, q ) ); + stateMap.insert( std::make_pair( symbol, q ) ); automaton.addState( q ); } // step 6 - for( auto const& symbol : m_first ) { - const automaton::State & q = m_stateMap.find( symbol )->second; + for( auto const& symbol : first ) { + const automaton::State & q = stateMap.find( symbol )->second; automaton.addTransition( q0, symbol.getInputSymbol( ), q ); } - for( auto const& pair : m_pairs ) { - const automaton::State & p = m_stateMap.find( pair.getFirst( ) )->second; - const automaton::State & q = m_stateMap.find( pair.getSecond( ) )->second; + for( auto const& pair : pairs ) { + const automaton::State & p = stateMap.find( pair.getFirst( ) )->second; + const automaton::State & q = stateMap.find( pair.getSecond( ) )->second; automaton.addTransition( p, pair.getSecond( ).getInputSymbol( ), q ); } // step 7 - for( auto const& symbol : m_last ) { - const automaton::State & q = m_stateMap.find( symbol )->second; + for( auto const& symbol : last ) { + const automaton::State & q = stateMap.find( symbol )->second; automaton.addFinalState( q ); } - if(regexp::RegExpEpsilon::languageContainsEpsilon(re)) + if(regexp::RegExpEpsilon::languageContainsEpsilon(regexp)) automaton.addFinalState( q0 ); return automaton; } -automaton::NFA GlushkovNFA::convert( const regexp::FormalRegExp & re ) { - throw exception::AlibException("Unimplemented"); +void GlushkovNFA::Visit(void* userData, const regexp::FormalRegExp& regexp) const +{ + /* + automaton::NFA* & out = *((automaton::NFA**) userData); + out = new automaton::NFA(this->convert(regexp)); + */ + throw exception::AlibException("Glushkov: Converting FormalRegExp NYI"); // TODO +} + +void GlushkovNFA::Visit(void* userData, const regexp::UnboundedRegExp& regexp) const +{ + automaton::NFA* & out = *((automaton::NFA**) userData); + out = new automaton::NFA(this->convert(regexp)); } +const GlushkovNFA GlushkovNFA::GLUSHKOV_NFA; + } /* namespace fa2re */ } /* namespace conversions */ diff --git a/alib2algo/src/conversions/re2fa/GlushkovNFA.h b/alib2algo/src/conversions/re2fa/GlushkovNFA.h index fa42209388e245a19ac2f8c2825b80c133d95cc5..1cb1c806b7aa9859135c1a9841ee8b22664fb6fe 100644 --- a/alib2algo/src/conversions/re2fa/GlushkovNFA.h +++ b/alib2algo/src/conversions/re2fa/GlushkovNFA.h @@ -10,18 +10,10 @@ #include <map> -#include <alphabet/Symbol.h> -#include <automaton/common/State.h> -#include <regexp/unbounded/UnboundedRegExp.h> -#include <regexp/unbounded/UnboundedRegExpElements.h> -#include <regexp/formal/FormalRegExp.h> -#include <regexp/formal/FormalRegExpElements.h> -#include <regexp/RegExp.h> - -#include "../../regexp/GlushkovTraversal.h" -#include "std/hexavigesimal.h" - #include <automaton/FSM/NFA.h> +#include <regexp/RegExp.h> +#include <regexp/formal/FormalRegExp.h> +#include <regexp/unbounded/UnboundedRegExp.h> namespace conversions { @@ -31,28 +23,24 @@ namespace re2fa { * Converts regular expression to finite automaton using Glushkov's NFA construction algorithm. * Source: Melichar 2.107 */ -class GlushkovNFA : public regexp::VisitableRegExpBase::visitor_type { +class GlushkovNFA : public regexp::VisitableRegExpBase::const_visitor_type +{ public: /** * Performs conversion. * @param re Original regular expression. - * @return FSM equivalent to original regular expression. - * + * @return NFA equivalent to original regular expression. */ - automaton::NFA convert( const regexp::UnboundedRegExp & re ); - automaton::NFA convert( const regexp::FormalRegExp & re ); + static automaton::NFA convert(const regexp::RegExp& re); - automaton::NFA convert( const regexp::RegExp & re ); + static automaton::NFA convert(const regexp::UnboundedRegExp& re); + static automaton::NFA convert(const regexp::FormalRegExp& re); private: - std::map<regexp::GlushkovSymbol, automaton::State> m_stateMap; - std::set<regexp::GlushkovSymbol> m_first; - std::set<regexp::GlushkovSymbol> m_last; - std::set<regexp::GlushkovPair> m_pairs; - - void Visit(void* , const regexp::FormalRegExp& regexp); - void Visit(void* , const regexp::UnboundedRegExp& regexp); + void Visit(void*, const regexp::FormalRegExp& regexp) const; + void Visit(void*, const regexp::UnboundedRegExp& regexp) const; + static const GlushkovNFA GLUSHKOV_NFA; }; } /* namespace re2fa */ diff --git a/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.cpp b/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.cpp index c8dad374dd5dcbf78b6438a384e7fce5deffe3f2..7206e72e153c0882fa23f8093f6c88eb2ae4b3d9 100644 --- a/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.cpp +++ b/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.cpp @@ -56,6 +56,7 @@ grammar::RightRG GlushkovNFA::convert(const regexp::UnboundedRegExp& regexp) // step 5 std::map<regexp::GlushkovSymbol, alphabet::Symbol> symbolMap; + for(const auto& symbol : regexp::GlushkovTraversal::getSymbols(regexp)) { alphabet::Symbol nt(alphabet::LabeledSymbol(label::Label(label::LabelPairLabel(std::make_pair(label::Label(label::StringLabel(symbol.getInputSymbol())), label::Label(label::IntegerLabel(symbol.getId()))))))); diff --git a/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.h b/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.h index 9d75324ebdcb930dbea7f4c66ef7591f66d486b0..32de94e8b020907573114155fb9c1c8b33bea075 100644 --- a/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.h +++ b/alib2algo/src/conversions/re2rg/re2rrg/GlushkovNFA.h @@ -30,6 +30,7 @@ class GlushkovNFA : public regexp::VisitableRegExpBase::const_visitor_type public: /** * Performs conversion. + * @param regexp original regular expression * @return right regular grammar equivalent to source regexp. */ static grammar::Grammar convert(const regexp::RegExp& regexp); diff --git a/alib2algo/src/conversions/rg2re/Algebraic.cpp b/alib2algo/src/conversions/rg2re/Algebraic.cpp index 36bca86b616deb5cafb4b7365e4d31bc06aa9247..509e463059548b6c1f12cde6a86ff266e7345bf5 100644 --- a/alib2algo/src/conversions/rg2re/Algebraic.cpp +++ b/alib2algo/src/conversions/rg2re/Algebraic.cpp @@ -10,6 +10,7 @@ #include "../../equations/LeftRegularEquationSolver.h" #include "../../equations/RightRegularEquationSolver.h" +#include <exception/AlibException.h> #include <regexp/unbounded/UnboundedRegExpElements.h> namespace conversions diff --git a/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.cpp b/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab6089d16227ef9fb83be60d90b1666be6c946c7 --- /dev/null +++ b/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.cpp @@ -0,0 +1,149 @@ +/* + * LeftToRightRegularGrammar.cpp + * + * Created on: 8. 3. 2014 + * Author: Tomas Pecka + */ + +#include "LeftToRightRegularGrammar.h" + +#include <exception/AlibException.h> + +namespace conversions { + +namespace rg2rg { + +grammar::RightRG LeftToRightRegularGrammar::convert(const grammar::Grammar& grammar) +{ + grammar::RightRG* out = NULL; + grammar.getData().Accept((void*) &out, LeftToRightRegularGrammar::LEFT_TO_RIGHT_REGULAR_GRAMMAR); + grammar::RightRG res = std::move(*out); + delete out; + return res; +} + +grammar::RightRG LeftToRightRegularGrammar::convert(const grammar::LeftRG& grammar) +{ + // 1. + alphabet::Symbol s = alphabet::createUniqueSymbol( grammar.getInitialSymbol( ), grammar.getNonterminalAlphabet(), grammar.getTerminalAlphabet() ); + + grammar::RightRG rrg( s ); + + for(const auto & nonterminalSymbol : grammar.getNonterminalAlphabet() ) { + rrg.addNonterminalSymbol( nonterminalSymbol ); + } + + rrg.setTerminalAlphabet( grammar.getTerminalAlphabet( ) ); + rrg.setGeneratesEpsilon( grammar.getGeneratesEpsilon( ) ); + + // 2 + for( const auto & rule : grammar.getRules( ) ) { + const alphabet::Symbol& lhs = rule.first; + + for(const auto & ruleRHS : rule.second ) { + if( ruleRHS.is<std::pair<alphabet::Symbol, alphabet::Symbol>>( ) ) { + const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); + + alphabet::Symbol leftSide = ( rhs.first ); + std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( rhs.second, lhs ); + rrg.addRule( leftSide, rightSide ); + + if( lhs == grammar.getInitialSymbol( ) ) { + alphabet::Symbol leftSide = rhs.first; + alphabet::Symbol rightSide = rhs.second; + rrg.addRule( leftSide, rightSide ); + } + } else { + const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); + + alphabet::Symbol leftSide = rrg.getInitialSymbol( ); + std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( rhs, lhs ); + rrg.addRule( leftSide, rightSide ); + + if( lhs == grammar.getInitialSymbol( ) ) { + alphabet::Symbol leftSide = rrg.getInitialSymbol( ); + alphabet::Symbol rightSide = rhs; + rrg.addRule( leftSide, rightSide ); + } + } + } + } + return rrg; +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::UnknownGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type UnknownGrammar"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::UnrestrictedGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::CSG&) const +{ + throw exception::AlibException("Unsupported grammar type CSG"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::NonContractingGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type NonContractingGrammar"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::CNF&) const +{ + throw exception::AlibException("Unsupported grammar type CNF"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::CFG&) const +{ + throw exception::AlibException("Unsupported grammar type CFG"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::EpsilonFreeCFG&) const +{ + throw exception::AlibException("Unsupported grammar type EpsilonFreeCFG"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::GNF&) const +{ + throw exception::AlibException("Unsupported grammar type GNF"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::LG&) const +{ + throw exception::AlibException("Unsupported grammar type LG"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::RightRG&) const +{ + throw exception::AlibException("Unsupported grammar type RightRG"); +} + +void LeftToRightRegularGrammar::Visit(void* userData, const grammar::LeftRG& grammar) const +{ + grammar::RightRG* & out = *((grammar::RightRG**) userData); + out = new grammar::RightRG(this->convert(grammar)); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::RightLG&) const +{ + throw exception::AlibException("Unsupported grammar type RightLG"); +} + +void LeftToRightRegularGrammar::Visit(void*, const grammar::LeftLG&) const +{ + throw exception::AlibException("Unsupported grammar type LeftLG"); +} + +const LeftToRightRegularGrammar LeftToRightRegularGrammar::LEFT_TO_RIGHT_REGULAR_GRAMMAR; + +} /* namespace rg2rg */ + +} /* namespace conversions */ diff --git a/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.h b/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.h new file mode 100644 index 0000000000000000000000000000000000000000..ab25664de272a7242ffd7774d4021111320270fb --- /dev/null +++ b/alib2algo/src/conversions/rg2rg/LeftToRightRegularGrammar.h @@ -0,0 +1,61 @@ +/* + * LeftToRightRegularGrammar.h + * + * Created on: 8. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef LEFT_TORIGHT_REGULAR_GRAMMAR_H_ +#define LEFT_TORIGHT_REGULAR_GRAMMAR_H_ + +#include <grammar/Grammar.h> +#include <grammar/Regular/LeftRG.h> +#include <grammar/Regular/RightRG.h> + +namespace conversions{ + +namespace rg2rg +{ + +/** + * Converts left regular grammar to right regular grammar. + */ +class LeftToRightRegularGrammar : public grammar::VisitableGrammarBase::const_visitor_type +{ +public: + /** + * Performs conversion. + * @param grammar Left regular grammar to convert + * @return right regular grammar which is equivalent to source left regular grammar. + */ + static grammar::RightRG convert(const grammar::Grammar& grammar); + static grammar::RightRG convert(const grammar::LeftRG& grammar); + +private: + void Visit(void*, const grammar::UnknownGrammar& grammar) const; + + void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; + void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; + + void Visit(void*, const grammar::CSG& grammar) const; + void Visit(void*, const grammar::NonContractingGrammar& grammar) const; + + void Visit(void*, const grammar::CNF& grammar) const; + void Visit(void*, const grammar::CFG& grammar) const; + void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; + void Visit(void*, const grammar::GNF& grammar) const; + void Visit(void*, const grammar::LG& grammar) const; + + void Visit(void*, const grammar::RightRG& grammar) const; + void Visit(void*, const grammar::LeftRG& grammar) const; + void Visit(void*, const grammar::RightLG& grammar) const; + void Visit(void*, const grammar::LeftLG& grammar) const; + + static const LeftToRightRegularGrammar LEFT_TO_RIGHT_REGULAR_GRAMMAR; +}; + +} /* namespace rg2rg */ + +} /* namespace conversions */ + +#endif /* LEFT_TO_RIGHT_REGULAR_GRAMMAR_H_ */ diff --git a/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.cpp b/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1da71429b51d6b0d754ad9d6ea54fa0ba9e5fd3 --- /dev/null +++ b/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.cpp @@ -0,0 +1,152 @@ +/* + * RightToLeftRegularGrammar.cpp + * + * Created on: 8. 3. 2014 + * Author: Tomas Pecka + */ + +#include "RightToLeftRegularGrammar.h" + +#include <exception/AlibException.h> + +namespace conversions +{ + +namespace rg2rg +{ + +grammar::LeftRG RightToLeftRegularGrammar::convert(const grammar::Grammar& grammar) +{ + grammar::LeftRG* out = NULL; + grammar.getData().Accept((void*) &out, RightToLeftRegularGrammar::RIGHT_TO_LEFT_REGULAR_GRAMMAR); + grammar::LeftRG res = std::move(*out); + delete out; + return res; +} + +grammar::LeftRG RightToLeftRegularGrammar::convert(const grammar::RightRG& grammar) +{ + // 1. + alphabet::Symbol s = alphabet::createUniqueSymbol( grammar.getInitialSymbol( ), grammar.getNonterminalAlphabet(), grammar.getTerminalAlphabet() ); + + grammar::LeftRG lrg(s); + + for(const auto & nonterminalSymbol : grammar.getNonterminalAlphabet()) { + lrg.addNonterminalSymbol( nonterminalSymbol ); + } + + lrg.setTerminalAlphabet( grammar.getTerminalAlphabet( ) ); + lrg.setGeneratesEpsilon( grammar.getGeneratesEpsilon( ) ); + + // 2. + for( const auto & rule : grammar.getRules( ) ) { + const alphabet::Symbol& lhs = rule.first; + + for(const auto & ruleRHS : rule.second ) { + if( ruleRHS.is<std::pair<alphabet::Symbol, alphabet::Symbol>>( ) ) { + const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); + + alphabet::Symbol leftSide = rhs.second; + std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( lhs, rhs.first ); + lrg.addRule( leftSide, rightSide ); + + if( lhs == grammar.getInitialSymbol( ) ) { + alphabet::Symbol leftSide = rhs.second; + alphabet::Symbol rightSide = rhs.first; + lrg.addRule( leftSide, rightSide ); + } + } else { + const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); + + alphabet::Symbol leftSide = lrg.getInitialSymbol( ); + std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair ( lhs, rhs ); + lrg.addRule( leftSide, rightSide ); + + if( lhs == grammar.getInitialSymbol( ) ) { + alphabet::Symbol leftSide = lrg.getInitialSymbol( ); + alphabet::Symbol rightSide = rhs; + lrg.addRule( leftSide, rightSide ); + } + } + } + } + return lrg; +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::UnknownGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type UnknownGrammar"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::UnrestrictedGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::CSG&) const +{ + throw exception::AlibException("Unsupported grammar type CSG"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::NonContractingGrammar&) const +{ + throw exception::AlibException("Unsupported grammar type NonContractingGrammar"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::CNF&) const +{ + throw exception::AlibException("Unsupported grammar type CNF"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::CFG&) const +{ + throw exception::AlibException("Unsupported grammar type CFG"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::EpsilonFreeCFG&) const +{ + throw exception::AlibException("Unsupported grammar type EpsilonFreeCFG"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::GNF&) const +{ + throw exception::AlibException("Unsupported grammar type GNF"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::LG&) const +{ + throw exception::AlibException("Unsupported grammar type LG"); +} + +void RightToLeftRegularGrammar::Visit(void* userData, const grammar::RightRG& grammar) const +{ + grammar::LeftRG* & out = *((grammar::LeftRG**) userData); + out = new grammar::LeftRG(this->convert(grammar)); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::LeftRG&) const +{ + throw exception::AlibException("Unsupported grammar type RightRG"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::RightLG&) const +{ + throw exception::AlibException("Unsupported grammar type RightLG"); +} + +void RightToLeftRegularGrammar::Visit(void*, const grammar::LeftLG&) const +{ + throw exception::AlibException("Unsupported grammar type LeftLG"); +} + +const RightToLeftRegularGrammar RightToLeftRegularGrammar::RIGHT_TO_LEFT_REGULAR_GRAMMAR; + + +} /* namespace rg2rg */ + +} /* namespace conversions */ diff --git a/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.h b/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.h new file mode 100644 index 0000000000000000000000000000000000000000..bccd75f1305fca80316adcfe5623d82d3a49ce82 --- /dev/null +++ b/alib2algo/src/conversions/rg2rg/RightToLeftRegularGrammar.h @@ -0,0 +1,62 @@ +/* + * RightToLeftRegularGrammar.h + * + * Created on: 8. 3. 2014 + * Author: Tomas Pecka + */ + +#ifndef RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ +#define RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ + +#include <grammar/Grammar.h> +#include <grammar/Regular/LeftRG.h> +#include <grammar/Regular/RightRG.h> + +namespace conversions +{ + +namespace rg2rg +{ + +/** + * Converts right regular grammar to left regular grammar. + */ +class RightToLeftRegularGrammar : public grammar::VisitableGrammarBase::const_visitor_type +{ +public: + /** + * Performs conversion. + * @param grammar Right regular grammar to convert + * @return left regular grammar which is equivalent to source right regular grammar. + */ + static grammar::LeftRG convert(const grammar::Grammar& grammar); + static grammar::LeftRG convert(const grammar::RightRG& grammar); + +private: + void Visit(void*, const grammar::UnknownGrammar& grammar) const; + + void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; + void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; + + void Visit(void*, const grammar::CSG& grammar) const; + void Visit(void*, const grammar::NonContractingGrammar& grammar) const; + + void Visit(void*, const grammar::CNF& grammar) const; + void Visit(void*, const grammar::CFG& grammar) const; + void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; + void Visit(void*, const grammar::GNF& grammar) const; + void Visit(void*, const grammar::LG& grammar) const; + + void Visit(void*, const grammar::RightRG& grammar) const; + void Visit(void*, const grammar::LeftRG& grammar) const; + void Visit(void*, const grammar::RightLG& grammar) const; + void Visit(void*, const grammar::LeftLG& grammar) const; + + static const RightToLeftRegularGrammar RIGHT_TO_LEFT_REGULAR_GRAMMAR; +}; + +} /* namespace rg2rg */ + +} /* namespace conversions */ + +#endif /* RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ */ diff --git a/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.cpp b/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.cpp deleted file mode 100644 index 0a1cca7dbab6ce98c99987d1a8cab27ca8068503..0000000000000000000000000000000000000000 --- a/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * LeftToRightRegularGrammar.cpp - * - * Created on: 8. 3. 2014 - * Author: Tomas Pecka - */ - -#include "LeftToRightRegularGrammar.h" - -namespace conversions { - -namespace rg2rg { - -grammar::RightRG LeftToRightRegularGrammar::convert(const grammar::LeftRG& lrg) -{ - // 1. - alphabet::Symbol s = alphabet::createUniqueSymbol( lrg.getInitialSymbol( ), lrg.getNonterminalAlphabet(), lrg.getTerminalAlphabet() ); - - grammar::RightRG rrg( s ); - - for(const auto & nonterminalSymbol : lrg.getNonterminalAlphabet() ) { - rrg.addNonterminalSymbol( nonterminalSymbol ); - } - - rrg.setTerminalAlphabet( lrg.getTerminalAlphabet( ) ); - rrg.setGeneratesEpsilon( lrg.getGeneratesEpsilon( ) ); - - // 2 - for( const auto & rule : lrg.getRules( ) ) { - const alphabet::Symbol& lhs = rule.first; - - for(const auto & ruleRHS : rule.second ) { - if( ruleRHS.is<std::pair<alphabet::Symbol, alphabet::Symbol>>( ) ) { - const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); - - alphabet::Symbol leftSide = ( rhs.first ); - std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( rhs.second, lhs ); - rrg.addRule( leftSide, rightSide ); - - if( lhs == lrg.getInitialSymbol( ) ) { - alphabet::Symbol leftSide = rhs.first; - alphabet::Symbol rightSide = rhs.second; - rrg.addRule( leftSide, rightSide ); - } - } else { - const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); - - alphabet::Symbol leftSide = rrg.getInitialSymbol( ); - std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( rhs, lhs ); - rrg.addRule( leftSide, rightSide ); - - if( lhs == lrg.getInitialSymbol( ) ) { - alphabet::Symbol leftSide = rrg.getInitialSymbol( ); - alphabet::Symbol rightSide = rhs; - rrg.addRule( leftSide, rightSide ); - } - } - } - } - return rrg; -} - -} /* namespace rg2rg */ - -} /* namespace conversions */ diff --git a/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.h b/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.h deleted file mode 100644 index b217f735686b252d802134bed1ccb922cda959ca..0000000000000000000000000000000000000000 --- a/alib2algo/src/conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * LeftToRightRegularGrammar.h - * - * Created on: 8. 3. 2014 - * Author: Tomas Pecka - */ - -#ifndef LEFT_TORIGHT_REGULAR_GRAMMAR_H_ -#define LEFT_TORIGHT_REGULAR_GRAMMAR_H_ - -#include <grammar/Regular/LeftRG.h> -#include <grammar/Regular/RightRG.h> - -namespace conversions{ - -namespace rg2rg -{ - -class LeftToRightRegularGrammar -{ -public: - /** - * Performs conversion. - * @return right regular grammar which is equivalent to source left regular grammar. - */ - grammar::RightRG convert(const grammar::LeftRG& lrg); -}; - -} /* namespace rg2rg */ - -} /* namespace conversions */ - -#endif /* LEFT_TO_RIGHT_REGULAR_GRAMMAR_H_ */ diff --git a/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.cpp b/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.cpp deleted file mode 100644 index a43a808f34c681c1811f523dad951bd045a6c139..0000000000000000000000000000000000000000 --- a/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * RightToLeftRegularGrammar.cpp - * - * Created on: 8. 3. 2014 - * Author: Tomas Pecka - */ - -#include "RightToLeftRegularGrammar.h" - -namespace conversions -{ - -namespace rg2rg -{ - -grammar::LeftRG RightToLeftRegularGrammar::convert(const grammar::RightRG& rrg) -{ - // 1. - alphabet::Symbol s = alphabet::createUniqueSymbol( rrg.getInitialSymbol( ), rrg.getNonterminalAlphabet(), rrg.getTerminalAlphabet() ); - - grammar::LeftRG lrg(s); - - for(const auto & nonterminalSymbol : rrg.getNonterminalAlphabet()) { - lrg.addNonterminalSymbol( nonterminalSymbol ); - } - - lrg.setTerminalAlphabet( rrg.getTerminalAlphabet( ) ); - lrg.setGeneratesEpsilon( rrg.getGeneratesEpsilon( ) ); - - // 2. - for( const auto & rule : rrg.getRules( ) ) { - const alphabet::Symbol& lhs = rule.first; - - for(const auto & ruleRHS : rule.second ) { - if( ruleRHS.is<std::pair<alphabet::Symbol, alphabet::Symbol>>( ) ) { - const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); - - alphabet::Symbol leftSide = rhs.second; - std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair( lhs, rhs.first ); - lrg.addRule( leftSide, rightSide ); - - if( lhs == rrg.getInitialSymbol( ) ) { - alphabet::Symbol leftSide = rhs.second; - alphabet::Symbol rightSide = rhs.first; - lrg.addRule( leftSide, rightSide ); - } - } else { - const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); - - alphabet::Symbol leftSide = lrg.getInitialSymbol( ); - std::pair<alphabet::Symbol, alphabet::Symbol> rightSide = std::make_pair ( lhs, rhs ); - lrg.addRule( leftSide, rightSide ); - - if( lhs == rrg.getInitialSymbol( ) ) { - alphabet::Symbol leftSide = lrg.getInitialSymbol( ); - alphabet::Symbol rightSide = rhs; - lrg.addRule( leftSide, rightSide ); - } - } - } - } - return lrg; -} - -} /* namespace rg2rg */ - -} /* namespace conversions */ diff --git a/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.h b/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.h deleted file mode 100644 index 7cecd00f2702e57d3a3e502cedc5bcc27426ac26..0000000000000000000000000000000000000000 --- a/alib2algo/src/conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * RightToLeftRegularGrammar.h - * - * Created on: 8. 3. 2014 - * Author: Tomas Pecka - */ - -#ifndef RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ -#define RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ - -#include <grammar/Regular/LeftRG.h> -#include <grammar/Regular/RightRG.h> - -namespace conversions -{ - -namespace rg2rg -{ - -/** - * Converts right regular grammar to left regular grammar. - */ -class RightToLeftRegularGrammar -{ -public: - /** - * Performs conversion. - * @return left regular grammar which is equivalent to source right regular grammar. - */ - grammar::LeftRG convert(const grammar::RightRG& rrg); -}; - -} /* namespace rg2rg */ - -} /* namespace conversions */ - -#endif /* RIGHT_TO_LEFT_REGULAR_GRAMMAR_H_ */ diff --git a/alib2algo/src/equations/LeftRegularEquationSolver.cpp b/alib2algo/src/equations/LeftRegularEquationSolver.cpp index cc9fed801761292214289595d2801af941658e28..80051cc993ccc1645d214d9b621c5006fd108103 100644 --- a/alib2algo/src/equations/LeftRegularEquationSolver.cpp +++ b/alib2algo/src/equations/LeftRegularEquationSolver.cpp @@ -12,71 +12,71 @@ namespace equations { -regexp::UnboundedRegExp LeftRegularEquationSolver::eliminate( void ) { +regexp::UnboundedRegExp LeftRegularEquationSolver::eliminate(void) { regexp::RegExpOptimize opt; - for( auto itA = m_symbolsByDepth.rbegin( ); itA != m_symbolsByDepth.rend( ); itA ++ ) { - const alphabet::Symbol & a = * itA; + for(auto itA = nonterminalSymbolsByDepth.rbegin(); itA != nonterminalSymbolsByDepth.rend(); itA ++) { + const alphabet::Symbol& a = * itA; /* * Apply Arden's Lemma * A = A0 + B1 + C2 * => A = 10*B + 20*C */ - regexp::UnboundedRegExpIteration loop( std::move( m_eqTransition[ a ][ a ] ) ); - opt.optimize( loop ); + regexp::UnboundedRegExpIteration loop(std::move(equationTransition.find(std::make_pair(a, a))->second)); + opt.optimize(loop); // for all transitions from A apply Arden's Lemma - for( auto itB = std::next( itA ) ; itB != m_symbolsByDepth.rend( ); itB ++ ) { - const alphabet::Symbol & b = * itB; + for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); itB ++) { + const alphabet::Symbol& b = * itB; regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( std::move( m_eqTransition[ a ][ b ] ) ); - concat.appendElement( loop ); + concat.appendElement(std::move(equationTransition.find(std::make_pair(a, b))->second)); + concat.appendElement(loop); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( concat ) ); - m_eqTransition[ a ][ b ] = std::move( alt ); - opt.optimize( m_eqTransition[ a ][ b ] ); + alt.appendElement(std::move(concat)); + equationTransition.find(std::make_pair(a, b))->second = std::move(alt); + opt.optimize(equationTransition.find(std::make_pair(a, b))->second); } regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( std::move( m_eqFinal[ a ] ) ); - concat.appendElement( std::move( loop ) ); + concat.appendElement(std::move(equationFinal.find(a)->second)); + concat.appendElement(std::move(loop)); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( concat ) ); - m_eqFinal[ a ] = std::move( alt ); - opt.optimize( m_eqFinal[ a ] ); + alt.appendElement(std::move(concat)); + equationFinal.find(a)->second = std::move(alt); + opt.optimize(equationFinal.find(a)->second); /* * eliminate A from rest of the equations using this pattern: - * B->C = B->C + concatenate( B->A, A->C ) + * B->C = B->C + concatenate(B->A, A->C) */ - for( auto itB = std::next( itA ); itB != m_symbolsByDepth.rend( ); itB ++ ) { - const alphabet::Symbol & b = * itB; + for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); itB ++) { + const alphabet::Symbol& b = * itB; - for( auto itC = std::next( itA ); itC != m_symbolsByDepth.rend( ); itC ++ ) { - const alphabet::Symbol & c = * itC; + for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); itC ++) { + const alphabet::Symbol& c = * itC; regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( m_eqTransition[ a ][ c ] ); - concat.appendElement( m_eqTransition[ b ][ a ] ); + concat.appendElement(equationTransition.find(std::make_pair(a, c))->second); + concat.appendElement(equationTransition.find(std::make_pair(b, a))->second); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( m_eqTransition[ b ][ c ] ) ); - alt.appendElement( std::move( concat ) ); - m_eqTransition[ b ][ c ] = std::move( alt ); - opt.optimize( m_eqTransition[ b ][ c ] ); + alt.appendElement(std::move(equationTransition.find(std::make_pair(b, c))->second)); + alt.appendElement(std::move(concat)); + equationTransition.find(std::make_pair(b, c))->second = std::move(alt); + opt.optimize(equationTransition.find(std::make_pair(b, c))->second); } regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( m_eqFinal[ a ] ); - concat.appendElement( std::move( m_eqTransition[ b ][ a ] ) ); + concat.appendElement(equationFinal.find(a)->second); + concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second)); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( m_eqFinal[ b ] ) ); - alt.appendElement( std::move( concat ) ); - m_eqFinal[ b ] = std::move( alt ); - opt.optimize( m_eqFinal[ b ] ); + alt.appendElement(std::move(equationFinal.find(b)->second)); + alt.appendElement(std::move(concat)); + equationFinal.find(b)->second = std::move(alt); + opt.optimize(equationFinal.find(b)->second); } } - return opt.optimize( regexp::UnboundedRegExp( std::move ( m_eqFinal[ * m_symbolsByDepth.begin( ) ] ) ) ); + return opt.optimize(regexp::UnboundedRegExp(std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second))); } } /* namespace equations */ diff --git a/alib2algo/src/equations/RegularEquationSolver.cpp b/alib2algo/src/equations/RegularEquationSolver.cpp index 74f8484fc9732b9d5051ee1ca8a349aa38c3ffe1..9ed3e952891a897861ab1ddfda3c5ddb23552c99 100644 --- a/alib2algo/src/equations/RegularEquationSolver.cpp +++ b/alib2algo/src/equations/RegularEquationSolver.cpp @@ -7,80 +7,127 @@ #include "RegularEquationSolver.h" -#include "regexp/unbounded/UnboundedRegExpElements.h" +#include <exception/AlibException.h> +#include <algorithm> namespace equations { -regexp::UnboundedRegExp RegularEquationSolver::solve( const alphabet::Symbol & solveFor ) { - if( ! isInSet( solveFor, m_symbols ) ) - throw exception::AlibException( "Trying to solve for symbol not present in equation system" ); +void RegularEquationSolver::setSymbols(const std::set<alphabet::Symbol>& newSymbols) { + std::set<alphabet::Symbol> removed, added; + + std::set_difference(nonterminalSymbols.begin(), nonterminalSymbols.end(), newSymbols.begin(), newSymbols.end(), std::inserter(removed, removed.end())); + std::set_difference(newSymbols.begin(), newSymbols.end(), nonterminalSymbols.begin(), nonterminalSymbols.end(), std::inserter(added, added.end())); - /* - * Firstly, organize states by depth so we can output better looking - * expressions. We need to solve equation system for automaton initial state, - * so lets start with the deepest ones and walk towards initial one. - */ - symbolsByDepth( solveFor ); + for(const auto& symb : removed) { + removeSymbol(symb); + } - return eliminate( ); + for(const auto& symb : added) { + addSymbol(symb); + } } -void RegularEquationSolver::addSymbol( const alphabet::Symbol & symb ) { - m_symbols.insert( symb ); +void RegularEquationSolver::removeSymbol(const alphabet::Symbol& symb) { + for(const auto& kv : equationTransition) { + const alphabet::Symbol& from = kv.first.first; + const alphabet::Symbol& to = kv.first.second; + const regexp::UnboundedRegExpAlternation& alt = kv.second; + + if((from == symb || to == symb) && alt.getElements().size() != 0) { + throw exception::AlibException("Symbol '" + (std::string) symb + "' is in use."); + } + } + + for(const auto& kv : equationFinal) { + const alphabet::Symbol& from = kv.first; + const regexp::UnboundedRegExpAlternation& alt = kv.second; + + if(from == symb && alt.getElements().size() != 0) { + throw exception::AlibException("Symbol '" + (std::string) from + "' is in use."); + } + } + + + nonterminalSymbols.erase(nonterminalSymbols.find(symb)); + equationFinal.erase(equationFinal.find(symb)); - for( const auto & s1 : m_symbols ) - { - m_eqTransition[ symb ][ s1 ] = regexp::UnboundedRegExpAlternation { }; - if( s1 != symb ) - m_eqTransition[ s1 ][ symb ] = regexp::UnboundedRegExpAlternation { }; + for(const auto& s : nonterminalSymbols) { + equationTransition.erase(equationTransition.find(std::make_pair(s, symb))); + equationTransition.erase(equationTransition.find(std::make_pair(symb, s))); } + equationTransition.erase(equationTransition.find(std::make_pair(symb, symb))); +} + +void RegularEquationSolver::addSymbol(const alphabet::Symbol& symb) { + for(const auto& s : nonterminalSymbols) { + equationTransition.insert(std::make_pair(std::make_pair(symb, s), regexp::UnboundedRegExpAlternation { })); + equationTransition.insert(std::make_pair(std::make_pair(s, symb), regexp::UnboundedRegExpAlternation { })); + } + equationTransition.insert(std::make_pair(std::make_pair(symb, symb), regexp::UnboundedRegExpAlternation { })); - m_eqFinal[ symb ] = regexp::UnboundedRegExpAlternation { }; + nonterminalSymbols.insert(symb); + equationFinal.insert(std::make_pair(symb, regexp::UnboundedRegExpAlternation { })); } -void RegularEquationSolver::addEquation( const alphabet::Symbol & from, const alphabet::Symbol & to, const regexp::UnboundedRegExpElement& eq ) { - if( ! isInSet( from, m_symbols ) ) - throw exception::AlibException( "Symbol '" + (std::string) from + "' not in equation system." ); +void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement& eq) { + if(nonterminalSymbols.count(from) == 0) { + throw exception::AlibException("Symbol from ('" + (std::string) from + "') is not in equation system."); + } - if( ! isInSet( to, m_symbols ) ) - throw exception::AlibException( "Symbol '" + (std::string) to + "' not in equation system." ); + if(nonterminalSymbols.count(to) == 0) { + throw exception::AlibException("Symbol to ('" + (std::string) to + "') is not in equation system."); + } - m_eqTransition[ from ][ to ].appendElement( eq ); + equationTransition.find(std::make_pair(from, to))->second.appendElement(eq); } -void RegularEquationSolver::addEquation( const alphabet::Symbol & from, const regexp::UnboundedRegExpElement& eq ) { - if( ! isInSet( from, m_symbols ) ) - throw exception::AlibException( "Symbol '" + (std::string) from + "' not in equation system." ); +void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement& eq) { + if(nonterminalSymbols.count(from) == 0) { + throw exception::AlibException("Symbol from ('" + (std::string) from + "') is not in equation system."); + } - m_eqFinal[ from ].appendElement( eq ); + equationFinal.find(from)->second.appendElement(eq); } -void RegularEquationSolver::symbolsByDepth( const alphabet::Symbol & solveFor ) { +void RegularEquationSolver::sortSymbolsByDepth(const alphabet::Symbol& solveFor) { std::map<alphabet::Symbol, bool> visited; std::queue<alphabet::Symbol> queue; - for( const auto & symbol : m_symbols ) - visited[ symbol ] = false; + for(const auto& symbol : nonterminalSymbols) { + visited[symbol] = false; + } - visited[ solveFor ] = true; - queue.push( solveFor ); + visited[solveFor] = true; + queue.push(solveFor); - while( ! queue.empty( ) ) - { - alphabet::Symbol s = queue.front( ); - queue.pop( ); + while(! queue.empty()) { + alphabet::Symbol s = queue.front(); + queue.pop(); - m_symbolsByDepth.push_back( s ); + nonterminalSymbolsByDepth.push_back(s); - auto map_s = m_eqTransition.find( s ); - for( auto it = map_s->second.begin( ); it != map_s->second.end( ); it ++ ) - { - if( it->second.getElements().size() > 0 && visited[ it->first ] == false ) { - visited[ it->first ] = true; - queue.push( it->first ); + for(const auto& kv : equationTransition) { + // find all transitions from current symbol that are non-empty, enqueue transition's target symbol + if(kv.first.first == s && visited[ kv.first.second ] == false && kv.second.getElements().size() > 0) { + visited[kv.first.second] = true; + queue.push(kv.first.second); } } } } +regexp::UnboundedRegExp RegularEquationSolver::solve(const alphabet::Symbol& solveFor) { + if(nonterminalSymbols.count(solveFor) == 0) { + throw exception::AlibException("Symbol solveFor ('" + (std::string) solveFor + "') is not in equation system."); + } + + /* + * Firstly, organize states by depth so we can output better looking + * expressions. We need to solve equation system for automaton's initial state, + * so lets start with the deepest ones and walk towards the initial one. + */ + sortSymbolsByDepth(solveFor); + return eliminate(); +} + } /* namespace equations */ diff --git a/alib2algo/src/equations/RegularEquationSolver.h b/alib2algo/src/equations/RegularEquationSolver.h index 9911783a3dee5af4ae796ed80193aed112118e91..1136d232e0d073c9c399fcf9e2571508e1c47ad7 100644 --- a/alib2algo/src/equations/RegularEquationSolver.h +++ b/alib2algo/src/equations/RegularEquationSolver.h @@ -8,19 +8,13 @@ #ifndef REGULAREQUATIONSOLVER_H_ #define REGULAREQUATIONSOLVER_H_ +#include <regexp/unbounded/UnboundedRegExpElements.h> +#include <alphabet/Symbol.h> + #include <map> #include <deque> #include <queue> -#include <alphabet/Symbol.h> -#include <exception/AlibException.h> -#include <regexp/unbounded/UnboundedRegExpElement.h> -#include <regexp/unbounded/UnboundedRegExpAlternation.h> - -#include "common/macros.h" - -// #include "RegExpOptimize.h" //TODO uncomment when implemented - namespace equations { /** @@ -32,8 +26,24 @@ public: * Adds nonterminal symbol into system. * * @param symb given symbol + * @ + */ + void addSymbol(const alphabet::Symbol& symbol); + + /** + * Removes nonterminal symbol from equation system. + * + * @param symb given symbol + * @throws AlibException when symbol is in use + */ + void removeSymbol(const alphabet::Symbol& symbol); + + /** + * Sets nonterminal symbols of the equation system. + * @param symbol Symbols to set + * @throws AlibException */ - void addSymbol( const alphabet::Symbol & symb ); + void setSymbols(const std::set<alphabet::Symbol>& symbols); /** * Adds equation in form FROM = eq TO @@ -42,7 +52,7 @@ public: * @param to symbol * @param eq equation */ - void addEquation( const alphabet::Symbol & from, const alphabet::Symbol & to, const regexp::UnboundedRegExpElement& eq ); + void addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement& eq); /** * Adds equation in form: FROM = eq @@ -50,7 +60,7 @@ public: * @param from * @param eq */ - void addEquation( const alphabet::Symbol & from, const regexp::UnboundedRegExpElement& eq ); + void addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement& eq); /** * Solve expression system @@ -58,40 +68,40 @@ public: * @param solveFor will solve equation system for given symbol * @return regexp */ - regexp::UnboundedRegExp solve( const alphabet::Symbol & solveFor ); + regexp::UnboundedRegExp solve(const alphabet::Symbol& solveFor); protected: /** * actual equations elimination * @return pointer to solutions RegExp tree root */ - virtual regexp::UnboundedRegExp eliminate( void ) = 0; + virtual regexp::UnboundedRegExp eliminate(void) = 0; /** - * Runs BFS to determine depth of symbols in equation system and stores it in m_symbolsByDepth; - * @see m_symbolsByDepth + * Runs BFS to determine depth of symbols in equation system and stores it in nonterminalSymbolsByDepth; + * @see nonterminalSymbolsByDepth */ - void symbolsByDepth( const alphabet::Symbol & solveFor ); + void sortSymbolsByDepth(const alphabet::Symbol& solveFor); /** * @see symbolsByDepth */ - std::deque<alphabet::Symbol> m_symbolsByDepth; + std::deque<alphabet::Symbol> nonterminalSymbolsByDepth; /** * Stores transitions from nonterminal to nonterminal, eg A = 2A + 2B + 1C */ - std::map<alphabet::Symbol, std::map<alphabet::Symbol, regexp::UnboundedRegExpAlternation>> m_eqTransition; + std::map<std::pair<alphabet::Symbol, alphabet::Symbol>, regexp::UnboundedRegExpAlternation> equationTransition; /** * Stores equation not going to particular nonterminal, eg A = 01* */ - std::map<alphabet::Symbol, regexp::UnboundedRegExpAlternation> m_eqFinal; + std::map<alphabet::Symbol, regexp::UnboundedRegExpAlternation> equationFinal; /** * Set of symbols */ - std::set<alphabet::Symbol> m_symbols; + std::set<alphabet::Symbol> nonterminalSymbols; }; } /* namespace equations */ diff --git a/alib2algo/src/equations/RightRegularEquationSolver.cpp b/alib2algo/src/equations/RightRegularEquationSolver.cpp index b9d1dac2ea680a800396236f035b452b9d541d50..63b14225b7e5440ae3e7aff9ff78781872f25c7c 100644 --- a/alib2algo/src/equations/RightRegularEquationSolver.cpp +++ b/alib2algo/src/equations/RightRegularEquationSolver.cpp @@ -12,71 +12,71 @@ namespace equations { -regexp::UnboundedRegExp RightRegularEquationSolver::eliminate( void ) { +regexp::UnboundedRegExp RightRegularEquationSolver::eliminate(void) { regexp::RegExpOptimize opt; - for( auto itA = m_symbolsByDepth.rbegin( ); itA != m_symbolsByDepth.rend( ); itA ++ ) { - const alphabet::Symbol & a = * itA; + for(auto itA = nonterminalSymbolsByDepth.rbegin(); itA != nonterminalSymbolsByDepth.rend(); itA ++) { + const alphabet::Symbol& a = * itA; /* * Apply Arden's Lemma * A = 0A + 1B + 2C * => A = 0*1B + 0*2C */ - regexp::UnboundedRegExpIteration loop( std::move( m_eqTransition[ a ][ a ] ) ); - opt.optimize( loop ); + regexp::UnboundedRegExpIteration loop(std::move(equationTransition.find(std::make_pair(a, a))->second)); + opt.optimize(loop); // for all transitions from A apply Arden's Lemma - for( auto itB = std::next( itA ) ; itB != m_symbolsByDepth.rend( ); itB ++ ) { - const alphabet::Symbol & b = * itB; + for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); itB ++) { + const alphabet::Symbol& b = * itB; regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( loop ); - concat.appendElement( std::move( m_eqTransition[ a ][ b ] ) ); + concat.appendElement(loop); + concat.appendElement(std::move(equationTransition.find(std::make_pair(a,b))->second)); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( concat ) ); - m_eqTransition[ a ][ b ] = std::move( alt ); - opt.optimize( m_eqTransition[ a ][ b ] ); + alt.appendElement(std::move(concat)); + equationTransition.find(std::make_pair(a, b))->second = std::move(alt); + opt.optimize(equationTransition.find(std::make_pair(a, b))->second); } regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( std::move( loop ) ); - concat.appendElement( std::move( m_eqFinal[ a ] ) ); + concat.appendElement(std::move(loop)); + concat.appendElement(std::move(equationFinal.find(a)->second)); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( concat ) ); - m_eqFinal[ a ] = std::move( alt ); - opt.optimize( m_eqFinal[ a ] ); + alt.appendElement(std::move(concat)); + equationFinal.find(a)->second = std::move(alt); + opt.optimize(equationFinal.find(a)->second); /* * eliminate A from rest of the equations using this pattern: - * B->C = B->C + concatenate( B->A, A->C ) + * B->C = B->C + concatenate(B->A, A->C) */ - for( auto itB = std::next( itA ); itB != m_symbolsByDepth.rend( ); itB ++ ) { - const alphabet::Symbol & b = * itB; + for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); itB ++) { + const alphabet::Symbol& b = * itB; - for( auto itC = std::next( itA ); itC != m_symbolsByDepth.rend( ); itC ++ ) { - const alphabet::Symbol & c = * itC; + for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); itC ++) { + const alphabet::Symbol& c = * itC; regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( m_eqTransition[ b ][ a ] ); - concat.appendElement( m_eqTransition[ a ][ c ] ); + concat.appendElement(equationTransition.find(std::make_pair(b, a))->second); + concat.appendElement(equationTransition.find(std::make_pair(a, c))->second); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( m_eqTransition[ b ][ c ] ) ); - alt.appendElement( std::move( concat ) ); - m_eqTransition[ b ][ c ] = std::move( alt ); - opt.optimize( m_eqTransition[ b ][ c ] ); + alt.appendElement(std::move(equationTransition.find(std::make_pair(b, c))->second)); + alt.appendElement(std::move(concat)); + equationTransition.find(std::make_pair(b, c))->second = std::move(alt); + opt.optimize(equationTransition.find(std::make_pair(b, c))->second); } regexp::UnboundedRegExpConcatenation concat; - concat.appendElement( std::move( m_eqTransition[ b ][ a ] ) ); - concat.appendElement( m_eqFinal[ a ] ); + concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second)); + concat.appendElement(equationFinal.find(a)->second); regexp::UnboundedRegExpAlternation alt; - alt.appendElement( std::move( m_eqFinal[ b ] ) ); - alt.appendElement( std::move( concat ) ); - m_eqFinal[ b ] = std::move( alt ); - opt.optimize( m_eqFinal[ b ] ); + alt.appendElement(std::move(equationFinal.find(b)->second)); + alt.appendElement(std::move(concat)); + equationFinal.find(b)->second = std::move(alt); + opt.optimize(equationFinal.find(b)->second); } } - return opt.optimize( regexp::UnboundedRegExp( std::move ( m_eqFinal[ * m_symbolsByDepth.begin( ) ] ) ) ); + return opt.optimize(regexp::UnboundedRegExp(std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second))); } } /* namespace equations */ diff --git a/alib2algo/test-src/conversions/re2fa/re2faTest.cpp b/alib2algo/test-src/conversions/re2fa/re2faTest.cpp index 3e0a368f99de1bd821eb792cb5321d02529733a9..4806de5eb3591f0f92beeb2f5de3ff19ed3767c4 100644 --- a/alib2algo/test-src/conversions/re2fa/re2faTest.cpp +++ b/alib2algo/test-src/conversions/re2fa/re2faTest.cpp @@ -83,10 +83,8 @@ void re2faTest::testBrzozowski() { regexp::RegExp regexp1( parser.parseValue() ); automaton::Automaton nfa1 = conversions::re2fa::BrzozowskiDerivation::convert(regexp1); - alib::DataFactory::toStdout(nfa1); regexp::RegExp regexp2( conversions::fa2re::Algebraic::convert(static_cast<const automaton::NFA&>(nfa1.getData())) ); - alib::DataFactory::toStdout(regexp2); automaton::Automaton nfa2 = conversions::re2fa::BrzozowskiDerivation::convert(regexp2); @@ -98,8 +96,5 @@ void re2faTest::testBrzozowski() { automaton::DFA mdfa2_2 = minimize::MinimizeDFA::minimize(mdfa2_1); automaton::DFA mdfa2_3 = normalize::NormalizeDFA::normalize(mdfa2_2); - alib::DataFactory::toStdout(mdfa1_3); - alib::DataFactory::toStdout(mdfa2_3); - CPPUNIT_ASSERT( mdfa1_3 == mdfa2_3); } diff --git a/alib2algo/test-src/conversions/rg2rg/rg2rgTest.cpp b/alib2algo/test-src/conversions/rg2rg/rg2rgTest.cpp index c8952a67181b4fdc32953c781899588ca56152f7..8f1862e70dea0c2e722fed3b213415ef8d9dbe01 100644 --- a/alib2algo/test-src/conversions/rg2rg/rg2rgTest.cpp +++ b/alib2algo/test-src/conversions/rg2rg/rg2rgTest.cpp @@ -6,8 +6,8 @@ #include "label/Label.h" #include "alphabet/LabeledSymbol.h" -#include "conversions/rg2rg/rrg2lrg/RightToLeftRegularGrammar.h" -#include "conversions/rg2rg/lrg2rrg/LeftToRightRegularGrammar.h" +#include "conversions/rg2rg/RightToLeftRegularGrammar.h" +#include "conversions/rg2rg/LeftToRightRegularGrammar.h" #define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) @@ -32,8 +32,7 @@ void rg2rgTest::testConversion() { rrGrammar.addRule(alphabet::symbolFrom(2), std::make_pair(alphabet::symbolFrom("b"), alphabet::symbolFrom(3))); rrGrammar.addRule(alphabet::symbolFrom(3), alphabet::symbolFrom("a")); - conversions::rg2rg::RightToLeftRegularGrammar convertor;; - grammar::LeftRG lrGrammar = convertor.convert(rrGrammar); + grammar::LeftRG lrGrammar = conversions::rg2rg::RightToLeftRegularGrammar::convert(rrGrammar); grammar::LeftRG lrGrammarRef(alphabet::symbolFrom(4)); @@ -64,8 +63,7 @@ void rg2rgTest::testConversion2() { lrGrammar.addRule(alphabet::symbolFrom(3), std::make_pair(alphabet::symbolFrom(2), alphabet::symbolFrom("b"))); lrGrammar.addRule(alphabet::symbolFrom(4), std::make_pair(alphabet::symbolFrom(3), alphabet::symbolFrom("a"))); - conversions::rg2rg::LeftToRightRegularGrammar convertor; - grammar::RightRG rrGrammar = convertor.convert(lrGrammar); + grammar::RightRG rrGrammar = conversions::rg2rg::LeftToRightRegularGrammar::convert(lrGrammar); grammar::RightRG rrGrammarRef(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(5)))));