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

net.finmath.integration.PiecewiseContantDoubleUnaryOperator 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
package net.finmath.integration;

import java.util.Arrays;
import java.util.List;
import java.util.function.DoubleUnaryOperator;
import java.util.function.Function;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;

/**
 * A piecewise constant {@link java.util.function.DoubleUnaryOperator} \( f : \mathbb{R} \rightarrow \mathbb{R} \)
 * with exact calculation of the integral \( \int_{a}^{b} f(x) dx \) for given bounds \( a, b \).
 *
 * The summation uses Kahan error correction.
 *
 * For convenience the class can act as {@link java.util.function.DoubleUnaryOperator} specialization
 * and as {@link java.util.function.Function}.
 *
 * @author Christian Fries
 */
public class PiecewiseContantDoubleUnaryOperator implements DoubleUnaryOperator, Function {

	private final double[] intervalRightPoints;
	private final double[] values;

	/**
	 * Construct a piecewise constant {@link java.util.function.DoubleUnaryOperator}
	 * \( f : \mathbb{R} \rightarrow \mathbb{R} \).
	 *
	 * @param intervalRightPoints Array of length \( n \) with the right hand points \( x_{i} \) of the intervals \( (x_{i-1},x_{i}] \) on which we have values.
	 * @param values Array of length \( n+1 \) with the values \( f_{i} \) on the intervals \( (x_{i-1},x_{i}] \) where:
	 * 
    *
  • the first value \( f_{0} \) in this array corresponds to the value on \( (-\infty,x_{0}] \)
  • *
  • the last value \( f_{n} \) in this array corresponds to the value on \( (x_{n-1},\infty) \)
  • *
*/ public PiecewiseContantDoubleUnaryOperator(double[] intervalRightPoints, double[] values) { super(); Validate.notNull(intervalRightPoints, "Argument intervalRightPoints must not be null."); Validate.notNull(values, "Argument values must not be null."); Validate.isTrue(values.length == intervalRightPoints.length+1, "Length of values must equal length of intervalRightPoints + 1."); this.intervalRightPoints = intervalRightPoints; this.values = values; } /** * Construct a piecewise constant {@link java.util.function.DoubleUnaryOperator} * \( f : \mathbb{R} \rightarrow \mathbb{R} \). * * @param intervalRightPoints List of length \( n \) with the right hand points \( x_{i} \) of the intervals \( (x_{i-1},x_{i}] \) on which we have values. * @param values List of length \( n+1 \) with the values \( f_{i} \) on the intervals \( (x_{i-1},x_{i}] \) where: *
    *
  • the first value \( f_{0} \) in this array corresponds to the value on \( (-\infty,x_{0}] \)
  • *
  • the last value \( f_{n} \) in this array corresponds to the value on \( (x_{n-1},\infty) \)
  • *
*/ public PiecewiseContantDoubleUnaryOperator(List intervalRightPoints, List values) { this( ArrayUtils.toPrimitive(intervalRightPoints.toArray(new Double[intervalRightPoints.size()])), ArrayUtils.toPrimitive(values.toArray(new Double[values.size()])) ); } /** * Get the integral \( \int_{a}^{b} g(f(x)) dx \) of this function \( f \) plugged into a given function \( g \) * for given bounds \( a, b \). * * @param lowerBound The lower bound a. * @param upperBound The upper bound b. * @param operator The given function g. * @return The integral \( \int_{a}^{b} g(f(x)) dx \). */ public double getIntegral(double lowerBound, double upperBound, DoubleUnaryOperator operator) { if(lowerBound == upperBound) { return 0.0; } if(lowerBound > upperBound) { return -getIntegral(upperBound, lowerBound); } int indexUpperOfLowerBound = Arrays.binarySearch(intervalRightPoints, lowerBound); if(indexUpperOfLowerBound < 0) { indexUpperOfLowerBound = -indexUpperOfLowerBound-1; } int indexLowerOfUpperBound = Arrays.binarySearch(intervalRightPoints, upperBound); if(indexLowerOfUpperBound < 0) { indexLowerOfUpperBound = -indexLowerOfUpperBound-1; } indexLowerOfUpperBound--; if(indexLowerOfUpperBound < indexUpperOfLowerBound) { // lower and upper bound fall in the same interval return operator.applyAsDouble(values[indexUpperOfLowerBound]) * (upperBound-lowerBound); } else { // running error of error correction double error = 0.0; // right part of interval where lower bound is double integral = operator.applyAsDouble(values[indexUpperOfLowerBound]) * (intervalRightPoints[indexUpperOfLowerBound]-lowerBound); // in between intervals (if any) for(int i=indexUpperOfLowerBound; i operator) { return getIntegral(lowerBound, upperBound, toPrimitive(operator)); } private DoubleUnaryOperator toPrimitive(Function operator) { final DoubleUnaryOperator doubleUnaryOperator = x -> operator.apply(x); return doubleUnaryOperator; } /** * Get the integral \( \int_{a}^{b} f(x) dx \) of this function \( f \) * for given bounds \( a, b \). * * @param lowerBound The lower bound a. * @param upperBound The upper bound b. * @return The integral \( \int_{a}^{b} f(x) dx \). */ public double getIntegral(double lowerBound, double upperBound) { return getIntegral(lowerBound, upperBound, DoubleUnaryOperator.identity()); } /** * Get the value of this unary operator \( f \) at the given argument. * * @param operand The given argument. * @return The value \( f(x) \). */ @Override public double applyAsDouble(double operand) { int index = Arrays.binarySearch(intervalRightPoints, operand); if (index < 0) { index = -index - 1; } return values[index]; } /** * Get the value of this function \( f \) at the given argument. * * @param value The given argument. * @return The value \( f(x) \). */ @Override public Double apply(Double value) { return applyAsDouble(value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy