SplineInterpolator implements Interpolator { public InterpolatingFunction interpolate(double[] x, double[] y) { if (x.length != y.length) { throw new IllegalArgumentException(MessageFormat.format( "Dimension mismatch {0} != {1}.", x.length, y.length)); } if (x.length < minNumPoints) { throw new IllegalArgumentException(MessageFormat.format( "{0} points are required, got only {1}.", minNumPoints, x.length)); } int n = x.length - 1; for (int i = 0; i < n; i++) { if (x[i] >= x[i + 1]) { throw new IllegalArgumentException(MessageFormat.format( "Points {0} and {1} are not strictly increasing ({2} >= {3}).", i, i + 1, x[i], x[i + 1])); } } double[] h = new double[n]; for (int i = 0; i < n; i++) { h[i] = x[i + 1] - x[i]; } double[] mu = new double[n]; double[] z = new double[n + 1]; mu[0] = 0d; z[0] = 0d; double g = 0; for (int i = 1; i < n; i++) { g = 2d * (x[i + 1] - x[i - 1]) - h[i - 1] * mu[i - 1]; mu[i] = h[i] / g; z[i] = (3d * (y[i + 1] * h[i - 1] - y[i] * (x[i + 1] - x[i - 1]) + y[i - 1] * h[i]) / (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g; } double[] b = new double[n]; double[] c = new double[n + 1]; double[] d = new double[n]; z[n] = 0d; c[n] = 0d; for (int j = n - 1; j >= 0; j--) { c[j] = z[j] - mu[j] * c[j + 1]; b[j] = (y[j + 1] - y[j]) / h[j] - h[j] * (c[j + 1] + 2d * c[j]) / 3d; d[j] = (c[j + 1] - c[j]) / (3d * h[j]); } PolynomialFunction[] polynomials = new PolynomialFunction[n]; double[] coefficients = new double[4]; for (int i = 0; i < n; i++) { coefficients[0] = y[i]; coefficients[1] = b[i]; coefficients[2] = c[i]; coefficients[3] = d[i]; polynomials[i] = new PolynomialFunction(coefficients); } return new InterpolatingFunction(x, polynomials); }  @Override int getMinNumPoints(); InterpolatingFunction interpolate(double[] x, double[] y);  }
@Test public void testInterpolationOfStraightLine() { double[] x = new double[]{0d, 2d, 4d, 6d, 8d}; double[] y = new double[]{1d, 1d, 1d, 1d, 1d}; final InterpolatingFunction function = splineInterpolator.interpolate(x, y); assertKnownValuesAreAssignedCorrectly(x, y, function); assertEquals(1d, function.value(1d), 0d); assertEquals(1d, function.value(3d), 0d); assertEquals(1d, function.value(5d), 0d); assertEquals(1d, function.value(7d), 0d); }
@Test public void testInterpolationOfFunctionWithPositiveAndNegativeSlope() { double[] x = new double[]{0d, 2d, 4d, 6d, 8d}; double[] y = new double[]{1d, 3d, 5d, 3d, 1d}; final InterpolatingFunction function = splineInterpolator.interpolate(x, y); assertKnownValuesAreAssignedCorrectly(x, y, function); assertEquals(2d, function.value(1d), 1); assertEquals(4d, function.value(3d), 1); assertEquals(4d, function.value(5d), 1); assertEquals(2d, function.value(7d), 1); }
@Test public void testInterpolationOfQuadraticFunction() { double[] x = new double[]{0d, 2d, 4d, 6d, 8d}; double[] y = new double[]{Math.pow(0d, 2), Math.pow(2d, 2), Math.pow(4d, 2), Math.pow(6d, 2), Math.pow(8d, 2)}; final InterpolatingFunction function = splineInterpolator.interpolate(x, y); assertKnownValuesAreAssignedCorrectly(x, y, function); assertEquals(Math.pow(1d, 2), function.value(1d), 0.5); assertEquals(Math.pow(3d, 2), function.value(3d), 2); assertEquals(Math.pow(5d, 2), function.value(5d), 2); assertEquals(Math.pow(7d, 2), function.value(7d), 2.5); }
@Test public void testInterpolationOfSinusFunction() { double[] x = new double[]{0d, 2d, 4d, 6d, 8d, 10d, 12d, 14d, 16d}; double[] y = new double[]{Math.sin(0d), Math.sin(Math.PI / 8), Math.sin(Math.PI / 4), Math.sin(Math.PI / 8 * 3), Math.sin(Math.PI / 2), Math.sin(Math.PI / 8 * 5), Math.sin(Math.PI / 4 * 3), Math.sin(Math.PI / 8 * 7), Math.sin(Math.PI)}; final InterpolatingFunction function = splineInterpolator.interpolate(x, y); assertKnownValuesAreAssignedCorrectly(x, y, function); assertEquals(Math.sin(Math.PI / 16), function.value(1d), 1e-4); assertEquals(Math.sin(Math.PI / 16 * 3), function.value(3d), 1e-2); assertEquals(Math.sin(Math.PI / 16 * 5), function.value(5d), 1e-1); assertEquals(Math.sin(Math.PI / 16 * 7), function.value(7d), 1e-1); assertEquals(Math.sin(Math.PI / 16 * 9), function.value(9d), 1e-1); assertEquals(Math.sin(Math.PI / 16 * 11), function.value(11d), 1e-1); assertEquals(Math.sin(Math.PI / 16 * 13), function.value(13d), 1e-1); assertEquals(Math.sin(Math.PI / 16 * 15), function.value(15d), 1e-2); }
@Test public void testInterpolationOfRandomValues() { double[] x = new double[]{0d, 4d, 7d, 8d, 10d, 14d, 16d}; double[] y = new double[]{2d, 1d, 8d, 5d, 4d, 1d, 7d}; final InterpolatingFunction function = splineInterpolator.interpolate(x, y); assertKnownValuesAreAssignedCorrectly(x, y, function); assertEquals(-0.75, function.value(2d), 1e-2); assertEquals(6.23, function.value(5.5), 1e-2); assertEquals(6.58, function.value(7.5), 1e-2); assertEquals(3.91, function.value(9d), 1e-2); assertEquals(1.67, function.value(12d), 1e-2); assertEquals(3.39, function.value(15d), 1e-2); }