net.finmath.marketdata2.interpolation.RationalFunctionInterpolation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of finmath-lib Show documentation
Show all versions of finmath-lib Show documentation
finmath lib is a Mathematical Finance Library in Java.
It provides algorithms and methodologies related to mathematical finance.
/*
* (c) Copyright Christian P. Fries, Germany. Contact: [email protected].
*
* Created on 28.05.2004
*/
package net.finmath.marketdata2.interpolation;
import java.io.IOException;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
//import net.finmath.interpolation.RationalFunctionInterpolation.RationalFunction;
import net.finmath.stochastic.RandomVariable;
/**
* This class provides methodologies to interpolate given sample points by
* rational functions, that is, given interpolation points (xi,yi)
* the class provides a continuous function y = f(x) where
*
* -
* f(xi) = yi and
*
* -
* for xi < x < xi+1 the function is a fraction of two polynomes
* f(x) = (sum aj xj) / (sum bk xk).
*
*
*
* This setup comprises linear interpolation (for which the function is C0) and
* cubic spline interpolation (for which the function is C1).
*
* @author Christian Fries
* @version 1.3
*/
public class RationalFunctionInterpolation {
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
}
public enum ExtrapolationMethod {
/** Extrapolation using the interpolation function of the adjacent interval **/
DEFAULT,
/** Constant extrapolation. **/
CONSTANT,
/** Linear extrapolation. **/
LINEAR
}
// The curve to interpolate
private final double[] points; // times (i.e. double[])
private final RandomVariable[] values;
private InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR;
private ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.DEFAULT;
private static class RationalFunction {
private final RandomVariable[] coefficientsNumerator;
private final RandomVariable[] coefficientsDenominator;
/**
* Create a rational interpolation function.
*
* @param coefficientsNumerator The coefficients of the polynomial of the numerator, in increasing order.
* @param coefficientsDenominator The coefficients of the polynomial of the denominator, in increasing order.
*/
RationalFunction(final RandomVariable[] coefficientsNumerator, final RandomVariable[]coefficientsDenominator) {
super();
this.coefficientsNumerator = coefficientsNumerator;
this.coefficientsDenominator = coefficientsDenominator;
}
/**
* Create a polynomial interpolation function.
*
* @param coefficients The coefficients of the polynomial, in increasing order.
*/
RationalFunction(final RandomVariable[] coefficients) {
super();
coefficientsNumerator = coefficients;
coefficientsDenominator = null;
}
/**
* Returns the value for a given arguments.
*
* @param x Given argument.
* @return Returns the value for the given argument.
*/
public RandomVariable getValue(final double x)
{
RandomVariable powerOfX = new RandomVariableFromDoubleArray(1.0);
RandomVariable valueNumerator = coefficientsNumerator[0];
for (int i = 1; ii sample points of a function y=f(x).
* @param values The corresponding array of the yi sample values to the sample points xi.
*/
public RationalFunctionInterpolation(final double[] points, final RandomVariable[] values) {
super();
this.points = points;
this.values = values;
}
/**
* Generate a rational function interpolation from a given set of points using
* the specified interpolation and extrapolation method.
*
* @param points The array of the xi sample points of a function y=f(x).
* @param values The corresponding array of the yi sample values to the sample points xi.
* @param interpolationMethod The interpolation method to be used.
* @param extrapolationMethod The extrapolation method to be used.
*/
public RationalFunctionInterpolation(final double[] points, final RandomVariable[] values, final InterpolationMethod interpolationMethod, final ExtrapolationMethod extrapolationMethod) {
super();
this.points = points;
this.values = values;
this.interpolationMethod = interpolationMethod;
this.extrapolationMethod = extrapolationMethod;
}
/**
* Returns the interpolation method used.
*
* @return Returns the interpolationMethod.
*/
public InterpolationMethod getInterpolationMethod() {
return interpolationMethod;
}
/**
* Get an interpolated value for a given argument x.
*
* @param x The abscissa at which the interpolation should be performed.
* @return The interpolated value (ordinate).
*/
public RandomVariable getValue(final double x) // x is time
{
synchronized(interpolatingRationalFunctionsLazyInitLock) {
if(interpolatingRationalFunctions == null) {
doCreateRationalFunctions();
}
}
// Get interpolating rational function for the given point x
final int pointIndex = java.util.Arrays.binarySearch(points, x);
if(pointIndex >= 0) {
return values[pointIndex];
}
int intervalIndex = -pointIndex-2;
// Check for extrapolation
if(intervalIndex < 0) {
// Extrapolation
if(extrapolationMethod == ExtrapolationMethod.CONSTANT) {
return values[0];
} else if(extrapolationMethod == ExtrapolationMethod.LINEAR) {
return values[0].add((values[1].sub(values[0])).div(points[1]-points[0]).mult(x-points[0]));
} else {
intervalIndex = 0;
}
}
else if(intervalIndex > points.length-2) {
// Extrapolation
if(extrapolationMethod == ExtrapolationMethod.CONSTANT) {
return values[points.length-1];
} else if(extrapolationMethod == ExtrapolationMethod.LINEAR) {
return values[points.length-1].add((values[points.length-2].sub(values[points.length-1])).div(points[points.length-2]-points[points.length-1]).mult(x-points[points.length-1]));
} else {
intervalIndex = points.length-2;
}
}
final RationalFunction rationalFunction = interpolatingRationalFunctions[intervalIndex];
// Calculate interpolating value
return rationalFunction.getValue(x-points[intervalIndex]);
}
private void readObject(final java.io.ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
// initialization of transients
interpolatingRationalFunctionsLazyInitLock = new Object();
}
private void doCreateRationalFunctions()
{
switch(interpolationMethod)
{
case PIECEWISE_CONSTANT:
case PIECEWISE_CONSTANT_LEFTPOINT:
case PIECEWISE_CONSTANT_RIGHTPOINT:
doCreateRationalFunctionsForPiecewiseConstantInterpolation();
break;
case LINEAR:
default:
doCreateRationalFunctionsForLinearInterpolation();
break;
}
}
private void doCreateRationalFunctionsForPiecewiseConstantInterpolation()
{
/*
* Generate a rational function for each given interval
*/
interpolatingRationalFunctions = new RationalFunction[points.length-1];
// create numerator polynomials (constant)
for(int pointIndex = 0; pointIndex < points.length-1; pointIndex++ ) {
RandomVariable[] numeratorPolynomCoeff;
if (interpolationMethod == InterpolationMethod.PIECEWISE_CONSTANT_RIGHTPOINT) {
numeratorPolynomCoeff = new RandomVariable[] {values[pointIndex+1]};
} else {
numeratorPolynomCoeff = new RandomVariable[] {values[pointIndex]};
}
interpolatingRationalFunctions[pointIndex] = new RationalFunction(numeratorPolynomCoeff);
}
}
private void doCreateRationalFunctionsForLinearInterpolation()
{
/*
* Generate a rational function for each given interval
*/
interpolatingRationalFunctions = new RationalFunction[points.length-1];
// create numerator polynomials (linear)
for(int pointIndex = 0; pointIndex < points.length-1; pointIndex++ ) {
final RandomVariable[] numeratorPolynomCoeff = new RandomVariable[2];
final double xl = points[pointIndex];
final double xr = points[pointIndex+1];
final RandomVariable fl = values[pointIndex];
final RandomVariable fr = values[pointIndex+1];
numeratorPolynomCoeff[1] = fr.sub(fl).div(xr-xl);
numeratorPolynomCoeff[0] = fl;
interpolatingRationalFunctions[pointIndex] = new RationalFunction(numeratorPolynomCoeff);
}
}
/*
private void doCreateRationalFunctionsForHarmonicSplineInterpolation(){
int numberOfPoints = points.length;
// Calculate parameters
double[] step = new double[numberOfPoints-1];
double[] slope = new double[numberOfPoints-1];
double[] doubleStep = new double[numberOfPoints-2];
for(int i = 0; i < numberOfPoints-1; i++){
step[i] = (points[i+1] - points[i]);
slope[i] = (values[i+1] - values[i]) / step[i];
if(i > 0){
doubleStep[i-1] = points[i+1] - points[i-1];
}
}
// Calculate first derivatives ...
double[] derivative = new double[numberOfPoints];
// ... for boundary points:
// in t_0
derivative[0] =(2*step[0] + step[1])/doubleStep[0] * slope[0] - step[0]/doubleStep[0] * slope[1];
// in t_n
derivative[numberOfPoints-1] =(2*step[numberOfPoints-2] + step[numberOfPoints-3])/doubleStep[numberOfPoints-3] * slope[numberOfPoints-2]
- step[numberOfPoints-2]/doubleStep[numberOfPoints-3] * slope[numberOfPoints-3];
// monotonicity filtering
if(interpolationMethod == InterpolationMethod.HARMONIC_SPLINE_WITH_MONOTONIC_FILTERING){
// in t_0
if((derivative[0]*slope[0] > 0) && (slope[0]*slope[1] <= 0) && (Math.abs(derivative[0]) < 3*Math.abs(slope[0])))
derivative[0] = 3 * slope[0];
if( derivative[0]*slope[0] <= 0 )
derivative[0] = 0;
// in t_n
if((derivative[numberOfPoints-1]*slope[numberOfPoints-2] > 0) && (slope[numberOfPoints-2]*slope[numberOfPoints-3] <= 0)
&& (Math.abs(derivative[numberOfPoints-1]) < 3*Math.abs(slope[numberOfPoints-2])))
derivative[numberOfPoints-1] = 3 * slope[numberOfPoints-2];
if( derivative[numberOfPoints-1]*slope[numberOfPoints-2] <= 0 )
derivative[numberOfPoints-1] = 0;
}
// ... for inner points:
for(int i = 1; i < numberOfPoints-1; i++){
if( slope[i-1] * slope[i] <= 0 ){
derivative[i] = 0;
}
else{
double weightedHarmonicMean = (step[i-1] + 2*step[i]) / (3*doubleStep[i-1]*slope[i-1])
+ (2*step[i-1] + step[i]) / (3*doubleStep[i-1]*slope[i]);
derivative[i] = 1.0 / weightedHarmonicMean;
}
}
interpolatingRationalFunctions = new RationalFunction[numberOfPoints-1];
// create numerator polynomials (third order polynomial)
for(int i = 0; i < numberOfPoints-1; i++ ) {
double[] numeratortorPolynomCoeff = new double[4];
numeratortorPolynomCoeff[0] = values[i];
numeratortorPolynomCoeff[1] = derivative[i];
numeratortorPolynomCoeff[2] = (3*slope[i] - 2*derivative[i] - derivative[i+1]) / step[i];
numeratortorPolynomCoeff[3] = (derivative[i] + derivative[i+1] - 2*slope[i]) / (step[i] * step[i]);
interpolatingRationalFunctions[i] = new RationalFunction(numeratortorPolynomCoeff);
}
}
*/
}