Newer
Older
/*
* RegularEquationSolver.h
*
* Created on: 4. 3. 2014
#ifndef REGULAR_EQUATIONS_SOLVER_H_
#define REGULAR_EQUATIONS_SOLVER_H_
#include <alib/algorithm>
#include <alib/map>
#include <alib/deque>
#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 TerminalSymbolType, class VariableSymbolType >
public:
/**
* Adds nonterminal symbol into system.
*
* @param symb given symbol
void addVariableSymbol ( const VariableSymbolType & symbol );
/**
* Removes nonterminal symbol from equation system.
*
* @param symb given symbol
* @throws CommonException when symbol is in use
void removeVariableSymbol ( const VariableSymbolType & symbol );
/**
* Sets nonterminal symbols of the equation system.
* @param symbol Symbols to set
void setVariableSymbols ( const ext::set < VariableSymbolType > & symbols );
/**
* Adds equation in form FROM = eq TO
*
* @param from symbol
* @param to symbol
* @param eq equation
*/
void addEquation ( const VariableSymbolType & from, const VariableSymbolType & to, const regexp::UnboundedRegExpElement < TerminalSymbolType > & eq );
/**
* Adds equation in form: FROM = eq
*
* @param from
* @param eq
*/
void addEquation ( const VariableSymbolType & from, const regexp::UnboundedRegExpElement < TerminalSymbolType > & eq );
/**
* Solve expression system
*
* @param solveFor will solve equation system for given symbol
* @return regexp
*/
regexp::UnboundedRegExp < TerminalSymbolType > solve ( const VariableSymbolType & solveFor );
protected:
/**
* actual equations elimination
* @return pointer to solutions RegExp tree root
*/
virtual regexp::UnboundedRegExp < TerminalSymbolType > eliminate ( void ) = 0;
* Runs BFS to determine depth of symbols in equation system and stores it in nonterminalSymbolsByDepth;
* @see nonterminalSymbolsByDepth
void sortSymbolsByDepth ( const VariableSymbolType & solveFor );
/**
* @see symbolsByDepth
*/
ext::deque < VariableSymbolType > nonterminalSymbolsByDepth;
/**
* Stores transitions from nonterminal to nonterminal, eg A = 2A + 2B + 1C
*/
ext::map < std::pair < VariableSymbolType, VariableSymbolType >, regexp::UnboundedRegExpAlternation < TerminalSymbolType > > equationTransition;
/**
* Stores equation not going to particular nonterminal, eg A = 01*
*/
ext::map < VariableSymbolType, regexp::UnboundedRegExpAlternation < TerminalSymbolType > > equationFinal;
/**
* Set of symbols
*/
ext::set < VariableSymbolType > nonterminalSymbols;
template < class TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::setVariableSymbols ( const ext::set < VariableSymbolType > & newSymbols ) {
ext::set < VariableSymbolType > removed;
ext::set < VariableSymbolType > 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 VariableSymbolType & symb : removed ) {
removeVariableSymbol ( symb );
for ( const VariableSymbolType & symb : added ) {
addVariableSymbol ( symb );
template < class TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::removeVariableSymbol ( const VariableSymbolType & symb ) {
for ( const auto & kv : equationTransition ) {
const VariableSymbolType & from = kv.first.first;
const VariableSymbolType & to = kv.first.second;
const regexp::UnboundedRegExpAlternation < TerminalSymbolType > & alt = kv.second;
if ( ( from == symb || to == symb ) && !alt.getElements ( ).empty ( ) ) {
throw exception::CommonException ( "Symbol '" + ext::to_string ( symb ) + "' is in use." );
for ( const auto & kv : equationFinal ) {
const VariableSymbolType & from = kv.first;
const regexp::UnboundedRegExpAlternation < TerminalSymbolType > & alt = kv.second;
if ( from == symb && !alt.getElements ( ).empty ( ) ) {
throw exception::CommonException ( "Symbol '" + ext::to_string ( from ) + "' is in use." );
nonterminalSymbols.erase ( nonterminalSymbols.find ( symb ) );
equationFinal.erase ( equationFinal.find ( symb ) );
for ( const VariableSymbolType & 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 TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::addVariableSymbol ( const VariableSymbolType & symb ) {
for ( const VariableSymbolType & s : nonterminalSymbols) {
equationTransition.insert ( std::make_pair ( std::make_pair ( symb, s ), regexp::UnboundedRegExpAlternation < TerminalSymbolType > { } ) );
equationTransition.insert ( std::make_pair ( std::make_pair ( s, symb ), regexp::UnboundedRegExpAlternation < TerminalSymbolType > { } ) );
equationTransition.insert ( std::make_pair ( std::make_pair ( symb, symb ), regexp::UnboundedRegExpAlternation < TerminalSymbolType > { } ) );
nonterminalSymbols.insert ( symb );
equationFinal.insert ( std::make_pair ( symb, regexp::UnboundedRegExpAlternation < TerminalSymbolType > { } ) );
template < class TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::addEquation ( const VariableSymbolType & from, const VariableSymbolType & to, const regexp::UnboundedRegExpElement < TerminalSymbolType > & eq ) {
if ( nonterminalSymbols.count ( from ) == 0 ) {
throw exception::CommonException ( "Symbol from ('" + ext::to_string ( from ) + "') is not in equation system." );
if ( nonterminalSymbols.count ( to ) == 0 ) {
throw exception::CommonException ( "Symbol to ('" + ext::to_string ( to ) + "') is not in equation system." );
equationTransition.find ( std::make_pair ( from, to ) )->second.appendElement ( eq );
template < class TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::addEquation ( const VariableSymbolType & from, const regexp::UnboundedRegExpElement < TerminalSymbolType > & eq ) {
if ( nonterminalSymbols.count ( from ) == 0 ) {
throw exception::CommonException ( "Symbol from ('" + ext::to_string ( from ) + "') is not in equation system." );
equationFinal.find ( from )->second.appendElement ( eq );
template < class TerminalSymbolType, class VariableSymbolType >
void RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::sortSymbolsByDepth ( const VariableSymbolType & solveFor ) {
ext::map < VariableSymbolType, bool > visited;
std::queue < VariableSymbolType > queue;
for(const VariableSymbolType & symbol : nonterminalSymbols ) {
visited [ symbol ] = false;
visited [ solveFor ] = true;
queue.push ( solveFor );
while ( ! queue.empty ( ) ) {
VariableSymbolType s = std::move ( 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 ( ).empty ( ) ) {
visited [ kv.first.second ] = true;
queue.push ( kv.first.second );
template < class TerminalSymbolType, class VariableSymbolType >
regexp::UnboundedRegExp < TerminalSymbolType > RegularEquationSolver < TerminalSymbolType, VariableSymbolType >::solve ( const VariableSymbolType & solveFor ) {
if ( nonterminalSymbols.count ( solveFor ) == 0 ) {
throw exception::CommonException ( "Symbol solveFor ('" + ext::to_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 ( );