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.CalculusFieldElement;
25  import org.hipparchus.analysis.differentiation.*;
26  import org.hipparchus.complex.Complex;
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.random.RandomDataGenerator;
29  import org.hipparchus.util.Binary64;
30  import org.hipparchus.util.FastMath;
31  import org.junit.Assert;
32  import org.junit.Test;
33  
34  /**
35   * Tests the FieldPolynomialFunction implementation of a UnivariateFunction.
36   *
37   */
38  public final class FieldPolynomialFunctionTest {
39      /** Error tolerance for tests */
40      protected double tolerance = 1e-12;
41  
42      /**
43       * tests the value of a constant polynomial.
44       *
45       * <p>value of this is 2.5 everywhere.</p>
46       */
47      @Test
48      public void testConstants() {
49          double c0 = 2.5;
50          FieldPolynomialFunction<Binary64> f = buildD64(c0);
51  
52          // verify that we are equal to c[0] at several (nonsymmetric) places
53          Assert.assertEquals(c0, f.value(0).getReal(), tolerance);
54          Assert.assertEquals(c0, f.value(-1).getReal(), tolerance);
55          Assert.assertEquals(c0, f.value(-123.5).getReal(), tolerance);
56          Assert.assertEquals(c0, f.value(3).getReal(), tolerance);
57          Assert.assertEquals(c0, f.value(new Binary64(456.89)).getReal(), tolerance);
58  
59          Assert.assertEquals(0, f.degree());
60          Assert.assertEquals(0, f.polynomialDerivative().value(0).getReal(), tolerance);
61  
62          Assert.assertEquals(0, f.polynomialDerivative().polynomialDerivative().value(0).getReal(), tolerance);
63      }
64  
65      /**
66       * tests the value of a linear polynomial.
67       *
68       * <p>This will test the function f(x) = 3*x - 1.5</p>
69       * <p>This will have the values
70       *  <tt>f(0) = -1.5, f(-1) = -4.5, f(-2.5) = -9,
71       *      f(0.5) = 0, f(1.5) = 3</tt> and {@code f(3) = 7.5}
72       * </p>
73       */
74      @Test
75      public void testLinear() {
76         FieldPolynomialFunction<Binary64> f = buildD64(-1.5, 3);
77  
78          // verify that we are equal to c[0] when x=0
79          Assert.assertEquals(-1.5, f.value(new Binary64(0)).getReal(), tolerance);
80  
81          // now check a few other places
82          Assert.assertEquals(-4.5, f.value(new Binary64(-1)).getReal(), tolerance);
83          Assert.assertEquals(-9, f.value(new Binary64(-2.5)).getReal(), tolerance);
84          Assert.assertEquals(0, f.value(new Binary64(0.5)).getReal(), tolerance);
85          Assert.assertEquals(3, f.value(new Binary64(1.5)).getReal(), tolerance);
86          Assert.assertEquals(7.5, f.value(new Binary64(3)).getReal(), tolerance);
87  
88          Assert.assertEquals(1, f.degree());
89  
90          Assert.assertEquals(0, f.polynomialDerivative().polynomialDerivative().value(0).getReal(), tolerance);
91      }
92  
93      /**
94       * Tests a second order polynomial.
95       * <p> This will test the function f(x) = 2x^2 - 3x -2 = (2x+1)(x-2)</p>
96       */
97      @Test
98      public void testQuadratic() {
99          FieldPolynomialFunction<Binary64> f = buildD64(-2, -3, 2);
100 
101         // verify that we are equal to c[0] when x=0
102         Assert.assertEquals(-2, f.value(0).getReal(), tolerance);
103 
104         // now check a few other places
105         Assert.assertEquals(0, f.value(-0.5).getReal(), tolerance);
106         Assert.assertEquals(0, f.value(2).getReal(), tolerance);
107         Assert.assertEquals(-2, f.value(1.5).getReal(), tolerance);
108         Assert.assertEquals(7, f.value(-1.5).getReal(), tolerance);
109         Assert.assertEquals(265.5312, f.value(12.34).getReal(), 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         FieldPolynomialFunction<Binary64> f = buildD64(0, 0, 15, -13, -3, 1);
119 
120         // verify that we are equal to c[0] when x=0
121         Assert.assertEquals(0, f.value(0).getReal(), tolerance);
122 
123         // now check a few other places
124         Assert.assertEquals(0, f.value(5).getReal(), tolerance);
125         Assert.assertEquals(0, f.value(1).getReal(), tolerance);
126         Assert.assertEquals(0, f.value(-3).getReal(), tolerance);
127         Assert.assertEquals(54.84375, f.value(-1.5).getReal(), tolerance);
128         Assert.assertEquals(-8.06637, f.value(1.3).getReal(), tolerance);
129 
130         Assert.assertEquals(5, f.degree());
131     }
132 
133     /**
134      * tests the firstDerivative function by comparison
135      *
136      * <p>This will test the functions
137      * {@code f(x) = x^3 - 2x^2 + 6x + 3, g(x) = 3x^2 - 4x + 6}
138      * and {@code h(x) = 6x - 4}
139      */
140     @Test
141     public void testfirstDerivativeComparison() {
142         double[] f_coeff = { 3, 6, -2, 1 };
143         double[] g_coeff = { 6, -4, 3 };
144         double[] h_coeff = { -4, 6 };
145 
146         FieldPolynomialFunction<Binary64> f = buildD64(f_coeff);
147         FieldPolynomialFunction<Binary64> g = buildD64(g_coeff);
148         FieldPolynomialFunction<Binary64> h = buildD64(h_coeff);
149 
150         // compare f' = g
151         Assert.assertEquals(f.polynomialDerivative().value(0).getReal(), g.value(0).getReal(), tolerance);
152         Assert.assertEquals(f.polynomialDerivative().value(1).getReal(), g.value(1).getReal(), tolerance);
153         Assert.assertEquals(f.polynomialDerivative().value(100).getReal(), g.value(100).getReal(), tolerance);
154         Assert.assertEquals(f.polynomialDerivative().value(4.1).getReal(), g.value(4.1).getReal(), tolerance);
155         Assert.assertEquals(f.polynomialDerivative().value(-3.25).getReal(), g.value(-3.25).getReal(), tolerance);
156 
157         // compare g' = h
158         Assert.assertEquals(g.polynomialDerivative().value(FastMath.PI).getReal(), h.value(FastMath.PI).getReal(), tolerance);
159         Assert.assertEquals(g.polynomialDerivative().value(FastMath.E).getReal(),  h.value(FastMath.E).getReal(),  tolerance);
160     }
161 
162     @Test
163     public void testAddition() {
164         FieldPolynomialFunction<Binary64> p1 = buildD64( -2, 1 );
165         FieldPolynomialFunction<Binary64> p2 = buildD64( 2, -1, 0 );
166         checkNullPolynomial(p1.add(p2));
167 
168         p2 = p1.add(p1);
169         checkCoeffs(Double.MIN_VALUE, p2, -4, 2);
170 
171         p1 = buildD64( 1, -4, 2 );
172         p2 = buildD64( -1, 3, -2 );
173         p1 = p1.add(p2);
174         Assert.assertEquals(1, p1.degree());
175         checkCoeffs(Double.MIN_VALUE, p1, 0, -1);
176     }
177 
178     @Test
179     public void testSubtraction() {
180         FieldPolynomialFunction<Binary64> p1 = buildD64( -2, 1 );
181         checkNullPolynomial(p1.subtract(p1));
182 
183         FieldPolynomialFunction<Binary64> p2 = buildD64( -2, 6 );
184         p2 = p2.subtract(p1);
185         checkCoeffs(Double.MIN_VALUE, p2, 0, 5);
186 
187         p1 = buildD64( 1, -4, 2 );
188         p2 = buildD64( -1, 3, 2 );
189         p1 = p1.subtract(p2);
190         Assert.assertEquals(1, p1.degree());
191         checkCoeffs(Double.MIN_VALUE, p1, 2, -7);
192     }
193 
194     @Test
195     public void testMultiplication() {
196         FieldPolynomialFunction<Binary64> p1 = buildD64( -3, 2 );
197         FieldPolynomialFunction<Binary64> p2 = buildD64( 3, 2, 1 );
198         checkCoeffs(Double.MIN_VALUE, p1.multiply(p2), -9, 0, 1, 2);
199 
200         p1 = buildD64( 0, 1 );
201         p2 = p1;
202         for (int i = 2; i < 10; ++i) {
203             p2 = p2.multiply(p1);
204             double[] c = new double[i + 1];
205             c[i] = 1;
206             checkCoeffs(Double.MIN_VALUE, p2, c);
207         }
208     }
209 
210     /**
211      * tests the firstDerivative function by comparison
212      *
213      * <p>This will test the functions
214      * {@code f(x) = x^3 - 2x^2 + 6x + 3, g(x) = 3x^2 - 4x + 6}
215      * and {@code h(x) = 6x - 4}
216      */
217     @Test
218     public void testMath341() {
219         double[] f_coeff = { 3, 6, -2, 1 };
220         double[] g_coeff = { 6, -4, 3 };
221         double[] h_coeff = { -4, 6 };
222 
223         FieldPolynomialFunction<Binary64> f = buildD64(f_coeff);
224         FieldPolynomialFunction<Binary64> g = buildD64(g_coeff);
225         FieldPolynomialFunction<Binary64> h = buildD64(h_coeff);
226 
227         // compare f' = g
228         Assert.assertEquals(f.polynomialDerivative().value(0).getReal(), g.value(0).getReal(), tolerance);
229         Assert.assertEquals(f.polynomialDerivative().value(1).getReal(), g.value(1).getReal(), tolerance);
230         Assert.assertEquals(f.polynomialDerivative().value(100).getReal(), g.value(100).getReal(), tolerance);
231         Assert.assertEquals(f.polynomialDerivative().value(4.1).getReal(), g.value(4.1).getReal(), tolerance);
232         Assert.assertEquals(f.polynomialDerivative().value(-3.25).getReal(), g.value(-3.25).getReal(), tolerance);
233 
234         // compare g' = h
235         Assert.assertEquals(g.polynomialDerivative().value(FastMath.PI).getReal(), h.value(FastMath.PI).getReal(), tolerance);
236         Assert.assertEquals(g.polynomialDerivative().value(FastMath.E).getReal(),  h.value(FastMath.E).getReal(),  tolerance);
237     }
238 
239     @Test
240     public void testAntiDerivative() {
241         // 1 + 2x + 3x^2
242         final double[] coeff = {1, 2, 3};
243         final FieldPolynomialFunction<Binary64> p = buildD64(coeff);
244         // x + x^2 + x^3
245         checkCoeffs(Double.MIN_VALUE, p.antiDerivative(), 0, 1, 1, 1);
246     }
247 
248     @Test
249     public void testAntiDerivativeConstant() {
250         final double[] coeff = {2};
251         final FieldPolynomialFunction<Binary64> p = buildD64(coeff);
252         checkCoeffs(Double.MIN_VALUE, p.antiDerivative(), 0, 2);
253     }
254 
255     @Test
256     public void testAntiDerivativeZero() {
257         final double[] coeff = {0};
258         final FieldPolynomialFunction<Binary64> p = buildD64(coeff);
259         checkCoeffs(Double.MIN_VALUE, p.antiDerivative(), 0);
260     }
261 
262     @Test
263     public void testAntiDerivativeRandom() {
264         final RandomDataGenerator ran = new RandomDataGenerator(1000);
265         double[] coeff = null;
266         FieldPolynomialFunction<Binary64> p = null;
267         int d = 0;
268         for (int i = 0; i < 20; i++) {
269             d = ran.nextInt(1, 50);
270             coeff = new double[d];
271             for (int j = 0; j < d; j++) {
272                 coeff[j] = ran.nextUniform(-100, 1000);
273             }
274             p = buildD64(coeff);
275             checkInverseDifferentiation(p);
276         }
277     }
278 
279     @Test
280     public void testIntegrate() {
281         // -x^2
282         final double[] coeff = {0, 0, -1};
283         final FieldPolynomialFunction<Binary64> p = buildD64(coeff);
284         Assert.assertEquals(-2d/3d, p.integrate(-1, 1).getReal(),Double.MIN_VALUE);
285 
286         // x(x-1)(x+1) - should integrate to 0 over [-1,1]
287         final FieldPolynomialFunction<Binary64> p2 = buildD64(0, 1).
288                                                       multiply(buildD64(-1, 1)).
289                                                       multiply(buildD64(1, 1));
290         Assert.assertEquals(0, p2.integrate(-1, 1).getReal(), Double.MIN_VALUE);
291     }
292 
293     @Test(expected = MathIllegalArgumentException.class)
294     public void testIntegrateInfiniteBounds() {
295         final FieldPolynomialFunction<Binary64> p = buildD64(1);
296         p.integrate(0, Double.POSITIVE_INFINITY);
297     }
298 
299     @Test(expected = MathIllegalArgumentException.class)
300     public void testIntegrateBadInterval() {
301         final FieldPolynomialFunction<Binary64> p = buildD64(1);
302         p.integrate(0, -1);
303     }
304 
305     @Test
306     public void testIssue259WithComplex() {
307         final double nonZeroParameterForQuadraticCoeff = -1.;
308         final Complex[] coefficients = buildImaginaryCoefficients(1., 2., nonZeroParameterForQuadraticCoeff);
309         templateIssue259DisappearingCoefficients(coefficients);
310     }
311 
312     @Test
313     public void testIssue259WithGradient() {
314         final double nonZeroParameterForQuadraticCoeff = -1.;
315         final Gradient[] coefficients = buildUnivariateGradientCoefficients(1.,2., nonZeroParameterForQuadraticCoeff);
316         templateIssue259DisappearingCoefficients(coefficients);
317     }
318 
319     @Test
320     public void testIssue259WithDerivativeStructure() {
321         final double nonZeroParameterForQuadraticCoeff = -1.;
322         final DerivativeStructure[] coefficients = buildUnivariateDSCoefficients(1.,2., nonZeroParameterForQuadraticCoeff);
323         templateIssue259DisappearingCoefficients(coefficients);
324     }
325 
326     @Test
327     public void testIssue259WithUnivariateDerivative1() {
328         final double nonZeroParameterForQuadraticCoeff = -1.;
329         final UnivariateDerivative1[] coefficients = buildUnivariateDerivative1Coefficients(1.,2., nonZeroParameterForQuadraticCoeff);
330         templateIssue259DisappearingCoefficients(coefficients);
331     }
332 
333     @Test
334     public void testIssue259WithUnivariateDerivative2() {
335         final double nonZeroParameterForQuadraticCoeff = -1.;
336         final UnivariateDerivative2[] coefficients = buildUnivariateDerivative2Coefficients(1.,2., nonZeroParameterForQuadraticCoeff);
337         templateIssue259DisappearingCoefficients(coefficients);
338     }
339 
340     private <T extends CalculusFieldElement<T>> void templateIssue259DisappearingCoefficients(T[] coefficients) {
341         final FieldPolynomialFunction<T> polynomialFunction = new FieldPolynomialFunction<>(coefficients);
342         Assert.assertEquals(coefficients.length, polynomialFunction.getCoefficients().length);
343         for (int i = 0; i < coefficients.length; i++) {
344             Assert.assertEquals(coefficients[i], polynomialFunction.getCoefficients()[i]);
345         }
346     }
347 
348     private <T extends CalculusFieldElement<T>> void checkInverseDifferentiation(FieldPolynomialFunction<T> p) {
349         final T[] c0 = p.getCoefficients();
350         final T[] c1 = p.antiDerivative().polynomialDerivative().getCoefficients();
351         Assert.assertEquals(c0.length, c1.length);
352         for (int i = 0; i < c0.length; ++i) {
353             Assert.assertEquals(c0[i].getReal(), c1[i].getReal(), 1e-12);
354         }
355     }
356 
357     private <T extends CalculusFieldElement<T>> void checkCoeffs(final double tolerance, final FieldPolynomialFunction<T> p,
358                                                                  final double... ref) {
359         final T[] c = p.getCoefficients();
360         Assert.assertEquals(ref.length, c.length);
361         for (int i = 0; i < ref.length; ++i) {
362             Assert.assertEquals(ref[i], c[i].getReal(), tolerance);
363         }
364     }
365 
366     private <T extends CalculusFieldElement<T>> void checkNullPolynomial(FieldPolynomialFunction<T> p) {
367         for (T coefficient : p.getCoefficients()) {
368             Assert.assertEquals(0, coefficient.getReal(), 1e-15);
369         }
370     }
371 
372     private FieldPolynomialFunction<Binary64> buildD64(double...c) {
373         Binary64[] array = new Binary64[c.length];
374         for (int i = 0; i < c.length; ++i) {
375             array[i] = new Binary64(c[i]);
376         }
377         return new FieldPolynomialFunction<>(array);
378     }
379 
380     private Complex[] buildImaginaryCoefficients(double...c) {
381         Complex[] array = new Complex[c.length];
382         for (int i = 0; i < c.length; ++i) {
383             array[i] = new Complex(0., c[i]);
384         }
385         return array;
386     }
387 
388     private DerivativeStructure[] buildUnivariateDSCoefficients(double...c) {
389         DerivativeStructure[] array = new DerivativeStructure[c.length];
390         final DSFactory factory = new DSFactory(1, 1);
391         for (int i = 0; i < c.length; ++i) {
392             array[i] = factory.variable(0, 0.).multiply(c[i]);
393         }
394         return array;
395     }
396 
397     private Gradient[] buildUnivariateGradientCoefficients(double...c) {
398         Gradient[] array = new Gradient[c.length];
399         for (int i = 0; i < c.length; ++i) {
400             array[i] = Gradient.variable(1, 0, 0.).multiply(c[i]);
401         }
402         return array;
403     }
404 
405     private UnivariateDerivative1[] buildUnivariateDerivative1Coefficients(double...c) {
406         UnivariateDerivative1[] array = new UnivariateDerivative1[c.length];
407         for (int i = 0; i < c.length; ++i) {
408             array[i] = new UnivariateDerivative1(0., c[i]);
409         }
410         return array;
411     }
412 
413     private UnivariateDerivative2[] buildUnivariateDerivative2Coefficients(double...c) {
414         UnivariateDerivative2[] array = new UnivariateDerivative2[c.length];
415         for (int i = 0; i < c.length; ++i) {
416             array[i] = new UnivariateDerivative2(0., c[i], 0.);
417         }
418         return array;
419     }
420 
421 }