/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.interpolation;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Arrays;
import org.testng.annotations.Test;
import com.opengamma.analytics.math.function.PiecewisePolynomialWithSensitivityFunction1D;
import com.opengamma.analytics.math.interpolation.data.InterpolationBoundedValues;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.util.test.TestGroup;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class LogClampedCubicSplineInterpolator1DTest {
private static final Interpolator1D LOG_INTERP = Interpolator1DFactory.LOG_CLAMPED_CUBIC_INSTANCE;
private static final Interpolator1D BARE_INTERP = Interpolator1DFactory.CLAMPED_CUBIC_INSTANCE;
private static final double EPS = 1.0e-12;
private static final double DELTA = 1.0e-5;
/**
* Check consistency with bare interpolator
*/
@Test
public void sampleDataTest1() {
double[] xValues = new double[] {-1.0, 1.0, 2.5, 4.2, 10.0, 15.0, 30.0 };
double[] yValues = new double[] {4.0, 2.0, 1.0, 5.0, 10.0, 3.5, -2.0 };
double[] keys = new double[] {-0.8, 0.0, 1.2, 7.8, 10.0, 17.52, 25.0 };
int nData = yValues.length;
int nKeys = keys.length;
double[] yValuesExp = new double[nData];
for (int i = 0; i < nData; ++i) {
yValuesExp[i] = Math.exp(yValues[i]);
}
Interpolator1DDataBundle bundle = LOG_INTERP.getDataBundle(xValues, yValuesExp);
Interpolator1DDataBundle bundleSorted = LOG_INTERP.getDataBundleFromSortedArrays(xValues, yValuesExp);
assertEquals(bundle, bundleSorted);
Interpolator1DDataBundle bundleBare = BARE_INTERP.getDataBundle(xValues, yValues);
for (int i = 0; i < nKeys; ++i) {
double valueBare = BARE_INTERP.interpolate(bundleBare, keys[i]);
double value = LOG_INTERP.interpolate(bundle, keys[i]);
assertEquals(Math.exp(valueBare), value, EPS);
double[] senseBare = BARE_INTERP.getNodeSensitivitiesForValue(bundleBare, keys[i]);
double[] sense = LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[i]);
assertEquals(nData, sense.length);
for (int j = 0; j < nData; ++j) {
assertEquals(senseBare[j] * value / yValuesExp[j], sense[j], EPS);
}
}
for (int i = 0; i < nData; ++i) {
assertTrue(bundle.containsKey(xValues[i]));
assertEquals(yValuesExp[i], bundle.getValues()[i], EPS);
assertEquals(xValues[i], bundle.getKeys()[i], EPS);
}
int[] sampleIndex = new int[] {0, 1, 3 };
for (int i = 0; i < sampleIndex.length; ++i) {
assertEquals(xValues[sampleIndex[i]], bundle.getLowerBoundKey(xValues[sampleIndex[i]] + 0.01));
assertEquals(sampleIndex[i], bundle.getLowerBoundIndex(xValues[sampleIndex[i]] + 0.01));
InterpolationBoundedValues bdValues = bundle.getBoundedValues(xValues[sampleIndex[i]] + 0.02);
assertEquals(yValuesExp[sampleIndex[i] + 1], bdValues.getHigherBoundValue(), EPS);
assertEquals(yValuesExp[sampleIndex[i]], bdValues.getLowerBoundValue(), EPS);
}
/**
* Check sensitivity by finite difference approximation
*/
for (int i = 0; i < nData; ++i) {
double[] yValuesExpUp = Arrays.copyOf(yValuesExp, nData);
double[] yValuesExpDown = Arrays.copyOf(yValuesExp, nData);
yValuesExpUp[i] += DELTA;
yValuesExpDown[i] -= DELTA;
Interpolator1DDataBundle upBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpUp);
Interpolator1DDataBundle downBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpDown);
for (int j = 0; j < nKeys; ++j) {
double app = 0.5 * (LOG_INTERP.interpolate(upBundle, keys[j]) - LOG_INTERP.interpolate(downBundle, keys[j])) / DELTA;
assertEquals(app, LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[j])[i], Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Endpoint sensitivity
*/
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[0], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[1], EPS);
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 1], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 2], EPS);
/**
* Check first derivative by finite difference approximation
*/
for (int i = 0; i < nKeys; ++i) {
double app = 0.5 * (LOG_INTERP.interpolate(bundle, keys[i] + DELTA) - LOG_INTERP.interpolate(bundle, keys[i] - DELTA)) / DELTA;
assertEquals(app, LOG_INTERP.firstDerivative(bundle, keys[i]), Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Check consistency with bare interpolator using nontrivial boundary condition (i.e., first derivative values at end points)
*/
@Test
public void sampleDataWithBoundaryConditionTest1() {
double[] xValues = new double[] {-1.0, 1.0, 2.5, 4.2, 10.0, 15.0, 30.0 };
double[] yValues = new double[] {4.0, 2.0, 1.0, 5.0, 10.0, 3.5, -2.0 };
double[] keys = new double[] {-0.8, 0.0, 1.2, 7.8, 10.0, 17.52, 25.0 };
int nData = yValues.length;
int nKeys = keys.length;
double left = -.0;
double right = 0.;
double[] yValuesExp = new double[nData];
for (int i = 0; i < nData; ++i) {
yValuesExp[i] = Math.exp(yValues[i]);
}
double leftExp = left * yValuesExp[0];
double rightExp = right * yValuesExp[nData - 1];
Interpolator1DDataBundle bundle = ((PiecewisePolynomialInterpolator1D) LOG_INTERP).getDataBundleFromSortedArrays(xValues, yValuesExp, leftExp, rightExp);
Interpolator1DDataBundle bundleBare = ((PiecewisePolynomialInterpolator1D) BARE_INTERP).getDataBundle(xValues, yValues, left, right);
for (int i = 0; i < nKeys; ++i) {
double valueBare = BARE_INTERP.interpolate(bundleBare, keys[i]);
double value = LOG_INTERP.interpolate(bundle, keys[i]);
assertEquals(Math.exp(valueBare), value, EPS);
double[] senseBare = BARE_INTERP.getNodeSensitivitiesForValue(bundleBare, keys[i]);
double[] sense = LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[i]);
assertEquals(nData, sense.length);
for (int j = 0; j < nData; ++j) {
assertEquals(senseBare[j] * value / yValuesExp[j], sense[j], EPS);
}
}
for (int i = 0; i < nData; ++i) {
assertTrue(bundle.containsKey(xValues[i]));
assertEquals(yValuesExp[i], bundle.getValues()[i], EPS);
assertEquals(xValues[i], bundle.getKeys()[i], EPS);
}
int[] sampleIndex = new int[] {0, 1, 3 };
for (int i = 0; i < sampleIndex.length; ++i) {
assertEquals(xValues[sampleIndex[i]], bundle.getLowerBoundKey(xValues[sampleIndex[i]] + 0.01));
assertEquals(sampleIndex[i], bundle.getLowerBoundIndex(xValues[sampleIndex[i]] + 0.01));
InterpolationBoundedValues bdValues = bundle.getBoundedValues(xValues[sampleIndex[i]] + 0.02);
assertEquals(yValuesExp[sampleIndex[i] + 1], bdValues.getHigherBoundValue(), EPS);
assertEquals(yValuesExp[sampleIndex[i]], bdValues.getLowerBoundValue(), EPS);
}
/**
* Check sensitivity by finite difference approximation
*/
for (int i = 0; i < nData; ++i) {
double[] yValuesExpUp = Arrays.copyOf(yValuesExp, nData);
double[] yValuesExpDown = Arrays.copyOf(yValuesExp, nData);
yValuesExpUp[i] += DELTA;
yValuesExpDown[i] -= DELTA;
Interpolator1DDataBundle upBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpUp);
Interpolator1DDataBundle downBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpDown);
for (int j = 0; j < nKeys; ++j) {
double app = 0.5 * (LOG_INTERP.interpolate(upBundle, keys[j]) - LOG_INTERP.interpolate(downBundle, keys[j])) / DELTA;
assertEquals(app, LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[j])[i], Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Endpoint sensitivity
*/
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[0], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[1], EPS);
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 1], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 2], EPS);
/**
* Check first derivative by finite difference approximation
*/
for (int i = 0; i < nKeys; ++i) {
double app = 0.5 * (LOG_INTERP.interpolate(bundle, keys[i] + DELTA) - LOG_INTERP.interpolate(bundle, keys[i] - DELTA)) / DELTA;
assertEquals(app, LOG_INTERP.firstDerivative(bundle, keys[i]), Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Check consistency with bare interpolator for flat data
*/
@Test
public void sampleDataTest2() {
double[] xValues = new double[] {1.0, 2.0, 3.0, 4.0, 5.0 };
double[] yValues = new double[] {1.0, 1.0, 1.0, 1.0, 1.0 };
double[] keys = new double[] {0.1, 1.2, 3.7 };
int nData = yValues.length;
int nKeys = keys.length;
double[] yValuesExp = new double[nData];
for (int i = 0; i < nData; ++i) {
yValuesExp[i] = Math.exp(yValues[i]);
}
Interpolator1DDataBundle bundle = LOG_INTERP.getDataBundle(xValues, yValuesExp);
Interpolator1DDataBundle bundleSorted = LOG_INTERP.getDataBundleFromSortedArrays(xValues, yValuesExp);
assertEquals(bundle, bundleSorted);
Interpolator1DDataBundle bundleBare = BARE_INTERP.getDataBundle(xValues, yValues);
for (int i = 0; i < nKeys; ++i) {
double valueBare = BARE_INTERP.interpolate(bundleBare, keys[i]);
double value = LOG_INTERP.interpolate(bundle, keys[i]);
assertEquals(Math.exp(valueBare), value, EPS);
double[] senseBare = BARE_INTERP.getNodeSensitivitiesForValue(bundleBare, keys[i]);
double[] sense = LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[i]);
assertEquals(nData, sense.length);
for (int j = 0; j < nData; ++j) {
assertEquals(senseBare[j] * value / yValuesExp[j], sense[j], EPS);
}
}
for (int i = 0; i < nData; ++i) {
assertTrue(bundle.containsKey(xValues[i]));
assertEquals(yValuesExp[i], bundle.getValues()[i], EPS);
assertEquals(xValues[i], bundle.getKeys()[i], EPS);
}
int[] sampleIndex = new int[] {0, 1, 3 };
for (int i = 0; i < sampleIndex.length; ++i) {
assertEquals(xValues[sampleIndex[i]], bundle.getLowerBoundKey(xValues[sampleIndex[i]] + 0.01));
assertEquals(sampleIndex[i], bundle.getLowerBoundIndex(xValues[sampleIndex[i]] + 0.01));
InterpolationBoundedValues bdValues = bundle.getBoundedValues(xValues[sampleIndex[i]] + 0.02);
assertEquals(yValuesExp[sampleIndex[i] + 1], bdValues.getHigherBoundValue(), EPS);
assertEquals(yValuesExp[sampleIndex[i]], bdValues.getLowerBoundValue(), EPS);
}
/**
* Check sensitivity by finite difference approximation
*/
for (int i = 0; i < nData; ++i) {
double[] yValuesExpUp = Arrays.copyOf(yValuesExp, nData);
double[] yValuesExpDown = Arrays.copyOf(yValuesExp, nData);
yValuesExpUp[i] += DELTA;
yValuesExpDown[i] -= DELTA;
Interpolator1DDataBundle upBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpUp);
Interpolator1DDataBundle downBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpDown);
for (int j = 0; j < nKeys; ++j) {
double app = 0.5 * (LOG_INTERP.interpolate(upBundle, keys[j]) - LOG_INTERP.interpolate(downBundle, keys[j])) / DELTA;
assertEquals(app, LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[j])[i], Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Endpoint sensitivity
*/
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[0], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[1], EPS);
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 1], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 2], EPS);
/**
* Check first derivative by finite difference approximation
*/
for (int i = 0; i < nKeys; ++i) {
double app = 0.5 * (LOG_INTERP.interpolate(bundle, keys[i] + DELTA) - LOG_INTERP.interpolate(bundle, keys[i] - DELTA)) / DELTA;
assertEquals(app, LOG_INTERP.firstDerivative(bundle, keys[i]), Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Check consistency with bare interpolator for linear data
*/
@Test
public void sampleDataTest3() {
double[] xValues = new double[] {-1.0, 2.0, 3.0, 4.0, 5.0 };
double[] yValues = new double[] {-2.0, 4.0, 6.0, 8.0, 10.0 };
double[] keys = new double[] {0., 1.2, 2.0, 4.7 };
int nData = yValues.length;
int nKeys = keys.length;
double[] yValuesExp = new double[nData];
for (int i = 0; i < nData; ++i) {
yValuesExp[i] = Math.exp(yValues[i]);
}
Interpolator1DDataBundle bundle = LOG_INTERP.getDataBundle(xValues, yValuesExp);
Interpolator1DDataBundle bundleSorted = LOG_INTERP.getDataBundleFromSortedArrays(xValues, yValuesExp);
assertEquals(bundle, bundleSorted);
Interpolator1DDataBundle bundleBare = BARE_INTERP.getDataBundle(xValues, yValues);
for (int i = 0; i < nKeys; ++i) {
double valueBare = BARE_INTERP.interpolate(bundleBare, keys[i]);
double value = LOG_INTERP.interpolate(bundle, keys[i]);
assertEquals(Math.exp(valueBare), value, EPS);
double[] senseBare = BARE_INTERP.getNodeSensitivitiesForValue(bundleBare, keys[i]);
double[] sense = LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[i]);
assertEquals(nData, sense.length);
for (int j = 0; j < nData; ++j) {
assertEquals(senseBare[j] * value / yValuesExp[j], sense[j], EPS);
}
}
for (int i = 0; i < nData; ++i) {
assertTrue(bundle.containsKey(xValues[i]));
assertEquals(yValuesExp[i], bundle.getValues()[i], EPS);
assertEquals(xValues[i], bundle.getKeys()[i], EPS);
}
int[] sampleIndex = new int[] {0, 1, 3 };
for (int i = 0; i < sampleIndex.length; ++i) {
assertEquals(xValues[sampleIndex[i]], bundle.getLowerBoundKey(xValues[sampleIndex[i]] + 0.01));
assertEquals(sampleIndex[i], bundle.getLowerBoundIndex(xValues[sampleIndex[i]] + 0.01));
InterpolationBoundedValues bdValues = bundle.getBoundedValues(xValues[sampleIndex[i]] + 0.02);
assertEquals(yValuesExp[sampleIndex[i] + 1], bdValues.getHigherBoundValue(), EPS);
assertEquals(yValuesExp[sampleIndex[i]], bdValues.getLowerBoundValue(), EPS);
}
/**
* Check sensitivity by finite difference approximation
*/
for (int i = 0; i < nData; ++i) {
double[] yValuesExpUp = Arrays.copyOf(yValuesExp, nData);
double[] yValuesExpDown = Arrays.copyOf(yValuesExp, nData);
yValuesExpUp[i] += DELTA;
yValuesExpDown[i] -= DELTA;
Interpolator1DDataBundle upBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpUp);
Interpolator1DDataBundle downBundle = LOG_INTERP.getDataBundle(xValues, yValuesExpDown);
for (int j = 0; j < nKeys; ++j) {
double app = 0.5 * (LOG_INTERP.interpolate(upBundle, keys[j]) - LOG_INTERP.interpolate(downBundle, keys[j])) / DELTA;
assertEquals(app, LOG_INTERP.getNodeSensitivitiesForValue(bundle, keys[j])[i], Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Endpoint sensitivity
*/
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[0], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[0])[1], EPS);
assertEquals(1.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 1], EPS);
assertEquals(0.0, LOG_INTERP.getNodeSensitivitiesForValue(bundle, xValues[nData - 1])[nData - 2], EPS);
/**
* Check first derivative by finite difference approximation
*/
for (int i = 0; i < nKeys; ++i) {
double app = 0.5 * (LOG_INTERP.interpolate(bundle, keys[i] + DELTA) - LOG_INTERP.interpolate(bundle, keys[i] - DELTA)) / DELTA;
assertEquals(app, LOG_INTERP.firstDerivative(bundle, keys[i]), Math.max(Math.abs(app), 1.0) * DELTA);
}
}
/**
* Exception expected
*/
@Test
public void errorTest() {
double[] xValues1 = new double[] {-1.0, 1.0, 2.5, 4.2, };
double[] yValues1 = new double[] {5.0, 10.0, 3.5, -0.0 };
try {
LOG_INTERP.getDataBundle(xValues1, yValues1);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("y should be positive", e.getMessage());
}
double[] xValues2 = new double[] {-1.0, 1.0, 2.5, 4.2, };
double[] yValues2 = new double[] {5.0, 10.0, -3.5, 5.0 };
try {
LOG_INTERP.getDataBundleFromSortedArrays(xValues2, yValues2);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("y should be positive", e.getMessage());
}
try {
((PiecewisePolynomialInterpolator1D) LOG_INTERP).getDataBundleFromSortedArrays(xValues2, yValues2, 1.0, 1.0);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("y should be positive", e.getMessage());
}
}
/**
* Print test for 3 log cubic interpolators
*/
@Test(enabled = false)
public void printTest() {
PiecewisePolynomialWithSensitivityFunction1D func = new PiecewisePolynomialWithSensitivityFunction1D();
double[] xValues = new double[] {-3.2, -0.9, 1.4, 1.8, 6.7 };
double[] yValues = new double[] {1.0, 1.5, 2.2, 1.3, 1.8 };
double[] yValuesClamp = new double[] {0.0, 1.0, 1.5, 2.2, 1.3, 1.8, 0.0 };
int nData = yValues.length;
int nKeys = 100;
double[] keys = new double[nKeys];
double interval = (xValues[nData - 1] - xValues[0]) / (nKeys - 1);
for (int i = 0; i < nKeys; ++i) {
keys[i] = xValues[0] + interval * i;
}
double[] yValuesExp = new double[nData];
for (int i = 0; i < nData; ++i) {
yValuesExp[i] = Math.exp(yValues[i]);
}
Interpolator1D nat = Interpolator1DFactory.LOG_NATURAL_CUBIC_INSTANCE;
Interpolator1D knot = Interpolator1DFactory.LOG_NOTAKNOT_CUBIC_INSTANCE;
Interpolator1D clam = Interpolator1DFactory.LOG_CLAMPED_CUBIC_INSTANCE;
Interpolator1DDataBundle bundleNat = nat.getDataBundle(xValues, yValuesExp);
Interpolator1DDataBundle bundleKnot = knot.getDataBundle(xValues, yValuesExp);
Interpolator1DDataBundle bundleClam = clam.getDataBundle(xValues, yValuesExp);
PiecewisePolynomialInterpolator natBare = new NaturalSplineInterpolator();
PiecewisePolynomialInterpolator knotBare = new CubicSplineInterpolator();
PiecewisePolynomialInterpolator clamBare = new CubicSplineInterpolator();
PiecewisePolynomialResultsWithSensitivity resNat = natBare.interpolateWithSensitivity(xValues, yValues);
PiecewisePolynomialResultsWithSensitivity resKnot = knotBare.interpolateWithSensitivity(xValues, yValues);
PiecewisePolynomialResultsWithSensitivity resClam = clamBare.interpolateWithSensitivity(xValues, yValuesClamp);
for (int i = 0; i < nKeys; ++i) {
System.out.println(keys[i] + "\t" + nat.interpolate(bundleNat, keys[i]) + "\t" + knot.interpolate(bundleKnot, keys[i]) + "\t" + clam.interpolate(bundleClam, keys[i]));
}
System.out.println();
for (int i = 0; i < nKeys; ++i) {
System.out.println(keys[i] + "\t" + func.evaluate(resNat, keys[i]).getData()[0] + "\t" + func.evaluate(resKnot, keys[i]).getData()[0] + "\t" + func.evaluate(resClam, keys[i]).getData()[0]);
}
}
}