SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
GammaAcceptanceRejectionGen.java
1/*
2 * Class: GammaAcceptanceRejectionGen
3 * Description: gamma random variate generators using a method that combines
4 acceptance-rejection with acceptance-complement
5 * Environment: Java
6 * Software: SSJ
7 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
8 * Organization: DIRO, Universite de Montreal
9 * @author
10 * @since
11 *
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *
25 */
26package umontreal.ssj.randvar;
27
28import umontreal.ssj.rng.*;
29import umontreal.ssj.probdist.*;
30import umontreal.ssj.util.Num;
31import cern.jet.stat.Gamma;
32
64
65 private RandomStream auxStream;
66 private static final double q1 = 0.0416666664;
67 private static final double q2 = 0.0208333723;
68 private static final double q3 = 0.0079849875;
69 private static final double q4 = 0.0015746717;
70 private static final double q5 = -0.0003349403;
71 private static final double q6 = 0.0003340332;
72 private static final double q7 = 0.0006053049;
73 private static final double q8 = -0.0004701849;
74 private static final double q9 = 0.0001710320;
75 private static final double a1 = 0.333333333;
76 private static final double a2 = -0.249999949;
77 private static final double a3 = 0.199999867;
78 private static final double a4 = -0.166677482;
79 private static final double a5 = 0.142873973;
80 private static final double a6 = -0.124385581;
81 private static final double a7 = 0.110368310;
82 private static final double a8 = -0.112750886;
83 private static final double a9 = 0.104089866;
84 private static final double e1 = 1.000000000;
85 private static final double e2 = 0.499999994;
86 private static final double e3 = 0.166666848;
87 private static final double e4 = 0.041664508;
88 private static final double e5 = 0.008345522;
89 private static final double e6 = 0.001353826;
90 private static final double e7 = 0.000247453;
91
92 private int gen;
93 // UNURAN parameters for the distribution
94 private double beta;
95 private double gamma;
96 // Generator parameters
97 // Acceptance rejection combined with acceptance complement
98 private static final int gs = 0;
99 private static final int gd = 1;
100 private double b;
101 private double ss;
102 private double s;
103 private double d;
104 private double r;
105 private double q0;
106 private double c;
107 private double si;
108
109 // Threshold on shape parameter alpha.
110 // Method of Liu, Martin and Syring, @cite rLIU13a will be used if alpha
111 // is smaller than this threshold.
112 private static final double USE_LMS_THRESHOLD = 0.1;
113
122 public GammaAcceptanceRejectionGen(RandomStream s, RandomStream aux, double alpha, double lambda) {
123 super(s, null);
124 auxStream = aux;
125 setParams(alpha, lambda); // lambda is the rate.
126 beta = 1.0 / lambda; // scale parameter.
127 gamma = 0.0;
128 init();
129 }
130
136 public GammaAcceptanceRejectionGen(RandomStream s, double alpha, double lambda) {
137 this(s, s, alpha, lambda);
138 }
139
146 super(s, dist);
147 auxStream = aux;
148 if (dist != null)
149 setParams(dist.getAlpha(), dist.getLambda());
150 beta = 1.0 / dist.getLambda();
151 gamma = 0.0;
152 init();
153 }
154
160 this(s, s, dist);
161 }
162
167 return auxStream;
168 }
169
176 public static double nextDouble(RandomStream s, RandomStream aux, double alpha, double lambda) {
177 int gen = gs;
178 double s_ = 0, ss = 0, d = 0, q0 = 0, r = 0, c = 0, si = 0, b = 0;
179
180 if (alpha < USE_LMS_THRESHOLD) {
181 // algorithm of Liu, Martin and Syring (2015)
182 return acceptanceRejectionLms(s, aux, alpha, 1.0 / lambda);
183 }
184 // Code taken from UNURAN
185 else if (alpha < 1.0) {
186 gen = gs;
187 b = 1.0 + 0.36788794412 * alpha; // Step 1
188 } else {
189 gen = gd;
190 // Step 1. Preparations
191 ss = alpha - 0.5;
192 s_ = Math.sqrt(ss);
193 d = 5.656854249 - 12.0 * s_;
194
195 // Step 4. Set-up for hat case
196 r = 1.0 / alpha;
197 q0 = ((((((((q9 * r + q8) * r + q7) * r + q6) * r + q5) * r + q4) * r + q3) * r + q2) * r + q1) * r;
198 if (alpha > 3.686) {
199 if (alpha > 13.022) {
200 b = 1.77;
201 si = 0.75;
202 c = 0.1515 / s_;
203 } else {
204 b = 1.654 + 0.0076 * ss;
205 si = 1.68 / s_ + 0.275;
206 c = 0.062 / s_ + 0.024;
207 }
208 } else {
209 b = 0.463 + s_ - 0.178 * ss;
210 si = 1.235;
211 c = 0.195 / s_ - 0.079 + 0.016 * s_;
212 }
213 }
214 return acceptanceRejection(s, aux, alpha, 1.0 / lambda, 0, gen, b, s_, ss, d, r, q0, c, si);
215 }
216
217 public double nextDouble() {
218 if (alpha < USE_LMS_THRESHOLD)
219 return acceptanceRejectionLms(stream, auxStream, alpha, beta);
220
221 return acceptanceRejection(stream, auxStream, alpha, beta, gamma, gen, b, s, ss, d, r, q0, c, si);
222 }
223
227 public static double nextDouble(RandomStream s, double alpha, double lambda) {
228 return nextDouble(s, s, alpha, lambda);
229 }
230
237 public double nextDoubleLog() {
238 if (alpha < USE_LMS_THRESHOLD)
239 return acceptanceRejectionLmsLog(stream, auxStream, alpha, beta);
240
241 return Math.log(acceptanceRejection(stream, auxStream, alpha, beta, gamma, gen, b, s, ss, d, r, q0, c, si));
242 }
243
253 public static double nextDoubleLog(RandomStream s, RandomStream aux, double alpha, double lambda) {
254 int gen = gs;
255 double s_ = 0, ss = 0, d = 0, q0 = 0, r = 0, c = 0, si = 0, b = 0;
256
257 if (alpha < USE_LMS_THRESHOLD) {
258 // algorithm of Liu, Martin and Syring (2015)
259 return acceptanceRejectionLmsLog(s, aux, alpha, 1.0 / lambda);
260 } else {
261 return Math.log(nextDouble(s, aux, alpha, lambda));
262 }
263 }
264
268 public static double nextDoubleLog(RandomStream s, double alpha, double lambda) {
269 return nextDoubleLog(s, s, alpha, lambda);
270 }
271
272 private static double acceptanceRejection(RandomStream stream, RandomStream auxStream, double alpha, double beta,
273 double gamma, int gen, double b, double s, double ss, double d, double r, double q0, double c, double si) {
274 // Code taken from UNURAN
275 double X, p, U, E;
276 double q, sign_U, t, v, w, x;
277 switch (gen) {
278 case gs:
279 while (true) {
280 p = b * stream.nextDouble();
281 stream = auxStream;
282 if (p <= 1.0) { // Step 2. Case gds <= 1
283 X = Math.exp(Math.log(p) / alpha);
284 if (Math.log(stream.nextDouble()) <= -X)
285 break;
286 } else { // Step 3. Case gds > 1
287 X = -Math.log((b - p) / alpha);
288 if (Math.log(stream.nextDouble()) <= ((alpha - 1.0) * Math.log(X)))
289 break;
290 }
291 }
292 break;
293 case gd:
294 do {
295
296 // Step 2. Normal deviate
297 t = NormalDist.inverseF01(stream.nextDouble());
298 stream = auxStream;
299 x = s + 0.5 * t;
300 X = x * x;
301 if (t >= 0.)
302 break; // Immediate acceptance
303
304 // Step 3. Uniform random number
305 U = stream.nextDouble();
306 if (d * U <= t * t * t)
307 break; // Squeeze acceptance
308
309 // Step 5. Calculation of q
310 if (x > 0.) {
311 // Step 6.
312 v = t / (s + s);
313 if (Math.abs(v) > 0.25)
314 q = q0 - s * t + 0.25 * t * t + (ss + ss) * Math.log(1. + v);
315 else
316 q = q0 + 0.5 * t * t
317 * ((((((((a9 * v + a8) * v + a7) * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1)
318 * v;
319 // Step 7. Quotient acceptance
320 if (Math.log(1. - U) <= q)
321 break;
322 }
323
324 // Step 8. Double exponential deviate t
325 while (true) {
326 do {
327 E = -Math.log(stream.nextDouble());
328 U = stream.nextDouble();
329 U = U + U - 1.;
330 sign_U = (U > 0) ? 1. : -1.;
331 t = b + (E * si) * sign_U;
332 } while (t <= -0.71874483771719); // Step 9. Rejection of t
333
334 // Step 10. New q(t)
335 v = t / (s + s);
336 if (Math.abs(v) > 0.25)
337 q = q0 - s * t + 0.25 * t * t + (ss + ss) * Math.log(1. + v);
338 else
339 q = q0 + 0.5 * t * t
340 * ((((((((a9 * v + a8) * v + a7) * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1)
341 * v;
342
343 // Step 11.
344 if (q <= 0.)
345 continue;
346
347 if (q > 0.5)
348 w = Math.exp(q) - 1.;
349 else
350 w = ((((((e7 * q + e6) * q + e5) * q + e4) * q + e3) * q + e2) * q + e1) * q;
351
352 // Step 12. Hat acceptance
353 if (c * U * sign_U <= w * Math.exp(E - 0.5 * t * t)) {
354 x = s + 0.5 * t;
355 X = x * x;
356 break;
357 }
358 }
359 } while (false);
360 break;
361 default:
362 throw new IllegalStateException();
363 }
364
365 return gamma + beta * X;
366 }
367
372 private static double acceptanceRejectionLms(RandomStream stream, RandomStream auxStream, double alpha,
373 double scale) {
374
375 return Math.exp(acceptanceRejectionLmsLog(stream, auxStream, alpha, scale)); // return the gamma variable
376 }
377
385 private static double acceptanceRejectionLmsLog(RandomStream stream, RandomStream auxStream, double alpha,
386 double scale) {
387
388 double lambda = 1.0 / alpha - 1.0;
389 double w = alpha / Num.EBASE / (1.0 - alpha);
390 double r = 1.0 / (1.0 + w);
391 double c = 1.0 / Gamma.gamma(alpha + 1.0);
392
393 double u = stream.nextDouble();
394 double z = 0;
395 double Z = 0;
396 while (true) {
397 if (u <= r) {
398 z = -Math.log(u / r);
399 } else {
400 z = Math.log(auxStream.nextDouble()) / lambda;
401 }
402 if (functionHLms(z, alpha, c) / functionEtaLms(z, alpha, lambda, w, c) > auxStream.nextDouble()) {
403 Z = z;
404 break;
405 }
406 u = auxStream.nextDouble();
407 }
408 return Math.log(scale) - (Z / alpha); // return scaled log gamma variable
409 }
410
411 // The function h in Liu, Martin and Syring (2015).
412 private static double functionHLms(double z, double alpha, double c) {
413 return c * Math.exp(-z - Math.exp(-z / alpha));
414 }
415
416 // The function eta in Liu, Martin and Syring (2015).
417 private static double functionEtaLms(double z, double alpha, double lambda, double w, double c) {
418 if (z >= 0)
419 return c * Math.exp(-z);
420 else
421 return c * w * lambda * Math.exp(lambda * z);
422 }
423
424 private void init() {
425 // Code taken from UNURAN
426 if (alpha < 1.0) {
427 gen = gs;
428 b = 1.0 + 0.36788794412 * alpha; // Step 1
429 } else {
430 gen = gd;
431 // Step 1. Preparations
432 ss = alpha - 0.5;
433 s = Math.sqrt(ss);
434 d = 5.656854249 - 12.0 * s;
435
436 // Step 4. Set-up for hat case
437 r = 1.0 / alpha;
438 q0 = ((((((((q9 * r + q8) * r + q7) * r + q6) * r + q5) * r + q4) * r + q3) * r + q2) * r + q1) * r;
439 if (alpha > 3.686) {
440 if (alpha > 13.022) {
441 b = 1.77;
442 si = 0.75;
443 c = 0.1515 / s;
444 } else {
445 b = 1.654 + 0.0076 * ss;
446 si = 1.68 / s + 0.275;
447 c = 0.062 / s + 0.024;
448 }
449 } else {
450 b = 0.463 + s - 0.178 * ss;
451 si = 1.235;
452 c = 0.195 / s - 0.079 + 0.016 * s;
453 }
454 }
455 }
456
457}
Extends the class ContinuousDistribution for the gamma distribution tjoh95a  (page 337) with shape pa...
Extends the class ContinuousDistribution for the normal distribution (e.g., tjoh95a  (page 80)).
static double inverseF01(double u)
Same as inverseF(0, 1, u).
GammaAcceptanceRejectionGen(RandomStream s, RandomStream aux, GammaDist dist)
Creates a new generator object for the gamma distribution dist, using main stream s and auxiliary str...
static double nextDoubleLog(RandomStream s, double alpha, double lambda)
Same as nextDoubleLog (s, s, alpha, lambda).
static double nextDouble(RandomStream s, double alpha, double lambda)
Same as nextDouble (s, s, alpha, lambda).
GammaAcceptanceRejectionGen(RandomStream s, RandomStream aux, double alpha, double lambda)
Creates a gamma random variate generator with parameters.
GammaAcceptanceRejectionGen(RandomStream s, double alpha, double lambda)
Creates a gamma random variate generator with parameters.
RandomStream getAuxStream()
Returns the auxiliary stream associated with this object.
double nextDoubleLog()
Returns the natural log value of a new gamma variate.
static double nextDoubleLog(RandomStream s, RandomStream aux, double alpha, double lambda)
Returns the natural log value of a new gamma variate with parameters.
static double nextDouble(RandomStream s, RandomStream aux, double alpha, double lambda)
Generates a new gamma variate with parameters &#160;alpha and &#160;lambda, using main stream s and auxilia...
GammaAcceptanceRejectionGen(RandomStream s, GammaDist dist)
Creates a new generator object for the gamma distribution dist and stream s for both the main and aux...
double nextDouble()
Generates a random number from the continuous distribution contained in this object.
GammaGen(RandomStream s, double alpha, double lambda)
Creates a gamma random variate generator with parameters.
Definition GammaGen.java:56
void setParams(double alpha, double lambda)
Sets the parameter and of this object.
static final double EBASE
The constant .
Definition Num.java:128
This interface defines the basic structures to handle multiple streams of uniform (pseudo)random numb...
double nextDouble()
Returns a (pseudo)random number from the uniform distribution over the interval , using this stream,...