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 }