source: src/main/java/agents/anac/y2019/harddealer/math3/analysis/interpolation/BicubicInterpolatingFunction.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 11.2 KB
Line 
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 */
17package agents.anac.y2019.harddealer.math3.analysis.interpolation;
18
19import java.util.Arrays;
20import agents.anac.y2019.harddealer.math3.analysis.BivariateFunction;
21import agents.anac.y2019.harddealer.math3.exception.DimensionMismatchException;
22import agents.anac.y2019.harddealer.math3.exception.NoDataException;
23import agents.anac.y2019.harddealer.math3.exception.OutOfRangeException;
24import agents.anac.y2019.harddealer.math3.exception.NonMonotonicSequenceException;
25import agents.anac.y2019.harddealer.math3.util.MathArrays;
26
27/**
28 * Function that implements the
29 * <a href="http://en.wikipedia.org/wiki/Bicubic_interpolation">
30 * bicubic spline interpolation</a>.
31 *
32 * @since 3.4
33 */
34public class BicubicInterpolatingFunction
35 implements BivariateFunction {
36 /** Number of coefficients. */
37 private static final int NUM_COEFF = 16;
38 /**
39 * Matrix to compute the spline coefficients from the function values
40 * and function derivatives values
41 */
42 private static final double[][] AINV = {
43 { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
44 { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
45 { -3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0 },
46 { 2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0 },
47 { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
48 { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
49 { 0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0 },
50 { 0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0 },
51 { -3,0,3,0,0,0,0,0,-2,0,-1,0,0,0,0,0 },
52 { 0,0,0,0,-3,0,3,0,0,0,0,0,-2,0,-1,0 },
53 { 9,-9,-9,9,6,3,-6,-3,6,-6,3,-3,4,2,2,1 },
54 { -6,6,6,-6,-3,-3,3,3,-4,4,-2,2,-2,-2,-1,-1 },
55 { 2,0,-2,0,0,0,0,0,1,0,1,0,0,0,0,0 },
56 { 0,0,0,0,2,0,-2,0,0,0,0,0,1,0,1,0 },
57 { -6,6,6,-6,-4,-2,4,2,-3,3,-3,3,-2,-1,-2,-1 },
58 { 4,-4,-4,4,2,2,-2,-2,2,-2,2,-2,1,1,1,1 }
59 };
60
61 /** Samples x-coordinates */
62 private final double[] xval;
63 /** Samples y-coordinates */
64 private final double[] yval;
65 /** Set of cubic splines patching the whole data grid */
66 private final BicubicFunction[][] splines;
67
68 /**
69 * @param x Sample values of the x-coordinate, in increasing order.
70 * @param y Sample values of the y-coordinate, in increasing order.
71 * @param f Values of the function on every grid point.
72 * @param dFdX Values of the partial derivative of function with respect
73 * to x on every grid point.
74 * @param dFdY Values of the partial derivative of function with respect
75 * to y on every grid point.
76 * @param d2FdXdY Values of the cross partial derivative of function on
77 * every grid point.
78 * @throws DimensionMismatchException if the various arrays do not contain
79 * the expected number of elements.
80 * @throws NonMonotonicSequenceException if {@code x} or {@code y} are
81 * not strictly increasing.
82 * @throws NoDataException if any of the arrays has zero length.
83 */
84 public BicubicInterpolatingFunction(double[] x,
85 double[] y,
86 double[][] f,
87 double[][] dFdX,
88 double[][] dFdY,
89 double[][] d2FdXdY)
90 throws DimensionMismatchException,
91 NoDataException,
92 NonMonotonicSequenceException {
93 final int xLen = x.length;
94 final int yLen = y.length;
95
96 if (xLen == 0 || yLen == 0 || f.length == 0 || f[0].length == 0) {
97 throw new NoDataException();
98 }
99 if (xLen != f.length) {
100 throw new DimensionMismatchException(xLen, f.length);
101 }
102 if (xLen != dFdX.length) {
103 throw new DimensionMismatchException(xLen, dFdX.length);
104 }
105 if (xLen != dFdY.length) {
106 throw new DimensionMismatchException(xLen, dFdY.length);
107 }
108 if (xLen != d2FdXdY.length) {
109 throw new DimensionMismatchException(xLen, d2FdXdY.length);
110 }
111
112 MathArrays.checkOrder(x);
113 MathArrays.checkOrder(y);
114
115 xval = x.clone();
116 yval = y.clone();
117
118 final int lastI = xLen - 1;
119 final int lastJ = yLen - 1;
120 splines = new BicubicFunction[lastI][lastJ];
121
122 for (int i = 0; i < lastI; i++) {
123 if (f[i].length != yLen) {
124 throw new DimensionMismatchException(f[i].length, yLen);
125 }
126 if (dFdX[i].length != yLen) {
127 throw new DimensionMismatchException(dFdX[i].length, yLen);
128 }
129 if (dFdY[i].length != yLen) {
130 throw new DimensionMismatchException(dFdY[i].length, yLen);
131 }
132 if (d2FdXdY[i].length != yLen) {
133 throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
134 }
135 final int ip1 = i + 1;
136 final double xR = xval[ip1] - xval[i];
137 for (int j = 0; j < lastJ; j++) {
138 final int jp1 = j + 1;
139 final double yR = yval[jp1] - yval[j];
140 final double xRyR = xR * yR;
141 final double[] beta = new double[] {
142 f[i][j], f[ip1][j], f[i][jp1], f[ip1][jp1],
143 dFdX[i][j] * xR, dFdX[ip1][j] * xR, dFdX[i][jp1] * xR, dFdX[ip1][jp1] * xR,
144 dFdY[i][j] * yR, dFdY[ip1][j] * yR, dFdY[i][jp1] * yR, dFdY[ip1][jp1] * yR,
145 d2FdXdY[i][j] * xRyR, d2FdXdY[ip1][j] * xRyR, d2FdXdY[i][jp1] * xRyR, d2FdXdY[ip1][jp1] * xRyR
146 };
147
148 splines[i][j] = new BicubicFunction(computeSplineCoefficients(beta));
149 }
150 }
151 }
152
153 /**
154 * {@inheritDoc}
155 */
156 public double value(double x, double y)
157 throws OutOfRangeException {
158 final int i = searchIndex(x, xval);
159 final int j = searchIndex(y, yval);
160
161 final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
162 final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
163
164 return splines[i][j].value(xN, yN);
165 }
166
167 /**
168 * Indicates whether a point is within the interpolation range.
169 *
170 * @param x First coordinate.
171 * @param y Second coordinate.
172 * @return {@code true} if (x, y) is a valid point.
173 */
174 public boolean isValidPoint(double x, double y) {
175 if (x < xval[0] ||
176 x > xval[xval.length - 1] ||
177 y < yval[0] ||
178 y > yval[yval.length - 1]) {
179 return false;
180 } else {
181 return true;
182 }
183 }
184
185 /**
186 * @param c Coordinate.
187 * @param val Coordinate samples.
188 * @return the index in {@code val} corresponding to the interval
189 * containing {@code c}.
190 * @throws OutOfRangeException if {@code c} is out of the
191 * range defined by the boundary values of {@code val}.
192 */
193 private int searchIndex(double c, double[] val) {
194 final int r = Arrays.binarySearch(val, c);
195
196 if (r == -1 ||
197 r == -val.length - 1) {
198 throw new OutOfRangeException(c, val[0], val[val.length - 1]);
199 }
200
201 if (r < 0) {
202 // "c" in within an interpolation sub-interval: Return the
203 // index of the sample at the lower end of the sub-interval.
204 return -r - 2;
205 }
206 final int last = val.length - 1;
207 if (r == last) {
208 // "c" is the last sample of the range: Return the index
209 // of the sample at the lower end of the last sub-interval.
210 return last - 1;
211 }
212
213 // "c" is another sample point.
214 return r;
215 }
216
217 /**
218 * Compute the spline coefficients from the list of function values and
219 * function partial derivatives values at the four corners of a grid
220 * element. They must be specified in the following order:
221 * <ul>
222 * <li>f(0,0)</li>
223 * <li>f(1,0)</li>
224 * <li>f(0,1)</li>
225 * <li>f(1,1)</li>
226 * <li>f<sub>x</sub>(0,0)</li>
227 * <li>f<sub>x</sub>(1,0)</li>
228 * <li>f<sub>x</sub>(0,1)</li>
229 * <li>f<sub>x</sub>(1,1)</li>
230 * <li>f<sub>y</sub>(0,0)</li>
231 * <li>f<sub>y</sub>(1,0)</li>
232 * <li>f<sub>y</sub>(0,1)</li>
233 * <li>f<sub>y</sub>(1,1)</li>
234 * <li>f<sub>xy</sub>(0,0)</li>
235 * <li>f<sub>xy</sub>(1,0)</li>
236 * <li>f<sub>xy</sub>(0,1)</li>
237 * <li>f<sub>xy</sub>(1,1)</li>
238 * </ul>
239 * where the subscripts indicate the partial derivative with respect to
240 * the corresponding variable(s).
241 *
242 * @param beta List of function values and function partial derivatives
243 * values.
244 * @return the spline coefficients.
245 */
246 private double[] computeSplineCoefficients(double[] beta) {
247 final double[] a = new double[NUM_COEFF];
248
249 for (int i = 0; i < NUM_COEFF; i++) {
250 double result = 0;
251 final double[] row = AINV[i];
252 for (int j = 0; j < NUM_COEFF; j++) {
253 result += row[j] * beta[j];
254 }
255 a[i] = result;
256 }
257
258 return a;
259 }
260}
261
262/**
263 * Bicubic function.
264 */
265class BicubicFunction implements BivariateFunction {
266 /** Number of points. */
267 private static final short N = 4;
268 /** Coefficients */
269 private final double[][] a;
270
271 /**
272 * Simple constructor.
273 *
274 * @param coeff Spline coefficients.
275 */
276 BicubicFunction(double[] coeff) {
277 a = new double[N][N];
278 for (int j = 0; j < N; j++) {
279 final double[] aJ = a[j];
280 for (int i = 0; i < N; i++) {
281 aJ[i] = coeff[i * N + j];
282 }
283 }
284 }
285
286 /**
287 * {@inheritDoc}
288 */
289 public double value(double x, double y) {
290 if (x < 0 || x > 1) {
291 throw new OutOfRangeException(x, 0, 1);
292 }
293 if (y < 0 || y > 1) {
294 throw new OutOfRangeException(y, 0, 1);
295 }
296
297 final double x2 = x * x;
298 final double x3 = x2 * x;
299 final double[] pX = {1, x, x2, x3};
300
301 final double y2 = y * y;
302 final double y3 = y2 * y;
303 final double[] pY = {1, y, y2, y3};
304
305 return apply(pX, pY, a);
306 }
307
308 /**
309 * Compute the value of the bicubic polynomial.
310 *
311 * @param pX Powers of the x-coordinate.
312 * @param pY Powers of the y-coordinate.
313 * @param coeff Spline coefficients.
314 * @return the interpolated value.
315 */
316 private double apply(double[] pX, double[] pY, double[][] coeff) {
317 double result = 0;
318 for (int i = 0; i < N; i++) {
319 final double r = MathArrays.linearCombination(coeff[i], pY);
320 result += r * pX[i];
321 }
322
323 return result;
324 }
325}
Note: See TracBrowser for help on using the repository browser.