001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math.analysis.polynomials;
018
019 import java.util.Arrays;
020 import junit.framework.TestCase;
021
022 import org.apache.commons.math.FunctionEvaluationException;
023 import org.apache.commons.math.analysis.UnivariateRealFunction;
024
025 /**
026 * Tests the PolynomialSplineFunction implementation.
027 *
028 * @version $Revision: 799857 $
029 */
030 public class PolynomialSplineFunctionTest extends TestCase {
031
032 /** Error tolerance for tests */
033 protected double tolerance = 1.0e-12;
034
035 /**
036 * Quadratic polynomials used in tests:
037 *
038 * x^2 + x [-1, 0)
039 * x^2 + x + 2 [0, 1)
040 * x^2 + x + 4 [1, 2)
041 *
042 * Defined so that evaluation using PolynomialSplineFunction evaluation
043 * algorithm agrees at knot point boundaries.
044 */
045 protected PolynomialFunction[] polynomials = {
046 new PolynomialFunction(new double[] {0d, 1d, 1d}),
047 new PolynomialFunction(new double[] {2d, 1d, 1d}),
048 new PolynomialFunction(new double[] {4d, 1d, 1d})
049 };
050
051 /** Knot points */
052 protected double[] knots = {-1, 0, 1, 2};
053
054 /** Derivative of test polynomials -- 2x + 1 */
055 protected PolynomialFunction dp =
056 new PolynomialFunction(new double[] {1d, 2d});
057
058
059 public void testConstructor() {
060 PolynomialSplineFunction spline =
061 new PolynomialSplineFunction(knots, polynomials);
062 assertTrue(Arrays.equals(knots, spline.getKnots()));
063 assertEquals(1d, spline.getPolynomials()[0].getCoefficients()[2], 0);
064 assertEquals(3, spline.getN());
065
066 try { // too few knots
067 new PolynomialSplineFunction(new double[] {0}, polynomials);
068 fail("Expecting IllegalArgumentException");
069 } catch (IllegalArgumentException ex) {
070 // expected
071 }
072
073 try { // too many knots
074 new PolynomialSplineFunction(new double[] {0,1,2,3,4}, polynomials);
075 fail("Expecting IllegalArgumentException");
076 } catch (IllegalArgumentException ex) {
077 // expected
078 }
079
080 try { // knots not increasing
081 new PolynomialSplineFunction(new double[] {0,1, 3, 2}, polynomials);
082 fail("Expecting IllegalArgumentException");
083 } catch (IllegalArgumentException ex) {
084 // expected
085 }
086 }
087
088 public void testValues() throws Exception {
089 PolynomialSplineFunction spline =
090 new PolynomialSplineFunction(knots, polynomials);
091 UnivariateRealFunction dSpline = spline.derivative();
092
093 /**
094 * interior points -- spline value at x should equal p(x - knot)
095 * where knot is the largest knot point less than or equal to x and p
096 * is the polynomial defined over the knot segment to which x belongs.
097 */
098 double x = -1;
099 int index = 0;
100 for (int i = 0; i < 10; i++) {
101 x+=0.25;
102 index = findKnot(knots, x);
103 assertEquals("spline function evaluation failed for x=" + x,
104 polynomials[index].value(x - knots[index]), spline.value(x), tolerance);
105 assertEquals("spline derivative evaluation failed for x=" + x,
106 dp.value(x - knots[index]), dSpline.value(x), tolerance);
107 }
108
109 // knot points -- centering should zero arguments
110 for (int i = 0; i < 3; i++) {
111 assertEquals("spline function evaluation failed for knot=" + knots[i],
112 polynomials[i].value(0), spline.value(knots[i]), tolerance);
113 assertEquals("spline function evaluation failed for knot=" + knots[i],
114 dp.value(0), dSpline.value(knots[i]), tolerance);
115 }
116
117 try { //outside of domain -- under min
118 x = spline.value(-1.5);
119 fail("Expecting IllegalArgumentException");
120 } catch (FunctionEvaluationException ex) {
121 // expected
122 }
123
124 try { //outside of domain -- over max
125 x = spline.value(2.5);
126 fail("Expecting IllegalArgumentException");
127 } catch (FunctionEvaluationException ex) {
128 // expected
129 }
130 }
131
132 /**
133 * Do linear search to find largest knot point less than or equal to x.
134 * Implementation does binary search.
135 */
136 protected int findKnot(double[] knots, double x) {
137 if (x < knots[0] || x >= knots[knots.length -1]) {
138 throw new IllegalArgumentException("x is out of range");
139 }
140 for (int i = 0; i < knots.length; i++) {
141 if (knots[i] > x) {
142 return i -1;
143 }
144 }
145 throw new IllegalArgumentException("x is out of range");
146 }
147 }
148