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    *      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.discrete;
23  
24  import org.hipparchus.exception.LocalizedCoreFormats;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.util.FastMath;
27  import org.hipparchus.util.MathUtils;
28  
29  /**
30   * Implementation of the geometric distribution.
31   *
32   * @see <a href="http://en.wikipedia.org/wiki/Geometric_distribution">Geometric distribution (Wikipedia)</a>
33   * @see <a href="http://mathworld.wolfram.com/GeometricDistribution.html">Geometric Distribution (MathWorld)</a>
34   */
35  public class GeometricDistribution extends AbstractIntegerDistribution {
36  
37      /** Serializable version identifier. */
38      private static final long serialVersionUID = 20130507L;
39      /** The probability of success. */
40      private final double probabilityOfSuccess;
41      /** {@code log(p)} where p is the probability of success. */
42      private final double logProbabilityOfSuccess;
43      /** {@code log(1 - p)} where p is the probability of success. */
44      private final double log1mProbabilityOfSuccess;
45  
46      /**
47       * Create a geometric distribution with the given probability of success.
48       *
49       * @param p probability of success.
50       * @throws MathIllegalArgumentException if {@code p <= 0} or {@code p > 1}.
51       */
52      public GeometricDistribution(double p)
53          throws MathIllegalArgumentException {
54          if (p <= 0 || p > 1) {
55              throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_LEFT, p, 0, 1);
56          }
57  
58          probabilityOfSuccess = p;
59          logProbabilityOfSuccess = FastMath.log(p);
60          log1mProbabilityOfSuccess = FastMath.log1p(-p);
61      }
62  
63      /**
64       * Access the probability of success for this distribution.
65       *
66       * @return the probability of success.
67       */
68      public double getProbabilityOfSuccess() {
69          return probabilityOfSuccess;
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public double probability(int x) {
75          if (x < 0) {
76              return 0.0;
77          } else {
78              return FastMath.exp(log1mProbabilityOfSuccess * x) * probabilityOfSuccess;
79          }
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public double logProbability(int x) {
85          if (x < 0) {
86              return Double.NEGATIVE_INFINITY;
87          } else {
88              return x * log1mProbabilityOfSuccess + logProbabilityOfSuccess;
89          }
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public double cumulativeProbability(int x) {
95          if (x < 0) {
96              return 0.0;
97          } else {
98              return -FastMath.expm1(log1mProbabilityOfSuccess * (x + 1));
99          }
100     }
101 
102     /**
103      * {@inheritDoc}
104      *
105      * For probability parameter {@code p}, the mean is {@code (1 - p) / p}.
106      */
107     @Override
108     public double getNumericalMean() {
109         return (1 - probabilityOfSuccess) / probabilityOfSuccess;
110     }
111 
112     /**
113      * {@inheritDoc}
114      *
115      * For probability parameter {@code p}, the variance is
116      * {@code (1 - p) / (p * p)}.
117      */
118     @Override
119     public double getNumericalVariance() {
120         return (1 - probabilityOfSuccess) / (probabilityOfSuccess * probabilityOfSuccess);
121     }
122 
123     /**
124      * {@inheritDoc}
125      *
126      * The lower bound of the support is always 0.
127      *
128      * @return lower bound of the support (always 0)
129      */
130     @Override
131     public int getSupportLowerBound() {
132         return 0;
133     }
134 
135     /**
136      * {@inheritDoc}
137      *
138      * The upper bound of the support is infinite (which we approximate as
139      * {@code Integer.MAX_VALUE}).
140      *
141      * @return upper bound of the support (always Integer.MAX_VALUE)
142      */
143     @Override
144     public int getSupportUpperBound() {
145         return Integer.MAX_VALUE;
146     }
147 
148     /**
149      * {@inheritDoc}
150      *
151      * The support of this distribution is connected.
152      *
153      * @return {@code true}
154      */
155     @Override
156     public boolean isSupportConnected() {
157         return true;
158     }
159 
160     /**
161      * {@inheritDoc}
162      */
163     @Override
164     public int inverseCumulativeProbability(double p) throws MathIllegalArgumentException {
165         MathUtils.checkRangeInclusive(p, 0, 1);
166 
167         if (p == 1) {
168             return Integer.MAX_VALUE;
169         }
170         if (p == 0) {
171             return 0;
172         }
173         return Math.max(0, (int) Math.ceil(FastMath.log1p(-p)/log1mProbabilityOfSuccess-1));
174     }
175 }