package beast.math.distributions; import org.apache.commons.math.MathException; import org.apache.commons.math.distribution.ContinuousDistribution; import beast.core.Description; import beast.core.Input; import beast.core.parameter.RealParameter; @Description("Laplace distribution. f(x|\\mu,b) = \\frac{1}{2b} \\exp \\left( -\\frac{|x-\\mu|}{b} \\right)" + "The probability density function of the Laplace distribution is also reminiscent of the normal distribution; " + "however, whereas the normal distribution is expressed in terms of the squared difference from the mean ?, " + "the Laplace density is expressed in terms of the absolute difference from the mean. Consequently the Laplace " + "distribution has fatter tails than the normal distribution.") public class LaplaceDistribution extends ParametricDistribution { final public Input<RealParameter> muInput = new Input<>("mu", "location parameter, defaults to 0"); final public Input<RealParameter> scaleInput = new Input<>("scale", "scale parameter, defaults to 1"); // the mean parameter double mu; // the scale parameter double scale; // the maximum density double c; LaplaceImpl dist = new LaplaceImpl(); @Override public void initAndValidate() { refresh(); } /** * make sure internal state is up to date * */ void refresh() { if (muInput.get() == null) { mu = 0; } else { mu = muInput.get().getValue(); } if (scaleInput.get() == null || scaleInput.get().getValue()<=0.0) { scale = 1; } else { scale = scaleInput.get().getValue(); } //Normalizing constant c = 1.0 / (2.0 * scale); } @Override public ContinuousDistribution getDistribution() { refresh(); return dist; } class LaplaceImpl implements ContinuousDistribution { @Override public double cumulativeProbability(double x) throws MathException { // =0.5\,[1 + \sgn(x-\mu)\,(1-\exp(-|x-\mu|/b))]. if (x == mu) { return 0.5; } else { return (0.5) * (1 + ((x - mu) / Math.abs(x - mu)) * (1 - Math.exp(-Math.abs(x - mu) / scale))); } } @Override public double cumulativeProbability(double x0, double x1) throws MathException { return cumulativeProbability(x1) - cumulativeProbability(x0); } @Override public double inverseCumulativeProbability(double p) throws MathException { // \mu - b\,\sgn(p-0.5)\,\ln(1 - 2|p-0.5|). return mu - scale * Math.signum(p - 0.5) * Math.log(1.0 - 2.0 * Math.abs(p - 0.5)); } @Override public double density(double x) { // f(x|\mu,b) = \frac{1}{2b} \exp \left( -\frac{|x-\mu|}{b} \right) \,\! return c * Math.exp(-Math.abs(x - mu) / scale); } @Override public double logDensity(double x) { return Math.log(c) - (Math.abs(x - mu) / scale); } } // class LaplaceImpl @Override public double getMean() { return mu; } } // class