/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2013 Ausenco Engineering Canada 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.BasicObjects;
import com.jaamsim.Graphics.DisplayEntity;
import com.jaamsim.Samples.SampleProvider;
import com.jaamsim.datatypes.DoubleVector;
import com.jaamsim.events.EventManager;
import com.jaamsim.input.InputErrorException;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.Output;
import com.jaamsim.input.ValueListInput;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.Unit;
import com.jaamsim.units.UserSpecifiedUnit;
/**
* EntitlementSelector selects an index to return based on the difference
* between the expected and actual numbers of samples for each index. The
* object with the largest difference (expected - actual) is selected.
* @author Harry King
*
*/
public class EntitlementSelector extends DisplayEntity implements SampleProvider {
@Keyword(description = "A list of N numbers equal to the relative proportion for each of the "
+ "N indices. Must sum to 1.0.",
exampleList = {"0.3 0.7"})
private final ValueListInput proportionList;
private int lastSample; // the index that was selected most recently
private int totalCount; // the total number of samples that have been selected
private int[] sampleCount; // number of times each index has been selected
private double[] sampleDifference; // (actual number of samples) - (expected number)
{
proportionList = new ValueListInput("ProportionList", "Key Inputs", null);
proportionList.setUnitType(DimensionlessUnit.class);
proportionList.setRequired(true);
this.addInput(proportionList);
}
public EntitlementSelector() {
sampleCount = new int[0];
sampleDifference = new double[0];
}
@Override
public void validate() {
super.validate();
// The entries in the ProportionList must sum to 1.0
if (Math.abs(proportionList.getValue().sum() - 1.0) > 1.0e-10) {
throw new InputErrorException("The entries in the ProportionList must sum to 1.0");
}
}
@Override
public void earlyInit() {
super.earlyInit();
lastSample = -1;
totalCount = 0;
sampleCount = new int[proportionList.getValue().size()];
sampleDifference = new double[proportionList.getValue().size()];
}
/**
* Returns the next sample.
*/
@Output(name = "Value",
description = "The last sampled index (from 1 to N).",
unitType = UserSpecifiedUnit.class,
sequence = 0)
@Override
public final double getNextSample(double simTime) {
// If we are not in a model context, do not perturb the distribution by sampling,
// instead simply return the last sampled value
if (!EventManager.hasCurrent()) {
return lastSample;
}
// Make the next selection
DoubleVector probList = proportionList.getValue();
int index = 0;
double maxDiff = Double.NEGATIVE_INFINITY;
totalCount++;
for (int i=0; i<probList.size(); i++) {
double diff = totalCount * probList.get(i) - sampleCount[i];
if (diff > maxDiff) {
maxDiff = diff;
index = i;
}
}
lastSample = index + 1;
// Collect statistics on the sampled values
sampleCount[index]++;
for(int i=0; i<sampleCount.length; i++) {
sampleDifference[i] = sampleCount[i] - totalCount*proportionList.getValue().get(i);
}
return lastSample;
}
@Override
public Class<? extends Unit> getUnitType() {
return DimensionlessUnit.class;
}
@Override
public double getMeanValue(double simTime) {
return 0;
}
@Override
public double getMinValue() {
return 1;
}
@Override
public double getMaxValue() {
return proportionList.getValue().size();
}
@Output(name = "NumberOfSamples",
description = "The number of times the distribution has been sampled.",
sequence = 1)
public int getNumberOfSamples(double simTime) {
return totalCount;
}
@Output(name = "SampleCount",
description = "The number samples for each entity.",
sequence = 2)
public DoubleVector getSampleCount(double simTime) {
DoubleVector ret = new DoubleVector(sampleCount.length);
for (int i=0; i<sampleCount.length; i++) {
ret.add(sampleCount[i]);
}
return ret;
}
@Output(name = "SampleDifference",
description = "The difference between the actual number samples for each entity and the "
+ "expected number.",
sequence = 3)
public DoubleVector getSampleDifference(double simTime) {
DoubleVector ret = new DoubleVector(sampleDifference.length);
for (int i=0; i<sampleDifference.length; i++) {
ret.add(sampleDifference[i]);
}
return ret;
}
}