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 java.io.Serializable;
20  
21  import org.apache.commons.math.MathException;
22  
23  
24  /**
25   * Base class for integer-valued discrete distributions.  Default
26   * implementations are provided for some of the methods that do not vary
27   * from distribution to distribution.
28   *  
29   * @version $Revision: 620368 $ $Date: 2008-02-10 18:04:48 -0700 (Sun, 10 Feb 2008) $
30   */
31  public abstract class AbstractIntegerDistribution extends AbstractDistribution
32      implements IntegerDistribution, Serializable {
33          
34      /** Serializable version identifier */
35      private static final long serialVersionUID = -1146319659338487221L;
36      
37      /**
38       * Default constructor.
39       */
40      protected AbstractIntegerDistribution() {
41          super();
42      }
43      
44      /**
45       * For a random variable X whose values are distributed according
46       * to this distribution, this method returns P(X ≤ x).  In other words,
47       * this method represents the  (cumulative) distribution function, or
48       * CDF, for this distribution.
49       * <p>
50       * If <code>x</code> does not represent an integer value, the CDF is 
51       * evaluated at the greatest integer less than x.
52       * 
53       * @param x the value at which the distribution function is evaluated.
54       * @return cumulative probability that a random variable with this
55       * distribution takes a value less than or equal to <code>x</code>
56       * @throws MathException if the cumulative probability can not be
57       * computed due to convergence or other numerical errors.
58       */
59      public double cumulativeProbability(double x) throws MathException {
60          return cumulativeProbability((int) Math.floor(x));  
61      }
62      
63      /**
64       * For a random variable X whose values are distributed according
65       * to this distribution, this method returns P(x0 &le; X &le; x1).
66       * 
67       * @param x0 the (inclusive) lower bound
68       * @param x1 the (inclusive) upper bound
69       * @return the probability that a random variable with this distribution
70       * will take a value between <code>x0</code> and <code>x1</code>,
71       * including the endpoints.
72       * @throws MathException if the cumulative probability can not be
73       * computed due to convergence or other numerical errors.
74       * @throws IllegalArgumentException if <code>x0 > x1</code>
75       */
76      public double cumulativeProbability(double x0, double x1)
77          throws MathException {
78          if (x0 > x1) {
79              throw new IllegalArgumentException
80              ("lower endpoint must be less than or equal to upper endpoint");
81          }
82          if (Math.floor(x0) < x0) {
83              return cumulativeProbability(((int) Math.floor(x0)) + 1,
84                 (int) Math.floor(x1)); // don't want to count mass below x0
85          } else { // x0 is mathematical integer, so use as is
86              return cumulativeProbability((int) Math.floor(x0),
87                  (int) Math.floor(x1)); 
88          }
89      }
90      
91      /**
92       * For a random variable X whose values are distributed according
93       * to this distribution, this method returns P(X &le; x).  In other words,
94       * this method represents the probability distribution function, or PDF,
95       * for this distribution.
96       * 
97       * @param x the value at which the PDF is evaluated.
98       * @return PDF for this distribution. 
99       * @throws MathException if the cumulative probability can not be
100      *            computed due to convergence or other numerical errors.
101      */
102     abstract public double cumulativeProbability(int x) throws MathException;
103     
104     /**
105      * For a random variable X whose values are distributed according
106      * to this distribution, this method returns P(X = x). In other words, this
107      * method represents the probability mass function,  or PMF, for the distribution.
108      * <p>
109      * If <code>x</code> does not represent an integer value, 0 is returned.
110      * 
111      * @param x the value at which the probability density function is evaluated
112      * @return the value of the probability density function at x
113      */
114     public double probability(double x) {
115         double fl = Math.floor(x);
116         if (fl == x) {
117             return this.probability((int) x);
118         } else {
119             return 0;
120         }
121     }
122     
123     /**
124     * For a random variable X whose values are distributed according
125      * to this distribution, this method returns P(x0 &le; X &le; x1).
126      * 
127      * @param x0 the inclusive, lower bound
128      * @param x1 the inclusive, upper bound
129      * @return the cumulative probability. 
130      * @throws MathException if the cumulative probability can not be
131      *            computed due to convergence or other numerical errors.
132      * @throws IllegalArgumentException if x0 > x1
133      */
134     public double cumulativeProbability(int x0, int x1) throws MathException {
135         if (x0 > x1) {
136             throw new IllegalArgumentException
137                 ("lower endpoint must be less than or equal to upper endpoint");
138         }
139         return cumulativeProbability(x1) - cumulativeProbability(x0 - 1);
140     }
141     
142     /**
143      * For a random variable X whose values are distributed according
144      * to this distribution, this method returns the largest x, such
145      * that P(X &le; x) &le; <code>p</code>.
146      *
147      * @param p the desired probability
148      * @return the largest x such that P(X &le; x) <= p
149      * @throws MathException if the inverse cumulative probability can not be
150      *            computed due to convergence or other numerical errors.
151      * @throws IllegalArgumentException if p < 0 or p > 1
152      */
153     public int inverseCumulativeProbability(final double p) throws MathException{
154         if (p < 0.0 || p > 1.0) {
155             throw new IllegalArgumentException(
156                 "p must be between 0 and 1.0 (inclusive)");
157         }
158         
159         // by default, do simple bisection.
160         // subclasses can override if there is a better method.
161         int x0 = getDomainLowerBound(p);
162         int x1 = getDomainUpperBound(p);
163         double pm;
164         while (x0 < x1) {
165             int xm = x0 + (x1 - x0) / 2;
166             pm = cumulativeProbability(xm);
167             if (pm > p) {
168                 // update x1
169                 if (xm == x1) {
170                     // this can happen with integer division
171                     // simply decrement x1
172                     --x1;
173                 } else {
174                     // update x1 normally
175                     x1 = xm;
176                 }
177             } else {
178                 // update x0
179                 if (xm == x0) {
180                     // this can happen with integer division
181                     // simply increment x0
182                     ++x0;
183                 } else {
184                     // update x0 normally
185                     x0 = xm;
186                 }
187             }
188         }
189         
190         // insure x0 is the correct critical point
191         pm = cumulativeProbability(x0);
192         while (pm > p) {
193             --x0;
194             pm = cumulativeProbability(x0);
195         }
196     
197         return x0;        
198     }
199     
200     /**
201      * Access the domain value lower bound, based on <code>p</code>, used to
202      * bracket a PDF root.  This method is used by
203      * {@link #inverseCumulativeProbability(double)} to find critical values.
204      * 
205      * @param p the desired probability for the critical value
206      * @return domain value lower bound, i.e.
207      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
208      */
209     protected abstract int getDomainLowerBound(double p);
210     
211     /**
212      * Access the domain value upper bound, based on <code>p</code>, used to
213      * bracket a PDF root.  This method is used by
214      * {@link #inverseCumulativeProbability(double)} to find critical values.
215      * 
216      * @param p the desired probability for the critical value
217      * @return domain value upper bound, i.e.
218      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
219      */
220     protected abstract int getDomainUpperBound(double p);
221 }