View Javadoc

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.math.distribution;
18  
19  import org.apache.commons.math.MathException;
20  import org.apache.commons.math.special.Gamma;
21  import org.apache.commons.math.special.Beta;
22  
23  /**
24   * Implements the Beta distribution.
25   * <p>
26   * References:
27   * <ul>
28   * <li><a href="http://en.wikipedia.org/wiki/Beta_distribution">
29   * Beta distribution</a></li>
30   * </ul>
31   * </p>
32   * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
33   * @since 2.0
34   */
35  public class BetaDistributionImpl
36      extends AbstractContinuousDistribution implements BetaDistribution {
37  
38      /** Serializable version identifier. */
39      private static final long serialVersionUID = -1221965979403477668L;
40  
41      /** First shape parameter. */
42      private double alpha;
43  
44      /** Second shape parameter. */
45      private double beta;
46  
47      /** Normalizing factor used in density computations.
48       * updated whenever alpha or beta are changed.
49       */
50      private double z;
51  
52      /**
53       * Build a new instance.
54       * @param alpha first shape parameter (must be positive)
55       * @param beta second shape parameter (must be positive)
56       */
57      public BetaDistributionImpl(double alpha, double beta) {
58          this.alpha = alpha;
59          this.beta = beta;
60          z = Double.NaN;
61      }
62  
63      /** {@inheritDoc} */
64      public void setAlpha(double alpha) {
65          this.alpha = alpha;
66          z = Double.NaN;
67      }
68  
69      /** {@inheritDoc} */
70      public double getAlpha() {
71          return alpha;
72      }
73  
74      /** {@inheritDoc} */
75      public void setBeta(double beta) {
76          this.beta = beta;
77          z = Double.NaN;
78      }
79  
80      /** {@inheritDoc} */
81      public double getBeta() {
82          return beta;
83      }
84  
85      /**
86       * Recompute the normalization factor.
87       */
88      private void recomputeZ() {
89          if (Double.isNaN(z)) {
90              z = Gamma.logGamma(alpha) + Gamma.logGamma(beta) - Gamma.logGamma(alpha + beta);
91          }
92      }
93  
94      /** {@inheritDoc} */
95      public double density(Double x) throws MathException {
96          recomputeZ();
97          if (x < 0 || x > 1) {
98              return 0;
99          } else if (x == 0) {
100             if (alpha < 1) {
101                 throw new MathException("Cannot compute beta density at 0 when alpha = {0,number}", alpha);
102             }
103             return 0;
104         } else if (x == 1) {
105             if (beta < 1) {
106                 throw new MathException("Cannot compute beta density at 1 when beta = %.3g", beta);
107             }
108             return 0;
109         } else {
110             double logX = Math.log(x);
111             double log1mX = Math.log1p(-x);
112             return Math.exp((alpha - 1) * logX + (beta - 1) * log1mX - z);
113         }
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public double inverseCumulativeProbability(double p) throws MathException {
119         if (p == 0) {
120             return 0;
121         } else if (p == 1) {
122             return 1;
123         } else {
124             return super.inverseCumulativeProbability(p);
125         }
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     protected double getInitialDomain(double p) {
131         return p;
132     }
133 
134     /** {@inheritDoc} */
135     @Override
136     protected double getDomainLowerBound(double p) {
137         return 0;
138     }
139 
140     /** {@inheritDoc} */
141     @Override
142     protected double getDomainUpperBound(double p) {
143         return 1;
144     }
145 
146     /** {@inheritDoc} */
147     public double cumulativeProbability(double x) throws MathException {
148         if (x <= 0) {
149             return 0;
150         } else if (x >= 1) {
151             return 1;
152         } else {
153             return Beta.regularizedBeta(x, alpha, beta);
154         }
155     }
156 
157     /** {@inheritDoc} */
158     @Override
159     public double cumulativeProbability(double x0, double x1) throws MathException {
160         return cumulativeProbability(x1) - cumulativeProbability(x0);
161     }
162 }