1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.analysis.polynomials; 23 24 import org.hipparchus.CalculusFieldElement; 25 import org.hipparchus.analysis.FieldUnivariateFunction; 26 import org.hipparchus.analysis.differentiation.Derivative; 27 import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction; 28 import org.hipparchus.exception.LocalizedCoreFormats; 29 import org.hipparchus.exception.MathIllegalArgumentException; 30 import org.hipparchus.exception.NullArgumentException; 31 import org.hipparchus.util.MathUtils; 32 33 /** 34 * Implements the representation of a real polynomial function in 35 * Newton Form. For reference, see <b>Elementary Numerical Analysis</b>, 36 * ISBN 0070124477, chapter 2. 37 * <p> 38 * The formula of polynomial in Newton form is 39 * p(x) = a[0] + a[1](x-c[0]) + a[2](x-c[0])(x-c[1]) + ... + 40 * a[n](x-c[0])(x-c[1])...(x-c[n-1]) 41 * Note that the length of a[] is one more than the length of c[]</p> 42 * 43 */ 44 public class PolynomialFunctionNewtonForm implements UnivariateDifferentiableFunction, FieldUnivariateFunction { 45 46 /** 47 * The coefficients of the polynomial, ordered by degree -- i.e. 48 * coefficients[0] is the constant term and coefficients[n] is the 49 * coefficient of x^n where n is the degree of the polynomial. 50 */ 51 private double[] coefficients; 52 53 /** 54 * Centers of the Newton polynomial. 55 */ 56 private final double[] c; 57 58 /** 59 * When all c[i] = 0, a[] becomes normal polynomial coefficients, 60 * i.e. a[i] = coefficients[i]. 61 */ 62 private final double[] a; 63 64 /** 65 * Whether the polynomial coefficients are available. 66 */ 67 private boolean coefficientsComputed; 68 69 /** 70 * Construct a Newton polynomial with the given a[] and c[]. The order of 71 * centers are important in that if c[] shuffle, then values of a[] would 72 * completely change, not just a permutation of old a[]. 73 * <p> 74 * The constructor makes copy of the input arrays and assigns them.</p> 75 * 76 * @param a Coefficients in Newton form formula. 77 * @param c Centers. 78 * @throws NullArgumentException if any argument is {@code null}. 79 * @throws MathIllegalArgumentException if any array has zero length. 80 * @throws MathIllegalArgumentException if the size difference between 81 * {@code a} and {@code c} is not equal to 1. 82 */ 83 public PolynomialFunctionNewtonForm(double[] a, double[] c) 84 throws MathIllegalArgumentException, NullArgumentException { 85 86 verifyInputArray(a, c); 87 this.a = new double[a.length]; 88 this.c = new double[c.length]; 89 System.arraycopy(a, 0, this.a, 0, a.length); 90 System.arraycopy(c, 0, this.c, 0, c.length); 91 coefficientsComputed = false; 92 } 93 94 /** 95 * Calculate the function value at the given point. 96 * 97 * @param z Point at which the function value is to be computed. 98 * @return the function value. 99 */ 100 @Override 101 public double value(double z) { 102 return evaluate(a, c, z); 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 @Override 109 public <T extends Derivative<T>> T value(final T t) { 110 verifyInputArray(a, c); 111 112 final int n = c.length; 113 T value = t.getField().getZero().add(a[n]); 114 for (int i = n - 1; i >= 0; i--) { 115 value = t.subtract(c[i]).multiply(value).add(a[i]); 116 } 117 118 return value; 119 120 } 121 122 /** 123 * {@inheritDoc} 124 */ 125 @Override 126 public <T extends CalculusFieldElement<T>> T value(final T t) { 127 verifyInputArray(a, c); 128 129 final int n = c.length; 130 T value = t.getField().getZero().add(a[n]); 131 for (int i = n - 1; i >= 0; i--) { 132 value = t.subtract(c[i]).multiply(value).add(a[i]); 133 } 134 135 return value; 136 137 } 138 139 /** 140 * Returns the degree of the polynomial. 141 * 142 * @return the degree of the polynomial 143 */ 144 public int degree() { 145 return c.length; 146 } 147 148 /** 149 * Returns a copy of coefficients in Newton form formula. 150 * <p> 151 * Changes made to the returned copy will not affect the polynomial.</p> 152 * 153 * @return a fresh copy of coefficients in Newton form formula 154 */ 155 public double[] getNewtonCoefficients() { 156 double[] out = new double[a.length]; 157 System.arraycopy(a, 0, out, 0, a.length); 158 return out; 159 } 160 161 /** 162 * Returns a copy of the centers array. 163 * <p> 164 * Changes made to the returned copy will not affect the polynomial.</p> 165 * 166 * @return a fresh copy of the centers array. 167 */ 168 public double[] getCenters() { 169 double[] out = new double[c.length]; 170 System.arraycopy(c, 0, out, 0, c.length); 171 return out; 172 } 173 174 /** 175 * Returns a copy of the coefficients array. 176 * <p> 177 * Changes made to the returned copy will not affect the polynomial.</p> 178 * 179 * @return a fresh copy of the coefficients array. 180 */ 181 public double[] getCoefficients() { 182 if (!coefficientsComputed) { 183 computeCoefficients(); 184 } 185 double[] out = new double[coefficients.length]; 186 System.arraycopy(coefficients, 0, out, 0, coefficients.length); 187 return out; 188 } 189 190 /** 191 * Evaluate the Newton polynomial using nested multiplication. It is 192 * also called <a href="http://mathworld.wolfram.com/HornersRule.html"> 193 * Horner's Rule</a> and takes O(N) time. 194 * 195 * @param a Coefficients in Newton form formula. 196 * @param c Centers. 197 * @param z Point at which the function value is to be computed. 198 * @return the function value. 199 * @throws NullArgumentException if any argument is {@code null}. 200 * @throws MathIllegalArgumentException if any array has zero length. 201 * @throws MathIllegalArgumentException if the size difference between 202 * {@code a} and {@code c} is not equal to 1. 203 */ 204 public static double evaluate(double[] a, double[] c, double z) 205 throws MathIllegalArgumentException, NullArgumentException { 206 verifyInputArray(a, c); 207 208 final int n = c.length; 209 double value = a[n]; 210 for (int i = n - 1; i >= 0; i--) { 211 value = a[i] + (z - c[i]) * value; 212 } 213 214 return value; 215 } 216 217 /** 218 * Calculate the normal polynomial coefficients given the Newton form. 219 * It also uses nested multiplication but takes O(N^2) time. 220 */ 221 protected void computeCoefficients() { 222 final int n = degree(); 223 224 coefficients = new double[n+1]; 225 for (int i = 0; i <= n; i++) { 226 coefficients[i] = 0.0; 227 } 228 229 coefficients[0] = a[n]; 230 for (int i = n-1; i >= 0; i--) { 231 for (int j = n-i; j > 0; j--) { 232 coefficients[j] = coefficients[j-1] - c[i] * coefficients[j]; 233 } 234 coefficients[0] = a[i] - c[i] * coefficients[0]; 235 } 236 237 coefficientsComputed = true; 238 } 239 240 /** 241 * Verifies that the input arrays are valid. 242 * <p> 243 * The centers must be distinct for interpolation purposes, but not 244 * for general use. Thus it is not verified here.</p> 245 * 246 * @param a the coefficients in Newton form formula 247 * @param c the centers 248 * @throws NullArgumentException if any argument is {@code null}. 249 * @throws MathIllegalArgumentException if any array has zero length. 250 * @throws MathIllegalArgumentException if the size difference between 251 * {@code a} and {@code c} is not equal to 1. 252 */ 253 protected static void verifyInputArray(double[] a, double[] c) 254 throws MathIllegalArgumentException, NullArgumentException { 255 MathUtils.checkNotNull(a); 256 MathUtils.checkNotNull(c); 257 if (a.length == 0 || c.length == 0) { 258 throw new MathIllegalArgumentException(LocalizedCoreFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY); 259 } 260 if (a.length != c.length + 1) { 261 throw new MathIllegalArgumentException(LocalizedCoreFormats.ARRAY_SIZES_SHOULD_HAVE_DIFFERENCE_1, 262 a.length, c.length); 263 } 264 } 265 266 }