package beast.math.distributions; import org.apache.commons.math.MathException; import org.apache.commons.math.distribution.ContinuousDistribution; import org.apache.commons.math.distribution.Distribution; import beast.core.Description; import beast.core.Input; @Description("Uniform distribution over a given interval (including lower and upper values)") public class Uniform extends ParametricDistribution { final public Input<Double> lowerInput = new Input<>("lower", "lower bound on the interval, default 0", 0.0); final public Input<Double> upperInput = new Input<>("upper", "lower bound on the interval, default 1", 1.0); UniformImpl distr = new UniformImpl(); double _lower, _upper, density; private boolean infiniteSupport; @Override public void initAndValidate() { _lower = lowerInput.get(); _upper = upperInput.get(); if (_lower >= _upper) { throw new IllegalArgumentException("Upper value should be higher than lower value"); } distr.setBounds(_lower, _upper); infiniteSupport = Double.isInfinite(_lower) || Double.isInfinite(_upper); if (infiniteSupport) { density = 1.0; } else { density = 1.0 / (_upper - _lower); } } class UniformImpl implements ContinuousDistribution { private double lower; private double upper; public void setBounds(final double lower, final double upper) { this.lower = lower; this.upper = upper; } @Override public double cumulativeProbability(double x) throws MathException { x = Math.max(x, lower); return (x - lower) / (upper - lower); } @Override public double cumulativeProbability(double x0, double x1) throws MathException { x0 = Math.max(x0, lower); x1 = Math.min(x1, upper); if (x1 < lower || x1 > upper) { throw new RuntimeException("Value x (" + x1 + ") out of bounds (" + lower + "," + upper + ")."); } return (x1 - x0) / (upper - lower); } @Override public double inverseCumulativeProbability(final double p) throws MathException { if (p < 0.0 || p > 1.0) { throw new RuntimeException("inverseCumulativeProbability::argument out of range [0...1]"); } if( p == 0 ) { // works even when one bound is infinite return _lower; } if( p == 1 ) { // works even when one bound is infinite return _upper; } if( infiniteSupport ) { throw new RuntimeException("Inverse Cumulative Probability for 0 < p < 1 and infinite support") ; } return (upper - lower) * p + lower; } @Override public double density(final double x) { if (x >= lower && x <= upper) { return density; } else { return 0; } } @Override public double logDensity(final double x) { return Math.log(density(x)); } } // class UniformImpl @Override public Distribution getDistribution() { return distr; } @Override public double density(final double x) { if (x >= _lower && x <= _upper) { // (BUG)?? why does this not return this.density??? (JH) return 1; } else { return 0; } } @Override public double getMean() { if (Double.isInfinite(_lower) || Double.isInfinite(_upper)) { return Double.NaN; } return offsetInput.get() + (_upper + _lower)/2; } }