diff --git a/alib2algo/src/regexp/simplify/RegExpOptimize.h b/alib2algo/src/regexp/simplify/RegExpOptimize.h index f96bdd2157a4ab5c07c03f2d340a2b0f520354aa..10b969194c1f38402bc0f13fabe34de7bfa8ee75 100644 --- a/alib2algo/src/regexp/simplify/RegExpOptimize.h +++ b/alib2algo/src/regexp/simplify/RegExpOptimize.h @@ -54,6 +54,7 @@ namespace simplify { * - V6 : <- : x*y = y + xx*y * - V7 : : bleh * - V8 : -> : if \e in h(x) => xx* = x* + * - V8R : -> : if \e in h(x) => x*x = x* * - V9 : -> : (xy)*x = x(yx)* * - V10: <- : ( x + y )* = ( x* + y* )* * @@ -108,12 +109,12 @@ private: template < class SymbolType > class Unbounded { public: - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpAlternation < SymbolType > && node ); - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpConcatenation < SymbolType > && node ); - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpIteration < SymbolType > && node ); - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpSymbol < SymbolType > && node ); - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpEmpty < SymbolType > && node ); - static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpEpsilon < SymbolType > && node ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpAlternation < SymbolType > && node, bool recursive ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpConcatenation < SymbolType > && node, bool recursive ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpIteration < SymbolType > && node, bool recursive ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpSymbol < SymbolType > && node, bool recursive ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpEmpty < SymbolType > && node, bool recursive ); + static ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > visit ( regexp::UnboundedRegExpEpsilon < SymbolType > && node, bool recursive ); static bool A1( regexp::UnboundedRegExpAlternation < SymbolType > & node ); static bool A2( regexp::UnboundedRegExpAlternation < SymbolType > & node ); @@ -133,6 +134,7 @@ private: static bool V5( regexp::UnboundedRegExpAlternation < SymbolType > & node ); static bool V6( regexp::UnboundedRegExpAlternation < SymbolType > & node ); static bool V8( regexp::UnboundedRegExpConcatenation < SymbolType > & node ); + static bool V8R( regexp::UnboundedRegExpConcatenation < SymbolType > & node ); static bool V9( regexp::UnboundedRegExpConcatenation < SymbolType > & node ); static bool V10( regexp::UnboundedRegExpIteration < SymbolType > & node ); @@ -210,7 +212,7 @@ template < class SymbolType > UnboundedRegExpStructure < SymbolType > RegExpOptimize::optimize( const UnboundedRegExpStructure < SymbolType > & regexp ) { UnboundedRegExpStructure < SymbolType > structure = regexp; - return regexp::UnboundedRegExpStructure < SymbolType > ( std::move ( structure.getStructure ( ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( ) ); + return regexp::UnboundedRegExpStructure < SymbolType > ( std::move ( structure.getStructure ( ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( true ) ); } } /* namespace simplify */ diff --git a/alib2algo/src/regexp/simplify/RegExpOptimizeUnboundedPart.hpp b/alib2algo/src/regexp/simplify/RegExpOptimizeUnboundedPart.hpp index 6b2de0e07bb146b9a059a5f96902ad4f0320a1d2..aafecc03a25774fb75451ba4ce1dd2242272f1ab 100644 --- a/alib2algo/src/regexp/simplify/RegExpOptimizeUnboundedPart.hpp +++ b/alib2algo/src/regexp/simplify/RegExpOptimizeUnboundedPart.hpp @@ -15,32 +15,41 @@ template < class SymbolType > void RegExpOptimize::optimize( UnboundedRegExpAlternation < SymbolType > & alt ) { while ( Unbounded < SymbolType >::A10 ( alt ) || Unbounded < SymbolType >::V2 ( alt ) || Unbounded < SymbolType >::V5 ( alt ) || Unbounded < SymbolType >::V6 ( alt ) ); - for( unsigned i = 0; i < alt.getChildren ( ).size ( ); i++ ) - alt.setChild ( std::move ( alt.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( ), i ); + for( size_t i = 0; i < alt.getChildren ( ).size ( ); i++ ) + alt.setChild ( std::move ( alt.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( true ), i ); while ( Unbounded < SymbolType >::A1( alt ) || Unbounded < SymbolType >::A2( alt ) || Unbounded < SymbolType >::A3( alt ) || Unbounded < SymbolType >::A4( alt ) || Unbounded < SymbolType >::A10( alt ) || Unbounded < SymbolType >::V2( alt ) || Unbounded < SymbolType >::V5( alt ) || Unbounded < SymbolType >::V6( alt ) || Unbounded < SymbolType >::X1( alt ) ); + + for( size_t i = 0; i < alt.getChildren ( ).size ( ); i++ ) + alt.setChild ( std::move ( alt.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( false ), i ); } template < class SymbolType > void RegExpOptimize::optimize( UnboundedRegExpConcatenation < SymbolType > & concat ) { - while ( Unbounded < SymbolType >::V8 ( concat ) ); + while ( Unbounded < SymbolType >::V8 ( concat ) || Unbounded < SymbolType >::V8R ( concat ) ); + + for( size_t i = 0; i < concat.getChildren ( ).size ( ); i++ ) + concat.setChild ( std::move ( concat.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( true ), i ); - for( unsigned i = 0; i < concat.getChildren ( ).size ( ); i++ ) - concat.setChild ( std::move ( concat.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( ), i ); + while ( Unbounded < SymbolType >::A5( concat ) || Unbounded < SymbolType >::A6( concat ) || Unbounded < SymbolType >::A7( concat ) || Unbounded < SymbolType >::A8( concat ) || Unbounded < SymbolType >::A9( concat ) || Unbounded < SymbolType >::V8( concat ) || Unbounded < SymbolType >::V8R( concat ) || Unbounded < SymbolType >::V9( concat ) ); - while ( Unbounded < SymbolType >::A5( concat ) || Unbounded < SymbolType >::A6( concat ) || Unbounded < SymbolType >::A7( concat ) || Unbounded < SymbolType >::A8( concat ) || Unbounded < SymbolType >::A9( concat ) || Unbounded < SymbolType >::V8( concat ) || Unbounded < SymbolType >::V9( concat ) ); + for( size_t i = 0; i < concat.getChildren ( ).size ( ); i++ ) + concat.setChild ( std::move ( concat.getChild ( i ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( false ), i ); } template < class SymbolType > void RegExpOptimize::optimize( UnboundedRegExpIteration < SymbolType > & iter ) { - iter.setChild ( std::move ( iter.getChild ( ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( ) ); + iter.setChild ( std::move ( iter.getChild ( ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( true ) ); while ( Unbounded < SymbolType >::A11( iter ) || Unbounded < SymbolType >::V1( iter ) || Unbounded < SymbolType >::V3( iter ) || Unbounded < SymbolType >::V4( iter ) || Unbounded < SymbolType >::V10( iter ) ); + + iter.setChild ( std::move ( iter.getChild ( ) ).template accept < ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > >, RegExpOptimize::Unbounded < SymbolType > > ( false ) ); } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit ( UnboundedRegExpAlternation < SymbolType > && alt ) { - optimize ( alt ); +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit ( UnboundedRegExpAlternation < SymbolType > && alt, bool recursive ) { + if ( recursive ) + optimize ( alt ); if( alt.getElements ( ).size( ) == 1 ) return ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > ( std::move ( alt.getChildren ( ).front ( ) ) ); @@ -52,8 +61,9 @@ ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize: } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpConcatenation < SymbolType > && concat ) { - optimize ( concat ); +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpConcatenation < SymbolType > && concat, bool recursive ) { + if ( recursive ) + optimize ( concat ); if( concat.getElements ( ).size( ) == 1 ) return ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > ( std::move ( concat.getChildren ( ).front ( ) ) ); @@ -65,8 +75,9 @@ ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize: } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpIteration < SymbolType > && iter ) { - optimize ( iter ); +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpIteration < SymbolType > && iter, bool recursive ) { + if ( recursive ) + optimize ( iter ); // V1 is implemented right here if( dynamic_cast < UnboundedRegExpEmpty < SymbolType > * > ( & iter.getChild ( ) ) ) @@ -80,17 +91,17 @@ ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize: } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpSymbol < SymbolType > && node ) { +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpSymbol < SymbolType > && node, bool ) { return ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > ( node ); } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpEmpty < SymbolType > && node ) { +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpEmpty < SymbolType > && node, bool ) { return ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > ( node ); } template < class SymbolType > -ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpEpsilon < SymbolType > && node ) { +ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > RegExpOptimize::Unbounded < SymbolType >::visit( UnboundedRegExpEpsilon < SymbolType > && node, bool ) { return ext::ptr_value < regexp::UnboundedRegExpElement < SymbolType > > ( node ); } @@ -352,45 +363,42 @@ bool RegExpOptimize::Unbounded < SymbolType >::A9( UnboundedRegExpConcatenation * @return bool true if optimization applied else false */ template < class SymbolType > -bool RegExpOptimize::Unbounded < SymbolType >::A10( UnboundedRegExpAlternation < SymbolType > & /* node */ ) { +bool RegExpOptimize::Unbounded < SymbolType >::A10( UnboundedRegExpAlternation < SymbolType > & node ) { bool optimized = false; /* * problem: * - \e + x*x = x* - * - but if we do not have the eps, but we do have iteration, then \e \in h(iter), therefore \e in h(node). + * - but if we do not have the eps, but we do have node that generates epsilon... It can actually be the x*x itself... */ // check if we have some epsilon or iteration left, else nothing to do - /*auto eps = find_if( node.getElements().begin( ), node.getElements().end( ), [ ]( const UnboundedRegExpElement < SymbolType > & a ) -> bool { - return dynamic_cast < const UnboundedRegExpEpsilon < SymbolType > * > ( & a ) || dynamic_cast < const UnboundedRegExpIteration < SymbolType > * > ( & a ); + auto eps = find_if( node.getElements().begin( ), node.getElements().end( ), [ ]( const UnboundedRegExpElement < SymbolType > & a ) -> bool { + return regexp::properties::RegExpEpsilon::languageContainsEpsilon ( a ); }); if( eps == node.getElements().end( ) ) return false; - for( unsigned i = 0; i < node.getChildren ( ).size ( ); i++ ) { - UnboundedRegExpConcatenation < SymbolType > * childConcat = dynamic_cast < UnboundedRegExpConcatenation < SymbolType > * > ( & node.getChildren ( ) [ i ] ); - if( ! childConcat ) + for( size_t i = 0; i < node.getChildren ( ).size ( ); i++ ) { + const UnboundedRegExpConcatenation < SymbolType > * childConcat = dynamic_cast < const UnboundedRegExpConcatenation < SymbolType > * > ( & node.getChildren ( ) [ i ] ); + if( ! childConcat || childConcat->getElements ( ).size ( ) < 2 ) continue; // if iteration is first element of concatenation - UnboundedRegExpIteration < SymbolType > * iter = dynamic_cast < UnboundedRegExpIteration < SymbolType > * > ( & childConcat->getElements ( ).front( ) ); + const UnboundedRegExpIteration < SymbolType > * iter = dynamic_cast < const UnboundedRegExpIteration < SymbolType > * > ( & childConcat->getElements ( ).front( ) ); if( ! iter ) continue; - // concatenation without the iteration node - UnboundedRegExpConcatenation < SymbolType > tmpConcat ( * childConcat ); - tmpConcat.getChildren ( ).erase ( tmpConcat.getChildren ( ).begin( ) ); - ext::ptr_value < UnboundedRegExpElement < SymbolType > > tmpConcatOpt = optimizeInner ( tmpConcat ); + // if element of iteration is concatenation, we need to check this specially + const UnboundedRegExpConcatenation < SymbolType > * concat = dynamic_cast < const UnboundedRegExpConcatenation < SymbolType > * > ( & iter->getChild ( ) ); - // check if the iteration element is the same as the rest of the concatenation - if( iter->getElement() == tmpConcatOpt ) { + if ( ( concat && equal ( concat->getChildren ( ).begin( ), concat->getChildren ( ).end ( ), childConcat->begin ( ) + 1 , childConcat->end ( ) ) ) || ( childConcat->getElements ( ).size ( ) == 2 && iter->getChild ( ) == childConcat->getElements ( ) [ 1 ] ) ) { optimized = true; node.setChild ( std::move ( childConcat->getElements().front() ), i ); } - } */ + } return optimized; } @@ -516,7 +524,7 @@ bool RegExpOptimize::Unbounded < SymbolType >::V4( UnboundedRegExpIteration < Sy for ( UnboundedRegExpElement < SymbolType > && n : ext::make_mover ( std::move ( * cont ).getChildren ( ) ) ) newAlt.pushBackChild ( std::move ( static_cast < UnboundedRegExpIteration < SymbolType > & > ( n ).getChild ( ) ) ); - node.setChild ( Unbounded < SymbolType >::visit ( std::move ( newAlt ) ) ); + node.setChild ( Unbounded < SymbolType >::visit ( std::move ( newAlt ), true ) ); return true; } @@ -558,7 +566,7 @@ bool RegExpOptimize::Unbounded < SymbolType >::V5( UnboundedRegExpAlternation < if( dynamic_cast < UnboundedRegExpConcatenation < SymbolType > * > ( & iter->getChild ( ) ) ) { UnboundedRegExpConcatenation < SymbolType > * iterConcat = dynamic_cast < UnboundedRegExpConcatenation < SymbolType > * > ( & iter->getChild ( ) ); - if( iterConcat->getChildren().size( ) != ( unsigned ) distance ( std::next ( itC ), concat->getChildren ( ).end ( ) ) + if( iterConcat->getChildren().size( ) != ( size_t ) distance ( std::next ( itC ), concat->getChildren ( ).end ( ) ) || ! equal ( iterConcat->getChildren ( ).begin ( ), iterConcat->getChildren ( ).end ( ), std::next ( itC ), [ ] ( const UnboundedRegExpElement < SymbolType > & a, const UnboundedRegExpElement < SymbolType > & b ) -> bool { return a == b; } ) ) { ++ itC; @@ -662,7 +670,7 @@ bool RegExpOptimize::Unbounded < SymbolType >::V6( UnboundedRegExpAlternation < } ext::retract ( itStartX, iterConcat->getChildren().size( ) ); - if( iterConcat->getChildren ( ).size( ) != ( unsigned ) distance( itStartX, concat->getChildren ( ).end( ) ) + if( iterConcat->getChildren ( ).size( ) != ( size_t ) distance( itStartX, concat->getChildren ( ).end( ) ) || ! equal ( iterConcat->getChildren ( ).begin ( ), iterConcat->getChildren ( ).end ( ), itStartX, [ ] ( const UnboundedRegExpElement < SymbolType > & a, const UnboundedRegExpElement < SymbolType > & b ) -> bool { return a == b; } ) ) { ++ itC; @@ -749,7 +757,7 @@ bool RegExpOptimize::Unbounded < SymbolType >::V8( UnboundedRegExpConcatenation if( concat ) { // check if not out of bounds - if( ( unsigned ) distance( node.getChildren ( ).begin( ), it ) < concat->getChildren ( ).size ( ) ) { + if( ( size_t ) distance( node.getChildren ( ).begin( ), it ) < concat->getChildren ( ).size ( ) ) { it ++; continue; } @@ -758,8 +766,8 @@ bool RegExpOptimize::Unbounded < SymbolType >::V8( UnboundedRegExpConcatenation ext::retract ( it2, concat->getChildren ( ).size ( ) ); if( regexp::properties::RegExpEpsilon::languageContainsEpsilon ( * concat ) && - concat->getChildren().size ( ) == ( unsigned ) distance ( it2, node.getChildren ( ).end( ) ) && - equal ( concat->getChildren ( ).begin( ), concat->getChildren ( ).end( ), it2, [ ] ( const UnboundedRegExpElement < SymbolType > & a, const UnboundedRegExpElement < SymbolType > & b ) -> bool { return a == b; } ) ) { + concat->getChildren().size ( ) == ( size_t ) distance ( it2, node.getChildren ( ).end( ) ) && + equal ( concat->getChildren ( ).begin( ), concat->getChildren ( ).end( ), it2 ) ) { optimized = true; it = node.erase ( it2, it ); @@ -785,6 +793,69 @@ bool RegExpOptimize::Unbounded < SymbolType >::V8( UnboundedRegExpConcatenation return optimized; } +/** + * optimization V8R: \e in h(x) => x*x=x* + * @param node UnboundedRegExpConcatenation < SymbolType > node + * @return bool true if optimization applied else false + */ +template < class SymbolType > +bool RegExpOptimize::Unbounded < SymbolType >::V8R( UnboundedRegExpConcatenation < SymbolType > & node ) { + bool optimized = false; + + // interpretation: if there is iteration in concatenation node, and element of iteration contains eps and is straight before this iteration, then this element can be omitted + + if ( node.getChildren ( ).size ( ) == 0 ) + return false; + + for( auto it = node.getChildren ( ).rbegin( ); it != node.getChildren ( ).rend( ); ) { + const UnboundedRegExpIteration < SymbolType > * iter = dynamic_cast < const UnboundedRegExpIteration < SymbolType > * > ( & * it ); + + if( ! iter ) { + ++ it; + continue; + } + + // if element of iteration is concatenation, we need to check this specially + const UnboundedRegExpConcatenation < SymbolType > * concat = dynamic_cast < const UnboundedRegExpConcatenation < SymbolType > * > ( & iter->getChild ( ) ); + + if( concat ) { + // check if not out of bounds + if( ( size_t ) distance( node.getChildren ( ).rbegin( ), it ) < concat->getChildren ( ).size ( ) ) { + it ++; + continue; + } + + auto it2 = it; + ext::retract ( it2, concat->getChildren ( ).size ( ) ); + + if( regexp::properties::RegExpEpsilon::languageContainsEpsilon ( * concat ) && + concat->getChildren().size ( ) == ( size_t ) distance ( it2, node.getChildren ( ).rend( ) ) && + equal ( concat->getChildren ( ).rbegin( ), concat->getChildren ( ).rend( ), it2 ) ) { + optimized = true; + + it = node.erase ( it2, it ); + } else + ++ it; + } else { + // check if not at the first node + if ( it == node.getChildren ( ).rbegin ( ) ) { + it ++; + continue; + } + + auto prev = std::prev ( it ); + + if ( regexp::properties::RegExpEpsilon::languageContainsEpsilon ( iter->getElement ( ) ) && iter->getElement ( ) == * prev ) { + it = node.erase ( prev ); + optimized = true; + } else + ++ it; + } + } + + return optimized; +} + /** * optimization V9: (xy)*x = x(yx)* * @param node UnboundedRegExpConcatenation < SymbolType > node diff --git a/alib2algo/test-src/regexp/simplify/RegExpOptimizeTest.cpp b/alib2algo/test-src/regexp/simplify/RegExpOptimizeTest.cpp index 995cf7d070daa8c54de0fc0a45f2db28c36a86c5..4ae9974137332bc1f7267179deeaa4f09784378a 100644 --- a/alib2algo/test-src/regexp/simplify/RegExpOptimizeTest.cpp +++ b/alib2algo/test-src/regexp/simplify/RegExpOptimizeTest.cpp @@ -21,7 +21,13 @@ TEST_CASE ( "RegExp Optimize", "[unit][algo][regexp][simplify]" ) { std::make_pair ( "#0*+a*", "a*" ), std::make_pair ( "a+(a+a)", "a" ), std::make_pair ( "(a+b*)(a+b*)*", "(a+b)*" ), - std::make_pair ( "(a+b+d)*+e*+a+b+c+e", "c+e*+(a+b+d)*" ) + std::make_pair ( "(a+b+d)*+e*+a+b+c+e", "c+e*+(a+b+d)*" ), + + std::make_pair ( "#E+x*x", "x*" ), + std::make_pair ( "#E+(x y)*(x y)", "(x y)*" ), + std::make_pair ( "#E+(x y)* x y z", "#E + (x y)* x y z" ), + std::make_pair ( "#E+x*x y", "#E + x* x y" ), + std::make_pair ( "(x+#E)*(x+#E)", "x*" ) // std::make_pair ( "(x y)*x", "x(y x)*" ), );