View Javadoc
1   /*
2    * Licensed to the Hipparchus project 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 Hipparchus project 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  package org.hipparchus.analysis.interpolation;
18  
19  import org.hipparchus.exception.LocalizedCoreFormats;
20  import org.hipparchus.exception.MathIllegalArgumentException;
21  import org.hipparchus.random.RandomGenerator;
22  import org.hipparchus.random.Well1024a;
23  import org.junit.jupiter.api.Test;
24  
25  import java.util.Arrays;
26  
27  import static org.junit.jupiter.api.Assertions.assertEquals;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  import static org.junit.jupiter.api.Assertions.fail;
30  
31  class GridAxisTest {
32  
33      @Test
34      void testLinearAscending() {
35          for (int n = 2; n < 12; ++n) {
36              checkAscending(createLinear(25, n));
37          }
38      }
39  
40      @Test
41      void testLinearDescending() {
42          for (int n = 2; n < 12; ++n) {
43              checkDescending(createLinear(25, n));
44          }
45      }
46  
47      @Test
48      void testLinearRandomAccess() {
49          final RandomGenerator random = new Well1024a(0x967ab81207d7b2f4l);
50          for (int n = 2; n < 12; ++n) {
51              checkRandomAccess(random, createLinear(25, n));
52          }
53      }
54  
55      @Test
56      void testQuadraticAscending() {
57          for (int n = 2; n < 12; ++n) {
58              checkAscending(createQuadratic(25, n));
59          }
60      }
61  
62      @Test
63      void testQuadraticDescending() {
64          for (int n = 2; n < 12; ++n) {
65              checkDescending(createQuadratic(25, n));
66          }
67      }
68  
69      @Test
70      void testQuadraticRandomAccess() {
71          final RandomGenerator random = new Well1024a(0x80fc3b30a2da4549l);
72          for (int n = 2; n < 12; ++n) {
73              checkRandomAccess(random, createQuadratic(25, n));
74          }
75      }
76  
77      @Test
78      void testIrregularAscending() {
79          final RandomGenerator random = new Well1024a(0x66133fa03616fbc9l);
80          for (int n = 2; n < 12; ++n) {
81              checkAscending(createIrregular(random, 25, n));
82          }
83      }
84  
85      @Test
86      void testIrregularDescending() {
87          final RandomGenerator random = new Well1024a(0x72404bbdc66bc2c7l);
88          for (int n = 2; n < 12; ++n) {
89              checkDescending(createIrregular(random, 25, n));
90          }
91      }
92  
93      @Test
94      void testIrregularRandomAccess() {
95          final RandomGenerator random = new Well1024a(0x254fbf2a8207e0f6l);
96          for (int n = 2; n < 12; ++n) {
97              checkRandomAccess(random, createIrregular(random, 25, n));
98          }
99      }
100 
101     @Test
102     void testTooSmallGrid() {
103         try {
104             new GridAxis(new double[3], 4);
105             fail("an exception should have been thrown");
106         } catch (MathIllegalArgumentException miae) {
107             assertEquals(LocalizedCoreFormats.INSUFFICIENT_DIMENSION, miae.getSpecifier());
108             assertEquals(3, ((Integer) miae.getParts()[0]).intValue());
109             assertEquals(4, ((Integer) miae.getParts()[1]).intValue());
110         }
111     }
112 
113     @Test
114     void testDuplicate() {
115         try {
116             new GridAxis(new double[] { 0.0, 1.0, 2.0, 2.0, 3.0 }, 2);
117             fail("an exception should have been thrown");
118         } catch (MathIllegalArgumentException miae) {
119             assertEquals(LocalizedCoreFormats.NOT_STRICTLY_INCREASING_SEQUENCE, miae.getSpecifier());
120             assertEquals(2.0, ((Double)  miae.getParts()[0]).doubleValue(), 1.0e-15);
121             assertEquals(2.0, ((Double)  miae.getParts()[1]).doubleValue(), 1.0e-15);
122             assertEquals(3,   ((Integer) miae.getParts()[2]).intValue());
123             assertEquals(2,   ((Integer) miae.getParts()[3]).intValue());
124         }
125     }
126 
127     @Test
128     void testUnsorted() {
129         try {
130             new GridAxis(new double[] { 0.0, 1.0, 0.5, 2.0, 3.0 }, 2);
131             fail("an exception should have been thrown");
132         } catch (MathIllegalArgumentException miae) {
133             assertEquals(LocalizedCoreFormats.NOT_STRICTLY_INCREASING_SEQUENCE, miae.getSpecifier());
134             assertEquals(0.5, ((Double)  miae.getParts()[0]).doubleValue(), 1.0e-15);
135             assertEquals(1.0, ((Double)  miae.getParts()[1]).doubleValue(), 1.0e-15);
136             assertEquals(2,   ((Integer) miae.getParts()[2]).intValue());
137             assertEquals(1,   ((Integer) miae.getParts()[3]).intValue());
138         }
139     }
140 
141     private GridAxis createLinear(final int size, final int n) {
142         final double[] gridData = new double[size];
143         for (int i = 0; i < size; ++i) {
144             gridData[i] = 2 * i + 0.5;
145         }
146         return create(gridData, n);
147     }
148 
149     private GridAxis createQuadratic(final int size, final int n) {
150         final double[] gridData = new double[size];
151         for (int i = 0; i < size; ++i) {
152             gridData[i] = (i + 0.5) * (i + 3);
153         }
154         return create(gridData, n);
155     }
156 
157     private GridAxis createIrregular(final RandomGenerator random, final int size, final int n) {
158         final double[] gridData = new double[size];
159         for (int i = 0; i < size; ++i) {
160             gridData[i] = 50.0 * random.nextDouble();
161         }
162         Arrays.sort(gridData);
163         return create(gridData, n);
164     }
165 
166     private GridAxis create(final double[] gridData, final int n) {
167         final GridAxis gridAxis = new GridAxis(gridData, n);
168         assertEquals(n, gridAxis.getN());
169         for (int i = 0; i < 5; ++i) {
170             assertEquals(gridData[i], gridAxis.node(i), 1.0e-15);
171         }
172         return gridAxis;
173     }
174 
175     private void checkAscending(final GridAxis gridAxis) {
176         final double inf = gridAxis.node(0) - 2.0;
177         final double sup = gridAxis.node(gridAxis.size() - 1) + 2.0;
178         for (double t = inf; t < sup; t += 0.125) {
179             checkInterpolation(t, gridAxis);
180         }
181     }
182 
183     private void checkDescending(final GridAxis gridAxis) {
184         final double inf = gridAxis.node(0) - 2.0;
185         final double sup = gridAxis.node(gridAxis.size() - 1) + 2.0;
186         for (double t = sup; t > inf; t -= 0.125) {
187             checkInterpolation(t, gridAxis);
188         }
189     }
190 
191     private void checkRandomAccess(final RandomGenerator random, final GridAxis gridAxis) {
192         final double inf = gridAxis.node(0) - 2.0;
193         final double sup = gridAxis.node(gridAxis.size() - 1) + 2.0;
194         for (int i = 0; i < 1000; ++i) {
195             checkInterpolation(inf + random.nextDouble() * (sup - inf), gridAxis);
196         }
197     }
198 
199     private void checkInterpolation(final double t, final GridAxis gridAxis) {
200         final int s = gridAxis.size();
201         final int n = gridAxis.getN();
202         final int o = (n - 1) / 2;
203         final int p = n / 2;
204         final int i = gridAxis.interpolationIndex(t);
205         assertTrue(i >= 0);
206         assertTrue(i + n - 1 < s);
207         if (t < gridAxis.node(0)) {
208             // extrapolating below grid
209             assertEquals(0, i);
210         } else if (t < gridAxis.node(s - 1)) {
211 
212             // interpolating within the grid
213             // the nodes should surround the test value
214             assertTrue(gridAxis.node(i) <= t);
215             assertTrue(gridAxis.node(i + n - 1) > t);
216 
217             if (t >= gridAxis.node(o) && t <  gridAxis.node(s - p)) {
218                 // interpolation in the part of the grid where balancing is possible
219                 // the central nodes should surround the test value
220                 assertTrue(gridAxis.node(i + o)     <= t);
221                 assertTrue(gridAxis.node(i + o + 1) >  t);
222             }
223 
224         } else {
225             // extrapolating above grid
226             assertEquals(s - n, i);
227         }
228     }
229 
230 }