1   /*
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
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,
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.
16   */
17  package org.apache.commons.math.analysis;
18  
19  import org.apache.commons.math.MathException;
20  import junit.framework.TestCase;
21  
22  /**
23   * Testcase for Divided Difference interpolator.
24   * <p>
25   * The error of polynomial interpolation is
26   *     f(z) - p(z) = f^(n)(zeta) * (z-x[0])(z-x[1])...(z-x[n-1]) / n!
27   * where f^(n) is the n-th derivative of the approximated function and
28   * zeta is some point in the interval determined by x[] and z.
29   * <p>
30   * Since zeta is unknown, f^(n)(zeta) cannot be calculated. But we can bound
31   * it and use the absolute value upper bound for estimates. For reference,
32   * see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X, chapter 2.
33   * 
34   * @version $Revision$ $Date$ 
35   */
36  public final class DividedDifferenceInterpolatorTest extends TestCase {
37  
38      /**
39       * Test of interpolator for the sine function.
40       * <p>
41       * |sin^(n)(zeta)| <= 1.0, zeta in [0, 2*PI]
42       */
43      public void testSinFunction() throws MathException {
44          UnivariateRealFunction f = new SinFunction();
45          UnivariateRealInterpolator interpolator = new DividedDifferenceInterpolator();
46          double x[], y[], z, expected, result, tolerance;
47  
48          // 6 interpolating points on interval [0, 2*PI]
49          int n = 6;
50          double min = 0.0, max = 2 * Math.PI;
51          x = new double[n];
52          y = new double[n];
53          for (int i = 0; i < n; i++) {
54              x[i] = min + i * (max - min) / n;
55              y[i] = f.value(x[i]);
56          }
57          double derivativebound = 1.0;
58          UnivariateRealFunction p = interpolator.interpolate(x, y);
59  
60          z = Math.PI / 4; expected = f.value(z); result = p.value(z);
61          tolerance = Math.abs(derivativebound * partialerror(x, z));
62          assertEquals(expected, result, tolerance);
63  
64          z = Math.PI * 1.5; expected = f.value(z); result = p.value(z);
65          tolerance = Math.abs(derivativebound * partialerror(x, z));
66          assertEquals(expected, result, tolerance);
67      }
68  
69      /**
70       * Test of interpolator for the exponential function.
71       * <p>
72       * |expm1^(n)(zeta)| <= e, zeta in [-1, 1]
73       */
74      public void testExpm1Function() throws MathException {
75          UnivariateRealFunction f = new Expm1Function();
76          UnivariateRealInterpolator interpolator = new DividedDifferenceInterpolator();
77          double x[], y[], z, expected, result, tolerance;
78  
79          // 5 interpolating points on interval [-1, 1]
80          int n = 5;
81          double min = -1.0, max = 1.0;
82          x = new double[n];
83          y = new double[n];
84          for (int i = 0; i < n; i++) {
85              x[i] = min + i * (max - min) / n;
86              y[i] = f.value(x[i]);
87          }
88          double derivativebound = Math.E;
89          UnivariateRealFunction p = interpolator.interpolate(x, y);
90  
91          z = 0.0; expected = f.value(z); result = p.value(z);
92          tolerance = Math.abs(derivativebound * partialerror(x, z));
93          assertEquals(expected, result, tolerance);
94  
95          z = 0.5; expected = f.value(z); result = p.value(z);
96          tolerance = Math.abs(derivativebound * partialerror(x, z));
97          assertEquals(expected, result, tolerance);
98  
99          z = -0.5; expected = f.value(z); result = p.value(z);
100         tolerance = Math.abs(derivativebound * partialerror(x, z));
101         assertEquals(expected, result, tolerance);
102     }
103 
104     /**
105      * Test of parameters for the interpolator.
106      */
107     public void testParameters() throws Exception {
108         UnivariateRealInterpolator interpolator = new DividedDifferenceInterpolator();
109 
110         try {
111             // bad abscissas array
112             double x[] = { 1.0, 2.0, 2.0, 4.0 };
113             double y[] = { 0.0, 4.0, 4.0, 2.5 };
114             UnivariateRealFunction p = interpolator.interpolate(x, y);
115             p.value(0.0);
116             fail("Expecting MathException - bad abscissas array");
117         } catch (MathException ex) {
118             // expected
119         }
120     }
121 
122     /**
123      * Returns the partial error term (z-x[0])(z-x[1])...(z-x[n-1])/n!
124      */
125     protected double partialerror(double x[], double z) throws
126         IllegalArgumentException {
127 
128         if (x.length < 1) {
129             throw new IllegalArgumentException
130                 ("Interpolation array cannot be empty.");
131         }
132         double out = 1;
133         for (int i = 0; i < x.length; i++) {
134             out *= (z - x[i]) / (i + 1);
135         }
136         return out;
137     }
138 }