BetaDistribution.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.NumberIsTooSmallException;
  19. import org.apache.commons.math3.exception.util.LocalizedFormats;
  20. import org.apache.commons.math3.random.RandomGenerator;
  21. import org.apache.commons.math3.random.Well19937c;
  22. import org.apache.commons.math3.special.Beta;
  23. import org.apache.commons.math3.special.Gamma;
  24. import org.apache.commons.math3.util.FastMath;

  25. /**
  26.  * Implements the Beta distribution.
  27.  *
  28.  * @see <a href="http://en.wikipedia.org/wiki/Beta_distribution">Beta distribution</a>
  29.  * @since 2.0 (changed to concrete class in 3.0)
  30.  */
  31. public class BetaDistribution extends AbstractRealDistribution {
  32.     /**
  33.      * Default inverse cumulative probability accuracy.
  34.      * @since 2.1
  35.      */
  36.     public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
  37.     /** Serializable version identifier. */
  38.     private static final long serialVersionUID = -1221965979403477668L;
  39.     /** First shape parameter. */
  40.     private final double alpha;
  41.     /** Second shape parameter. */
  42.     private final double beta;
  43.     /** Normalizing factor used in density computations.
  44.      * updated whenever alpha or beta are changed.
  45.      */
  46.     private double z;
  47.     /** Inverse cumulative probability accuracy. */
  48.     private final double solverAbsoluteAccuracy;

  49.     /**
  50.      * Build a new instance.
  51.      * <p>
  52.      * <b>Note:</b> this constructor will implicitly create an instance of
  53.      * {@link Well19937c} as random generator to be used for sampling only (see
  54.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  55.      * needed for the created distribution, it is advised to pass {@code null}
  56.      * as random generator via the appropriate constructors to avoid the
  57.      * additional initialisation overhead.
  58.      *
  59.      * @param alpha First shape parameter (must be positive).
  60.      * @param beta Second shape parameter (must be positive).
  61.      */
  62.     public BetaDistribution(double alpha, double beta) {
  63.         this(alpha, beta, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
  64.     }

  65.     /**
  66.      * Build a new instance.
  67.      * <p>
  68.      * <b>Note:</b> this constructor will implicitly create an instance of
  69.      * {@link Well19937c} as random generator to be used for sampling only (see
  70.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  71.      * needed for the created distribution, it is advised to pass {@code null}
  72.      * as random generator via the appropriate constructors to avoid the
  73.      * additional initialisation overhead.
  74.      *
  75.      * @param alpha First shape parameter (must be positive).
  76.      * @param beta Second shape parameter (must be positive).
  77.      * @param inverseCumAccuracy Maximum absolute error in inverse
  78.      * cumulative probability estimates (defaults to
  79.      * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
  80.      * @since 2.1
  81.      */
  82.     public BetaDistribution(double alpha, double beta, double inverseCumAccuracy) {
  83.         this(new Well19937c(), alpha, beta, inverseCumAccuracy);
  84.     }

  85.     /**
  86.      * Creates a &beta; distribution.
  87.      *
  88.      * @param rng Random number generator.
  89.      * @param alpha First shape parameter (must be positive).
  90.      * @param beta Second shape parameter (must be positive).
  91.      * @since 3.3
  92.      */
  93.     public BetaDistribution(RandomGenerator rng, double alpha, double beta) {
  94.         this(rng, alpha, beta, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
  95.     }

  96.     /**
  97.      * Creates a &beta; distribution.
  98.      *
  99.      * @param rng Random number generator.
  100.      * @param alpha First shape parameter (must be positive).
  101.      * @param beta Second shape parameter (must be positive).
  102.      * @param inverseCumAccuracy Maximum absolute error in inverse
  103.      * cumulative probability estimates (defaults to
  104.      * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
  105.      * @since 3.1
  106.      */
  107.     public BetaDistribution(RandomGenerator rng,
  108.                             double alpha,
  109.                             double beta,
  110.                             double inverseCumAccuracy) {
  111.         super(rng);

  112.         this.alpha = alpha;
  113.         this.beta = beta;
  114.         z = Double.NaN;
  115.         solverAbsoluteAccuracy = inverseCumAccuracy;
  116.     }

  117.     /**
  118.      * Access the first shape parameter, {@code alpha}.
  119.      *
  120.      * @return the first shape parameter.
  121.      */
  122.     public double getAlpha() {
  123.         return alpha;
  124.     }

  125.     /**
  126.      * Access the second shape parameter, {@code beta}.
  127.      *
  128.      * @return the second shape parameter.
  129.      */
  130.     public double getBeta() {
  131.         return beta;
  132.     }

  133.     /** Recompute the normalization factor. */
  134.     private void recomputeZ() {
  135.         if (Double.isNaN(z)) {
  136.             z = Gamma.logGamma(alpha) + Gamma.logGamma(beta) - Gamma.logGamma(alpha + beta);
  137.         }
  138.     }

  139.     /** {@inheritDoc} */
  140.     public double density(double x) {
  141.         final double logDensity = logDensity(x);
  142.         return logDensity == Double.NEGATIVE_INFINITY ? 0 : FastMath.exp(logDensity);
  143.     }

  144.     /** {@inheritDoc} **/
  145.     @Override
  146.     public double logDensity(double x) {
  147.         recomputeZ();
  148.         if (x < 0 || x > 1) {
  149.             return Double.NEGATIVE_INFINITY;
  150.         } else if (x == 0) {
  151.             if (alpha < 1) {
  152.                 throw new NumberIsTooSmallException(LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_0_FOR_SOME_ALPHA, alpha, 1, false);
  153.             }
  154.             return Double.NEGATIVE_INFINITY;
  155.         } else if (x == 1) {
  156.             if (beta < 1) {
  157.                 throw new NumberIsTooSmallException(LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_1_FOR_SOME_BETA, beta, 1, false);
  158.             }
  159.             return Double.NEGATIVE_INFINITY;
  160.         } else {
  161.             double logX = FastMath.log(x);
  162.             double log1mX = FastMath.log1p(-x);
  163.             return (alpha - 1) * logX + (beta - 1) * log1mX - z;
  164.         }
  165.     }

  166.     /** {@inheritDoc} */
  167.     public double cumulativeProbability(double x)  {
  168.         if (x <= 0) {
  169.             return 0;
  170.         } else if (x >= 1) {
  171.             return 1;
  172.         } else {
  173.             return Beta.regularizedBeta(x, alpha, beta);
  174.         }
  175.     }

  176.     /**
  177.      * Return the absolute accuracy setting of the solver used to estimate
  178.      * inverse cumulative probabilities.
  179.      *
  180.      * @return the solver absolute accuracy.
  181.      * @since 2.1
  182.      */
  183.     @Override
  184.     protected double getSolverAbsoluteAccuracy() {
  185.         return solverAbsoluteAccuracy;
  186.     }

  187.     /**
  188.      * {@inheritDoc}
  189.      *
  190.      * For first shape parameter {@code alpha} and second shape parameter
  191.      * {@code beta}, the mean is {@code alpha / (alpha + beta)}.
  192.      */
  193.     public double getNumericalMean() {
  194.         final double a = getAlpha();
  195.         return a / (a + getBeta());
  196.     }

  197.     /**
  198.      * {@inheritDoc}
  199.      *
  200.      * For first shape parameter {@code alpha} and second shape parameter
  201.      * {@code beta}, the variance is
  202.      * {@code (alpha * beta) / [(alpha + beta)^2 * (alpha + beta + 1)]}.
  203.      */
  204.     public double getNumericalVariance() {
  205.         final double a = getAlpha();
  206.         final double b = getBeta();
  207.         final double alphabetasum = a + b;
  208.         return (a * b) / ((alphabetasum * alphabetasum) * (alphabetasum + 1));
  209.     }

  210.     /**
  211.      * {@inheritDoc}
  212.      *
  213.      * The lower bound of the support is always 0 no matter the parameters.
  214.      *
  215.      * @return lower bound of the support (always 0)
  216.      */
  217.     public double getSupportLowerBound() {
  218.         return 0;
  219.     }

  220.     /**
  221.      * {@inheritDoc}
  222.      *
  223.      * The upper bound of the support is always 1 no matter the parameters.
  224.      *
  225.      * @return upper bound of the support (always 1)
  226.      */
  227.     public double getSupportUpperBound() {
  228.         return 1;
  229.     }

  230.     /** {@inheritDoc} */
  231.     public boolean isSupportLowerBoundInclusive() {
  232.         return false;
  233.     }

  234.     /** {@inheritDoc} */
  235.     public boolean isSupportUpperBoundInclusive() {
  236.         return false;
  237.     }

  238.     /**
  239.      * {@inheritDoc}
  240.      *
  241.      * The support of this distribution is connected.
  242.      *
  243.      * @return {@code true}
  244.      */
  245.     public boolean isSupportConnected() {
  246.         return true;
  247.     }
  248. }