com.enterprisemath.math.probability.IntervalFrequencyDistribution Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of em-math Show documentation
Show all versions of em-math Show documentation
Advanced mathematical algorithms.
The newest version!
package com.enterprisemath.math.probability;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.enterprisemath.utils.ValidationUtils;
import java.security.SecureRandom;
import java.util.Collections;
/**
* Frequency distribution defined by intervals. Whole real axis is split to the intervals equal in length.
* Probability is constant on each interval. Each interval is considered to be bounded in the minimum and unbounded
* at the maximum.
*
* @author radek.hecl
*/
public class IntervalFrequencyDistribution implements ProbabilityDistribution {
/**
* Builder object.
*/
public static class Builder {
/**
* Width of the unit.
*/
private Double unitWidth;
/**
* Function values.
*/
private SortedMap values = new TreeMap();
/**
* Sets unit width.
*
* @param unitWidth unit width
* @return this instance
*/
public Builder setUnitWidth(Double unitWidth) {
this.unitWidth = unitWidth;
return this;
}
/**
* Sets unit value.
*
* @param unitId unit id
* @param value value
* @return this instance
*/
public Builder setUnitValue(int unitId, double value) {
values.put(unitId, value);
return this;
}
/**
* Creates the result object.
*
* @return created object
*/
public IntervalFrequencyDistribution build() {
return new IntervalFrequencyDistribution(this);
}
}
/**
* Object for generating random values.
*/
private static final SecureRandom random = new SecureRandom();
/**
* Width of the unit.
*/
private Double unitWidth;
/**
* Function values.
*/
private SortedMap values;
/**
* Creates new instance.
*
* @param builder builder object
*/
public IntervalFrequencyDistribution(Builder builder) {
unitWidth = builder.unitWidth;
values = Collections.unmodifiableSortedMap(new TreeMap(builder.values));
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardPositiveDouble(unitWidth, "unitWidth must be positive");
ValidationUtils.guardNotNullMap(values, "values cannot have null element");
}
@Override
public double getValue(Double x) {
int id = getIntervalId(x);
if (values.containsKey(id)) {
return values.get(id);
}
else {
return 0;
}
}
@Override
public double getLnValue(Double x) {
int id = getIntervalId(x);
if (values.containsKey(id)) {
return Math.log(values.get(id));
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public Double generateRandom() {
double r = random.nextDouble();
double cum = 0;
for (int id : values.keySet()) {
cum = cum + unitWidth * values.get(id);
if (r < cum) {
return id * unitWidth + random.nextDouble() * unitWidth;
}
}
throw new RuntimeException("error in source code, fix code");
}
/**
* Returns unit width.
*
* @return unit width
*/
public Double getUnitWidth() {
return unitWidth;
}
/**
* Returns unit values. Key is unit id, values is value over the whole interval.
*
* @return unit values
*/
public SortedMap getUnitValues() {
return values;
}
/**
* Returns interval id.
*
* @param x random value
* @return interval id
*/
private int getIntervalId(double x) {
double did = Math.abs(x) / unitWidth;
int id = (int) did;
if (x < 0) {
if (did != (double) id) {
id = id + 1;
}
id = -id;
}
return id;
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}