source: src/main/java/agents/anac/y2019/harddealer/math3/analysis/interpolation/PiecewiseBicubicSplineInterpolatingFunction.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: 7.5 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.analysis.polynomials.PolynomialSplineFunction;
22import agents.anac.y2019.harddealer.math3.exception.DimensionMismatchException;
23import agents.anac.y2019.harddealer.math3.exception.InsufficientDataException;
24import agents.anac.y2019.harddealer.math3.exception.NoDataException;
25import agents.anac.y2019.harddealer.math3.exception.NullArgumentException;
26import agents.anac.y2019.harddealer.math3.exception.OutOfRangeException;
27import agents.anac.y2019.harddealer.math3.exception.NonMonotonicSequenceException;
28import agents.anac.y2019.harddealer.math3.util.MathArrays;
29
30/**
31 * Function that implements the
32 * <a href="http://www.paulinternet.nl/?page=bicubic">bicubic spline</a>
33 * interpolation.
34 * This implementation currently uses {@link AkimaSplineInterpolator} as the
35 * underlying one-dimensional interpolator, which requires 5 sample points;
36 * insufficient data will raise an exception when the
37 * {@link #value(double,double) value} method is called.
38 *
39 * @since 3.4
40 */
41public class PiecewiseBicubicSplineInterpolatingFunction
42 implements BivariateFunction {
43 /** The minimum number of points that are needed to compute the function. */
44 private static final int MIN_NUM_POINTS = 5;
45 /** Samples x-coordinates */
46 private final double[] xval;
47 /** Samples y-coordinates */
48 private final double[] yval;
49 /** Set of cubic splines patching the whole data grid */
50 private final double[][] fval;
51
52 /**
53 * @param x Sample values of the x-coordinate, in increasing order.
54 * @param y Sample values of the y-coordinate, in increasing order.
55 * @param f Values of the function on every grid point. the expected number
56 * of elements.
57 * @throws NonMonotonicSequenceException if {@code x} or {@code y} are not
58 * strictly increasing.
59 * @throws NullArgumentException if any of the arguments are null
60 * @throws NoDataException if any of the arrays has zero length.
61 * @throws DimensionMismatchException if the length of x and y don't match the row, column
62 * height of f
63 */
64 public PiecewiseBicubicSplineInterpolatingFunction(double[] x,
65 double[] y,
66 double[][] f)
67 throws DimensionMismatchException,
68 NullArgumentException,
69 NoDataException,
70 NonMonotonicSequenceException {
71 if (x == null ||
72 y == null ||
73 f == null ||
74 f[0] == null) {
75 throw new NullArgumentException();
76 }
77
78 final int xLen = x.length;
79 final int yLen = y.length;
80
81 if (xLen == 0 ||
82 yLen == 0 ||
83 f.length == 0 ||
84 f[0].length == 0) {
85 throw new NoDataException();
86 }
87
88 if (xLen < MIN_NUM_POINTS ||
89 yLen < MIN_NUM_POINTS ||
90 f.length < MIN_NUM_POINTS ||
91 f[0].length < MIN_NUM_POINTS) {
92 throw new InsufficientDataException();
93 }
94
95 if (xLen != f.length) {
96 throw new DimensionMismatchException(xLen, f.length);
97 }
98
99 if (yLen != f[0].length) {
100 throw new DimensionMismatchException(yLen, f[0].length);
101 }
102
103 MathArrays.checkOrder(x);
104 MathArrays.checkOrder(y);
105
106 xval = x.clone();
107 yval = y.clone();
108 fval = f.clone();
109 }
110
111 /**
112 * {@inheritDoc}
113 */
114 public double value(double x,
115 double y)
116 throws OutOfRangeException {
117 final AkimaSplineInterpolator interpolator = new AkimaSplineInterpolator();
118 final int offset = 2;
119 final int count = offset + 3;
120 final int i = searchIndex(x, xval, offset, count);
121 final int j = searchIndex(y, yval, offset, count);
122
123 final double xArray[] = new double[count];
124 final double yArray[] = new double[count];
125 final double zArray[] = new double[count];
126 final double interpArray[] = new double[count];
127
128 for (int index = 0; index < count; index++) {
129 xArray[index] = xval[i + index];
130 yArray[index] = yval[j + index];
131 }
132
133 for (int zIndex = 0; zIndex < count; zIndex++) {
134 for (int index = 0; index < count; index++) {
135 zArray[index] = fval[i + index][j + zIndex];
136 }
137 final PolynomialSplineFunction spline = interpolator.interpolate(xArray, zArray);
138 interpArray[zIndex] = spline.value(x);
139 }
140
141 final PolynomialSplineFunction spline = interpolator.interpolate(yArray, interpArray);
142
143 double returnValue = spline.value(y);
144
145 return returnValue;
146 }
147
148 /**
149 * Indicates whether a point is within the interpolation range.
150 *
151 * @param x First coordinate.
152 * @param y Second coordinate.
153 * @return {@code true} if (x, y) is a valid point.
154 * @since 3.3
155 */
156 public boolean isValidPoint(double x,
157 double y) {
158 if (x < xval[0] ||
159 x > xval[xval.length - 1] ||
160 y < yval[0] ||
161 y > yval[yval.length - 1]) {
162 return false;
163 } else {
164 return true;
165 }
166 }
167
168 /**
169 * @param c Coordinate.
170 * @param val Coordinate samples.
171 * @param offset how far back from found value to offset for querying
172 * @param count total number of elements forward from beginning that will be
173 * queried
174 * @return the index in {@code val} corresponding to the interval containing
175 * {@code c}.
176 * @throws OutOfRangeException if {@code c} is out of the range defined by
177 * the boundary values of {@code val}.
178 */
179 private int searchIndex(double c,
180 double[] val,
181 int offset,
182 int count) {
183 int r = Arrays.binarySearch(val, c);
184
185 if (r == -1 || r == -val.length - 1) {
186 throw new OutOfRangeException(c, val[0], val[val.length - 1]);
187 }
188
189 if (r < 0) {
190 // "c" in within an interpolation sub-interval, which returns
191 // negative
192 // need to remove the negative sign for consistency
193 r = -r - offset - 1;
194 } else {
195 r -= offset;
196 }
197
198 if (r < 0) {
199 r = 0;
200 }
201
202 if ((r + count) >= val.length) {
203 // "c" is the last sample of the range: Return the index
204 // of the sample at the lower end of the last sub-interval.
205 r = val.length - count;
206 }
207
208 return r;
209 }
210}
Note: See TracBrowser for help on using the repository browser.