/**
* 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 org.testng.annotations.Test;
import org.testng.internal.junit.ArrayAsserts;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.math.FunctionUtils;
import com.opengamma.analytics.math.differentiation.FiniteDifferenceType;
import com.opengamma.analytics.math.differentiation.ScalarFieldFirstOrderDifferentiator;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.data.InterpolationBoundedValues;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.util.test.TestGroup;
/**
* Test SquareLinearInterpolator1D
*/
@Test(groups = TestGroup.UNIT)
public class SquareLinearInterpolator1DTest {
private static final Interpolator1D INTERP = new SquareLinearInterpolator1D();
private static final double TOL = 1.0E-12;
private static final double EPS = 1.0E-6;
private static final ScalarFieldFirstOrderDifferentiator DIFF = new ScalarFieldFirstOrderDifferentiator(
FiniteDifferenceType.CENTRAL, EPS);
private static final double TOLERANCE_DELTA = 1.0E-6;
private static final double TOLERANCE_DELTA_0 = 1.0E-3;
/**
* Consistency with LinearInterpolator1D
*/
@Test
public void linearInterpolationConsistencyTest() {
double[][] xDataSet = new double[][] { {1., 2., 3.1, 4.8, 5.2 }, {-4.2, -1.2, 0.0, 11.0 / 7.0, 2.4, 3.3 },
{3., 5., 6., 7., 9.2, 9.9, 10.2 } };
double[][] yDataSet = new double[][] { {1.4, 2., 2.4, 3.6, 4.9 }, {4.5, 3.1, 2.6, 1.5, 1.1, 0.4 },
{4.5, 2.4, 2., 3.6, 5.2, 6.9, 6.1 } };
int nSet = xDataSet.length;
for (int k = 0; k < nSet; ++k) {
double[] xData = xDataSet[k];
double[] yData = yDataSet[k];
int nData = xData.length;
double[] ySq = new double[nData];
for (int i = 0; i < nData; ++i) {
ySq[i] = yData[i] * yData[i];
}
Interpolator1D linInterp = new LinearInterpolator1D();
Interpolator1DDataBundle bundleLin = linInterp.getDataBundle(xData, ySq);
Interpolator1DDataBundle bundleSqr = INTERP.getDataBundleFromSortedArrays(xData, yData);
Function1D<DoubleMatrix1D, Double> interpFunc = getInterpolationFunction(INTERP, bundleSqr);
int nKeys = 100;
double interval = (xData[nData - 1] - xData[0]) / (nKeys - 1);
for (int i = 0; i < nKeys; ++i) {
double key = xData[0] + interval * i;
/* value */
double expectedValue = Math.sqrt(linInterp.interpolate(bundleLin, key));
double computedValue = INTERP.interpolate(bundleSqr, key);
InterpolatorTestUtil.assertRelative("linearInterpolationConsistencyTest, interpolate", expectedValue,
computedValue, TOL);
/* first derivative */
double expectedFirst = 0.5 * linInterp.firstDerivative(bundleLin, key) / expectedValue;
double computedFirst = INTERP.firstDerivative(bundleSqr, key);
InterpolationBoundedValues boundedValues = bundleSqr.getBoundedValues(key);
int index = boundedValues.getLowerBoundIndex();
double min = index == nData - 1 ? xData[nData - 2] : boundedValues.getLowerBoundKey();
double max = index == nData - 1 ? xData[nData - 1] : boundedValues.getHigherBoundKey();
Function1D<DoubleMatrix1D, Boolean> domain = getDomainFunction(min, max);
Function1D<DoubleMatrix1D, DoubleMatrix1D> diffFunc = DIFF.differentiate(interpFunc, domain);
double finiteFirst = diffFunc.evaluate(new DoubleMatrix1D(new double[] {key })).getEntry(0);
InterpolatorTestUtil.assertRelative("linearInterpolationConsistencyTest, firstDerivative", expectedFirst,
computedFirst, TOL);
InterpolatorTestUtil.assertRelative("linearInterpolationConsistencyTest, firstDerivative", finiteFirst,
computedFirst, EPS);
/* node sensitivity */
double[] expectedSense = linInterp.getNodeSensitivitiesForValue(bundleLin, key);
double[] computedSense = INTERP.getNodeSensitivitiesForValue(bundleSqr, key);
double[] computedSenseFinite = INTERP.getFiniteDifferenceSensitivities(bundleSqr, key);
for (int j = 0; j < nData; ++j) {
expectedSense[j] *= yData[j] / expectedValue;
}
InterpolatorTestUtil.assertArrayRelative("linearInterpolationConsistencyTest, getNodeSensitivitiesForValue",
expectedSense, computedSense, TOL);
InterpolatorTestUtil.assertArrayRelative("linearInterpolationConsistencyTest, getNodeSensitivitiesForValue",
computedSenseFinite, computedSense, EPS);
}
}
}
/**
* Recover a function of the form $\sqrt{a_i x + b_i}$ in the i-th interval
*/
@Test
public void recoveryTest() {
final double[] xData = new double[] {1.0, 2.0, 3.5, 4.0 };
final int nData = xData.length;
final double[] aValue = new double[] {1.5, 2.0, -2.0 };
final double[] bValue = new double[] {2.0, 1.0, 15.0 };
Function1D<Double, Double> valFunc = new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
int index = Math.min(nData - 2, FunctionUtils.getLowerBoundIndex(xData, x));
return Math.sqrt(aValue[index] * x + bValue[index]);
}
};
Function1D<Double, Double> gradFunc = new Function1D<Double,Double>(){
@Override
public Double evaluate(Double x) {
int index = Math.min(nData - 2, FunctionUtils.getLowerBoundIndex(xData, x));
return 0.5 * aValue[index] / Math.sqrt(aValue[index] * x + bValue[index]);
}
};
double[] yData = new double[nData];
for (int i = 0; i < nData; ++i) {
yData[i] = valFunc.evaluate(xData[i]);
}
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
int nKeys = 100;
double interval = (xData[nData - 1] - xData[0]) / (nKeys - 1);
for (int i = 0; i < nKeys; ++i) {
double key = xData[0] + interval * i;
/* value */
double computed = INTERP.interpolate(bundle, key);
double expected = valFunc.evaluate(key);
InterpolatorTestUtil.assertRelative("recoveryTest, interpolate", expected, computed, TOL);
/* first derivative */
double computedFirst = INTERP.firstDerivative(bundle, key);
double expectedFirst = gradFunc.evaluate(key);
InterpolatorTestUtil.assertRelative("recoveryTest, firstDerivative", expectedFirst, computedFirst, TOL);
/* sensitivity */
double[] computedSense = INTERP.getNodeSensitivitiesForValue(bundle, key);
double[] finiteSense = INTERP.getFiniteDifferenceSensitivities(bundle, key);
InterpolatorTestUtil.assertArrayRelative("recoveryTest, getNodeSensitivitiesForValue", finiteSense,
computedSense, EPS);
}
}
/**
* y Data contains a negative number.
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void negativeDataTest() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {1.0, -2.2, 2.3, 2.1 };
INTERP.getDataBundle(xData, yData);
}
/**
* y Data contains a negative number.
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void getDataBundleFromSortedArrays() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {1.0, -2.2, 2.3, 2.1 };
INTERP.getDataBundleFromSortedArrays(xData, yData);
}
private Function1D<DoubleMatrix1D, Boolean> getDomainFunction(final double min, final double max) {
return new Function1D<DoubleMatrix1D, Boolean>() {
@Override
public Boolean evaluate(DoubleMatrix1D x) {
double x1 = x.getEntry(0);
return x1 >= min && x1 <= max;
}
};
}
private Function1D<DoubleMatrix1D, Double> getInterpolationFunction(final Interpolator1D interp,
final Interpolator1DDataBundle bundle) {
return new Function1D<DoubleMatrix1D, Double>() {
@Override
public Double evaluate(DoubleMatrix1D x) {
double x1 = x.getEntry(0);
return interp.interpolate(bundle, x1);
}
};
}
/** Tests interpolation when all values are 0. */
@Test
public void interpolationAll0() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {0.0, 0.0, 0.0, 0.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
double[] xTest = new double[] {1.0, 2.5, 3.0, 3.5, 4.0 };
int nbTest = xTest.length;
for(int i=0; i<nbTest; i++) {
assertEquals("SquareLinearInterpolator - 0 values", 0, INTERP.interpolate(bundle, xTest[i]), EPS);
}
}
/** Tests interpolation when all values are 0. */
@Test
public void interpolationOne0() {
double[] xData = new double[] {1.0, 2.0, 3.0};
double[] yData = new double[] {1.0, 0.0, 1.0};
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
assertEquals("SquareLinearInterpolator - 0 values", 1.0, INTERP.interpolate(bundle, 1.0), EPS);
assertEquals("SquareLinearInterpolator - 0 values", 1.0, INTERP.interpolate(bundle, 3.0), EPS);
double[] xTest = new double[] {1.5, 2.0, 2.5};
int nbTest = xTest.length;
for(int i=0; i<nbTest; i++) {
InterpolationBoundedValues boundedValues = bundle.getBoundedValues(xTest[i]);
double x1 = boundedValues.getLowerBoundKey();
double y1 = boundedValues.getLowerBoundValue();
double x2 = boundedValues.getHigherBoundKey();
double y2 = boundedValues.getHigherBoundValue();
double w = (x2 - xTest[i]) / (x2 - x1);
double y21 = y1 * y1;
double y22 = y2 * y2;
double ySq = w * y21 + (1.0 - w) * y22;
assertEquals("SquareLinearInterpolator - 0 values", Math.sqrt(ySq), INTERP.interpolate(bundle, xTest[i]), EPS);
}
}
/** Tests first derivative when all values are 0. */
@Test
public void firstDerivativeAll0() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {0.0, 0.0, 0.0, 0.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
double[] xTest = new double[] {1.0, 2.5, 3.0, 3.5, 4.0 };
int nbTest = xTest.length;
for(int i=0; i<nbTest; i++) {
assertEquals("SquareLinearInterpolator - 0 values", 0, INTERP.firstDerivative(bundle, xTest[i]), EPS);
}
}
/** Tests first derivative when all values are 0. */
@Test
public void firstDerivativeOne0() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {1.0, 0.0, 1.0, 1.0 };
double shift = 1.0E-8;
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
double[] xTest = new double[] {1.0, 2.5, 3.0, 3.5};
int nbTest = xTest.length;
for (int i = 0; i < nbTest; i++) {
double y = INTERP.interpolate(bundle, xTest[i]);
double yP = INTERP.interpolate(bundle, xTest[i] + shift);
assertEquals("SquareLinearInterpolator - 0 values - " + i,
(yP - y) / shift, INTERP.firstDerivative(bundle, xTest[i]), TOLERANCE_DELTA);
}
}
/** Tests input sensitivity when all values are 0. */
@Test
public void sensitivityAll0() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {0.0, 0.0, 0.0, 0.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
int nbData = yData.length;
double[] xTest = new double[] {1.0, 1.1, 2.5, 3.0 - 1.0E-13, 3.0, 3.0 + 1.0E-13, 3.5, 4.0 };
int nbTest = xTest.length;
double shift = 1.0E-8;
for(int i=0; i<nbTest; i++) {
double[] sensiAD = INTERP.getNodeSensitivitiesForValue(bundle, xTest[i]);
double y = INTERP.interpolate(bundle, xTest[i]);
double[] sensiFD = new double[nbData];
for(int j=0; j<nbData; j++) {
double[] yDataBumped = yData.clone();
yDataBumped[j] += shift;
Interpolator1DDataBundle bundleBumped = INTERP.getDataBundle(xData, yDataBumped);
double yBumped = INTERP.interpolate(bundleBumped, xTest[i]);
sensiFD[j] = (yBumped - y)/ shift;
}
ArrayAsserts.assertArrayEquals("SquareLinearInterpolator1DTest - " + i, sensiFD, sensiAD, TOLERANCE_DELTA);
}
}
/** Tests input sensitivity when all values are 0. */
@Test
public void sensitivityOne0() {
double[] xData = new double[] {1.0, 2.0, 3.0, 4.0 };
double[] yData = new double[] {0.1, 0.0, 0.1, 1.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
int nbData = yData.length;
double[] xTest = new double[] {1.0, 1.1, 2.0 - 1.0E-14, 2.0, 2.0 + 1.0E-14, 2.5, 3.1, 3.5, 4.0};
int nbTest = xTest.length;
double shift = 1.0E-4;
for(int i=0; i<nbTest; i++) {
double[] sensiAD = INTERP.getNodeSensitivitiesForValue(bundle, xTest[i]);
double y = INTERP.interpolate(bundle, xTest[i]);
double[] sensiFD = new double[nbData];
for(int j=0; j<nbData; j++) {
double[] yDataBumped = yData.clone();
yDataBumped[j] += shift;
Interpolator1DDataBundle bundleBumped = INTERP.getDataBundle(xData, yDataBumped);
double yBumped = INTERP.interpolate(bundleBumped, xTest[i]);
sensiFD[j] = (yBumped - y)/ shift;
}
ArrayAsserts.assertArrayEquals("SquareLinearInterpolator1DTest - " + i, sensiFD, sensiAD, TOLERANCE_DELTA_0);
}
}
/** Tests first derivative at node when value is 0. */
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void firstDerivativeNodeOne0Exception1() {
double[] xData = new double[] {1.0, 2.0, 3.0};
double[] yData = new double[] {1.0, 0.0, 1.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
INTERP.firstDerivative(bundle, 2.0);
}
/** Tests first derivative at node when value is 0. */
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void firstDerivativeNodeOne0Exception2() {
double[] xData = new double[] {1.0, 2.0, 3.0 };
double[] yData = new double[] {1.0, 0.0, 1.0 };
Interpolator1DDataBundle bundle = INTERP.getDataBundle(xData, yData);
INTERP.firstDerivative(bundle, 2.0 - 1.0E-14);
}
}