Derivative.java

package edu.udel.cis.vsl.tass.model.impl;

import java.util.Arrays;

import edu.udel.cis.vsl.tass.model.IF.AbstractFunctionIF;
import edu.udel.cis.vsl.tass.model.IF.ContinuityException;
import edu.udel.cis.vsl.tass.model.IF.DerivativeIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.scope.ScopeIF;
import edu.udel.cis.vsl.tass.model.IF.variable.FormalVariableIF;

/**
 * Clairaut's theorem states that if a function from R^n->R has continuous
 * second partial derivatives at any given point, then any pair of partial
 * derivatives commute at that point. By induction, this means that any n
 * partial derivatives will commute if the function has continuous nth partial
 * derivatives at that point.
 * 
 * Our assumption is that at any point the function is differentiable up to the
 * continuity value in any variable.
 * 
 * For now, we will apply Clairut's theorem to any parameter/return types.
 * Later, we can either prove this is correct or restrict as necessary.
 */
public class Derivative extends AbstractFunction implements DerivativeIF {

	private int orders[];

	private AbstractFunctionIF function;
	
	public Derivative(ScopeIF containingScope, String name,
			AbstractFunctionIF function, int[] orders) throws SyntaxException {
		super(containingScope, name, function.returnType(), function
				.numFormals());
		this.orders = orders;
		/*
		 * Check if this is the derivative of a derivative. If it is, "flatten"
		 * it so that it is a single derivative with the orders added point-wise
		 * and the base function used as the function.
		 */
		if (function instanceof DerivativeIF) {
			this.function = ((DerivativeIF) function).function();
			for (int i = 0; i < orders.length; i++) {
				orders[i] += ((Derivative) function).orders()[i];
			}
		} else {
			this.function = function;
		}
		int c = 0;
		for (int i = 0; i < orders.length; i++) {
			c += orders[i];
		}
		if (c > function.continuity()) {
			throw new ContinuityException(
					this,
					"The continuity of the function "
							+ function
							+ " is insufficient to assure that the derivative is valid.");
		}
		setContinuity(function.continuity() - c);
	}

	public int[] orders() {
		return orders;
	}

	public AbstractFunctionIF function() {
		return function;
	}

	public int orderForVariable(FormalVariableIF variable) {
		return orders[variable.index()];
	}

	public String toString() {
		String result = "\\D[" + name;

		for (int i = 0; i < orders.length; i++) {
			result += ",{" + function.formal(i).name() + "," + orders[i] + "}";
		}
		result += "]";
		return result;
	}

	public int hashCode() {
		int result = function.hashCode();

		for (int order : orders)
			result += order;
		return result;
	}

	public boolean equals(Object object) {
		if (object instanceof Derivative) {
			Derivative that = (Derivative) object;

			return function.equals(that.function)
					&& Arrays.equals(orders, that.orders);
		}
		return false;
	}
}