From f237f93ed211b3c08ab93f32ce78ab46387d1694 Mon Sep 17 00:00:00 2001 From: Mikkel Meyer Andersen Date: Sun, 26 Dec 2010 22:51:54 +0000 Subject: [PATCH] Fixes MATH-385 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/branches/MATH_2_X@1052978 13f79535-47bb-0310-9956-ffa450edef68 --- .../AbstractContinuousDistribution.java | 13 +++ .../distribution/AbstractDistribution.java | 108 ++++++++++++++++++ .../AbstractIntegerDistribution.java | 38 ++++++ .../distribution/BetaDistributionImpl.java | 69 +++++++++++ .../BinomialDistributionImpl.java | 58 ++++++++++ .../distribution/CauchyDistributionImpl.java | 64 +++++++++++ .../ChiSquaredDistributionImpl.java | 63 ++++++++++ .../math/distribution/Distribution.java | 55 +++++++++ .../ExponentialDistributionImpl.java | 63 ++++++++++ .../math/distribution/FDistributionImpl.java | 91 +++++++++++++++ .../distribution/GammaDistributionImpl.java | 66 +++++++++++ .../HypergeometricDistributionImpl.java | 70 ++++++++++++ .../distribution/NormalDistributionImpl.java | 66 +++++++++++ .../distribution/PascalDistributionImpl.java | 69 +++++++++++ .../distribution/PoissonDistributionImpl.java | 57 +++++++++ .../math/distribution/TDistributionImpl.java | 87 ++++++++++++++ .../distribution/WeibullDistributionImpl.java | 74 ++++++++++++ .../distribution/ZipfDistributionImpl.java | 74 ++++++++++++ .../distribution/BetaDistributionTest.java | 15 +++ .../BinomialDistributionTest.java | 14 +++ .../distribution/CauchyDistributionTest.java | 14 +++ .../ChiSquareDistributionTest.java | 13 +++ .../ExponentialDistributionTest.java | 13 +++ .../math/distribution/FDistributionTest.java | 18 +++ .../distribution/GammaDistributionTest.java | 14 +++ .../HypergeometricDistributionTest.java | 15 +++ .../distribution/NormalDistributionTest.java | 18 +++ .../distribution/PascalDistributionTest.java | 14 +++ .../distribution/PoissonDistributionTest.java | 13 +++ .../math/distribution/TDistributionTest.java | 16 +++ .../distribution/WeibullDistributionTest.java | 20 ++++ .../distribution/ZipfDistributionTest.java | 11 ++ 32 files changed, 1393 insertions(+) diff --git a/src/main/java/org/apache/commons/math/distribution/AbstractContinuousDistribution.java b/src/main/java/org/apache/commons/math/distribution/AbstractContinuousDistribution.java index 7b3827e3d..b0550d2ff 100644 --- a/src/main/java/org/apache/commons/math/distribution/AbstractContinuousDistribution.java +++ b/src/main/java/org/apache/commons/math/distribution/AbstractContinuousDistribution.java @@ -228,4 +228,17 @@ public abstract class AbstractContinuousDistribution return solverAbsoluteAccuracy; } + /** + * Access the lower bound of the support. + * + * @return lower bound of the support (might be Double.NEGATIVE_INFINITY) + */ + public abstract double getSupportLowerBound(); + + /** + * Access the upper bound of the support. + * + * @return upper bound of the support (might be Double.POSITIVE_INFINITY) + */ + public abstract double getSupportUpperBound(); } diff --git a/src/main/java/org/apache/commons/math/distribution/AbstractDistribution.java b/src/main/java/org/apache/commons/math/distribution/AbstractDistribution.java index 8c22e4f63..11a4064c1 100644 --- a/src/main/java/org/apache/commons/math/distribution/AbstractDistribution.java +++ b/src/main/java/org/apache/commons/math/distribution/AbstractDistribution.java @@ -33,6 +33,12 @@ public abstract class AbstractDistribution /** Serializable version identifier */ private static final long serialVersionUID = -38038050983108802L; + private double numericalMean = Double.NaN; + private boolean numericalMeanIsCalculated = false; + + private double numericalVariance = Double.NaN; + private boolean numericalVarianceIsCalculated = false; + /** * Default constructor. */ @@ -66,4 +72,106 @@ public abstract class AbstractDistribution } return cumulativeProbability(x1) - cumulativeProbability(x0); } + + /** + * This method invalidates cached moments when parameters change. + * Usually it is called from a sub-class when the distribution + * gets its parameters updated. + * + * @deprecated as of 2.2 (sub-classes will become immutable in 3.0) + */ + @Deprecated + protected void invalidateParameterDependentMoments() { + numericalMeanIsCalculated = false; + numericalVarianceIsCalculated = false; + } + + /** + * Use this method to actually calculate the mean for the + * specific distribution. Use {@link #getNumericalMean()} + * (which implements caching) to actually get the mean. + * + * @return the mean or Double.NaN if it's not defined + */ + protected abstract double calculateNumericalMean(); + + /** + * Use this method to get the numerical value of the mean of this + * distribution. + * + * @return the mean or Double.NaN if it's not defined + */ + public double getNumericalMean() { + if (!numericalMeanIsCalculated) { + numericalMean = calculateNumericalMean(); + numericalMeanIsCalculated = true; + } + + return numericalMean; + } + + /** + * Use this method to actually calculate the variance for the + * specific distribution. Use {@link #getNumericalVariance()} + * (which implements caching) to actually get the variance. + * + * @return the variance or Double.NaN if it's not defined + */ + protected abstract double calculateNumericalVariance(); + + /** + * Use this method to get the numerical value of the variance of this + * distribution. + * + * @return the variance (possibly Double.POSITIVE_INFINITY as + * for certain cases in {@link TDistributionImpl}) or + * Double.NaN if it's not defined + */ + public double getNumericalVariance() { + if (!numericalVarianceIsCalculated) { + numericalVariance = calculateNumericalVariance(); + numericalVarianceIsCalculated = true; + } + + return numericalVariance; + } + + /** + * Use this method to get information about whether the lower bound + * of the support is inclusive or not. + * + * @return whether the lower bound of the support is inclusive or not + */ + public abstract boolean isSupportLowerBoundInclusive(); + + /** + * Use this method to get information about whether the upper bound + * of the support is inclusive or not. + * + * @return whether the upper bound of the support is inclusive or not + */ + public abstract boolean isSupportUpperBoundInclusive(); + + /** + * Use this method to get information about whether the support is connected, + * i.e. whether all values between the lower and upper bound of the support + * is included in the support. + * + * For {@link AbstractIntegerDistribution} the support is discrete, so + * if this is true, then the support is + * {lower bound, lower bound + 1, ..., upper bound}. + * + * For {@link AbstractContinuousDistribution} the support is continuous, so + * if this is true, then the support is the interval + * [lower bound, upper bound] + * where the limits are inclusive or not according to + * {@link #isSupportLowerBoundInclusive()} and {@link #isSupportUpperBoundInclusive()} + * (in the example both are true). If both are false, then the support is the interval + * (lower bound, upper bound) + * + * @return whether the support limits given by subclassed methods are connected or not + */ + public boolean isSupportConnected() { + return true; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/AbstractIntegerDistribution.java b/src/main/java/org/apache/commons/math/distribution/AbstractIntegerDistribution.java index be420a55b..63bcdf8e8 100644 --- a/src/main/java/org/apache/commons/math/distribution/AbstractIntegerDistribution.java +++ b/src/main/java/org/apache/commons/math/distribution/AbstractIntegerDistribution.java @@ -291,4 +291,42 @@ public abstract class AbstractIntegerDistribution extends AbstractDistribution * P(X < upper bound) > p */ protected abstract int getDomainUpperBound(double p); + + /** + * Access the lower bound of the support. + * + * @return lower bound of the support (Integer.MIN_VALUE for negative infinity) + */ + public abstract int getSupportLowerBound(); + + /** + * Access the upper bound of the support. + * + * @return upper bound of the support (Integer.MAX_VALUE for positive infinity) + */ + public abstract int getSupportUpperBound(); + + /** + * Use this method to get information about whether the lower bound + * of the support is inclusive or not. For discrete support, + * only true here is meaningful. + * + * @return true (always but at Integer.MIN_VALUE because of the nature of discrete support) + */ + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + /** + * Use this method to get information about whether the upper bound + * of the support is inclusive or not. For discrete support, + * only true here is meaningful. + * + * @return true (always but at Integer.MAX_VALUE because of the nature of discrete support) + */ + @Override + public boolean isSupportUpperBoundInclusive() { + return true; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/BetaDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/BetaDistributionImpl.java index af099d8cc..e67ef8b4d 100644 --- a/src/main/java/org/apache/commons/math/distribution/BetaDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/BetaDistributionImpl.java @@ -92,6 +92,7 @@ public class BetaDistributionImpl public void setAlpha(double alpha) { this.alpha = alpha; z = Double.NaN; + invalidateParameterDependentMoments(); } /** {@inheritDoc} */ @@ -106,6 +107,7 @@ public class BetaDistributionImpl public void setBeta(double beta) { this.beta = beta; z = Double.NaN; + invalidateParameterDependentMoments(); } /** {@inheritDoc} */ @@ -223,4 +225,71 @@ public class BetaDistributionImpl protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the parameters. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always 1 no matter the parameters. + * + * @return upper bound of the support (always 1) + */ + @Override + public double getSupportUpperBound() { + return 1; + } + + /** + * {@inheritDoc} + * + * For first shape parameter s1 and + * second shape parameter s2, the mean is + * s1 / (s1 + s2) + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final double alpha = getAlpha(); + return alpha / (alpha + getBeta()); + } + + /** + * {@inheritDoc} + * + * For first shape parameter s1 and + * second shape parameter s2, + * the variance is + * [ s1 * s2 ] / [ (s1 + s2)^2 * (s1 + s2 + 1) ] + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double alpha = getAlpha(); + final double beta = getBeta(); + final double alphabetasum = alpha + beta; + return (alpha * beta) / ((alphabetasum * alphabetasum) * (alphabetasum + 1)); + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return false; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/BinomialDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/BinomialDistributionImpl.java index eaf83bc4c..899734615 100644 --- a/src/main/java/org/apache/commons/math/distribution/BinomialDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/BinomialDistributionImpl.java @@ -83,7 +83,9 @@ public class BinomialDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setNumberOfTrials(int trials) { setNumberOfTrialsInternal(trials); + invalidateParameterDependentMoments(); } + /** * Change the number of trials for this distribution. * @@ -110,7 +112,9 @@ public class BinomialDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setProbabilityOfSuccess(double p) { setProbabilityOfSuccessInternal(p); + invalidateParameterDependentMoments(); } + /** * Change the probability of success for this distribution. * @@ -220,4 +224,58 @@ public class BinomialDistributionImpl extends AbstractIntegerDistribution // use default bisection impl return super.inverseCumulativeProbability(p); } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the number of trials + * and probability parameter. + * + * @return lower bound of the support (always 0) + */ + @Override + public int getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is the number of trials. + * + * @return upper bound of the support (equal to number of trials) + */ + @Override + public int getSupportUpperBound() { + return getNumberOfTrials(); + } + + /** + * {@inheritDoc} + * + * For n number of trials and + * probability parameter p, the mean is + * n * p + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return (double)getNumberOfTrials() * getProbabilityOfSuccess(); + } + + /** + * {@inheritDoc} + * + * For n number of trials and + * probability parameter p, the variance is + * n * p * (1 - p) + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double p = getProbabilityOfSuccess(); + return (double)getNumberOfTrials() * p * (1 - p); + } } diff --git a/src/main/java/org/apache/commons/math/distribution/CauchyDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/CauchyDistributionImpl.java index 7b79a1bf6..4be6e3bd0 100644 --- a/src/main/java/org/apache/commons/math/distribution/CauchyDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/CauchyDistributionImpl.java @@ -157,7 +157,9 @@ public class CauchyDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setMedian(double median) { setMedianInternal(median); + invalidateParameterDependentMoments(); } + /** * Modify the median. * @param newMedian for this distribution @@ -175,7 +177,9 @@ public class CauchyDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setScale(double s) { setScaleInternal(s); + invalidateParameterDependentMoments(); } + /** * Modify the scale parameter. * @param s scale parameter for this distribution @@ -267,4 +271,64 @@ public class CauchyDistributionImpl extends AbstractContinuousDistribution protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always negative infinity no matter + * the parameters. + * + * @return lower bound of the support (always Double.NEGATIVE_INFINITY) + */ + @Override + public double getSupportLowerBound() { + return Double.NEGATIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity no matter + * the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * The mean is always undefined no matter the parameters. + * + * @return mean (always Double.NaN) + */ + @Override + protected double calculateNumericalMean() { + return Double.NaN; + } + + /** + * {@inheritDoc} + * + * The variance is always undefined no matter the parameters. + * + * @return variance (always Double.NaN) + */ + @Override + protected double calculateNumericalVariance() { + return Double.NaN; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return false; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/ChiSquaredDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/ChiSquaredDistributionImpl.java index 04d28b25c..bbe3884dd 100644 --- a/src/main/java/org/apache/commons/math/distribution/ChiSquaredDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/ChiSquaredDistributionImpl.java @@ -91,6 +91,7 @@ public class ChiSquaredDistributionImpl @Deprecated public void setDegreesOfFreedom(double degreesOfFreedom) { setDegreesOfFreedomInternal(degreesOfFreedom); + invalidateParameterDependentMoments(); } /** * Modify the degrees of freedom. @@ -269,4 +270,66 @@ public class ChiSquaredDistributionImpl protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the + * degrees of freedom. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity no matter the + * degrees of freedom. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For k degrees of freedom, the mean is + * k + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return getDegreesOfFreedom(); + } + + /** + * {@inheritDoc} + * + * For k degrees of freedom, the variance is + * 2 * k + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + return 2*getDegreesOfFreedom(); + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/Distribution.java b/src/main/java/org/apache/commons/math/distribution/Distribution.java index fda80033b..3edc3a4d2 100644 --- a/src/main/java/org/apache/commons/math/distribution/Distribution.java +++ b/src/main/java/org/apache/commons/math/distribution/Distribution.java @@ -52,4 +52,59 @@ public interface Distribution { * @throws IllegalArgumentException if x0 > x1 */ double cumulativeProbability(double x0, double x1) throws MathException; + + /** + * Use this method to get the numerical value of the mean of this + * distribution. + * + * @return the mean or Double.NaN if it's not defined + */ + double getNumericalMean(); + + /** + * Use this method to get the numerical value of the variance of this + * distribution. + * + * @return the variance (possibly Double.POSITIVE_INFINITY as + * for certain cases in {@link TDistributionImpl}) or + * Double.NaN if it's not defined + */ + double getNumericalVariance(); + + /** + * Use this method to get information about whether the lower bound + * of the support is inclusive or not. + * + * @return whether the lower bound of the support is inclusive or not + */ + boolean isSupportLowerBoundInclusive(); + + /** + * Use this method to get information about whether the upper bound + * of the support is inclusive or not. + * + * @return whether the upper bound of the support is inclusive or not + */ + boolean isSupportUpperBoundInclusive(); + + /** + * Use this method to get information about whether the support is connected, + * i.e. whether all values between the lower and upper bound of the support + * is included in the support. + * + * For {@link AbstractIntegerDistribution} the support is discrete, so + * if this is true, then the support is + * {lower bound, lower bound + 1, ..., upper bound}. + * + * For {@link AbstractContinuousDistribution} the support is continuous, so + * if this is true, then the support is the interval + * [lower bound, upper bound] + * where the limits are inclusive or not according to + * {@link #isSupportLowerBoundInclusive()} and {@link #isSupportUpperBoundInclusive()} + * (in the example both are true). If both are false, then the support is the interval + * (lower bound, upper bound) + * + * @return whether the support limits given by subclassed methods are connected or not + */ + boolean isSupportConnected(); } diff --git a/src/main/java/org/apache/commons/math/distribution/ExponentialDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/ExponentialDistributionImpl.java index 9b295fb29..d434c2eab 100644 --- a/src/main/java/org/apache/commons/math/distribution/ExponentialDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/ExponentialDistributionImpl.java @@ -76,6 +76,7 @@ public class ExponentialDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setMean(double mean) { setMeanInternal(mean); + invalidateParameterDependentMoments(); } /** * Modify the mean. @@ -263,4 +264,66 @@ public class ExponentialDistributionImpl extends AbstractContinuousDistribution protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the mean parameter. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the mean parameter. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For mean parameter k, the mean is + * k + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return getMean(); + } + + /** + * {@inheritDoc} + * + * For mean parameter k, the variance is + * k^2 + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double mean = getMean(); + return mean * mean; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/FDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/FDistributionImpl.java index 624be0acd..db8d48c66 100644 --- a/src/main/java/org/apache/commons/math/distribution/FDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/FDistributionImpl.java @@ -209,6 +209,7 @@ public class FDistributionImpl @Deprecated public void setNumeratorDegreesOfFreedom(double degreesOfFreedom) { setNumeratorDegreesOfFreedomInternal(degreesOfFreedom); + invalidateParameterDependentMoments(); } /** @@ -243,6 +244,7 @@ public class FDistributionImpl @Deprecated public void setDenominatorDegreesOfFreedom(double degreesOfFreedom) { setDenominatorDegreesOfFreedomInternal(degreesOfFreedom); + invalidateParameterDependentMoments(); } /** @@ -278,4 +280,93 @@ public class FDistributionImpl protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the parameters. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For denominator degrees of freedom parameter b, + * the mean is + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final double denominatorDF = getDenominatorDegreesOfFreedom(); + + if (denominatorDF > 2) { + return denominatorDF / (denominatorDF - 2); + } + + return Double.NaN; + } + + /** + * {@inheritDoc} + * + * For numerator degrees of freedom parameter a + * and denominator degrees of freedom parameter b, + * the variance is + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double denominatorDF = getDenominatorDegreesOfFreedom(); + + if (denominatorDF > 4) { + final double numeratorDF = getNumeratorDegreesOfFreedom(); + final double denomDFMinusTwo = denominatorDF - 2; + + return ( 2 * (denominatorDF * denominatorDF) * (numeratorDF + denominatorDF - 2) ) + / ( (numeratorDF * (denomDFMinusTwo * denomDFMinusTwo) * (denominatorDF - 4)) ); + } + + return Double.NaN; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/GammaDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/GammaDistributionImpl.java index bbc3ec173..4a971c763 100644 --- a/src/main/java/org/apache/commons/math/distribution/GammaDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/GammaDistributionImpl.java @@ -137,6 +137,7 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setAlpha(double alpha) { setAlphaInternal(alpha); + invalidateParameterDependentMoments(); } /** @@ -170,6 +171,7 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setBeta(double newBeta) { setBetaInternal(newBeta); + invalidateParameterDependentMoments(); } /** @@ -298,4 +300,68 @@ public class GammaDistributionImpl extends AbstractContinuousDistribution protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the parameters. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For shape parameter alpha and scale + * parameter beta, the mean is + * alpha * beta + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return getAlpha() * getBeta(); + } + + /** + * {@inheritDoc} + * + * For shape parameter alpha and scale + * parameter beta, the variance is + * alpha * beta^2 + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double beta = getBeta(); + return getAlpha() * beta * beta; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java index b2a6bbbd6..610c3ff73 100644 --- a/src/main/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java @@ -241,7 +241,9 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setNumberOfSuccesses(int num) { setNumberOfSuccessesInternal(num); + invalidateParameterDependentMoments(); } + /** * Modify the number of successes. * @@ -266,7 +268,9 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setPopulationSize(int size) { setPopulationSizeInternal(size); + invalidateParameterDependentMoments(); } + /** * Modify the population size. * @@ -291,6 +295,7 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setSampleSize(int size) { setSampleSizeInternal(size); + invalidateParameterDependentMoments(); } /** * Modify the sample size. @@ -351,4 +356,69 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution } return ret; } + + /** + * {@inheritDoc} + * + * For population size N, + * number of successes m, and + * sample size n, + * the lower bound of the support is + * max(0, n + m - N) + * + * @return lower bound of the support + */ + @Override + public int getSupportLowerBound() { + return FastMath.max(0, + getSampleSize() + getNumberOfSuccesses() - getPopulationSize()); + } + + /** + * {@inheritDoc} + * + * For number of successes m and + * sample size n, + * the upper bound of the support is + * min(m, n) + * + * @return upper bound of the support + */ + @Override + public int getSupportUpperBound() { + return FastMath.min(getNumberOfSuccesses(), getSampleSize()); + } + + /** + * {@inheritDoc} + * + * For population size N, + * number of successes m, and + * sample size n, the mean is + * n * m / N + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return (double)(getSampleSize() * getNumberOfSuccesses()) / (double)getPopulationSize(); + } + + /** + * {@inheritDoc} + * + * For population size N, + * number of successes m, and + * sample size n, the variance is + * [ n * m * (N - n) * (N - m) ] / [ N^2 * (N - 1) ] + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double N = getPopulationSize(); + final double m = getNumberOfSuccesses(); + final double n = getSampleSize(); + return ( n * m * (N - n) * (N - m) ) / ( (N*N * (N - 1)) ); + } } diff --git a/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java index 4bc45706b..75660fd0c 100644 --- a/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java @@ -104,7 +104,9 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setMean(double mean) { setMeanInternal(mean); + invalidateParameterDependentMoments(); } + /** * Modify the mean. * @param newMean for this distribution @@ -130,7 +132,9 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setStandardDeviation(double sd) { setStandardDeviationInternal(sd); + invalidateParameterDependentMoments(); } + /** * Modify the standard deviation. * @param sd standard deviation for this distribution @@ -304,4 +308,66 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution return ret; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always negative infinity + * no matter the parameters. + * + * @return lower bound of the support (always Double.NEGATIVE_INFINITY) + */ + @Override + public double getSupportLowerBound() { + return Double.NEGATIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For mean parameter mu, the mean is mu + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return getMean(); + } + + /** + * {@inheritDoc} + * + * For standard deviation parameter s, + * the variance is s^2 + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double s = getStandardDeviation(); + return s * s; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return false; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/PascalDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/PascalDistributionImpl.java index 7cc7b0ed6..d7ae88248 100644 --- a/src/main/java/org/apache/commons/math/distribution/PascalDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/PascalDistributionImpl.java @@ -80,7 +80,9 @@ public class PascalDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setNumberOfSuccesses(int successes) { setNumberOfSuccessesInternal(successes); + invalidateParameterDependentMoments(); } + /** * Change the number of successes for this distribution. * @param successes the new number of successes @@ -106,7 +108,9 @@ public class PascalDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setProbabilityOfSuccess(double p) { setProbabilityOfSuccessInternal(p); + invalidateParameterDependentMoments(); } + /** * Change the probability of success for this distribution. * @param p the new probability of success @@ -211,4 +215,69 @@ public class PascalDistributionImpl extends AbstractIntegerDistribution return ret; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the parameters. + * + * @return lower bound of the support (always 0) + */ + @Override + public int getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. Positive infinity is symbolised + * by Integer.MAX_VALUE together with + * {@link #isSupportUpperBoundInclusive()} being false + * + * @return upper bound of the support (always Integer.MAX_VALUE for positive infinity) + */ + @Override + public int getSupportUpperBound() { + return Integer.MAX_VALUE; + } + + /** + * {@inheritDoc} + * + * For number of successes r and + * probability of success p, the mean is + * ( r * p ) / ( 1 - p ) + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final double p = getProbabilityOfSuccess(); + final double r = getNumberOfSuccesses(); + return ( r * p ) / ( 1 - p ); + } + + /** + * {@inheritDoc} + * + * For number of successes r and + * probability of success p, the mean is + * ( r * p ) / ( 1 - p )^2 + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double p = getProbabilityOfSuccess(); + final double r = getNumberOfSuccesses(); + final double pInv = 1 - p; + return ( r * p ) / (pInv * pInv); + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/PoissonDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/PoissonDistributionImpl.java index 64f792b60..5654e6873 100644 --- a/src/main/java/org/apache/commons/math/distribution/PoissonDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/PoissonDistributionImpl.java @@ -157,6 +157,7 @@ public class PoissonDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setMean(double p) { setNormalAndMeanInternal(normal, p); + invalidateParameterDependentMoments(); } /** * Set the Poisson mean for the distribution. The mean value must be @@ -300,4 +301,60 @@ public class PoissonDistributionImpl extends AbstractIntegerDistribution public void setNormal(NormalDistribution value) { setNormalAndMeanInternal(value, mean); } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the mean parameter. + * + * @return lower bound of the support (always 0) + */ + @Override + public int getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is positive infinity, + * regardless of the parameter values. There is no integer infinity, + * so this method returns Integer.MAX_VALUE and + * {@link #isSupportUpperBoundInclusive()} returns true. + * + * @return upper bound of the support (always Integer.MAX_VALUE for positive infinity) + */ + @Override + public int getSupportUpperBound() { + return Integer.MAX_VALUE; + } + + /** + * {@inheritDoc} + * + * For mean parameter p, the mean is p + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + return getMean(); + } + + /** + * {@inheritDoc} + * + * For mean parameter p, the variance is p + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + return getMean(); + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return true; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/TDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/TDistributionImpl.java index 3f0bbfbeb..f5c2951bc 100644 --- a/src/main/java/org/apache/commons/math/distribution/TDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/TDistributionImpl.java @@ -81,7 +81,9 @@ public class TDistributionImpl @Deprecated public void setDegreesOfFreedom(double degreesOfFreedom) { setDegreesOfFreedomInternal(degreesOfFreedom); + invalidateParameterDependentMoments(); } + /** * Modify the degrees of freedom. * @param newDegreesOfFreedom the new degrees of freedom. @@ -223,4 +225,89 @@ public class TDistributionImpl protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always negative infinity + * no matter the parameters. + * + * @return lower bound of the support (always Double.NEGATIVE_INFINITY) + */ + @Override + public double getSupportLowerBound() { + return Double.NEGATIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * For degrees of freedom parameter df, the mean is + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final double df = getDegreesOfFreedom(); + + if (df > 1) { + return 0; + } + + return Double.NaN; + } + + /** + * {@inheritDoc} + * + * For degrees of freedom parameter df, the variance is + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double df = getDegreesOfFreedom(); + + if (df > 2) { + return df / (df - 2); + } + + if (df > 1 && df <= 2) { + return Double.POSITIVE_INFINITY; + } + + return Double.NaN; + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return false; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/WeibullDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/WeibullDistributionImpl.java index 706986e48..01fb93391 100644 --- a/src/main/java/org/apache/commons/math/distribution/WeibullDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/WeibullDistributionImpl.java @@ -21,6 +21,7 @@ import java.io.Serializable; import org.apache.commons.math.MathRuntimeException; import org.apache.commons.math.exception.util.LocalizedFormats; +import org.apache.commons.math.special.Gamma; import org.apache.commons.math.util.FastMath; /** @@ -170,6 +171,7 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setShape(double alpha) { setShapeInternal(alpha); + invalidateParameterDependentMoments(); } /** * Modify the shape parameter. @@ -192,6 +194,7 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution @Deprecated public void setScale(double beta) { setScaleInternal(beta); + invalidateParameterDependentMoments(); } /** * Modify the scale parameter. @@ -259,4 +262,75 @@ public class WeibullDistributionImpl extends AbstractContinuousDistribution protected double getSolverAbsoluteAccuracy() { return solverAbsoluteAccuracy; } + + /** + * {@inheritDoc} + * + * The lower bound of the support is always 0 no matter the parameters. + * + * @return lower bound of the support (always 0) + */ + @Override + public double getSupportLowerBound() { + return 0; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is always positive infinity + * no matter the parameters. + * + * @return upper bound of the support (always Double.POSITIVE_INFINITY) + */ + @Override + public double getSupportUpperBound() { + return Double.POSITIVE_INFINITY; + } + + /** + * {@inheritDoc} + * + * The mean is scale * Gamma(1 + (1 / shape)) + * where Gamma(...) is the Gamma-function + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final double shape = getShape(); + final double scale = getScale(); + + return scale * FastMath.exp(Gamma.logGamma(1 + (1 / shape))); + } + + /** + * {@inheritDoc} + * + * The variance is + * scale^2 * Gamma(1 + (2 / shape)) - mean^2 + * where Gamma(...) is the Gamma-function + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final double shape = getShape(); + final double scale = getScale(); + final double mean = getNumericalMean(); + + return (scale * scale) * + FastMath.exp(Gamma.logGamma(1 + (2 / shape))) - + (mean * mean); + } + + @Override + public boolean isSupportLowerBoundInclusive() { + return true; + } + + @Override + public boolean isSupportUpperBoundInclusive() { + return false; + } } diff --git a/src/main/java/org/apache/commons/math/distribution/ZipfDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/ZipfDistributionImpl.java index c643f7f25..008b67dd0 100644 --- a/src/main/java/org/apache/commons/math/distribution/ZipfDistributionImpl.java +++ b/src/main/java/org/apache/commons/math/distribution/ZipfDistributionImpl.java @@ -76,6 +76,7 @@ public class ZipfDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setNumberOfElements(final int n) { setNumberOfElementsInternal(n); + invalidateParameterDependentMoments(); } /** * Set the number of elements (e.g. corpus size) for the distribution. @@ -115,7 +116,9 @@ public class ZipfDistributionImpl extends AbstractIntegerDistribution @Deprecated public void setExponent(final double s) { setExponentInternal(s); + invalidateParameterDependentMoments(); } + /** * Set the exponent characterising the distribution. * The parameter value must be positive; otherwise an @@ -211,4 +214,75 @@ public class ZipfDistributionImpl extends AbstractIntegerDistribution return value; } + /** + * {@inheritDoc} + * + * The lower bound of the support is always 1 no matter the parameters. + * + * @return lower bound of the support (always 1) + */ + @Override + public int getSupportLowerBound() { + return 1; + } + + /** + * {@inheritDoc} + * + * The upper bound of the support is the number of elements + * + * @return upper bound of the support + */ + @Override + public int getSupportUpperBound() { + return getNumberOfElements(); + } + + /** + * {@inheritDoc} + * + * For number of elements N and exponent s, the mean is + * Hs1 / Hs where + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalMean() { + final int N = getNumberOfElements(); + final double s = getExponent(); + + final double Hs1 = generalizedHarmonic(N, s - 1); + final double Hs = generalizedHarmonic(N, s); + + return Hs1 / Hs; + } + + /** + * {@inheritDoc} + * + * For number of elements N and exponent s, the mean is + * (Hs2 / Hs) - (Hs1^2 / Hs^2) where + * + * + * @return {@inheritDoc} + */ + @Override + protected double calculateNumericalVariance() { + final int N = getNumberOfElements(); + final double s = getExponent(); + + final double Hs2 = generalizedHarmonic(N, s - 2); + final double Hs1 = generalizedHarmonic(N, s - 1); + final double Hs = generalizedHarmonic(N, s); + + return (Hs2 / Hs) - ((Hs1 * Hs1) / (Hs * Hs)); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/BetaDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/BetaDistributionTest.java index af8166e69..b5197c13d 100644 --- a/src/test/java/org/apache/commons/math/distribution/BetaDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/BetaDistributionTest.java @@ -18,6 +18,7 @@ package org.apache.commons.math.distribution; import junit.framework.TestCase; import org.apache.commons.math.MathException; +import org.apache.commons.math.util.FastMath; public class BetaDistributionTest extends TestCase { public void testCumulative() throws MathException { @@ -286,4 +287,18 @@ public class BetaDistributionTest extends TestCase { assertEquals(String.format("density at x=%.1f for alpha=%.1f, beta=%.1f", x[i], alpha, beta), expected[i], d.density(x[i]), 1e-5); } } + + public void testMomonts() { + final double tol = 1e-9; + BetaDistribution dist; + + dist = new BetaDistributionImpl(1, 1); + assertEquals(dist.getNumericalMean(), 0.5, tol); + assertEquals(dist.getNumericalVariance(), 1.0 / 12.0, tol); + + dist.setAlpha(2); + dist.setBeta(5); + assertEquals(dist.getNumericalMean(), 2.0 / 7.0, tol); + assertEquals(dist.getNumericalVariance(), 10.0 / (49.0 * 8.0), tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/BinomialDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/BinomialDistributionTest.java index c6073670d..d52cd0ef6 100644 --- a/src/test/java/org/apache/commons/math/distribution/BinomialDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/BinomialDistributionTest.java @@ -113,4 +113,18 @@ public class BinomialDistributionTest extends IntegerDistributionAbstractTest { verifyInverseCumulativeProbabilities(); } + public void testMomonts() { + final double tol = 1e-9; + BinomialDistribution dist; + + dist = new BinomialDistributionImpl(10, 0.5); + assertEquals(dist.getNumericalMean(), 10d * 0.5d, tol); + assertEquals(dist.getNumericalVariance(), 10d * 0.5d * 0.5d, tol); + + dist.setNumberOfTrials(30); + dist.setProbabilityOfSuccess(0.3); + assertEquals(dist.getNumericalMean(), 30d * 0.3d, tol); + assertEquals(dist.getNumericalVariance(), 30d * 0.3d * (1d - 0.3d), tol); + } + } diff --git a/src/test/java/org/apache/commons/math/distribution/CauchyDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/CauchyDistributionTest.java index 8dad7e858..3aa50296c 100644 --- a/src/test/java/org/apache/commons/math/distribution/CauchyDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/CauchyDistributionTest.java @@ -113,4 +113,18 @@ public class CauchyDistributionTest extends ContinuousDistributionAbstractTest // success } } + + public void testMomonts() { + final double tol = 1e-9; + CauchyDistribution dist; + + dist = new CauchyDistributionImpl(10.2, 0.15); + assertEquals(dist.getNumericalMean(), Double.NaN, tol); + assertEquals(dist.getNumericalVariance(), Double.NaN, tol); + + dist.setMedian(23.12); + dist.setScale(2.12); + assertEquals(dist.getNumericalMean(), Double.NaN, tol); + assertEquals(dist.getNumericalVariance(), Double.NaN, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/ChiSquareDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/ChiSquareDistributionTest.java index 895ab70b4..4a5b9a0d2 100644 --- a/src/test/java/org/apache/commons/math/distribution/ChiSquareDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/ChiSquareDistributionTest.java @@ -132,4 +132,17 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes } } + public void testMomonts() { + final double tol = 1e-9; + ChiSquaredDistribution dist; + + dist = new ChiSquaredDistributionImpl(1500); + assertEquals(dist.getNumericalMean(), 1500, tol); + assertEquals(dist.getNumericalVariance(), 3000, tol); + + dist.setDegreesOfFreedom(1.12); + assertEquals(dist.getNumericalMean(), 1.12, tol); + assertEquals(dist.getNumericalVariance(), 2.24, tol); + } + } diff --git a/src/test/java/org/apache/commons/math/distribution/ExponentialDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/ExponentialDistributionTest.java index 5662bcf18..c99088d20 100644 --- a/src/test/java/org/apache/commons/math/distribution/ExponentialDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/ExponentialDistributionTest.java @@ -121,4 +121,17 @@ public class ExponentialDistributionTest extends ContinuousDistributionAbstractT } } + + public void testMomonts() { + final double tol = 1e-9; + ExponentialDistribution dist; + + dist = new ExponentialDistributionImpl(11d); + assertEquals(dist.getNumericalMean(), 11d, tol); + assertEquals(dist.getNumericalVariance(), 11d * 11d, tol); + + dist.setMean(10.5d); + assertEquals(dist.getNumericalMean(), 10.5d, tol); + assertEquals(dist.getNumericalVariance(), 10.5d * 10.5d, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/FDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/FDistributionTest.java index c69dcd60e..630419b59 100644 --- a/src/test/java/org/apache/commons/math/distribution/FDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/FDistributionTest.java @@ -129,4 +129,22 @@ public class FDistributionTest extends ContinuousDistributionAbstractTest { assertEquals(0.975, x, 1.0e-5); } + public void testMomonts() { + final double tol = 1e-9; + FDistribution dist; + + dist = new FDistributionImpl(1, 2); + assertEquals(dist.getNumericalMean(), Double.NaN, tol); + assertEquals(dist.getNumericalVariance(), Double.NaN, tol); + + dist.setNumeratorDegreesOfFreedom(1); + dist.setDenominatorDegreesOfFreedom(3); + assertEquals(dist.getNumericalMean(), 3d / (3d - 2d), tol); + assertEquals(dist.getNumericalVariance(), Double.NaN, tol); + + dist.setNumeratorDegreesOfFreedom(1); + dist.setDenominatorDegreesOfFreedom(5); + assertEquals(dist.getNumericalMean(), 5d / (5d - 2d), tol); + assertEquals(dist.getNumericalVariance(), (2d * 5d * 5d * 4d) / 9d, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/GammaDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/GammaDistributionTest.java index 840a0d7d5..007985fa5 100644 --- a/src/test/java/org/apache/commons/math/distribution/GammaDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/GammaDistributionTest.java @@ -152,4 +152,18 @@ public class GammaDistributionTest extends ContinuousDistributionAbstractTest { setInverseCumulativeTestValues(new double[] {0, Double.POSITIVE_INFINITY}); verifyInverseCumulativeProbabilities(); } + + public void testMomonts() { + final double tol = 1e-9; + GammaDistribution dist; + + dist = new GammaDistributionImpl(1, 2); + assertEquals(dist.getNumericalMean(), 2, tol); + assertEquals(dist.getNumericalVariance(), 4, tol); + + dist.setAlpha(1.1); + dist.setBeta(4.2); + assertEquals(dist.getNumericalMean(), 1.1d * 4.2d, tol); + assertEquals(dist.getNumericalVariance(), 1.1d * 4.2d * 4.2d, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/HypergeometricDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/HypergeometricDistributionTest.java index 4b638d457..94f5573e1 100644 --- a/src/test/java/org/apache/commons/math/distribution/HypergeometricDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/HypergeometricDistributionTest.java @@ -211,4 +211,19 @@ public class HypergeometricDistributionTest extends IntegerDistributionAbstractT }; testHypergeometricDistributionProbabilities(populationSize, sampleSize, numberOfSucceses, data); } + + public void testMomonts() { + final double tol = 1e-9; + HypergeometricDistribution dist; + + dist = new HypergeometricDistributionImpl(1500, 40, 100); + assertEquals(dist.getNumericalMean(), 40d * 100d / 1500d, tol); + assertEquals(dist.getNumericalVariance(), ( 100d * 40d * (1500d - 100d) * (1500d - 40d) ) / ( (1500d * 1500d * 1499d) ), tol); + + dist.setPopulationSize(3000); + dist.setNumberOfSuccesses(55); + dist.setSampleSize(200); + assertEquals(dist.getNumericalMean(), 55d * 200d / 3000d, tol); + assertEquals(dist.getNumericalVariance(), ( 200d * 55d * (3000d - 200d) * (3000d - 55d) ) / ( (3000d * 3000d * 2999d) ), tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java index c9ed3d214..a3752cf4a 100644 --- a/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java @@ -204,4 +204,22 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest assertEquals(2.0, result, defaultTolerance); } + public void testMomonts() { + final double tol = 1e-9; + NormalDistribution dist; + + dist = new NormalDistributionImpl(0, 1); + assertEquals(dist.getNumericalMean(), 0, tol); + assertEquals(dist.getNumericalVariance(), 1, tol); + + dist.setMean(2.2); + dist.setStandardDeviation(1.4); + assertEquals(dist.getNumericalMean(), 2.2, tol); + assertEquals(dist.getNumericalVariance(), 1.4 * 1.4, tol); + + dist.setMean(-2000.9); + dist.setStandardDeviation(10.4); + assertEquals(dist.getNumericalMean(), -2000.9, tol); + assertEquals(dist.getNumericalVariance(), 10.4 * 10.4, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/PascalDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/PascalDistributionTest.java index fbff95006..f6f6a877b 100644 --- a/src/test/java/org/apache/commons/math/distribution/PascalDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/PascalDistributionTest.java @@ -119,4 +119,18 @@ public class PascalDistributionTest extends IntegerDistributionAbstractTest { verifyCumulativeProbabilities(); verifyInverseCumulativeProbabilities(); } + + public void testMomonts() { + final double tol = 1e-9; + PascalDistribution dist; + + dist = new PascalDistributionImpl(10, 0.5); + assertEquals(dist.getNumericalMean(), ( 10d * 0.5d ) / 0.5d, tol); + assertEquals(dist.getNumericalVariance(), ( 10d * 0.5d ) / (0.5d * 0.5d), tol); + + dist.setNumberOfSuccesses(25); + dist.setProbabilityOfSuccess(0.3); + assertEquals(dist.getNumericalMean(), ( 25d * 0.3d ) / 0.7d, tol); + assertEquals(dist.getNumericalVariance(), ( 25d * 0.3d ) / (0.7d * 0.7d), tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/PoissonDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/PoissonDistributionTest.java index 06f455e1b..f3475c2cf 100644 --- a/src/test/java/org/apache/commons/math/distribution/PoissonDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/PoissonDistributionTest.java @@ -217,4 +217,17 @@ public class PoissonDistributionTest extends IntegerDistributionAbstractTest { mean *= 10.0; } } + + public void testMomonts() { + final double tol = 1e-9; + PoissonDistribution dist; + + dist = new PoissonDistributionImpl(1); + assertEquals(dist.getNumericalMean(), 1, tol); + assertEquals(dist.getNumericalVariance(), 1, tol); + + dist.setMean(11.23); + assertEquals(dist.getNumericalMean(), 11.23, tol); + assertEquals(dist.getNumericalVariance(), 11.23, tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/TDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/TDistributionTest.java index 9c9fd75de..8360c6172 100644 --- a/src/test/java/org/apache/commons/math/distribution/TDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/TDistributionTest.java @@ -116,4 +116,20 @@ public class TDistributionTest extends ContinuousDistributionAbstractTest { } } + public void testMomonts() { + final double tol = 1e-9; + TDistribution dist; + + dist = new TDistributionImpl(1); + assertEquals(dist.getNumericalMean(), Double.NaN, tol); + assertEquals(dist.getNumericalVariance(), Double.NaN, tol); + + dist.setDegreesOfFreedom(1.5); + assertEquals(dist.getNumericalMean(), 0, tol); + assertEquals(dist.getNumericalVariance(), Double.POSITIVE_INFINITY, tol); + + dist.setDegreesOfFreedom(5); + assertEquals(dist.getNumericalMean(), 0, tol); + assertEquals(dist.getNumericalVariance(), 5d / (5d - 2d), tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/WeibullDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/WeibullDistributionTest.java index cfd8cd963..861428271 100644 --- a/src/test/java/org/apache/commons/math/distribution/WeibullDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/WeibullDistributionTest.java @@ -17,6 +17,7 @@ package org.apache.commons.math.distribution; +import org.apache.commons.math.special.Gamma; import org.apache.commons.math.util.FastMath; /** @@ -121,4 +122,23 @@ public class WeibullDistributionTest extends ContinuousDistributionAbstractTest // success } } + + public void testMomonts() { + final double tol = 1e-9; + WeibullDistribution dist; + + dist = new WeibullDistributionImpl(2.5, 3.5); + // In R: 3.5*gamma(1+(1/2.5)) (or emperically: mean(rweibull(10000, 2.5, 3.5))) + assertEquals(dist.getNumericalMean(), 3.5 * FastMath.exp(Gamma.logGamma(1 + (1 / 2.5))), tol); + assertEquals(dist.getNumericalVariance(), (3.5 * 3.5) * + FastMath.exp(Gamma.logGamma(1 + (2 / 2.5))) - + (dist.getNumericalMean() * dist.getNumericalMean()), tol); + + dist.setShape(10.4); + dist.setScale(2.222); + assertEquals(dist.getNumericalMean(), 2.222 * FastMath.exp(Gamma.logGamma(1 + (1 / 10.4))), tol); + assertEquals(dist.getNumericalVariance(), (2.222 * 2.222) * + FastMath.exp(Gamma.logGamma(1 + (2 / 10.4))) - + (dist.getNumericalMean() * dist.getNumericalMean()), tol); + } } diff --git a/src/test/java/org/apache/commons/math/distribution/ZipfDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/ZipfDistributionTest.java index 08b867571..b4132cc74 100644 --- a/src/test/java/org/apache/commons/math/distribution/ZipfDistributionTest.java +++ b/src/test/java/org/apache/commons/math/distribution/ZipfDistributionTest.java @@ -17,6 +17,8 @@ package org.apache.commons.math.distribution; +import org.apache.commons.math.util.FastMath; + /** * Test cases for {@link ZipfDistribution}. * Extends IntegerDistributionAbstractTest. See class javadoc for @@ -75,4 +77,13 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest { public int[] makeInverseCumulativeTestValues() { return new int[] {0, 0, 0, 0, 0, 0, 1, 9, 9, 9, 8, 7, 10}; } + + public void testMomonts() { + final double tol = 1e-9; + ZipfDistribution dist; + + dist = new ZipfDistributionImpl(2, 0.5); + assertEquals(dist.getNumericalMean(), FastMath.sqrt(2), tol); + assertEquals(dist.getNumericalVariance(), 0.24264068711928521, tol); + } }