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