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  *      http://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.apache.commons.math3.analysis.interpolation;
18 
19 import org.apache.commons.math3.exception.DimensionMismatchException;
20 import org.apache.commons.math3.exception.InsufficientDataException;
21 import org.apache.commons.math3.exception.NonMonotonicSequenceException;
22 import org.apache.commons.math3.exception.NullArgumentException;
23 import org.apache.commons.math3.analysis.BivariateFunction;
24 import org.apache.commons.math3.distribution.UniformRealDistribution;
25 import org.apache.commons.math3.random.RandomGenerator;
26 import org.apache.commons.math3.random.Well19937c;
27 import org.junit.Assert;
28 import org.junit.Test;
29 
30 /**
31  * Test case for the piecewise bicubic interpolator.
32  */
33 public final class PiecewiseBicubicSplineInterpolatorTest {
34     /**
35      * Test preconditions.
36      */
37     @Test
testPreconditions()38     public void testPreconditions() {
39         double[] xval = new double[] { 3, 4, 5, 6.5, 7.5 };
40         double[] yval = new double[] { -4, -3, -1, 2.5, 3.5 };
41         double[][] zval = new double[xval.length][yval.length];
42 
43         BivariateGridInterpolator interpolator = new PiecewiseBicubicSplineInterpolator();
44 
45         try {
46             interpolator.interpolate( null, yval, zval );
47             Assert.fail( "Failed to detect x null pointer" );
48         } catch ( NullArgumentException iae ) {
49             // Expected.
50         }
51 
52         try {
53             interpolator.interpolate( xval, null, zval );
54             Assert.fail( "Failed to detect y null pointer" );
55         } catch ( NullArgumentException iae ) {
56             // Expected.
57         }
58 
59         try {
60             interpolator.interpolate( xval, yval, null );
61             Assert.fail( "Failed to detect z null pointer" );
62         } catch ( NullArgumentException iae ) {
63             // Expected.
64         }
65 
66         try {
67             double xval1[] = { 0.0, 1.0, 2.0, 3.0 };
68             interpolator.interpolate( xval1, yval, zval );
69             Assert.fail( "Failed to detect insufficient x data" );
70         } catch ( InsufficientDataException iae ) {
71             // Expected.
72         }
73 
74         try  {
75             double yval1[] = { 0.0, 1.0, 2.0, 3.0 };
76             interpolator.interpolate( xval, yval1, zval );
77             Assert.fail( "Failed to detect insufficient y data" );
78         } catch ( InsufficientDataException iae ) {
79             // Expected.
80         }
81 
82         try {
83             double zval1[][] = new double[4][4];
84             interpolator.interpolate( xval, yval, zval1 );
85             Assert.fail( "Failed to detect insufficient z data" );
86         } catch ( InsufficientDataException iae ) {
87             // Expected.
88         }
89 
90         try {
91             double xval1[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
92             interpolator.interpolate( xval1, yval, zval );
93             Assert.fail( "Failed to detect data set array with different sizes." );
94         } catch ( DimensionMismatchException iae ) {
95             // Expected.
96         }
97 
98         try {
99             double yval1[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
100             interpolator.interpolate( xval, yval1, zval );
101             Assert.fail( "Failed to detect data set array with different sizes." );
102         } catch ( DimensionMismatchException iae ) {
103             // Expected.
104         }
105 
106         // X values not sorted.
107         try {
108             double xval1[] = { 0.0, 1.0, 0.5, 7.0, 3.5 };
109             interpolator.interpolate( xval1, yval, zval );
110             Assert.fail( "Failed to detect unsorted x arguments." );
111         } catch ( NonMonotonicSequenceException iae ) {
112             // Expected.
113         }
114 
115         // Y values not sorted.
116         try {
117             double yval1[] = { 0.0, 1.0, 1.5, 0.0, 3.0 };
118             interpolator.interpolate( xval, yval1, zval );
119             Assert.fail( "Failed to detect unsorted y arguments." );
120         } catch ( NonMonotonicSequenceException iae ) {
121             // Expected.
122         }
123     }
124 
125     /**
126      * Interpolating a plane.
127      * <p>
128      * z = 2 x - 3 y + 5
129      */
130     @Test
testInterpolation1()131     public void testInterpolation1() {
132         final int sz = 21;
133         double[] xval = new double[sz];
134         double[] yval = new double[sz];
135         // Coordinate values
136         final double delta = 1d / (sz - 1);
137         for ( int i = 0; i < sz; i++ ){
138             xval[i] = -1 + 15 * i * delta;
139             yval[i] = -20 + 30 * i * delta;
140         }
141 
142         // Function values
143         BivariateFunction f = new BivariateFunction() {
144                 public double value( double x, double y ) {
145                     return 2 * x - 3 * y + 5;
146                 }
147             };
148         double[][] zval = new double[xval.length][yval.length];
149         for ( int i = 0; i < xval.length; i++ ) {
150             for ( int j = 0; j < yval.length; j++ ) {
151                 zval[i][j] = f.value(xval[i], yval[j]);
152             }
153         }
154 
155         BivariateGridInterpolator interpolator = new PiecewiseBicubicSplineInterpolator();
156         BivariateFunction p = interpolator.interpolate(xval, yval, zval);
157         double x, y;
158 
159         final RandomGenerator rng = new Well19937c(1234567L); // "tol" depends on the seed.
160         final UniformRealDistribution distX = new UniformRealDistribution( rng, xval[0], xval[xval.length - 1] );
161         final UniformRealDistribution distY = new UniformRealDistribution( rng, yval[0], yval[yval.length - 1] );
162 
163         final int numSamples = 50;
164         final double tol = 2e-14;
165         for ( int i = 0; i < numSamples; i++ ) {
166             x = distX.sample();
167             for ( int j = 0; j < numSamples; j++ ) {
168                 y = distY.sample();
169 //                 System.out.println(x + " " + y + " " + f.value(x, y) + " " + p.value(x, y));
170                 Assert.assertEquals(f.value(x, y),  p.value(x, y), tol);
171             }
172 //             System.out.println();
173         }
174     }
175 
176     /**
177      * Interpolating a paraboloid.
178      * <p>
179      * z = 2 x<sup>2</sup> - 3 y<sup>2</sup> + 4 x y - 5
180      */
181     @Test
testInterpolation2()182     public void testInterpolation2() {
183         final int sz = 21;
184         double[] xval = new double[sz];
185         double[] yval = new double[sz];
186         // Coordinate values
187         final double delta = 1d / (sz - 1);
188         for ( int i = 0; i < sz; i++ ) {
189             xval[i] = -1 + 15 * i * delta;
190             yval[i] = -20 + 30 * i * delta;
191         }
192 
193         // Function values
194         BivariateFunction f = new BivariateFunction() {
195                 public double value( double x, double y ) {
196                     return 2 * x * x - 3 * y * y + 4 * x * y - 5;
197                 }
198             };
199         double[][] zval = new double[xval.length][yval.length];
200         for ( int i = 0; i < xval.length; i++ ) {
201             for ( int j = 0; j < yval.length; j++ ) {
202                 zval[i][j] = f.value(xval[i], yval[j]);
203             }
204         }
205 
206         BivariateGridInterpolator interpolator = new PiecewiseBicubicSplineInterpolator();
207         BivariateFunction p = interpolator.interpolate(xval, yval, zval);
208         double x, y;
209 
210         final RandomGenerator rng = new Well19937c(1234567L); // "tol" depends on the seed.
211         final UniformRealDistribution distX = new UniformRealDistribution( rng, xval[0], xval[xval.length - 1] );
212         final UniformRealDistribution distY = new UniformRealDistribution( rng, yval[0], yval[yval.length - 1] );
213 
214         final int numSamples = 50;
215         final double tol = 5e-13;
216         for ( int i = 0; i < numSamples; i++ ) {
217             x = distX.sample();
218             for ( int j = 0; j < numSamples; j++ ) {
219                 y = distY.sample();
220 //                 System.out.println(x + " " + y + " " + f.value(x, y) + " " + p.value(x, y));
221                 Assert.assertEquals(f.value(x, y),  p.value(x, y), tol);
222             }
223 //             System.out.println();
224         }
225     }
226 }
227