/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.math.impl.interpolation; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; import com.opengamma.strata.collect.array.DoubleMatrix; import com.opengamma.strata.math.impl.function.PiecewisePolynomialFunction1D; /** * Test. */ @Test public class NonnegativityPreservingCubicSplineInterpolatorTest { private static final double EPS = 1e-14; private static final double INF = 1. / 0.; /** * */ public void positivityClampedTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5. }; final double[] yValues = new double[] {0., 0.1, 1., 1., 20., 5., 0. }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialResult result = interp.interpolate(xValues, yValues); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); assertEquals(resultPos.getDimensions(), result.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), result.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), result.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 4. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); } final int nData = xValues.length; for (int i = 1; i < nData - 2; ++i) { final double tau = Math.signum(resultPos.getCoefMatrix().get(i, 3)); assertTrue(resultPos.getCoefMatrix().get(i, 2) * tau >= -3. * yValues[i + 1] * tau / (xValues[i + 1] - xValues[i])); assertTrue(resultPos.getCoefMatrix().get(i, 2) * tau <= 3. * yValues[i + 1] * tau / (xValues[i] - xValues[i - 1])); } } /** * */ public void positivityClampedMultiTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5. }; final double[][] yValues = new double[][] { {0., 0.1, 1., 1., 20., 5., 0. }, {-10., 0.1, 1., 1., 20., 5., 0. } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialResult result = interp.interpolate(xValues, yValues); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); assertEquals(resultPos.getDimensions(), result.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), result.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), result.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 4. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); } int dim = yValues.length; int nData = xValues.length; for (int j = 0; j < dim; ++j) { for (int i = 1; i < nData - 2; ++i) { DoubleMatrix coefMatrix = resultPos.getCoefMatrix(); double tau = Math.signum(coefMatrix.get(dim * i + j, 3)); assertTrue(coefMatrix.get(dim * i + j, 2) * tau >= -3. * yValues[j][i + 1] * tau / (xValues[i + 1] - xValues[i])); assertTrue(coefMatrix.get(dim * i + j, 2) * tau <= 3. * yValues[j][i + 1] * tau / (xValues[i] - xValues[i - 1])); } } } /** * */ public void positivityNotAKnotTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5. }; final double[] yValues = new double[] {0.1, 1., 1., 20., 5. }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialResult result = interp.interpolate(xValues, yValues); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); assertEquals(resultPos.getDimensions(), result.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), result.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), result.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 4. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); } final int nData = xValues.length; for (int i = 1; i < nData - 2; ++i) { final double tau = Math.signum(resultPos.getCoefMatrix().get(i, 3)); assertTrue(resultPos.getCoefMatrix().get(i, 2) * tau >= -3. * yValues[i] * tau / (xValues[i + 1] - xValues[i])); assertTrue(resultPos.getCoefMatrix().get(i, 2) * tau <= 3. * yValues[i] * tau / (xValues[i] - xValues[i - 1])); } } /** * */ public void positivityEndIntervalsTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5., 6. }; final double[][] yValues = new double[][] { {0.01, 0.01, 0.01, 10., 20., 1. }, {0.01, 0.01, 10., 10., 0.01, 0.01 } }; PiecewisePolynomialInterpolator interp = new NaturalSplineInterpolator(); PiecewisePolynomialResult result = interp.interpolate(xValues, yValues); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); assertEquals(resultPos.getDimensions(), result.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), result.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), result.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 5. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); } int dim = yValues.length; int nData = xValues.length; for (int j = 0; j < dim; ++j) { for (int i = 1; i < nData - 2; ++i) { DoubleMatrix coefMatrix = resultPos.getCoefMatrix(); double tau = Math.signum(coefMatrix.get(dim * i + j, 3)); assertTrue(coefMatrix.get(dim * i + j, 2) * tau >= -3. * yValues[j][i] * tau / (xValues[i + 1] - xValues[i])); assertTrue(coefMatrix.get(dim * i + j, 2) * tau <= 3. * yValues[j][i] * tau / (xValues[i] - xValues[i - 1])); } } } /** * PiecewiseCubicHermiteSplineInterpolator is not modified for positive data */ public void noModificationTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5. }; final double[][] yValues = new double[][] { {0.1, 1., 1., 20., 5. }, {1., 2., 3., 0., 0. } }; PiecewisePolynomialInterpolator interp = new PiecewiseCubicHermiteSplineInterpolator(); PiecewisePolynomialResult result = interp.interpolate(xValues, yValues); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); assertEquals(resultPos.getDimensions(), result.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), result.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), result.getOrder()); for (int i = 1; i < xValues.length - 1; ++i) { for (int j = 0; j < 4; ++j) { final double ref = result.getCoefMatrix().get(i, j) == 0. ? 1. : Math.abs(result.getCoefMatrix().get(i, j)); assertEquals(resultPos.getCoefMatrix().get(i, j), result.getCoefMatrix().get(i, j), ref * EPS); } } } /** * */ public void flipTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5., 6. }; final double[] yValues = new double[] {3., 0.1, 0.01, 0.01, 0.1, 3. }; final double[] xValuesFlip = new double[] {6., 2., 3., 5., 4., 1. }; final double[] yValuesFlip = new double[] {3., 0.1, 0.01, 0.1, 0.01, 3. }; PiecewisePolynomialInterpolator interp = new NaturalSplineInterpolator(); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); PiecewisePolynomialResult resultPosFlip = interpPos.interpolate(xValuesFlip, yValuesFlip); assertEquals(resultPos.getDimensions(), resultPosFlip.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), resultPosFlip.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), resultPosFlip.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 5. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); } final int nData = xValues.length; for (int i = 0; i < nData - 1; ++i) { for (int k = 0; k < 4; ++k) assertEquals(resultPos.getCoefMatrix().get(i, k), resultPosFlip.getCoefMatrix().get(i, k)); } } /** * */ public void flipMultiTest() { final double[] xValues = new double[] {1., 2., 3., 4., 5., 6. }; final double[][] yValues = new double[][] { {3., 0.1, 0.01, 0.01, 0.1, 3. }, {3., 0.1, 0.01, 0.001, 2., 3. } }; final double[] xValuesFlip = new double[] {1., 2., 3., 5., 4., 6. }; final double[][] yValuesFlip = new double[][] { {3., 0.1, 0.01, 0.1, 0.01, 3. }, {3., 0.1, 0.01, 2., 0.001, 3. } }; PiecewisePolynomialInterpolator interp = new NaturalSplineInterpolator(); PiecewisePolynomialFunction1D function = new PiecewisePolynomialFunction1D(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); PiecewisePolynomialResult resultPos = interpPos.interpolate(xValues, yValues); PiecewisePolynomialResult resultPosFlip = interpPos.interpolate(xValuesFlip, yValuesFlip); assertEquals(resultPos.getDimensions(), resultPosFlip.getDimensions()); assertEquals(resultPos.getNumberOfIntervals(), resultPosFlip.getNumberOfIntervals()); assertEquals(resultPos.getOrder(), resultPosFlip.getOrder()); final int nPts = 101; for (int i = 0; i < 101; ++i) { final double key = 1. + 5. / (nPts - 1) * i; assertTrue(function.evaluate(resultPos, key).get(0) >= 0.); assertTrue(function.evaluate(resultPos, key).get(1) >= 0.); } int dim = yValues.length; int nData = xValues.length; for (int j = 0; j < dim; ++j) { for (int i = 0; i < nData - 1; ++i) { for (int k = 0; k < 4; ++k) assertEquals(resultPos.getCoefMatrix().get(dim * i + j, k), resultPosFlip.getCoefMatrix().get(dim * i + j, k)); } } } /* * Error tests */ /** * Primary interpolation method should be cubic. * Note that CubicSplineInterpolator returns a linear or quadratic function in certain situations */ @Test(expectedExceptions = IllegalArgumentException.class) public void lowDegreeTest() { final double[] xValues = new double[] {1., 2., 3. }; final double[] yValues = new double[] {0., 0.1, 0.05 }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void lowDegreeMultiTest() { final double[] xValues = new double[] {1., 2., 3. }; final double[][] yValues = new double[][] { {0., 0.1, 0.05 }, {0., 0.1, 1.05 } }; PiecewisePolynomialInterpolator interp = new LinearInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void dataShortTest() { final double[] xValues = new double[] {1., 2. }; final double[] yValues = new double[] {0., 0.1 }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void dataShortMultiTest() { final double[] xValues = new double[] {1., 2., }; final double[][] yValues = new double[][] { {0., 0.1 }, {0., 0.1 } }; PiecewisePolynomialInterpolator interp = new PiecewiseCubicHermiteSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void coincideDataTest() { final double[] xValues = new double[] {1., 1., 3. }; final double[] yValues = new double[] {0., 0.1, 0.05 }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void coincideDataMultiTest() { final double[] xValues = new double[] {1., 2., 2. }; final double[][] yValues = new double[][] { {2., 0., 0.1, 0.05, 2. }, {1., 0., 0.1, 1.05, 2. } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void diffDataTest() { final double[] xValues = new double[] {1., 2., 3., 4. }; final double[] yValues = new double[] {0., 0.1, 0.05 }; PiecewisePolynomialInterpolator interp = new NaturalSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void diffDataMultiTest() { final double[] xValues = new double[] {1., 2., 3., 4. }; final double[][] yValues = new double[][] { {2., 0., 0.1, 0.05, 2. }, {1., 0., 0.1, 1.05, 2. } }; PiecewisePolynomialInterpolator interp = new NaturalSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nullXdataTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[] yValues = new double[] {0., 0.1, 0.05, 0.2 }; xValues = null; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nullYdataTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[] yValues = new double[] {0., 0.1, 0.05, 0.2 }; yValues = null; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nullXdataMultiTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[][] yValues = new double[][] { {0., 0.1, 0.05, 0.2 }, {0., 0.1, 0.05, 0.2 } }; xValues = null; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nullYdataMultiTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[][] yValues = new double[][] { {0., 0.1, 0.05, 0.2 }, {0., 0.1, 0.05, 0.2 } }; yValues = null; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void infXdataTest() { double[] xValues = new double[] {1., 2., 3., INF }; double[] yValues = new double[] {0., 0.1, 0.05, 0.2 }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void infYdataTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[] yValues = new double[] {0., 0., 0.1, 0.05, 0.2, INF }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nanXdataTest() { double[] xValues = new double[] {1., 2., 3., Double.NaN }; double[] yValues = new double[] {0., 0.1, 0.05, 0.2 }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nanYdataTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[] yValues = new double[] {0., 0., 0.1, 0.05, 0.2, Double.NaN }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void infXdataMultiTest() { double[] xValues = new double[] {1., 2., 3., INF }; double[][] yValues = new double[][] { {0., 0.1, 0.05, 0.2 }, {0., 0.1, 0.05, 0.2 } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void infYdataMultiTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[][] yValues = new double[][] { {0., 0., 0.1, 0.05, 0.2, 1. }, {0., 0., 0.1, 0.05, 0.2, INF } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nanXdataMultiTest() { double[] xValues = new double[] {1., 2., 3., Double.NaN }; double[][] yValues = new double[][] { {0., 0.1, 0.05, 0.2 }, {0., 0.1, 0.05, 0.2 } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void nanYdataMultiTest() { double[] xValues = new double[] {1., 2., 3., 4. }; double[][] yValues = new double[][] { {0., 0., 0.1, 0.05, 0.2, 1.1 }, {0., 0., 0.1, 0.05, 0.2, Double.NaN } }; PiecewisePolynomialInterpolator interp = new CubicSplineInterpolator(); PiecewisePolynomialInterpolator interpPos = new NonnegativityPreservingCubicSplineInterpolator(interp); interpPos.interpolate(xValues, yValues); } }