SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
GammaDist.java
1/*
2 * Class: GammaDist
3 * Description: gamma 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;
28import umontreal.ssj.functions.MathFunction;
29import umontreal.ssj.util.RootFinder;
30
49public class GammaDist extends ContinuousDistribution {
50 private double alpha; // shape parameter
51 private double lambda; // rate parameter
52 private double logFactor; // Log (lambda^alpha / Gamma (alpha))
53 private static final double ALIM = 1.0E5;
54
55 private static class Function implements MathFunction {
56 // For MLE
57 private int n;
58 private double empiricalMean;
59 private double sumLn;
60
61 public Function(int n, double empiricalMean, double sumLn) {
62 this.n = n;
63 this.empiricalMean = empiricalMean;
64 this.sumLn = sumLn;
65 }
66
67 public double evaluate(double x) {
68 if (x <= 0.0)
69 return 1.0e200;
70 return (n * Math.log(empiricalMean / x) + n * Num.digamma(x) - sumLn);
71 }
72 }
73
74 private static class myFunc implements MathFunction {
75 // For inverseF
76 protected int d;
77 protected double alp, u;
78
79 public myFunc(double alp, int d, double u) {
80 this.alp = alp;
81 this.d = d;
82 this.u = u;
83 }
84
85 public double evaluate(double x) {
86 return u - GammaDist.cdf(alp, d, x);
87 }
88 }
89
94 public GammaDist(double alpha) {
95 setParams(alpha, 1.0, decPrec);
96 }
97
102 public GammaDist(double alpha, double lambda) {
103 setParams(alpha, lambda, decPrec);
104 }
105
111 public GammaDist(double alpha, double lambda, int d) {
112 setParams(alpha, lambda, d);
113 }
114
115 static double mybelog(double x)
116 /*
117 * This is the function 1 + (1 - x*x + 2*x*log(x)) / ((1 - x)*(1 - x))
118 */
119 {
120 if (x < 1.0e-30)
121 return 0.0;
122 if (x > 1.0e30)
123 return 2.0 * (Math.log(x) - 1.0) / x;
124 if (x == 1.0)
125 return 1.0;
126
127 double t = 1.0 - x;
128 if (x < 0.9 || x > 1.1) {
129 double w = (t + x * Math.log(x)) / (t * t);
130 return 2.0 * w;
131 }
132
133 // For x near 1, use a series expansion to avoid loss of precision.
134 double term;
135 final double EPS = 1.0e-12;
136 double tpow = 1.0;
137 double sum = 0.5;
138 int j = 3;
139 do {
140 tpow *= t;
141 term = tpow / (j * (j - 1));
142 sum += term;
143 j++;
144 } while (Math.abs(term / sum) > EPS);
145 return 2.0 * sum;
146 }
147
148 public double density(double x) {
149 if (x <= 0)
150 return 0.0;
151 double z = logFactor + (alpha - 1.0) * Math.log(x) - lambda * x;
152 if (z > -XBIGM)
153 return Math.exp(z);
154 else
155 return 0.0;
156 }
157
158 public double cdf(double x) {
159 return cdf(alpha, lambda, decPrec, x);
160 }
161
162 public double barF(double x) {
163 return barF(alpha, lambda, decPrec, x);
164 }
165
166 public double inverseF(double u) {
167 return inverseF(alpha, decPrec, u) / lambda;
168 }
169
170 public double getMean() {
171 return GammaDist.getMean(alpha, lambda);
172 }
173
174 public double getVariance() {
175 return GammaDist.getVariance(alpha, lambda);
176 }
177
178 public double getStandardDeviation() {
179 return GammaDist.getStandardDeviation(alpha, lambda);
180 }
181
186 public static double density(double alpha, double lambda, double x) {
187 if (alpha <= 0)
188 throw new IllegalArgumentException("alpha <= 0");
189 if (lambda <= 0)
190 throw new IllegalArgumentException("lambda <= 0");
191
192 if (x <= 0)
193 return 0.0;
194 double z = alpha * Math.log(lambda * x) - lambda * x - Num.lnGamma(alpha);
195 if (z > -XBIGM)
196 return Math.exp(z) / x;
197 else
198 return 0.0;
199 }
200
212 public static double cdf(double alpha, double lambda, int d, double x) {
213 return cdf(alpha, d, lambda * x);
214 }
215
219 public static double cdf(double alpha, int d, double x) {
220 if (alpha <= 0.0)
221 throw new IllegalArgumentException("alpha <= 0");
222 if (d <= 0)
223 throw new IllegalArgumentException("d <= 0");
224 if (x <= 0.0)
225 return 0.0;
226 if (1.0 == alpha)
227 return ExponentialDist.cdf(1.0, x);
228
229 if (alpha > 10.0) {
230 if (x > alpha * 10.0)
231 return 1.0;
232 } else {
233 if (x > XBIG)
234 return 1.0;
235 }
236
237 if (alpha >= ALIM) {
238 double d2 = x + 1.0 / 3.0 - alpha - 0.02 / alpha;
239 double S = alpha - 1.0 / 2.0;
240 double w = mybelog(S / x);
241 double y = d2 * Math.sqrt(w / x);
242 return NormalDist.cdf01(y);
243 }
244
245 if (x <= 1.0 || x < alpha) {
246 double factor, z, rn, term;
247 factor = Math.exp(alpha * Math.log(x) - x - Num.lnGamma(alpha));
248 final double EPS = EPSARRAY[d];
249 z = 1.0;
250 term = 1.0;
251 rn = alpha;
252 do {
253 rn += 1.0;
254 term *= x / rn;
255 z += term;
256 } while (term >= EPS * z);
257 return z * factor / alpha;
258
259 } else
260 return 1.0 - barF(alpha, d, x);
261 }
262
266 public static double barF(double alpha, double lambda, int d, double x) {
267 return barF(alpha, d, lambda * x);
268 }
269
273 public static double barF(double alpha, int d, double x) {
274 if (alpha <= 0.0)
275 throw new IllegalArgumentException("alpha <= 0");
276 if (d <= 0)
277 throw new IllegalArgumentException("d <= 0");
278 if (x <= 0.0)
279 return 1.0;
280 if (1.0 == alpha)
281 return ExponentialDist.barF(1.0, x);
282
283 if (alpha >= 70.0) {
284 if (x >= alpha * XBIG)
285 return 0.0;
286 } else {
287 if (x >= XBIGM)
288 return 0.0;
289 }
290
291 if (alpha >= ALIM) {
292 double d2 = x + 1.0 / 3.0 - alpha - 0.02 / alpha;
293 double S = alpha - 1.0 / 2.0;
294 double w = mybelog(S / x);
295 double y = d2 * Math.sqrt(w / x);
296 return NormalDist.barF01(y);
297 }
298
299 if (x <= 1.0 || x < alpha)
300 return 1.0 - cdf(alpha, d, x);
301
302 double[] V = new double[6];
303 final double EPS = EPSARRAY[d];
304 final double RENORM = 1.0E100;
305 double R, dif;
306 int i;
307 double factor = Math.exp(alpha * Math.log(x) - x - Num.lnGamma(alpha));
308
309 double A = 1.0 - alpha;
310 double B = A + x + 1.0;
311 double term = 0.0;
312 V[0] = 1.0;
313 V[1] = x;
314 V[2] = x + 1.0;
315 V[3] = x * B;
316 double res = V[2] / V[3];
317
318 do {
319 A += 1.0;
320 B += 2.0;
321 term += 1.0;
322 V[4] = B * V[2] - A * term * V[0];
323 V[5] = B * V[3] - A * term * V[1];
324 if (V[5] != 0.0) {
325 R = V[4] / V[5];
326 dif = Math.abs(res - R);
327 if (dif <= EPS * R)
328 return factor * res;
329 res = R;
330 }
331 for (i = 0; i < 4; i++)
332 V[i] = V[i + 2];
333 if (Math.abs(V[4]) >= RENORM) {
334 for (i = 0; i < 4; i++)
335 V[i] /= RENORM;
336 }
337 } while (true);
338 }
339
343 public static double inverseF(double alpha, double lambda, int d, double u) {
344 return inverseF(alpha, d, u) / lambda;
345 }
346
350 public static double inverseF(double alpha, int d, double u) {
351 if (alpha <= 0.0)
352 throw new IllegalArgumentException("alpha <= 0");
353 if (u > 1.0 || u < 0.0)
354 throw new IllegalArgumentException("u not in [0,1]");
355 if (u <= 0.0)
356 return 0;
357 if (u >= 1.0)
358 return Double.POSITIVE_INFINITY;
359 if (d <= 0)
360 throw new IllegalArgumentException("d <= 0");
361 if (d > 15)
362 d = 15;
363 final double EPS = Math.pow(10.0, -d);
364
365 double sigma = GammaDist.getStandardDeviation(alpha, 1.0);
366 double x = NormalDist.inverseF(alpha, sigma, u);
367 if (x < 0.)
368 x = 0.;
369 double v = GammaDist.cdf(alpha, d, x);
370 double xmax;
371 if (alpha < 1.0)
372 xmax = 100.0;
373 else
374 xmax = alpha + 40.0 * sigma;
375 myFunc f = new myFunc(alpha, d, u);
376
377 if (u <= 1.0e-8 || alpha <= 1.5) {
378 if (v < u)
379 return RootFinder.bisection(x, xmax, f, EPS);
380 else
381 return RootFinder.bisection(0, x, f, EPS);
382 } else {
383 if (v < u)
384 return RootFinder.brentDekker(x, xmax, f, EPS);
385 else
386 return RootFinder.brentDekker(0, x, f, EPS);
387 }
388 }
389
409 public static double[] getMLE(double[] x, int n) {
410 double parameters[];
411 double sum = 0.0;
412 double sumLn = 0.0;
413 double empiricalMean;
414 double alphaMME;
415 double a;
416 final double LN_EPS = Num.LN_DBL_MIN - Num.LN2;
417
418 parameters = new double[2];
419 if (n <= 0)
420 throw new IllegalArgumentException("n <= 0");
421 for (int i = 0; i < n; i++) {
422 sum += x[i];
423 if (x[i] <= 0.0)
424 sumLn += LN_EPS;
425 else
426 sumLn += Math.log(x[i]);
427 }
428 empiricalMean = sum / (double) n;
429
430 sum = 0.0;
431 for (int i = 0; i < n; i++) {
432 sum += (x[i] - empiricalMean) * (x[i] - empiricalMean);
433 }
434
435 alphaMME = (empiricalMean * empiricalMean * (double) n) / sum;
436 if ((a = alphaMME - 10.0) <= 0) {
437 a = 1.0e-5;
438 }
439
440 Function f = new Function(n, empiricalMean, sumLn);
441 parameters[0] = RootFinder.brentDekker(a, alphaMME + 10.0, f, 1e-7);
442 parameters[1] = parameters[0] / empiricalMean;
443
444 return parameters;
445 }
446
456 public static GammaDist getInstanceFromMLE(double[] x, int n) {
457 double parameters[] = getMLE(x, n);
458 return new GammaDist(parameters[0], parameters[1]);
459 }
460
467 public static double getMean(double alpha, double lambda) {
468 if (alpha <= 0.0)
469 throw new IllegalArgumentException("alpha <= 0");
470 if (lambda <= 0.0)
471 throw new IllegalArgumentException("lambda <= 0");
472
473 return (alpha / lambda);
474 }
475
484 public static double getVariance(double alpha, double lambda) {
485 if (alpha <= 0.0)
486 throw new IllegalArgumentException("alpha <= 0");
487 if (lambda <= 0.0)
488 throw new IllegalArgumentException("lambda <= 0");
489
490 return (alpha / (lambda * lambda));
491 }
492
499 public static double getStandardDeviation(double alpha, double lambda) {
500 if (alpha <= 0.0)
501 throw new IllegalArgumentException("alpha <= 0");
502 if (lambda <= 0.0)
503 throw new IllegalArgumentException("lambda <= 0");
504
505 return (Math.sqrt(alpha) / lambda);
506 }
507
511 public double getAlpha() {
512 return alpha;
513 }
514
518 public double getLambda() {
519 return lambda;
520 }
521
522 public void setParams(double alpha, double lambda, int d) {
523 if (alpha <= 0)
524 throw new IllegalArgumentException("alpha <= 0");
525 if (lambda <= 0)
526 throw new IllegalArgumentException("lambda <= 0");
527
528 this.alpha = alpha;
529 this.lambda = lambda;
530 this.decPrec = d;
531 logFactor = alpha * Math.log(lambda) - Num.lnGamma(alpha);
532 supportA = 0.0;
533 }
534
539 public double[] getParams() {
540 double[] retour = { alpha, lambda };
541 return retour;
542 }
543
547 public String toString() {
548 return getClass().getSimpleName() + " : alpha = " + alpha + ", lambda = " + lambda;
549 }
550
551}
Classes implementing continuous distributions should inherit from this base class.
Extends the class ContinuousDistribution for the exponential distribution tjoh95a  (page 494) with me...
double barF(double x)
Returns the complementary distribution function.
double cdf(double x)
Returns the distribution function .
GammaDist(double alpha)
Constructs a GammaDist object with parameters = alpha and .
double inverseF(double u)
Returns the inverse distribution function .
double getMean()
Returns the mean.
double getStandardDeviation()
Returns the standard deviation.
double cdf(double x)
Returns the distribution function .
static GammaDist getInstanceFromMLE(double[] x, int n)
Creates a new instance of a gamma distribution with parameters.
static double getVariance(double alpha, double lambda)
Computes and returns the variance of the gamma distribution with parameters.
static double inverseF(double alpha, int d, double u)
Same as inverseF(alpha, 1, d, u).
static double getMean(double alpha, double lambda)
Computes and returns the mean of the gamma distribution with parameters and .
static double cdf(double alpha, int d, double x)
Equivalent to cdf (alpha, 1.0, d, x).
static double inverseF(double alpha, double lambda, int d, double u)
Computes the inverse distribution function.
static double cdf(double alpha, double lambda, int d, double x)
Returns an approximation of the gamma distribution function with parameters = alpha and = lambda,...
String toString()
Returns a String containing information about the current distribution.
static double[] getMLE(double[] x, int n)
Estimates the parameters of the gamma distribution using the maximum likelihood method,...
double density(double x)
Returns , the density evaluated at .
double getAlpha()
Return the parameter for this object.
static double barF(double alpha, double lambda, int d, double x)
Computes the complementary distribution function.
double barF(double x)
Returns the complementary distribution function.
GammaDist(double alpha, double lambda)
Constructs a GammaDist object with parameters = alpha and = lambda.
double getVariance()
Returns the variance.
static double getStandardDeviation(double alpha, double lambda)
Computes and returns the standard deviation of the gamma distribution with parameters and .
static double density(double alpha, double lambda, double x)
Computes the density function ( fgamma ) at .
double getLambda()
Return the parameter for this object.
GammaDist(double alpha, double lambda, int d)
Constructs a GammaDist object with parameters = alpha and = lambda, and approximations of roughly d...
double[] getParams()
Return a table containing the parameters of the current distribution.
static double barF(double alpha, int d, double x)
Same as barF(alpha, 1.0, d, x).
Extends the class ContinuousDistribution for the normal distribution (e.g., tjoh95a  (page 80)).
static double cdf01(double x)
Same as cdf(0, 1, x).
static double barF01(double x)
Same as barF(0, 1, x).
double inverseF(double u)
Returns the inverse distribution function .
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static final double LN_DBL_MIN
Natural logarithm of DBL_MIN.
Definition Num.java:118
static double lnGamma(double x)
Returns the natural logarithm of the gamma function evaluated at x.
Definition Num.java:417
static double digamma(double x)
Returns the value of the logarithmic derivative of the Gamma function .
Definition Num.java:487
static final double LN2
The values of .
Definition Num.java:148
This class provides numerical methods to solve non-linear equations.
static double brentDekker(double a, double b, MathFunction f, double tol)
Computes a root of the function in f using the Brent-Dekker method.
static double bisection(double a, double b, MathFunction f, double tol)
Computes a root of the function in f using the bisection method.
This interface should be implemented by classes which represent univariate mathematical functions.