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 */ 009package org.jscience.mathematics.function; 010 011import java.io.Serializable; 012import org.jscience.mathematics.structure.Ring; 013 014import javolution.context.ArrayFactory; 015import javolution.lang.MathLib; 016import javolution.lang.Realtime; 017import javolution.lang.ValueType; 018import javolution.text.Text; 019import 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 */ 028public final class Term implements Serializable, Comparable<Term>, ValueType, 029 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 thisSize = this.size(); 158 final int thatSize = that.size(); 159 Term result = FACTORY.array(thisSize + thatSize); 160 result._size = 0; 161 for (int i = 0, j = 0;;) { 162 Variable<?> left = (i < thisSize) ? this._variables[i] : null; 163 Variable<?> right = (j < thatSize) ? that._variables[j] : null; 164 if (left == null) { 165 if (right == null) 166 return result; 167 result._powers[result._size] = that._powers[j++]; 168 result._variables[result._size++] = right; 169 continue; 170 } 171 if (right == null) { 172 result._powers[result._size] = this._powers[i++]; 173 result._variables[result._size++] = left; 174 continue; 175 } 176 if (right == left) { 177 result._powers[result._size] = this._powers[i++] 178 + that._powers[j++]; 179 result._variables[result._size++] = right; 180 continue; 181 } 182 final int cmp = left.getSymbol().compareTo(right.getSymbol()); 183 if (cmp < 0) { 184 result._powers[result._size] = this._powers[i++]; 185 result._variables[result._size++] = left; 186 } else if (cmp > 0) { 187 result._powers[result._size] = that._powers[j++]; 188 result._variables[result._size++] = right; 189 } else { 190 throw new IllegalArgumentException( 191 "Found distinct variables with same symbol: " 192 + left.getSymbol()); 193 } 194 } 195 } 196 197 /** 198 * Return the division of this term with the one specified. 199 * 200 * @param that the term divisor. 201 * @return <code>this / that</code> 202 * @throws UnsupportedOperationException if this division would 203 * result in negative power. 204 * @throws IllegalArgumentException if the specified term holds a 205 * variable having the same symbol as one of the variable of 206 * this term; but both variables are distinct. 207 */ 208 public Term divide(Term that) { 209 final int thisSize = this._size; 210 final int thatSize = that._size; 211 Term result = FACTORY.array(MathLib.max(thisSize, thatSize)); 212 result._size = 0; 213 for (int i = 0, j = 0;;) { 214 Variable<?> left = (i < thisSize) ? this._variables[i] : null; 215 Variable<?> right = (j < thatSize) ? that._variables[j] : null; 216 if (left == null) { 217 if (right == null) 218 return result; 219 throw new UnsupportedOperationException(this + "/" + that 220 + " would result in a negative power"); 221 } 222 if (right == null) { 223 result._powers[result._size] = this._powers[i++]; 224 result._variables[result._size++] = left; 225 continue; 226 } 227 if (right == left) { 228 final int power = this._powers[i++] - that._powers[j++]; 229 if (power < 0) 230 throw new UnsupportedOperationException(this + "/" + that 231 + " would result in a negative power"); 232 if (power > 0) { 233 result._powers[result._size] = power; 234 result._variables[result._size++] = right; 235 } 236 continue; 237 } 238 final int cmp = left.getSymbol().compareTo(right.getSymbol()); 239 if (cmp < 0) { 240 result._powers[result._size] = this._powers[i++]; 241 result._variables[result._size++] = left; 242 } else if (cmp > 0) { 243 throw new UnsupportedOperationException(this + "/" + that 244 + " would result in a negative power"); 245 } else { 246 throw new IllegalArgumentException( 247 "Found distinct variables with same symbol: " 248 + left.getSymbol()); 249 } 250 } 251 } 252 253 /** 254 * Indicates if this term is equal to the object specified. 255 * 256 * @param obj the object to compare for equality. 257 * @return <code>true</code> if this term and the specified object are 258 * considered equal; <code>false</code> otherwise. 259 */ 260 public boolean equals(Object obj) { 261 if (this == obj) 262 return true; 263 if (!(obj instanceof Term)) 264 return false; 265 Term that = (Term) obj; 266 if (this._size != that._size) 267 return false; 268 for (int i = 0; i < _size; i++) { 269 if ((!this._variables[i].equals(that._variables[i])) 270 || (this._powers[i] != that._powers[i])) 271 return false; 272 } 273 return true; 274 } 275 276 /** 277 * Returns a hash code for this term. 278 * 279 * @return a hash code value for this object. 280 */ 281 public final int hashCode() { 282 int h = 0; 283 for (int i = 0; i < _size; i++) { 284 h += _variables[i].hashCode() * _powers[i]; 285 } 286 return h; 287 } 288 289 /** 290 * Returns the text representation of this term as a 291 * <code>java.lang.String</code>. 292 * 293 * @return <code>toText().toString()</code> 294 */ 295 public final String toString() { 296 return toText().toString(); 297 } 298 299 /** 300 * Returns the text representation of this term. 301 */ 302 public Text toText() { 303 TextBuilder tb = TextBuilder.newInstance(); 304 for (int i = 0; i < _size; i++) { 305 tb.append(_variables[i].getSymbol()); 306 int power = _powers[i]; 307 switch (power) { 308 case 1: 309 break; 310 case 2: 311 tb.append('²'); 312 break; 313 case 3: 314 tb.append('³'); 315 break; 316 default: 317 tb.append(power); 318 } 319 } 320 return tb.toText(); 321 } 322 323 /** 324 * Returns an entierely new copy of this term 325 * {@link javolution.context.AllocatorContext allocated} 326 * by the calling thread (possibly on the stack). 327 * 328 * @return an identical and independant copy of this term. 329 */ 330 public Term copy() { 331 Term term = FACTORY.array(_size); 332 term._size = _size; 333 for (int i = 0; i < _size; i++) { 334 term._powers[i] = _powers[i]; 335 term._variables[i] = _variables[i]; 336 } 337 return term; 338 } 339 340 /** 341 * Compares this term with the one specified for order. 342 * 343 * @param that the term to be compared to. 344 * @return a negative integer, zero, or a positive integer as this term 345 * is less than, equal to, or greater than the specified term. 346 */ 347 public int compareTo(Term that) { 348 int n = Math.min(this._size, that._size); 349 for (int i = 0; i < n; i++) { 350 int cmp = this._variables[i].getSymbol().compareTo( 351 that._variables[i].getSymbol()); 352 if (cmp != 0) 353 return cmp; 354 cmp = that._powers[i] - this._powers[i]; 355 if (cmp != 0) 356 return cmp; 357 } 358 return that._size - this._size; 359 } 360 361 /** 362 * Evaluates this term by replacing its {@link Variable 363 * variables} by their current (context-local) values. 364 * 365 * @return the evaluation of this term or <code>null</code> if ONE. 366 * @throws FunctionException if any of this term's variable is not set. 367 */ 368 @SuppressWarnings("unchecked") 369 Ring evaluate() { 370 Ring result = null; 371 for (int i = 0; i < _size; i++) { 372 Ring pow2 = (Ring) _variables[i].get(); 373 if (pow2 == null) 374 throw new FunctionException("Variable: " + _variables[i] 375 + " is not set"); 376 int n = _powers[i]; 377 while (n >= 1) { // Iteration. 378 if ((n & 1) == 1) { 379 result = (result == null) ? pow2 : (Ring) result 380 .times(pow2); 381 } 382 pow2 = (Ring) pow2.times(pow2); 383 n >>>= 1; 384 } 385 } 386 return result; 387 } 388 389 private static final long serialVersionUID = 1L; 390}