    1   /*
    2    *
    3    * Copyright (c) 2004 The Apache Software Foundation. All rights reserved.
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
    6    * use this file except in compliance with the License. You may obtain a copy
    7    * 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, WITHOUT
    13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    14   * License for the specific language governing permissions and limitations
    15   * under the License.
    16   *
    17   */
    18  package org.apache.commons.math.analysis;
    19
    20  import java.util.Arrays;
    21  import junit.framework.TestCase;
    22
    23  import org.apache.commons.math.FunctionEvaluationException;
    24
    25  /***
    26   * Tests the PolynomialSplineFunction implementation.
    27   *
    28   * @version $Revision: 155427 $
    29   */
    30  public class PolynomialSplineFunctionTest extends TestCase {
    31
    32      /*** Error tolerance for tests */
    33      protected double tolerance = 1.0e-12;
    34
    35      /***
    36       * Quadratic polynomials used in tests:
    37       *
    38       * x^2 + x            [-1, 0)
    39       * x^2 + x + 2        [0, 1)
    40       * x^2 + x + 4        [1, 2)
    41       *
    42       * Defined so that evaluation using PolynomialSplineFunction evaluation
    43       * algorithm agrees at knot point boundaries.
    44       */
    45      protected PolynomialFunction[] polynomials = {
    46          new PolynomialFunction(new double[] {0d, 1d, 1d}),
    47          new PolynomialFunction(new double[] {2d, 1d, 1d}),
    48          new PolynomialFunction(new double[] {4d, 1d, 1d})
    49      };
    50
    51      /*** Knot points  */
    52      protected double[] knots = {-1, 0, 1, 2};
    53
    54      /*** Derivative of test polynomials -- 2x + 1  */
    55      protected PolynomialFunction dp =
    56          new PolynomialFunction(new double[] {1d, 2d});
    57
    58
    59      public void testConstructor() {
    60          PolynomialSplineFunction spline =
    61              new PolynomialSplineFunction(knots, polynomials);
    62          assertTrue(Arrays.equals(knots, spline.getKnots()));
    63          assertEquals(1d, spline.getPolynomials()[0].getCoefficients()[2], 0);
    64          assertEquals(3, spline.getN());
    65
    66          try { // too few knots
    67              spline =
    68                  new PolynomialSplineFunction(new double[] {0}, polynomials);
    69              fail("Expecting IllegalArgumentException");
    70          } catch (IllegalArgumentException ex) {
    71              // expected
    72          }
    73
    74          try { // too many knots
    75              spline =
    76                  new PolynomialSplineFunction(new double[] {0,1,2,3,4}, polynomials);
    77              fail("Expecting IllegalArgumentException");
    78          } catch (IllegalArgumentException ex) {
    79              // expected
    80          }
    81
    82          try { // knots not increasing
    83              spline =
    84                  new PolynomialSplineFunction(new double[] {0,1, 3, 2}, polynomials);
    85              fail("Expecting IllegalArgumentException");
    86          } catch (IllegalArgumentException ex) {
    87              // expected
    88          }
    89      }
    90
    91      public void testValues() throws Exception {
    92          PolynomialSplineFunction spline =
    93              new PolynomialSplineFunction(knots, polynomials);
    94          UnivariateRealFunction dSpline = spline.derivative();
    95
    96          /***
    97           * interior points -- spline value at x should equal p(x - knot)
    98           * where knot is the largest knot point less than or equal to x and p
    99           * is the polynomial defined over the knot segment to which x belongs.
    100          */
    101         double x = -1;
    102         int index = 0;
    103         for (int i = 0; i < 10; i++) {
    104            x+=0.25;
    105            index = findKnot(knots, x);
    106            assertEquals("spline function evaluation failed for x=" + x,
    107                    polynomials[index].value(x - knots[index]), spline.value(x), tolerance);
    108            assertEquals("spline derivative evaluation failed for x=" + x,
    109                    dp.value(x - knots[index]), dSpline.value(x), tolerance);
    110         }
    111
    112         // knot points -- centering should zero arguments
    113         for (int i = 0; i < 3; i++) {
    114             assertEquals("spline function evaluation failed for knot=" + knots[i],
    115                     polynomials[i].value(0), spline.value(knots[i]), tolerance);
    116             assertEquals("spline function evaluation failed for knot=" + knots[i],
    117                     dp.value(0), dSpline.value(knots[i]), tolerance);
    118         }
    119
    120         try { //outside of domain -- under min
    121             x = spline.value(-1.5);
    122             fail("Expecting IllegalArgumentException");
    123         } catch (FunctionEvaluationException ex) {
    124             // expected
    125         }
    126
    127         try { //outside of domain -- over max
    128             x = spline.value(2.5);
    129             fail("Expecting IllegalArgumentException");
    130         } catch (FunctionEvaluationException ex) {
    131             // expected
    132         }
    133     }
    134
    135     /***
    136      *  Do linear search to find largest knot point less than or equal to x.
    137      *  Implementation does binary search.
    138      */
    139      protected int findKnot(double[] knots, double x) {
    140          if (x < knots[0] || x >= knots[knots.length -1]) {
    141              throw new IllegalArgumentException("x is out of range");
    142          }
    143          for (int i = 0; i < knots.length; i++) {
    144              if (knots[i] > x) {
    145                  return i -1;
    146              }
    147          }
    148          throw new IllegalArgumentException("x is out of range");
    149      }
    150 }
    151