/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.market.curve.interpolator; import java.io.Serializable; import com.opengamma.strata.collect.array.DoubleArray; /** * Extrapolator implementation based on a exponential function. * <p> * Outside the data range the function is * an exponential exp(m*x) where m is such that: * - on the left: exp(m * firstXValue) = firstYValue * - on the right: exp(m * lastXValue) = lastYValue */ final class ExponentialCurveExtrapolator implements CurveExtrapolator, Serializable { /** * The serialization version id. */ private static final long serialVersionUID = 1L; /** * The extrapolator name. */ public static final String NAME = "Exponential"; /** * The extrapolator instance. */ public static final CurveExtrapolator INSTANCE = new ExponentialCurveExtrapolator(); /** * Restricted constructor. */ private ExponentialCurveExtrapolator() { } // resolve instance private Object readResolve() { return INSTANCE; } //------------------------------------------------------------------------- @Override public String getName() { return NAME; } @Override public BoundCurveExtrapolator bind(DoubleArray xValues, DoubleArray yValues, BoundCurveInterpolator interpolator) { return new Bound(xValues, yValues, interpolator); } //------------------------------------------------------------------------- @Override public String toString() { return NAME; } //------------------------------------------------------------------------- /** * Bound extrapolator. */ static class Bound implements BoundCurveExtrapolator { private final int nodeCount; private final double firstXValue; private final double firstYValue; private final double lastXValue; private final double lastYValue; private final double leftGradient; private final double rightGradient; Bound(DoubleArray xValues, DoubleArray yValues, BoundCurveInterpolator interpolator) { this.nodeCount = xValues.size(); this.firstXValue = xValues.get(0); this.firstYValue = yValues.get(0); this.lastXValue = xValues.get(nodeCount - 1); this.lastYValue = yValues.get(nodeCount - 1); // left this.leftGradient = Math.log(firstYValue) / firstXValue; // right this.rightGradient = Math.log(lastYValue) / lastXValue; } //------------------------------------------------------------------------- @Override public double leftExtrapolate(double xValue) { return Math.exp(leftGradient * xValue); } @Override public double leftExtrapolateFirstDerivative(double xValue) { return leftGradient * Math.exp(leftGradient * xValue); } @Override public DoubleArray leftExtrapolateParameterSensitivity(double xValue) { double ex = Math.exp(leftGradient * xValue); double[] result = new double[nodeCount]; result[0] = ex * xValue / (firstXValue * firstYValue); return DoubleArray.ofUnsafe(result); } //------------------------------------------------------------------------- @Override public double rightExtrapolate(double xValue) { return Math.exp(rightGradient * xValue); } @Override public double rightExtrapolateFirstDerivative(double xValue) { return rightGradient * Math.exp(rightGradient * xValue); } @Override public DoubleArray rightExtrapolateParameterSensitivity(double xValue) { double ex = Math.exp(rightGradient * xValue); double[] result = new double[nodeCount]; result[nodeCount - 1] = ex * xValue / (lastXValue * lastYValue); return DoubleArray.ofUnsafe(result); } } }