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 java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  
27  import org.hipparchus.analysis.MultivariateFunction;
28  import org.hipparchus.exception.LocalizedCoreFormats;
29  import org.hipparchus.exception.MathIllegalArgumentException;
30  import org.hipparchus.exception.MathIllegalStateException;
31  import org.hipparchus.random.RandomGenerator;
32  import org.hipparchus.random.UnitSphereRandomVectorGenerator;
33  import org.hipparchus.random.Well1024a;
34  import org.hipparchus.random.Well19937a;
35  import org.hipparchus.util.FastMath;
36  import org.junit.Assert;
37  import org.junit.Test;
38  
39  /**
40   * Test case for the {@link MicrosphereProjectionInterpolator
41   * "microsphere projection"} interpolator.
42   */
43  public final class MicrosphereProjectionInterpolatorTest {
44      /**
45       * Test of interpolator for a plane.
46       * <p>
47       * y = 2 x<sub>1</sub> - 3 x<sub>2</sub> + 5
48       */
49      @Test
50      public void testLinearFunction2D() {
51          MultivariateFunction f = new MultivariateFunction() {
52              @Override
53              public double value(double[] x) {
54                  if (x.length != 2) {
55                      throw new IllegalArgumentException();
56                  }
57                  return 2 * x[0] - 3 * x[1] + 5;
58              }
59          };
60  
61          final double darkFraction = 0.5;
62          final double darkThreshold = 1e-2;
63          final double background = Double.NaN;
64          final double exponent = 1.1;
65          final boolean shareSphere = true;
66          final double noInterpolationTolerance = Math.ulp(1d);
67          final RandomGenerator random = new Well1024a(0x1c7a150c83a6d9dal);
68  
69          // N-dimensional interpolator.
70          final MultivariateInterpolator interpolator
71              = new MicrosphereProjectionInterpolator(new InterpolatingMicrosphere(2, 500,
72                                                      darkFraction,
73                                                      darkThreshold,
74                                                      background,
75                                                      new UnitSphereRandomVectorGenerator(2, random)),
76                                                      exponent,
77                                                      shareSphere,
78                                                      noInterpolationTolerance);
79  
80          // 2D interpolator.
81          final MultivariateInterpolator interpolator2D
82              = new MicrosphereProjectionInterpolator(new InterpolatingMicrosphere2D(16,
83                                                                                     darkFraction,
84                                                                                     darkThreshold,
85                                                                                     background),
86                                                      exponent,
87                                                      shareSphere,
88                                                      noInterpolationTolerance);
89  
90          final double min = -1;
91          final double max = 1;
92          final double range = max - min;
93          final int res = 5;
94          final int n = res * res; // Number of sample points.
95          final int dim = 2;
96          double[][] x = new double[n][dim];
97          double[] y = new double[n];
98          int index = 0;
99          for (int i = 0; i < res; i++) {
100             final double x1Val = toCoordinate(min, range, res, i);
101             for (int j = 0; j < res; j++) {
102                 final double x2Val = toCoordinate(min, range, res, j);
103                 x[index][0] = x1Val;
104                 x[index][1] = x2Val;
105                 y[index] = f.value(x[index]);
106                 ++index;
107             }
108         }
109 
110         final MultivariateFunction p = interpolator.interpolate(x, y);
111         final MultivariateFunction p2D = interpolator2D.interpolate(x, y);
112 
113         double[] c = new double[dim];
114         double expected, result, result2D;
115 
116         final int sampleIndex = 2;
117         c[0] = x[sampleIndex][0];
118         c[1] = x[sampleIndex][1];
119         expected = f.value(c);
120         result = p.value(c);
121         result2D = p2D.value(c);
122         Assert.assertEquals("on sample point (exact)", expected, result2D, FastMath.ulp(1d));
123         Assert.assertEquals("on sample point (ND vs 2D)", result2D, result, FastMath.ulp(1d));
124 
125         // Interpolation.
126         c[0] = 0.654321;
127         c[1] = -0.345678;
128         expected = f.value(c);
129         result = p.value(c);
130         result2D = p2D.value(c);
131         Assert.assertEquals("interpolation (exact)", expected, result2D, 1e-1);
132         Assert.assertEquals("interpolation (ND vs 2D)", result2D, result, 1e-1);
133 
134         // Extrapolation.
135         c[0] = 0 - 1e-2;
136         c[1] = 1 + 1e-2;
137         expected = f.value(c);
138         result = p.value(c);
139         result2D = p2D.value(c);
140         Assert.assertFalse(Double.isNaN(result));
141         Assert.assertFalse(Double.isNaN(result2D));
142         Assert.assertEquals("extrapolation (exact)", expected, result2D, 1e-1);
143         Assert.assertEquals("extrapolation (ND vs 2D)", result2D, result, 1e-2);
144 
145         // Far away.
146         c[0] = 20;
147         c[1] = -30;
148         result = p.value(c);
149         Assert.assertTrue(result + " should be NaN", Double.isNaN(result));
150         result2D = p2D.value(c);
151         Assert.assertTrue(result2D + " should be NaN", Double.isNaN(result2D));
152     }
153     
154     @Test
155     public void testWrongDimensions() {
156         checkWrongArguments(0, 1, 0.5, 0.0, 0.0,
157                             LocalizedCoreFormats.NUMBER_TOO_SMALL_BOUND_EXCLUDED);
158         checkWrongArguments(1, 0, 0.5, 0.0, 0.0,
159                             LocalizedCoreFormats.NUMBER_TOO_SMALL_BOUND_EXCLUDED);
160         checkWrongArguments(1, 1, 0.5, -1.0, 0.0,
161                             LocalizedCoreFormats.NUMBER_TOO_SMALL);
162     }
163 
164     private void checkWrongArguments(int dimension,
165                                      int size,
166                                      double maxDarkFraction,
167                                      double darkThreshold,
168                                      double background,
169                                      LocalizedCoreFormats expected) {
170         try {
171             new InterpolatingMicrosphere(dimension, size, maxDarkFraction, darkThreshold, background, null);
172             Assert.fail("an exception should have been thrown");
173         } catch (MathIllegalArgumentException miae) {
174             Assert.assertEquals(expected, miae.getSpecifier());
175         }
176     }
177 
178     @Test
179     public void testCopy() {
180         UnitSphereRandomVectorGenerator random =
181                         new UnitSphereRandomVectorGenerator(3, new Well19937a(0x265318ael));
182         InterpolatingMicrosphere original = new InterpolatingMicrosphere(3, 30, 0.5, 0.2, 0.0, random);
183         InterpolatingMicrosphere copy     = original.copy();
184         Assert.assertFalse(original == copy);
185         Assert.assertEquals(original.getDimension(), copy.getDimension());
186         Assert.assertEquals(original.getSize(),      copy.getSize());
187     }
188 
189     @Test
190     public void testSizeLimit() {
191         UnitSphereRandomVectorGenerator random =
192                         new UnitSphereRandomVectorGenerator(3, new Well19937a(0x453l));
193         InterpolatingMicrosphere ims = new InterpolatingMicrosphere(3, 30, 0.5, 0.2, 0.0, random);
194         try {
195             Method add = InterpolatingMicrosphere.class.getDeclaredMethod("add", double[].class, Boolean.TYPE);
196             add.setAccessible(true);
197             try {
198                 add.invoke(ims, random.nextVector(), true);
199                 Assert.fail("an exception should have been thrown");
200             } catch (InvocationTargetException ite) {
201                 MathIllegalStateException miae = (MathIllegalStateException) ite.getCause();
202                 Assert.assertEquals(LocalizedCoreFormats.MAX_COUNT_EXCEEDED, miae.getSpecifier());
203             }
204         } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException e) {
205             Assert.fail(e.getLocalizedMessage());
206         }
207     }
208 
209     @Test
210     public void testInconsistentDimensions() {
211         final int d1 = 5;
212         final int d2 = 3;
213         try {
214             UnitSphereRandomVectorGenerator random =
215                             new UnitSphereRandomVectorGenerator(d1, new Well19937a(0x1l));
216             new InterpolatingMicrosphere(d2, 30, 0.5, 0.2, 0.0, random);
217             Assert.fail("an exception should have been thrown");
218         } catch (MathIllegalArgumentException miae) {
219             Assert.assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
220             Assert.assertEquals(d1, ((Integer) miae.getParts()[0]).intValue());
221             Assert.assertEquals(d2, ((Integer) miae.getParts()[1]).intValue());
222         }
223     }
224 
225     /**
226      * @param min Minimum of the coordinate range.
227      * @param range Extent of the coordinate interval.
228      * @param res Number of pixels.
229      * @param pixel Pixel index.
230      */
231     private static double toCoordinate(double min,
232                                        double range,
233                                        int res,
234                                        int pixel) {
235         return pixel * range / (res - 1) + min;
236     }
237 }