* Added density functions to remaining continuous distributions (F, T, Weibull, Cauchy).

* Deprecated HasDensity interface.
* Added density tests.
* Made Brent Solver (inverse cum) absolute accuracy configurable for all continuous distributions.

JIRA: MATH-332
JIRA: MATH-282
Thanks to Mikkel Meyer Andersen

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@924362 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Phil Steitz 2010-03-17 16:45:31 +00:00
parent 467494bca5
commit 439cb994d1
24 changed files with 540 additions and 115 deletions

View File

@ -740,6 +740,8 @@ public class MessagesResources_fr
// org.apache.commons.math.distribution.AbstractContinuousDistribution
{ "Cumulative probability function returned NaN for argument {0} p = {1}",
"Fonction de probabilit\u00e9 cumulative retourn\u00e9 NaN \u00e0 l''argument de {0} p = {1}" },
{ "This distribution does not have a density function implemented",
"La fonction de densit\u00e9 pour cette distribution n'a pas \u00e9t\u00e9 mis en oeuvre" },
// org.apache.commons.math.distribution.AbstractIntegerDistribution
{ "Discrete cumulative probability function returned NaN for argument {0}",

View File

@ -50,6 +50,17 @@ public abstract class AbstractContinuousDistribution
super();
}
/**
* Return the probability density for a particular point.
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @throws MathRuntimeException if the specialized class hasn't implemented this function
*/
public double density(double x) throws MathRuntimeException {
throw new MathRuntimeException(new UnsupportedOperationException(),
"This distribution does not have a density function implemented");
}
/**
* For this distribution, X, this method returns the critical point x, such
* that P(X &lt; x) = <code>p</code>.
@ -101,10 +112,10 @@ public abstract class AbstractContinuousDistribution
* the default solver's defaultAbsoluteAccuracy of 0 (will be the
* case if density has bounded support and p is 0 or 1).
*/
if (Math.abs(rootFindingFunction.value(lowerBound)) < 1E-6) {
if (Math.abs(rootFindingFunction.value(lowerBound)) < getSolverAbsoluteAccuracy()) {
return lowerBound;
}
if (Math.abs(rootFindingFunction.value(upperBound)) < 1E-6) {
if (Math.abs(rootFindingFunction.value(upperBound)) < getSolverAbsoluteAccuracy()) {
return upperBound;
}
// Failed bracket convergence was not because of corner solution

View File

@ -17,6 +17,7 @@
package org.apache.commons.math.distribution;
import org.apache.commons.math.MathException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.special.Gamma;
import org.apache.commons.math.special.Beta;
@ -97,19 +98,37 @@ public class BetaDistributionImpl
}
}
/** {@inheritDoc} */
public double density(Double x) throws MathException {
/**
* Return the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @deprecated
*/
public double density(Double x) {
return density(x.doubleValue());
}
/**
* Return the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
public double density(double x) {
recomputeZ();
if (x < 0 || x > 1) {
return 0;
} else if (x == 0) {
if (alpha < 1) {
throw new MathException("Cannot compute beta density at 0 when alpha = {0,number}", alpha);
throw MathRuntimeException.createIllegalArgumentException(
"Cannot compute beta density at 0 when alpha = {0,number}", alpha);
}
return 0;
} else if (x == 1) {
if (beta < 1) {
throw new MathException("Cannot compute beta density at 1 when beta = %.3g", beta);
throw MathRuntimeException.createIllegalArgumentException(
"Cannot compute beta density at 1 when beta = %.3g", beta);
}
return 0;
} else {

View File

@ -84,6 +84,18 @@ public class CauchyDistributionImpl extends AbstractContinuousDistribution
return scale;
}
/**
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
final double dev = x - median;
return (1 / Math.PI) * (scale / (dev * dev + scale * scale));
}
/**
* For this distribution, X, this method returns the critical point x, such
* that P(X &lt; x) = <code>p</code>.
@ -123,10 +135,10 @@ public class CauchyDistributionImpl extends AbstractContinuousDistribution
}
/**
* Modify the median.
* @param median for this distribution
* @param newMedian for this distribution
*/
private void setMedianInternal(double median) {
this.median = median;
private void setMedianInternal(double newMedian) {
this.median = newMedian;
}
/**

View File

@ -29,12 +29,18 @@ public class ChiSquaredDistributionImpl
extends AbstractContinuousDistribution
implements ChiSquaredDistribution, Serializable {
/** Default inverse cumulative probability accuracy */
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = -8352658048349159782L;
/** Internal Gamma distribution. */
private GammaDistribution gamma;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a Chi-Squared distribution with the given degrees of freedom.
* @param df degrees of freedom.
@ -56,6 +62,21 @@ public class ChiSquaredDistributionImpl
super();
setGammaInternal(g);
setDegreesOfFreedomInternal(df);
solverAbsoluteAccuracy = DEFAULT_INVERSE_ABSOLUTE_ACCURACY;
}
/**
* Create a Chi-Squared distribution with the given degrees of freedom and
* inverse cumulative probability accuracy.
* @param df degrees of freedom.
* @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
* (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
*/
public ChiSquaredDistributionImpl(double df, double inverseCumAccuracy) {
super();
gamma = new GammaDistributionImpl(df / 2.0, 2.0);
setDegreesOfFreedomInternal(df);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
@ -88,8 +109,20 @@ public class ChiSquaredDistributionImpl
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @deprecated
*/
public double density(Double x) {
return density(x.doubleValue());
}
/**
* Return the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
return gamma.density(x);
}
@ -218,11 +251,15 @@ public class ChiSquaredDistributionImpl
}
/**
* Access the Gamma distribution.
* @return the internal Gamma distribution.
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy
*/
private GammaDistribution getGamma() {
return gamma;
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
}

View File

@ -19,7 +19,14 @@ package org.apache.commons.math.distribution;
import org.apache.commons.math.MathException;
/**
* Base interface for continuous distributions.
* <p>Base interface for continuous distributions.</p>
*
* <p>Note: this interface will be extended in version 3.0 to include
* <br/><code>public double density(double x)</code><br/>
* that is, from version 3.0 forward, continuous distributions <strong>must</strong>
* include implementations of probability density functions. As of version
* 2.1, all continuous distribution implementations included in commons-math
* provide implementations of this method.</p>
*
* @version $Revision$ $Date$
*/

View File

@ -56,15 +56,15 @@ public class ExponentialDistributionImpl extends AbstractContinuousDistribution
}
/**
* Modify the mean.
* @param mean the new mean.
* @throws IllegalArgumentException if <code>mean</code> is not positive.
* @param newMean the new mean.
* @throws IllegalArgumentException if <code>newMean</code> is not positive.
*/
private void setMeanInternal(double mean) {
if (mean <= 0.0) {
private void setMeanInternal(double newMean) {
if (newMean <= 0.0) {
throw MathRuntimeException.createIllegalArgumentException(
"mean must be positive ({0})", mean);
"mean must be positive ({0})", newMean);
}
this.mean = mean;
this.mean = newMean;
}
/**
@ -80,8 +80,20 @@ public class ExponentialDistributionImpl extends AbstractContinuousDistribution
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @deprecated - use density(double)
*/
public double density(Double x) {
return density(x.doubleValue());
}
/**
* Return the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
if (x < 0) {
return 0;
}

View File

@ -32,6 +32,9 @@ public class FDistributionImpl
extends AbstractContinuousDistribution
implements FDistribution, Serializable {
/** Default inverse cumulative probability accuracy */
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Message for non positive degrees of freddom. */
private static final String NON_POSITIVE_DEGREES_OF_FREEDOM_MESSAGE =
"degrees of freedom must be positive ({0})";
@ -45,6 +48,9 @@ public class FDistributionImpl
/** The numerator degrees of freedom*/
private double denominatorDegreesOfFreedom;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a F distribution using the given degrees of freedom.
* @param numeratorDegreesOfFreedom the numerator degrees of freedom.
@ -52,9 +58,40 @@ public class FDistributionImpl
*/
public FDistributionImpl(double numeratorDegreesOfFreedom,
double denominatorDegreesOfFreedom) {
this(numeratorDegreesOfFreedom, denominatorDegreesOfFreedom, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
* Create a F distribution using the given degrees of freedom and inverse cumulative probability accuracy.
* @param numeratorDegreesOfFreedom the numerator degrees of freedom.
* @param denominatorDegreesOfFreedom the denominator degrees of freedom.
* @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
* (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
*/
public FDistributionImpl(double numeratorDegreesOfFreedom, double denominatorDegreesOfFreedom,
double inverseCumAccuracy) {
super();
setNumeratorDegreesOfFreedomInternal(numeratorDegreesOfFreedom);
setDenominatorDegreesOfFreedomInternal(denominatorDegreesOfFreedom);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
final double nhalf = numeratorDegreesOfFreedom / 2;
final double mhalf = denominatorDegreesOfFreedom / 2;
final double logx = Math.log(x);
final double logn = Math.log(numeratorDegreesOfFreedom);
final double logm = Math.log(denominatorDegreesOfFreedom);
final double lognxm = Math.log(numeratorDegreesOfFreedom * x + denominatorDegreesOfFreedom);
return Math.exp(nhalf*logn + nhalf*logx - logx + mhalf*logm - nhalf*lognxm -
mhalf*lognxm - Beta.logBeta(nhalf, mhalf));
}
/**
@ -226,4 +263,15 @@ public class FDistributionImpl
public double getDenominatorDegreesOfFreedom() {
return denominatorDegreesOfFreedom;
}
/**
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy
*/
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
}

View File

@ -30,6 +30,9 @@ import org.apache.commons.math.special.Gamma;
public class GammaDistributionImpl extends AbstractContinuousDistribution
implements GammaDistribution, Serializable {
/** Default inverse cumulative probability accuracy */
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = -3239549463135430361L;
@ -39,15 +42,30 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution
/** The scale parameter. */
private double beta;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a new gamma distribution with the given alpha and beta values.
* @param alpha the shape parameter.
* @param beta the scale parameter.
*/
public GammaDistributionImpl(double alpha, double beta) {
this(alpha, beta, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
* Create a new gamma distribution with the given alpha and beta values.
* @param alpha the shape parameter.
* @param beta the scale parameter.
* @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
* (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
*/
public GammaDistributionImpl(double alpha, double beta, double inverseCumAccuracy) {
super();
setAlphaInternal(alpha);
setBetaInternal(beta);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
@ -117,16 +135,16 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution
/**
* Modify the shape parameter, alpha.
* @param alpha the new shape parameter.
* @throws IllegalArgumentException if <code>alpha</code> is not positive.
* @param newAlpha the new shape parameter.
* @throws IllegalArgumentException if <code>newAlpha</code> is not positive.
*/
private void setAlphaInternal(double alpha) {
if (alpha <= 0.0) {
private void setAlphaInternal(double newAlpha) {
if (newAlpha <= 0.0) {
throw MathRuntimeException.createIllegalArgumentException(
"alpha must be positive ({0})",
alpha);
newAlpha);
}
this.alpha = alpha;
this.alpha = newAlpha;
}
/**
@ -139,27 +157,27 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution
/**
* Modify the scale parameter, beta.
* @param beta the new scale parameter.
* @throws IllegalArgumentException if <code>beta</code> is not positive.
* @param newBeta the new scale parameter.
* @throws IllegalArgumentException if <code>newBeta</code> is not positive.
* @deprecated as of 2.1 (class will become immutable in 3.0)
*/
@Deprecated
public void setBeta(double beta) {
setBetaInternal(beta);
public void setBeta(double newBeta) {
setBetaInternal(newBeta);
}
/**
* Modify the scale parameter, beta.
* @param beta the new scale parameter.
* @throws IllegalArgumentException if <code>beta</code> is not positive.
* @param newBeta the new scale parameter.
* @throws IllegalArgumentException if <code>newBeta</code> is not positive.
*/
private void setBetaInternal(double beta) {
if (beta <= 0.0) {
private void setBetaInternal(double newBeta) {
if (newBeta <= 0.0) {
throw MathRuntimeException.createIllegalArgumentException(
"beta must be positive ({0})",
beta);
newBeta);
}
this.beta = beta;
this.beta = newBeta;
}
/**
@ -171,16 +189,28 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution
}
/**
* Return the probability density for a particular point.
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
public double density(Double x) {
@Override
public double density(double x) {
if (x < 0) return 0;
return Math.pow(x / beta, alpha - 1) / beta * Math.exp(-x / beta) / Math.exp(Gamma.logGamma(alpha));
}
/**
* Return the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @deprecated
*/
public double density(Double x) {
return density(x.doubleValue());
}
/**
* Access the domain value lower bound, based on <code>p</code>, used to
* bracket a CDF root. This method is used by
@ -249,4 +279,15 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution
return ret;
}
/**
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy
*/
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
}

View File

@ -20,10 +20,15 @@ package org.apache.commons.math.distribution;
import org.apache.commons.math.MathException;
/**
* Interface that signals that a distribution can compute the probability density function
* <p>Interface that signals that a distribution can compute the probability density function
* for a particular point.
* @param <P> the type of the point at which density is to be computed, this
* may be for example <code>Double</code>
* may be for example <code>Double.</code></p>
*
* <p>This interface is deprecated. As of version 2.0, the {@link ContinuousDistribution}
* interface will be extended to include a <code>density(double)<code> method.</p>
*
* @deprecated to be removed in math 3.0
* @version $Revision$ $Date$
*/
public interface HasDensity<P> {

View File

@ -102,10 +102,10 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution
}
/**
* Modify the mean.
* @param mean for this distribution
* @param newMean for this distribution
*/
private void setMeanInternal(double mean) {
this.mean = mean;
private void setMeanInternal(double newMean) {
this.mean = newMean;
}
/**
@ -145,8 +145,19 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
* @deprecated
*/
public double density(Double x) {
return density(x.doubleValue());
}
/**
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
public double density(double x) {
double x0 = x - mean;
return Math.exp(-x0 * x0 / (2 * standardDeviation * standardDeviation)) / (standardDeviation * SQRT2PI);
}

View File

@ -21,6 +21,7 @@ import java.io.Serializable;
import org.apache.commons.math.MathException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.special.Beta;
import org.apache.commons.math.special.Gamma;
/**
* Default implementation of
@ -32,19 +33,38 @@ public class TDistributionImpl
extends AbstractContinuousDistribution
implements TDistribution, Serializable {
/** Default inverse cumulative probability accuracy */
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = -5852615386664158222L;
/** The degrees of freedom*/
private double degreesOfFreedom;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a t distribution using the given degrees of freedom and the
* specified inverse cumulative probability absolute accuracy.
*
* @param degreesOfFreedom the degrees of freedom.
* @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
* (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
*/
public TDistributionImpl(double degreesOfFreedom, double inverseCumAccuracy) {
super();
setDegreesOfFreedomInternal(degreesOfFreedom);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
* Create a t distribution using the given degrees of freedom.
* @param degreesOfFreedom the degrees of freedom.
*/
public TDistributionImpl(double degreesOfFreedom) {
super();
setDegreesOfFreedomInternal(degreesOfFreedom);
this(degreesOfFreedom, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
@ -58,15 +78,15 @@ public class TDistributionImpl
}
/**
* Modify the degrees of freedom.
* @param degreesOfFreedom the new degrees of freedom.
* @param newDegreesOfFreedom the new degrees of freedom.
*/
private void setDegreesOfFreedomInternal(double degreesOfFreedom) {
if (degreesOfFreedom <= 0.0) {
private void setDegreesOfFreedomInternal(double newDegreesOfFreedom) {
if (newDegreesOfFreedom <= 0.0) {
throw MathRuntimeException.createIllegalArgumentException(
"degrees of freedom must be positive ({0})",
degreesOfFreedom);
newDegreesOfFreedom);
}
this.degreesOfFreedom = degreesOfFreedom;
this.degreesOfFreedom = newDegreesOfFreedom;
}
/**
@ -77,6 +97,20 @@ public class TDistributionImpl
return degreesOfFreedom;
}
/**
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
final double n = degreesOfFreedom;
final double nPlus1Over2 = (n + 1) / 2;
return Math.exp(Gamma.logGamma(nPlus1Over2) - 0.5 * (Math.log(Math.PI) + Math.log(n)) -
Gamma.logGamma(n/2) - nPlus1Over2 * Math.log(1 + x * x /n));
}
/**
* For this distribution, X, this method returns P(X &lt; <code>x</code>).
* @param x the value at which the CDF is evaluated.
@ -170,4 +204,15 @@ public class TDistributionImpl
protected double getInitialDomain(double p) {
return 0.0;
}
/**
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy
*/
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
}

View File

@ -31,6 +31,9 @@ import org.apache.commons.math.MathRuntimeException;
public class WeibullDistributionImpl extends AbstractContinuousDistribution
implements WeibullDistribution, Serializable {
/** Default inverse cumulative probability accuracy */
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = 8589540077390120676L;
@ -40,6 +43,9 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution
/** The scale parameter. */
private double scale;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Creates weibull distribution with the given shape and scale and a
* location equal to zero.
@ -47,9 +53,22 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution
* @param beta the scale parameter.
*/
public WeibullDistributionImpl(double alpha, double beta){
this(alpha, beta, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
* Creates weibull distribution with the given shape, scale and inverse
* cumulative probability accuracy and a location equal to zero.
* @param alpha the shape parameter.
* @param beta the scale parameter.
* @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
* (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
*/
public WeibullDistributionImpl(double alpha, double beta, double inverseCumAccuracy){
super();
setShapeInternal(alpha);
setScaleInternal(beta);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
@ -83,6 +102,31 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution
return scale;
}
/**
* Returns the probability density for a particular point.
*
* @param x The point at which the density should be computed.
* @return The pdf at point x.
*/
@Override
public double density(double x) {
if (x < 0) {
return 0;
}
final double xscale = x / scale;
final double xscalepow = Math.pow(xscale, shape - 1);
/*
* Math.pow(x / scale, shape) =
* Math.pow(xscale, shape) =
* Math.pow(xscale, shape - 1) * xscale
*/
final double xscalepowshape = xscalepow * xscale;
return (shape / scale) * xscalepow * Math.exp(-xscalepowshape);
}
/**
* For this distribution, X, this method returns the critical point x, such
* that P(X &lt; x) = <code>p</code>.
@ -196,4 +240,15 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution
// use median
return Math.pow(scale * Math.log(2.0), 1.0 / shape);
}
/**
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy
*/
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
}

View File

@ -39,6 +39,12 @@ The <action> type attribute can be add,update,fix,remove.
</properties>
<body>
<release version="2.1" date="TBD" description="TBD">
<action dev="psteitz" type="update" issue="MATH-332" due-to="Mikkel Meyer Andersen">
Added density functions to remaining continuous distributions (F, T, Weibull, Cauchy).
As of Math 2.1, all continuous distributions implement density functions. The HasDensity
interface has been deprecated and in version 3.0, density(double) will be added to the
ContinuousDistribution interface.
</action>
<action dev="sebb" type="update" issue="MATH-337">
Changed equals() methods to use instanceof check rather than catching ClassCastException;
this also allows some null checks to be omitted.
@ -52,7 +58,8 @@ The <action> type attribute can be add,update,fix,remove.
</action>
<action dev="psteitz" type="fix" issue="MATH-282">
Resolved multiple problems leading to inaccuracy and/or failure to compute Normal,
ChiSquare and Poisson probabilities, Erf and Gamma functions.
ChiSquare and Poisson probabilities, Erf and Gamma functions. Made Brent solver
absolute accuracy configurable for all continuous distributions.
</action>
<action dev="luc" type="fix" issue="MATH-347" >
Fixed too stringent interval check in Brent solver: initial guess is now

View File

@ -34,28 +34,42 @@ public class CauchyDistributionTest extends ContinuousDistributionAbstractTest
super(arg0);
}
// --------------------- Override tolerance --------------
protected double defaultTolerance = NormalDistributionImpl.DEFAULT_INVERSE_ABSOLUTE_ACCURACY;
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(defaultTolerance);
}
//-------------- Implementations for abstract methods -----------------------
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public CauchyDistribution makeDistribution() {
return new CauchyDistributionImpl(1.2, 2.1);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using Mathematica
return new double[] {-667.2485619d, -65.6230835d, -25.48302995d,
-12.05887818d, -5.263135428d, 7.663135428d, 14.45887818d,
27.88302995d, 68.0230835d, 669.6485619d};
// quantiles computed using R 2.9.2
return new double[] {-667.24856187, -65.6230835029, -25.4830299460, -12.0588781808,
-5.26313542807, 669.64856187, 68.0230835029, 27.8830299460, 14.4588781808, 7.66313542807};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.900d, 0.950d,
0.975d, 0.990d, 0.999d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999,
0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {1.49599158008e-06, 0.000149550440335, 0.000933076881878, 0.00370933207799, 0.0144742330437,
1.49599158008e-06, 0.000149550440335, 0.000933076881878, 0.00370933207799, 0.0144742330437};
}
//---------------------------- Additional test cases -------------------------

View File

@ -38,23 +38,22 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public ChiSquaredDistribution makeDistribution() {
return new ChiSquaredDistributionImpl(5.0);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using R version 1.8.1 (linux version)
return new double[] {0.210216d, 0.5542981d, 0.8312116d, 1.145476d, 1.610308d,
20.51501d, 15.08627d, 12.83250d, 11.07050d, 9.236357d};
// quantiles computed using R version 2.9.2
return new double[] {0.210212602629, 0.554298076728, 0.831211613487, 1.14547622606, 1.61030798696,
20.5150056524, 15.0862724694, 12.8325019940, 11.0704976935, 9.23635689978};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d,
0.990d, 0.975d, 0.950d, 0.900d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
}
/** Creates the default inverse cumulative probability test input values */
@ -67,16 +66,23 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
/** Creates the default inverse cumulative probability density test expected values */
@Override
public double[] makeInverseCumulativeTestValues() {
return new double[] {0, 0.210216d, 0.5542981d, 0.8312116d, 1.145476d, 1.610308d,
20.51501d, 15.08627d, 12.83250d, 11.07050d, 9.236357d,
return new double[] {0, 0.210212602629, 0.554298076728, 0.831211613487, 1.14547622606, 1.61030798696,
20.5150056524, 15.0862724694, 12.8325019940, 11.0704976935, 9.23635689978,
Double.POSITIVE_INFINITY};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.0115379817652, 0.0415948507811, 0.0665060119842, 0.0919455953114, 0.121472591024,
0.000433630076361, 0.00412780610309, 0.00999340341045, 0.0193246438937, 0.0368460089216};
}
// --------------------- Override tolerance --------------
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(5e-6);
setTolerance(1e-9);
}
//---------------------------- Additional test cases -------------------------

View File

@ -34,6 +34,7 @@ import org.apache.commons.math.TestUtils;
* <p>
* makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
* makeCumulativeTestValues() -- expected cumulative probabilites
* makeDensityTestValues() -- expected density values at cumulativeTestPoints
* makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf
* makeInverseCumulativeTestValues() -- expected inverse cdf values
* <p>
@ -74,6 +75,9 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
/** Values used to test inverse cumulative probability density calculations */
private double[] inverseCumulativeTestValues;
/** Values used to test density calculations */
private double[] densityTestValues;
//-------------------------------------------------------------------------
/**
@ -89,12 +93,15 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
/** Creates the default continuous distribution instance to use in tests. */
public abstract ContinuousDistribution makeDistribution();
/** Creates the default cumulative probability density test input values */
/** Creates the default cumulative probability test input values */
public abstract double[] makeCumulativeTestPoints();
/** Creates the default cumulative probability density test expected values */
/** Creates the default cumulative probability test expected values */
public abstract double[] makeCumulativeTestValues();
/** Creates the default density test expected values */
public abstract double[] makeDensityTestValues();
//---- Default implementations of inverse test data generation methods ----
/** Creates the default inverse cumulative probability test input values */
@ -120,6 +127,7 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
cumulativeTestValues = makeCumulativeTestValues();
inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
inverseCumulativeTestValues = makeInverseCumulativeTestValues();
densityTestValues = makeDensityTestValues();
}
/**
@ -133,6 +141,7 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
cumulativeTestValues = null;
inverseCumulativeTestPoints = null;
inverseCumulativeTestValues = null;
densityTestValues = null;
}
//-------------------- Verification methods -------------------------------
@ -163,6 +172,19 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
}
}
/**
* Verifies that density calculations match expected values
*/
protected void verifyDensities() throws Exception {
for (int i = 0; i < cumulativeTestPoints.length; i++) {
TestUtils.assertEquals("Incorrect probability density value returned for "
+ cumulativeTestPoints[i], densityTestValues[i],
//TODO: remove cast when density(double) is added to ContinuousDistribution
((AbstractContinuousDistribution) distribution).density(cumulativeTestPoints[i]),
getTolerance());
}
}
//------------------------ Default test cases -----------------------------
/**
@ -181,6 +203,14 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
verifyInverseCumulativeProbabilities();
}
/**
* Verifies that density calculations return expected values
* for default test instance data
*/
public void testDensities() throws Exception {
verifyDensities();
}
/**
* Verifies that probability computations are consistent
*/
@ -256,6 +286,14 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
this.cumulativeTestValues = cumulativeTestValues;
}
protected double[] getDensityTestValues() {
return densityTestValues;
}
protected void setDensityTestValues(double[] densityTestValues) {
this.densityTestValues = densityTestValues;
}
/**
* @return Returns the distribution.
*/
@ -266,7 +304,7 @@ public abstract class ContinuousDistributionAbstractTest extends TestCase {
/**
* @param distribution The distribution to set.
*/
protected void setDistribution(ContinuousDistribution distribution) {
protected void setDistribution(AbstractContinuousDistribution distribution) {
this.distribution = distribution;
}

View File

@ -33,27 +33,41 @@ public class ExponentialDistributionTest extends ContinuousDistributionAbstractT
super(name);
}
// --------------------- Override tolerance --------------
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(1E-9);
}
//-------------- Implementations for abstract methods -----------------------
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public ExponentialDistribution makeDistribution() {
return new ExponentialDistributionImpl(5.0);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using R version 1.8.1 (linux version)
return new double[] {0.005002502d, 0.05025168d, 0.1265890d, 0.2564665d, 0.5268026d,
34.53878d, 23.02585d, 18.44440d, 14.97866d, 11.51293d};
// quantiles computed using R version 2.9.2
return new double[] {0.00500250166792, 0.0502516792675, 0.126589039921, 0.256466471938,
0.526802578289, 34.5387763949, 23.0258509299, 18.4443972706, 14.9786613678, 11.5129254650};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d,
0.990d, 0.975d, 0.950d, 0.900d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999,
0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.1998, 0.198, 0.195, 0.19, 0.18, 0.000200000000000,
0.00200000000002, 0.00499999999997, 0.00999999999994, 0.0199999999999};
}
//------------ Additional tests -------------------------------------------

View File

@ -38,31 +38,36 @@ public class FDistributionTest extends ContinuousDistributionAbstractTest {
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public FDistribution makeDistribution() {
return new FDistributionImpl(5.0, 6.0);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using R version 1.8.1 (linux version)
return new double[] {0.03468084d ,0.09370091d, 0.1433137d,
0.2020084d, 0.2937283d, 20.80266d, 8.745895d, 5.987565d,
4.387374d, 3.107512d};
// quantiles computed using R version 2.9.2
return new double[] {0.0346808448626, 0.0937009113303, 0.143313661184, 0.202008445998, 0.293728320107,
20.8026639595, 8.74589525602, 5.98756512605, 4.38737418741, 3.10751166664};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d,
0.990d, 0.975d, 0.950d, 0.900d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.0689156576706, 0.236735653193, 0.364074131941, 0.481570789649, 0.595880479994,
0.000133443915657, 0.00286681303403, 0.00969192007502, 0.0242883861471, 0.0605491314658};
}
// --------------------- Override tolerance --------------
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(4e-6);
setTolerance(1e-9);
}
//---------------------------- Additional test cases -------------------------

View File

@ -38,31 +38,36 @@ public class GammaDistributionTest extends ContinuousDistributionAbstractTest {
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public GammaDistribution makeDistribution() {
return new GammaDistributionImpl(4d, 2d);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using R version 1.8.1 (linux version)
return new double[] {0.8571048, 1.646497, 2.179731, 2.732637,
3.489539, 26.12448, 20.09024, 17.53455,
15.50731, 13.36157};
// quantiles computed using R version 2.9.2
return new double[] {0.857104827257, 1.64649737269, 2.17973074725, 2.7326367935, 3.48953912565,
26.1244815584, 20.0902350297, 17.5345461395, 15.5073130559, 13.3615661365};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d,
0.990d, 0.975d, 0.950d, 0.900d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.00427280075546, 0.0204117166709, 0.0362756163658, 0.0542113174239, 0.0773195272491,
0.000394468852816, 0.00366559696761, 0.00874649473311, 0.0166712508128, 0.0311798227954};
}
// --------------------- Override tolerance --------------
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(6e-6);
setTolerance(1e-9);
}
//---------------------------- Additional test cases -------------------------

View File

@ -40,7 +40,7 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public NormalDistribution makeDistribution() {
return new NormalDistributionImpl(2.1, 1.4);
}
@ -59,6 +59,13 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
0.990d, 0.975d, 0.950d, 0.900d};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.00240506434076, 0.0190372444310, 0.0417464784322, 0.0736683145538, 0.125355951380,
0.00240506434076, 0.0190372444310, 0.0417464784322, 0.0736683145538, 0.125355951380};
}
// --------------------- Override tolerance --------------
protected double defaultTolerance = NormalDistributionImpl.DEFAULT_INVERSE_ABSOLUTE_ACCURACY;
@Override
@ -83,11 +90,22 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
}
public void testQuantiles() throws Exception {
setDensityTestValues(new double[] {0.0385649760808, 0.172836231799, 0.284958771715, 0.172836231799, 0.0385649760808,
0.00316560600853, 9.55930184035e-05, 1.06194251052e-06});
verifyQuantiles();
verifyDensities();
setDistribution(new NormalDistributionImpl(0, 1));
setDensityTestValues(new double[] {0.0539909665132, 0.241970724519, 0.398942280401, 0.241970724519, 0.0539909665132,
0.00443184841194, 0.000133830225765, 1.48671951473e-06});
verifyQuantiles();
verifyDensities();
setDistribution(new NormalDistributionImpl(0, 0.1));
setDensityTestValues(new double[] {0.539909665132, 2.41970724519, 3.98942280401, 2.41970724519,
0.539909665132, 0.0443184841194, 0.00133830225765, 1.48671951473e-05});
verifyQuantiles();
verifyDensities();
}
public void testInverseCumulativeProbabilityExtremes() throws Exception {

View File

@ -37,31 +37,37 @@ public class TDistributionTest extends ContinuousDistributionAbstractTest {
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public TDistribution makeDistribution() {
return new TDistributionImpl(5.0);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using R version 1.8.1 (linux version)
return new double[] {-5.89343,-3.36493, -2.570582, -2.015048,
-1.475884, 0.0, 5.89343, 3.36493, 2.570582,
2.015048, 1.475884};
// quantiles computed using R version 2.9.2
return new double[] {-5.89342953136, -3.36492999891, -2.57058183564, -2.01504837333, -1.47588404882,
5.89342953136, 3.36492999891, 2.57058183564, 2.01504837333, 1.47588404882};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.5d, 0.999d,
0.990d, 0.975d, 0.950d, 0.900d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999,
0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.000756494565517, 0.0109109752919, 0.0303377878006, 0.0637967988952, 0.128289492005,
0.000756494565517, 0.0109109752919, 0.0303377878006, 0.0637967988952, 0.128289492005};
}
// --------------------- Override tolerance --------------
@Override
protected void setUp() throws Exception {
super.setUp();
setTolerance(1E-6);
setTolerance(1E-9);
}
//---------------------------- Additional test cases -------------------------
@ -77,14 +83,17 @@ public class TDistributionTest extends ContinuousDistributionAbstractTest {
public void testSmallDf() throws Exception {
setDistribution(new TDistributionImpl(1d));
setTolerance(1E-4);
// quantiles computed using R version 1.8.1 (linux version)
setCumulativeTestPoints(new double[] {-318.3088, -31.82052, -12.70620, -6.313752,
-3.077684, 0.0, 318.3088, 31.82052, 12.70620,
6.313752, 3.077684});
// quantiles computed using R version 2.9.2
setCumulativeTestPoints(new double[] {-318.308838986, -31.8205159538, -12.7062047362,
-6.31375151468, -3.07768353718, 318.308838986, 31.8205159538, 12.7062047362,
6.31375151468, 3.07768353718});
setDensityTestValues(new double[] {3.14158231817e-06, 0.000314055924703, 0.00195946145194,
0.00778959736375, 0.0303958893917, 3.14158231817e-06, 0.000314055924703,
0.00195946145194, 0.00778959736375, 0.0303958893917});
setInverseCumulativeTestValues(getCumulativeTestPoints());
verifyCumulativeProbabilities();
verifyInverseCumulativeProbabilities();
verifyDensities();
}
public void testInverseCumulativeProbabilityExtremes() throws Exception {

View File

@ -38,24 +38,29 @@ public class WeibullDistributionTest extends ContinuousDistributionAbstractTest
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ContinuousDistribution makeDistribution() {
public WeibullDistribution makeDistribution() {
return new WeibullDistributionImpl(1.2, 2.1);
}
/** Creates the default cumulative probability distribution test input values */
@Override
public double[] makeCumulativeTestPoints() {
// quantiles computed using Mathematica
return new double[] {0.00664355181d, 0.04543282833d, 0.09811627374d,
0.1767135246d, 0.3219468654d, 4.207902826d, 5.23968437d,
6.232056007d, 7.497630467d, 10.51154969d};
// quantiles computed using R version 2.9.2
return new double[] {0.00664355180993, 0.0454328283309, 0.0981162737374, 0.176713524579, 0.321946865392,
10.5115496887, 7.4976304671, 6.23205600701, 5.23968436955, 4.2079028257};
}
/** Creates the default cumulative probability density test expected values */
@Override
public double[] makeCumulativeTestValues() {
return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.900d, 0.950d,
0.975d, 0.990d, 0.999d};
return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
}
/** Creates the default probability density test expected values */
@Override
public double[] makeDensityTestValues() {
return new double[] {0.180535929306, 0.262801138133, 0.301905425199, 0.330899152971,
0.353441418887, 0.000788590320203, 0.00737060094841, 0.0177576041516, 0.0343043442574, 0.065664589369};
}
//---------------------------- Additional test cases -------------------------

View File

@ -218,7 +218,7 @@ public class RandomDataTest extends RetryTestCase {
}
}
/* TODO: re-enable when MATH-282 is resolved
public void testNextPoissonConsistency() throws Exception {
// Small integral means
for (int i = 1; i < 100; i++) {
@ -235,7 +235,6 @@ public class RandomDataTest extends RetryTestCase {
checkNextPoissonConsistency(randomData.nextUniform(1000, 3000));
}
}
*/
/**
* Verifies that nextPoisson(mean) generates an empirical distribution of values