/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.function;
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import org.testng.annotations.Test;
import com.opengamma.strata.math.impl.interpolation.ConstrainedCubicSplineInterpolator;
import com.opengamma.strata.math.impl.interpolation.CubicSplineInterpolator;
import com.opengamma.strata.math.impl.interpolation.NaturalSplineInterpolator;
import com.opengamma.strata.math.impl.interpolation.PiecewiseCubicHermiteSplineInterpolator;
import com.opengamma.strata.math.impl.interpolation.PiecewisePolynomialInterpolator;
import com.opengamma.strata.math.impl.interpolation.PiecewisePolynomialResultsWithSensitivity;
import com.opengamma.strata.math.impl.interpolation.SemiLocalCubicSplineInterpolator;
/**
* Test.
*/
@Test
public class PiecewisePolynomialWithSensitivityFunction1DTest {
private static final double EPS = 1.e-7;
private static final PiecewisePolynomialWithSensitivityFunction1D FUNCTION = new PiecewisePolynomialWithSensitivityFunction1D();
/**
*
*/
@Test
public void firstDerivativeFiniteDifferenceTest() {
final PiecewisePolynomialInterpolator[] interps = new PiecewisePolynomialInterpolator[] {new NaturalSplineInterpolator(), new CubicSplineInterpolator(),
new PiecewiseCubicHermiteSplineInterpolator(), new ConstrainedCubicSplineInterpolator(), new SemiLocalCubicSplineInterpolator() };
final int nInterps = interps.length;
for (int k = 0; k < nInterps; ++k) {
final double[] xValues = new double[] {1., 2.8, 3.1, 5.9, 10., 16. };
final double[] yValues = new double[] {1., 2., 3., -2., 5., -5. };
final int nData = xValues.length;
double[] yValuesUp = Arrays.copyOf(yValues, nData);
double[] yValuesDw = Arrays.copyOf(yValues, nData);
final double[] xKeys = new double[10 * nData];
final double xMin = xValues[0];
final double xMax = xValues[nData - 1];
for (int i = 0; i < 10 * nData; ++i) {
xKeys[i] = xMin + (xMax - xMin) / (10 * nData - 1) * i;
}
PiecewisePolynomialResultsWithSensitivity result = interps[k].interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nData; ++j) {
yValuesUp[j] = yValues[j] * (1. + EPS);
yValuesDw[j] = yValues[j] * (1. - EPS);
final PiecewisePolynomialResultsWithSensitivity resultUp = interps[k].interpolateWithSensitivity(xValues, yValuesUp);
final PiecewisePolynomialResultsWithSensitivity resultDw = interps[k].interpolateWithSensitivity(xValues, yValuesDw);
final double[] valuesUp = FUNCTION.evaluate(resultUp, xKeys).rowArray(0);
final double[] valuesDw = FUNCTION.evaluate(resultDw, xKeys).rowArray(0);
final double[] diffUp = FUNCTION.differentiate(resultUp, xKeys).rowArray(0);
final double[] diffDw = FUNCTION.differentiate(resultDw, xKeys).rowArray(0);
for (int i = 0; i < 10 * nData; ++i) {
final double xKeyUp = xKeys[i] * (1. + EPS);
final double xKeyDw = xKeys[i] * (1. - EPS);
double valueFinite = 0.5 * (valuesUp[i] - valuesDw[i]) / EPS / yValues[j];
double senseFinite = 0.5 * (diffUp[i] - diffDw[i]) / EPS / yValues[j];
final double resNodeSensitivity = FUNCTION.nodeSensitivity(result, xKeys[i]).get(j);
final double resNodeSensitivityXkeyUp = FUNCTION.nodeSensitivity(result, xKeyUp).get(j);
final double resNodeSensitivityXkeyDw = FUNCTION.nodeSensitivity(result, xKeyDw).get(j);
final double senseFiniteXkey = 0.5 * (resNodeSensitivityXkeyUp - resNodeSensitivityXkeyDw) / EPS / xKeys[i];
final double resDiffNodeSensitivity = FUNCTION.differentiateNodeSensitivity(result, xKeys[i]).get(j);
assertEquals(valueFinite, resNodeSensitivity, Math.max(Math.abs(yValues[j]) * EPS, EPS));
assertEquals(senseFinite, resDiffNodeSensitivity, Math.max(Math.abs(yValues[j]) * EPS, EPS));
assertEquals(senseFiniteXkey, resDiffNodeSensitivity, Math.max(Math.abs(xKeys[i]) * EPS, EPS));
}
yValuesUp[j] = yValues[j];
yValuesDw[j] = yValues[j];
}
}
}
/**
*
*/
@Test
public void secondDerivativeFiniteDifferenceTest() {
final PiecewisePolynomialInterpolator[] interps = new PiecewisePolynomialInterpolator[] {new NaturalSplineInterpolator(), new CubicSplineInterpolator(),
new PiecewiseCubicHermiteSplineInterpolator(), new ConstrainedCubicSplineInterpolator(), new SemiLocalCubicSplineInterpolator() };
final int nInterps = interps.length;
for (int k = 0; k < nInterps; ++k) {
final double[] xValues = new double[] {1., 2.8, 3.1, 5.9, 10., 16. };
final double[] yValues = new double[] {1., 2., 3., -2., 5., -5. };
final int nData = xValues.length;
double[] yValuesUp = Arrays.copyOf(yValues, nData);
double[] yValuesDw = Arrays.copyOf(yValues, nData);
final double[] xKeys = new double[10 * nData];
final double xMin = xValues[0];
final double xMax = xValues[nData - 1];
for (int i = 0; i < 10 * nData; ++i) {
xKeys[i] = xMin + (xMax - xMin) / (10 * nData - 1) * i;
}
PiecewisePolynomialResultsWithSensitivity result = interps[k].interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nData; ++j) {
yValuesUp[j] = yValues[j] * (1. + EPS);
yValuesDw[j] = yValues[j] * (1. - EPS);
final PiecewisePolynomialResultsWithSensitivity resultUp = interps[k].interpolateWithSensitivity(xValues, yValuesUp);
final PiecewisePolynomialResultsWithSensitivity resultDw = interps[k].interpolateWithSensitivity(xValues, yValuesDw);
final double[] diffUp = FUNCTION.differentiateTwice(resultUp, xKeys).toArray()[0];
final double[] diffDw = FUNCTION.differentiateTwice(resultDw, xKeys).toArray()[0];
for (int i = 0; i < 10 * nData; ++i) {
final double xKeyUp = xKeys[i] * (1. + EPS);
final double xKeyDw = xKeys[i] * (1. - EPS);
double senseFinite = 0.5 * (diffUp[i] - diffDw[i]) / EPS / yValues[j];
final double resdiffNodeSensitivityXkeyUp = FUNCTION.differentiateNodeSensitivity(result, xKeyUp).get(j);
final double resdiffNodeSensitivityXkeyDw = FUNCTION.differentiateNodeSensitivity(result, xKeyDw).get(j);
final double senseFiniteXkey = 0.5 * (resdiffNodeSensitivityXkeyUp - resdiffNodeSensitivityXkeyDw) / EPS / xKeys[i];
final double resDiffTwiceNodeSensitivity = FUNCTION.differentiateTwiceNodeSensitivity(result, xKeys[i]).get(j);
assertEquals(senseFinite, resDiffTwiceNodeSensitivity, Math.max(Math.abs(yValues[j]) * EPS, EPS));
assertEquals(senseFiniteXkey, resDiffTwiceNodeSensitivity, Math.max(Math.abs(xKeys[i]) * EPS, EPS));
}
yValuesUp[j] = yValues[j];
yValuesDw[j] = yValues[j];
}
}
}
/**
* Interpolations with longer yValues
*/
@Test
public void clampedFiniteDifferenceTest() {
final PiecewisePolynomialInterpolator[] interps = new PiecewisePolynomialInterpolator[] {new CubicSplineInterpolator() };
final int nInterps = interps.length;
for (int k = 0; k < nInterps; ++k) {
final double[] xValues = new double[] {1., 2.8, 3.1, 5.9, 10., 16. };
final double[] bcs = new double[] {-2., -1.5, 0., 1. / 3., 3.2 };
final int nBcs = bcs.length;
for (int l = 0; l < nBcs; ++l) {
for (int m = 0; m < nBcs; ++m) {
final double[] yValues = new double[] {bcs[l], 1., 2., 3., -2., 5., -5., bcs[m] };
final int nData = xValues.length;
double[] yValuesUp = Arrays.copyOf(yValues, nData + 2);
double[] yValuesDw = Arrays.copyOf(yValues, nData + 2);
final double[] xKeys = new double[10 * nData];
final double xMin = xValues[0];
final double xMax = xValues[nData - 1];
for (int i = 0; i < 10 * nData; ++i) {
xKeys[i] = xMin + (xMax - xMin) / (10 * nData - 1) * i;
}
PiecewisePolynomialResultsWithSensitivity result = interps[k].interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nData; ++j) {
yValuesUp[j + 1] = yValues[j + 1] * (1. + EPS);
yValuesDw[j + 1] = yValues[j + 1] * (1. - EPS);
final PiecewisePolynomialResultsWithSensitivity resultUp = interps[k].interpolateWithSensitivity(xValues, yValuesUp);
final PiecewisePolynomialResultsWithSensitivity resultDw = interps[k].interpolateWithSensitivity(xValues, yValuesDw);
final double[] valuesUp = FUNCTION.evaluate(resultUp, xKeys).toArray()[0];
final double[] valuesDw = FUNCTION.evaluate(resultDw, xKeys).toArray()[0];
final double[] diffUp = FUNCTION.differentiate(resultUp, xKeys).toArray()[0];
final double[] diffDw = FUNCTION.differentiate(resultDw, xKeys).toArray()[0];
for (int i = 0; i < 10 * nData; ++i) {
final double xKeyUp = xKeys[i] * (1. + EPS);
final double xKeyDw = xKeys[i] * (1. - EPS);
double valueFinite = 0.5 * (valuesUp[i] - valuesDw[i]) / EPS / yValues[j + 1];
double senseFinite = 0.5 * (diffUp[i] - diffDw[i]) / EPS / yValues[j + 1];
final double resNodeSensitivity = FUNCTION.nodeSensitivity(result, xKeys[i]).get(j);
final double resNodeSensitivityXkeyUp = FUNCTION.nodeSensitivity(result, xKeyUp).get(j);
final double resNodeSensitivityXkeyDw = FUNCTION.nodeSensitivity(result, xKeyDw).get(j);
final double senseFiniteXkey = 0.5 * (resNodeSensitivityXkeyUp - resNodeSensitivityXkeyDw) / EPS / xKeys[i];
final double resDiffNodeSensitivity = FUNCTION.differentiateNodeSensitivity(result, xKeys[i]).get(j);
assertEquals(valueFinite, resNodeSensitivity, Math.max(Math.abs(yValues[j + 1]) * EPS, EPS));
assertEquals(senseFinite, resDiffNodeSensitivity, Math.max(Math.abs(yValues[j + 1]) * EPS, EPS));
assertEquals(senseFiniteXkey, resDiffNodeSensitivity, Math.max(Math.abs(xKeys[i]) * EPS, EPS));
}
yValuesUp[j + 1] = yValues[j + 1];
yValuesDw[j + 1] = yValues[j + 1];
}
}
}
}
}
/**
*
*/
@Test
public void clampedSecondDerivativeFiniteDifferenceTest() {
final PiecewisePolynomialInterpolator[] interps = new PiecewisePolynomialInterpolator[] {new CubicSplineInterpolator() };
final int nInterps = interps.length;
for (int k = 0; k < nInterps; ++k) {
final double[] xValues = new double[] {1., 2.8, 3.1, 5.9, 10., 16. };
final double[] bcs = new double[] {-2., -1.5, 0., 1. / 3., 3.2 };
final int nBcs = bcs.length;
for (int l = 0; l < nBcs; ++l) {
for (int m = 0; m < nBcs; ++m) {
final double[] yValues = new double[] {bcs[l], 1., 2., 3., -2., 5., -5., bcs[m] };
final int nData = xValues.length;
double[] yValuesUp = Arrays.copyOf(yValues, nData + 2);
double[] yValuesDw = Arrays.copyOf(yValues, nData + 2);
final double[] xKeys = new double[10 * nData];
final double xMin = xValues[0];
final double xMax = xValues[nData - 1];
for (int i = 0; i < 10 * nData; ++i) {
xKeys[i] = xMin + (xMax - xMin) / (10 * nData - 1) * i;
}
PiecewisePolynomialResultsWithSensitivity result = interps[k].interpolateWithSensitivity(xValues, yValues);
for (int j = 0; j < nData; ++j) {
yValuesUp[j + 1] = yValues[j + 1] * (1. + EPS);
yValuesDw[j + 1] = yValues[j + 1] * (1. - EPS);
final PiecewisePolynomialResultsWithSensitivity resultUp = interps[k].interpolateWithSensitivity(xValues, yValuesUp);
final PiecewisePolynomialResultsWithSensitivity resultDw = interps[k].interpolateWithSensitivity(xValues, yValuesDw);
final double[] diffUp = FUNCTION.differentiateTwice(resultUp, xKeys).toArray()[0];
final double[] diffDw = FUNCTION.differentiateTwice(resultDw, xKeys).toArray()[0];
for (int i = 0; i < 10 * nData; ++i) {
final double xKeyUp = xKeys[i] * (1. + EPS);
final double xKeyDw = xKeys[i] * (1. - EPS);
double senseFinite = 0.5 * (diffUp[i] - diffDw[i]) / EPS / yValues[j + 1];
final double resdiffNodeSensitivityXkeyUp = FUNCTION.differentiateNodeSensitivity(result, xKeyUp).get(j);
final double resdiffNodeSensitivityXkeyDw = FUNCTION.differentiateNodeSensitivity(result, xKeyDw).get(j);
final double senseFiniteXkey = 0.5 * (resdiffNodeSensitivityXkeyUp - resdiffNodeSensitivityXkeyDw) / EPS / xKeys[i];
final double resDiffTwiceNodeSensitivity = FUNCTION.differentiateTwiceNodeSensitivity(result, xKeys[i]).get(j);
assertEquals(senseFinite, resDiffTwiceNodeSensitivity, Math.max(Math.abs(yValues[j + 1]) * EPS, EPS));
assertEquals(senseFiniteXkey, resDiffTwiceNodeSensitivity, Math.max(Math.abs(xKeys[i]) * EPS, EPS));
}
yValuesUp[j + 1] = yValues[j + 1];
yValuesDw[j + 1] = yValues[j + 1];
}
}
}
}
}
}