/*
* JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
* Copyright (C) 2006 - JScience (http://jscience.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package org.jscience.mathematics.function;
import java.io.Serializable;
import org.jscience.mathematics.structure.Ring;
import javolution.context.ArrayFactory;
import javolution.lang.MathLib;
import javolution.lang.Realtime;
import javolution.lang.ValueType;
import javolution.text.Text;
import javolution.text.TextBuilder;
/**
* This class represents the term of a {@link Polynomial polynomial}
* such as x·y².
*
* @author Jean-Marie Dautelle
* @version 3.0, February 13, 2006
*/
public final class Term implements Serializable, Comparable, ValueType,
Realtime {
/**
* Holds the multiplicative identity.
*/
public static Term ONE = new Term(0);
/**
* Holds the term's factory.
*/
private static final ArrayFactory FACTORY = new ArrayFactory() {
@Override
protected Term create(int size) {
return new Term(size);
}
};
/**
* Holds the variables (ordered).
*/
private final Variable>[] _variables;
/**
* Holds the corresponding powers (positive and different from zero).
*/
private final int[] _powers;
/**
* Holds the number of variables.
*/
private int _size;
/**
* Creates a new term of specified capacity.
*
* @param capacity the maxium number of variables.
*/
private Term(int capacity) {
_variables = new Variable[capacity];
_powers = new int[capacity];
}
/**
* Return the term corresponding to the specified variable raised to
* the specified power.
*
* @param v the variable.
* @param n the power.
* @return the term for vn
* @throws IllegalArgumentException if n < 0
*/
public static Term valueOf(Variable> v, int n) {
if (n == 0)
return ONE;
if (n < 0)
throw new IllegalArgumentException("n: " + n
+ " negative values are not allowed");
Term term = FACTORY.array(1);
term._variables[0] = v;
term._powers[0] = n;
term._size = 1;
return term;
}
/**
* Returns the number of variables for this term.
*
* @return the number of variables.
*/
public int size() {
return _size;
}
/**
* Returns the variable at the specified index (variables are
* lexically ordered).
*
* @param index the variable index.
* @return this term variables at specified position.
* @throws IndexOutOfBoundsException if
* (index < 0) || (index >= size())
*/
public Variable> getVariable(int index) {
if (index > _size)
throw new IllegalArgumentException();
return _variables[index];
}
/**
* Returns the power of the variable at the specified position.
*
* @param index the variable index.
* @return the power of the variable at the specified index.
* @throws IndexOutOfBoundsException if
* (index < 0) || (index >= size())
*/
public int getPower(int index) {
if (index > _size)
throw new IllegalArgumentException();
return _powers[index];
}
/**
* Returns the power of the specified variable.
*
* @param v the variable for which the power is returned.
* @return the power of the corresponding variable or 0 if
* this term does not hold the specified variable.
*/
public int getPower(Variable> v) {
for (int i = 0; i < _size; i++) {
if (_variables[i] == v)
return _powers[i];
}
return 0;
}
/**
* Return the product of this term with the one specified.
*
* @param that the term multiplier.
* @return this · that
* @throws IllegalArgumentException if the specified term holds a
* variable having the same symbol as one of the variable of
* this term; but both variables are distinct.
*/
public Term times(Term that) {
final int thisSize = this.size();
final int thatSize = that.size();
Term result = FACTORY.array(thisSize + thatSize);
result._size = 0;
for (int i = 0, j = 0;;) {
Variable> left = (i < thisSize) ? this._variables[i] : null;
Variable> right = (j < thatSize) ? that._variables[j] : null;
if (left == null) {
if (right == null)
return result;
result._powers[result._size] = that._powers[j++];
result._variables[result._size++] = right;
continue;
}
if (right == null) {
result._powers[result._size] = this._powers[i++];
result._variables[result._size++] = left;
continue;
}
if (right == left) {
result._powers[result._size] = this._powers[i++]
+ that._powers[j++];
result._variables[result._size++] = right;
continue;
}
final int cmp = left.getSymbol().compareTo(right.getSymbol());
if (cmp < 0) {
result._powers[result._size] = this._powers[i++];
result._variables[result._size++] = left;
} else if (cmp > 0) {
result._powers[result._size] = that._powers[j++];
result._variables[result._size++] = right;
} else {
throw new IllegalArgumentException(
"Found distinct variables with same symbol: "
+ left.getSymbol());
}
}
}
/**
* Return the division of this term with the one specified.
*
* @param that the term divisor.
* @return this / that
* @throws UnsupportedOperationException if this division would
* result in negative power.
* @throws IllegalArgumentException if the specified term holds a
* variable having the same symbol as one of the variable of
* this term; but both variables are distinct.
*/
public Term divide(Term that) {
final int thisSize = this._size;
final int thatSize = that._size;
Term result = FACTORY.array(MathLib.max(thisSize, thatSize));
result._size = 0;
for (int i = 0, j = 0;;) {
Variable> left = (i < thisSize) ? this._variables[i] : null;
Variable> right = (j < thatSize) ? that._variables[j] : null;
if (left == null) {
if (right == null)
return result;
throw new UnsupportedOperationException(this + "/" + that
+ " would result in a negative power");
}
if (right == null) {
result._powers[result._size] = this._powers[i++];
result._variables[result._size++] = left;
continue;
}
if (right == left) {
final int power = this._powers[i++] - that._powers[j++];
if (power < 0)
throw new UnsupportedOperationException(this + "/" + that
+ " would result in a negative power");
if (power > 0) {
result._powers[result._size] = power;
result._variables[result._size++] = right;
}
continue;
}
final int cmp = left.getSymbol().compareTo(right.getSymbol());
if (cmp < 0) {
result._powers[result._size] = this._powers[i++];
result._variables[result._size++] = left;
} else if (cmp > 0) {
throw new UnsupportedOperationException(this + "/" + that
+ " would result in a negative power");
} else {
throw new IllegalArgumentException(
"Found distinct variables with same symbol: "
+ left.getSymbol());
}
}
}
/**
* Indicates if this term is equal to the object specified.
*
* @param obj the object to compare for equality.
* @return true if this term and the specified object are
* considered equal; false otherwise.
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Term))
return false;
Term that = (Term) obj;
if (this._size != that._size)
return false;
for (int i = 0; i < _size; i++) {
if ((!this._variables[i].equals(that._variables[i]))
|| (this._powers[i] != that._powers[i]))
return false;
}
return true;
}
/**
* Returns a hash code for this term.
*
* @return a hash code value for this object.
*/
public final int hashCode() {
int h = 0;
for (int i = 0; i < _size; i++) {
h += _variables[i].hashCode() * _powers[i];
}
return h;
}
/**
* Returns the text representation of this term as a
* java.lang.String.
*
* @return toText().toString()
*/
public final String toString() {
return toText().toString();
}
/**
* Returns the text representation of this term.
*/
public Text toText() {
TextBuilder tb = TextBuilder.newInstance();
for (int i = 0; i < _size; i++) {
tb.append(_variables[i].getSymbol());
int power = _powers[i];
switch (power) {
case 1:
break;
case 2:
tb.append('²');
break;
case 3:
tb.append('³');
break;
default:
tb.append(power);
}
}
return tb.toText();
}
/**
* Returns an entierely new copy of this term
* {@link javolution.context.AllocatorContext allocated}
* by the calling thread (possibly on the stack).
*
* @return an identical and independant copy of this term.
*/
public Term copy() {
Term term = FACTORY.array(_size);
term._size = _size;
for (int i = 0; i < _size; i++) {
term._powers[i] = _powers[i];
term._variables[i] = _variables[i];
}
return term;
}
/**
* Compares this term with the one specified for order.
*
* @param that the term to be compared to.
* @return a negative integer, zero, or a positive integer as this term
* is less than, equal to, or greater than the specified term.
*/
public int compareTo(Term that) {
int n = Math.min(this._size, that._size);
for (int i = 0; i < n; i++) {
int cmp = this._variables[i].getSymbol().compareTo(
that._variables[i].getSymbol());
if (cmp != 0)
return cmp;
cmp = that._powers[i] - this._powers[i];
if (cmp != 0)
return cmp;
}
return that._size - this._size;
}
/**
* Evaluates this term by replacing its {@link Variable
* variables} by their current (context-local) values.
*
* @return the evaluation of this term or null if ONE.
* @throws FunctionException if any of this term's variable is not set.
*/
@SuppressWarnings("unchecked")
Ring evaluate() {
Ring result = null;
for (int i = 0; i < _size; i++) {
Ring pow2 = (Ring) _variables[i].get();
if (pow2 == null)
throw new FunctionException("Variable: " + _variables[i]
+ " is not set");
int n = _powers[i];
while (n >= 1) { // Iteration.
if ((n & 1) == 1) {
result = (result == null) ? pow2 : (Ring) result
.times(pow2);
}
pow2 = (Ring) pow2.times(pow2);
n >>>= 1;
}
}
return result;
}
private static final long serialVersionUID = 1L;
}
Ads help maintain this website.