Factorization.java

package edu.udel.cis.vsl.tass.symbolic.factor;

import java.util.Arrays;

import edu.udel.cis.vsl.tass.symbolic.IF.tree.NumericConcreteExpressionIF;
import edu.udel.cis.vsl.tass.symbolic.IF.tree.TreeExpressionIF;
import edu.udel.cis.vsl.tass.symbolic.expression.SymbolicExpression;
import edu.udel.cis.vsl.tass.symbolic.polynomial.Polynomial;
import edu.udel.cis.vsl.tass.symbolic.power.PowerExpression;

/**
 * An instance of this class represents a factorization of a polynomial. The
 * polynomial is expressed as a product of a scalar and a (possibly empty) set
 * of polynomials of positive degree.
 * 
 * If this is a factorization over the reals, constant is the leading
 * coefficient of the polynomial, and the factors are all monic polynomials of
 * positive degree.
 * 
 * If this is a factorization over the integers, constant is an integer, and is
 * not necessarily the leading coefficient of the polynomial. Moreover, the
 * factors are not necessarily monic. For example, 4x+6y=2*(2x+3y) might be the
 * factorization for 4x+6y. Instead, each factor will have the property that the
 * GCD of the absolute values of its coefficients is 1. Moreover, the
 * coefficient of the leading coefficient of each factor will be positive.
 * 
 * The factors are guaranteed to be indexed in order of increasing id.
 */
public class Factorization extends SymbolicExpression implements
		TreeExpressionIF {

	/**
	 * This is the leading coefficient of the polynomial that is being factored.
	 */
	private NumericConcreteExpressionIF constant;

	private PowerExpression[] factorPowers;

	/**
	 * Pre-requisite: the given factors must comply to the conditions described
	 * in the javadoc comment for this class. In particular, they must occur in
	 * increasing order by id. These facts are NOT checked by this method, so
	 * errors could result if the user does not guarantee this.
	 */
	public Factorization(NumericConcreteExpressionIF constant,
			PowerExpression[] factorPowers) {
		super(constant.type());

		assert constant != null;
		assert factorPowers != null;
		assert !(constant.isZero() && factorPowers.length != 0);

		for (PowerExpression factorPower : factorPowers) {
			assert factorPower.type().equals(type());
			assert factorPower.base() instanceof Polynomial;
			assert ((Polynomial) factorPower.base()).degree().signum() > 0;
		}
		this.constant = constant;
		this.factorPowers = factorPowers;
	}

	public NumericConcreteExpressionIF constant() {
		return constant;
	}

	public int numFactors() {
		return factorPowers.length;
	}

	public PowerExpression[] factorPowers() {
		return factorPowers;
	}

	public Polynomial factor(int index) {
		return (Polynomial) factorPowers[index].base();
	}

	public NumericConcreteExpressionIF exponent(int index) {
		return factorPowers[index].exponent();
	}

	/**
	 * A trivial factorization is one in which the there is at most one factor.
	 * By "at most one" we mean that the sum of the multiplicities is less that
	 * or equal to 1.
	 */
	public boolean isTrivial() {
		return factorPowers.length == 0
				|| (factorPowers.length == 1 && factorPowers[0].exponent()
						.isOne());
	}

	public PowerExpression factorPower(int index) {
		return factorPowers[index];
	}

	public NumericConcreteExpressionIF multiplicity(int index) {
		return factorPowers[index].exponent();
	}

	public String toString() {
		String result = constant.toString();
		int numFactors = factorPowers.length;

		for (int i = 0; i < numFactors; i++) {
			result += "*" + factorPowers[i].atomString();
		}
		return result;
	}

	public String atomString() {
		return toString();
	}

	@Override
	protected boolean intrinsicEquals(SymbolicExpression expression) {
		if (expression instanceof Factorization) {
			Factorization that = (Factorization) expression;

			return constant.equals(that.constant)
					&& Arrays.equals(factorPowers, that.factorPowers);
		}
		return false;
	}

	@Override
	protected int intrinsicHashCode() {
		return Factorization.class.hashCode() + constant.hashCode()
				+ Arrays.hashCode(factorPowers);
	}

	public boolean isZero() {
		return constant.isZero();
	}

	public TreeExpressionIF argument(int index) {
		switch (index) {
		case 0:
			return constant;
		default:
			return factorPowers[index - 1];
		}
	}

	public SymbolicKind kind() {
		return SymbolicKind.MULTIPLY;
	}

	public int numArguments() {
		return numFactors() + 1;
	}

}