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
9
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
package org.apache.commons.math.analysis.interpolation;
19
import static org.junit.Assert.assertEquals;
20
import static org.junit.Assert.assertTrue;
21
import static org.junit.Assert.fail;
23
import org.apache.commons.math.MathException;
24
import org.junit.Test;
27
* Test of the LoessInterpolator class.
29
public class LoessInterpolatorTest {
32
public void testOnOnePoint() throws MathException {
33
double[] xval = {0.5};
34
double[] yval = {0.7};
35
double[] res = new LoessInterpolator().smooth(xval, yval);
36
assertEquals(1, res.length);
37
assertEquals(0.7, res[0], 0.0);
41
public void testOnTwoPoints() throws MathException {
42
double[] xval = {0.5, 0.6};
43
double[] yval = {0.7, 0.8};
44
double[] res = new LoessInterpolator().smooth(xval, yval);
45
assertEquals(2, res.length);
46
assertEquals(0.7, res[0], 0.0);
47
assertEquals(0.8, res[1], 0.0);
51
public void testOnStraightLine() throws MathException {
52
double[] xval = {1,2,3,4,5};
53
double[] yval = {2,4,6,8,10};
54
LoessInterpolator li = new LoessInterpolator(0.6, 2);
55
double[] res = li.smooth(xval, yval);
56
assertEquals(5, res.length);
57
for(int i = 0; i < 5; ++i) {
58
assertEquals(yval[i], res[i], 1e-8);
63
public void testOnDistortedSine() throws MathException {
65
double[] xval = new double[numPoints];
66
double[] yval = new double[numPoints];
70
generateSineData(xval, yval, xnoise, ynoise);
72
LoessInterpolator li = new LoessInterpolator(0.3, 4);
74
double[] res = li.smooth(xval, yval);
76
// Check that the resulting curve differs from
77
// the "real" sine less than the jittered one
79
double noisyResidualSum = 0;
80
double fitResidualSum = 0;
82
for(int i = 0; i < numPoints; ++i) {
83
double expected = Math.sin(xval[i]);
84
double noisy = yval[i];
87
noisyResidualSum += Math.pow(noisy - expected, 2);
88
fitResidualSum += Math.pow(fit - expected, 2);
91
assertTrue(fitResidualSum < noisyResidualSum);
95
public void testIncreasingBandwidthIncreasesSmoothness() throws MathException {
97
double[] xval = new double[numPoints];
98
double[] yval = new double[numPoints];
102
generateSineData(xval, yval, xnoise, ynoise);
104
// Check that variance decreases as bandwidth increases
106
double[] bandwidths = {0.1, 0.5, 1.0};
107
double[] variances = new double[bandwidths.length];
108
for (int i = 0; i < bandwidths.length; i++) {
109
double bw = bandwidths[i];
111
LoessInterpolator li = new LoessInterpolator(bw, 4);
113
double[] res = li.smooth(xval, yval);
115
for (int j = 1; j < res.length; ++j) {
116
variances[i] += Math.pow(res[j] - res[j-1], 2);
120
for(int i = 1; i < variances.length; ++i) {
121
assertTrue(variances[i] < variances[i-1]);
126
public void testIncreasingRobustnessItersIncreasesSmoothnessWithOutliers() throws MathException {
128
double[] xval = new double[numPoints];
129
double[] yval = new double[numPoints];
133
generateSineData(xval, yval, xnoise, ynoise);
135
// Introduce a couple of outliers
136
yval[numPoints/3] *= 100;
137
yval[2 * numPoints/3] *= -100;
139
// Check that variance decreases as the number of robustness
140
// iterations increases
142
double[] variances = new double[4];
143
for (int i = 0; i < 4; i++) {
144
LoessInterpolator li = new LoessInterpolator(0.3, i);
146
double[] res = li.smooth(xval, yval);
148
for (int j = 1; j < res.length; ++j) {
149
variances[i] += Math.abs(res[j] - res[j-1]);
153
for(int i = 1; i < variances.length; ++i) {
154
assertTrue(variances[i] < variances[i-1]);
159
public void testUnequalSizeArguments() {
161
new LoessInterpolator().smooth(new double[] {1,2,3}, new double[] {1,2,3,4});
163
} catch(MathException e) {
169
public void testEmptyData() {
171
new LoessInterpolator().smooth(new double[] {}, new double[] {});
173
} catch(MathException e) {
179
public void testNonStrictlyIncreasing() {
181
new LoessInterpolator().smooth(new double[] {4,3,1,2}, new double[] {3,4,5,6});
183
} catch(MathException e) {
187
new LoessInterpolator().smooth(new double[] {1,2,2,3}, new double[] {3,4,5,6});
189
} catch(MathException e) {
195
public void testNotAllFiniteReal() {
197
new LoessInterpolator().smooth(new double[] {1,2,Double.NaN}, new double[] {3,4,5});
199
} catch(MathException e) {
203
new LoessInterpolator().smooth(new double[] {1,2,Double.POSITIVE_INFINITY}, new double[] {3,4,5});
205
} catch(MathException e) {
209
new LoessInterpolator().smooth(new double[] {1,2,Double.NEGATIVE_INFINITY}, new double[] {3,4,5});
211
} catch(MathException e) {
215
new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.NaN});
217
} catch(MathException e) {
221
new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.POSITIVE_INFINITY});
223
} catch(MathException e) {
227
new LoessInterpolator().smooth(new double[] {3,4,5}, new double[] {1,2,Double.NEGATIVE_INFINITY});
229
} catch(MathException e) {
235
public void testInsufficientBandwidth() {
237
LoessInterpolator li = new LoessInterpolator(0.1, 3);
238
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});
240
} catch(MathException e) {
246
public void testCompletelyIncorrectBandwidth() {
248
new LoessInterpolator(-0.2, 3);
250
} catch(MathException e) {
254
new LoessInterpolator(1.1, 3);
256
} catch(MathException e) {
261
private void generateSineData(double[] xval, double[] yval, double xnoise, double ynoise) {
262
double dx = 2 * Math.PI / xval.length;
264
for(int i = 0; i < xval.length; ++i) {
266
yval[i] = Math.sin(x) + (2 * Math.random() - 1) * ynoise;
267
x += dx * (1 + (2 * Math.random() - 1) * xnoise);