RandomVariableLazyEvaluation.java
/*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*
* 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 <code>RandomVariableFromDoubleArray</code> using
* late evaluation of Java 8 streams
*
* Accesses performed exclusively through the interface
* <code>RandomVariable</code> 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 <code>RandomVariableFromDoubleArray</code> 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 <code>RandomVariable</code>.
*
* @param value Object implementing <code>RandomVariable</code>.
*/
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 <code>RandomVariable</code>.
*
* @param value Object implementing <code>RandomVariable</code>.
* @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<size(); i++) {
if(get(i) != randomVariable.get(i)) {
return false;
}
}
return true;
}
@Override
public double getFiltrationTime() {
return time;
}
@Override
public int getTypePriority() {
return 0;
}
@Override
public double get(final int pathOrState) {
if(isDeterministic()) {
return valueIfNonStochastic;
} else {
cache();
return realizationsArray[pathOrState];
// return realizations.applyAsDouble(pathOrState);
}
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#size()
*/
@Override
public int size() {
return size;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getMin()
*/
@Override
public double getMin() {
if(isDeterministic()) {
return valueIfNonStochastic;
}
return getRealizationsStream().min().getAsDouble();
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getMax()
*/
@Override
public double getMax() {
if(isDeterministic()) {
return valueIfNonStochastic;
}
return getRealizationsStream().max().getAsDouble();
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getAverage()
*/
@Override
public double getAverage() {
if(isDeterministic()) {
return valueIfNonStochastic;
}
if(size() == 0) {
return Double.NaN;
}
return getRealizationsStream().sum()/size();
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getAverage(net.finmath.stochastic.RandomVariable)
*/
@Override
public double getAverage(final RandomVariable probabilities) {
if(isDeterministic()) {
return valueIfNonStochastic * probabilities.getAverage();
}
if(size() == 0) {
return Double.NaN;
}
return this.cache().mult(probabilities).getRealizationsStream().sum();
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getVariance()
*/
@Override
public double getVariance() {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
double sum = 0.0;
double sumOfSquared = 0.0;
for (final double realization : getRealizations()) {
sum += realization;
sumOfSquared += realization * realization;
}
return sumOfSquared/size() - sum/size() * sum/size();
}
@Override
public double getVariance(final RandomVariable probabilities) {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
double mean = 0.0;
double secondMoment = 0.0;
for(int i=0; i<size(); i++) {
mean += get(i) * probabilities.get(i);
secondMoment += get(i) * get(i) * probabilities.get(i);
}
return secondMoment - mean*mean;
}
@Override
public double getSampleVariance() {
if(isDeterministic() || size() == 1) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
return getVariance() * size()/(size()-1);
}
@Override
public double getStandardDeviation() {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
return Math.sqrt(getVariance());
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getStandardDeviation(net.finmath.stochastic.RandomVariable)
*/
@Override
public double getStandardDeviation(final RandomVariable probabilities) {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
return Math.sqrt(getVariance(probabilities));
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getStandardError()
*/
@Override
public double getStandardError() {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
return getStandardDeviation()/Math.sqrt(size());
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getStandardError(net.finmath.stochastic.RandomVariable)
*/
@Override
public double getStandardError(final RandomVariable probabilities) {
if(isDeterministic()) {
return 0.0;
}
if(size() == 0) {
return Double.NaN;
}
return getStandardDeviation(probabilities)/size();
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getQuantile()
*/
@Override
public double getQuantile(final double quantile) {
if(isDeterministic()) {
return valueIfNonStochastic;
}
if(size() == 0) {
return Double.NaN;
}
final double[] realizationsSorted = getRealizations().clone();
Arrays.sort(realizationsSorted);
final int indexOfQuantileValue = Math.min(Math.max((int)Math.round((size()+1) * quantile - 1), 0), size()-1);
return realizationsSorted[indexOfQuantileValue];
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getQuantile(net.finmath.stochastic.RandomVariable)
*/
@Override
public double getQuantile(final double quantile, final RandomVariable probabilities) {
if(isDeterministic()) {
return valueIfNonStochastic;
}
if(size() == 0) {
return Double.NaN;
}
throw new RuntimeException("Method not implemented.");
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getConditionalVaR()
*/
@Override
public double getQuantileExpectation(final double quantileStart, final double quantileEnd) {
if(isDeterministic()) {
return valueIfNonStochastic;
}
if(size() == 0) {
return Double.NaN;
}
if(quantileStart > 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.length; intervalIndex++)
{
if(valueIfNonStochastic > 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<intervalPoints.length; intervalIndex++)
{
int sampleCount = 0;
while (sampleIndex < realizationsSorted.length &&
realizationsSorted[sampleIndex] <= intervalPoints[intervalIndex])
{
sampleIndex++;
sampleCount++;
}
histogramValues[intervalIndex] = sampleCount;
}
histogramValues[intervalPoints.length] = realizationsSorted.length-sampleIndex;
// Normalize histogramValues
if(realizationsSorted.length > 0) {
for(int i=0; i<histogramValues.length; i++) {
histogramValues[i] /= realizationsSorted.length;
}
}
}
return histogramValues;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getHistogram(int,double)
*/
@Override
public double[][] getHistogram(final int numberOfPoints, final double standardDeviations) {
final double[] intervalPoints = new double[numberOfPoints];
final double[] anchorPoints = new double[numberOfPoints+1];
final double center = getAverage();
final double radius = standardDeviations * getStandardDeviation();
final double stepSize = (numberOfPoints-1) / 2.0;
for(int i=0; i<numberOfPoints;i++) {
final double alpha = (-(double)(numberOfPoints-1) / 2.0 + i) / stepSize;
intervalPoints[i] = center + alpha * radius;
anchorPoints[i] = center + alpha * radius - radius / (2 * stepSize);
}
anchorPoints[numberOfPoints] = center + 1 * radius + radius / (2 * stepSize);
final double[][] result = new double[2][];
result[0] = anchorPoints;
result[1] = getHistogram(intervalPoints);
return result;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#isDeterministic()
*/
@Override
public boolean isDeterministic() {
return realizations == null;
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#expand()
*/
public RandomVariable expand(final int numberOfPaths) {
if(isDeterministic()) {
// Expand random variable to a vector of path values
final double[] clone = new double[numberOfPaths];
Arrays.fill(clone,valueIfNonStochastic);
return new RandomVariableFromDoubleArray(time,clone);
}
return new RandomVariableFromDoubleArray(time,getRealizations());
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getRealizations()
*/
@Override
public double[] getRealizations() {
if(isDeterministic()) {
final double[] result = new double[1];
result[0] = get(0);
return result;
}
else {
cache();
return realizationsArray;
}
}
@Override
public Double doubleValue() {
if(isDeterministic()) {
return valueIfNonStochastic;
} else {
throw new UnsupportedOperationException("The random variable is non-deterministic");
}
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getOperator()
*/
@Override
public IntToDoubleFunction getOperator() {
return realizations;
}
public RandomVariableFromDoubleArray getRandomVariable() {
if(isDeterministic()) {
return new RandomVariableFromDoubleArray(time, valueIfNonStochastic);
} else {
return new RandomVariableFromDoubleArray(time, getRealizations());
}
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#getRealizationsStream()
*/
@Override
public DoubleStream getRealizationsStream() {
if(isDeterministic()) {
return DoubleStream.generate(new DoubleSupplier() {
@Override
public double getAsDouble() {
return valueIfNonStochastic;
}
});
}
else {
return IntStream.range(0,size()).mapToDouble(realizations).parallel();
}
}
@Override
public RandomVariable apply(final DoubleUnaryOperator operator) {
if(isDeterministic()) {
return new RandomVariableLazyEvaluation(time, operator.applyAsDouble(valueIfNonStochastic));
}
else
{
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i));
}
};
return new RandomVariableLazyEvaluation(time, newRealizations, size());
}
}
@Override
public RandomVariable cache() {
synchronized (this)
{
if(realizationsArray == null) {
realizationsArray = getRealizationsStream().toArray();
realizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return realizationsArray[i];
}
};
}
}
return this;
}
@Override
public RandomVariable apply(final DoubleBinaryOperator operator, final RandomVariable argument) {
final double newTime = Math.max(time, argument.getFiltrationTime());
if(isDeterministic() && argument.isDeterministic()) {
return new RandomVariableLazyEvaluation(newTime, operator.applyAsDouble(valueIfNonStochastic, argument.get(0)));
}
else if(!isDeterministic() && argument.isDeterministic()) {
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argument.get(0));
}
};
return new RandomVariableLazyEvaluation(newTime, newRealizations, size());
}
else if(isDeterministic() && !argument.isDeterministic()) {
if(false) {
final IntToDoubleFunction argumentRealizations = argument.getOperator();
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argumentRealizations.applyAsDouble(i));
}
};
return new RandomVariableLazyEvaluation(newTime, newRealizations, argument.size());
}
else {
final double[] argumentRealizations = argument.getRealizations();
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argumentRealizations[i]);
}
};
return new RandomVariableLazyEvaluation(newTime, newRealizations, argument.size());
}
}
else
{
if(false) {
final IntToDoubleFunction argumentRealizations = argument.getOperator();
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argumentRealizations.applyAsDouble(i));
}
};
return new RandomVariableLazyEvaluation(newTime, newRealizations, size());
}
else {
final double[] argumentRealizations = argument.getRealizations();
final IntToDoubleFunction newRealizations = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argumentRealizations[i]);
}
};
return new RandomVariableLazyEvaluation(newTime, newRealizations, size());
}
}
}
public RandomVariable apply(final DoubleBinaryOperator operatorOuter, final DoubleBinaryOperator operatorInner, final RandomVariable argument1, final RandomVariable argument2)
{
double newTime = Math.max(time, argument1.getFiltrationTime());
newTime = Math.max(newTime, argument2.getFiltrationTime());
if(this.isDeterministic() && argument1.isDeterministic() && argument2.isDeterministic()) {
return new RandomVariableLazyEvaluation(newTime, operatorOuter.applyAsDouble(valueIfNonStochastic, operatorInner.applyAsDouble(argument1.get(0), argument2.get(0))));
}
else {
final int newSize = Math.max(Math.max(this.size(), argument1.size()), argument2.size());
if(false) {
if(argument1.isDeterministic() && argument2.isDeterministic()) {
final double argument1Realization = argument1.get(0);
final double argument2Realization = argument2.get(0);
final double innerResult = operatorInner.applyAsDouble(argument1Realization, argument2Realization);
return new RandomVariableLazyEvaluation(newTime,new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorOuter.applyAsDouble(realizations.applyAsDouble(i), innerResult);
}
}, newSize);
}
else {
return new RandomVariableLazyEvaluation(newTime,new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorOuter.applyAsDouble(realizations.applyAsDouble(i), operatorInner.applyAsDouble(argument1.get(i), argument2.get(i)));
}
}, newSize);
}
}
else {
IntToDoubleFunction innerResult;
if(argument1.isDeterministic() && argument2.isDeterministic()) {
final double argument1Realization = argument1.get(0);
final double argument2Realization = argument2.get(0);
innerResult = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorInner.applyAsDouble(argument1Realization, argument2Realization);
}
};
}
else if(argument1.isDeterministic() && !argument2.isDeterministic()) {
final double argument1Realization = argument1.get(0);
final double[] argument2Realizations = argument2.getRealizations();
innerResult = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorInner.applyAsDouble(argument1Realization, argument2Realizations[i]);
}
};
}
else if(!argument1.isDeterministic() && argument2.isDeterministic()) {
final double[] argument1Realizations = argument1.getRealizations();
final double argument2Realization = argument2.get(0);
innerResult = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorInner.applyAsDouble(argument1Realizations[i], argument2Realization);
}
};
}
else {// if(!argument1.isDeterministic() && !argument2.isDeterministic()) {
final double[] argument1Realizations = argument1.getRealizations();
final double[] argument2Realizations = argument2.getRealizations();
innerResult = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorInner.applyAsDouble(argument1Realizations[i], argument2Realizations[i]);
}
};
}
if(isDeterministic()) {
return new RandomVariableLazyEvaluation(newTime,new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorOuter.applyAsDouble(valueIfNonStochastic, innerResult.applyAsDouble(i));
}
}, newSize);
}
else {
return new RandomVariableLazyEvaluation(newTime,new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operatorOuter.applyAsDouble(realizations.applyAsDouble(i), innerResult.applyAsDouble(i));
}
}, newSize);
}
}
}
}
@Override
public RandomVariable apply(final DoubleTernaryOperator operator, final RandomVariable argument1, final RandomVariable argument2)
{
double newTime = Math.max(time, argument1.getFiltrationTime());
newTime = Math.max(newTime, argument2.getFiltrationTime());
if(this.isDeterministic() && argument1.isDeterministic() && argument2.isDeterministic()) {
return new RandomVariableLazyEvaluation(newTime, operator.applyAsDouble(valueIfNonStochastic, argument1.get(0), argument2.get(0)));
}
else {
final int newSize = Math.max(Math.max(this.size(), argument1.size()), argument2.size());
IntToDoubleFunction result;
if(argument1.isDeterministic() && argument2.isDeterministic()) {
final double argument1Realization = argument1.get(0);
final double argument2Realization = argument2.get(0);
if(isDeterministic()) {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argument1Realization, argument2Realization);
}
};
}
else {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argument1Realization, argument2Realization);
}
};
}
}
else if(argument1.isDeterministic() && !argument2.isDeterministic()) {
final double argument1Realization = argument1.get(0);
final double[] argument2Realizations = argument2.getRealizations();
if(isDeterministic()) {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argument1Realization, argument2Realizations[i]);
}
};
}
else {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argument1Realization, argument2Realizations[i]);
}
};
}
}
else if(!argument1.isDeterministic() && argument2.isDeterministic()) {
final double[] argument1Realizations = argument1.getRealizations();
final double argument2Realization = argument2.get(0);
if(isDeterministic()) {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argument1Realizations[i], argument2Realization);
}
};
}
else {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argument1Realizations[i], argument2Realization);
}
};
}
}
else {// if(!argument1.isDeterministic() && !argument2.isDeterministic()) {
final double[] argument1Realizations = argument1.getRealizations();
final double[] argument2Realizations = argument2.getRealizations();
if(isDeterministic()) {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(valueIfNonStochastic, argument1Realizations[i], argument2Realizations[i]);
}
};
}
else {
result = new IntToDoubleFunction() {
@Override
public double applyAsDouble(final int i) {
return operator.applyAsDouble(realizations.applyAsDouble(i), argument1Realizations[i], argument2Realizations[i]);
}
};
}
}
return new RandomVariableLazyEvaluation(newTime, result, newSize);
}
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#cap(double)
*/
@Override
public RandomVariable cap(final double cap) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return Math.min(x, cap);
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#floor(double)
*/
@Override
public RandomVariable floor(final double floor) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return Math.max(x, floor);
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#add(double)
*/
@Override
public RandomVariable add(final double value) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return x + value;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#sub(double)
*/
@Override
public RandomVariable sub(final double value) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return x - value;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#mult(double)
*/
@Override
public RandomVariable mult(final double value) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return x * value;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#div(double)
*/
@Override
public RandomVariable div(final double value) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return x / value;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#pow(double)
*/
@Override
public RandomVariable pow(final double exponent) {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return Math.pow(x, exponent);
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#average()
*/
@Override
public RandomVariable average() {
return new RandomVariableLazyEvaluation(getAverage());
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#squared()
*/
@Override
public RandomVariable squared() {
return apply(new DoubleUnaryOperator() {
@Override
public double applyAsDouble(final double x) {
return x * x;
}
});
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#sqrt()
*/
@Override
public RandomVariable sqrt() {
return apply(Math::sqrt);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#exp()
*/
@Override
public RandomVariable exp() {
return apply(Math::exp);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#log()
*/
@Override
public RandomVariable log() {
return apply(Math::log);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#sin()
*/
@Override
public RandomVariable sin() {
return apply(Math::sin);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#cos()
*/
@Override
public RandomVariable cos() {
return apply(Math::cos);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#add(net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable add(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x + y;
}
}, randomVariable);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#sub(net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable sub(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x - y;
}
}, randomVariable);
}
@Override
public RandomVariable bus(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return -x + y;
}
}, randomVariable);
}
/* (non-Javadoc)
* @see net.finmath.stochastic.RandomVariable#mult(net.finmath.stochastic.RandomVariable)
*/
@Override
public RandomVariable mult(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x * y;
}
}, randomVariable);
}
@Override
public RandomVariable div(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x / y;
}
}, randomVariable);
}
@Override
public RandomVariable vid(final RandomVariable randomVariable) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return y / x;
}
}, randomVariable);
}
@Override
public RandomVariable cap(final RandomVariable cap) {
return apply(Math::min, cap);
}
@Override
public RandomVariable floor(final RandomVariable floor) {
return apply(Math::max, floor);
}
@Override
public RandomVariable accrue(final RandomVariable rate, final double periodLength) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x * (1.0 + y * periodLength);
}
}, rate);
}
@Override
public RandomVariable discount(final RandomVariable rate, final double periodLength) {
return apply(new DoubleBinaryOperator() {
@Override
public double applyAsDouble(final double x, final double y) {
return x / (1.0 + y * periodLength);
}
}, rate);
}
@Override
public RandomVariable choose(final RandomVariable valueIfTriggerNonNegative, final RandomVariable valueIfTriggerNegative) {
return apply(new DoubleTernaryOperator() {
@Override
public double applyAsDouble(final double x, final double y, final double z) {
return (x >= 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<newRealizations.length; i++) {
newRealizations[i] = Double.isNaN(get(i)) ? 1.0 : 0.0;
}
return new RandomVariableLazyEvaluation(time, newRealizations);
}
}
}