/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.interpolation;
import java.util.Arrays;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.math.interpolation.data.ArrayInterpolator1DDataBundle;
import com.opengamma.analytics.math.interpolation.data.InterpolationBoundedValues;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.util.ArgumentChecker;
/**
* Two points are interpolated by an exponential function y = a * exp( b * x ), where a, b are real constants.
* Note that all of y data should have the same sign.
*/
public class ExponentialInterpolator1D extends Interpolator1D {
private static final long serialVersionUID = 1L;
@Override
public Double interpolate(final Interpolator1DDataBundle data, final Double value) {
Validate.notNull(value, "value");
Validate.notNull(data, "data bundle");
InterpolationBoundedValues boundedValues = data.getBoundedValues(value);
Double x1 = boundedValues.getLowerBoundKey();
Double y1 = boundedValues.getLowerBoundValue();
if (boundedValues.getLowerBoundIndex() == data.size() - 1) {
return y1;
}
Double x2 = boundedValues.getHigherBoundKey();
Double y2 = boundedValues.getHigherBoundValue();
return Math.pow(y2 / y1, (value - x1) / (x2 - x1)) * y1;
}
@Override
public double firstDerivative(final Interpolator1DDataBundle data, final Double value) {
Validate.notNull(value, "value");
Validate.notNull(data, "data bundle");
int lowerIndex = data.getLowerBoundIndex(value);
if (lowerIndex == data.size() - 1) {
--lowerIndex;
}
Double x1 = data.getKeys()[lowerIndex];
Double y1 = data.getValues()[lowerIndex];
Double x2 = data.getKeys()[lowerIndex + 1];
Double y2 = data.getValues()[lowerIndex + 1];
double xDiffInv = 1.0 / (x2 - x1);
double y2ovy1 = y2 / y1;
return Math.pow(y2ovy1, (value - x1) * xDiffInv) * y1 * xDiffInv * Math.log(y2ovy1);
}
@Override
public Interpolator1DDataBundle getDataBundle(final double[] x, final double[] y) {
int nValues = y.length;
for (int i = 1; i < nValues; ++i) {
ArgumentChecker.isTrue(y[i - 1] * y[i] > 0, "All y values should have the same sign");
}
return new ArrayInterpolator1DDataBundle(x, y);
}
@Override
public Interpolator1DDataBundle getDataBundleFromSortedArrays(final double[] x, final double[] y) {
int nValues = y.length;
for (int i = 1; i < nValues; ++i) {
ArgumentChecker.isTrue(y[i - 1] * y[i] > 0, "All y values should have the same sign");
}
return new ArrayInterpolator1DDataBundle(x, y, true);
}
@Override
public double[] getNodeSensitivitiesForValue(Interpolator1DDataBundle data, Double value) {
int size = data.size();
double[] res = new double[size];
Arrays.fill(res, 0.0);
int lowerIndex = data.getLowerBoundIndex(value);
if (lowerIndex == size - 1) {
res[size - 1] = 1.0;
return res;
}
Double x1 = data.getKeys()[lowerIndex];
Double y1 = data.getValues()[lowerIndex];
Double x2 = data.getKeys()[lowerIndex + 1];
Double y2 = data.getValues()[lowerIndex + 1];
double diffInv = 1.0 / (x2 - x1);
double x1diffInv = (value - x1) * diffInv;
double x2diffInv = (x2 - value) * diffInv;
double y1ovy2 = y1 / y2;
res[lowerIndex] = Math.pow(y1ovy2, -x1diffInv) * x2diffInv;
res[lowerIndex + 1] = Math.pow(y1ovy2, x2diffInv) * x1diffInv;
return res;
}
}