/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2013 Ausenco Engineering Canada Inc.
* Copyright (C) 2016 JaamSim Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaamsim.ProbabilityDistributions;
import com.jaamsim.datatypes.DoubleVector;
import com.jaamsim.input.InputErrorException;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.ValueListInput;
import com.jaamsim.rng.MRG1999a;
import com.jaamsim.units.Unit;
import com.jaamsim.units.UserSpecifiedUnit;
/**
* ContinuousDistribution is a user-defined probability distribution that selects an output value based on an ordered list
* of values and cumulative probabilities. The inputs specify a continuous cumulative probability distribution by
* linearly interpolating between the given values and cumulative probabilities.
* @author Harry King
*
*/
public class ContinuousDistribution extends Distribution {
@Keyword(description = "The list of values for the user-defined cumulative probability distribution.",
exampleList = {"2.0 4.3 8.9"})
private final ValueListInput valueListInput;
@Keyword(description = "The list of cumulative probabilities corresponding to the values in the ValueList. " +
"The cumulative probabilities must be given in increasing order. The first value must be exactly 0.0. " +
"The last value must be exactly 1.0.",
exampleList = {"0.0 0.6 1.0"})
private final CumulativeProbInput cumulativeProbabilityListInput;
private final MRG1999a rng = new MRG1999a();
{
valueListInput = new ValueListInput("ValueList", "Key Inputs", null);
valueListInput.setUnitType(UserSpecifiedUnit.class);
valueListInput.setRequired(true);
valueListInput.setMonotonic( 1 );
this.addInput( valueListInput);
cumulativeProbabilityListInput = new CumulativeProbInput("CumulativeProbabilityList", "Key Inputs", null);
cumulativeProbabilityListInput.setRequired(true);
this.addInput(cumulativeProbabilityListInput);
}
public ContinuousDistribution() {}
@Override
public void validate() {
super.validate();
// The number of entries in the ValueList and CumulativeProbabilityList inputs must match
if( cumulativeProbabilityListInput.getValue().size() != valueListInput.getValue().size() ) {
throw new InputErrorException( "The number of entries for CumulativeProbabilityList and ValueList must be equal" );
}
}
@Override
public void earlyInit() {
super.earlyInit();
rng.setSeedStream(getStreamNumber(), getSubstreamNumber());
}
@Override
protected void setUnitType(Class<? extends Unit> specified) {
super.setUnitType(specified);
valueListInput.setUnitType(specified);
}
@Override
protected double getSample(double simTime) {
double rand = rng.nextUniform();
DoubleVector cumList = cumulativeProbabilityListInput.getValue();
for( int i=1; i<cumList.size(); i++) {
if( rand < cumList.get(i) ) {
double cum = cumList.get(i);
double lastCum = cumList.get(i-1);
double val = valueListInput.getValue().get(i);
double lastVal = valueListInput.getValue().get(i-1);
return lastVal + (rand-lastCum)*(val-lastVal)/(cum-lastCum);
}
}
return valueListInput.getValue().get( cumList.size()-1 );
}
@Override
public double getMinValue() {
return Math.max( valueListInput.getValue().get(0), super.getMinValue());
}
@Override
public double getMaxValue() {
return Math.min( valueListInput.getValue().lastElement(), super.getMaxValue());
}
@Override
protected double getMean(double simTime) {
double sum = 0.0;
DoubleVector cumList = cumulativeProbabilityListInput.getValue();
DoubleVector valueList = valueListInput.getValue();
if (cumList == null || valueList == null)
return Double.NaN;
for( int i=1; i<cumList.size(); i++) {
sum += ( cumList.get(i) - cumList.get(i-1) ) * ( valueList.get(i) + valueList.get(i-1) );
}
return 0.5 * sum;
}
@Override
protected double getStandardDev(double simTime) {
double sum = 0.0;
DoubleVector cumList = cumulativeProbabilityListInput.getValue();
DoubleVector valueList = valueListInput.getValue();
if (cumList == null || valueList == null)
return Double.NaN;
for( int i=1; i<cumList.size(); i++) {
double val = valueList.get(i);
double lastVal = valueList.get(i-1);
sum += ( cumList.get(i) - cumList.get(i-1) ) * ( val*val + val*lastVal + lastVal*lastVal );
}
double mean = getMean(simTime);
return Math.sqrt( sum/3.0 - (mean * mean) );
}
}