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 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22 package org.hipparchus.distribution.continuous;
23
24 import org.hipparchus.exception.LocalizedCoreFormats;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.special.Beta;
27 import org.hipparchus.special.Gamma;
28 import org.hipparchus.util.FastMath;
29
30 /**
31 * Implements the Beta distribution.
32 *
33 * @see <a href="http://en.wikipedia.org/wiki/Beta_distribution">Beta distribution</a>
34 */
35 public class BetaDistribution extends AbstractRealDistribution {
36 /** Serializable version identifier. */
37 private static final long serialVersionUID = 20160320L;
38 /** First shape parameter. */
39 private final double alpha;
40 /** Second shape parameter. */
41 private final double beta;
42 /** Normalizing factor used in density computations. */
43 private final double z;
44
45 /**
46 * Build a new instance.
47 *
48 * @param alpha First shape parameter (must be positive).
49 * @param beta Second shape parameter (must be positive).
50 */
51 public BetaDistribution(double alpha, double beta) {
52 this(alpha, beta, DEFAULT_SOLVER_ABSOLUTE_ACCURACY);
53 }
54
55 /**
56 * Build a new instance.
57 *
58 * @param alpha First shape parameter (must be positive).
59 * @param beta Second shape parameter (must be positive).
60 * @param inverseCumAccuracy Maximum absolute error in inverse
61 * cumulative probability estimates (defaults to
62 * {@link #DEFAULT_SOLVER_ABSOLUTE_ACCURACY}).
63 */
64 public BetaDistribution(double alpha, double beta, double inverseCumAccuracy) {
65 super(inverseCumAccuracy);
66
67 this.alpha = alpha;
68 this.beta = beta;
69 this.z = Gamma.logGamma(alpha) +
70 Gamma.logGamma(beta) -
71 Gamma.logGamma(alpha + beta);
72 }
73
74 /**
75 * Access the first shape parameter, {@code alpha}.
76 *
77 * @return the first shape parameter.
78 */
79 public double getAlpha() {
80 return alpha;
81 }
82
83 /**
84 * Access the second shape parameter, {@code beta}.
85 *
86 * @return the second shape parameter.
87 */
88 public double getBeta() {
89 return beta;
90 }
91
92 /** {@inheritDoc} */
93 @Override
94 public double density(double x) {
95 final double logDensity = logDensity(x);
96 return logDensity == Double.NEGATIVE_INFINITY ? 0 : FastMath.exp(logDensity);
97 }
98
99 /** {@inheritDoc} **/
100 @Override
101 public double logDensity(double x) {
102 if (x < 0 || x > 1) {
103 return Double.NEGATIVE_INFINITY;
104 } else if (x == 0) {
105 if (alpha < 1) {
106 throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_0_FOR_SOME_ALPHA,
107 alpha, 1, false);
108 }
109 return Double.NEGATIVE_INFINITY;
110 } else if (x == 1) {
111 if (beta < 1) {
112 throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_1_FOR_SOME_BETA,
113 beta, 1, false);
114 }
115 return Double.NEGATIVE_INFINITY;
116 } else {
117 double logX = FastMath.log(x);
118 double log1mX = FastMath.log1p(-x);
119 return (alpha - 1) * logX + (beta - 1) * log1mX - z;
120 }
121 }
122
123 /** {@inheritDoc} */
124 @Override
125 public double cumulativeProbability(double x) {
126 if (x <= 0) {
127 return 0;
128 } else if (x >= 1) {
129 return 1;
130 } else {
131 return Beta.regularizedBeta(x, alpha, beta);
132 }
133 }
134
135 /**
136 * {@inheritDoc}
137 *
138 * For first shape parameter {@code alpha} and second shape parameter
139 * {@code beta}, the mean is {@code alpha / (alpha + beta)}.
140 */
141 @Override
142 public double getNumericalMean() {
143 final double a = getAlpha();
144 return a / (a + getBeta());
145 }
146
147 /**
148 * {@inheritDoc}
149 *
150 * For first shape parameter {@code alpha} and second shape parameter
151 * {@code beta}, the variance is
152 * {@code (alpha * beta) / [(alpha + beta)^2 * (alpha + beta + 1)]}.
153 */
154 @Override
155 public double getNumericalVariance() {
156 final double a = getAlpha();
157 final double b = getBeta();
158 final double alphabetasum = a + b;
159 return (a * b) / ((alphabetasum * alphabetasum) * (alphabetasum + 1));
160 }
161
162 /**
163 * {@inheritDoc}
164 *
165 * The lower bound of the support is always 0 no matter the parameters.
166 *
167 * @return lower bound of the support (always 0)
168 */
169 @Override
170 public double getSupportLowerBound() {
171 return 0;
172 }
173
174 /**
175 * {@inheritDoc}
176 *
177 * The upper bound of the support is always 1 no matter the parameters.
178 *
179 * @return upper bound of the support (always 1)
180 */
181 @Override
182 public double getSupportUpperBound() {
183 return 1;
184 }
185
186 /**
187 * {@inheritDoc}
188 *
189 * The support of this distribution is connected.
190 *
191 * @return {@code true}
192 */
193 @Override
194 public boolean isSupportConnected() {
195 return true;
196 }
197 }