View Javadoc
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.UnitTestUtils;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.random.RandomDataGenerator;
27  import org.hipparchus.util.Binary64;
28  import org.hipparchus.util.FastMath;
29  import org.junit.jupiter.api.Test;
30  
31  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
32  import static org.junit.jupiter.api.Assertions.assertEquals;
33  import static org.junit.jupiter.api.Assertions.assertThrows;
34  
35  /**
36   * Tests the PolynomialFunction implementation of a UnivariateFunction.
37   *
38   */
39  public final class PolynomialFunctionTest {
40      /** Error tolerance for tests */
41      protected double tolerance = 1e-12;
42  
43      /**
44       * tests the value of a constant polynomial.
45       *
46       * <p>value of this is 2.5 everywhere.</p>
47       */
48      @Test
49      void testConstants() {
50          double[] c = { 2.5 };
51          PolynomialFunction f = new PolynomialFunction(c);
52  
53          // verify that we are equal to c[0] at several (nonsymmetric) places
54          assertEquals(f.value(0), c[0], tolerance);
55          assertEquals(f.value(-1), c[0], tolerance);
56          assertEquals(f.value(-123.5), c[0], tolerance);
57          assertEquals(f.value(3), c[0], tolerance);
58          assertEquals(f.value(456.89), c[0], tolerance);
59  
60          assertEquals(0, f.degree());
61          assertEquals(0, f.polynomialDerivative().value(0), tolerance);
62  
63          assertEquals(0, f.polynomialDerivative().polynomialDerivative().value(0), tolerance);
64      }
65  
66      /**
67       * tests the value of a linear polynomial.
68       *
69       * <p>This will test the function f(x) = 3*x - 1.5</p>
70       * <p>This will have the values
71       *  <tt>f(0) = -1.5, f(-1) = -4.5, f(-2.5) = -9,
72       *      f(0.5) = 0, f(1.5) = 3</tt> and {@code f(3) = 7.5}
73       * </p>
74       */
75      @Test
76      void testLinear() {
77          double[] c = { -1.5, 3 };
78          PolynomialFunction f = new PolynomialFunction(c);
79  
80          // verify that we are equal to c[0] when x=0
81          assertEquals(f.value(new Binary64(0)).getReal(), c[0], tolerance);
82  
83          // now check a few other places
84          assertEquals(-4.5, f.value(new Binary64(-1)).getReal(), tolerance);
85          assertEquals(-9, f.value(new Binary64(-2.5)).getReal(), tolerance);
86          assertEquals(0, f.value(new Binary64(0.5)).getReal(), tolerance);
87          assertEquals(3, f.value(new Binary64(1.5)).getReal(), tolerance);
88          assertEquals(7.5, f.value(new Binary64(3)).getReal(), tolerance);
89  
90          assertEquals(1, f.degree());
91  
92          assertEquals(0, f.polynomialDerivative().polynomialDerivative().value(0), tolerance);
93      }
94  
95      /**
96       * Tests a second order polynomial.
97       * <p> This will test the function f(x) = 2x^2 - 3x -2 = (2x+1)(x-2)</p>
98       */
99      @Test
100     void testQuadratic() {
101         double[] c = { -2, -3, 2 };
102         PolynomialFunction f = new PolynomialFunction(c);
103 
104         // verify that we are equal to c[0] when x=0
105         assertEquals(f.value(0), c[0], tolerance);
106 
107         // now check a few other places
108         assertEquals(0, f.value(-0.5), tolerance);
109         assertEquals(0, f.value(2), tolerance);
110         assertEquals(-2, f.value(1.5), tolerance);
111         assertEquals(7, f.value(-1.5), tolerance);
112         assertEquals(265.5312, f.value(12.34), tolerance);
113     }
114 
115     /**
116      * This will test the quintic function
117      *   f(x) = x^2(x-5)(x+3)(x-1) = x^5 - 3x^4 -13x^3 + 15x^2</p>
118      */
119     @Test
120     void testQuintic() {
121         double[] c = { 0, 0, 15, -13, -3, 1 };
122         PolynomialFunction f = new PolynomialFunction(c);
123 
124         // verify that we are equal to c[0] when x=0
125         assertEquals(f.value(0), c[0], tolerance);
126 
127         // now check a few other places
128         assertEquals(0, f.value(5), tolerance);
129         assertEquals(0, f.value(1), tolerance);
130         assertEquals(0, f.value(-3), tolerance);
131         assertEquals(54.84375, f.value(-1.5), tolerance);
132         assertEquals(-8.06637, f.value(1.3), tolerance);
133 
134         assertEquals(5, f.degree());
135     }
136 
137     /**
138      * tests the firstDerivative function by comparison
139      *
140      * <p>This will test the functions
141      * {@code f(x) = x^3 - 2x^2 + 6x + 3, g(x) = 3x^2 - 4x + 6}
142      * and {@code h(x) = 6x - 4}
143      */
144     @Test
145     void testfirstDerivativeComparison() {
146         double[] f_coeff = { 3, 6, -2, 1 };
147         double[] g_coeff = { 6, -4, 3 };
148         double[] h_coeff = { -4, 6 };
149 
150         PolynomialFunction f = new PolynomialFunction(f_coeff);
151         PolynomialFunction g = new PolynomialFunction(g_coeff);
152         PolynomialFunction h = new PolynomialFunction(h_coeff);
153 
154         // compare f' = g
155         assertEquals(f.polynomialDerivative().value(0), g.value(0), tolerance);
156         assertEquals(f.polynomialDerivative().value(1), g.value(1), tolerance);
157         assertEquals(f.polynomialDerivative().value(100), g.value(100), tolerance);
158         assertEquals(f.polynomialDerivative().value(4.1), g.value(4.1), tolerance);
159         assertEquals(f.polynomialDerivative().value(-3.25), g.value(-3.25), tolerance);
160 
161         // compare g' = h
162         assertEquals(g.polynomialDerivative().value(FastMath.PI), h.value(FastMath.PI), tolerance);
163         assertEquals(g.polynomialDerivative().value(FastMath.E),  h.value(FastMath.E),  tolerance);
164     }
165 
166     @Test
167     void testString() {
168         PolynomialFunction p = new PolynomialFunction(new double[] { -5, 3, 1 });
169         checkPolynomial(p, "-5 + 3 x + x^2");
170         checkPolynomial(new PolynomialFunction(new double[] { 0, -2, 3 }),
171                         "-2 x + 3 x^2");
172         checkPolynomial(new PolynomialFunction(new double[] { 1, -2, 3 }),
173                       "1 - 2 x + 3 x^2");
174         checkPolynomial(new PolynomialFunction(new double[] { 0,  2, 3 }),
175                        "2 x + 3 x^2");
176         checkPolynomial(new PolynomialFunction(new double[] { 1,  2, 3 }),
177                      "1 + 2 x + 3 x^2");
178         checkPolynomial(new PolynomialFunction(new double[] { 1,  0, 3 }),
179                      "1 + 3 x^2");
180         checkPolynomial(new PolynomialFunction(new double[] { 0 }),
181                      "0");
182     }
183 
184     @Test
185     void testAddition() {
186         PolynomialFunction p1 = new PolynomialFunction(new double[] { -2, 1 });
187         PolynomialFunction p2 = new PolynomialFunction(new double[] { 2, -1, 0 });
188         checkNullPolynomial(p1.add(p2));
189 
190         p2 = p1.add(p1);
191         checkPolynomial(p2, "-4 + 2 x");
192 
193         p1 = new PolynomialFunction(new double[] { 1, -4, 2 });
194         p2 = new PolynomialFunction(new double[] { -1, 3, -2 });
195         p1 = p1.add(p2);
196         assertEquals(1, p1.degree());
197         checkPolynomial(p1, "-x");
198     }
199 
200     @Test
201     void testSubtraction() {
202         PolynomialFunction p1 = new PolynomialFunction(new double[] { -2, 1 });
203         checkNullPolynomial(p1.subtract(p1));
204 
205         PolynomialFunction p2 = new PolynomialFunction(new double[] { -2, 6 });
206         p2 = p2.subtract(p1);
207         checkPolynomial(p2, "5 x");
208 
209         p1 = new PolynomialFunction(new double[] { 1, -4, 2 });
210         p2 = new PolynomialFunction(new double[] { -1, 3, 2 });
211         p1 = p1.subtract(p2);
212         assertEquals(1, p1.degree());
213         checkPolynomial(p1, "2 - 7 x");
214     }
215 
216     @Test
217     void testMultiplication() {
218         PolynomialFunction p1 = new PolynomialFunction(new double[] { -3, 2 });
219         PolynomialFunction p2 = new PolynomialFunction(new double[] { 3, 2, 1 });
220         checkPolynomial(p1.multiply(p2), "-9 + x^2 + 2 x^3");
221 
222         p1 = new PolynomialFunction(new double[] { 0, 1 });
223         p2 = p1;
224         for (int i = 2; i < 10; ++i) {
225             p2 = p2.multiply(p1);
226             checkPolynomial(p2, "x^" + i);
227         }
228     }
229 
230     @Test
231     void testSerial() {
232         PolynomialFunction p2 = new PolynomialFunction(new double[] { 3, 2, 1 });
233         assertEquals(p2, UnitTestUtils.serializeAndRecover(p2));
234     }
235 
236     /**
237      * tests the firstDerivative function by comparison
238      *
239      * <p>This will test the functions
240      * {@code f(x) = x^3 - 2x^2 + 6x + 3, g(x) = 3x^2 - 4x + 6}
241      * and {@code h(x) = 6x - 4}
242      */
243     @Test
244     void testMath341() {
245         double[] f_coeff = { 3, 6, -2, 1 };
246         double[] g_coeff = { 6, -4, 3 };
247         double[] h_coeff = { -4, 6 };
248 
249         PolynomialFunction f = new PolynomialFunction(f_coeff);
250         PolynomialFunction g = new PolynomialFunction(g_coeff);
251         PolynomialFunction h = new PolynomialFunction(h_coeff);
252 
253         // compare f' = g
254         assertEquals(f.polynomialDerivative().value(0), g.value(0), tolerance);
255         assertEquals(f.polynomialDerivative().value(1), g.value(1), tolerance);
256         assertEquals(f.polynomialDerivative().value(100), g.value(100), tolerance);
257         assertEquals(f.polynomialDerivative().value(4.1), g.value(4.1), tolerance);
258         assertEquals(f.polynomialDerivative().value(-3.25), g.value(-3.25), tolerance);
259 
260         // compare g' = h
261         assertEquals(g.polynomialDerivative().value(FastMath.PI), h.value(FastMath.PI), tolerance);
262         assertEquals(g.polynomialDerivative().value(FastMath.E),  h.value(FastMath.E),  tolerance);
263     }
264 
265     @Test
266     void testAntiDerivative() {
267         // 1 + 2x + 3x^2
268         final double[] coeff = {1, 2, 3};
269         final PolynomialFunction p = new PolynomialFunction(coeff);
270         // x + x^2 + x^3
271         final double[] aCoeff = {0, 1, 1, 1};
272         assertArrayEquals(aCoeff, p.antiDerivative().getCoefficients(), Double.MIN_VALUE);
273     }
274 
275     @Test
276     void testAntiDerivativeConstant() {
277         final double[] coeff = {2};
278         final PolynomialFunction p = new PolynomialFunction(coeff);
279         final double[] aCoeff = {0, 2};
280         assertArrayEquals(aCoeff, p.antiDerivative().getCoefficients(), Double.MIN_VALUE);
281     }
282 
283     @Test
284     void testAntiDerivativeZero() {
285         final double[] coeff = {0};
286         final PolynomialFunction p = new PolynomialFunction(coeff);
287         final double[] aCoeff = {0};
288         assertArrayEquals(aCoeff, p.antiDerivative().getCoefficients(), Double.MIN_VALUE);
289     }
290 
291     @Test
292     void testAntiDerivativeRandom() {
293         final RandomDataGenerator ran = new RandomDataGenerator(1000);
294         double[] coeff = null;
295         PolynomialFunction p = null;
296         int d = 0;
297         for (int i = 0; i < 20; i++) {
298             d = ran.nextInt(1, 50);
299             coeff = new double[d];
300             for (int j = 0; j < d; j++) {
301                 coeff[j] = ran.nextUniform(-100, 1000);
302             }
303             p = new PolynomialFunction(coeff);
304             checkInverseDifferentiation(p);
305         }
306     }
307 
308     @Test
309     void testIntegrate() {
310         // -x^2
311         final double[] coeff = {0, 0, -1};
312         final PolynomialFunction p = new PolynomialFunction(coeff);
313         assertEquals(-2d/3d, p.integrate(-1, 1),Double.MIN_VALUE);
314 
315         // x(x-1)(x+1) - should integrate to 0 over [-1,1]
316         final PolynomialFunction p2 = new PolynomialFunction(new double[] {0, 1}).
317                 multiply(new PolynomialFunction(new double[]{-1,1})).
318                          multiply(new PolynomialFunction(new double[] {1, 1}));
319         assertEquals(0, p2.integrate(-1, 1), Double.MIN_VALUE);
320     }
321 
322     @Test
323     void testIntegrateInfiniteBounds() {
324         assertThrows(MathIllegalArgumentException.class, () -> {
325             final PolynomialFunction p = new PolynomialFunction(new double[]{1});
326             p.integrate(0, Double.POSITIVE_INFINITY);
327         });
328     }
329 
330     @Test
331     void testIntegrateBadInterval() {
332         assertThrows(MathIllegalArgumentException.class, () -> {
333             final PolynomialFunction p = new PolynomialFunction(new double[]{1});
334             p.integrate(0, -1);
335         });
336     }
337 
338     public void checkPolynomial(PolynomialFunction p, String reference) {
339         assertEquals(reference, p.toString());
340     }
341 
342     private void checkInverseDifferentiation(PolynomialFunction p) {
343         assertArrayEquals(p.getCoefficients(),
344                                  p.antiDerivative().polynomialDerivative().getCoefficients(),
345                                  1e-12);
346     }
347 
348     private void checkNullPolynomial(PolynomialFunction p) {
349         for (double coefficient : p.getCoefficients()) {
350             assertEquals(0, coefficient, 1e-15);
351         }
352     }
353 }