net.finmath.montecarlo.RandomVariableLazyEvaluation 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 09.02.2006
*/
package net.finmath.montecarlo;
import java.util.Arrays;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleSupplier;
import java.util.function.DoubleUnaryOperator;
import java.util.function.IntToDoubleFunction;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import net.finmath.functions.DoubleTernaryOperator;
import net.finmath.stochastic.RandomVariable;
/**
* Implements a Monte-Carlo random variable (like RandomVariableFromDoubleArray
using
* late evaluation of Java 8 streams
*
* Accesses performed exclusively through the interface
* RandomVariable
is thread safe (and does not mutate the class).
*
* The implementation require Java 8 or better.
*
* @TODO The implementation of getAverage does not use a Kahan summation, while RandomVariableFromDoubleArray
does.
*
* @author Christian Fries
* @author OSC
* @version 2.0
*/
public class RandomVariableLazyEvaluation implements RandomVariable {
/**
*
*/
private static final long serialVersionUID = 8413020544732461630L;
private final double time; // Time (filtration)
// Operator
private IntToDoubleFunction realizations;
private final int size;
// Data model for the non-stochastic case (if realizations==null)
private final double valueIfNonStochastic;
private transient double[] realizationsArray = null;
/**
* Create a random variable from a given other implementation of RandomVariable
.
*
* @param value Object implementing RandomVariable
.
*/
public RandomVariableLazyEvaluation(final RandomVariable value) {
super();
time = value.getFiltrationTime();
realizations = value.isDeterministic() ? null : value::get;
size = value.size();
valueIfNonStochastic = value.isDeterministic() ? value.get(0) : Double.NaN;
}
/**
* Create a non stochastic random variable, i.e. a constant.
*
* @param value the value, a constant.
*/
public RandomVariableLazyEvaluation(final double value) {
this(0.0, value);
}
/**
* Create a random variable by applying a function to a given other implementation of RandomVariable
.
*
* @param value Object implementing RandomVariable
.
* @param function A function mapping double to double.
*/
public RandomVariableLazyEvaluation(final RandomVariable value, final DoubleUnaryOperator function) {
super();
time = value.getFiltrationTime();
realizations = value.isDeterministic() ? null : new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return function.applyAsDouble(value.get(i));
}
};
size = value.size();
valueIfNonStochastic = value.isDeterministic() ? function.applyAsDouble(value.get(0)) : Double.NaN;
}
/**
* Create a non stochastic random variable, i.e. a constant.
*
* @param time the filtration time, set to 0.0 if not used.
* @param value the value, a constant.
*/
public RandomVariableLazyEvaluation(final double time, final double value) {
super();
this.time = time;
realizations = null;
size = 1;
valueIfNonStochastic = value;
}
/**
* Create a non stochastic random variable, i.e. a constant.
*
* @param time the filtration time, set to 0.0 if not used.
* @param numberOfPath The number of path/state of the associated Monte-Carlo simulation or lattice.
* @param value the value, a constant.
*/
public RandomVariableLazyEvaluation(final double time, final int numberOfPath, final double value) {
super();
this.time = time;
size = numberOfPath;
realizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return value;
}
};
valueIfNonStochastic = Double.NaN;
}
/**
* Create a stochastic random variable.
*
* @param time the filtration time, set to 0.0 if not used.
* @param realisations the vector of realizations.
*/
public RandomVariableLazyEvaluation(final double time, final double[] realisations) {
super();
this.time = time;
size = realisations.length;
realizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return realisations[i];
}
};
valueIfNonStochastic = Double.NaN;
realizationsArray = realisations;
}
/**
* Create a stochastic random variable.
*
* @param time the filtration time, set to 0.0 if not used.
* @param realisations the vector of realizations.
* @param size The number of path/state of the associated Monte-Carlo simulation or lattice.
*/
public RandomVariableLazyEvaluation(final double time, final IntToDoubleFunction realisations, final int size) {
super();
this.time = time;
realizations = realisations;
this.size = size;
valueIfNonStochastic = Double.NaN;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#equals(net.finmath.montecarlo.RandomVariableFromDoubleArray)
*/
@Override
public boolean equals(final RandomVariable randomVariable) {
if(time != randomVariable.getFiltrationTime()) {
return false;
}
if(this.isDeterministic() && randomVariable.isDeterministic()) {
return valueIfNonStochastic == randomVariable.get(0);
}
if(this.isDeterministic() != randomVariable.isDeterministic()) {
return false;
}
for(int i=0; i quantileEnd) {
return getQuantileExpectation(quantileEnd, quantileStart);
}
final double[] realizationsSorted = getRealizations().clone();
Arrays.sort(realizationsSorted);
final int indexOfQuantileValueStart = Math.min(Math.max((int)Math.round((size()+1) * quantileStart - 1), 0), size()-1);
final int indexOfQuantileValueEnd = Math.min(Math.max((int)Math.round((size()+1) * quantileEnd - 1), 0), size()-1);
double quantileExpectation = 0.0;
for (int i=indexOfQuantileValueStart; i<=indexOfQuantileValueEnd;i++) {
quantileExpectation += realizationsSorted[i];
}
quantileExpectation /= indexOfQuantileValueEnd-indexOfQuantileValueStart+1;
return quantileExpectation;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getHistogram()
*/
@Override
public double[] getHistogram(final double[] intervalPoints)
{
final double[] histogramValues = new double[intervalPoints.length+1];
if(isDeterministic()) {
/*
* If the random variable is deterministic we will return an array
* consisting of 0's and one and only one 1.
*/
Arrays.fill(histogramValues, 0.0);
for (int intervalIndex=0; intervalIndex intervalPoints[intervalIndex]) {
histogramValues[intervalIndex] = 1.0;
break;
}
}
histogramValues[intervalPoints.length] = 1.0;
}
else {
/*
* If the random variable is deterministic we will return an array
* representing a density, where the sum of the entries is one.
* There is one exception:
* If the size of the random variable is 0, all entries will be zero.
*/
final double[] realizationsSorted = getRealizations().clone();
Arrays.sort(realizationsSorted);
int sampleIndex=0;
for (int intervalIndex=0; intervalIndex 0) {
for(int i=0; i= 0 ? y : z);
}
}, valueIfTriggerNonNegative, valueIfTriggerNegative);
}
@Override
public RandomVariable invert() {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return 1.0 / x;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#abs()
*/
@Override
public RandomVariable abs() {
return apply(Math::abs);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#addProduct(net.finmath.stochastic.RandomVariable, double)
*/
@Override
public RandomVariable addProduct(final RandomVariable factor1, final double factor2) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x + y * factor2;
}
}, factor1);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#addProduct(net.finmath.stochastic.RandomVariable, net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable addProduct(final RandomVariable factor1, final RandomVariable factor2) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x + y;
}
}, new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x * y;
}
}, factor1, factor2);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#addRatio(net.finmath.stochastic.RandomVariable, net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable addRatio(final RandomVariable numerator, final RandomVariable denominator) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x + y;
}
}, new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x / y;
}
}, numerator, denominator);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#subRatio(net.finmath.stochastic.RandomVariable, net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable subRatio(final RandomVariable numerator, final RandomVariable denominator) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x - y;
}
}, new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x / y;
}
}, numerator, denominator);
}
@Override
public RandomVariable isNaN() {
if(isDeterministic()) {
return new RandomVariableLazyEvaluation(time, Double.isNaN(valueIfNonStochastic) ? 1.0 : 0.0);
}
else {
final double[] newRealizations = new double[size()];
for(int i=0; i