Merged BinomialDistribution and BinomialDistributionImpl (MATH-711).

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1205963 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sebastien Brisard 2011-11-24 19:37:34 +00:00
parent 936b937517
commit a0817f428e
5 changed files with 169 additions and 241 deletions

View File

@ -16,31 +16,175 @@
*/
package org.apache.commons.math.distribution;
import java.io.Serializable;
import org.apache.commons.math.exception.OutOfRangeException;
import org.apache.commons.math.exception.NotPositiveException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.special.Beta;
import org.apache.commons.math.util.FastMath;
/**
* The Binomial Distribution.
*
* <p>
* References:
* <ul>
* <li><a href="http://mathworld.wolfram.com/BinomialDistribution.html">
* Binomial Distribution</a></li>
* </ul>
* </p>
* Implementation of the binomial distribution.
*
* @see <a href="http://en.wikipedia.org/wiki/Binomial_distribution">Binomial distribution (Wikipedia)</a>
* @see <a href="http://mathworld.wolfram.com/BinomialDistribution.html">Binomial Distribution (MathWorld)</a>
* @version $Id$
*/
public interface BinomialDistribution extends IntegerDistribution {
public class BinomialDistribution extends AbstractIntegerDistribution
implements Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 6751309484392813623L;
/** The number of trials. */
private final int numberOfTrials;
/** The probability of success. */
private final double probabilityOfSuccess;
/**
* Create a binomial distribution with the given number of trials and
* probability of success.
*
* @param trials Number of trials.
* @param p Probability of success.
* @throws NotPositiveException if {@code trials < 0}.
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
*/
public BinomialDistribution(int trials, double p) {
if (trials < 0) {
throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
trials);
}
if (p < 0 || p > 1) {
throw new OutOfRangeException(p, 0, 1);
}
probabilityOfSuccess = p;
numberOfTrials = trials;
}
/**
* Access the number of trials for this distribution.
*
* @return the number of trials.
*/
int getNumberOfTrials();
public int getNumberOfTrials() {
return numberOfTrials;
}
/**
* Access the probability of success for this distribution.
*
* @return the probability of success.
*/
double getProbabilityOfSuccess();
public double getProbabilityOfSuccess() {
return probabilityOfSuccess;
}
/** {@inheritDoc} */
@Override
protected int getDomainLowerBound(double p) {
return -1;
}
/** {@inheritDoc} */
@Override
protected int getDomainUpperBound(double p) {
return numberOfTrials;
}
/** {@inheritDoc} */
@Override
public double cumulativeProbability(int x) {
double ret;
if (x < 0) {
ret = 0.0;
} else if (x >= numberOfTrials) {
ret = 1.0;
} else {
ret = 1.0 - Beta.regularizedBeta(getProbabilityOfSuccess(),
x + 1.0, numberOfTrials - x);
}
return ret;
}
/** {@inheritDoc} */
public double probability(int x) {
double ret;
if (x < 0 || x > numberOfTrials) {
ret = 0.0;
} else {
ret = FastMath.exp(SaddlePointExpansion.logBinomialProbability(x,
numberOfTrials, probabilityOfSuccess,
1.0 - probabilityOfSuccess));
}
return ret;
}
/**
* {@inheritDoc}
*
* This implementation return -1 when {@code p == 0} and
* {@code Integer.MAX_VALUE} when {@code p == 1}.
*/
@Override
public int inverseCumulativeProbability(final double p) {
// handle extreme values explicitly
if (p == 0) {
return -1;
}
if (p == 1) {
return Integer.MAX_VALUE;
}
// 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 {@code n} trials and probability parameter {@code p}, the mean is
* {@code n * p}.
*/
@Override
protected double calculateNumericalMean() {
return getNumberOfTrials() * getProbabilityOfSuccess();
}
/**
* {@inheritDoc}
*
* For {@code n} trials and probability parameter {@code p}, the variance is
* {@code n * p * (1 - p)}.
*/
@Override
protected double calculateNumericalVariance() {
final double p = getProbabilityOfSuccess();
return getNumberOfTrials() * p * (1 - p);
}
}

View File

@ -1,216 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math.distribution;
import java.io.Serializable;
import org.apache.commons.math.exception.OutOfRangeException;
import org.apache.commons.math.exception.NotPositiveException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.special.Beta;
import org.apache.commons.math.util.FastMath;
/**
* The default implementation of {@link BinomialDistribution}.
*
* @version $Id$
*/
public class BinomialDistributionImpl extends AbstractIntegerDistribution
implements BinomialDistribution, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 6751309484392813623L;
/** The number of trials. */
private final int numberOfTrials;
/** The probability of success. */
private final double probabilityOfSuccess;
/**
* Create a binomial distribution with the given number of trials and
* probability of success.
*
* @param trials Number of trials.
* @param p Probability of success.
* @throws NotPositiveException if {@code trials < 0}.
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
*/
public BinomialDistributionImpl(int trials, double p) {
if (trials < 0) {
throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
trials);
}
if (p < 0 || p > 1) {
throw new OutOfRangeException(p, 0, 1);
}
probabilityOfSuccess = p;
numberOfTrials = trials;
}
/**
* {@inheritDoc}
*/
public int getNumberOfTrials() {
return numberOfTrials;
}
/**
* {@inheritDoc}
*/
public double getProbabilityOfSuccess() {
return probabilityOfSuccess;
}
/**
* Access the domain value lower bound, based on {@code p}, used to
* bracket a PDF root.
*
* @param p Desired probability for the critical value.
* @return the domain value lower bound, i.e. {@code P(X < 'lower bound') < p}.
*/
@Override
protected int getDomainLowerBound(double p) {
return -1;
}
/**
* Access the domain value upper bound, based on {@code p}, used to
* bracket a PDF root.
*
* @param p Desired probability for the critical value
* @return the domain value upper bound, i.e. {@code P(X < 'upper bound') > p}.
*/
@Override
protected int getDomainUpperBound(double p) {
return numberOfTrials;
}
/**
* For this distribution, {@code X}, this method returns {@code P(X <= x)}.
*
* @param x Value at which the PDF is evaluated.
* @return PDF for this distribution.
* due to convergence or other numerical errors.
*/
@Override
public double cumulativeProbability(int x) {
double ret;
if (x < 0) {
ret = 0.0;
} else if (x >= numberOfTrials) {
ret = 1.0;
} else {
ret = 1.0 - Beta.regularizedBeta(getProbabilityOfSuccess(),
x + 1.0, numberOfTrials - x);
}
return ret;
}
/**
* For this distribution, {@code X}, this method returns {@code P(X = x)}.
*
* @param x Value at which the PMF is evaluated.
* @return PMF for this distribution.
*/
public double probability(int x) {
double ret;
if (x < 0 || x > numberOfTrials) {
ret = 0.0;
} else {
ret = FastMath.exp(SaddlePointExpansion.logBinomialProbability(x,
numberOfTrials, probabilityOfSuccess,
1.0 - probabilityOfSuccess));
}
return ret;
}
/**
* For this distribution, {@code X}, this method returns the largest
* {@code x}, such that {@code P(X < x) p}.
* It will return -1 when p = 0 and {@code Integer.MAX_VALUE} when p = 1.
*
* @param p Desired probability.
* @return the largest {@code x} such that {@code P(X < x) <= p}.
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
*/
@Override
public int inverseCumulativeProbability(final double p) {
// handle extreme values explicitly
if (p == 0) {
return -1;
}
if (p == 1) {
return Integer.MAX_VALUE;
}
// 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 <code>n</code> number of trials and
* probability parameter <code>p</code>, the mean is
* <code>n * p</code>
*
* @return {@inheritDoc}
*/
@Override
protected double calculateNumericalMean() {
return (double)getNumberOfTrials() * getProbabilityOfSuccess();
}
/**
* {@inheritDoc}
*
* For <code>n</code> number of trials and
* probability parameter <code>p</code>, the variance is
* <code>n * p * (1 - p)</code>
*
* @return {@inheritDoc}
*/
@Override
protected double calculateNumericalVariance() {
final double p = getProbabilityOfSuccess();
return (double)getNumberOfTrials() * p * (1 - p);
}
}

View File

@ -25,7 +25,7 @@ import java.security.SecureRandom;
import java.util.Collection;
import org.apache.commons.math.distribution.BetaDistribution;
import org.apache.commons.math.distribution.BinomialDistributionImpl;
import org.apache.commons.math.distribution.BinomialDistribution;
import org.apache.commons.math.distribution.CauchyDistributionImpl;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
import org.apache.commons.math.distribution.ContinuousDistribution;
@ -613,7 +613,7 @@ public class RandomDataImpl implements RandomData, Serializable {
}
/**
* Generates a random value from the {@link BinomialDistributionImpl Binomial Distribution}.
* Generates a random value from the {@link BinomialDistribution Binomial Distribution}.
* This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
* to generate random values.
*
@ -623,7 +623,7 @@ public class RandomDataImpl implements RandomData, Serializable {
* @since 2.2
*/
public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) {
return nextInversionDeviate(new BinomialDistributionImpl(numberOfTrials, probabilityOfSuccess));
return nextInversionDeviate(new BinomialDistribution(numberOfTrials, probabilityOfSuccess));
}
/**

View File

@ -31,7 +31,7 @@ public class BinomialDistributionTest extends IntegerDistributionAbstractTest {
/** Creates the default discrete distribution instance to use in tests. */
@Override
public IntegerDistribution makeDistribution() {
return new BinomialDistributionImpl(10, 0.70);
return new BinomialDistribution(10, 0.70);
}
/** Creates the default probability density test input values */
@ -82,7 +82,7 @@ public class BinomialDistributionTest extends IntegerDistributionAbstractTest {
/** Test degenerate case p = 0 */
@Test
public void testDegenerate0() throws Exception {
setDistribution(new BinomialDistributionImpl(5, 0.0d));
setDistribution(new BinomialDistribution(5, 0.0d));
setCumulativeTestPoints(new int[] { -1, 0, 1, 5, 10 });
setCumulativeTestValues(new double[] { 0d, 1d, 1d, 1d, 1d });
setDensityTestPoints(new int[] { -1, 0, 1, 10, 11 });
@ -97,7 +97,7 @@ public class BinomialDistributionTest extends IntegerDistributionAbstractTest {
/** Test degenerate case p = 1 */
@Test
public void testDegenerate1() throws Exception {
setDistribution(new BinomialDistributionImpl(5, 1.0d));
setDistribution(new BinomialDistribution(5, 1.0d));
setCumulativeTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
setCumulativeTestValues(new double[] { 0d, 0d, 0d, 0d, 1d, 1d });
setDensityTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
@ -113,12 +113,12 @@ public class BinomialDistributionTest extends IntegerDistributionAbstractTest {
public void testMoments() {
final double tol = 1e-9;
BinomialDistribution dist;
dist = new BinomialDistributionImpl(10, 0.5);
dist = new BinomialDistribution(10, 0.5);
Assert.assertEquals(dist.getNumericalMean(), 10d * 0.5d, tol);
Assert.assertEquals(dist.getNumericalVariance(), 10d * 0.5d * 0.5d, tol);
dist = new BinomialDistributionImpl(30, 0.3);
Assert.assertEquals(dist.getNumericalVariance(), 10d * 0.5d * 0.5d, tol);
dist = new BinomialDistribution(30, 0.3);
Assert.assertEquals(dist.getNumericalMean(), 30d * 0.3d, tol);
Assert.assertEquals(dist.getNumericalVariance(), 30d * 0.3d * (1d - 0.3d), tol);
}

View File

@ -26,7 +26,7 @@ import org.apache.commons.math.Retry;
import org.apache.commons.math.RetryRunner;
import org.apache.commons.math.TestUtils;
import org.apache.commons.math.distribution.BetaDistribution;
import org.apache.commons.math.distribution.BinomialDistributionImpl;
import org.apache.commons.math.distribution.BinomialDistribution;
import org.apache.commons.math.distribution.BinomialDistributionTest;
import org.apache.commons.math.distribution.CauchyDistributionImpl;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
@ -963,7 +963,7 @@ public class RandomDataTest {
double[] densityValues = testInstance.makeDensityTestValues();
int sampleSize = 1000;
int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
BinomialDistributionImpl distribution = (BinomialDistributionImpl) testInstance.makeDistribution();
BinomialDistribution distribution = (BinomialDistribution) testInstance.makeDistribution();
double[] expectedCounts = new double[length];
long[] observedCounts = new long[length];
for (int i = 0; i < length; i++) {