BinomialDistribution.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math3.distribution;

  18. import org.apache.commons.math3.exception.NotPositiveException;
  19. import org.apache.commons.math3.exception.OutOfRangeException;
  20. import org.apache.commons.math3.exception.util.LocalizedFormats;
  21. import org.apache.commons.math3.random.RandomGenerator;
  22. import org.apache.commons.math3.random.Well19937c;
  23. import org.apache.commons.math3.special.Beta;
  24. import org.apache.commons.math3.util.FastMath;

  25. /**
  26.  * Implementation of the binomial distribution.
  27.  *
  28.  * @see <a href="http://en.wikipedia.org/wiki/Binomial_distribution">Binomial distribution (Wikipedia)</a>
  29.  * @see <a href="http://mathworld.wolfram.com/BinomialDistribution.html">Binomial Distribution (MathWorld)</a>
  30.  */
  31. public class BinomialDistribution extends AbstractIntegerDistribution {
  32.     /** Serializable version identifier. */
  33.     private static final long serialVersionUID = 6751309484392813623L;
  34.     /** The number of trials. */
  35.     private final int numberOfTrials;
  36.     /** The probability of success. */
  37.     private final double probabilityOfSuccess;

  38.     /**
  39.      * Create a binomial distribution with the given number of trials and
  40.      * probability of success.
  41.      * <p>
  42.      * <b>Note:</b> this constructor will implicitly create an instance of
  43.      * {@link Well19937c} as random generator to be used for sampling only (see
  44.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  45.      * needed for the created distribution, it is advised to pass {@code null}
  46.      * as random generator via the appropriate constructors to avoid the
  47.      * additional initialisation overhead.
  48.      *
  49.      * @param trials Number of trials.
  50.      * @param p Probability of success.
  51.      * @throws NotPositiveException if {@code trials < 0}.
  52.      * @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
  53.      */
  54.     public BinomialDistribution(int trials, double p) {
  55.         this(new Well19937c(), trials, p);
  56.     }

  57.     /**
  58.      * Creates a binomial distribution.
  59.      *
  60.      * @param rng Random number generator.
  61.      * @param trials Number of trials.
  62.      * @param p Probability of success.
  63.      * @throws NotPositiveException if {@code trials < 0}.
  64.      * @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
  65.      * @since 3.1
  66.      */
  67.     public BinomialDistribution(RandomGenerator rng,
  68.                                 int trials,
  69.                                 double p) {
  70.         super(rng);

  71.         if (trials < 0) {
  72.             throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
  73.                                            trials);
  74.         }
  75.         if (p < 0 || p > 1) {
  76.             throw new OutOfRangeException(p, 0, 1);
  77.         }

  78.         probabilityOfSuccess = p;
  79.         numberOfTrials = trials;
  80.     }

  81.     /**
  82.      * Access the number of trials for this distribution.
  83.      *
  84.      * @return the number of trials.
  85.      */
  86.     public int getNumberOfTrials() {
  87.         return numberOfTrials;
  88.     }

  89.     /**
  90.      * Access the probability of success for this distribution.
  91.      *
  92.      * @return the probability of success.
  93.      */
  94.     public double getProbabilityOfSuccess() {
  95.         return probabilityOfSuccess;
  96.     }

  97.     /** {@inheritDoc} */
  98.     public double probability(int x) {
  99.         final double logProbability = logProbability(x);
  100.         return logProbability == Double.NEGATIVE_INFINITY ? 0 : FastMath.exp(logProbability);
  101.     }

  102.     /** {@inheritDoc} **/
  103.     @Override
  104.     public double logProbability(int x) {
  105.         if (numberOfTrials == 0) {
  106.             return (x == 0) ? 0. : Double.NEGATIVE_INFINITY;
  107.         }
  108.         double ret;
  109.         if (x < 0 || x > numberOfTrials) {
  110.             ret = Double.NEGATIVE_INFINITY;
  111.         } else {
  112.             ret = SaddlePointExpansion.logBinomialProbability(x,
  113.                     numberOfTrials, probabilityOfSuccess,
  114.                     1.0 - probabilityOfSuccess);
  115.         }
  116.         return ret;
  117.     }

  118.     /** {@inheritDoc} */
  119.     public double cumulativeProbability(int x) {
  120.         double ret;
  121.         if (x < 0) {
  122.             ret = 0.0;
  123.         } else if (x >= numberOfTrials) {
  124.             ret = 1.0;
  125.         } else {
  126.             ret = 1.0 - Beta.regularizedBeta(probabilityOfSuccess,
  127.                     x + 1.0, numberOfTrials - x);
  128.         }
  129.         return ret;
  130.     }

  131.     /**
  132.      * {@inheritDoc}
  133.      *
  134.      * For {@code n} trials and probability parameter {@code p}, the mean is
  135.      * {@code n * p}.
  136.      */
  137.     public double getNumericalMean() {
  138.         return numberOfTrials * probabilityOfSuccess;
  139.     }

  140.     /**
  141.      * {@inheritDoc}
  142.      *
  143.      * For {@code n} trials and probability parameter {@code p}, the variance is
  144.      * {@code n * p * (1 - p)}.
  145.      */
  146.     public double getNumericalVariance() {
  147.         final double p = probabilityOfSuccess;
  148.         return numberOfTrials * p * (1 - p);
  149.     }

  150.     /**
  151.      * {@inheritDoc}
  152.      *
  153.      * The lower bound of the support is always 0 except for the probability
  154.      * parameter {@code p = 1}.
  155.      *
  156.      * @return lower bound of the support (0 or the number of trials)
  157.      */
  158.     public int getSupportLowerBound() {
  159.         return probabilityOfSuccess < 1.0 ? 0 : numberOfTrials;
  160.     }

  161.     /**
  162.      * {@inheritDoc}
  163.      *
  164.      * The upper bound of the support is the number of trials except for the
  165.      * probability parameter {@code p = 0}.
  166.      *
  167.      * @return upper bound of the support (number of trials or 0)
  168.      */
  169.     public int getSupportUpperBound() {
  170.         return probabilityOfSuccess > 0.0 ? numberOfTrials : 0;
  171.     }

  172.     /**
  173.      * {@inheritDoc}
  174.      *
  175.      * The support of this distribution is connected.
  176.      *
  177.      * @return {@code true}
  178.      */
  179.     public boolean isSupportConnected() {
  180.         return true;
  181.     }
  182. }