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

net.finmath.interpolation.RationalFunctionInterpolation Maven / Gradle / Ivy

Go to download

finmath lib is a Mathematical Finance Library in Java. It provides algorithms and methodologies related to mathematical finance.

There is a newer version: 6.0.19
Show newest version
/*
 * (c) Copyright Christian P. Fries, Germany. Contact: [email protected].
 *
 * Created on 28.05.2004
 */
package net.finmath.interpolation;

import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.function.DoubleUnaryOperator;

import net.finmath.functions.LinearAlgebra;

/**
 * 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 implements DoubleUnaryOperator, Serializable { private static final long serialVersionUID = -3214160594013393575L; 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; private final double[] values; private InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR; private ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.DEFAULT; private static class RationalFunction implements Serializable { private static final long serialVersionUID = -1596026703859403853L; private final double[] coefficientsNumerator; private final double[] 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 double[] coefficientsNumerator, final double[] 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 double[] coefficients) { this(coefficients, null); } /** * Returns the value for a given arguments. * * @param x Given argument. * @return Returns the value for the given argument. */ public double getValue(final double x) { double valueNumerator = 0.0; double valueDenominator = 0.0; double powerOfX = 1.0; for (final double polynomialCoefficient : coefficientsNumerator) { valueNumerator += polynomialCoefficient * powerOfX; powerOfX *= x; } if(coefficientsDenominator == null) { return valueNumerator; } powerOfX = 1.0; for (final double polynomialCoefficient : coefficientsDenominator) { valueDenominator += polynomialCoefficient * powerOfX; powerOfX *= x; } return valueNumerator/valueDenominator; } } // The interpolated curve - a rational function for each interval (one less than number of points) private RationalFunction[] interpolatingRationalFunctions; private transient Object interpolatingRationalFunctionsLazyInitLock = new Object(); /** * Generate a rational function interpolation from a given set of points. * * @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. */ public RationalFunctionInterpolation(final double[] points, final double[] 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 double[] 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 double getValue(final double x) { 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]+(values[1]-values[0])/(points[1]-points[0])*(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]+(values[points.length-2]-values[points.length-1])/(points[points.length-2]-points[points.length-1])*(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 doCreateRationalFunctions() { switch(interpolationMethod) { case PIECEWISE_CONSTANT: case PIECEWISE_CONSTANT_LEFTPOINT: case PIECEWISE_CONSTANT_RIGHTPOINT: doCreateRationalFunctionsForPiecewiseConstantInterpolation(); break; case LINEAR: default: doCreateRationalFunctionsForLinearInterpolation(); break; case CUBIC_SPLINE: doCreateRationalFunctionsForCubicSplineInterpolation(); break; case AKIMA: doCreateRationalFunctionsForAkimaInterpolation(); break; case AKIMA_CONTINUOUS: doCreateRationalFunctionsForAkimaInterpolation(1E-02); break; case HARMONIC_SPLINE: doCreateRationalFunctionsForHarmonicSplineInterpolation(); break; case HARMONIC_SPLINE_WITH_MONOTONIC_FILTERING: doCreateRationalFunctionsForHarmonicSplineInterpolation(); 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++ ) { double[] numeratorPolynomCoeff; if (interpolationMethod == InterpolationMethod.PIECEWISE_CONSTANT_RIGHTPOINT) { numeratorPolynomCoeff = new double[] {values[pointIndex+1]}; } else { numeratorPolynomCoeff = new double[] {values[pointIndex]}; } interpolatingRationalFunctions[pointIndex] = new RationalFunction(numeratorPolynomCoeff); } } private void doCreateRationalFunctionsForLinearInterpolation() { if(points.length == 0) { throw new IllegalArgumentException("Interpolation requested on curve with no points."); } /* * 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 double[] numeratorPolynomCoeff = new double[2]; final double xl = points[pointIndex]; final double xr = points[pointIndex+1]; final double fl = values[pointIndex]; final double fr = values[pointIndex+1]; numeratorPolynomCoeff[1] = (fr-fl) / (xr-xl); numeratorPolynomCoeff[0] = fl; interpolatingRationalFunctions[pointIndex] = new RationalFunction(numeratorPolynomCoeff); } } private void doCreateRationalFunctionsForCubicSplineInterpolation() { final int numberOfPoints = points.length; // Calculate interval lengths final double[] step = new double[numberOfPoints-1]; for (int i=0; i 1) { secondDerivativeMarix[0][1] = secondDerivativeMarix[1][0]; secondDerivativeMarix[numberOfPoints-2][numberOfPoints-1] = secondDerivativeMarix[numberOfPoints-1][numberOfPoints-2]; } // Solve equation secondDerivativeVector = LinearAlgebra.solveLinearEquationSymmetric(secondDerivativeMarix, v); /* * Generate a rational function for each given interval */ interpolatingRationalFunctions = new RationalFunction[numberOfPoints-1]; // create numerator polynomials (third order polynomial) for(int i = 0; i < numberOfPoints-1; i++ ) { final double[] numeratortorPolynomCoeff = new double[4]; numeratortorPolynomCoeff[0] = values[i]; numeratortorPolynomCoeff[1] = (values[i+1] - values[i])/step[i] - (secondDerivativeVector[i+1] + 2*secondDerivativeVector[i])*step[i]/6; numeratortorPolynomCoeff[2] = secondDerivativeVector[i] / 2; numeratortorPolynomCoeff[3] = (secondDerivativeVector[i+1] - secondDerivativeVector[i]) / (6*step[i]); interpolatingRationalFunctions[i] = new RationalFunction(numeratortorPolynomCoeff); } } private void doCreateRationalFunctionsForAkimaInterpolation() { doCreateRationalFunctionsForAkimaInterpolation(0.0); } private void doCreateRationalFunctionsForAkimaInterpolation(final double minSlopeDifferenceWeight) { final int numberOfPoints = points.length; if(numberOfPoints < 4) { // Akima interpolation not possible doCreateRationalFunctionsForCubicSplineInterpolation(); } else { // Calculate slopes final double[] step = new double[numberOfPoints-1]; final double[] slope = new double[numberOfPoints-1]; final double[] absSlopeDifference = 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) { absSlopeDifference[i-1] = Math.abs(slope[i] - slope[i-1]) + minSlopeDifferenceWeight; } } // Calculate first derivatives ... final double[] derivative = new double[numberOfPoints]; // ... for the 2 left and 2 right outer boundary points: // in t_0 derivative[0] = 0.5 * (3 * slope[0] - slope[1]); // in t_1 if((absSlopeDifference[1] == 0) && (absSlopeDifference[0] == 0)){ derivative[1] = (step[1] * slope[0] + step[0] * slope[1]) / (step[0] + step[1]); } else{ derivative[1] = (absSlopeDifference[1] * slope[0] + absSlopeDifference[0] * slope[1]) / (absSlopeDifference[1] + absSlopeDifference[0]); } // in t_{n-1} if((absSlopeDifference[numberOfPoints-3] == 0) && (absSlopeDifference[numberOfPoints-4] == 0)){ derivative[numberOfPoints-2] = (step[numberOfPoints-2] * slope[numberOfPoints-3] + step[numberOfPoints-3] * slope[numberOfPoints-2]) / (step[numberOfPoints-3] + step[numberOfPoints-2]); } else{ derivative[numberOfPoints-2] = (absSlopeDifference[numberOfPoints-3] * slope[numberOfPoints-3] + absSlopeDifference[numberOfPoints-4] * slope[numberOfPoints-2]) / (absSlopeDifference[numberOfPoints-3] + absSlopeDifference[numberOfPoints-4]); } // in t_n derivative[numberOfPoints-1] = 0.5 * (3 * slope[numberOfPoints-2] - slope[numberOfPoints-3]); // ... for inner points: for(int i = 2; i < numberOfPoints-2; i++){ // Check if denominator would be zero if( (absSlopeDifference[i] == 0) && (absSlopeDifference[i-2] == 0) ){ // Take Convention derivative[i] = (step[i] * slope[i-1] + step[i-1] * slope[i]) / (step[i-1] + step[i]); } else{ derivative[i] = (absSlopeDifference[i] * slope[i-1] + absSlopeDifference[i-2] * slope[i]) / (absSlopeDifference[i] + absSlopeDifference[i-2]); } } /* * Generate a rational function for each given interval */ interpolatingRationalFunctions = new RationalFunction[numberOfPoints-1]; // create numerator polynomials (third order polynomial) for(int i = 0; i < numberOfPoints-1; i++ ) { final double[] numeratorPolynomCoeff = new double[4]; numeratorPolynomCoeff[0] = values[i]; numeratorPolynomCoeff[1] = derivative[i]; numeratorPolynomCoeff[2] = (3*slope[i] - 2*derivative[i] - derivative[i+1]) / step[i]; numeratorPolynomCoeff[3] = (derivative[i] + derivative[i+1] - 2*slope[i]) / (step[i] * step[i]); interpolatingRationalFunctions[i] = new RationalFunction(numeratorPolynomCoeff); } } } private void doCreateRationalFunctionsForHarmonicSplineInterpolation(){ final int numberOfPoints = points.length; // Calculate parameters final double[] step = new double[numberOfPoints-1]; final double[] slope = new double[numberOfPoints-1]; final 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 ... final 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{ final 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; } } /* * Generate a rational function for each given interval */ interpolatingRationalFunctions = new RationalFunction[numberOfPoints-1]; // create numerator polynomials (third order polynomial) for(int i = 0; i < numberOfPoints-1; i++ ) { final 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); } } public static void main(final String[] args) { /* * Example. Shows how to use this class. */ final int samplePoints = 200; /* * Given input points */ final double[] givenPoints = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 }; final double[] givenValues = { 5.0, 6.0, 4.0, 7.0, 5.0, 6.0 }; System.out.println("Interplation of given input points (x,y):"); System.out.println(" x: " + Arrays.toString(givenPoints)); System.out.println(" y: " + Arrays.toString(givenValues)); System.out.println(); // Create interpolated curve System.out.println("Default:"); RationalFunctionInterpolation interpolation = new RationalFunctionInterpolation(givenPoints, givenValues); for(int samplePointIndex = 0; samplePointIndex




© 2015 - 2024 Weber Informatics LLC | Privacy Policy