View Javadoc

1   /*
2    * Copyright 2003-2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.math.distribution;
17  
18  import java.io.Serializable;
19  
20  import org.apache.commons.math.MathException;
21  
22  
23  /**
24   * Base class for integer-valued discrete distributions.  Default
25   * implementations are provided for some of the methods that do not vary
26   * from distribution to distribution.
27   *  
28   * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
29   */
30  public abstract class AbstractIntegerDistribution extends AbstractDistribution
31      implements IntegerDistribution, Serializable {
32          
33      /** Serializable version identifier */
34      private static final long serialVersionUID = -1146319659338487221L;
35      
36      /**
37       * Default constructor.
38       */
39      protected AbstractIntegerDistribution() {
40          super();
41      }
42      
43      /**
44       * For a random variable X whose values are distributed according
45       * to this distribution, this method returns P(X ≤ x).  In other words,
46       * this method represents the  (cumulative) distribution function, or
47       * CDF, for this distribution.
48       * <p>
49       * If <code>x</code> does not represent an integer value, the CDF is 
50       * evaluated at the greatest integer less than x.
51       * 
52       * @param x the value at which the distribution function is evaluated.
53       * @return cumulative probability that a random variable with this
54       * distribution takes a value less than or equal to <code>x</code>
55       * @throws MathException if the cumulative probability can not be
56       * computed due to convergence or other numerical errors.
57       */
58      public double cumulativeProbability(double x) throws MathException {
59          return cumulativeProbability((int) Math.floor(x));  
60      }
61      
62      /**
63       * For a random variable X whose values are distributed according
64       * to this distribution, this method returns P(X &le; x).  In other words,
65       * this method represents the probability distribution function, or PDF,
66       * for this distribution.
67       * 
68       * @param x the value at which the PDF is evaluated.
69       * @return PDF for this distribution. 
70       * @throws MathException if the cumulative probability can not be
71       *            computed due to convergence or other numerical errors.
72       */
73      abstract public double cumulativeProbability(int x) throws MathException;
74      
75      /**
76       * For a random variable X whose values are distributed according
77       * to this distribution, this method returns P(X = x). In other words, this
78       * method represents the probability mass function,  or PMF, for the distribution.
79       * <p>
80       * If <code>x</code> does not represent an integer value, 0 is returned.
81       * 
82       * @param x the value at which the probability density function is evaluated
83       * @return the value of the probability density function at x
84       */
85      public double probability(double x) {
86          double fl = Math.floor(x);
87          if (fl == x) {
88              return this.probability((int) x);
89          } else {
90              return 0;
91          }
92      }
93      
94      /**
95      * For a random variable X whose values are distributed according
96       * to this distribution, this method returns P(x0 &le; X &le; x1).
97       * 
98       * @param x0 the inclusive, lower bound
99       * @param x1 the inclusive, upper bound
100      * @return the cumulative probability. 
101      * @throws MathException if the cumulative probability can not be
102      *            computed due to convergence or other numerical errors.
103      * @throws IllegalArgumentException if x0 > x1
104      */
105     public double cumulativeProbability(int x0, int x1) throws MathException {
106         if (x0 > x1) {
107             throw new IllegalArgumentException
108                 ("lower endpoint must be less than or equal to upper endpoint");
109         }
110         return cumulativeProbability(x1) - cumulativeProbability(x0 - 1);
111     }
112     
113     /**
114      * For a random variable X whose values are distributed according
115      * to this distribution, this method returns the largest x, such
116      * that P(X &le; x) &le; <code>p</code>.
117      *
118      * @param p the desired probability
119      * @return the largest x such that P(X &le; x) <= p
120      * @throws MathException if the inverse cumulative probability can not be
121      *            computed due to convergence or other numerical errors.
122      * @throws IllegalArgumentException if p < 0 or p > 1
123      */
124     public int inverseCumulativeProbability(final double p) throws MathException{
125         if (p < 0.0 || p > 1.0) {
126             throw new IllegalArgumentException(
127                 "p must be between 0 and 1.0 (inclusive)");
128         }
129         
130         // by default, do simple bisection.
131         // subclasses can override if there is a better method.
132         int x0 = getDomainLowerBound(p);
133         int x1 = getDomainUpperBound(p);
134         double pm;
135         while (x0 < x1) {
136             int xm = x0 + (x1 - x0) / 2;
137             pm = cumulativeProbability(xm);
138             if (pm > p) {
139                 // update x1
140                 if (xm == x1) {
141                     // this can happen with integer division
142                     // simply decrement x1
143                     --x1;
144                 } else {
145                     // update x1 normally
146                     x1 = xm;
147                 }
148             } else {
149                 // update x0
150                 if (xm == x0) {
151                     // this can happen with integer division
152                     // simply increment x0
153                     ++x0;
154                 } else {
155                     // update x0 normally
156                     x0 = xm;
157                 }
158             }
159         }
160         
161         // insure x0 is the correct critical point
162         pm = cumulativeProbability(x0);
163         while (pm > p) {
164             --x0;
165             pm = cumulativeProbability(x0);
166         }
167     
168         return x0;        
169     }
170     
171     /**
172      * Access the domain value lower bound, based on <code>p</code>, used to
173      * bracket a PDF root.  This method is used by
174      * {@link #inverseCumulativeProbability(double)} to find critical values.
175      * 
176      * @param p the desired probability for the critical value
177      * @return domain value lower bound, i.e.
178      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
179      */
180     protected abstract int getDomainLowerBound(double p);
181     
182     /**
183      * Access the domain value upper bound, based on <code>p</code>, used to
184      * bracket a PDF root.  This method is used by
185      * {@link #inverseCumulativeProbability(double)} to find critical values.
186      * 
187      * @param p the desired probability for the critical value
188      * @return domain value upper bound, i.e.
189      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
190      */
191     protected abstract int getDomainUpperBound(double p);
192 }