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 java.util.Arrays;
25  
26  import org.hipparchus.exception.LocalizedCoreFormats;
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.exception.MathIllegalStateException;
29  import org.hipparchus.util.Binary64;
30  import org.junit.Assert;
31  import org.junit.Test;
32  
33  /**
34   * Tests the PolynomialSplineFunction implementation.
35   *
36   */
37  public class PolynomialSplineFunctionTest {
38  
39      /** Error tolerance for tests */
40      protected double tolerance = 1.0e-12;
41  
42      /**
43       * Quadratic polynomials used in tests:
44       *
45       * x^2 + x            [-1, 0)
46       * x^2 + x + 2        [0, 1)
47       * x^2 + x + 4        [1, 2)
48       *
49       * Defined so that evaluation using PolynomialSplineFunction evaluation
50       * algorithm agrees at knot point boundaries.
51       */
52      protected PolynomialFunction[] polynomials = {
53          new PolynomialFunction(new double[] {0d, 1d, 1d}),
54          new PolynomialFunction(new double[] {2d, 1d, 1d}),
55          new PolynomialFunction(new double[] {4d, 1d, 1d})
56      };
57  
58      /** Knot points  */
59      protected double[] knots = {-1, 0, 1, 2};
60  
61      /** Derivative of test polynomials -- 2x + 1  */
62      protected PolynomialFunction dp =
63          new PolynomialFunction(new double[] {1d, 2d});
64  
65  
66      @Test
67      public void testConstructor() {
68          PolynomialSplineFunction spline =
69              new PolynomialSplineFunction(knots, polynomials);
70          Assert.assertTrue(Arrays.equals(knots, spline.getKnots()));
71          Assert.assertEquals(1d, spline.getPolynomials()[0].getCoefficients()[2], 0);
72          Assert.assertEquals(3, spline.getN());
73  
74          try { // too few knots
75              new PolynomialSplineFunction(new double[] {0}, polynomials);
76              Assert.fail("Expecting MathIllegalArgumentException");
77          } catch (MathIllegalArgumentException ex) {
78              // expected
79          }
80  
81          try { // too many knots
82              new PolynomialSplineFunction(new double[] {0,1,2,3,4}, polynomials);
83              Assert.fail("Expecting MathIllegalArgumentException");
84          } catch (MathIllegalArgumentException ex) {
85              // expected
86          }
87  
88          try { // knots not increasing
89              new PolynomialSplineFunction(new double[] {0,1, 3, 2}, polynomials);
90              Assert.fail("Expecting MathIllegalArgumentException");
91          } catch (MathIllegalArgumentException ex) {
92              // expected
93          }
94      }
95  
96      @Test
97      public void testValues() {
98          PolynomialSplineFunction spline =
99              new PolynomialSplineFunction(knots, polynomials);
100         PolynomialSplineFunction dSpline = spline.polynomialSplineDerivative();
101 
102         /**
103          * interior points -- spline value at x should equal p(x - knot)
104          * where knot is the largest knot point less than or equal to x and p
105          * is the polynomial defined over the knot segment to which x belongs.
106          */
107         double x = -1;
108         int index = 0;
109         for (int i = 0; i < 10; i++) {
110            x+=0.25;
111            index = findKnot(knots, x);
112            Assert.assertEquals("spline function evaluation failed for x=" + x,
113                    polynomials[index].value(x - knots[index]), spline.value(x), tolerance);
114            Assert.assertEquals("spline derivative evaluation failed for x=" + x,
115                    dp.value(x - knots[index]), dSpline.value(x), tolerance);
116         }
117 
118         // knot points -- centering should zero arguments
119         for (int i = 0; i < 3; i++) {
120             Assert.assertEquals("spline function evaluation failed for knot=" + knots[i],
121                     polynomials[i].value(0), spline.value(knots[i]), tolerance);
122             Assert.assertEquals("spline function evaluation failed for knot=" + knots[i],
123                     dp.value(0), dSpline.value(new Binary64(knots[i])).getReal(), tolerance);
124         }
125 
126         try { //outside of domain -- under min
127             x = spline.value(-1.5);
128             Assert.fail("Expecting MathIllegalArgumentException");
129         } catch (MathIllegalArgumentException ex) {
130             // expected
131         }
132 
133         try { //outside of domain -- over max
134             x = spline.value(2.5);
135             Assert.fail("Expecting MathIllegalArgumentException");
136         } catch (MathIllegalArgumentException ex) {
137             // expected
138         }
139     }
140 
141     @Test
142     public void testIsValidPoint() {
143         final PolynomialSplineFunction spline =
144             new PolynomialSplineFunction(knots, polynomials);
145         final double xMin = knots[0];
146         final double xMax = knots[knots.length - 1];
147 
148         double x;
149 
150         x = xMin;
151         Assert.assertTrue(spline.isValidPoint(x));
152         // Ensure that no exception is thrown.
153         spline.value(x);
154 
155         x = xMax;
156         Assert.assertTrue(spline.isValidPoint(x));
157         // Ensure that no exception is thrown.
158         spline.value(x);
159 
160         final double xRange = xMax - xMin;
161         x = xMin + xRange / 3.4;
162         Assert.assertTrue(spline.isValidPoint(x));
163         // Ensure that no exception is thrown.
164         spline.value(x);
165 
166         final double small = 1e-8;
167         x = xMin - small;
168         Assert.assertFalse(spline.isValidPoint(x));
169         // Ensure that an exception would have been thrown.
170         try {
171             spline.value(x);
172             Assert.fail("MathIllegalArgumentException expected");
173         } catch (MathIllegalArgumentException expected) {}
174     }
175 
176     /**
177      *  Do linear search to find largest knot point less than or equal to x.
178      *  Implementation does binary search.
179      */
180      protected int findKnot(double[] knots, double x) {
181          if (x < knots[0] || x >= knots[knots.length -1]) {
182              throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
183                                                     x, knots[0], knots[knots.length -1]);
184          }
185          for (int i = 0; i < knots.length; i++) {
186              if (knots[i] > x) {
187                  return i - 1;
188              }
189          }
190          throw new MathIllegalStateException(LocalizedCoreFormats.ILLEGAL_STATE);
191      }
192 }
193