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