1 /**
2  Translation of SimpleRNG.
3  Removed the builtin RNG to use std.random, but kept the distribution functions.
4  John D. Cook confirmed this code as public domain.
5 
6  Authors: John D. Cook.
7  See_also: $(WEB www.johndcook.com/cpp_random_number_generation.html)
8  */
9 module gfm.math.simplerng;
10 
11 public import std.random;
12 import std.math;
13 
14 /// Returns: Normal (Gaussian) random sample.
15 /// See_also: Box-Muller algorithm.
16 double randNormal(RNG)(ref RNG rng, double mean = 0.0, double standardDeviation = 1.0)
17 {
18     assert(standardDeviation > 0);
19     double u1;
20 
21     do
22     {
23         u1 = uniform01(rng);
24     } while (u1 == 0); // u1 must not be zero
25     double u2 = uniform01(rng);
26     double r = sqrt(-2.0 * log(u1));
27     double theta = 2.0 * double(PI) * u2;
28     return mean + standardDeviation * r * sin(theta);
29 }
30 
31 /// Returns: Exponential random sample with specified mean.
32 double randExponential(RNG)(ref RNG rng, double mean = 1.0)
33 {
34     assert(mean > 0);
35     return -mean*log(uniform01(rng));
36 }
37 
38 /// Returns: Gamma random sample.
39 /// See_also: "A Simple Method for Generating Gamma Variables"
40 /// by George Marsaglia and Wai Wan Tsang.  ACM Transactions on Mathematical Software
41 /// Vol 26, No 3, September 2000, pages 363-372.
42 double randGamma(RNG)(ref RNG rng, double shape, double scale)
43 {
44     double d, c, x, xsquared, v, u;
45 
46     if (shape >= 1.0)
47     {
48         d = shape - 1.0/3.0;
49         c = 1.0/sqrt(9.0*d);
50         for (;;)
51         {
52             do
53             {
54                 x = randNormal(rng);
55                 v = 1.0 + c*x;
56             }
57             while (v <= 0.0);
58             v = v*v*v;
59             u = uniform01(rng);
60             xsquared = x*x;
61             if (u < 1.0 -.0331*xsquared*xsquared || log(u) < 0.5*xsquared + d*(1.0 - v + log(v)))
62                 return scale*d*v;
63         }
64     }
65     else
66     {
67         assert(shape > 0);
68         double g = randGamma(rng, shape+1.0, 1.0);
69         double w = uniform01(rng);
70         return scale*g*pow(w, 1.0/shape);
71     }
72 }
73 
74 /// Returns: Chi-square sample.
75 double randChiSquare(RNG)(ref RNG rng, double degreesOfFreedom)
76 {
77     // A chi squared distribution with n degrees of freedom
78     // is a gamma distribution with shape n/2 and scale 2.
79     return randGamma(rng, 0.5 * degreesOfFreedom, 2.0);
80 }
81 
82 /// Returns: Inverse-gamma sample.
83 double randInverseGamma(RNG)(ref RNG rng, double shape, double scale)
84 {
85     // If X is gamma(shape, scale) then
86     // 1/Y is inverse gamma(shape, 1/scale)
87     return 1.0 / randGamma(rng, shape, 1.0 / scale);
88 }
89 
90 /// Returns: Weibull sample.
91 double randWeibull(RNG)(ref RNG rng, double shape, double scale)
92 {
93     assert(shape > 0 && scale > 0);
94     return scale * pow(-log(uniform01(rng)), 1.0 / shape);
95 }
96 
97 /// Returns: Cauchy sample.
98 double randCauchy(RNG)(ref RNG rng, double median, double scale)
99 {
100     assert(scale > 0);
101     double p = uniform01(rng);
102 
103     // Apply inverse of the Cauchy distribution function to a uniform
104     return median + scale*tan(double(PI)*(p - 0.5));
105 }
106 
107 /// Returns: Student-t sample.
108 /// See_also: Seminumerical Algorithms by Knuth.
109 double randStudentT(RNG)(ref RNG rng, double degreesOfFreedom)
110 {
111     assert(degreesOfFreedom > 0);
112 
113 
114     double y1 = getNormal(rng);
115     double y2 = getChiSquare(rng, degreesOfFreedom);
116     return y1 / sqrt(y2 / degreesOfFreedom);
117 }
118 
119 /// Returns: Laplace distribution random sample (also known as the double exponential distribution).
120 double randLaplace(RNG)(ref RNG rng, double mean, double scale)
121 {
122     double u = uniform01(rng);
123     return (u < 0.5) ? (mean + scale*log(2.0*u))
124                         : (mean - scale*log(2*(1-u)));
125 }
126 
127 /// Returns: Log-normal sample.
128 double randLogNormal(RNG)(ref RNG rng, double mu, double sigma)
129 {
130     return exp(getNormal(rng, mu, sigma));
131 }
132 
133 /// Returns: Beta sample.
134 double randBeta(RNG)(ref RNG rng, double a, double b)
135 {
136     assert(a > 0 && b > 0);
137 
138     // There are more efficient methods for generating beta samples.
139     // However such methods are a little more efficient and much more complicated.
140     // For an explanation of why the following method works, see
141     // http://www.johndcook.com/distribution_chart.html#gamma_beta
142 
143     double u = getGamma(rng, a, 1.0);
144     double v = getGamma(rng, b, 1.0);
145     return u / (u + v);
146 }
147 
148 /// Returns: Poisson sample.
149 int randPoisson(RNG)(ref RNG rng, double lambda)
150 {
151     return (lambda < 30.0) ? poissonSmall(rng, lambda) : poissonLarge(rng, lambda);
152 }
153 
154 private
155 {
156     int poissonSmall(RNG)(ref RNG rng, double lambda)
157     {
158         // Algorithm due to Donald Knuth, 1969.
159         double p = 1.0, L = exp(-lambda);
160         int k = 0;
161         do
162         {
163             k++;
164             p *= uniform01(rng);
165         }
166         while (p > L);
167         return k - 1;
168     }
169 
170     int poissonLarge(RNG)(ref RNG rng, double lambda)
171     {
172         // "Rejection method PA" from "The Computer Generation of Poisson Random Variables" by A. C. Atkinson
173         // Journal of the Royal Statistical Society Series C (Applied Statistics) Vol. 28, No. 1. (1979)
174         // The article is on pages 29-35. The algorithm given here is on page 32.
175 
176         double c = 0.767 - 3.36/lambda;
177         double beta = double(PI)/sqrt(3.0*lambda);
178         double alpha = beta*lambda;
179         double k = log(c) - lambda - log(beta);
180 
181         for(;;)
182         {
183             double u = uniform01(rng);
184             double x = (alpha - log((1.0 - u)/u))/beta;
185             int n = cast(int)(floor(x + 0.5));
186             if (n < 0)
187                 continue;
188             double v = uniform01(rng);
189             double y = alpha - beta*x;
190             double temp = 1.0 + exp(y);
191             double lhs = y + log(v/(temp*temp));
192             double rhs = k + n*log(lambda) - logFactorial(n);
193             if (lhs <= rhs)
194                 return n;
195         }
196     }
197 
198     double logFactorial(int n) nothrow
199     {
200         assert(n >= 0);
201         if (n > 254)
202         {
203             double x = n + 1;
204             return (x - 0.5)*log(x) - x + 0.5*log(2*double(PI)) + 1.0/(12.0*x);
205         }
206         else
207         {
208             return LOG_FACTORIAL[n];
209         }
210     }
211 }
212 
213 private static immutable double[255] LOG_FACTORIAL =
214 [
215     0.000000000000000,
216     0.000000000000000,
217     0.693147180559945,
218     1.791759469228055,
219     3.178053830347946,
220     4.787491742782046,
221     6.579251212010101,
222     8.525161361065415,
223     10.604602902745251,
224     12.801827480081469,
225     15.104412573075516,
226     17.502307845873887,
227     19.987214495661885,
228     22.552163853123421,
229     25.191221182738683,
230     27.899271383840894,
231     30.671860106080675,
232     33.505073450136891,
233     36.395445208033053,
234     39.339884187199495,
235     42.335616460753485,
236     45.380138898476908,
237     48.471181351835227,
238     51.606675567764377,
239     54.784729398112319,
240     58.003605222980518,
241     61.261701761002001,
242     64.557538627006323,
243     67.889743137181526,
244     71.257038967168000,
245     74.658236348830158,
246     78.092223553315307,
247     81.557959456115029,
248     85.054467017581516,
249     88.580827542197682,
250     92.136175603687079,
251     95.719694542143202,
252     99.330612454787428,
253     102.968198614513810,
254     106.631760260643450,
255     110.320639714757390,
256     114.034211781461690,
257     117.771881399745060,
258     121.533081515438640,
259     125.317271149356880,
260     129.123933639127240,
261     132.952575035616290,
262     136.802722637326350,
263     140.673923648234250,
264     144.565743946344900,
265     148.477766951773020,
266     152.409592584497350,
267     156.360836303078800,
268     160.331128216630930,
269     164.320112263195170,
270     168.327445448427650,
271     172.352797139162820,
272     176.395848406997370,
273     180.456291417543780,
274     184.533828861449510,
275     188.628173423671600,
276     192.739047287844900,
277     196.866181672889980,
278     201.009316399281570,
279     205.168199482641200,
280     209.342586752536820,
281     213.532241494563270,
282     217.736934113954250,
283     221.956441819130360,
284     226.190548323727570,
285     230.439043565776930,
286     234.701723442818260,
287     238.978389561834350,
288     243.268849002982730,
289     247.572914096186910,
290     251.890402209723190,
291     256.221135550009480,
292     260.564940971863220,
293     264.921649798552780,
294     269.291097651019810,
295     273.673124285693690,
296     278.067573440366120,
297     282.474292687630400,
298     286.893133295426990,
299     291.323950094270290,
300     295.766601350760600,
301     300.220948647014100,
302     304.686856765668720,
303     309.164193580146900,
304     313.652829949878990,
305     318.152639620209300,
306     322.663499126726210,
307     327.185287703775200,
308     331.717887196928470,
309     336.261181979198450,
310     340.815058870798960,
311     345.379407062266860,
312     349.954118040770250,
313     354.539085519440790,
314     359.134205369575340,
315     363.739375555563470,
316     368.354496072404690,
317     372.979468885689020,
318     377.614197873918670,
319     382.258588773060010,
320     386.912549123217560,
321     391.575988217329610,
322     396.248817051791490,
323     400.930948278915760,
324     405.622296161144900,
325     410.322776526937280,
326     415.032306728249580,
327     419.750805599544780,
328     424.478193418257090,
329     429.214391866651570,
330     433.959323995014870,
331     438.712914186121170,
332     443.475088120918940,
333     448.245772745384610,
334     453.024896238496130,
335     457.812387981278110,
336     462.608178526874890,
337     467.412199571608080,
338     472.224383926980520,
339     477.044665492585580,
340     481.872979229887900,
341     486.709261136839360,
342     491.553448223298010,
343     496.405478487217580,
344     501.265290891579240,
345     506.132825342034830,
346     511.008022665236070,
347     515.890824587822520,
348     520.781173716044240,
349     525.679013515995050,
350     530.584288294433580,
351     535.496943180169520,
352     540.416924105997740,
353     545.344177791154950,
354     550.278651724285620,
355     555.220294146894960,
356     560.169054037273100,
357     565.124881094874350,
358     570.087725725134190,
359     575.057539024710200,
360     580.034272767130800,
361     585.017879388839220,
362     590.008311975617860,
363     595.005524249382010,
364     600.009470555327430,
365     605.020105849423770,
366     610.037385686238740,
367     615.061266207084940,
368     620.091704128477430,
369     625.128656730891070,
370     630.172081847810200,
371     635.221937855059760,
372     640.278183660408100,
373     645.340778693435030,
374     650.409682895655240,
375     655.484856710889060,
376     660.566261075873510,
377     665.653857411105950,
378     670.747607611912710,
379     675.847474039736880,
380     680.953419513637530,
381     686.065407301994010,
382     691.183401114410800,
383     696.307365093814040,
384     701.437263808737160,
385     706.573062245787470,
386     711.714725802289990,
387     716.862220279103440,
388     722.015511873601330,
389     727.174567172815840,
390     732.339353146739310,
391     737.509837141777440,
392     742.685986874351220,
393     747.867770424643370,
394     753.055156230484160,
395     758.248113081374300,
396     763.446610112640200,
397     768.650616799717000,
398     773.860102952558460,
399     779.075038710167410,
400     784.295394535245690,
401     789.521141208958970,
402     794.752249825813460,
403     799.988691788643450,
404     805.230438803703120,
405     810.477462875863580,
406     815.729736303910160,
407     820.987231675937890,
408     826.249921864842800,
409     831.517780023906310,
410     836.790779582469900,
411     842.068894241700490,
412     847.352097970438420,
413     852.640365001133090,
414     857.933669825857460,
415     863.231987192405430,
416     868.535292100464630,
417     873.843559797865740,
418     879.156765776907600,
419     884.474885770751830,
420     889.797895749890240,
421     895.125771918679900,
422     900.458490711945270,
423     905.796028791646340,
424     911.138363043611210,
425     916.485470574328820,
426     921.837328707804890,
427     927.193914982476710,
428     932.555207148186240,
429     937.921183163208070,
430     943.291821191335660,
431     948.667099599019820,
432     954.046996952560450,
433     959.431492015349480,
434     964.820563745165940,
435     970.214191291518320,
436     975.612353993036210,
437     981.015031374908400,
438     986.422203146368590,
439     991.833849198223450,
440     997.249949600427840,
441     1002.670484599700300,
442     1008.095434617181700,
443     1013.524780246136200,
444     1018.958502249690200,
445     1024.396581558613400,
446     1029.838999269135500,
447     1035.285736640801600,
448     1040.736775094367400,
449     1046.192096209724900,
450     1051.651681723869200,
451     1057.115513528895000,
452     1062.583573670030100,
453     1068.055844343701400,
454     1073.532307895632800,
455     1079.012946818975000,
456     1084.497743752465600,
457     1089.986681478622400,
458     1095.479742921962700,
459     1100.976911147256000,
460     1106.478169357800900,
461     1111.983500893733000,
462     1117.492889230361000,
463     1123.006317976526100,
464     1128.523770872990800,
465     1134.045231790853000,
466     1139.570684729984800,
467     1145.100113817496100,
468     1150.633503306223700,
469     1156.170837573242400,
470 ];
471 
472 unittest
473 {
474     Xorshift32 rng;
475     rng.seed(unpredictableSeed());
476 
477     double x = randNormal!Xorshift32(rng, 0.0, 1.0);
478     x = randExponential!Xorshift32(rng);
479     x = randGamma!Xorshift32(rng, 1.2, 1.0);
480     x = randGamma!Xorshift32(rng, 0.8, 2.0);
481     x = randChiSquare!Xorshift32(rng, 2.0);
482     x = randInverseGamma!Xorshift32(rng, 1.1, 0.7);
483     x = randWeibull!Xorshift32(rng, 3.0, 0.7);
484     x = randCauchy!Xorshift32(rng, 5.0, 1.4);
485 }