com.badlogic.gdx.math.CumulativeDistribution Maven / Gradle / Ivy
package com.badlogic.gdx.math;
import com.badlogic.gdx.utils.Array;
/** This class represents a cumulative distribution.
* It can be used in scenarios where there are values with different probabilities
* and it's required to pick one of those respecting the probability.
* For example one could represent the frequency of the alphabet letters using a cumulative distribution
* and use it to randomly pick a letter respecting their probabilities (useful when generating random words).
* Another example could be point generation on a mesh surface: one could generate a cumulative distribution using
* triangles areas as interval size, in this way triangles with a large area will be picked more often than triangles with a smaller one.
* See Wikipedia for a detailed explanation.
* @author Inferno */
public class CumulativeDistribution {
public class CumulativeValue{
public T value;
public float frequency;
public float interval;
public CumulativeValue(T value, float frequency, float interval){
this.value = value;
this.frequency = frequency;
this.interval = interval;
}
}
private Array values;
public CumulativeDistribution(){
values = new Array(false, 10, CumulativeValue.class);
}
/** Adds a value with a given interval size to the distribution */
public void add(T value, float intervalSize){
values.add(new CumulativeValue(value, 0, intervalSize));
}
/** Adds a value with interval size equal to zero to the distribution*/
public void add(T value){
values.add(new CumulativeValue(value, 0, 0));
}
/** Generate the cumulative distribution */
public void generate(){
float sum = 0;
for(int i=0; i < values.size; ++i){
sum += values.items[i].interval;
values.items[i].frequency = sum;
}
}
/** Generate the cumulative distribution in [0,1] where each interval will get a frequency between [0,1] */
public void generateNormalized(){
float sum = 0;
for(int i=0; i < values.size; ++i){
sum += values.items[i].interval;
}
float intervalSum = 0;
for(int i=0; i < values.size; ++i){
intervalSum += values.items[i].interval/sum;
values.items[i].frequency = intervalSum;
}
}
/** Generate the cumulative distribution in [0,1] where each value will have the same frequency and interval size*/
public void generateUniform(){
float freq = 1f/values.size;
for(int i=0; i < values.size; ++i){
//reset the interval to the normalized frequency
values.items[i].interval = freq;
values.items[i].frequency=(i+1)*freq;
}
}
/** Finds the value whose interval contains the given probability
* Binary search algorithm is used to find the value.
* @param probability
* @return the value whose interval contains the probability */
public T value(float probability){
CumulativeValue value = null;
int imax = values.size-1, imin = 0, imid;
while (imin <= imax){
imid = imin + ((imax - imin) / 2);
value = values.items[imid];
if(probability < value.frequency)
imax = imid -1;
else if(probability > value.frequency)
imin = imid +1;
else break;
}
return value.value;
}
/** @return the value whose interval contains a random probability in [0,1] */
public T value(){
return value(MathUtils.random());
}
/** @return the amount of values */
public int size(){
return values.size;
}
/**@return the interval size for the value at the given position */
public float getInterval(int index){
return values.items[index].interval;
}
/**@return the value at the given position */
public T getValue(int index){
return values.items[index].value;
}
/** Set the interval size on the passed in object.
* The object must be present in the distribution. */
public void setInterval(T obj, float intervalSize){
for(CumulativeValue value : values)
if(value.value == obj){
value.interval = intervalSize;
return;
}
}
/** Sets the interval size for the value at the given index */
public void setInterval(int index, float intervalSize){
values.items[index].interval = intervalSize;
}
/** Removes all the values from the distribution */
public void clear(){
values.clear();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy