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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.distribution.continuous;

  22. import org.hipparchus.exception.LocalizedCoreFormats;
  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.special.Beta;
  25. import org.hipparchus.special.Gamma;
  26. import org.hipparchus.util.FastMath;

  27. /**
  28.  * Implements the Beta distribution.
  29.  *
  30.  * @see <a href="http://en.wikipedia.org/wiki/Beta_distribution">Beta distribution</a>
  31.  */
  32. public class BetaDistribution extends AbstractRealDistribution {
  33.     /** Serializable version identifier. */
  34.     private static final long serialVersionUID = 20160320L;
  35.     /** First shape parameter. */
  36.     private final double alpha;
  37.     /** Second shape parameter. */
  38.     private final double beta;
  39.     /** Normalizing factor used in density computations. */
  40.     private final double z;

  41.     /**
  42.      * Build a new instance.
  43.      *
  44.      * @param alpha First shape parameter (must be positive).
  45.      * @param beta Second shape parameter (must be positive).
  46.      */
  47.     public BetaDistribution(double alpha, double beta) {
  48.         this(alpha, beta, DEFAULT_SOLVER_ABSOLUTE_ACCURACY);
  49.     }

  50.     /**
  51.      * Build a new instance.
  52.      *
  53.      * @param alpha First shape parameter (must be positive).
  54.      * @param beta Second shape parameter (must be positive).
  55.      * @param inverseCumAccuracy Maximum absolute error in inverse
  56.      * cumulative probability estimates (defaults to
  57.      * {@link #DEFAULT_SOLVER_ABSOLUTE_ACCURACY}).
  58.      */
  59.     public BetaDistribution(double alpha, double beta, double inverseCumAccuracy) {
  60.         super(inverseCumAccuracy);

  61.         this.alpha = alpha;
  62.         this.beta  = beta;
  63.         this.z     = Gamma.logGamma(alpha) +
  64.                      Gamma.logGamma(beta)  -
  65.                      Gamma.logGamma(alpha + beta);
  66.     }

  67.     /**
  68.      * Access the first shape parameter, {@code alpha}.
  69.      *
  70.      * @return the first shape parameter.
  71.      */
  72.     public double getAlpha() {
  73.         return alpha;
  74.     }

  75.     /**
  76.      * Access the second shape parameter, {@code beta}.
  77.      *
  78.      * @return the second shape parameter.
  79.      */
  80.     public double getBeta() {
  81.         return beta;
  82.     }

  83.     /** {@inheritDoc} */
  84.     @Override
  85.     public double density(double x) {
  86.         final double logDensity = logDensity(x);
  87.         return logDensity == Double.NEGATIVE_INFINITY ? 0 : FastMath.exp(logDensity);
  88.     }

  89.     /** {@inheritDoc} **/
  90.     @Override
  91.     public double logDensity(double x) {
  92.         if (x < 0 || x > 1) {
  93.             return Double.NEGATIVE_INFINITY;
  94.         } else if (x == 0) {
  95.             if (alpha < 1) {
  96.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_0_FOR_SOME_ALPHA,
  97.                                                        alpha, 1, false);
  98.             }
  99.             return Double.NEGATIVE_INFINITY;
  100.         } else if (x == 1) {
  101.             if (beta < 1) {
  102.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_1_FOR_SOME_BETA,
  103.                                                        beta, 1, false);
  104.             }
  105.             return Double.NEGATIVE_INFINITY;
  106.         } else {
  107.             double logX = FastMath.log(x);
  108.             double log1mX = FastMath.log1p(-x);
  109.             return (alpha - 1) * logX + (beta - 1) * log1mX - z;
  110.         }
  111.     }

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     public double cumulativeProbability(double x)  {
  115.         if (x <= 0) {
  116.             return 0;
  117.         } else if (x >= 1) {
  118.             return 1;
  119.         } else {
  120.             return Beta.regularizedBeta(x, alpha, beta);
  121.         }
  122.     }

  123.     /**
  124.      * {@inheritDoc}
  125.      *
  126.      * For first shape parameter {@code alpha} and second shape parameter
  127.      * {@code beta}, the mean is {@code alpha / (alpha + beta)}.
  128.      */
  129.     @Override
  130.     public double getNumericalMean() {
  131.         final double a = getAlpha();
  132.         return a / (a + getBeta());
  133.     }

  134.     /**
  135.      * {@inheritDoc}
  136.      *
  137.      * For first shape parameter {@code alpha} and second shape parameter
  138.      * {@code beta}, the variance is
  139.      * {@code (alpha * beta) / [(alpha + beta)^2 * (alpha + beta + 1)]}.
  140.      */
  141.     @Override
  142.     public double getNumericalVariance() {
  143.         final double a = getAlpha();
  144.         final double b = getBeta();
  145.         final double alphabetasum = a + b;
  146.         return (a * b) / ((alphabetasum * alphabetasum) * (alphabetasum + 1));
  147.     }

  148.     /**
  149.      * {@inheritDoc}
  150.      *
  151.      * The lower bound of the support is always 0 no matter the parameters.
  152.      *
  153.      * @return lower bound of the support (always 0)
  154.      */
  155.     @Override
  156.     public double getSupportLowerBound() {
  157.         return 0;
  158.     }

  159.     /**
  160.      * {@inheritDoc}
  161.      *
  162.      * The upper bound of the support is always 1 no matter the parameters.
  163.      *
  164.      * @return upper bound of the support (always 1)
  165.      */
  166.     @Override
  167.     public double getSupportUpperBound() {
  168.         return 1;
  169.     }

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