package de.lmu.ifi.dbs.elki.math.statistics.distribution;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.Random;
import de.lmu.ifi.dbs.elki.math.random.RandomFactory;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
/**
* Exponential distribution.
*
* @author Erich Schubert
*/
public class ExponentialDistribution extends AbstractDistribution {
/**
* Rate, inverse of mean
*/
double rate;
/**
* Location parameter.
*/
double location;
/**
* Constructor.
*
* @param rate Rate parameter (1/scale)
*/
public ExponentialDistribution(double rate) {
this(rate, 0.0, (Random) null);
}
/**
* Constructor.
*
* @param rate Rate parameter (1/scale)
* @param location Location parameter
*/
public ExponentialDistribution(double rate, double location) {
this(rate, location, (Random) null);
}
/**
* Constructor.
*
* @param rate Rate parameter (1/scale)
* @param random Random generator
*/
public ExponentialDistribution(double rate, Random random) {
this(rate, 0.0, random);
}
/**
* Constructor.
*
* @param rate Rate parameter (1/scale)
* @param location Location parameter
* @param random Random generator
*/
public ExponentialDistribution(double rate, double location, Random random) {
super(random);
this.rate = rate;
this.location = location;
}
/**
* Constructor.
*
* @param rate Rate parameter (1/scale)
* @param location Location parameter
* @param random Random generator
*/
public ExponentialDistribution(double rate, double location, RandomFactory random) {
super(random);
this.rate = rate;
this.location = location;
}
@Override
public double pdf(double val) {
if (val < location) {
return 0.;
}
return rate * Math.exp(-rate * (val - location));
}
/**
* PDF, static version
*
* @param val Value to compute PDF at
* @param rate Rate parameter (1/scale)
* @return probability density
*/
public static double pdf(double val, double rate) {
if (val < 0.) {
return 0.;
}
return rate * Math.exp(-rate * val);
}
@Override
public double cdf(double val) {
if (val < location) {
return 0.;
}
return 1 - Math.exp(-rate * (val - location));
}
/**
* Cumulative density, static version
*
* @param val Value to compute CDF at
* @param rate Rate parameter (1/scale)
* @return cumulative density
*/
public static double cdf(double val, double rate) {
if (val < 0.) {
return 0.;
}
return 1 - Math.exp(-rate * val);
}
@Override
public double quantile(double val) {
return -Math.log(1 - val) / rate + location;
}
/**
* Quantile function, static version
*
* @param val Value to compute quantile for
* @param rate Rate parameter
* @return Quantile
*/
public static double quantile(double val, double rate) {
return -Math.log(1 - val) / rate;
}
/**
* This method currently uses the naive approach of returning
* -log(uniform)
.
*
* TODO: there are variants that do not rely on the log method and are faster.
* We need to implement and evaluate these. For details: see
* "Computer methods for sampling from the exponential and normal distributions"
* J. H. Ahrens, U. Dieter, https://dl.acm.org/citation.cfm?id=361593
*/
@Override
public double nextRandom() {
return -Math.log(random.nextDouble()) / rate + location;
}
@Override
public String toString() {
return "ExponentialDistribution(rate=" + rate + ", location=" + location + ")";
}
/**
* Parameterization class
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractDistribution.Parameterizer {
/**
* Shape parameter gamma.
*/
public static final OptionID RATE_ID = new OptionID("distribution.exponential.rate", "Exponential distribution rate (lambda) parameter (inverse of scale).");
/** Parameters. */
double location, rate;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
DoubleParameter locP = new DoubleParameter(LOCATION_ID);
if (config.grab(locP)) {
location = locP.doubleValue();
}
DoubleParameter rateP = new DoubleParameter(RATE_ID);
if (config.grab(rateP)) {
rate = rateP.doubleValue();
}
}
@Override
protected ExponentialDistribution makeInstance() {
return new ExponentialDistribution(rate, location, rnd);
}
}
}