/**
* 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 com.opengamma.analytics.math.function.PiecewisePolynomialFunction1D;
import com.opengamma.analytics.math.interpolation.data.ArrayInterpolator1DDataBundle;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.util.ArgumentChecker;
/**
* Wrapping {@link ProductPiecewisePolynomialInterpolator}
*/
public class ProductPiecewisePolynomialInterpolator1D extends Interpolator1D {
private static final long serialVersionUID = 1L;
private static final PiecewisePolynomialFunction1D FUNC = new PiecewisePolynomialFunction1D();
private final ProductPiecewisePolynomialInterpolator _interp;
private static final double SMALL = 1e-14;
/**
* Construct {@link ProductPiecewisePolynomialInterpolator}
* @param baseInterpolator The base interpolator
*/
public ProductPiecewisePolynomialInterpolator1D(PiecewisePolynomialInterpolator baseInterpolator) {
_interp = new ProductPiecewisePolynomialInterpolator(baseInterpolator);
}
/**
* Construct {@link ProductPiecewisePolynomialInterpolator}
* @param baseInterpolator The base interpolator
* @param xValuesClamped X values of the clamped points
* @param yValuesClamped Y values of the clamped points
*/
public ProductPiecewisePolynomialInterpolator1D(PiecewisePolynomialInterpolator baseInterpolator,
double[] xValuesClamped, double[] yValuesClamped) {
_interp = new ProductPiecewisePolynomialInterpolator(baseInterpolator, xValuesClamped, yValuesClamped);
}
/**
* {@inheritDoc}
* For small Math.abs(value), this method returns the exact value if clamped at (0,0),
* otherwise this returns a reference value
*/
@Override
public Double interpolate(Interpolator1DDataBundle data, Double value) {
ArgumentChecker.notNull(value, "value");
ArgumentChecker.notNull(data, "data bundle");
ArgumentChecker.isTrue(data instanceof Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle,
"data should be instance of Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle");
Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle polyData = (Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle) data;
return interpolate(polyData, value, FUNC, SMALL);
}
/**
* {@inheritDoc}
* For small Math.abs(value), this method returns the exact value if clamped at (0,0),
* otherwise this returns a reference value
*/
@Override
public double firstDerivative(final Interpolator1DDataBundle data, final Double value) {
ArgumentChecker.notNull(value, "value");
ArgumentChecker.notNull(data, "data bundle");
ArgumentChecker.isTrue(data instanceof Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle,
"data should be instance of Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle");
Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle polyData = (Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle) data;
return firstDerivative(polyData, value, FUNC, SMALL);
}
/**
* {@inheritDoc}
* For small Math.abs(value), this method returns the exact value if clamped at (0,0),
* otherwise this returns a reference value
*/
@Override
public double[] getNodeSensitivitiesForValue(final Interpolator1DDataBundle data, final Double value) {
ArgumentChecker.notNull(value, "value");
ArgumentChecker.notNull(data, "data bundle");
ArgumentChecker.isTrue(data instanceof Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle,
"data should be instance of Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle");
Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle polyData = (Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle) data;
return getNodeSensitivitiesForValue(polyData, value, FUNC, SMALL);
}
/**
* Compute interpolation for product piecewise polynomials
* @param data Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle
* @param value The key value
* @param function The piecewise polynomial function
* @param small Threshold around the origin
* @return The interpolation
*/
Double interpolate(Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle data, Double value,
PiecewisePolynomialFunction1D function, double small) {
if (Math.abs(value) < small) {
return function.differentiate(data.getPiecewisePolynomialResult(), value).getEntry(0);
}
DoubleMatrix1D res = function.evaluate(data.getPiecewisePolynomialResult(), value);
return res.getEntry(0) / value;
}
/**
* Compute first derivative value for product piecewise polynomials
* @param data Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle
* @param value The key value
* @param function The piecewise polynomial function
* @param small Threshold around the origin
* @return The first derivative value
*/
double firstDerivative(Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle data, Double value,
PiecewisePolynomialFunction1D function, double small) {
if (Math.abs(value) < small) {
return 0.5 * function.differentiateTwice(data.getPiecewisePolynomialResult(), value).getEntry(0);
}
DoubleMatrix1D resValue = function.evaluate(data.getPiecewisePolynomialResult(), value);
DoubleMatrix1D resDerivative = function.differentiate(data.getPiecewisePolynomialResult(), value);
return resDerivative.getEntry(0) / value - resValue.getEntry(0) / value / value;
}
/**
* Compute node sensitivities for product piecewise polynomials
* @param data Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle
* @param value The key value
* @param function The piecewise polynomial function
* @param small Threshold around the origin
* @return The node sensitivities
*/
double[] getNodeSensitivitiesForValue(Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle data, Double value,
PiecewisePolynomialFunction1D function, double small) {
int nData = data.size();
double[] res = new double[nData];
double eps = data.getEps();
double smallDiff = data.getSmall();
if (Math.abs(value) < small) {
for (int i = 0; i < nData; ++i) {
double den = Math.abs(data.getValues()[i]) < smallDiff ? eps : data.getValues()[i] * eps;
double up = function.differentiate(data.getPiecewisePolynomialResultUp()[i], value).getData()[0];
double dw = function.differentiate(data.getPiecewisePolynomialResultDw()[i], value).getData()[0];
res[i] = 0.5 * (up - dw) / den;
}
} else {
for (int i = 0; i < nData; ++i) {
double den = Math.abs(data.getValues()[i]) < smallDiff ? eps : data.getValues()[i] * eps;
double up = function.evaluate(data.getPiecewisePolynomialResultUp()[i], value).getData()[0];
double dw = function.evaluate(data.getPiecewisePolynomialResultDw()[i], value).getData()[0];
res[i] = 0.5 * (up - dw) / den / value;
}
}
return res;
}
@Override
protected double[] getFiniteDifferenceSensitivities(final Interpolator1DDataBundle data, final Double value) {
throw new IllegalArgumentException("Use the method, getNodeSensitivitiesForValue");
}
@Override
public Interpolator1DDataBundle getDataBundle(final double[] x, final double[] y) {
return new Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle(new ArrayInterpolator1DDataBundle(x, y, false),
_interp);
}
@Override
public Interpolator1DDataBundle getDataBundleFromSortedArrays(final double[] x, final double[] y) {
return new Interpolator1DPiecewisePoynomialWithExtraKnotsDataBundle(new ArrayInterpolator1DDataBundle(x, y, true),
_interp);
}
}