com.opengamma.strata.math.impl.function.RealPolynomialFunction1D Maven / Gradle / Ivy
Show all versions of strata-math Show documentation
/*
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.function;
import java.util.Arrays;
import com.google.common.math.DoubleMath;
import com.opengamma.strata.collect.ArgChecker;
/**
* Class representing a polynomial that has real coefficients and takes a real
* argument. The function is defined as:
* $$
* \begin{align*}
* p(x) = a_0 + a_1 x + a_2 x^2 + \ldots + a_{n-1} x^{n-1}
* \end{align*}
* $$
*/
public class RealPolynomialFunction1D implements DoubleFunction1D {
private final double[] _coefficients;
private final int _n;
/**
* Creates an instance.
*
* The array of coefficients for a polynomial
* $p(x) = a_0 + a_1 x + a_2 x^2 + ... + a_{n-1} x^{n-1}$
* is $\\{a_0, a_1, a_2, ..., a_{n-1}\\}$.
*
* @param coefficients the array of coefficients, not null or empty
*/
public RealPolynomialFunction1D(double... coefficients) {
ArgChecker.notNull(coefficients, "coefficients");
ArgChecker.isTrue(coefficients.length > 0, "coefficients length must be greater than zero");
_coefficients = coefficients;
_n = _coefficients.length;
}
//-------------------------------------------------------------------------
@Override
public double applyAsDouble(double x) {
ArgChecker.notNull(x, "x");
double y = _coefficients[_n - 1];
for (int i = _n - 2; i >= 0; i--) {
y = x * y + _coefficients[i];
}
return y;
}
/**
* Gets the coefficients of this polynomial.
*
* @return the coefficients of this polynomial
*/
public double[] getCoefficients() {
return _coefficients;
}
/**
* Adds a function to the polynomial.
* If the function is not a {@link RealPolynomialFunction1D} then the addition takes
* place as in {@link DoubleFunction1D}, otherwise the result will also be a polynomial.
*
* @param f the function to add
* @return $P+f$
*/
@Override
public DoubleFunction1D add(DoubleFunction1D f) {
ArgChecker.notNull(f, "function");
if (f instanceof RealPolynomialFunction1D) {
RealPolynomialFunction1D p1 = (RealPolynomialFunction1D) f;
double[] c1 = p1.getCoefficients();
double[] c = _coefficients;
int n = c1.length;
boolean longestIsNew = n > _n;
double[] c3 = longestIsNew ? Arrays.copyOf(c1, n) : Arrays.copyOf(c, _n);
for (int i = 0; i < (longestIsNew ? _n : n); i++) {
c3[i] += longestIsNew ? c[i] : c1[i];
}
return new RealPolynomialFunction1D(c3);
}
return DoubleFunction1D.super.add(f);
}
/**
* Adds a constant to the polynomial (equivalent to adding the value to the constant
* term of the polynomial). The result is also a polynomial.
*
* @param a the value to add
* @return $P+a$
*/
@Override
public RealPolynomialFunction1D add(double a) {
double[] c = Arrays.copyOf(getCoefficients(), _n);
c[0] += a;
return new RealPolynomialFunction1D(c);
}
/**
* Returns the derivative of this polynomial (also a polynomial), where
* $$
* \begin{align*}
* P'(x) = a_1 + 2 a_2 x + 3 a_3 x^2 + 4 a_4 x^3 + \dots + n a_n x^{n-1}
* \end{align*}
* $$.
*
* @return the derivative polynomial
*/
@Override
public RealPolynomialFunction1D derivative() {
int n = _coefficients.length - 1;
double[] coefficients = new double[n];
for (int i = 1; i <= n; i++) {
coefficients[i - 1] = i * _coefficients[i];
}
return new RealPolynomialFunction1D(coefficients);
}
/**
* Divides the polynomial by a constant value (equivalent to dividing each coefficient by this value).
* The result is also a polynomial.
*
* @param a the divisor
* @return the polynomial
*/
@Override
public RealPolynomialFunction1D divide(double a) {
double[] c = Arrays.copyOf(getCoefficients(), _n);
for (int i = 0; i < _n; i++) {
c[i] /= a;
}
return new RealPolynomialFunction1D(c);
}
/**
* Multiplies the polynomial by a function.
* If the function is not a {@link RealPolynomialFunction1D} then the multiplication takes
* place as in {@link DoubleFunction1D}, otherwise the result will also be a polynomial.
*
* @param f the function by which to multiply
* @return $P \dot f$
*/
@Override
public DoubleFunction1D multiply(DoubleFunction1D f) {
ArgChecker.notNull(f, "function");
if (f instanceof RealPolynomialFunction1D) {
RealPolynomialFunction1D p1 = (RealPolynomialFunction1D) f;
double[] c = _coefficients;
double[] c1 = p1.getCoefficients();
int m = c1.length;
double[] newC = new double[_n + m - 1];
for (int i = 0; i < newC.length; i++) {
newC[i] = 0;
for (int j = Math.max(0, i + 1 - m); j < Math.min(_n, i + 1); j++) {
newC[i] += c[j] * c1[i - j];
}
}
return new RealPolynomialFunction1D(newC);
}
return DoubleFunction1D.super.multiply(f);
}
/**
* Multiplies the polynomial by a constant value (equivalent to multiplying each
* coefficient by this value). The result is also a polynomial.
*
* @param a the multiplicator
* @return the polynomial
*/
@Override
public RealPolynomialFunction1D multiply(double a) {
double[] c = Arrays.copyOf(getCoefficients(), _n);
for (int i = 0; i < _n; i++) {
c[i] *= a;
}
return new RealPolynomialFunction1D(c);
}
/**
* Subtracts a function from the polynomial.
*
* If the function is not a {@link RealPolynomialFunction1D} then the subtract takes place
* as in {@link DoubleFunction1D}, otherwise the result will also be a polynomial.
*
* @param f the function to subtract
* @return $P-f$
*/
@Override
public DoubleFunction1D subtract(DoubleFunction1D f) {
ArgChecker.notNull(f, "function");
if (f instanceof RealPolynomialFunction1D) {
RealPolynomialFunction1D p1 = (RealPolynomialFunction1D) f;
double[] c = _coefficients;
double[] c1 = p1.getCoefficients();
int m = c.length;
int n = c1.length;
int min = Math.min(m, n);
int max = Math.max(m, n);
double[] c3 = new double[max];
for (int i = 0; i < min; i++) {
c3[i] = c[i] - c1[i];
}
for (int i = min; i < max; i++) {
if (m == max) {
c3[i] = c[i];
} else {
c3[i] = -c1[i];
}
}
return new RealPolynomialFunction1D(c3);
}
return DoubleFunction1D.super.subtract(f);
}
/**
* Subtracts a constant from the polynomial (equivalent to subtracting the value from the
* constant term of the polynomial). The result is also a polynomial.
*
* @param a the value to add
* @return $P-a$
*/
@Override
public RealPolynomialFunction1D subtract(double a) {
double[] c = Arrays.copyOf(getCoefficients(), _n);
c[0] -= a;
return new RealPolynomialFunction1D(c);
}
/**
* Converts the polynomial to its monic form. If
* $$
* \begin{align*}
* P(x) = a_0 + a_1 x + a_2 x^2 + a_3 x^3 \dots + a_n x^n
* \end{align*}
* $$
* then the monic form is
* $$
* \begin{align*}
* P(x) = \lambda_0 + \lambda_1 x + \lambda_2 x^2 + \lambda_3 x^3 \dots + x^n
* \end{align*}
* $$
* where
* $$
* \begin{align*}
* \lambda_i = \frac{a_i}{a_n}
* \end{align*}
* $$
*
* @return the polynomial in monic form
*/
public RealPolynomialFunction1D toMonic() {
double an = _coefficients[_n - 1];
if (DoubleMath.fuzzyEquals(an, (double) 1, 1e-15)) {
return new RealPolynomialFunction1D(Arrays.copyOf(_coefficients, _n));
}
double[] rescaled = new double[_n];
for (int i = 0; i < _n; i++) {
rescaled[i] = _coefficients[i] / an;
}
return new RealPolynomialFunction1D(rescaled);
}
//-------------------------------------------------------------------------
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
RealPolynomialFunction1D other = (RealPolynomialFunction1D) obj;
if (!Arrays.equals(_coefficients, other._coefficients)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(_coefficients);
return result;
}
}