From 11e167e7e86094906c675ac7331f8c2c22e3ae16 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 6 Dec 2016 08:42:26 +0100 Subject: [PATCH] template Equations solver --- .../automaton/convert/ToRegExpAlgebraic.cpp | 8 +- .../equations/LeftRegularEquationSolver.cpp | 85 --------- .../src/equations/LeftRegularEquationSolver.h | 85 ++++++++- .../src/equations/RegularEquationSolver.cpp | 134 -------------- .../src/equations/RegularEquationSolver.h | 168 +++++++++++++++--- .../equations/RightRegularEquationSolver.cpp | 85 --------- .../equations/RightRegularEquationSolver.h | 85 ++++++++- .../src/grammar/convert/ToRegExpAlgebraic.cpp | 61 +------ .../src/grammar/convert/ToRegExpAlgebraic.h | 64 ++++++- 9 files changed, 376 insertions(+), 399 deletions(-) delete mode 100644 alib2algo/src/equations/LeftRegularEquationSolver.cpp delete mode 100644 alib2algo/src/equations/RegularEquationSolver.cpp delete mode 100644 alib2algo/src/equations/RightRegularEquationSolver.cpp diff --git a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp index f1da7bc1aa..5c2afe0dd6 100644 --- a/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp +++ b/alib2algo/src/automaton/convert/ToRegExpAlgebraic.cpp @@ -27,7 +27,7 @@ regexp::RegExp ToRegExpAlgebraic::convert(const automaton::Automaton& automaton) } regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::EpsilonNFA < > & automaton ) { - equations::RightRegularEquationSolver solver; + equations::RightRegularEquationSolver < alphabet::Symbol > solver; // initialize equations for( const auto & q : automaton.getStates( ) ) @@ -56,7 +56,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::Epsilon auto ToRegExpAlgebraicEpsilonNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::EpsilonNFA < > >(ToRegExpAlgebraic::convert); regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::MultiInitialStateNFA < > & automaton ) { - equations::RightRegularEquationSolver solver; + equations::RightRegularEquationSolver < alphabet::Symbol > solver; // initialize equations for( const auto & q : automaton.getStates( ) ) @@ -87,7 +87,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::MultiIn auto ToRegExpAlgebraicMultiInitialStateNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::MultiInitialStateNFA < > >(ToRegExpAlgebraic::convert); regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::NFA < > & automaton ) { - equations::RightRegularEquationSolver solver; + equations::RightRegularEquationSolver < alphabet::Symbol > solver; // initialize equations for( const auto & q : automaton.getStates( ) ) @@ -110,7 +110,7 @@ regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::NFA < > auto ToRegExpAlgebraicNFA = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, automaton::NFA < > >(ToRegExpAlgebraic::convert); regexp::UnboundedRegExp < > ToRegExpAlgebraic::convert( const automaton::DFA < > & automaton ) { - equations::RightRegularEquationSolver solver; + equations::RightRegularEquationSolver < alphabet::Symbol > solver; // initialize equations for( const auto & q : automaton.getStates( ) ) diff --git a/alib2algo/src/equations/LeftRegularEquationSolver.cpp b/alib2algo/src/equations/LeftRegularEquationSolver.cpp deleted file mode 100644 index 6e1eff9147..0000000000 --- a/alib2algo/src/equations/LeftRegularEquationSolver.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * LeftRegularEquationSolver.cpp - * - * Created on: 4. 3. 2014 - * Author: Tomas Pecka - */ - -#include "LeftRegularEquationSolver.h" -#include "regexp/unbounded/UnboundedRegExpElements.h" - -#include "../regexp/simplify/RegExpOptimize.h" - -namespace equations { - -regexp::UnboundedRegExp < > LeftRegularEquationSolver::eliminate(void) { - 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 < alphabet::Symbol > loop(std::move(equationTransition.find(std::make_pair(a, a))->second)); - regexp::simplify::RegExpOptimize::optimize(loop); - - // for all transitions from A apply Arden's Lemma - for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); ++ itB) { - const alphabet::Symbol& b = * itB; - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(std::move(equationTransition.find(std::make_pair(a, b))->second)); - concat.appendElement(loop); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(concat)); - equationTransition.find(std::make_pair(a, b))->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(a, b))->second); - } - - { - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(std::move(equationFinal.find(a)->second)); - concat.appendElement(std::move(loop)); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(concat)); - equationFinal.find(a)->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationFinal.find(a)->second); - } - - /* - * eliminate A from rest of the equations using this pattern: - * B->C = B->C + concatenate(B->A, A->C) - */ - for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); ++ itB) { - const alphabet::Symbol& b = * itB; - - for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); ++ itC) { - const alphabet::Symbol& c = * itC; - - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(equationTransition.find(std::make_pair(a, c))->second); - concat.appendElement(equationTransition.find(std::make_pair(b, a))->second); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - 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); - regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(b, c))->second); - } - - { - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(equationFinal.find(a)->second); - concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second)); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(equationFinal.find(b)->second)); - alt.appendElement(std::move(concat)); - equationFinal.find(b)->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationFinal.find(b)->second); - } - } - } - - return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < alphabet::Symbol > (std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second)))); -} - -} /* namespace equations */ diff --git a/alib2algo/src/equations/LeftRegularEquationSolver.h b/alib2algo/src/equations/LeftRegularEquationSolver.h index a4de207c74..fdb18f60af 100644 --- a/alib2algo/src/equations/LeftRegularEquationSolver.h +++ b/alib2algo/src/equations/LeftRegularEquationSolver.h @@ -5,21 +5,96 @@ LeftghtRegularEquationSolver.h * Author: Tomas Pecka */ -#ifndef LEFTREGULAREQUATIONSOLVER_H_ -#define LEFTREGULAREQUATIONSOLVER_H_ +#ifndef LEFT_REGULAR_EQUATIONS_SOLVER_H_ +#define LEFT_REGULAR_EQUATIONS_SOLVER_H_ #include "RegularEquationSolver.h" +#include "regexp/unbounded/UnboundedRegExpElements.h" + +#include <regexp/simplify/RegExpOptimize.h> namespace equations { -class LeftRegularEquationSolver : public RegularEquationSolver { +template < class SymbolType > +class LeftRegularEquationSolver : public RegularEquationSolver < SymbolType > { /** * @copydoc RegularEquationSolver::eliminate(void) */ - virtual regexp::UnboundedRegExp < > eliminate( void ); + virtual regexp::UnboundedRegExp < SymbolType > eliminate( void ); }; +template < class SymbolType > +regexp::UnboundedRegExp < SymbolType > LeftRegularEquationSolver < SymbolType >::eliminate(void) { + for(auto itA = this->nonterminalSymbolsByDepth.rbegin(); itA != this->nonterminalSymbolsByDepth.rend(); ++ itA) { + const SymbolType& a = * itA; + + /* + * Apply Arden's Lemma + * A = A0 + B1 + C2 + * => A = 10*B + 20*C + */ + regexp::UnboundedRegExpIteration < SymbolType > loop(std::move(this->equationTransition.find(std::make_pair(a, a))->second)); + regexp::simplify::RegExpOptimize::optimize(loop); + + // for all transitions from A apply Arden's Lemma + for(auto itB = std::next(itA) ; itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) { + const SymbolType& b = * itB; + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(std::move(this->equationTransition.find(std::make_pair(a, b))->second)); + concat.appendElement(loop); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(concat)); + this->equationTransition.find(std::make_pair(a, b))->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(a, b))->second); + } + + { + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(std::move(this->equationFinal.find(a)->second)); + concat.appendElement(std::move(loop)); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(concat)); + this->equationFinal.find(a)->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(a)->second); + } + + /* + * eliminate A from rest of the equations using this pattern: + * B->C = B->C + concatenate(B->A, A->C) + */ + for(auto itB = std::next(itA); itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) { + const SymbolType& b = * itB; + + for(auto itC = std::next(itA); itC != this->nonterminalSymbolsByDepth.rend(); ++ itC) { + const SymbolType& c = * itC; + + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(this->equationTransition.find(std::make_pair(a, c))->second); + concat.appendElement(this->equationTransition.find(std::make_pair(b, a))->second); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(this->equationTransition.find(std::make_pair(b, c))->second)); + alt.appendElement(std::move(concat)); + this->equationTransition.find(std::make_pair(b, c))->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(b, c))->second); + } + + { + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(this->equationFinal.find(a)->second); + concat.appendElement(std::move(this->equationTransition.find(std::make_pair(b, a))->second)); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(this->equationFinal.find(b)->second)); + alt.appendElement(std::move(concat)); + this->equationFinal.find(b)->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(b)->second); + } + } + } + + return regexp::UnboundedRegExp < SymbolType > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < SymbolType > (std::move( this->equationFinal.find(*this->nonterminalSymbolsByDepth.begin())->second)))); +} + } /* namespace equations */ -#endif /* LEFTREGULAREQUATIONSOLVER_H_ */ +#endif /* LEFT_REGULAR_EQUATIONS_SOLVER_H_ */ diff --git a/alib2algo/src/equations/RegularEquationSolver.cpp b/alib2algo/src/equations/RegularEquationSolver.cpp deleted file mode 100644 index 25bb443842..0000000000 --- a/alib2algo/src/equations/RegularEquationSolver.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * RegularEquationSolver.cpp - * - * Created on: 4. 3. 2014 - * Author: Tomas Pecka - */ - -#include "RegularEquationSolver.h" -#include <regexp/unbounded/UnboundedRegExpElements.h> - -#include <exception/CommonException.h> -#include <algorithm> - -namespace equations { - -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())); - - for(const auto& symb : removed) { - removeSymbol(symb); - } - - for(const auto& symb : added) { - addSymbol(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 < alphabet::Symbol > & alt = kv.second; - - if((from == symb || to == symb) && alt.getElements().size() != 0) { - throw exception::CommonException("Symbol '" + (std::string) symb + "' is in use."); - } - } - - for(const auto& kv : equationFinal) { - const alphabet::Symbol& from = kv.first; - const regexp::UnboundedRegExpAlternation < alphabet::Symbol > & alt = kv.second; - - if(from == symb && alt.getElements().size() != 0) { - throw exception::CommonException("Symbol '" + (std::string) from + "' is in use."); - } - } - - - nonterminalSymbols.erase(nonterminalSymbols.find(symb)); - equationFinal.erase(equationFinal.find(symb)); - - 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 < alphabet::Symbol > { })); - equationTransition.insert(std::make_pair(std::make_pair(s, symb), regexp::UnboundedRegExpAlternation < alphabet::Symbol > { })); - } - equationTransition.insert(std::make_pair(std::make_pair(symb, symb), regexp::UnboundedRegExpAlternation < alphabet::Symbol > { })); - - nonterminalSymbols.insert(symb); - equationFinal.insert(std::make_pair(symb, regexp::UnboundedRegExpAlternation < alphabet::Symbol > { })); -} - -void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq) { - if(nonterminalSymbols.count(from) == 0) { - throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system."); - } - - if(nonterminalSymbols.count(to) == 0) { - throw exception::CommonException("Symbol to ('" + (std::string) to + "') is not in equation system."); - } - - equationTransition.find(std::make_pair(from, to))->second.appendElement(eq); -} - -void RegularEquationSolver::addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq) { - if(nonterminalSymbols.count(from) == 0) { - throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system."); - } - - equationFinal.find(from)->second.appendElement(eq); -} - -void RegularEquationSolver::sortSymbolsByDepth(const alphabet::Symbol& solveFor) { - std::map<alphabet::Symbol, bool> visited; - std::queue<alphabet::Symbol> queue; - - for(const auto& symbol : nonterminalSymbols) { - visited[symbol] = false; - } - - visited[solveFor] = true; - queue.push(solveFor); - - while(! queue.empty()) { - alphabet::Symbol s = queue.front(); - queue.pop(); - - nonterminalSymbolsByDepth.push_back(s); - - 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::CommonException("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 2efe44f826..e23a332e3d 100644 --- a/alib2algo/src/equations/RegularEquationSolver.h +++ b/alib2algo/src/equations/RegularEquationSolver.h @@ -5,31 +5,34 @@ * Author: Tomas Pecka */ -#ifndef REGULAREQUATIONSOLVER_H_ -#define REGULAREQUATIONSOLVER_H_ - -#include <regexp/unbounded/UnboundedRegExp.h> -#include <regexp/unbounded/UnboundedRegExpElement.h> -#include <alphabet/Symbol.h> +#ifndef REGULAR_EQUATIONS_SOLVER_H_ +#define REGULAR_EQUATIONS_SOLVER_H_ +#include <algorithm> #include <map> #include <deque> #include <queue> +#include <exception/CommonException.h> + +#include <regexp/unbounded/UnboundedRegExp.h> +#include <regexp/unbounded/UnboundedRegExpElement.h> +#include <regexp/unbounded/UnboundedRegExpElements.h> + namespace equations { /** * Base class for regular equations solvers. */ +template < class SymbolType > class RegularEquationSolver { public: /** * Adds nonterminal symbol into system. * * @param symb given symbol - * @ */ - void addSymbol(const alphabet::Symbol& symbol); + void addSymbol(const SymbolType& symbol); /** * Removes nonterminal symbol from equation system. @@ -37,14 +40,14 @@ public: * @param symb given symbol * @throws CommonException when symbol is in use */ - void removeSymbol(const alphabet::Symbol& symbol); + void removeSymbol(const SymbolType& symbol); /** * Sets nonterminal symbols of the equation system. * @param symbol Symbols to set * @throws CommonException */ - void setSymbols(const std::set<alphabet::Symbol>& symbols); + void setSymbols(const std::set<SymbolType>& symbols); /** * Adds equation in form FROM = eq TO @@ -53,7 +56,7 @@ public: * @param to symbol * @param eq equation */ - void addEquation(const alphabet::Symbol& from, const alphabet::Symbol& to, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq); + void addEquation(const SymbolType& from, const SymbolType& to, const regexp::UnboundedRegExpElement < SymbolType > & eq); /** * Adds equation in form: FROM = eq @@ -61,7 +64,7 @@ public: * @param from * @param eq */ - void addEquation(const alphabet::Symbol& from, const regexp::UnboundedRegExpElement < alphabet::Symbol > & eq); + void addEquation(const SymbolType& from, const regexp::UnboundedRegExpElement < SymbolType > & eq); /** * Solve expression system @@ -69,42 +72,167 @@ public: * @param solveFor will solve equation system for given symbol * @return regexp */ - regexp::UnboundedRegExp < > solve(const alphabet::Symbol& solveFor); + regexp::UnboundedRegExp < SymbolType > solve(const SymbolType& solveFor); protected: /** * actual equations elimination * @return pointer to solutions RegExp tree root */ - virtual regexp::UnboundedRegExp < > eliminate(void) = 0; + virtual regexp::UnboundedRegExp < SymbolType > eliminate(void) = 0; /** * Runs BFS to determine depth of symbols in equation system and stores it in nonterminalSymbolsByDepth; * @see nonterminalSymbolsByDepth */ - void sortSymbolsByDepth(const alphabet::Symbol& solveFor); + void sortSymbolsByDepth(const SymbolType& solveFor); /** * @see symbolsByDepth */ - std::deque<alphabet::Symbol> nonterminalSymbolsByDepth; + std::deque<SymbolType> nonterminalSymbolsByDepth; /** * Stores transitions from nonterminal to nonterminal, eg A = 2A + 2B + 1C */ - std::map<std::pair<alphabet::Symbol, alphabet::Symbol>, regexp::UnboundedRegExpAlternation < alphabet::Symbol > > equationTransition; + std::map<std::pair<SymbolType, SymbolType>, regexp::UnboundedRegExpAlternation < SymbolType > > equationTransition; /** * Stores equation not going to particular nonterminal, eg A = 01* */ - std::map<alphabet::Symbol, regexp::UnboundedRegExpAlternation < alphabet::Symbol > > equationFinal; + std::map<SymbolType, regexp::UnboundedRegExpAlternation < SymbolType > > equationFinal; /** * Set of symbols */ - std::set<alphabet::Symbol> nonterminalSymbols; + std::set<SymbolType> nonterminalSymbols; }; +template < class SymbolType > +void RegularEquationSolver < SymbolType >::setSymbols(const std::set<SymbolType>& newSymbols) { + std::set<SymbolType> 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())); + + for(const auto& symb : removed) { + removeSymbol(symb); + } + + for(const auto& symb : added) { + addSymbol(symb); + } +} + +template < class SymbolType > +void RegularEquationSolver < SymbolType >::removeSymbol(const SymbolType& symb) { + for(const auto& kv : equationTransition) { + const SymbolType& from = kv.first.first; + const SymbolType& to = kv.first.second; + const regexp::UnboundedRegExpAlternation < SymbolType > & alt = kv.second; + + if((from == symb || to == symb) && alt.getElements().size() != 0) { + throw exception::CommonException("Symbol '" + (std::string) symb + "' is in use."); + } + } + + for(const auto& kv : equationFinal) { + const SymbolType& from = kv.first; + const regexp::UnboundedRegExpAlternation < SymbolType > & alt = kv.second; + + if(from == symb && alt.getElements().size() != 0) { + throw exception::CommonException("Symbol '" + (std::string) from + "' is in use."); + } + } + + + nonterminalSymbols.erase(nonterminalSymbols.find(symb)); + equationFinal.erase(equationFinal.find(symb)); + + 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))); +} + +template < class SymbolType > +void RegularEquationSolver < SymbolType >::addSymbol(const SymbolType& symb) { + for(const auto& s : nonterminalSymbols) { + equationTransition.insert(std::make_pair(std::make_pair(symb, s), regexp::UnboundedRegExpAlternation < SymbolType > { })); + equationTransition.insert(std::make_pair(std::make_pair(s, symb), regexp::UnboundedRegExpAlternation < SymbolType > { })); + } + equationTransition.insert(std::make_pair(std::make_pair(symb, symb), regexp::UnboundedRegExpAlternation < SymbolType > { })); + + nonterminalSymbols.insert(symb); + equationFinal.insert(std::make_pair(symb, regexp::UnboundedRegExpAlternation < SymbolType > { })); +} + +template < class SymbolType > +void RegularEquationSolver < SymbolType >::addEquation(const SymbolType& from, const SymbolType& to, const regexp::UnboundedRegExpElement < SymbolType > & eq) { + if(nonterminalSymbols.count(from) == 0) { + throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system."); + } + + if(nonterminalSymbols.count(to) == 0) { + throw exception::CommonException("Symbol to ('" + (std::string) to + "') is not in equation system."); + } + + equationTransition.find(std::make_pair(from, to))->second.appendElement(eq); +} + +template < class SymbolType > +void RegularEquationSolver < SymbolType >::addEquation(const SymbolType& from, const regexp::UnboundedRegExpElement < SymbolType > & eq) { + if(nonterminalSymbols.count(from) == 0) { + throw exception::CommonException("Symbol from ('" + (std::string) from + "') is not in equation system."); + } + + equationFinal.find(from)->second.appendElement(eq); +} + +template < class SymbolType > +void RegularEquationSolver < SymbolType >::sortSymbolsByDepth(const SymbolType& solveFor) { + std::map<SymbolType, bool> visited; + std::queue<SymbolType> queue; + + for(const auto& symbol : nonterminalSymbols) { + visited[symbol] = false; + } + + visited[solveFor] = true; + queue.push(solveFor); + + while(! queue.empty()) { + SymbolType s = queue.front(); + queue.pop(); + + nonterminalSymbolsByDepth.push_back(s); + + 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); + } + } + } +} + +template < class SymbolType > +regexp::UnboundedRegExp < SymbolType > RegularEquationSolver < SymbolType >::solve(const SymbolType& solveFor) { + if(nonterminalSymbols.count(solveFor) == 0) { + throw exception::CommonException("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 */ -#endif /* REGULAREQUATIONSOLVER_H_ */ +#endif /* REGULAR_EQUATIONS_SOLVER_H_ */ diff --git a/alib2algo/src/equations/RightRegularEquationSolver.cpp b/alib2algo/src/equations/RightRegularEquationSolver.cpp deleted file mode 100644 index aa32ad7b38..0000000000 --- a/alib2algo/src/equations/RightRegularEquationSolver.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * RightRegularEquationSolver.cpp - * - * Created on: 4. 3. 2014 - * Author: Tomas Pecka - */ - -#include "RightRegularEquationSolver.h" -#include "regexp/unbounded/UnboundedRegExpElements.h" - -#include "../regexp/simplify/RegExpOptimize.h" - -namespace equations { - -regexp::UnboundedRegExp < > RightRegularEquationSolver::eliminate(void) { - 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 < alphabet::Symbol > loop(std::move(equationTransition.find(std::make_pair(a, a))->second)); - regexp::simplify::RegExpOptimize::optimize(loop); - - // for all transitions from A apply Arden's Lemma - for(auto itB = std::next(itA) ; itB != nonterminalSymbolsByDepth.rend(); ++ itB) { - const alphabet::Symbol& b = * itB; - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(loop); - concat.appendElement(std::move(equationTransition.find(std::make_pair(a,b))->second)); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(concat)); - equationTransition.find(std::make_pair(a, b))->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(a, b))->second); - } - - { - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(std::move(loop)); - concat.appendElement(std::move(equationFinal.find(a)->second)); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(concat)); - equationFinal.find(a)->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationFinal.find(a)->second); - } - - /* - * eliminate A from rest of the equations using this pattern: - * B->C = B->C + concatenate(B->A, A->C) - */ - for(auto itB = std::next(itA); itB != nonterminalSymbolsByDepth.rend(); ++ itB) { - const alphabet::Symbol& b = * itB; - - for(auto itC = std::next(itA); itC != nonterminalSymbolsByDepth.rend(); ++ itC) { - const alphabet::Symbol& c = * itC; - - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(equationTransition.find(std::make_pair(b, a))->second); - concat.appendElement(equationTransition.find(std::make_pair(a, c))->second); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - 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); - regexp::simplify::RegExpOptimize::optimize(equationTransition.find(std::make_pair(b, c))->second); - } - - { - regexp::UnboundedRegExpConcatenation < alphabet::Symbol > concat; - concat.appendElement(std::move(equationTransition.find(std::make_pair(b, a))->second)); - concat.appendElement(equationFinal.find(a)->second); - regexp::UnboundedRegExpAlternation < alphabet::Symbol > alt; - alt.appendElement(std::move(equationFinal.find(b)->second)); - alt.appendElement(std::move(concat)); - equationFinal.find(b)->second = std::move(alt); - regexp::simplify::RegExpOptimize::optimize(equationFinal.find(b)->second); - } - } - } - - return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < alphabet::Symbol > (std::move( equationFinal.find(*nonterminalSymbolsByDepth.begin())->second)))); -} - -} /* namespace equations */ diff --git a/alib2algo/src/equations/RightRegularEquationSolver.h b/alib2algo/src/equations/RightRegularEquationSolver.h index 1a4cf23cb7..bcbec40f44 100644 --- a/alib2algo/src/equations/RightRegularEquationSolver.h +++ b/alib2algo/src/equations/RightRegularEquationSolver.h @@ -5,21 +5,96 @@ * Author: Tomas Pecka */ -#ifndef RIGHTREGULAREQUATIONSOLVER_H_ -#define RIGHTREGULAREQUATIONSOLVER_H_ +#ifndef RIGHT_REGULAR_EQUATIONS_SOLVER_H_ +#define RIGHT_REGULAR_EQUATIONS_SOLVER_H_ #include "RegularEquationSolver.h" +#include "regexp/unbounded/UnboundedRegExpElements.h" + +#include <regexp/simplify/RegExpOptimize.h> namespace equations { -class RightRegularEquationSolver : public RegularEquationSolver { +template < class SymbolType > +class RightRegularEquationSolver : public RegularEquationSolver < SymbolType > { /** * @copydoc RegularEquationSolver::eliminate(void) */ - virtual regexp::UnboundedRegExp < > eliminate( void ); + virtual regexp::UnboundedRegExp < SymbolType > eliminate( void ); }; +template < class SymbolType > +regexp::UnboundedRegExp < SymbolType > RightRegularEquationSolver < SymbolType >::eliminate(void) { + for(auto itA = this->nonterminalSymbolsByDepth.rbegin(); itA != this->nonterminalSymbolsByDepth.rend(); ++ itA) { + const SymbolType& a = * itA; + + /* + * Apply Arden's Lemma + * A = 0A + 1B + 2C + * => A = 0*1B + 0*2C + */ + regexp::UnboundedRegExpIteration < SymbolType > loop(std::move(this->equationTransition.find(std::make_pair(a, a))->second)); + regexp::simplify::RegExpOptimize::optimize(loop); + + // for all transitions from A apply Arden's Lemma + for(auto itB = std::next(itA) ; itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) { + const SymbolType& b = * itB; + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(loop); + concat.appendElement(std::move(this->equationTransition.find(std::make_pair(a,b))->second)); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(concat)); + this->equationTransition.find(std::make_pair(a, b))->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(a, b))->second); + } + + { + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(std::move(loop)); + concat.appendElement(std::move(this->equationFinal.find(a)->second)); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(concat)); + this->equationFinal.find(a)->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(a)->second); + } + + /* + * eliminate A from rest of the equations using this pattern: + * B->C = B->C + concatenate(B->A, A->C) + */ + for(auto itB = std::next(itA); itB != this->nonterminalSymbolsByDepth.rend(); ++ itB) { + const SymbolType& b = * itB; + + for(auto itC = std::next(itA); itC != this->nonterminalSymbolsByDepth.rend(); ++ itC) { + const SymbolType& c = * itC; + + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(this->equationTransition.find(std::make_pair(b, a))->second); + concat.appendElement(this->equationTransition.find(std::make_pair(a, c))->second); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(this->equationTransition.find(std::make_pair(b, c))->second)); + alt.appendElement(std::move(concat)); + this->equationTransition.find(std::make_pair(b, c))->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationTransition.find(std::make_pair(b, c))->second); + } + + { + regexp::UnboundedRegExpConcatenation < SymbolType > concat; + concat.appendElement(std::move(this->equationTransition.find(std::make_pair(b, a))->second)); + concat.appendElement(this->equationFinal.find(a)->second); + regexp::UnboundedRegExpAlternation < SymbolType > alt; + alt.appendElement(std::move(this->equationFinal.find(b)->second)); + alt.appendElement(std::move(concat)); + this->equationFinal.find(b)->second = std::move(alt); + regexp::simplify::RegExpOptimize::optimize(this->equationFinal.find(b)->second); + } + } + } + + return regexp::UnboundedRegExp < SymbolType > (regexp::simplify::RegExpOptimize::optimize(regexp::UnboundedRegExpStructure < SymbolType > (std::move( this->equationFinal.find(*this->nonterminalSymbolsByDepth.begin())->second)))); +} + } /* namespace equations */ -#endif /* RIGHTREGULAREQUATIONSOLVER_H_ */ +#endif /* RIGHT_REGULAR_EQUATIONS_SOLVER_H_ */ diff --git a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp index a424fb484c..a1203f3896 100644 --- a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp +++ b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.cpp @@ -7,12 +7,6 @@ #include "ToRegExpAlgebraic.h" -#include "../../equations/LeftRegularEquationSolver.h" -#include "../../equations/RightRegularEquationSolver.h" - -#include <regexp/unbounded/UnboundedRegExp.h> -#include <regexp/unbounded/UnboundedRegExpElements.h> - namespace grammar { namespace convert { @@ -21,59 +15,8 @@ regexp::RegExp ToRegExpAlgebraic::convert(const grammar::Grammar& grammar) { return dispatch(grammar.getData()); } -regexp::RegExp ToRegExpAlgebraic::convert(const grammar::LeftRG < > & grammar) { - equations::LeftRegularEquationSolver solver; - - for(const auto& symbol : grammar.getNonterminalAlphabet()) - solver.addSymbol(symbol); - - for(const auto & rule : grammar.getRules()) { - const alphabet::Symbol& lhs = rule.first; - - for(const auto& ruleRHS : rule.second) { - if(ruleRHS.is<alphabet::Symbol>()) { - const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); - solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs)); - } else { - const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); - solver.addEquation(lhs, rhs.first, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs.second)); - } - } - } - if(grammar.getGeneratesEpsilon()) - solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < alphabet::Symbol > ()); - - return regexp::RegExp{solver.solve(grammar.getInitialSymbol())}; -} - -auto ToRegExpAlgebraicLeftRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::RegExp, grammar::LeftRG < > >(ToRegExpAlgebraic::convert); - -regexp::RegExp ToRegExpAlgebraic::convert(const grammar::RightRG < > & grammar) { - equations::RightRegularEquationSolver solver; - - for(const auto& symbol : grammar.getNonterminalAlphabet()) - solver.addSymbol(symbol); - - for(const auto & rule : grammar.getRules()) { - const alphabet::Symbol& lhs = rule.first; - - for(const auto& ruleRHS : rule.second) { - if(ruleRHS.is<alphabet::Symbol>()) { - const alphabet::Symbol& rhs = ruleRHS.get<alphabet::Symbol>(); - solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs)); - } else { - const std::pair<alphabet::Symbol, alphabet::Symbol>& rhs = ruleRHS.get<std::pair<alphabet::Symbol, alphabet::Symbol>>(); - solver.addEquation(lhs, rhs.second, regexp::UnboundedRegExpSymbol < alphabet::Symbol > (rhs.first)); - } - } - } - if(grammar.getGeneratesEpsilon()) - solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < alphabet::Symbol > ()); - - return regexp::RegExp{solver.solve(grammar.getInitialSymbol())}; -} - -auto ToRegExpAlgebraicRightRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::RegExp, grammar::RightRG < > >(ToRegExpAlgebraic::convert); +auto ToRegExpAlgebraicLeftRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, grammar::LeftRG < > >(ToRegExpAlgebraic::convert); +auto ToRegExpAlgebraicRightRG = ToRegExpAlgebraic::RegistratorWrapper<regexp::UnboundedRegExp < >, grammar::RightRG < > >(ToRegExpAlgebraic::convert); } /* namespace convert */ diff --git a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h index a2db458e5f..51d2da4c64 100644 --- a/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h +++ b/alib2algo/src/grammar/convert/ToRegExpAlgebraic.h @@ -16,6 +16,12 @@ #include <regexp/RegExp.h> +#include <equations/LeftRegularEquationSolver.h> +#include <equations/RightRegularEquationSolver.h> + +#include <regexp/unbounded/UnboundedRegExp.h> +#include <regexp/unbounded/UnboundedRegExpElements.h> + namespace grammar { namespace convert { @@ -28,10 +34,64 @@ public: */ static regexp::RegExp convert(const grammar::Grammar& grammar); - static regexp::RegExp convert(const grammar::RightRG < > & grammar); - static regexp::RegExp convert(const grammar::LeftRG < > & grammar); + template < class SymbolType > + static regexp::UnboundedRegExp < SymbolType > convert(const grammar::RightRG < SymbolType > & grammar); + template < class SymbolType > + static regexp::UnboundedRegExp < SymbolType > convert(const grammar::LeftRG < SymbolType > & grammar); }; +template < class SymbolType > +regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert(const grammar::LeftRG < SymbolType > & grammar) { + equations::LeftRegularEquationSolver < SymbolType > solver; + + for(const auto& symbol : grammar.getNonterminalAlphabet()) + solver.addSymbol(symbol); + + for(const auto & rule : grammar.getRules()) { + const SymbolType& lhs = rule.first; + + for(const auto& ruleRHS : rule.second) { + if(ruleRHS.template is<SymbolType>()) { + const SymbolType& rhs = ruleRHS.template get<SymbolType>(); + solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < SymbolType > (rhs)); + } else { + const std::pair<SymbolType, SymbolType>& rhs = ruleRHS.template get<std::pair<SymbolType, SymbolType>>(); + solver.addEquation(lhs, rhs.first, regexp::UnboundedRegExpSymbol < SymbolType > (rhs.second)); + } + } + } + if(grammar.getGeneratesEpsilon()) + solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < SymbolType > ()); + + return solver.solve(grammar.getInitialSymbol()); +} + +template < class SymbolType > +regexp::UnboundedRegExp < SymbolType > ToRegExpAlgebraic::convert(const grammar::RightRG < SymbolType > & grammar) { + equations::RightRegularEquationSolver < SymbolType > solver; + + for(const auto& symbol : grammar.getNonterminalAlphabet()) + solver.addSymbol(symbol); + + for(const auto & rule : grammar.getRules()) { + const SymbolType& lhs = rule.first; + + for(const auto& ruleRHS : rule.second) { + if(ruleRHS.template is<SymbolType>()) { + const SymbolType& rhs = ruleRHS.template get<SymbolType>(); + solver.addEquation(lhs, regexp::UnboundedRegExpSymbol < SymbolType > (rhs)); + } else { + const std::pair<SymbolType, SymbolType>& rhs = ruleRHS.template get<std::pair<SymbolType, SymbolType>>(); + solver.addEquation(lhs, rhs.second, regexp::UnboundedRegExpSymbol < SymbolType > (rhs.first)); + } + } + } + if(grammar.getGeneratesEpsilon()) + solver.addEquation(grammar.getInitialSymbol(), regexp::UnboundedRegExpEpsilon < SymbolType > ()); + + return solver.solve(grammar.getInitialSymbol()); +} + } /* namespace covert */ } /* namespace grammar */ -- GitLab