1 // -*- C++ -*-
2 // $Id$
3 
4 /*
5  * Gamma distribution
6  *
7  * Source: Ahrens, J.H. and Dieter, U., Generating Gamma variates
8  * by a modified rejection technique.  Comm. ACM, 25,1 (Jan. 1982)
9  * pp. 47-54.
10  *
11  * This code has been adapted from RANDLIB.C 1.3, by
12  * Barry W. Brown, James Lovato, Kathy Russell, and John Venier.
13  * Code was originally by Ahrens and Dieter (see above).
14  *
15  * Adapter's notes:
16  * NEEDS_WORK: more precision for literals.
17  * NEEDS_WORK: ideally the normal_ member should be driven from
18  * the same IRNG as the Gamma object, in the event that independentState
19  * is used.  Not clear how this could be accomplished.
20  */
21 
22 #ifndef BZ_RANDOM_GAMMA
23 #define BZ_RANDOM_GAMMA
24 
25 #ifndef BZ_RANDOM_UNIFORM
26  #include <random/uniform.h>
27 #endif
28 
29 #ifndef BZ_RANDOM_NORMAL
30  #include <random/normal.h>
31 #endif
32 
33 #ifndef BZ_RANDOM_EXPONENTIAL
34  #include <random/exponential.h>
35 #endif
36 
37 #ifndef BZ_NUMINQUIRE_H
38  #include <blitz/numinquire.h>
39 #endif
40 
41 namespace ranlib {
42 
43 template<typename T = double, typename IRNG = defaultIRNG,
44     typename stateTag = defaultState>
45 class Gamma : public UniformOpen<T,IRNG,stateTag>
46 {
47 public:
48     typedef T T_numtype;
49 
Gamma()50     Gamma()
51     {
52         setMean(1.0);
53     }
54 
Gamma(unsigned int i)55   explicit Gamma(unsigned int i) :
56     UniformOpen<T,IRNG,stateTag>(i)
57   {
58     setMean(1.0);
59   };
60 
Gamma(T mean)61     Gamma(T mean)
62     {
63         setMean(mean);
64     }
65 
Gamma(T mean,unsigned int i)66   Gamma(T mean, unsigned int i) :
67     UniformOpen<T,IRNG,stateTag>(i)
68   {
69     setMean(mean);
70   };
71 
72     T random();
73 
setMean(T mean)74     void setMean(T mean)
75     {
76         BZPRECONDITION(mean >= 1.0);
77         a = mean;
78     }
79 
80 protected:
ranf()81     T ranf()
82     {
83         return UniformOpen<T,IRNG,stateTag>::random();
84     }
85 
snorm()86     T snorm()
87     {
88         return normal_.random();
89     }
90 
sexpo()91     T sexpo()
92     {
93         return exponential_.random();
94     }
95 
fsign(T num,T sign)96     T fsign(T num, T sign)
97     {
98         /* Transfers sign of argument sign to argument num */
99 
100         if ((sign>0.0L && num<0.0L)||(sign<0.0L && num>0.0L))
101             return -num;
102         else
103             return num;
104     }
105 
106     NormalUnit<T,IRNG,sharedState> normal_;
107     ExponentialUnit<T,IRNG,sharedState> exponential_;
108 
109     T a;
110 };
111 
112 template<typename T, typename IRNG, typename stateTag>
random()113 T Gamma<T,IRNG,stateTag>::random()
114 {
115     /*
116      INPUT: A =PARAMETER (MEAN) OF THE STANDARD GAMMA DISTRIBUTION
117      OUTPUT: SGAMMA = SAMPLE FROM THE GAMMA-(A)-DISTRIBUTION
118      COEFFICIENTS Q(K) - FOR Q0 = SUM(Q(K)*A**(-K))
119      COEFFICIENTS A(K) - FOR Q = Q0+(T*T/2)*SUM(A(K)*V**K)
120      COEFFICIENTS E(K) - FOR EXP(Q)-1 = SUM(E(K)*Q**K)
121      PREVIOUS A PRE-SET TO ZERO - AA IS A', AAA IS A"
122      SQRT32 IS THE SQUAREROOT OF 32 = 5.656854249492380
123      */
124 
125 static T q1 = 4.166669E-2;
126 static T q2 = 2.083148E-2;
127 static T q3 = 8.01191E-3;
128 static T q4 = 1.44121E-3;
129 static T q5 = -7.388E-5;
130 static T q6 = 2.4511E-4;
131 static T q7 = 2.424E-4;
132 static T a1 = 0.3333333;
133 static T a2 = -0.250003;
134 static T a3 = 0.2000062;
135 static T a4 = -0.1662921;
136 static T a5 = 0.1423657;
137 static T a6 = -0.1367177;
138 static T a7 = 0.1233795;
139 static T e1 = 1.0;
140 static T e2 = 0.4999897;
141 static T e3 = 0.166829;
142 static T e4 = 4.07753E-2;
143 static T e5 = 1.0293E-2;
144 static T aa = 0.0;
145 static T aaa = 0.0;
146 static T sqrt32 = 5.656854249492380195206754896838792314280;
147 
148 /* JJV added b0 to fix rare and subtle bug */
149 static T sgamma,s2,s,d,t,x,u,r,q0,b,b0,si,c,v,q,e,w,p;
150 
151     if(a == aa) goto S10;
152     if(a < 1.0) goto S120;
153 /*
154      STEP  1:  RECALCULATIONS OF S2,S,D IF A HAS CHANGED
155 */
156     aa = a;
157     s2 = a-0.5;
158     s = sqrt(s2);
159     d = sqrt32-12.0*s;
160 S10:
161 /*
162      STEP  2:  T=STANDARD NORMAL DEVIATE,
163                X=(S,1/2)-NORMAL DEVIATE.
164                IMMEDIATE ACCEPTANCE (I)
165 */
166     t = snorm();
167     x = s+0.5*t;
168     sgamma = x*x;
169     if(t >= 0.0) return sgamma;
170 /*
171      STEP  3:  U= 0,1 -UNIFORM SAMPLE. SQUEEZE ACCEPTANCE (S)
172 */
173     u = ranf();
174     if(d*u <= t*t*t) return sgamma;
175 /*
176      STEP  4:  RECALCULATIONS OF Q0,B,SI,C IF NECESSARY
177 */
178     if(a == aaa) goto S40;
179     aaa = a;
180     r = 1.0/ a;
181     q0 = ((((((q7*r+q6)*r+q5)*r+q4)*r+q3)*r+q2)*r+q1)*r;
182 /*
183                APPROXIMATION DEPENDING ON SIZE OF PARAMETER A
184                THE CONSTANTS IN THE EXPRESSIONS FOR B, SI AND
185                C WERE ESTABLISHED BY NUMERICAL EXPERIMENTS
186 */
187     if(a <= 3.686) goto S30;
188     if(a <= 13.022) goto S20;
189 /*
190                CASE 3:  A .GT. 13.022
191 */
192     b = 1.77;
193     si = 0.75;
194     c = 0.1515/s;
195     goto S40;
196 S20:
197 /*
198                CASE 2:  3.686 .LT. A .LE. 13.022
199 */
200     b = 1.654+7.6E-3*s2;
201     si = 1.68/s+0.275;
202     c = 6.2E-2/s+2.4E-2;
203     goto S40;
204 S30:
205 /*
206                CASE 1:  A .LE. 3.686
207 */
208     b = 0.463+s+0.178*s2;
209     si = 1.235;
210     c = 0.195/s-7.9E-2+1.6E-1*s;
211 S40:
212 /*
213      STEP  5:  NO QUOTIENT TEST IF X NOT POSITIVE
214 */
215     if(x <= 0.0) goto S70;
216 /*
217      STEP  6:  CALCULATION OF V AND QUOTIENT Q
218 */
219     v = t/(s+s);
220     if(fabs(v) <= 0.25) goto S50;
221     q = q0-s*t+0.25*t*t+(s2+s2)*log(1.0+v);
222     goto S60;
223 S50:
224     q = q0+0.5*t*t*((((((a7*v+a6)*v+a5)*v+a4)*v+a3)*v+a2)*v+a1)*v;
225 S60:
226 /*
227      STEP  7:  QUOTIENT ACCEPTANCE (Q)
228 */
229     if(log(1.0-u) <= q) return sgamma;
230 S70:
231 /*
232      STEP  8:  E=STANDARD EXPONENTIAL DEVIATE
233                U= 0,1 -UNIFORM DEVIATE
234                T=(B,SI)-DOUBLE EXPONENTIAL (LAPLACE) SAMPLE
235 */
236     e = sexpo();
237     u = ranf();
238     u += (u-1.0);
239     t = b+fsign(si*e,u);
240 /*
241      STEP  9:  REJECTION IF T .LT. TAU(1) = -.71874483771719
242 */
243     if(t < -0.7187449) goto S70;
244 /*
245      STEP 10:  CALCULATION OF V AND QUOTIENT Q
246 */
247     v = t/(s+s);
248     if(fabs(v) <= 0.25) goto S80;
249     q = q0-s*t+0.25*t*t+(s2+s2)*log(1.0+v);
250     goto S90;
251 S80:
252     q = q0+0.5*t*t*((((((a7*v+a6)*v+a5)*v+a4)*v+a3)*v+a2)*v+a1)*v;
253 S90:
254 /*
255      STEP 11:  HAT ACCEPTANCE (H) (IF Q NOT POSITIVE GO TO STEP 8)
256 */
257     if(q <= 0.0) goto S70;
258     if(q <= 0.5) goto S100;
259 /*
260  * JJV modified the code through line 115 to handle large Q case
261  */
262     if(q < 15.0) goto S95;
263 /*
264  * JJV Here Q is large enough that Q = log(exp(Q) - 1.0) (for real Q)
265  * JJV so reformulate test at 110 in terms of one EXP, if not too big
266  * JJV 87.49823 is close to the largest real which can be
267  * JJV exponentiated (87.49823 = log(1.0E38))
268  */
269     if((q+e-0.5*t*t) > 87.49823) goto S115;
270     if(c*fabs(u) > exp(q+e-0.5*t*t)) goto S70;
271     goto S115;
272 S95:
273     w = exp(q)-1.0;
274     goto S110;
275 S100:
276     w = ((((e5*q+e4)*q+e3)*q+e2)*q+e1)*q;
277 S110:
278 /*
279                IF T IS REJECTED, SAMPLE AGAIN AT STEP 8
280 */
281     if(c*fabs(u) > w*exp(e-0.5*t*t)) goto S70;
282 S115:
283     x = s+0.5*t;
284     sgamma = x*x;
285     return sgamma;
286 S120:
287 /*
288      ALTERNATE METHOD FOR PARAMETERS A BELOW 1  (.3678794=EXP(-1.))
289 
290      JJV changed B to B0 (which was added to declarations for this)
291      JJV in 120 to END to fix rare and subtle bug.
292      JJV Line: 'aa = 0.0' was removed (unnecessary, wasteful).
293      JJV Reasons: the state of AA only serves to tell the A >= 1.0
294      JJV case if certain A-dependent constants need to be recalculated.
295      JJV The A < 1.0 case (here) no longer changes any of these, and
296      JJV the recalculation of B (which used to change with an
297      JJV A < 1.0 call) is governed by the state of AAA anyway.
298     aa = 0.0;
299 */
300     b0 = 1.0+0.3678794*a;
301 S130:
302     p = b0*ranf();
303     if(p >= 1.0) goto S140;
304     sgamma = exp(log(p)/ a);
305     if(sexpo() < sgamma) goto S130;
306     return sgamma;
307 S140:
308     sgamma = -log((b0-p)/ a);
309     if(sexpo() < (1.0-a)*log(sgamma)) goto S130;
310     return sgamma;
311 
312 }
313 
314 }
315 
316 #endif // BZ_RANDOM_GAMMA
317