blob: 8af324fe0fb9bd8fa725a481508ab5fc897490f1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math4.legacy.analysis.polynomials;
import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
import org.apache.commons.math4.legacy.exception.OutOfRangeException;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests the PolynomialSplineFunction implementation.
*
*/
public class PolynomialSplineFunctionTest {
/** Error tolerance for tests */
protected double tolerance = 1.0e-12;
/**
* Quadratic polynomials used in tests:
*
* x^2 + x [-1, 0)
* x^2 + x + 2 [0, 1)
* x^2 + x + 4 [1, 2)
*
* Defined so that evaluation using PolynomialSplineFunction evaluation
* algorithm agrees at knot point boundaries.
*/
protected PolynomialFunction[] polynomials = {
new PolynomialFunction(new double[] {0d, 1d, 1d}),
new PolynomialFunction(new double[] {2d, 1d, 1d}),
new PolynomialFunction(new double[] {4d, 1d, 1d})
};
/** Knot points */
protected double[] knots = {-1, 0, 1, 2};
/** Derivative of test polynomials -- 2x + 1 */
protected PolynomialFunction dp =
new PolynomialFunction(new double[] {1d, 2d});
@Test
public void testConstructor() {
PolynomialSplineFunction spline =
new PolynomialSplineFunction(knots, polynomials);
Assert.assertArrayEquals(knots, spline.getKnots(), 0.0);
Assert.assertEquals(1d, spline.getPolynomials()[0].getCoefficients()[2], 0);
Assert.assertEquals(3, spline.getN());
try { // too few knots
new PolynomialSplineFunction(new double[] {0}, polynomials);
Assert.fail("Expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// expected
}
try { // too many knots
new PolynomialSplineFunction(new double[] {0,1,2,3,4}, polynomials);
Assert.fail("Expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// expected
}
try { // knots not increasing
new PolynomialSplineFunction(new double[] {0,1, 3, 2}, polynomials);
Assert.fail("Expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// expected
}
}
@Test
public void testValues() {
PolynomialSplineFunction spline =
new PolynomialSplineFunction(knots, polynomials);
UnivariateFunction dSpline = spline.polynomialSplineDerivative();
/**
* interior points -- spline value at x should equal p(x - knot)
* where knot is the largest knot point less than or equal to x and p
* is the polynomial defined over the knot segment to which x belongs.
*/
double x = -1;
int index = 0;
for (int i = 0; i < 10; i++) {
x+=0.25;
index = findKnot(knots, x);
Assert.assertEquals("spline function evaluation failed for x=" + x,
polynomials[index].value(x - knots[index]), spline.value(x), tolerance);
Assert.assertEquals("spline derivative evaluation failed for x=" + x,
dp.value(x - knots[index]), dSpline.value(x), tolerance);
}
// knot points -- centering should zero arguments
for (int i = 0; i < 3; i++) {
Assert.assertEquals("spline function evaluation failed for knot=" + knots[i],
polynomials[i].value(0), spline.value(knots[i]), tolerance);
Assert.assertEquals("spline function evaluation failed for knot=" + knots[i],
dp.value(0), dSpline.value(knots[i]), tolerance);
}
try { //outside of domain -- under min
x = spline.value(-1.5);
Assert.fail("Expecting OutOfRangeException");
} catch (OutOfRangeException ex) {
// expected
}
try { //outside of domain -- over max
x = spline.value(2.5);
Assert.fail("Expecting OutOfRangeException");
} catch (OutOfRangeException ex) {
// expected
}
}
@Test
public void testIsValidPoint() {
final PolynomialSplineFunction spline =
new PolynomialSplineFunction(knots, polynomials);
final double xMin = knots[0];
final double xMax = knots[knots.length - 1];
double x;
x = xMin;
Assert.assertTrue(spline.isValidPoint(x));
// Ensure that no exception is thrown.
spline.value(x);
x = xMax;
Assert.assertTrue(spline.isValidPoint(x));
// Ensure that no exception is thrown.
spline.value(x);
final double xRange = xMax - xMin;
x = xMin + xRange / 3.4;
Assert.assertTrue(spline.isValidPoint(x));
// Ensure that no exception is thrown.
spline.value(x);
final double small = 1e-8;
x = xMin - small;
Assert.assertFalse(spline.isValidPoint(x));
// Ensure that an exception would have been thrown.
try {
spline.value(x);
Assert.fail("OutOfRangeException expected");
} catch (OutOfRangeException expected) {}
}
/**
* Do linear search to find largest knot point less than or equal to x.
* Implementation does binary search.
*/
protected int findKnot(double[] knots, double x) {
if (x < knots[0] || x >= knots[knots.length -1]) {
throw new OutOfRangeException(x, knots[0], knots[knots.length -1]);
}
for (int i = 0; i < knots.length; i++) {
if (knots[i] > x) {
return i - 1;
}
}
throw new MathIllegalStateException();
}
}