/** * 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 that is designed for extrapolating a discount factor where the * trivial point (0,1) is NOT involved in the data. * The extrapolation is completed by applying a quadratic extrapolant on the discount * factor (not log of the discount factor), where the point (0,1) is inserted and * the first derivative value is assumed to be continuous at the first x-value. */ final class QuadraticLeftCurveExtrapolator implements CurveExtrapolator, Serializable { /** * The serialization version id. */ private static final long serialVersionUID = 1L; /** * The extrapolator name. */ public static final String NAME = "QuadraticLeft"; /** * The extrapolator instance. */ public static final CurveExtrapolator INSTANCE = new QuadraticLeftCurveExtrapolator(); /** * The epsilon value. */ private static final double EPS = 1e-8; /** * Restricted constructor. */ private QuadraticLeftCurveExtrapolator() { } // 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 eps; private final double leftQuadCoef; private final double leftLinCoef; private final DoubleArray leftSens; 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); double gradient = interpolator.firstDerivative(firstXValue); this.eps = EPS * (lastXValue - firstXValue); this.leftQuadCoef = gradient / firstXValue - (firstYValue - 1d) / firstXValue / firstXValue; this.leftLinCoef = -gradient + 2d * (firstYValue - 1d) / firstXValue; this.leftSens = interpolator.parameterSensitivity(firstXValue + eps); } //------------------------------------------------------------------------- @Override public double leftExtrapolate(double xValue) { if (firstXValue == 0d) { throw new IllegalArgumentException("The trivial point at x = 0 is already included"); } return leftQuadCoef * xValue * xValue + leftLinCoef * xValue + 1d; } @Override public double leftExtrapolateFirstDerivative(double xValue) { if (firstXValue == 0d) { throw new IllegalArgumentException("The trivial point at x = 0 is already included"); } return 2d * leftQuadCoef * xValue + leftLinCoef; } @Override public DoubleArray leftExtrapolateParameterSensitivity(double xValue) { if (firstXValue == 0d) { throw new IllegalArgumentException("The trivial point at x = 0 is already included"); } double[] result = leftSens.toArray(); for (int i = 1; i < nodeCount; i++) { double tmp = result[i] * xValue / eps; result[i] = tmp / firstXValue * xValue - tmp; } double tmp = (result[0] - 1d) / eps; result[0] = (tmp / firstXValue - 1d / firstXValue / firstXValue) * xValue * xValue + (2d / firstXValue - tmp) * xValue; return DoubleArray.ofUnsafe(result); } //------------------------------------------------------------------------- @Override public double rightExtrapolate(double xValue) { throw new IllegalArgumentException("QuadraticLeft extrapolator cannot be used for right extrapolation"); } @Override public double rightExtrapolateFirstDerivative(double xValue) { throw new IllegalArgumentException("QuadraticLeft extrapolator cannot be used for right extrapolation"); } @Override public DoubleArray rightExtrapolateParameterSensitivity(double xValue) { throw new IllegalArgumentException("QuadraticLeft extrapolator cannot be used for right extrapolation"); } } }