/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.math.interpolation; import org.apache.commons.lang.Validate; import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle; /** * Extrapolator based on a exponential function. Outside the data range the function is an exponential exp(m*x) where m is such that * - on the left: exp(m * data.firstKey()) = data.firstValue() * - on the right: exp(m * data.lastKey()) = data.lastValue() */ public class ExponentialExtrapolator1D extends Interpolator1D { private static final long serialVersionUID = 1L; @Override public Interpolator1DDataBundle getDataBundle(final double[] x, final double[] y) { throw new UnsupportedOperationException(); } @Override public Interpolator1DDataBundle getDataBundleFromSortedArrays(final double[] x, final double[] y) { throw new UnsupportedOperationException(); } @Override public Double interpolate(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); if (value < data.firstKey()) { return leftExtrapolate(data, value); } else if (value > data.lastKey()) { return rightExtrapolate(data, value); } throw new IllegalArgumentException("Value " + value + " was within data range"); } @Override public double firstDerivative(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); if (value < data.firstKey()) { return leftExtrapolateDerivative(data, value); } else if (value > data.lastKey()) { return rightExtrapolateDerivative(data, value); } throw new IllegalArgumentException("Value " + value + " was within data range"); } @Override public double[] getNodeSensitivitiesForValue(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); if (value < data.firstKey()) { return getLeftSensitivities(data, value); } else if (value > data.lastKey()) { return getRightSensitivities(data, value); } throw new IllegalArgumentException("Value " + value + " was within data range"); } private Double leftExtrapolate(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.firstKey(); final double y = data.firstValue(); final double m = Math.log(y) / x; return Math.exp(m * value); } private Double rightExtrapolate(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.lastKey(); final double y = data.lastValue(); final double m = Math.log(y) / x; return Math.exp(m * value); } private Double leftExtrapolateDerivative(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.firstKey(); final double y = data.firstValue(); final double m = Math.log(y) / x; return m * Math.exp(m * value); } private Double rightExtrapolateDerivative(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.lastKey(); final double y = data.lastValue(); final double m = Math.log(y) / x; return m * Math.exp(m * value); } private double[] getLeftSensitivities(final Interpolator1DDataBundle data, final double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.firstKey(); final double y = data.firstValue(); final double m = Math.log(y) / x; final double ex = Math.exp(m * value); final double[] result = new double[data.size()]; result[0] = ex * value / (x * y); return result; } private double[] getRightSensitivities(final Interpolator1DDataBundle data, final Double value) { Validate.notNull(data, "data"); Validate.notNull(value, "value"); final double x = data.lastKey(); final double y = data.lastValue(); final double m = Math.log(y) / x; final double ex = Math.exp(m * value); final double[] result = new double[data.size()]; result[data.size() - 1] = ex * value / (x * y); return result; } }