SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
HypergeometricDist.java
1/*
2 * Class: HypergeometricDist
3 * Description: hypergeometric distribution
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.probdist;
26
27import umontreal.ssj.util.Num;
28
44
45 private int m;
46 private int l;
47 private int k;
48 private double p0;
49
53
59 public static double MAXN = 100000;
60
64
70 public HypergeometricDist(int m, int l, int k) {
71 setParams(m, l, k);
72 }
73
74 public double prob(int x) {
75 if (x < supportA || x > supportB)
76 return 0.0;
77 if (pdf == null || x < xmin || x > xmax)
78 return prob(m, l, k, x);
79 return pdf[x - xmin];
80 }
81
82 public double cdf(int x) {
83 if (x < supportA)
84 return 0.0;
85 if (x >= supportB)
86 return 1.0;
87 if (cdf != null) {
88 if (x >= xmax)
89 return 1.0;
90 if (x < xmin)
91 return cdf(m, l, k, x);
92 if (x <= xmed)
93 return cdf[x - xmin];
94 else
95 // We keep the complementary distribution in the upper part of cdf
96 return 1.0 - cdf[x + 1 - xmin];
97 } else
98 return cdf(m, l, k, x);
99 }
100
101 public double barF(int x) {
102 if (x <= supportA)
103 return 1.0;
104 if (x > supportB)
105 return 0.0;
106 if (cdf != null) {
107 if (x > xmax)
108 return barF(m, l, k, x);
109 if (x <= xmin)
110 return 1.0;
111 if (x > xmed)
112 // We keep the complementary distribution in the upper part of cdf
113 return cdf[x - xmin];
114 else
115 return 1.0 - cdf[x - 1 - xmin];
116 } else
117 return barF(m, l, k, x);
118 }
119
120 public int inverseFInt(double u) {
121 if (u < 0 || u > 1)
122 throw new IllegalArgumentException("u is not in [0,1]");
123 if (u <= 0.0)
124 return Math.max(0, k - l + m);
125 if (u >= 1.0)
126 return Math.min(k, m);
127 double p = p0;
128 // Empirical correction, the original algorithm sets x=0.
129 int x = Math.max(0, k - l + m);
130 if (u <= p)
131 return x;
132 do {
133 u = u - p;
134 p = p * (m - x) * (k - x) / ((x + 1) * (l - m - k + 1.0 + x));
135 x++;
136 } while (u > p);
137 return x;
138 }
139
140 public double getMean() {
141 return HypergeometricDist.getMean(m, l, k);
142 }
143
144 public double getVariance() {
145 return HypergeometricDist.getVariance(m, l, k);
146 }
147
148 public double getStandardDeviation() {
149 return HypergeometricDist.getStandardDeviation(m, l, k);
150 }
151
156 public static double prob(int m, int l, int k, int x) {
157 final int SLIM = 70;
158 final double MAXEXP = (Num.DBL_MAX_EXP - 1) * Num.LN2;// To avoid overflow
159 if (l <= 0)
160 throw new IllegalArgumentException("l must be greater than 0");
161 if (m <= 0 || m > l)
162 throw new IllegalArgumentException("m is invalid: 1 <= m < l");
163 if (k <= 0 || k > l)
164 throw new IllegalArgumentException("k is invalid: 1 <= k < l");
165 if (x < Math.max(0, k - l + m) || x > Math.min(k, m))
166 return 0;
167
168 if (l <= SLIM)
169 return Num.combination(m, x) * Num.combination(l - m, k - x) / Num.combination(l, k);
170 else {
171 double res = Num.lnFactorial(m) + Num.lnFactorial(l - m) - Num.lnFactorial(l) - Num.lnFactorial(x)
172 - Num.lnFactorial(k - x) + Num.lnFactorial(k) - Num.lnFactorial(m - x) - Num.lnFactorial(l - m - k + x)
173 + Num.lnFactorial(l - k);
174 if (res >= MAXEXP)
175 throw new IllegalArgumentException("term overflow");
176 return Math.exp(res);
177 }
178 }
179
183 public static double cdf(int m, int l, int k, int x) {
184 if (l <= 0)
185 throw new IllegalArgumentException("l must be greater than 0");
186 if (m <= 0 || m > l)
187 throw new IllegalArgumentException("m is invalid: 1 <= m < l");
188 if (k <= 0 || k > l)
189 throw new IllegalArgumentException("k is invalid: 1 <= k < l");
190 int imin = Math.max(0, k - l + m);
191 int imax = Math.min(k, m);
192 if (x < imin)
193 return 0.0;
194 if (x >= imax)
195 return 1.0;
196 // Very inefficient
197 double res = 0.0;
198 for (int i = imin; i <= x; i++)
199 res += prob(m, l, k, i);
200 if (res >= 1.0)
201 return 1.0;
202 return res;
203 }
204
210 public static double barF(int m, int l, int k, int x) {
211 if (l <= 0)
212 throw new IllegalArgumentException("l must be greater than 0");
213 if (m <= 0 || m > l)
214 throw new IllegalArgumentException("m is invalid: 1 < =m < l");
215 if (k <= 0 || k > l)
216 throw new IllegalArgumentException("k is invalid: 1 < =k < l");
217 int imin = Math.max(0, k - l + m);
218 int imax = Math.min(k, m);
219 if (x <= imin)
220 return 1.0;
221 if (x > imax)
222 return 0.0;
223 // Very inefficient
224 double res = 0.0;
225 for (int i = imax; i >= x; i--)
226 res += prob(m, l, k, i);
227 if (res >= 1.0)
228 return 1.0;
229 return res;
230 }
231
237 public static int inverseF(int m, int l, int k, double u) {
238 // algo hin dans Kachitvichyanukul
239 if (u < 0 || u >= 1)
240 throw new IllegalArgumentException("u is not in [0,1]");
241 if (u <= 0.0)
242 return Math.max(0, k - l + m);
243 if (u >= 1.0)
244 return Math.min(k, m);
245 double p = 0;
246 if (k < l - m)
247 p = Math
248 .exp(Num.lnFactorial(l - m) + Num.lnFactorial(l - k) - Num.lnFactorial(l) - Num.lnFactorial(l - m - k));
249 else
250 p = Math.exp(Num.lnFactorial(m) + Num.lnFactorial(k) - Num.lnFactorial(k - l + m) - Num.lnFactorial(l));
251
252 // Empirical correction, the original algorithm sets x=0.
253 int x = Math.max(0, k - l + m);
254 if (u <= p)
255 return x;
256
257 do {
258 u = u - p;
259 p = p * (m - x) * (k - x) / ((x + 1) * (l - m - k + 1.0 + x));
260 x++;
261 } while (u > p && p > 0);
262 return x;
263 }
264
272 public static double getMean(int m, int l, int k) {
273 if (l <= 0)
274 throw new IllegalArgumentException("l must be greater than 0");
275 if (m <= 0 || m > l)
276 throw new IllegalArgumentException("m is invalid: 1<=m<l");
277 if (k <= 0 || k > l)
278 throw new IllegalArgumentException("k is invalid: 1<=k<l");
279
280 return ((double) k * (double) m / (double) l);
281 }
282
292 public static double getVariance(int m, int l, int k) {
293 if (l <= 0)
294 throw new IllegalArgumentException("l must be greater than 0");
295 if (m <= 0 || m > l)
296 throw new IllegalArgumentException("m is invalid: 1<=m<l");
297 if (k <= 0 || k > l)
298 throw new IllegalArgumentException("k is invalid: 1<=k<l");
299
300 return (((double) k * (double) m / (double) l) * (1 - ((double) m / (double) l)) * ((double) l - (double) k)
301 / ((double) l - 1));
302 }
303
310 public static double getStandardDeviation(int m, int l, int k) {
311 return Math.sqrt(HypergeometricDist.getVariance(m, l, k));
312 }
313
317 public int getM() {
318 return m;
319 }
320
324 public int getL() {
325 return l;
326 }
327
331 public int getK() {
332 return k;
333 }
334
335 private void setHypergeometric() {
336 int imin = Math.max(0, k - l + m);
337 int imax = Math.min(k, m);
338 supportA = imin;
339 supportB = imax;
340 int ns = imax - imin + 1;
341 if (ns > MAXN) {
342 pdf = null;
343 cdf = null;
344 return;
345 }
346
347 int offset = imin;
348 imin = 0;
349 imax -= offset;
350 double[] P = new double[ns];
351 double[] F = new double[ns];
352
353 // Computes the mode (taken from UNURAN)
354 int mode = (int) ((k + 1.0) * (m + 1.0) / (l + 2.0));
355 int imid = mode - offset;
356
357 P[imid] = prob(m, l, k, mode);
358
359 int i = imid;
360 while (i > imin && Math.abs(P[i]) > EPSILON) {
361 P[i - 1] = P[i] * (i + offset) / (m - i - offset + 1) * (l - m - k + i + offset) / (k - i - offset + 1);
362 i--;
363 }
364 imin = i;
365
366 i = imid;
367 while (i < imax && Math.abs(P[i]) > EPSILON) {
368 P[i + 1] = P[i] * (m - i - offset) / (i + offset + 1) * (k - i - offset) / (l - m - k + i + offset + 1);
369 i++;
370 }
371 imax = i;
372
373 F[imin] = P[imin];
374 i = imin;
375 while (i < imax && F[i] < 0.5) {
376 i++;
377 F[i] = F[i - 1] + P[i];
378 }
379 xmed = i;
380
381 F[imax] = P[imax];
382 i = imax - 1;
383 while (i > xmed) {
384 F[i] = P[i] + F[i + 1];
385 i--;
386 }
387
388 xmin = imin + offset;
389 xmax = imax + offset;
390 xmed += offset;
391 pdf = new double[imax + 1 - imin];
392 cdf = new double[imax + 1 - imin];
393 System.arraycopy(P, imin, pdf, 0, imax + 1 - imin);
394 System.arraycopy(F, imin, cdf, 0, imax + 1 - imin);
395 }
396
401 public double[] getParams() {
402 double[] retour = { m, l, k };
403 return retour;
404 }
405
409 public void setParams(int m, int l, int k) {
410 if (l <= 0)
411 throw new IllegalArgumentException("l must be greater than 0");
412 if (m <= 0 || m > l)
413 throw new IllegalArgumentException("m is invalid: 1 <= m < l");
414 if (k <= 0 || k > l)
415 throw new IllegalArgumentException("k is invalid: 1 <= k < l");
416 this.m = m;
417 this.l = l;
418 this.k = k;
419 setHypergeometric();
420 if (k < l - m)
421 p0 = Math
422 .exp(Num.lnFactorial(l - m) + Num.lnFactorial(l - k) - Num.lnFactorial(l) - Num.lnFactorial(l - m - k));
423 else
424 p0 = Math.exp(Num.lnFactorial(m) + Num.lnFactorial(k) - Num.lnFactorial(k - l + m) - Num.lnFactorial(l));
425 }
426
430 public String toString() {
431 return getClass().getSimpleName() + " : m = " + m + ", l = " + l + ", k = " + k;
432 }
433
434}
Classes implementing discrete distributions over the integers should inherit from this class.
static double EPSILON
Environment variable that determines what probability terms can be considered as negligible when buil...
static double MAXN
If the number of integers in the interval is larger than this constant, the tables will not be preco...
int getL()
Returns the associated with this object.
double getVariance()
Returns the variance of the distribution function.
int getK()
Returns the associated with this object.
int getM()
Returns the associated with this object.
static double getStandardDeviation(int m, int l, int k)
Computes and returns the standard deviation of the hypergeometric distribution with parameters ,...
String toString()
Returns a String containing information about the current distribution.
static double prob(int m, int l, int k, int x)
Computes the hypergeometric probability given by ( fheperg ).
double prob(int x)
Returns , the probability of .
static double getVariance(int m, int l, int k)
Computes and returns the variance.
double barF(int x)
Returns , the complementary distribution function.
double getMean()
Returns the mean of the distribution function.
static double barF(int m, int l, int k, int x)
Computes the complementary distribution function.
HypergeometricDist(int m, int l, int k)
Constructs an hypergeometric distribution with parameters ,.
static double cdf(int m, int l, int k, int x)
Computes the distribution function .
void setParams(int m, int l, int k)
Resets the parameters of this object to , and .
int inverseFInt(double u)
Returns the inverse distribution function , where.
double cdf(int x)
Returns the distribution function evaluated at (see ( FDistDisc )).
static int inverseF(int m, int l, int k, double u)
Computes for the hypergeometric distribution without using precomputed tables.
static double getMean(int m, int l, int k)
Computes and returns the mean of the Hypergeometric distribution with parameters ,...
double getStandardDeviation()
Returns the standard deviation of the distribution function.
double[] getParams()
Return a table containing the parameters of the current distribution.
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static double lnFactorial(int n)
Returns the value of , the natural logarithm of factorial .
Definition Num.java:313
static final int DBL_MAX_EXP
Largest int such that is representable (approximately) as a double.
Definition Num.java:96
static double combination(int n, int s)
Returns the value of , the number of different combinations of objects amongst.
Definition Num.java:243
static final double LN2
The values of .
Definition Num.java:148