/*
 * RTEOptimize.cpp
 *
 *  Created on: 1. 4. 2019
 *	  Author: Jan Travnicek
 */

namespace rte {

namespace simplify {

template < class SymbolType >
void RTEOptimize::optimize( FormalRTEElement < SymbolType > & element ) {
	ext::smart_ptr < FormalRTEElement < SymbolType > > optimized = optimizeInner ( element );

	FormalRTEAlternation < SymbolType > * alternation = dynamic_cast<FormalRTEAlternation < SymbolType > *>( & element );
	if( alternation ) {
		FormalRTEAlternation < SymbolType > * alternationOptimized = dynamic_cast<FormalRTEAlternation < SymbolType > * > ( optimized.get ( ) );
		if( alternationOptimized ) {
			* alternation = std::move( * alternationOptimized );
		} else {
			* alternation = FormalRTEAlternation < SymbolType > { * optimized, FormalRTEEmpty < SymbolType > { } };
		}
		return;
	}

	FormalRTESubstitution < SymbolType > * concatenation = dynamic_cast<FormalRTESubstitution < SymbolType > *>( & element );
	if( concatenation ) {
		FormalRTESubstitution < SymbolType > * concatenationOptimized = dynamic_cast<FormalRTESubstitution < SymbolType > * > ( optimized.get ( ) );
		if( concatenationOptimized ) {
			* concatenation = std::move( * concatenationOptimized );
		} else {
			* concatenation = FormalRTESubstitution < SymbolType > { * optimized, FormalRTESymbolSubst < SymbolType > { } };
		}
		return;
	}

	FormalRTEIteration < SymbolType > * iteration = dynamic_cast<FormalRTEIteration < SymbolType > *>( & element );
	if( iteration ) {
		FormalRTEIteration < SymbolType > * iterationOptimized = dynamic_cast<FormalRTEIteration < SymbolType > *>( optimized.get ( ) );
		if( iterationOptimized ) {
			* iteration = std::move( * iterationOptimized );
		} else {
			* iteration = FormalRTEIteration < SymbolType > { optimized };
		}
		return;
	}

	// Nothing to optimize original element was FormalRTESymbol, FormalRTESymbolSubst, or FormalRTEEmpty
}

template < class SymbolType >
ext::smart_ptr < FormalRTEElement < SymbolType > > RTEOptimize::optimizeInner( const FormalRTEElement < SymbolType > & node ) {
	FormalRTEElement < SymbolType > * elem = node.clone();

	// optimize while you can
	while(    A1( elem ) || A2( elem ) || A3( elem ) || A4( elem ) /*|| A10( elem ) || V2( elem ) || V5( elem ) || V6( elem ) || X1( elem )*/
	       || A5( elem ) || A6( elem ) || A7( elem ) || A8( elem ) || A9( elem ) /*|| V8( elem ) //|| V9( elem )*/
	       || A11( elem ) || V1( elem ) /*|| V3( elem ) || V4( elem ) || V10( elem )*/ || S(elem) );

	return ext::smart_ptr < FormalRTEElement < SymbolType > > ( elem );
}

template < class SymbolType >
bool RTEOptimize::S( FormalRTEElement < SymbolType > * & node ) {
	bool optimized = false;
	FormalRTEAlternation < SymbolType > * alternation = dynamic_cast<FormalRTEAlternation < SymbolType >*>( node );
	if( alternation ) {
		ext::smart_ptr < FormalRTEElement < SymbolType > > tmp = optimizeInner ( alternation->getLeftElement ( ) );
		if(* tmp != alternation->getLeftElement ( ) ) {
			optimized = true;
			alternation->setLeftElement ( * tmp );
		}

		tmp = optimizeInner ( alternation->getRightElement ( ) );
		if(* tmp != alternation->getRightElement ( ) ) {
			optimized = true;
			alternation->setRightElement ( * tmp );
		}

		return optimized;
	}

	FormalRTESubstitution < SymbolType > * concatenation = dynamic_cast<FormalRTESubstitution < SymbolType >*>( node );
	if( concatenation ) {
		ext::smart_ptr < FormalRTEElement < SymbolType > > tmp = optimizeInner ( concatenation->getLeftElement() );
		if(* tmp != concatenation->getLeftElement ( ) ) {
			optimized = true;
			concatenation->setLeftElement ( * tmp );
		}

		tmp = optimizeInner ( concatenation->getRightElement ( ));
		if(* tmp != concatenation->getRightElement ( )) {
			optimized = true;
			concatenation->setRightElement ( * tmp );
		}

		return optimized;
	}

	FormalRTEIteration < SymbolType > * iteration = dynamic_cast<FormalRTEIteration < SymbolType >*>( node );
	if( iteration ) {
		ext::smart_ptr < FormalRTEElement < SymbolType > > tmp = optimizeInner ( iteration->getElement() );

		if(* tmp != iteration->getElement ( ) ) {
			optimized = true;
			iteration->setElement ( * tmp );
		}
		return optimized;
	}

	return optimized;
}


/**
  * optimization A1: ( x + y ) + z = x + ( y + z )
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A1( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEAlternation < SymbolType > * n = dynamic_cast<FormalRTEAlternation < SymbolType > *>( node );
	if( ! n ) return false;

	if( dynamic_cast < FormalRTEAlternation < SymbolType > * > ( & n->getLeft ( ) ) ) {
		FormalRTEAlternation < SymbolType > leftAlt ( std::move ( static_cast < FormalRTEAlternation < SymbolType > & > ( n->getLeft ( ) ) ) );

		n->setLeft ( std::move ( leftAlt.getLeft ( ) ) );
		leftAlt.setLeft ( std::move ( leftAlt.getRight ( ) ) );
		leftAlt.setRight ( std::move ( n->getRight ( ) ) );
		n->setRight ( std::move ( leftAlt ) );

		return true;
	}

	return false;
}

/**
  * optimization A2: x + y = y + x (sort)
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A2 ( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEAlternation < SymbolType > * n = dynamic_cast<FormalRTEAlternation < SymbolType > *>( node );
	if( ! n ) return false;

	if ( dynamic_cast < FormalRTEAlternation < SymbolType > * > ( & n->getRight ( ) ) ) {
		FormalRTEAlternation < SymbolType > & rightAlt = static_cast < FormalRTEAlternation < SymbolType > & > ( n->getRight ( ) );

		if ( n->getLeft ( ) > rightAlt.getLeft ( ) ) {
			ext::ptr_value < FormalRTEElement < SymbolType > > tmp ( std::move ( n->getLeft ( ) ) );

			n->setLeft ( std::move ( rightAlt.getLeft ( ) ) );
			rightAlt.setLeft ( std::move ( tmp ) );
			return true;
		} else {
			return false;
		}
	}

	return false;
}

/**
  * optimization A3: x + \0 = x
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A3 ( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEAlternation < SymbolType > * n = dynamic_cast < FormalRTEAlternation < SymbolType > * > ( node );
	if( ! n ) return false;

	// input can be \0 + \0, so at least one element must be preserved

	if ( dynamic_cast < FormalRTEEmpty < SymbolType > * > ( & n->getRight ( ) ) ) {
		node = std::move ( n->getLeft ( ) ).clone ( );
		delete n;
		return true;
	}

	if ( dynamic_cast < FormalRTEEmpty < SymbolType > * > ( & n->getLeft ( ) ) ) {
		node = std::move ( n->getRight ( ) ).clone ( );
		delete n;
		return true;
	}

	return false;
}

/**
  * optimization A4: x + x = x
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A4( FormalRTEElement < SymbolType > * & node ) {
	/*
	 * two ways of implementing this opitimization:
	 * - sort and call std::unique ( O(n lg n) + O(n) ), but it also sorts...
	 * - check every element against other ( O(n*n) )
	 *
	 * As we always sort in optimization, we can use the first version, but A4 must be __always__ called __after__ A2
	 */

	FormalRTEAlternation < SymbolType > * n = dynamic_cast < FormalRTEAlternation < SymbolType > * > ( node );
	if ( ! n ) return false;

	if ( n->getLeftElement() == n->getRightElement() ) {
		node = std::move ( n->getRight ( ) ).clone ( );
		delete n;
		return true;
	}

	return false;
}

/**
  * optimization A5: x.(y.z) = (x.y).z = x.y.z
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A5( FormalRTEElement < SymbolType > * & node ) {
	FormalRTESubstitution < SymbolType > * n = dynamic_cast<FormalRTESubstitution < SymbolType > *>( node );
	if( ! n ) return false;

	FormalRTESubstitution < SymbolType > * leftNode = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & n->getLeft ( ) );
	if( leftNode && n->getSubstitutionSymbol ( ) == leftNode->getSubstitutionSymbol ( ) ) {
		FormalRTESubstitution < SymbolType > leftCon ( std::move ( * leftNode ) );

		n->setLeft ( std::move ( leftCon.getLeft ( ) ) );
		leftCon.setLeft ( std::move ( leftCon.getRight ( ) ) );
		leftCon.setRight ( std::move ( n->getRight ( ) ) );
		n->setRight ( std::move ( leftCon ) );

		return true;
	}

	return false;
}

/**
  * optimization A6: \e.x = x.\e = x
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A6( FormalRTEElement < SymbolType > * & node ) {
	FormalRTESubstitution < SymbolType > * n = dynamic_cast<FormalRTESubstitution < SymbolType > *>( node );
	if( ! n ) return false;

	// input can be \e + \e, so at least one element must be preserved

	if ( n->getSubstitutionSymbol ( ) == n->getLeft ( ) ) {
		node = std::move ( n->getRight ( ) ).clone ( );
		delete n;
		return true;
	}

	if ( n->getSubstitutionSymbol ( ) == n->getRight ( ) ) {
		node = std::move ( n->getRight ( ) ).clone ( );
		delete n;
		return true;
	}


	return false;
}

/**
  * optimization A7: \0.x = x.\0 = \0
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A7( FormalRTEElement < SymbolType > * & node ) {
	FormalRTESubstitution < SymbolType > * n = dynamic_cast<FormalRTESubstitution < SymbolType > *>( node );
	if( ! n ) return false;

	if ( /*dynamic_cast < FormalRTEEmpty < SymbolType > * > ( & n->getRight ( ) ) || */ dynamic_cast < FormalRTEEmpty < SymbolType > * > ( & n->getLeft ( ) ) ) {
		delete n;
		node = new FormalRTEEmpty < SymbolType > { };
		return true;
	}

	return false;
}

/**
  * optimization A8: x.(y+z) = x.y + x.z
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A8( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEAlternation < SymbolType > * n = dynamic_cast<FormalRTEAlternation < SymbolType > *>( node );
	if( ! n ) return false;

	FormalRTESubstitution < SymbolType > * left = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & n->getLeft ( ) );
	FormalRTESubstitution < SymbolType > * right = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & n->getRight ( ) );
	if ( left && right && left->getLeft ( ) == right->getLeft ( ) && left->getSubstitutionSymbol ( ) == right->getSubstitutionSymbol ( ) ) {
		FormalRTEAlternation < SymbolType > alt { std::move ( left->getRight ( ) ), std::move ( right->getRight ( ) ) };

		node = new FormalRTESubstitution < SymbolType > ( std::move ( left->getLeft ( ) ), std::move ( alt ), std::move ( left->getSubstitutionSymbol ( ) ) );
		delete n;
		return true;
	}

	return false;
}

/**
  * optimization A9: (x+y).z = x.z + y.z
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A9( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEAlternation < SymbolType > * n = dynamic_cast<FormalRTEAlternation < SymbolType > *>( node );
	if( ! n ) return false;

	FormalRTESubstitution < SymbolType > * left = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & n->getLeft ( ) );
	FormalRTESubstitution < SymbolType > * right = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & n->getRight ( ) );
	if ( left && right && left->getRight ( ) == right->getRight ( ) && left->getSubstitutionSymbol ( ) == right->getSubstitutionSymbol ( ) ) {
		FormalRTEAlternation < SymbolType > alt { std::move ( left->getLeft ( ) ), std::move ( right->getLeft ( ) ) };

		node = new FormalRTESubstitution < SymbolType > ( std::move ( alt ), std::move ( left->getRight ( ) ), std::move ( left->getSubstitutionSymbol ( ) ) );
		delete n;
		return true;
	}

	return false;
}

/**
  * optimization A10: x* = \e + x*x
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::A10( FormalRTEElement < SymbolType > * & n ) {*/
	/*
	 * 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).
	 */

/*	FormalRTEAlternation < SymbolType > * node = dynamic_cast<FormalRTEAlternation < SymbolType > * > ( n );
	if ( ! node ) return false;

	if ( dynamic_cast < FormalRTESymbolSubst < SymbolType > * > ( & node->getLeft ( ) ) ) {
		FormalRTESubstitution < SymbolType > * rightCon = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & node->getRight ( ) );
		if ( ! rightCon ) return false;

		FormalRTEIteration < SymbolType > * rightLeftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & rightCon->getLeft ( ) );
		if ( rightLeftIte ) {
			if ( rightLeftIte->getElement ( ) == rightCon->getRightElement ( ) ) {
				n = std::move ( rightCon->getLeft ( ) ).clone ( );
				delete node;
				return true;
			}
		}

		FormalRTEIteration < SymbolType > * rightRightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & rightCon->getRight ( ) );
		if ( rightRightIte ) {
			if ( rightRightIte->getElement ( ) == rightCon->getLeftElement ( ) ) {
				n = std::move ( rightCon->getRight ( ) ).clone ( );
				delete node;
				return true;
			}
		}
	}

	if ( dynamic_cast < FormalRTESymbolSubst < SymbolType > * > ( & node->getRight ( ) ) ) {
		FormalRTESubstitution < SymbolType > * leftCon = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & node->getLeft ( ) );
		if ( ! leftCon ) return false;

		FormalRTEIteration < SymbolType > * leftLeftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & leftCon->getLeft ( ) );
		if ( leftLeftIte ) {
			if ( leftLeftIte->getElement ( ) == leftCon->getRightElement ( ) ) {
				n = std::move ( leftCon->getLeft ( ) ).clone ( );
				delete node;
				return true;
			}
		}

		FormalRTEIteration < SymbolType > * leftRightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & leftCon->getRight ( ) );
		if ( leftRightIte ) {
			if ( leftRightIte->getElement ( ) == leftCon->getLeftElement ( ) ) {
				n = std::move ( leftCon->getRight ( ) ).clone ( );
				delete node;
				return true;
			}
		}
	}

	return false;
}*/

/**
  * optimization A11: x* = (\e + x)*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::A11( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEIteration < SymbolType > * n = dynamic_cast<FormalRTEIteration < SymbolType > *>( node );
	if( ! n ) return false;

	FormalRTEAlternation < SymbolType > * childAlt = dynamic_cast < FormalRTEAlternation < SymbolType > * > ( & n->getChild ( ) );
	if ( childAlt ) {
		if ( childAlt->getLeft ( ) == n->getSubstitutionSymbol ( ) ) {
			n->setChild ( std::move ( childAlt->getRight ( ) ) );
			return true;
		}
		if ( childAlt->getRight ( ) == n->getSubstitutionSymbol ( ) ) {
			n->setChild ( std::move ( childAlt->getLeft ( ) ) );
			return true;
		}
	}

	return false;
}

/**
  * optimization V1: \0* = \e
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
template < class SymbolType >
bool RTEOptimize::V1( FormalRTEElement < SymbolType > * & node ) {
	FormalRTEIteration < SymbolType > * n = dynamic_cast<FormalRTEIteration < SymbolType > *>( node );
	if( ! n ) return false;

	if ( dynamic_cast < FormalRTEEmpty < SymbolType > * > ( & n->getChild ( ) ) ) {
		delete std::exchange ( node, n->getSubstitutionSymbol ( ).clone ( ) );
		return true;
	}
	return false;
}

/**
  * optimization V2: x* + x = x*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V2( FormalRTEElement < SymbolType > * & n ) {
	FormalRTEAlternation < SymbolType > * node = dynamic_cast<FormalRTEAlternation < SymbolType > *>( n );
	if( ! node ) return false;

	FormalRTEIteration < SymbolType > * leftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & node->getLeft ( ) );
	if ( leftIte ) {
		if ( leftIte->getElement ( ) == node->getRightElement ( ) ) {
			n = std::move ( node->getLeft ( ) ).clone ( );
			delete node;
			return true;
		}
	}

	FormalRTEIteration < SymbolType > * rightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & node->getRight ( ) );
	if ( rightIte ) {
		if ( rightIte->getElement ( ) == node->getLeftElement ( ) ) {
			n = std::move ( node->getRight ( ) ).clone ( );
			delete node;
			return true;
		}
	}

	return false;
}*/

/**
  * optimization V3: x** = x*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V3( FormalRTEElement < SymbolType > * & n ) {
	FormalRTEIteration < SymbolType > * node = dynamic_cast<FormalRTEIteration < SymbolType > *>( n );
	if( ! node ) return false;

	FormalRTEIteration < SymbolType > * childIter = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & node->getChild ( ) );
	if( childIter ) {
		node->setChild ( std::move ( childIter->getChild ( ) ) );
		return true;
	}

	return false;
}*/

/**
  * optimization V4: (x+y)* = (x*y*)*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V4( FormalRTEElement < SymbolType > * & n ) {
	FormalRTEIteration < SymbolType > * node = dynamic_cast < FormalRTEIteration < SymbolType > *>( n );
	if( ! node ) return false;

	FormalRTESubstitution < SymbolType > * child = dynamic_cast < FormalRTESubstitution < SymbolType > * > ( & node->getChild ( ) );
	if( ! child ) return false;

	FormalRTEIteration < SymbolType > * leftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & child->getLeft ( ) );
	if( ! leftIte ) return false;

	FormalRTEIteration < SymbolType > * rightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & child->getRight ( ) );
	if( ! rightIte ) return false;

	node->setChild ( FormalRTEAlternation < SymbolType >( std::move ( leftIte->getElement ( ) ), std::move ( rightIte->getElement ( ) ) ) );

	return true;
}*/

/**
  * optimization V5: x*y = y + x*xy
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V5( FormalRTEElement < SymbolType > * & *//* n *//*) {
	return false; //TODO
}*/

/**
  * optimization V6: x*y = y + xx*y
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V6( FormalRTEElement < SymbolType > * & *//* n *//*) {
	return false; //TODO
}*/

/**
  * optimization V8: \e in h(x) => xx*=x*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V8( FormalRTEElement < SymbolType > * & *//* n *//*) {
	return false; //TODO
}*/

/**
  * optimization V9: (xy)*x = x(yx)*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V9( FormalRTEElement < SymbolType > * & *//* n *//*) {
	return false; //TODO
}*/

/**
  * optimization V10: (x+y)* = (x*+y*)*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::V10( FormalRTEElement < SymbolType > * & n ) {
	FormalRTEIteration < SymbolType > * node = dynamic_cast < FormalRTEIteration < SymbolType > *>( n );
	if( ! node ) return false;

	FormalRTEAlternation < SymbolType > * alt = dynamic_cast < FormalRTEAlternation < SymbolType > * > ( & node->getChild ( ) );
	if( ! alt ) return false;

	FormalRTEIteration < SymbolType > * leftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & alt->getLeft ( ) );
	if( ! leftIte ) return false;

	FormalRTEIteration < SymbolType > * rightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & alt->getRight ( ) );
	if( ! rightIte ) return false;

	alt->setLeft ( std::move ( leftIte->getChild ( ) ) );
	alt->setRight ( std::move ( rightIte->getChild ( ) ) );

	return true;
}*/

/**
  * optimization X1: a* + \e = a*
  * @param node FormalRTEElement < SymbolType > node
  * @return bool true if optimization applied else false
  */
/*template < class SymbolType >
bool RTEOptimize::X1( FormalRTEElement < SymbolType > * & n ) {
	FormalRTEAlternation < SymbolType > * node = dynamic_cast<FormalRTEAlternation < SymbolType > *>( n );
	if( ! node ) return false;

	FormalRTEIteration < SymbolType > * leftIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & node->getLeft ( ) );
	if ( leftIte ) {
		if ( dynamic_cast < FormalRTESymbolSubst < SymbolType > * > ( & node->getRight ( ) ) ) {
			n = std::move ( node->getLeft ( ) ).clone ( );
			delete node;
			return true;
		}
	}

	FormalRTEIteration < SymbolType > * rightIte = dynamic_cast < FormalRTEIteration < SymbolType > * > ( & node->getRight ( ) );
	if ( rightIte ) {
		if ( dynamic_cast < FormalRTESymbolSubst < SymbolType > * > ( & node->getLeft ( ) ) ) {
			n = std::move ( node->getRight ( ) ).clone ( );
			delete node;
			return true;
		}
	}

	return false;

}*/

} /* namespace simplify */

} /* namespace rte */
