/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.interpolation;
import java.util.Arrays;
import org.testng.annotations.Test;
import com.opengamma.strata.collect.DoubleArrayMath;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.math.impl.function.PiecewisePolynomialWithSensitivityFunction1D;
/**
*
*/
@Test
public class ProductPiecewisePolynomialInterpolatorTest {
private static final double EPS = 1.0e-12;
private static final double DELTA = 1.0e-6;
private static final PiecewisePolynomialInterpolator[] INTERP;
private static final PiecewisePolynomialInterpolator[] INTERP_SENSE;
static {
PiecewisePolynomialInterpolator cubic = new CubicSplineInterpolator();
PiecewisePolynomialInterpolator natural = new NaturalSplineInterpolator();
PiecewiseCubicHermiteSplineInterpolatorWithSensitivity pchip =
new PiecewiseCubicHermiteSplineInterpolatorWithSensitivity();
PiecewisePolynomialInterpolator hymanNat = new MonotonicityPreservingCubicSplineInterpolator(natural);
INTERP = new PiecewisePolynomialInterpolator[] {cubic, natural, hymanNat };
INTERP_SENSE = new PiecewisePolynomialInterpolator[] {cubic, natural, pchip, hymanNat };
}
private static final PiecewisePolynomialWithSensitivityFunction1D FUNC =
new PiecewisePolynomialWithSensitivityFunction1D();
/**
* No clamped points added
*/
@Test
public void notClampedTest() {
double[][] xValuesSet = new double[][] { {-5.0, -1.4, 3.2, 3.5, 7.6 }, {1., 2., 4.5, 12.1, 14.2 },
{-5.2, -3.4, -3.2, -0.9, -0.2 } };
double[][] yValuesSet = new double[][] { {-2.2, 1.1, 1.9, 2.3, -0.1 }, {3.4, 5.2, 4.3, 1.1, 0.2 },
{1.4, 2.2, 4.1, 1.9, 0.99 } };
for (int k = 0; k < xValuesSet.length; ++k) {
double[] xValues = Arrays.copyOf(xValuesSet[k], xValuesSet[k].length);
double[] yValues = Arrays.copyOf(yValuesSet[k], yValuesSet[k].length);
int nData = xValues.length;
double[] xyValues = new double[nData];
for (int j = 0; j < nData; ++j) {
xyValues[j] = xValues[j] * yValues[j];
}
int nKeys = 100;
double interval = (xValues[nData - 1] - xValues[0]) / (nKeys - 1.0);
int n = INTERP.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP[i]);
for (int j = 0; j < nKeys; ++j) {
double key = xValues[0] + interval * j;
InterpolatorTestUtil.assertRelative("notClampedTest", INTERP[i].interpolate(xValues, xyValues, key),
interp.interpolate(xValues, yValues, key), EPS);
}
}
n = INTERP_SENSE.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i]);
PiecewisePolynomialResultsWithSensitivity result = interp.interpolateWithSensitivity(xValues, yValues);
PiecewisePolynomialResultsWithSensitivity resultBase = INTERP_SENSE[i].interpolateWithSensitivity(xValues,
xyValues);
for (int j = 0; j < nKeys; ++j) {
double key = xValues[0] + interval * j;
InterpolatorTestUtil.assertRelative("notClampedTest", FUNC.evaluate(resultBase, key).get(0), FUNC
.evaluate(result, key)
.get(0), EPS);
InterpolatorTestUtil.assertArrayRelative("notClampedTest", FUNC.nodeSensitivity(resultBase, key).toArray(),
FUNC.nodeSensitivity(result, key).toArray(), EPS);
}
}
}
}
/**
* Clamped points
*/
@Test
public void clampedTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5, 7.6 };
double[] yValues = new double[] {-2.2, 1.1, 1.9, 2.3, -0.1 };
double[][] xValuesClampedSet = new double[][] { {0.0 }, {-7.2, -2.5, 8.45 }, {} };
double[][] yValuesClampedSet = new double[][] { {0.0 }, {-1.2, -1.4, 2.2 }, {} };
for (int k = 0; k < xValuesClampedSet.length; ++k) {
double[] xValuesClamped = Arrays.copyOf(xValuesClampedSet[k], xValuesClampedSet[k].length);
double[] yValuesClamped = Arrays.copyOf(yValuesClampedSet[k], yValuesClampedSet[k].length);
int nData = xValues.length;
int nClamped = xValuesClamped.length;
int nTotal = nData + nClamped;
double[] xValuesForBase = new double[nTotal];
double[] yValuesForBase = new double[nTotal];
System.arraycopy(xValues, 0, xValuesForBase, 0, nData);
System.arraycopy(yValues, 0, yValuesForBase, 0, nData);
System.arraycopy(xValuesClamped, 0, xValuesForBase, nData, nClamped);
System.arraycopy(yValuesClamped, 0, yValuesForBase, nData, nClamped);
DoubleArrayMath.sortPairs(xValuesForBase, yValuesForBase);
double[] xyValuesBase = new double[nTotal];
for (int j = 0; j < nTotal; ++j) {
xyValuesBase[j] = xValuesForBase[j] * yValuesForBase[j];
}
int nKeys = 100;
double interval = (xValues[nData - 1] - xValues[0]) / (nKeys - 1.0);
int n = INTERP.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP[i],
xValuesClamped, yValuesClamped);
for (int j = 0; j < nKeys; ++j) {
double key = xValues[0] + interval * j;
InterpolatorTestUtil.assertRelative("clampedTest", INTERP[i].interpolate(xValuesForBase, xyValuesBase, key),
interp.interpolate(xValues, yValues, key), EPS);
}
}
n = INTERP_SENSE.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i],
xValuesClamped, yValuesClamped);
PiecewisePolynomialResultsWithSensitivity result = interp.interpolateWithSensitivity(xValues, yValues);
PiecewisePolynomialResultsWithSensitivity resultBase = INTERP_SENSE[i].interpolateWithSensitivity(
xValuesForBase, xyValuesBase);
for (int j = 0; j < nKeys; ++j) {
double key = xValues[0] + interval * j;
InterpolatorTestUtil.assertRelative("clampedTest", FUNC.evaluate(resultBase, key).get(0),
FUNC.evaluate(result, key)
.get(0), EPS);
InterpolatorTestUtil.assertArrayRelative("clampedTest", FUNC.nodeSensitivity(resultBase, key).toArray(),
FUNC.nodeSensitivity(result, key).toArray(), EPS);
}
}
}
}
/**
* Test linear extrapolation without clamped points
*/
@Test
public void linearExtrapolationNoClampedTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5, 7.6 };
double[] yValues = new double[] {-2.2, 1.1, 1.9, 2.3, -0.1 };
int nData = xValues.length;
int nKeys = 20;
double interval = (3.0 * xValues[nData - 1] - xValues[nData - 1]) / (nKeys - 1);
double[] keys = new double[nKeys];
int n = INTERP.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP[i]);
PiecewisePolynomialResult result = interp.interpolate(xValues, yValues);
for (int j = 0; j < nKeys; ++j) {
keys[j] = xValues[nData - 1] + j * interval;
}
double[] values = FUNC.evaluate(result, keys).row(0).toArray();
for (int j = 2; j < nKeys; ++j) {
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", values[j - 1] - values[j - 2], values[j - 1] -
values[j - 2], EPS);
}
}
n = INTERP_SENSE.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i]);
PiecewisePolynomialResultsWithSensitivity result = interp.interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nKeys; ++j) {
keys[j] = xValues[nData - 1] + j * interval;
}
double[] values = FUNC.evaluate(result, keys).row(0).toArray();
for (int j = 2; j < nKeys; ++j) {
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", values[j - 1] - values[j - 2], values[j - 1] -
values[j - 2], EPS);
}
DoubleArray[] sense = FUNC.nodeSensitivity(result, keys);
for (int k = 0; k < nData; ++k) {
double[] yValuesUp = Arrays.copyOf(yValues, nData);
double[] yValuesDw = Arrays.copyOf(yValues, nData);
yValuesUp[k] += DELTA / xValues[k];
yValuesDw[k] -= DELTA / xValues[k];
PiecewisePolynomialResultsWithSensitivity resultUp = interp.interpolateWithSensitivity(xValues, yValuesUp);
PiecewisePolynomialResultsWithSensitivity resultDw = interp.interpolateWithSensitivity(xValues, yValuesDw);
double[] tmpUp = FUNC.evaluate(resultUp, keys).rowArray(0);
double[] tmpDw = FUNC.evaluate(resultDw, keys).rowArray(0);
for (int l = 0; l < nKeys; ++l) {
double res = 0.5 * (tmpUp[l] - tmpDw[l]) / DELTA; // lk
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", sense[l].get(k), res, DELTA);
}
}
}
}
/**
* Test linear extrapolation with clamped points
*/
public void linearExtrapolationClampedTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5, 7.6 };
double[] yValues = new double[] {-2.2, 1.1, 1.9, 2.3, -0.1 };
double[] xValuesClamped = new double[] {8.9 };
double[] yValuesClamped = new double[] {3.2 };
int nData = xValues.length;
int nClamped = xValuesClamped.length;
int nKeys = 20;
double interval = (3.0 * xValuesClamped[nClamped - 1] - xValuesClamped[nClamped - 1]) / (nKeys - 1);
double[] keys = new double[nKeys];
int n = INTERP.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP[i],
xValuesClamped, yValuesClamped);
PiecewisePolynomialResult result = interp.interpolate(xValues, yValues);
for (int j = 0; j < nKeys; ++j) {
keys[j] = xValuesClamped[nClamped - 1] + j * interval;
}
double[] values = FUNC.evaluate(result, keys).row(0).toArray();
for (int j = 2; j < nKeys; ++j) {
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", values[j - 1] - values[j - 2], values[j - 1] -
values[j - 2], EPS);
}
}
n = INTERP_SENSE.length;
for (int i = 0; i < n; ++i) {
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i],
xValuesClamped, yValuesClamped);
PiecewisePolynomialResultsWithSensitivity result = interp.interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nKeys; ++j) {
keys[j] = xValuesClamped[nClamped - 1] + j * interval;
}
double[] values = FUNC.evaluate(result, keys).row(0).toArray();
for (int j = 2; j < nKeys; ++j) {
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", values[j - 1] - values[j - 2], values[j - 1] -
values[j - 2], EPS);
}
DoubleArray[] sense = FUNC.nodeSensitivity(result, keys);
for (int k = 0; k < nData; ++k) {
double[] yValuesUp = Arrays.copyOf(yValues, nData);
double[] yValuesDw = Arrays.copyOf(yValues, nData);
yValuesUp[k] += DELTA / xValues[k];
yValuesDw[k] -= DELTA / xValues[k];
PiecewisePolynomialResultsWithSensitivity resultUp = interp.interpolateWithSensitivity(xValues, yValuesUp);
PiecewisePolynomialResultsWithSensitivity resultDw = interp.interpolateWithSensitivity(xValues, yValuesDw);
double[] tmpUp = FUNC.evaluate(resultUp, keys).rowArray(0);
double[] tmpDw = FUNC.evaluate(resultDw, keys).rowArray(0);
for (int l = 0; l < nKeys; ++l) {
double res = 0.5 * (tmpUp[l] - tmpDw[l]) / DELTA;
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", sense[l].get(k), res, DELTA * 10.0);
}
}
ProductPiecewisePolynomialInterpolator interpUp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i],
xValuesClamped, new double[] {yValuesClamped[0] + DELTA / xValuesClamped[0] });
PiecewisePolynomialResultsWithSensitivity resultUp = interpUp.interpolateWithSensitivity(xValues, yValues);
ProductPiecewisePolynomialInterpolator interpDw = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i],
xValuesClamped, new double[] {yValuesClamped[0] - DELTA / xValuesClamped[0] });
PiecewisePolynomialResultsWithSensitivity resultDw = interpDw.interpolateWithSensitivity(xValues, yValues);
double[] tmpUp = FUNC.evaluate(resultUp, keys).rowArray(0);
double[] tmpDw = FUNC.evaluate(resultDw, keys).rowArray(0);
for (int l = 0; l < nKeys; ++l) {
double res = 0.5 * (tmpUp[l] - tmpDw[l]) / DELTA;
InterpolatorTestUtil.assertRelative("linearExtrapolationTest", sense[l].get(nData), res, DELTA);
}
}
}
/**
* Wrong data length
*/
@SuppressWarnings("unused")
@Test(expectedExceptions = IllegalArgumentException.class)
public void clampedDifferentLengthTest() {
double[] xValues = new double[] {-5.0, };
double[] yValues = new double[] {-2.2, 1.1 };
new ProductPiecewisePolynomialInterpolator(INTERP[0], xValues, yValues);
}
/**
* Wrong data length
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void dataDifferentLengthTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5, 7.6 };
double[] yValues = new double[] {-2.2, 1.1, 1.9, 2.3 };
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[1]);
interp.interpolate(xValues, yValues);
}
/**
* Wrong data length
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void dataDifferentLengthWithSenseTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5 };
double[] yValues = new double[] {-2.2, 1.1, 1.9, 2.3, 1.2 };
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[1]);
interp.interpolateWithSensitivity(xValues, yValues);
}
/**
* 2D method is not implemented
*/
@Test(expectedExceptions = UnsupportedOperationException.class)
public void notImplementedTest() {
double[] xValues = new double[] {-5.0, -1.4, 3.2, 3.5, 7.6 };
double[][] yValues = new double[][] { {-2.2, 1.1, 1.9, 2.3, 1.2 }, {-2.2, 1.1, 1.9, 2.3, 1.2 } };
ProductPiecewisePolynomialInterpolator interp = new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[1]);
interp.interpolate(xValues, yValues);
}
}