/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.market.curve.interpolator;
import static com.opengamma.strata.collect.TestHelper.assertSerialization;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.function.Function;
import org.testng.annotations.Test;
import com.opengamma.strata.collect.DoubleArrayMath;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.math.impl.differentiation.FiniteDifferenceType;
import com.opengamma.strata.math.impl.differentiation.ScalarFieldFirstOrderDifferentiator;
import com.opengamma.strata.math.impl.differentiation.ScalarFirstOrderDifferentiator;
/**
* Test {@link ProductLinearCurveExtrapolator}.
*/
@Test
public class ProductLinearCurveExtrapolatorTest {
private static final CurveExtrapolator EXTRAP = ProductLinearCurveExtrapolator.INSTANCE;
private static final DoubleArray X_DATA = DoubleArray.of(-0.5, 0.4, 1.0, 1.8, 2.8, 5.0);
private static final DoubleArray Y_DATA = DoubleArray.of(3.0, 4.0, 3.1, 2.0, 7.0, 2.0);
private static final int SIZE = X_DATA.size();
private static final DoubleArray X_LEFT_TEST = DoubleArray.of(-3.5, -1.1);
private static final DoubleArray X_RIGHT_TEST = DoubleArray.of(8.5, 11.1);
private static final double EPS = 1.e-7;
private static final ScalarFirstOrderDifferentiator DIFF_CALC =
new ScalarFirstOrderDifferentiator(FiniteDifferenceType.CENTRAL, EPS);
private static final ScalarFieldFirstOrderDifferentiator SENS_CALC =
new ScalarFieldFirstOrderDifferentiator(FiniteDifferenceType.CENTRAL, EPS);
public void test_basics() {
assertEquals(EXTRAP.getName(), ProductLinearCurveExtrapolator.NAME);
assertEquals(EXTRAP.toString(), ProductLinearCurveExtrapolator.NAME);
}
public void test_extrapolation() {
BoundCurveInterpolator bind =
CurveInterpolators.DOUBLE_QUADRATIC.bind(X_DATA, Y_DATA, EXTRAP, EXTRAP);
double gradLeft =
(bind.interpolate(X_DATA.get(0) + EPS) * (X_DATA.get(0) + EPS) - Y_DATA.get(0) * X_DATA.get(0)) / EPS;
for (int i = 0; i < X_LEFT_TEST.size(); ++i) {
double xyLeft = gradLeft * (X_LEFT_TEST.get(i) - X_DATA.get(0)) + Y_DATA.get(0) * X_DATA.get(0);
double expected = xyLeft / X_LEFT_TEST.get(i);
assertEquals(bind.interpolate(X_LEFT_TEST.get(i)), expected, 10d * Math.abs(expected) * EPS);
}
double gradRight = (Y_DATA.get(SIZE - 1) * X_DATA.get(SIZE - 1) -
bind.interpolate(X_DATA.get(SIZE - 1) - EPS) * (X_DATA.get(SIZE - 1) - EPS)) / EPS;
for (int i = 0; i < X_RIGHT_TEST.size(); ++i) {
double xyRight = gradRight * (X_RIGHT_TEST.get(i) - X_DATA.get(SIZE - 1)) +
Y_DATA.get(SIZE - 1) * X_DATA.get(SIZE - 1);
double expected = xyRight / X_RIGHT_TEST.get(i);
assertEquals(bind.interpolate(X_RIGHT_TEST.get(i)), expected, 10d * Math.abs(expected) * EPS);
}
}
public void test_derivative_sensitivity() {
BoundCurveInterpolator bind =
CurveInterpolators.DOUBLE_QUADRATIC.bind(X_DATA, Y_DATA, EXTRAP, EXTRAP);
Function<Double, Double> derivFunc = x -> bind.interpolate(x);
for (int i = 0; i < X_LEFT_TEST.size(); ++i) {
assertEquals(bind.firstDerivative(X_LEFT_TEST.get(i)),
DIFF_CALC.differentiate(derivFunc).apply(X_LEFT_TEST.get(i)), EPS);
int index = i;
Function<DoubleArray, Double> sensFunc =
y -> CurveInterpolators.DOUBLE_QUADRATIC.bind(X_DATA, y, EXTRAP, EXTRAP).interpolate(X_LEFT_TEST.get(index));
assertTrue(DoubleArrayMath.fuzzyEquals(bind.parameterSensitivity(X_LEFT_TEST.get(index)).toArray(),
SENS_CALC.differentiate(sensFunc).apply(Y_DATA).toArray(), EPS));
}
for (int i = 0; i < X_RIGHT_TEST.size(); ++i) {
assertEquals(bind.firstDerivative(X_RIGHT_TEST.get(i)),
DIFF_CALC.differentiate(derivFunc).apply(X_RIGHT_TEST.get(i)), EPS);
int index = i;
Function<DoubleArray, Double> sensFunc =
y -> CurveInterpolators.DOUBLE_QUADRATIC.bind(X_DATA, y, EXTRAP, EXTRAP).interpolate(X_RIGHT_TEST.get(index));
assertTrue(DoubleArrayMath.fuzzyEquals(bind.parameterSensitivity(X_RIGHT_TEST.get(index)).toArray(),
SENS_CALC.differentiate(sensFunc).apply(Y_DATA).toArray(), EPS));
}
}
public void errorTest() {
DoubleArray xValues1 = DoubleArray.of(1, 2, 3);
DoubleArray xValues2 = DoubleArray.of(-3, -2, -1);
DoubleArray yValues = DoubleArray.of(1, 2, 3);
BoundCurveInterpolator bind1 =
CurveInterpolators.DOUBLE_QUADRATIC.bind(xValues1, yValues, EXTRAP, EXTRAP);
BoundCurveInterpolator bind2 =
CurveInterpolators.DOUBLE_QUADRATIC.bind(xValues2, yValues, EXTRAP, EXTRAP);
assertThrowsIllegalArg(() -> bind1.interpolate(-1));
assertThrowsIllegalArg(() -> bind1.firstDerivative(-1));
assertThrowsIllegalArg(() -> bind1.parameterSensitivity(-1));
assertThrowsIllegalArg(() -> bind2.interpolate(1));
assertThrowsIllegalArg(() -> bind2.firstDerivative(1));
assertThrowsIllegalArg(() -> bind2.parameterSensitivity(1));
}
public void test_serialization() {
assertSerialization(EXTRAP);
}
//-------------------------------------------------------------------------
public void sampleDataTest() {
DoubleArray xValues = DoubleArray.of(0.5, 1.0, 5.0, 10.0);
DoubleArray yValues = DoubleArray.of(0.02, 0.05, 0.015, 0.01);
DoubleArray rightKeys = DoubleArray.of(10.0, 12.0, 25.0, 35.0);
DoubleArray leftKeys = DoubleArray.of(0.5, 0.25, 0.12, 0.005);
BoundCurveInterpolator bind = CurveInterpolators.PRODUCT_NATURAL_SPLINE
.bind(xValues, yValues, CurveExtrapolators.FLAT, CurveExtrapolators.PRODUCT_LINEAR);
Function<Double, Double> fwdFunc = new Function<Double, Double>() {
@Override
public Double apply(Double x) {
return 0.5 * (bind.interpolate(x + EPS) * (x + EPS) - bind.interpolate(x - EPS) * (x - EPS)) / EPS;
}
};
for (int i = 1; i < 3; ++i) {
// constant forward
assertEquals(fwdFunc.apply(rightKeys.get(0)), fwdFunc.apply(rightKeys.get(i)), EPS);
// constant zero
assertEquals(bind.interpolate(leftKeys.get(0)), bind.interpolate(leftKeys.get(i)), EPS);
}
}
}