All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.finmath.marketdata2.model.curves.CurveInterpolation Maven / Gradle / Ivy

/*
 * (c) Copyright Christian P. Fries, Germany. Contact: [email protected].
 *
 * Created on 20.05.2005
 */
package net.finmath.marketdata2.model.curves;

import java.io.IOException;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import net.finmath.marketdata2.interpolation.RationalFunctionInterpolation;
import net.finmath.marketdata2.model.AnalyticModel;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.FloatingpointDate;

/**
 * This class represents a curveFromInterpolationPoints build from a set of points in 2D.
 *
 * It provides different interpolation and extrapolation methods applied to a transformation of the input point,
 * examples are
 * 
    *
  • linear interpolation of the input points
  • *
  • linear interpolation of the log of the input points
  • *
  • linear interpolation of the log of the input points divided by their respective time
  • *
  • cubic spline interpolation of the input points (or a function of the input points) (the curveFromInterpolationPoints will be C1).
  • *
  • Akima interpolation of the input points (or a function of the input points).
  • *
  • etc.
  • *
* *
* * For the interpolation methods provided see {@link net.finmath.marketdata.model.curves.CurveInterpolation.InterpolationMethod}. * For the extrapolation methods provided see {@link net.finmath.marketdata.model.curves.CurveInterpolation.ExtrapolationMethod}. * For the possible interpolation entities see {@link net.finmath.marketdata.model.curves.CurveInterpolation.InterpolationEntity}. * * To construct the curveFromInterpolationPoints, please use the inner class CurveBuilder (a builder pattern). * * For a demo on how to construct and/or calibrate a curveFromInterpolationPoints see, e.g. * net.finmath.tests.marketdata.curves.CurveTest. * * @author Christian Fries * @version 1.0 */ public class CurveInterpolation extends AbstractCurve implements Serializable, Cloneable { /** * Possible interpolation methods. * * @author Christian Fries */ public enum InterpolationMethod { /** Constant interpolation. Synonym of PIECEWISE_CONSTANT_LEFTPOINT. **/ PIECEWISE_CONSTANT, /** Constant interpolation. Right continuous, i.e. using the value of the left end point of the interval. **/ PIECEWISE_CONSTANT_LEFTPOINT, /** Constant interpolation using the value of the right end point of the interval. **/ PIECEWISE_CONSTANT_RIGHTPOINT, /** Linear interpolation. **/ LINEAR, // /** Cubic spline interpolation. **/ // CUBIC_SPLINE, // /** Akima interpolation (C1 sub-spline interpolation). **/ // AKIMA, // /** Akima interpolation (C1 sub-spline interpolation) with a smoothing in the weights. **/ // AKIMA_CONTINUOUS, /** Harmonic spline interpolation (C1 sub-spline interpolation). **/ HARMONIC_SPLINE, /** Harmonic spline interpolation (C1 sub-spline interpolation) with a monotonic filtering at the boundary points. **/ HARMONIC_SPLINE_WITH_MONOTONIC_FILTERING } /** * Possible extrapolation methods. * * @author Christian Fries */ public enum ExtrapolationMethod { /** Extrapolation using the interpolation function of the adjacent interval **/ DEFAULT, /** Constant extrapolation. **/ CONSTANT, /** Linear extrapolation. **/ LINEAR } /** * Possible interpolation entities. * @author Christian Fries */ public enum InterpolationEntity { /** Interpolation is performed on the native point values, i.e. value(t) **/ VALUE, /** Interpolation is performed on the log of the point values, i.e. log(value(t)) **/ LOG_OF_VALUE, /** Interpolation is performed on the log of the point values divided by their respective time, i.e. log(value(t))/t **/ LOG_OF_VALUE_PER_TIME } private static class Point implements Comparable, Serializable { private static final long serialVersionUID = 8857387999991917430L; private final double time; private RandomVariable value; private final boolean isParameter; /** * @param time The time (or x-value) of the point. * @param value The value (or y-value) of the point. * @param isParameter A boolean specifying if this point is considered a "degree of freedom", e.g., in a calibration. */ Point(final double time, final RandomVariable value, final boolean isParameter) { super(); this.time = time; this.value = value; this.isParameter = isParameter; } @Override public int compareTo(final Point point) { // Ordering of the curveFromInterpolationPoints points with respect to time. if(time < point.time) { return -1; } if(time > point.time) { return +1; } return 0; } @Override public Object clone() { return new Point(time,value,isParameter); } } /** * A builder (following the builder pattern) for CurveFromInterpolationPoints objects. * Allows to successively construct a curveFromInterpolationPoints object by adding points. * * @author Christian Fries */ public static class Builder implements CurveBuilder { private CurveInterpolation curveInterpolation = null; /** * Build a curveFromInterpolationPoints. */ public Builder() { curveInterpolation = new CurveInterpolation(null, null); } /** * Build a curveFromInterpolationPoints with a given name and given reference date. * * @param name The name of this curveFromInterpolationPoints. * @param referenceDate The reference date for this curveFromInterpolationPoints, i.e., the date which defined t=0. */ public Builder(final String name, final LocalDate referenceDate) { curveInterpolation = new CurveInterpolation(name, referenceDate); } /** * Build a curveFromInterpolationPoints by cloning a given curveFromInterpolationPoints. * * @param curveInterpolation A curveFromInterpolationPoints to be used as starting point for the new curveFromInterpolationPoints. * @throws CloneNotSupportedException Thrown, when the curveFromInterpolationPoints could not be cloned. */ public Builder(final CurveInterpolation curveInterpolation) throws CloneNotSupportedException { this.curveInterpolation = curveInterpolation.clone(); } /* (non-Javadoc) * @see net.finmath.marketdata.model.curves.CurveBuilderInterface#build() */ @Override public Curve build() { final CurveInterpolation buildCurve = curveInterpolation; curveInterpolation = null; return buildCurve; } /** * Set the interpolation method of the curveFromInterpolationPoints. * * @param interpolationMethod The interpolation method of the curveFromInterpolationPoints. * @return A self reference to this curveFromInterpolationPoints build object. */ public CurveBuilder setInterpolationMethod(final InterpolationMethod interpolationMethod) { curveInterpolation.interpolationMethod = interpolationMethod; return this; } /** * Set the extrapolation method of the curveFromInterpolationPoints. * * @param extrapolationMethod The extrapolation method of the curveFromInterpolationPoints. * @return A self reference to this curveFromInterpolationPoints build object. */ public CurveBuilder setExtrapolationMethod(final ExtrapolationMethod extrapolationMethod) { curveInterpolation.extrapolationMethod = extrapolationMethod; return this; } /** * Set the interpolationEntity of the curveFromInterpolationPoints. * * @param interpolationEntity The interpolation entity of the curveFromInterpolationPoints. * @return A self reference to this curveFromInterpolationPoints build object. */ public CurveBuilder setInterpolationEntity(final InterpolationEntity interpolationEntity) { curveInterpolation.interpolationEntity = interpolationEntity; return this; } /* (non-Javadoc) * @see net.finmath.marketdata.model.curves.CurveBuilderInterface#addPoint(double, double, boolean) */ @Override public CurveBuilder addPoint(final double time, final RandomVariable value, final boolean isParameter) { curveInterpolation.addPoint(time, value, isParameter); return this; } } private ArrayList points = new ArrayList<>(); private ArrayList pointsBeingParameters = new ArrayList<>(); private InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR; //CUBIC_SPLINE; private ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.CONSTANT; private InterpolationEntity interpolationEntity = InterpolationEntity.LOG_OF_VALUE; private RationalFunctionInterpolation rationalFunctionInterpolation = null; private transient Object rationalFunctionInterpolationLazyInitLock = new Object(); private SoftReference> curveCacheReference = null; //private LIBORModelMonteCarloSimulationModel model; private static final long serialVersionUID = -4126228588123963885L; private static NumberFormat formatterReal = NumberFormat.getInstance(Locale.US); /** * Create a curveFromInterpolationPoints with a given name, reference date and an interpolation method from given points * * @param name The name of this curveFromInterpolationPoints. * @param referenceDate The reference date for this curveFromInterpolationPoints, i.e., the date which defined t=0. * @param interpolationMethod The interpolation method used for the curveFromInterpolationPoints. * @param extrapolationMethod The extrapolation method used for the curveFromInterpolationPoints. * @param interpolationEntity The entity interpolated/extrapolated. * @param times A vector of times. * @param values A vector of corresponding values. */ public CurveInterpolation(final String name, final LocalDate referenceDate, final InterpolationMethod interpolationMethod, final ExtrapolationMethod extrapolationMethod, final InterpolationEntity interpolationEntity, final double[] times, final RandomVariable[] values) { super(name, referenceDate); this.interpolationMethod = interpolationMethod; this.extrapolationMethod = extrapolationMethod; this.interpolationEntity = interpolationEntity; if(times.length != values.length) { throw new IllegalArgumentException("Length of times not equal to length of values."); } for(int i=0; i curveCache = curveCacheReference != null ? curveCacheReference.get() : null; if(curveCache == null) { curveCache = new ConcurrentHashMap<>(); curveCacheReference = new SoftReference<>(curveCache); } final RandomVariable valueFromCache = curveCache.get(time); if(valueFromCache != null) { return valueFromCache; } final RandomVariable value = valueFromInterpolationEntity(getInterpolationEntityValue(time), time); curveCache.put(time, value); return value; } private RandomVariable getInterpolationEntityValue(final double time) { synchronized(rationalFunctionInterpolationLazyInitLock) { // Lazy initialization of interpolation function if(rationalFunctionInterpolation == null) { final double[] pointsArray = new double[points.size()];//time final RandomVariable[] valuesArray = new RandomVariable[points.size()]; for(int i=0; ii in i = f(xi). * @param value The yi in i = f(xi). * @param isParameter If true, then this point is served via {@link #getParameter()} and changed via {@link #getCloneForParameter(RandomVariable[])}, i.e., it can be calibrated. */ protected void addPoint(final double time, final RandomVariable value, final boolean isParameter) { synchronized (rationalFunctionInterpolationLazyInitLock) { if(interpolationEntity == InterpolationEntity.LOG_OF_VALUE_PER_TIME && time == 0) { boolean containsOne = false; int index=0; for(int i = 0; i< value.size(); i++){if(value.get(i)==1.0) {containsOne = true; index=i; break;}} if(containsOne && isParameter == false) { return; } else { throw new IllegalArgumentException("The interpolation method LOG_OF_VALUE_PER_TIME does not allow to add a value at time = 0 other than 1.0 (received 1 at index" + index + ")."); } } final RandomVariable interpolationEntityValue = interpolationEntityFromValue(value, time); final int index = getTimeIndex(time); if(index >= 0) { if(points.get(index).value == interpolationEntityValue) { return; // Already in list } else if(isParameter) { return; } else { throw new RuntimeException("Trying to add a value for a time for which another value already exists."); } } else { // Insert the new point, retain ordering. final Point point = new Point(time, interpolationEntityValue, isParameter); points.add(-index-1, point); if(isParameter) { // Add this point also to the list of parameters final int parameterIndex = getParameterIndex(time); if(parameterIndex >= 0) { new RuntimeException("CurveFromInterpolationPoints inconsistent."); } pointsBeingParameters.add(-parameterIndex-1, point); } } rationalFunctionInterpolation = null; curveCacheReference = null; } } /** * Returns the interpolation method used by this curveFromInterpolationPoints. * * @return The interpolation method used by this curveFromInterpolationPoints. */ public InterpolationMethod getInterpolationMethod() { return interpolationMethod; } /** * Returns the extrapolation method used by this curveFromInterpolationPoints. * * @return The extrapolation method used by this curveFromInterpolationPoints. */ public ExtrapolationMethod getExtrapolationMethod() { return extrapolationMethod; } /** * Returns the interpolation entity used by this curveFromInterpolationPoints. * * @return The interpolation entity used by this curveFromInterpolationPoints. */ public InterpolationEntity getInterpolationEntity() { return interpolationEntity; } protected int getTimeIndex(final double time) { final Point point = new Point(time, new RandomVariableFromDoubleArray(Double.NaN), false); final int index = java.util.Collections.binarySearch(points, point); return index; } protected int getParameterIndex(final double time) { final Point point = new Point(time, new RandomVariableFromDoubleArray(Double.NaN), false); return java.util.Collections.binarySearch(pointsBeingParameters, point); } @Override public RandomVariable[] getParameter() { final RandomVariable[] parameters = new RandomVariable[pointsBeingParameters.size()]; for(int i=0; i(); newCurve.pointsBeingParameters = new ArrayList<>(); newCurve.rationalFunctionInterpolation = null; newCurve.curveCacheReference = null; for(final Point point : points) { final Point newPoint = (Point) point.clone(); newCurve.points.add(newPoint); if(point.isParameter) { newCurve.pointsBeingParameters.add(newPoint); } } return newCurve; } @Override public Curve getCloneForParameter(final RandomVariable[] parameter) throws CloneNotSupportedException { if(Arrays.equals(parameter, getParameter())) { return this; } final CurveInterpolation newCurve = this.clone(); newCurve.setParameterPrivate(parameter); return newCurve; } @Override public CurveBuilder getCloneBuilder() throws CloneNotSupportedException { final Builder builder = new Builder(this); return builder; } @Override public String toString() { /* * Pretty print curveFromInterpolationPoints (appended to standard toString) */ final StringBuilder curveTableString = new StringBuilder(); final NumberFormat formatTime = new DecimalFormat("0.00000000E0"); // Floating point time is accurate to 3+5 digits. for (final Point point : points) { curveTableString.append(formatTime.format(point.time) + "\t"); curveTableString.append(FloatingpointDate.getDateFromFloatingPointDate(getReferenceDate(), point.time) + "\t"); curveTableString.append(valueFromInterpolationEntity(point.value, point.time) + "\n"); } return "CurveFromInterpolationPoints [points=" + points + ", pointsBeingParameters=" + pointsBeingParameters + ", interpolationMethod=" + interpolationMethod + ", extrapolationMethod=" + extrapolationMethod + ", interpolationEntity=" + interpolationEntity + ", rationalFunctionInterpolation=" + rationalFunctionInterpolation + ", toString()=" + super.toString() + ",\n" + curveTableString + "]"; } private void readObject(final java.io.ObjectInputStream in) throws ClassNotFoundException, IOException { in.defaultReadObject(); // initialization of transients rationalFunctionInterpolationLazyInitLock = new Object(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy