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.interpolation;
23  
24  import org.hipparchus.analysis.polynomials.PolynomialFunction;
25  import org.hipparchus.dfp.Dfp;
26  import org.hipparchus.dfp.DfpField;
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.fraction.BigFraction;
29  import org.hipparchus.util.FastMath;
30  import org.junit.jupiter.api.Test;
31  
32  import java.util.Random;
33  
34  import static org.junit.jupiter.api.Assertions.assertEquals;
35  import static org.junit.jupiter.api.Assertions.assertThrows;
36  
37  class FieldHermiteInterpolatorTest {
38  
39      @Test
40      void testZero() {
41          FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
42          interpolator.addSamplePoint(new BigFraction(0), new BigFraction[] { new BigFraction(0) });
43          for (int x = -10; x < 10; x++) {
44              BigFraction y = interpolator.value(new BigFraction(x))[0];
45              assertEquals(BigFraction.ZERO, y);
46              BigFraction[][] derivatives = interpolator.derivatives(new BigFraction(x), 1);
47              assertEquals(BigFraction.ZERO, derivatives[0][0]);
48              assertEquals(BigFraction.ZERO, derivatives[1][0]);
49          }
50      }
51  
52      @Test
53      void testQuadratic() {
54          FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
55          interpolator.addSamplePoint(new BigFraction(0), new BigFraction[] { new BigFraction(2) });
56          interpolator.addSamplePoint(new BigFraction(1), new BigFraction[] { new BigFraction(0) });
57          interpolator.addSamplePoint(new BigFraction(2), new BigFraction[] { new BigFraction(0) });
58          for (double x = -10; x < 10; x += 1.0) {
59              BigFraction y = interpolator.value(new BigFraction(x))[0];
60              assertEquals((x - 1) * (x - 2), y.doubleValue(), 1.0e-15);
61              BigFraction[][] derivatives = interpolator.derivatives(new BigFraction(x), 3);
62              assertEquals((x - 1) * (x - 2), derivatives[0][0].doubleValue(), 1.0e-15);
63              assertEquals(2 * x - 3, derivatives[1][0].doubleValue(), 1.0e-15);
64              assertEquals(2, derivatives[2][0].doubleValue(), 1.0e-15);
65              assertEquals(0, derivatives[3][0].doubleValue(), 1.0e-15);
66          }
67      }
68  
69      @Test
70      void testMixedDerivatives() {
71          FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
72          interpolator.addSamplePoint(new BigFraction(0), new BigFraction[] { new BigFraction(1) }, new BigFraction[] { new BigFraction(2) });
73          interpolator.addSamplePoint(new BigFraction(1), new BigFraction[] { new BigFraction(4) });
74          interpolator.addSamplePoint(new BigFraction(2), new BigFraction[] { new BigFraction(5) }, new BigFraction[] { new BigFraction(2) });
75          BigFraction[][] derivatives = interpolator.derivatives(new BigFraction(0), 5);
76          assertEquals(new BigFraction(  1), derivatives[0][0]);
77          assertEquals(new BigFraction(  2), derivatives[1][0]);
78          assertEquals(new BigFraction(  8), derivatives[2][0]);
79          assertEquals(new BigFraction(-24), derivatives[3][0]);
80          assertEquals(new BigFraction( 24), derivatives[4][0]);
81          assertEquals(new BigFraction(  0), derivatives[5][0]);
82          derivatives = interpolator.derivatives(new BigFraction(1), 5);
83          assertEquals(new BigFraction(  4), derivatives[0][0]);
84          assertEquals(new BigFraction(  2), derivatives[1][0]);
85          assertEquals(new BigFraction( -4), derivatives[2][0]);
86          assertEquals(new BigFraction(  0), derivatives[3][0]);
87          assertEquals(new BigFraction( 24), derivatives[4][0]);
88          assertEquals(new BigFraction(  0), derivatives[5][0]);
89          derivatives = interpolator.derivatives(new BigFraction(2), 5);
90          assertEquals(new BigFraction(  5), derivatives[0][0]);
91          assertEquals(new BigFraction(  2), derivatives[1][0]);
92          assertEquals(new BigFraction(  8), derivatives[2][0]);
93          assertEquals(new BigFraction( 24), derivatives[3][0]);
94          assertEquals(new BigFraction( 24), derivatives[4][0]);
95          assertEquals(new BigFraction(  0), derivatives[5][0]);
96      }
97  
98      @Test
99      void testRandomPolynomialsValuesOnly() {
100 
101         Random random = new Random(0x42b1e7dbd361a932l);
102 
103         for (int i = 0; i < 100; ++i) {
104 
105             int maxDegree = 0;
106             PolynomialFunction[] p = new PolynomialFunction[5];
107             for (int k = 0; k < p.length; ++k) {
108                 int degree = random.nextInt(7);
109                 p[k] = randomPolynomial(degree, random);
110                 maxDegree = FastMath.max(maxDegree, degree);
111             }
112 
113             DfpField field = new DfpField(30);
114             Dfp step = field.getOne().divide(field.newDfp(10));
115             FieldHermiteInterpolator<Dfp> interpolator = new FieldHermiteInterpolator<Dfp>();
116             for (int j = 0; j < 1 + maxDegree; ++j) {
117                 Dfp x = field.newDfp(j).multiply(step);
118                 Dfp[] values = new Dfp[p.length];
119                 for (int k = 0; k < p.length; ++k) {
120                     values[k] = field.newDfp(p[k].value(x.getReal()));
121                 }
122                 interpolator.addSamplePoint(x, values);
123             }
124 
125             for (int j = 0; j < 20; ++j) {
126                 Dfp x = field.newDfp(j).multiply(step);
127                 Dfp[] values = interpolator.value(x);
128                 assertEquals(p.length, values.length);
129                 for (int k = 0; k < p.length; ++k) {
130                     assertEquals(p[k].value(x.getReal()),
131                                         values[k].getReal(),
132                                         1.0e-8 * FastMath.abs(p[k].value(x.getReal())));
133                 }
134             }
135 
136         }
137 
138     }
139 
140     @Test
141     void testRandomPolynomialsFirstDerivative() {
142 
143         Random random = new Random(0x570803c982ca5d3bl);
144 
145         for (int i = 0; i < 100; ++i) {
146 
147             int maxDegree = 0;
148             PolynomialFunction[] p      = new PolynomialFunction[5];
149             PolynomialFunction[] pPrime = new PolynomialFunction[5];
150             for (int k = 0; k < p.length; ++k) {
151                 int degree = random.nextInt(7);
152                 p[k]      = randomPolynomial(degree, random);
153                 pPrime[k] = p[k].polynomialDerivative();
154                 maxDegree = FastMath.max(maxDegree, degree);
155             }
156 
157             DfpField field = new DfpField(30);
158             Dfp step = field.getOne().divide(field.newDfp(10));
159             FieldHermiteInterpolator<Dfp> interpolator = new FieldHermiteInterpolator<Dfp>();
160             for (int j = 0; j < 1 + maxDegree / 2; ++j) {
161                 Dfp x = field.newDfp(j).multiply(step);
162                 Dfp[] values      = new Dfp[p.length];
163                 Dfp[] derivatives = new Dfp[p.length];
164                 for (int k = 0; k < p.length; ++k) {
165                     values[k]      = field.newDfp(p[k].value(x.getReal()));
166                     derivatives[k] = field.newDfp(pPrime[k].value(x.getReal()));
167                 }
168                 interpolator.addSamplePoint(x, values, derivatives);
169             }
170 
171             Dfp h = step.divide(field.newDfp(100000));
172             for (int j = 0; j < 20; ++j) {
173                 Dfp x = field.newDfp(j).multiply(step);
174                 Dfp[] y  = interpolator.value(x);
175                 Dfp[] yP = interpolator.value(x.add(h));
176                 Dfp[] yM = interpolator.value(x.subtract(h));
177                 assertEquals(p.length, y.length);
178                 for (int k = 0; k < p.length; ++k) {
179                     assertEquals(p[k].value(x.getReal()),
180                                         y[k].getReal(),
181                                         1.0e-8 * FastMath.abs(p[k].value(x.getReal())));
182                     assertEquals(pPrime[k].value(x.getReal()),
183                                         yP[k].subtract(yM[k]).divide(h.multiply(2)).getReal(),
184                                         4.0e-8 * FastMath.abs(p[k].value(x.getReal())));
185                 }
186             }
187 
188         }
189     }
190 
191     @Test
192     void testSine() {
193         DfpField field = new DfpField(30);
194         FieldHermiteInterpolator<Dfp> interpolator = new FieldHermiteInterpolator<Dfp>();
195         for (Dfp x = field.getZero(); x.getReal() < FastMath.PI; x = x.add(0.5)) {
196             interpolator.addSamplePoint(x, new Dfp[] { x.sin() });
197         }
198         for (Dfp x = field.newDfp(0.1); x.getReal() < 2.9; x = x.add(0.01)) {
199             Dfp y = interpolator.value(x)[0];
200             assertEquals( x.sin().getReal(), y.getReal(), 3.5e-5);
201         }
202     }
203 
204     @Test
205     void testSquareRoot() {
206         DfpField field = new DfpField(30);
207         FieldHermiteInterpolator<Dfp> interpolator = new FieldHermiteInterpolator<Dfp>();
208         for (Dfp x = field.getOne(); x.getReal() < 3.6; x = x.add(0.5)) {
209             interpolator.addSamplePoint(x, new Dfp[] { x.sqrt() });
210         }
211         for (Dfp x = field.newDfp(1.1); x.getReal() < 3.5; x = x.add(0.01)) {
212             Dfp y = interpolator.value(x)[0];
213             assertEquals(x.sqrt().getReal(), y.getReal(), 1.5e-4);
214         }
215     }
216 
217     @Test
218     void testWikipedia() {
219         // this test corresponds to the example from Wikipedia page:
220         // http://en.wikipedia.org/wiki/Hermite_interpolation
221         FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
222         interpolator.addSamplePoint(new BigFraction(-1),
223                                     new BigFraction[] { new BigFraction( 2) },
224                                     new BigFraction[] { new BigFraction(-8) },
225                                     new BigFraction[] { new BigFraction(56) });
226         interpolator.addSamplePoint(new BigFraction( 0),
227                                     new BigFraction[] { new BigFraction( 1) },
228                                     new BigFraction[] { new BigFraction( 0) },
229                                     new BigFraction[] { new BigFraction( 0) });
230         interpolator.addSamplePoint(new BigFraction( 1),
231                                     new BigFraction[] { new BigFraction( 2) },
232                                     new BigFraction[] { new BigFraction( 8) },
233                                     new BigFraction[] { new BigFraction(56) });
234         for (BigFraction x = new BigFraction(-1); x.doubleValue() <= 1.0; x = x.add(new BigFraction(1, 8))) {
235             BigFraction y = interpolator.value(x)[0];
236             BigFraction x2 = x.multiply(x);
237             BigFraction x4 = x2.multiply(x2);
238             BigFraction x8 = x4.multiply(x4);
239             assertEquals(x8.add(new BigFraction(1)), y);
240         }
241     }
242 
243     @Test
244     void testOnePointParabola() {
245         FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
246         interpolator.addSamplePoint(new BigFraction(0),
247                                     new BigFraction[] { new BigFraction(1) },
248                                     new BigFraction[] { new BigFraction(1) },
249                                     new BigFraction[] { new BigFraction(2) });
250         for (BigFraction x = new BigFraction(-1); x.doubleValue() <= 1.0; x = x.add(new BigFraction(1, 8))) {
251             BigFraction y = interpolator.value(x)[0];
252             assertEquals(BigFraction.ONE.add(x.multiply(BigFraction.ONE.add(x))), y);
253         }
254     }
255 
256     private PolynomialFunction randomPolynomial(int degree, Random random) {
257         double[] coeff = new double[ 1 + degree];
258         for (int j = 0; j < degree; ++j) {
259             coeff[j] = random.nextDouble();
260         }
261         return new PolynomialFunction(coeff);
262     }
263 
264     @Test
265     void testEmptySampleValue() {
266         assertThrows(MathIllegalArgumentException.class, () -> {
267             new FieldHermiteInterpolator<BigFraction>().value(BigFraction.ZERO);
268         });
269     }
270 
271     @Test
272     void testEmptySampleDerivative() {
273         assertThrows(MathIllegalArgumentException.class, () -> {
274             new FieldHermiteInterpolator<BigFraction>().derivatives(BigFraction.ZERO, 1);
275         });
276     }
277 
278     @Test
279     void testDuplicatedAbscissa() {
280         assertThrows(MathIllegalArgumentException.class, () -> {
281             FieldHermiteInterpolator<BigFraction> interpolator = new FieldHermiteInterpolator<BigFraction>();
282             interpolator.addSamplePoint(new BigFraction(1), new BigFraction[]{new BigFraction(0)});
283             interpolator.addSamplePoint(new BigFraction(1), new BigFraction[]{new BigFraction(1)});
284         });
285     }
286 
287 }
288