001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2006 - JScience (http://jscience.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package org.jscience.mathematics.function;
010:
011: import java.io.Serializable;
012: import org.jscience.mathematics.structure.Ring;
013:
014: import javolution.context.ArrayFactory;
015: import javolution.lang.MathLib;
016: import javolution.lang.Realtime;
017: import javolution.lang.ValueType;
018: import javolution.text.Text;
019: import javolution.text.TextBuilder;
020:
021: /**
022: * This class represents the term of a {@link Polynomial polynomial}
023: * such as <code>x·y²</code>.
024: *
025: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
026: * @version 3.0, February 13, 2006
027: */
028: public final class Term implements Serializable, Comparable<Term>,
029: ValueType, Realtime {
030:
031: /**
032: * Holds the multiplicative identity.
033: */
034: public static Term ONE = new Term(0);
035:
036: /**
037: * Holds the term's factory.
038: */
039: private static final ArrayFactory<Term> FACTORY = new ArrayFactory<Term>() {
040:
041: @Override
042: protected Term create(int size) {
043: return new Term(size);
044: }
045: };
046:
047: /**
048: * Holds the variables (ordered).
049: */
050: private final Variable<?>[] _variables;
051:
052: /**
053: * Holds the corresponding powers (positive and different from zero).
054: */
055: private final int[] _powers;
056:
057: /**
058: * Holds the number of variables.
059: */
060: private int _size;
061:
062: /**
063: * Creates a new term of specified capacity.
064: *
065: * @param capacity the maxium number of variables.
066: */
067: private Term(int capacity) {
068: _variables = new Variable[capacity];
069: _powers = new int[capacity];
070: }
071:
072: /**
073: * Return the term corresponding to the specified variable raised to
074: * the specified power.
075: *
076: * @param v the variable.
077: * @param n the power.
078: * @return the term for <code>v<sup>n</sup></code>
079: * @throws IllegalArgumentException if <code>n < 0</code>
080: */
081: public static Term valueOf(Variable<?> v, int n) {
082: if (n == 0)
083: return ONE;
084: if (n < 0)
085: throw new IllegalArgumentException("n: " + n
086: + " negative values are not allowed");
087: Term term = FACTORY.array(1);
088: term._variables[0] = v;
089: term._powers[0] = n;
090: term._size = 1;
091: return term;
092: }
093:
094: /**
095: * Returns the number of variables for this term.
096: *
097: * @return the number of variables.
098: */
099: public int size() {
100: return _size;
101: }
102:
103: /**
104: * Returns the variable at the specified index (variables are
105: * lexically ordered).
106: *
107: * @param index the variable index.
108: * @return this term variables at specified position.
109: * @throws IndexOutOfBoundsException if
110: * <code>(index < 0) || (index >= size())</code>
111: */
112: public Variable<?> getVariable(int index) {
113: if (index > _size)
114: throw new IllegalArgumentException();
115: return _variables[index];
116: }
117:
118: /**
119: * Returns the power of the variable at the specified position.
120: *
121: * @param index the variable index.
122: * @return the power of the variable at the specified index.
123: * @throws IndexOutOfBoundsException if
124: * <code>(index < 0) || (index >= size())</code>
125: */
126: public int getPower(int index) {
127: if (index > _size)
128: throw new IllegalArgumentException();
129: return _powers[index];
130: }
131:
132: /**
133: * Returns the power of the specified variable.
134: *
135: * @param v the variable for which the power is returned.
136: * @return the power of the corresponding variable or <code>0</code> if
137: * this term does not hold the specified variable.
138: */
139: public int getPower(Variable<?> v) {
140: for (int i = 0; i < _size; i++) {
141: if (_variables[i] == v)
142: return _powers[i];
143: }
144: return 0;
145: }
146:
147: /**
148: * Return the product of this term with the one specified.
149: *
150: * @param that the term multiplier.
151: * @return <code>this · that</code>
152: * @throws IllegalArgumentException if the specified term holds a
153: * variable having the same symbol as one of the variable of
154: * this term; but both variables are distinct.
155: */
156: public Term times(Term that) {
157: final int this Size = this .size();
158: final int thatSize = that.size();
159: Term result = FACTORY.array(this Size + thatSize);
160: result._size = 0;
161: for (int i = 0, j = 0;;) {
162: Variable<?> left = (i < this Size) ? this ._variables[i]
163: : null;
164: Variable<?> right = (j < thatSize) ? that._variables[j]
165: : null;
166: if (left == null) {
167: if (right == null)
168: return result;
169: result._powers[result._size] = that._powers[j++];
170: result._variables[result._size++] = right;
171: continue;
172: }
173: if (right == null) {
174: result._powers[result._size] = this ._powers[i++];
175: result._variables[result._size++] = left;
176: continue;
177: }
178: if (right == left) {
179: result._powers[result._size] = this ._powers[i++]
180: + that._powers[j++];
181: result._variables[result._size++] = right;
182: continue;
183: }
184: final int cmp = left.getSymbol().compareTo(
185: right.getSymbol());
186: if (cmp < 0) {
187: result._powers[result._size] = this ._powers[i++];
188: result._variables[result._size++] = left;
189: } else if (cmp > 0) {
190: result._powers[result._size] = that._powers[j++];
191: result._variables[result._size++] = right;
192: } else {
193: throw new IllegalArgumentException(
194: "Found distinct variables with same symbol: "
195: + left.getSymbol());
196: }
197: }
198: }
199:
200: /**
201: * Return the division of this term with the one specified.
202: *
203: * @param that the term divisor.
204: * @return <code>this / that</code>
205: * @throws UnsupportedOperationException if this division would
206: * result in negative power.
207: * @throws IllegalArgumentException if the specified term holds a
208: * variable having the same symbol as one of the variable of
209: * this term; but both variables are distinct.
210: */
211: public Term divide(Term that) {
212: final int this Size = this ._size;
213: final int thatSize = that._size;
214: Term result = FACTORY.array(MathLib.max(this Size, thatSize));
215: result._size = 0;
216: for (int i = 0, j = 0;;) {
217: Variable<?> left = (i < this Size) ? this ._variables[i]
218: : null;
219: Variable<?> right = (j < thatSize) ? that._variables[j]
220: : null;
221: if (left == null) {
222: if (right == null)
223: return result;
224: throw new UnsupportedOperationException(this + "/"
225: + that + " would result in a negative power");
226: }
227: if (right == null) {
228: result._powers[result._size] = this ._powers[i++];
229: result._variables[result._size++] = left;
230: continue;
231: }
232: if (right == left) {
233: final int power = this ._powers[i++] - that._powers[j++];
234: if (power < 0)
235: throw new UnsupportedOperationException(this + "/"
236: + that
237: + " would result in a negative power");
238: if (power > 0) {
239: result._powers[result._size] = power;
240: result._variables[result._size++] = right;
241: }
242: continue;
243: }
244: final int cmp = left.getSymbol().compareTo(
245: right.getSymbol());
246: if (cmp < 0) {
247: result._powers[result._size] = this ._powers[i++];
248: result._variables[result._size++] = left;
249: } else if (cmp > 0) {
250: throw new UnsupportedOperationException(this + "/"
251: + that + " would result in a negative power");
252: } else {
253: throw new IllegalArgumentException(
254: "Found distinct variables with same symbol: "
255: + left.getSymbol());
256: }
257: }
258: }
259:
260: /**
261: * Indicates if this term is equal to the object specified.
262: *
263: * @param obj the object to compare for equality.
264: * @return <code>true</code> if this term and the specified object are
265: * considered equal; <code>false</code> otherwise.
266: */
267: public boolean equals(Object obj) {
268: if (this == obj)
269: return true;
270: if (!(obj instanceof Term))
271: return false;
272: Term that = (Term) obj;
273: if (this ._size != that._size)
274: return false;
275: for (int i = 0; i < _size; i++) {
276: if ((!this ._variables[i].equals(that._variables[i]))
277: || (this ._powers[i] != that._powers[i]))
278: return false;
279: }
280: return true;
281: }
282:
283: /**
284: * Returns a hash code for this term.
285: *
286: * @return a hash code value for this object.
287: */
288: public final int hashCode() {
289: int h = 0;
290: for (int i = 0; i < _size; i++) {
291: h += _variables[i].hashCode() * _powers[i];
292: }
293: return h;
294: }
295:
296: /**
297: * Returns the text representation of this term as a
298: * <code>java.lang.String</code>.
299: *
300: * @return <code>toText().toString()</code>
301: */
302: public final String toString() {
303: return toText().toString();
304: }
305:
306: /**
307: * Returns the text representation of this term.
308: */
309: public Text toText() {
310: TextBuilder tb = TextBuilder.newInstance();
311: for (int i = 0; i < _size; i++) {
312: tb.append(_variables[i].getSymbol());
313: int power = _powers[i];
314: switch (power) {
315: case 1:
316: break;
317: case 2:
318: tb.append('²');
319: break;
320: case 3:
321: tb.append('³');
322: break;
323: default:
324: tb.append(power);
325: }
326: }
327: return tb.toText();
328: }
329:
330: /**
331: * Returns an entierely new copy of this term
332: * {@link javolution.context.AllocatorContext allocated}
333: * by the calling thread (possibly on the stack).
334: *
335: * @return an identical and independant copy of this term.
336: */
337: public Term copy() {
338: Term term = FACTORY.array(_size);
339: term._size = _size;
340: for (int i = 0; i < _size; i++) {
341: term._powers[i] = _powers[i];
342: term._variables[i] = _variables[i];
343: }
344: return term;
345: }
346:
347: /**
348: * Compares this term with the one specified for order.
349: *
350: * @param that the term to be compared to.
351: * @return a negative integer, zero, or a positive integer as this term
352: * is less than, equal to, or greater than the specified term.
353: */
354: public int compareTo(Term that) {
355: int n = Math.min(this ._size, that._size);
356: for (int i = 0; i < n; i++) {
357: int cmp = this ._variables[i].getSymbol().compareTo(
358: that._variables[i].getSymbol());
359: if (cmp != 0)
360: return cmp;
361: cmp = that._powers[i] - this ._powers[i];
362: if (cmp != 0)
363: return cmp;
364: }
365: return that._size - this ._size;
366: }
367:
368: /**
369: * Evaluates this term by replacing its {@link Variable
370: * variables} by their current (context-local) values.
371: *
372: * @return the evaluation of this term or <code>null</code> if ONE.
373: * @throws FunctionException if any of this term's variable is not set.
374: */
375: @SuppressWarnings("unchecked")
376: Ring evaluate() {
377: Ring result = null;
378: for (int i = 0; i < _size; i++) {
379: Ring pow2 = (Ring) _variables[i].get();
380: if (pow2 == null)
381: throw new FunctionException("Variable: "
382: + _variables[i] + " is not set");
383: int n = _powers[i];
384: while (n >= 1) { // Iteration.
385: if ((n & 1) == 1) {
386: result = (result == null) ? pow2 : (Ring) result
387: .times(pow2);
388: }
389: pow2 = (Ring) pow2.times(pow2);
390: n >>>= 1;
391: }
392: }
393: return result;
394: }
395:
396: private static final long serialVersionUID = 1L;
397: }
|