1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.analysis.interpolation;
23
24 import org.hipparchus.exception.LocalizedCoreFormats;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.util.FastMath;
27 import org.junit.Assert;
28 import org.junit.Test;
29
30
31
32
33 public class LoessInterpolatorTest {
34
35 @Test
36 public void testOnOnePoint() {
37 double[] xval = {0.5};
38 double[] yval = {0.7};
39 double[] res = new LoessInterpolator().smooth(xval, yval);
40 Assert.assertEquals(1, res.length);
41 Assert.assertEquals(0.7, res[0], 0.0);
42 }
43
44 @Test
45 public void testOnTwoPoints() {
46 double[] xval = {0.5, 0.6};
47 double[] yval = {0.7, 0.8};
48 double[] res = new LoessInterpolator().smooth(xval, yval);
49 Assert.assertEquals(2, res.length);
50 Assert.assertEquals(0.7, res[0], 0.0);
51 Assert.assertEquals(0.8, res[1], 0.0);
52 }
53
54 @Test
55 public void testOnStraightLine() {
56 double[] xval = {1,2,3,4,5};
57 double[] yval = {2,4,6,8,10};
58 LoessInterpolator li = new LoessInterpolator(0.6, 2, 1e-12);
59 double[] res = li.smooth(xval, yval);
60 Assert.assertEquals(5, res.length);
61 for(int i = 0; i < 5; ++i) {
62 Assert.assertEquals(yval[i], res[i], 1e-8);
63 }
64 }
65
66 @Test
67 public void testOnDistortedSine() {
68 int numPoints = 100;
69 double[] xval = new double[numPoints];
70 double[] yval = new double[numPoints];
71 double xnoise = 0.1;
72 double ynoise = 0.2;
73
74 generateSineData(xval, yval, xnoise, ynoise);
75
76 LoessInterpolator li = new LoessInterpolator(0.3, 4, 1e-12);
77
78 double[] res = li.smooth(xval, yval);
79
80
81
82
83 double noisyResidualSum = 0;
84 double fitResidualSum = 0;
85
86 for(int i = 0; i < numPoints; ++i) {
87 double expected = FastMath.sin(xval[i]);
88 double noisy = yval[i];
89 double fit = res[i];
90
91 noisyResidualSum += FastMath.pow(noisy - expected, 2);
92 fitResidualSum += FastMath.pow(fit - expected, 2);
93 }
94
95 Assert.assertTrue(fitResidualSum < noisyResidualSum);
96 }
97
98 @Test
99 public void testIncreasingBandwidthIncreasesSmoothness() {
100 int numPoints = 100;
101 double[] xval = new double[numPoints];
102 double[] yval = new double[numPoints];
103 double xnoise = 0.1;
104 double ynoise = 0.1;
105
106 generateSineData(xval, yval, xnoise, ynoise);
107
108
109
110 double[] bandwidths = {0.1, 0.5, 1.0};
111 double[] variances = new double[bandwidths.length];
112 for (int i = 0; i < bandwidths.length; i++) {
113 double bw = bandwidths[i];
114
115 LoessInterpolator li = new LoessInterpolator(bw, 4, 1e-12);
116
117 double[] res = li.smooth(xval, yval);
118
119 for (int j = 1; j < res.length; ++j) {
120 variances[i] += FastMath.pow(res[j] - res[j-1], 2);
121 }
122 }
123
124 for(int i = 1; i < variances.length; ++i) {
125 Assert.assertTrue(variances[i] < variances[i-1]);
126 }
127 }
128
129 @Test
130 public void testIncreasingRobustnessItersIncreasesSmoothnessWithOutliers() {
131 int numPoints = 100;
132 double[] xval = new double[numPoints];
133 double[] yval = new double[numPoints];
134 double xnoise = 0.1;
135 double ynoise = 0.1;
136
137 generateSineData(xval, yval, xnoise, ynoise);
138
139
140 yval[numPoints/3] *= 100;
141 yval[2 * numPoints/3] *= -100;
142
143
144
145
146 double[] variances = new double[4];
147 for (int i = 0; i < 4; i++) {
148 LoessInterpolator li = new LoessInterpolator(0.3, i, 1e-12);
149
150 double[] res = li.smooth(xval, yval);
151
152 for (int j = 1; j < res.length; ++j) {
153 variances[i] += FastMath.abs(res[j] - res[j-1]);
154 }
155 }
156
157 for(int i = 1; i < variances.length; ++i) {
158 Assert.assertTrue(variances[i] < variances[i-1]);
159 }
160 }
161
162 @Test(expected=MathIllegalArgumentException.class)
163 public void testUnequalSizeArguments() {
164 new LoessInterpolator().smooth(new double[] {1,2,3}, new double[] {1,2,3,4});
165 }
166
167 @Test(expected=MathIllegalArgumentException.class)
168 public void testEmptyData() {
169 new LoessInterpolator().smooth(new double[] {}, new double[] {});
170 }
171
172 @Test(expected=MathIllegalArgumentException.class)
173 public void testNonStrictlyIncreasing1() {
174 new LoessInterpolator().smooth(new double[] {4,3,1,2}, new double[] {3,4,5,6});
175 }
176
177 @Test(expected=MathIllegalArgumentException.class)
178 public void testNonStrictlyIncreasing2() {
179 new LoessInterpolator().smooth(new double[] {1,2,2,3}, new double[] {3,4,5,6});
180 }
181
182 @Test
183 public void testNotAllFiniteReal1() {
184 try {
185 new LoessInterpolator().smooth(new double[] {1,2,Double.NaN}, new double[] {3,4,5});
186 Assert.fail("an exception should have been thrown");
187 } catch (MathIllegalArgumentException e) {
188 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
189 }
190 }
191
192 @Test
193 public void testNotAllFiniteReal2() {
194 try {
195 new LoessInterpolator().smooth(new double[] {1,2,Double.POSITIVE_INFINITY}, new double[] {3,4,5});
196 } catch (MathIllegalArgumentException e) {
197 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
198 }
199 }
200
201 @Test
202 public void testNotAllFiniteReal3() {
203 try {
204 new LoessInterpolator().smooth(new double[] {1,2,Double.NEGATIVE_INFINITY}, new double[] {3,4,5});
205 } catch (MathIllegalArgumentException e) {
206 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
207 }
208 }
209
210 @Test
211 public void testNotAllFiniteReal4() {
212 try {
213 new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.NaN});
214 } catch (MathIllegalArgumentException e) {
215 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
216 }
217 }
218
219 @Test
220 public void testNotAllFiniteReal5() {
221 try {
222 new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.POSITIVE_INFINITY});
223 } catch (MathIllegalArgumentException e) {
224 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
225 }
226 }
227
228 @Test
229 public void testNotAllFiniteReal6() {
230 try {
231 new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.NEGATIVE_INFINITY});
232 } catch (MathIllegalArgumentException e) {
233 Assert.assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
234 }
235 }
236
237 @Test(expected=MathIllegalArgumentException.class)
238 public void testInsufficientBandwidth() {
239 LoessInterpolator li = new LoessInterpolator(0.1, 3, 1e-12);
240 li.smooth(new double[] {1,2,3,4,5,6,7,8,9,10,11,12}, new double[] {1,2,3,4,5,6,7,8,9,10,11,12});
241 }
242
243 @Test(expected=MathIllegalArgumentException.class)
244 public void testCompletelyIncorrectBandwidth1() {
245 new LoessInterpolator(-0.2, 3, 1e-12);
246 }
247
248 @Test(expected=MathIllegalArgumentException.class)
249 public void testCompletelyIncorrectBandwidth2() {
250 new LoessInterpolator(1.1, 3, 1e-12);
251 }
252
253 @Test
254 public void testMath296withoutWeights() {
255 double[] xval = {
256 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
257 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0};
258 double[] yval = {
259 0.47, 0.48, 0.55, 0.56, -0.08, -0.04, -0.07, -0.07,
260 -0.56, -0.46, -0.56, -0.52, -3.03, -3.08, -3.09,
261 -3.04, 3.54, 3.46, 3.36, 3.35};
262
263 double[] yref = {
264 0.461, 0.499, 0.541, 0.308, 0.175, -0.042, -0.072,
265 -0.196, -0.311, -0.446, -0.557, -1.497, -2.133,
266 -3.08, -3.09, -0.621, 0.982, 3.449, 3.389, 3.336
267 };
268 LoessInterpolator li = new LoessInterpolator(0.3, 4, 1e-12);
269 double[] res = li.smooth(xval, yval);
270 Assert.assertEquals(xval.length, res.length);
271 for(int i = 0; i < res.length; ++i) {
272 Assert.assertEquals(yref[i], res[i], 0.02);
273 }
274 }
275
276 private void generateSineData(double[] xval, double[] yval, double xnoise, double ynoise) {
277 double dx = 2 * FastMath.PI / xval.length;
278 double x = 0;
279 for(int i = 0; i < xval.length; ++i) {
280 xval[i] = x;
281 yval[i] = FastMath.sin(x) + (2 * FastMath.random() - 1) * ynoise;
282 x += dx * (1 + (2 * FastMath.random() - 1) * xnoise);
283 }
284 }
285 }