PowerSimplification.java

package edu.udel.cis.vsl.sarl.simplify.simplification;

import edu.udel.cis.vsl.sarl.IF.expr.NumericExpression;
import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression;
import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression.SymbolicOperator;
import edu.udel.cis.vsl.sarl.IF.object.NumberObject;
import edu.udel.cis.vsl.sarl.IF.object.SymbolicObject;
import edu.udel.cis.vsl.sarl.IF.object.SymbolicObject.SymbolicObjectKind;
import edu.udel.cis.vsl.sarl.ideal.IF.Constant;
import edu.udel.cis.vsl.sarl.ideal.IF.IdealFactory;
import edu.udel.cis.vsl.sarl.ideal.IF.Monic;
import edu.udel.cis.vsl.sarl.ideal.IF.Monomial;
import edu.udel.cis.vsl.sarl.ideal.IF.RationalExpression;
import edu.udel.cis.vsl.sarl.simplify.simplifier.IdealSimplifierWorker;

/**
 * A simplification that applies to expressions in which the operator is
 * {@link SymbolicOperator#POWER}.
 * 
 * @author siegel
 */
public class PowerSimplification extends Simplification {

	public PowerSimplification(IdealSimplifierWorker worker) {
		super(worker);
	}

	/**
	 * <p>
	 * Attempts to decompose a power operation <code>base ^ exp</code> while the
	 * base is a monomial with a non-trivial (not one) constant.
	 * </p>
	 * 
	 * <p>
	 * Precondition and postcondition: {@code powerExpr} is generically
	 * simplified.
	 * </p>
	 * 
	 * <p>
	 * <code>base ^ exp</code> will be decomposed to
	 * <code>monomial_constant ^ exp * monomial_monic ^ exp</code> if both
	 * <code>monomial_constant & monomial_monic</code> are positive.
	 * </p>
	 * 
	 * @param powerExpr
	 *            the {@link SymbolicOperator#POWER} expression that might gets
	 *            decomposed (simplified).
	 * @param idf
	 *            A reference to the {@link IdealFactory}
	 * @return the simplified expression. If no simplification can be further
	 *         applied, the expression in unchanged.
	 */
	private RationalExpression simplifyPowerDecompose(
			RationalExpression powerExpr) {
		NumericExpression base = (NumericExpression) powerExpr.argument(0);
		SymbolicObject exp = powerExpr.argument(1);
		NumericExpression neExp;
		IdealFactory idf = idealFactory();

		if (exp.symbolicObjectKind() == SymbolicObjectKind.NUMBER) {
			NumberObject nobj = (NumberObject) exp;

			neExp = idf.number(nobj);
		} else
			neExp = (NumericExpression) exp;

		if (!(base instanceof Monomial))
			return powerExpr;

		Monomial monomialBase = (Monomial) base;
		Constant cons = monomialBase.monomialConstant(idf);
		Monic monic = monomialBase.monic(idf);

		if (cons.isOne())
			return powerExpr;

		// if exponent is an integer, both monic and constant are positive
		// this power expression can be decomposed:
		boolean decompose = false;

		if (neExp.type().isInteger())
			decompose = true;
		if (!decompose && intervalApproximation(cons).lower().signum() >= 0
				&& intervalApproximation(monic).lower().signum() >= 0)
			decompose = true;
		if (decompose) {
			RationalExpression result = idf.multiply(idf.power(monic, neExp),
					idf.power(cons, neExp));

			return result;
		}
		return powerExpr;
	}

	@Override
	public SymbolicExpression apply(SymbolicExpression x) {
		if (x.operator() == SymbolicOperator.POWER)
			return simplifyPowerDecompose((RationalExpression) x);
		return x;
	}

	@Override
	public SimplificationKind kind() {
		return SimplificationKind.POWER;
	}

}