All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jscience.mathematics.function.Polynomial Maven / Gradle / Ivy

The newest version!
/*
 * 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.util.List;
import java.util.Map;
import java.util.Set;

import org.jscience.mathematics.structure.GroupAdditive;
import org.jscience.mathematics.structure.GroupMultiplicative;
import org.jscience.mathematics.structure.Ring;

import javolution.util.FastMap;
import javolution.util.FastTable;
import javolution.context.ObjectFactory;
import javolution.text.Text;
import javolution.text.TextBuilder;

/**
 * 

This class represents a mathematical expression involving a sum of powers * in one or more {@link Variable variables} multiplied by * coefficients (such as x² + x·y + 3y²).

* *

Polynomials are characterized by the type of variable they operate * upon. For example:[code] * Variable> varX = new Variable.Local>("x"); * Polynomial> x = Polynomial.valueOf(Amount.valueOf(1, SI.METER), varX); * and * Variable varX = new Variable.Local("x"); * Polynomial x = Polynomial.valueOf(Complex.ONE, varX);[/code] * are two different polynomials, the first one operates on physical * {@link org.jscience.physics.amount.Amount measures}, * whereas the second operates on * {@link org.jscience.mathematics.number.Complex complex} numbers.

* *

Terms (others than {@link Term#ONE ONE}) having zero (additive identity) * for coefficient are automatically removed.

* * @author Jean-Marie Dautelle * @version 3.1, April 1, 2006 */ public class Polynomial> extends Function implements Ring> { /** * Holds the terms to coefficients mapping * (never empty, holds Term.ONE when constant) */ final FastMap _termToCoef = new FastMap(); /** * Default constructor. */ Polynomial() { } /** * Returns an univariate polynomial of degree one with the specified * coefficient multiplier. * * @param coefficient the coefficient for the variable of degree 1. * @param variable the variable for this polynomial. * @return valueOf(coefficient, Term.valueOf(variable, 1)) */ public static > Polynomial valueOf(R coefficient, Variable variable) { return valueOf(coefficient, Term.valueOf(variable, 1)); } /** * Returns a polynomial corresponding to the specified {@link Term term} * with the specified coefficient multiplier. * * @param coefficient the coefficient multiplier. * @param term the term multiplicand. * @return coefficient * term */ public static > Polynomial valueOf(R coefficient, Term term) { if (term.equals(Term.ONE)) return Constant.valueOf(coefficient); if (isZero(coefficient)) return Constant.valueOf(coefficient); Polynomial p = Polynomial.newInstance(); p._termToCoef.put(term, coefficient); return p; } private static boolean isZero(GroupAdditive coefficient) { return coefficient.equals(coefficient.opposite()); } /** * Returns the terms of this polynomial. * * @return this polynomial's terms. */ public Set getTerms() { return _termToCoef.unmodifiable().keySet(); } /** * Returns the coefficient for the specified term. * * @param term the term for which the coefficient is returned. * @return the coefficient for the specified term or null * if this polynomial does not contain the specified term. */ public final R getCoefficient(Term term) { return _termToCoef.get(term); } /** * Returns the order of this polynomial for the specified variable. * * @return the polynomial order relative to the specified variable. */ public int getOrder(Variable v) { int order = 0; for (Term term : _termToCoef.keySet()) { int power = term.getPower(v); if (power > order) { order = power; } } return order; } /** * Returns the sum of this polynomial with a constant polynomial * having the specified value (convenience method). * * @param constantValue the value of the constant polynomial to add. * @return this + Constant.valueOf(constantValue) */ public Polynomial plus(R constantValue) { return this.plus(Constant.valueOf(constantValue)); } /** * Returns the product of this polynomial with a constant polynomial * having the specified value (convenience method). * * @param constantValue the value of the constant polynomial to multiply. * @return this · Constant.valueOf(constantValue) */ public Polynomial times(R constantValue) { return this.times(Constant.valueOf(constantValue)); } /** * Returns the sum of two polynomials. * * @param that the polynomial being added. * @return this + that */ public Polynomial plus(Polynomial that) { Polynomial result = Polynomial.newInstance(); R zero = null; result._termToCoef.putAll(this._termToCoef); result._termToCoef.putAll(that._termToCoef); for (FastMap.Entry e = result._termToCoef.head(), end = result._termToCoef.tail(); (e = e.getNext()) != end;) { Term term = e.getKey(); R thisCoef = this._termToCoef.get(term); R thatCoef = that._termToCoef.get(term); if ((thisCoef != null) && (thatCoef != null)) { R sum = thisCoef.plus(thatCoef); if (isZero(sum)) { // Remove entry (be careful iterating) FastMap.Entry prev = e.getPrevious(); result._termToCoef.remove(term); e = prev; // Move back to previous entry. zero = sum; // To be used if constant polynomial. } else { result._termToCoef.put(term, sum); } } // Else the current coefficient is correct. } if (result._termToCoef.size() == 0) return Constant.valueOf(zero); return result; } /** * Returns the opposite of this polynomial. * * @return - this */ public Polynomial opposite() { Polynomial result = Polynomial.newInstance(); for (FastMap.Entry e = _termToCoef.head(), end = _termToCoef.tail(); (e = e.getNext()) != end;) { result._termToCoef.put(e.getKey(), e.getValue().opposite()); } return result; } /** * Returns the difference of two polynomials. * * @param that the polynomial being subtracted. * @return this - that */ public Polynomial minus(Polynomial that) { return this.plus(that.opposite()); } /** * Returns the product of two polynomials. * * @param that the polynomial multiplier. * @return this · that */ public Polynomial times(Polynomial that) { Polynomial result = Polynomial.newInstance(); R zero = null; for (Map.Entry entry1 : this._termToCoef.entrySet()) { Term t1 = entry1.getKey(); R c1 = entry1.getValue(); for (Map.Entry entry2 : that._termToCoef.entrySet()) { Term t2 = entry2.getKey(); R c2 = entry2.getValue(); Term t = t1.times(t2); R c = c1.times(c2); R prev = result.getCoefficient(t); R coef = (prev != null) ? prev.plus(c) : c; if (isZero(coef)) { zero = coef; } else { result._termToCoef.put(t, coef); } } } if (result._termToCoef.size() == 0) return Constant.valueOf(zero); return result; } /** * Returns the composition of this polynomial with the one specified. * * @param that the polynomial for which the return value is passed as * argument to this function. * @return the polynomial (this o that) * @throws FunctionException if this function is not univariate. */ public Polynomial compose(Polynomial that) { List> variables = getVariables(); if (getVariables().size() != 1) throw new FunctionException("This polynomial is not monovariate"); Variable v = variables.get(0); Polynomial result = null; for (Map.Entry entry : this._termToCoef.entrySet()) { Term term = entry.getKey(); Constant cst = Constant.valueOf(entry.getValue()); int power = term.getPower(v); if (power > 0) { Polynomial fn = that.pow(power); result = (result != null) ? result.plus(cst.times(fn)) : cst .times(fn); } else { // power = 0 result = (result != null) ? result.plus(cst) : cst; } } return result; } //////////////////////////////////////////////////////////////// // Overrides parent method potentially returning polynomials // //////////////////////////////////////////////////////////////// @SuppressWarnings("unchecked") @Override public Function compose(Function that) { return (Function) ((that instanceof Polynomial) ? compose((Polynomial)that) : super.compose(that)); } @Override public Polynomial differentiate(Variable v) { if (this.getOrder(v) > 0) { Polynomial result = null; for (Map.Entry entry : this._termToCoef.entrySet()) { Term term = entry.getKey(); R coef = entry.getValue(); int power = term.getPower(v); if (power > 0) { R newCoef = multiply(coef, power); Term newTerm = term.divide(Term.valueOf(v, 1)); Polynomial p = valueOf(newCoef, newTerm); result = (result != null) ? result.plus(p) : p; } } return result; } else { // Returns zero. R coef = _termToCoef.values().iterator().next(); return Constant.valueOf(coef.plus(coef.opposite())); } } private static > R multiply(R o, int n) { if (n <= 0) throw new IllegalArgumentException("n: " + n + " zero or negative values not allowed"); R shift2 = o; R result = null; while (n >= 1) { // Iteration. if ((n & 1) == 1) { result = (result == null) ? shift2 : result.plus(shift2); } shift2 = shift2.plus(shift2); n >>>= 1; } return result; } @SuppressWarnings("unchecked") @Override public Polynomial integrate(Variable v) { Polynomial result = null; for (Map.Entry entry : this._termToCoef.entrySet()) { Term term = entry.getKey(); R coef = entry.getValue(); int power = term.getPower(v); R newCoef = (R)((GroupMultiplicative)multiply((R)((GroupMultiplicative)coef).inverse(), power + 1)).inverse(); Term newTerm = term.times(Term.valueOf(v, 1)); Polynomial p = valueOf(newCoef, newTerm); result = (result != null) ? result.plus(p) : p; } return result; } @SuppressWarnings("unchecked") @Override public Function plus(Function that) { return (that instanceof Polynomial) ? this.plus((Polynomial)that) : super.plus(that); } @SuppressWarnings("unchecked") @Override public Function minus(Function that) { return (that instanceof Polynomial) ? this.minus((Polynomial)that) : super.minus(that); } @SuppressWarnings("unchecked") @Override public Function times(Function that) { return (that instanceof Polynomial) ? this.times((Polynomial)that) : super.times(that); } @SuppressWarnings("unchecked") @Override public Polynomial pow(int n) { return (Polynomial) super.pow(n); } @SuppressWarnings("unchecked") @Override public List> getVariables() { // We multiply all terms togethers, the resulting product // will hold all variabgles (powers are always positive). Term product = _termToCoef.head().getNext().getKey(); for (FastMap.Entry e = _termToCoef.head().getNext(), end = _termToCoef.tail(); (e = e.getNext()) != end;) { product = product.times(e.getKey()); } FastTable vars = FastTable.newInstance(); for (int i=0, n = product.size(); i < n; i++) { vars.add(product.getVariable(i)); } return vars; } @Override @SuppressWarnings("unchecked") public R evaluate() { R sum = null; for (Map.Entry entry : _termToCoef.entrySet()) { Term term = entry.getKey(); R coef = entry.getValue(); R termValue = (R) term.evaluate(); R value = (termValue != null) ? coef.times(termValue) : coef; sum = (sum == null) ? value : sum.plus(value); } return sum; } @Override public boolean equals(Object obj) { if (!(obj instanceof Polynomial)) return false; Polynomial that = (Polynomial) obj; return this._termToCoef.equals(that._termToCoef); } @Override public int hashCode() { return _termToCoef.hashCode(); } @Override public Text toText() { FastTable terms = FastTable.newInstance(); terms.addAll(_termToCoef.keySet()); terms.sort(); TextBuilder tb = TextBuilder.newInstance(); for (int i=0, n = terms.size(); i < n; i++) { if (i != 0) { tb.append(" + "); } tb.append('[').append(_termToCoef.get(terms.get(i))); tb.append(']').append(terms.get(i)); } return tb.toText(); } /** * Returns a copy of this polynomial * {@link javolution.context.AllocatorContext allocated} * by the calling thread (possibly on the stack). * * @return an identical and independant copy of this polynomial. */ public Polynomial copy() { Polynomial p = Polynomial.newInstance(); for (Map.Entry entry : _termToCoef.entrySet()) { p._termToCoef.put(entry.getKey().copy(), entry.getValue()); } return p; } @SuppressWarnings("unchecked") private static > Polynomial newInstance() { Polynomial p = FACTORY.object(); p._termToCoef.clear(); return p; } @SuppressWarnings("unchecked") private static final ObjectFactory FACTORY = new ObjectFactory() { protected Polynomial create() { return new Polynomial(); } }; private static final long serialVersionUID = 1L; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy