bpp-core  2.2.0
RandomTools.cpp
Go to the documentation of this file.
1 //
2 // File RandomTools.cpp
3 // Author : Julien Dutheil
4 // Last modification : Friday Septembre 24 2004
5 //
6 
7 /*
8  Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
9 
10  This software is a computer program whose purpose is to provide classes
11  for numerical calculus.
12 
13  This software is governed by the CeCILL license under French law and
14  abiding by the rules of distribution of free software. You can use,
15  modify and/ or redistribute the software under the terms of the CeCILL
16  license as circulated by CEA, CNRS and INRIA at the following URL
17  "http://www.cecill.info".
18 
19  As a counterpart to the access to the source code and rights to copy,
20  modify and redistribute granted by the license, users are provided only
21  with a limited warranty and the software's author, the holder of the
22  economic rights, and the successive licensors have only limited
23  liability.
24 
25  In this respect, the user's attention is drawn to the risks associated
26  with loading, using, modifying and/or developing or reproducing the
27  software by the user in light of its specific status of free software,
28  that may mean that it is complicated to manipulate, and that also
29  therefore means that it is reserved for developers and experienced
30  professionals having in-depth computer knowledge. Users are therefore
31  encouraged to load and test the software's suitability as regards their
32  requirements in conditions enabling the security of their systems and/or
33  data to be ensured and, more generally, to use and operate it in the
34  same conditions as regards security.
35 
36  The fact that you are presently reading this means that you have had
37  knowledge of the CeCILL license and that you accept its terms.
38  */
39 
40 #include "RandomTools.h"
41 #include "Uniform01K.h"
42 #include "../VectorTools.h"
43 #include "../NumConstants.h"
44 
45 #include <iostream>
46 
47 using namespace bpp;
48 using namespace std;
49 
51 
52 // Initiate random seed :
53 // RandomTools::RandInt RandomTools::r = time(NULL) ;
54 
55 void RandomTools::setSeed(long seed)
56 {
57  DEFAULT_GENERATOR->setSeed(seed);
58 }
59 
60 // Method to get a double random value (between 0 and specified range)
61 // Note : the number you get is between 0 and entry not including entry !
63 {
64  // double tm = r.drawFloatNumber();
65  double tm = generator.drawNumber();
66  return tm * entry;
67 }
68 
69 // Method to get a boolean random value
70 bool RandomTools::flipCoin(const RandomFactory& generator)
71 {
72  return (RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0, generator) - 0.5) > 0;
73 }
74 
75 double RandomTools::randGaussian(double mean, double variance, const RandomFactory& generator)
76 {
77  return RandomTools::qNorm(generator.drawNumber(), mean, sqrt(variance));
78 }
79 
80 double RandomTools::randGamma(double dblAlpha, const RandomFactory& generator)
81 {
82  assert(dblAlpha > 0.0);
83  if (dblAlpha < 1.0)
84  return RandomTools::DblGammaLessThanOne(dblAlpha, generator);
85  else if (dblAlpha > 1.0)
86  return RandomTools::DblGammaGreaterThanOne(dblAlpha, generator);
87  return -log(RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0, generator));
88 }
89 
90 double RandomTools::randGamma(double alpha, double beta, const RandomFactory& generator)
91 {
92  double x = RandomTools::randGamma(alpha, generator) / beta;
93  return x;
94 }
95 
96 double RandomTools::randExponential(double mean, const RandomFactory& generator)
97 {
98  return -mean* log(RandomTools::giveRandomNumberBetweenZeroAndEntry(1, generator));
99 }
100 
101 std::vector<size_t> RandomTools::randMultinomial(size_t n, const std::vector<double>& probs)
102 {
103  double s = VectorTools::sum(probs);
104  double r;
105  double cumprob;
106  vector<size_t> sample(n);
107  for (unsigned int i = 0; i < n; i++)
108  {
110  cumprob = 0;
111  bool test = true;
112  for (unsigned int j = 0; test &(j < probs.size()); j++)
113  {
114  cumprob += probs[j] / s;
115  if (r <= cumprob)
116  {
117  sample[i] = j;
118  test = false;
119  }
120  }
121  // This test should never be true if probs sum to one:
122  if (test)
123  sample[i] = probs.size();
124  }
125  return sample;
126 }
127 
128 // ------------------------------------------------------------------------------
129 
130 
131 double RandomTools::DblGammaGreaterThanOne(double dblAlpha, const RandomFactory& generator)
132 {
133  // Code adopted from David Heckerman
134  // -----------------------------------------------------------
135  // DblGammaGreaterThanOne(dblAlpha)
136  //
137  // routine to generate a gamma random variable with unit scale and
138  // alpha > 1
139  // reference: Ripley, Stochastic Simulation, p.90
140  // Chang and Feast, Appl.Stat. (28) p.290
141  // -----------------------------------------------------------
142  double rgdbl[6];
143 
144  rgdbl[1] = dblAlpha - 1.0;
145  rgdbl[2] = (dblAlpha - (1.0 / (6.0 * dblAlpha))) / rgdbl[1];
146  rgdbl[3] = 2.0 / rgdbl[1];
147  rgdbl[4] = rgdbl[3] + 2.0;
148  rgdbl[5] = 1.0 / sqrt(dblAlpha);
149 
150  for ( ; ; )
151  {
152  double dblRand1;
153  double dblRand2;
154  do
155  {
156  dblRand1 = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0, generator);
157  dblRand2 = RandomTools::giveRandomNumberBetweenZeroAndEntry(1.0, generator);
158  if (dblAlpha > 2.5)
159  dblRand1 = dblRand2 + rgdbl[5] * (1.0 - 1.86 * dblRand1);
160  }
161  while (!(0.0 < dblRand1 && dblRand1 < 1.0));
162 
163  double dblTemp = rgdbl[2] * dblRand2 / dblRand1;
164 
165  if (rgdbl[3] * dblRand1 + dblTemp + 1.0 / dblTemp <= rgdbl[4] ||
166  rgdbl[3] * log(dblRand1) + dblTemp - log(dblTemp) < 1.0)
167  {
168  return dblTemp * rgdbl[1];
169  }
170  }
171  assert(false);
172  return 0.0;
173 }
174 
175 double RandomTools::DblGammaLessThanOne(double dblAlpha, const RandomFactory& generator)
176 {
177  // routine to generate a gamma random variable with
178  // unit scale and alpha < 1
179  // reference: Ripley, Stochastic Simulation, p.88
180  double dblTemp;
181  const double dblexp = exp(1.0);
182  for ( ; ; )
183  {
184  double dblRand0 = giveRandomNumberBetweenZeroAndEntry(1.0, generator);
185  double dblRand1 = giveRandomNumberBetweenZeroAndEntry(1.0, generator);
186  if (dblRand0 <= (dblexp / (dblAlpha + dblexp)))
187  {
188  dblTemp = pow(((dblAlpha + dblexp) * dblRand0) /
189  dblexp, 1.0 / dblAlpha);
190  if (dblRand1 <= exp(-1.0 * dblTemp))
191  return dblTemp;
192  }
193  else
194  {
195  dblTemp = -1.0 * log((dblAlpha + dblexp) * (1.0 - dblRand0) / (dblAlpha * dblexp));
196  if (dblRand1 <= pow(dblTemp, dblAlpha - 1.0))
197  return dblTemp;
198  }
199  }
200  assert(false);
201  return 0.0;
202 }
203 
204 /******************************************************************************/
205 
206 // From Yang's PAML package:
207 
208 /******************************************************************************/
209 
210 double RandomTools::qNorm(double prob)
211 {
212  double a0 = -.322232431088, a1 = -1, a2 = -.342242088547, a3 = -.0204231210245;
213  double a4 = -.453642210148e-4, b0 = .0993484626060, b1 = .588581570495;
214  double b2 = .531103462366, b3 = .103537752850, b4 = .0038560700634;
215  double y, z = 0, p = prob, p1;
216 
217  p1 = (p < 0.5 ? p : 1 - p);
218  if (p1 < 1e-20)
219  return -9999;
220 
221  y = sqrt (log(1 / (p1 * p1)));
222  z = y + ((((y * a4 + a3) * y + a2) * y + a1) * y + a0) / ((((y * b4 + b3) * y + b2) * y + b1) * y + b0);
223  return p < 0.5 ? -z : z;
224 }
225 
226 double RandomTools::qNorm(double prob, double mu, double sigma)
227 {
228  return RandomTools::qNorm(prob) * sigma + mu;
229 }
230 
231 
232 double RandomTools::lnGamma (double alpha)
233 {
234  double x = alpha, f = 0, z;
235 
236  if (x < 7)
237  {
238  f = 1; z = x - 1;
239  while (++z < 7)
240  f *= z;
241  x = z; f = -log(f);
242  }
243  z = 1 / (x * x);
244  return f + (x - 0.5) * log(x) - x + .918938533204673
245  + (((-.000595238095238 * z + .000793650793651) * z - .002777777777778) * z
246  + .083333333333333) / x;
247 }
248 
249 
250 double RandomTools::incompleteGamma (double x, double alpha, double ln_gamma_alpha)
251 {
252  size_t i;
253  double p = alpha, g = ln_gamma_alpha;
254  double accurate = 1e-8, overflow = 1e30;
255  double factor, gin = 0, rn = 0, a = 0, b = 0, an = 0, dif = 0, term = 0;
256  vector<double> pn(6);
257 
258  if (x == 0)
259  return 0;
260  if (x < 0 || p <= 0)
261  return -1;
262 
263  factor = exp(p * log(x) - x - g);
264  if (x > 1 && x >= p)
265  goto l30;
266  /* (1) series expansion */
267  gin = 1; term = 1; rn = p;
268 l20:
269  rn++;
270  term *= x / rn; gin += term;
271 
272  if (term > accurate)
273  goto l20;
274  gin *= factor / p;
275  goto l50;
276 l30:
277  /* (2) continued fraction */
278  a = 1 - p; b = a + x + 1; term = 0;
279  pn[0] = 1; pn[1] = x; pn[2] = x + 1; pn[3] = x * b;
280  gin = pn[2] / pn[3];
281 l32:
282  a++; b += 2; term++; an = a * term;
283  for (i = 0; i < 2; i++)
284  {
285  pn[i + 4] = b * pn[i + 2] - an * pn[i];
286  }
287  if (pn[5] == 0)
288  goto l35;
289  rn = pn[4] / pn[5]; dif = fabs(gin - rn);
290  if (dif > accurate)
291  goto l34;
292  if (dif <= accurate * rn)
293  goto l42;
294 l34:
295  gin = rn;
296 l35:
297  for (i = 0; i < 4; i++)
298  {
299  pn[i] = pn[i + 2];
300  }
301  if (fabs(pn[4]) < overflow)
302  goto l32;
303  for (i = 0; i < 4; i++)
304  {
305  pn[i] /= overflow;
306  }
307  goto l32;
308 l42:
309  gin = 1 - factor * gin;
310 
311 l50:
312 
313  return gin;
314 }
315 
316 
317 double RandomTools::qChisq(double prob, double v)
318 {
319  double e = .5e-6, aa = .6931471805, p = prob, g;
320  double xx, c, ch, a = 0, q = 0, p1 = 0, p2 = 0, t = 0, x = 0, b = 0, s1, s2, s3, s4, s5, s6;
321 
322  if (p < .000002 || p > .999998 || v <= 0)
323  return -1;
324 
325  g = lnGamma (v / 2);
326  xx = v / 2; c = xx - 1;
327  if (v >= -1.24 * log(p))
328  goto l1;
329 
330  ch = pow((p * xx * exp(g + xx * aa)), 1 / xx);
331  if (ch - e < 0)
332  return ch;
333  goto l4;
334 l1:
335  if (v > .32)
336  goto l3;
337  ch = 0.4; a = log(1 - p);
338 l2:
339  q = ch; p1 = 1 + ch * (4.67 + ch); p2 = ch * (6.73 + ch * (6.66 + ch));
340  t = -0.5 + (4.67 + 2 * ch) / p1 - (6.73 + ch * (13.32 + 3 * ch)) / p2;
341  ch -= (1 - exp(a + g + .5 * ch + c * aa) * p2 / p1) / t;
342  if (fabs(q / ch - 1) - .01 <= 0)
343  goto l4;
344  else
345  goto l2;
346 
347 l3:
348  x = qNorm (p);
349  p1 = 0.222222 / v; ch = v * pow((x * sqrt(p1) + 1 - p1), 3.0);
350  if (ch > 2.2 * v + 6)
351  ch = -2 * (log(1 - p) - c * log(.5 * ch) + g);
352 l4:
353  q = ch; p1 = .5 * ch;
354  if ((t = incompleteGamma (p1, xx, g)) < 0)
355  {
356  std::cerr << "err IncompleteGamma" << std::endl;
357  return -1;
358  }
359  p2 = p - t;
360  t = p2 * exp(xx * aa + g + p1 - c * log(ch));
361  b = t / ch; a = 0.5 * t - b * c;
362 
363  s1 = (210 + a * (140 + a * (105 + a * (84 + a * (70 + 60 * a))))) / 420;
364  s2 = (420 + a * (735 + a * (966 + a * (1141 + 1278 * a)))) / 2520;
365  s3 = (210 + a * (462 + a * (707 + 932 * a))) / 2520;
366  s4 = (252 + a * (672 + 1182 * a) + c * (294 + a * (889 + 1740 * a))) / 5040;
367  s5 = (84 + 264 * a + c * (175 + 606 * a)) / 2520;
368  s6 = (120 + c * (346 + 127 * c)) / 5040;
369  ch += t * (1 + 0.5 * t * s1 - b * c * (s1 - b * (s2 - b * (s3 - b * (s4 - b * (s5 - b * s6))))));
370  if (fabs(q / ch - 1) > e)
371  goto l4;
372 
373  return ch;
374 }
375 
376 
377 double RandomTools::pNorm(double x, double mu, double sigma)
378 {
379  return RandomTools::pNorm((x - mu) / sigma);
380 }
381 
382 
383 double RandomTools::pNorm(double x)
384 {
385  const static double a[5] = {
386  2.2352520354606839287,
387  161.02823106855587881,
388  1067.6894854603709582,
389  18154.981253343561249,
390  0.065682337918207449113
391  };
392  const static double b[4] = {
393  47.20258190468824187,
394  976.09855173777669322,
395  10260.932208618978205,
396  45507.789335026729956
397  };
398  const static double c[9] = {
399  0.39894151208813466764,
400  8.8831497943883759412,
401  93.506656132177855979,
402  597.27027639480026226,
403  2494.5375852903726711,
404  6848.1904505362823326,
405  11602.651437647350124,
406  9842.7148383839780218,
407  1.0765576773720192317e-8
408  };
409  const static double d[8] = {
410  22.266688044328115691,
411  235.38790178262499861,
412  1519.377599407554805,
413  6485.558298266760755,
414  18615.571640885098091,
415  34900.952721145977266,
416  38912.003286093271411,
417  19685.429676859990727
418  };
419  const static double p[6] = {
420  0.21589853405795699,
421  0.1274011611602473639,
422  0.022235277870649807,
423  0.001421619193227893466,
424  2.9112874951168792e-5,
425  0.02307344176494017303
426  };
427  const static double q[5] = {
428  1.28426009614491121,
429  0.468238212480865118,
430  0.0659881378689285515,
431  0.00378239633202758244,
432  7.29751555083966205e-5
433  };
434 
435  double xden, xnum, temp, del, eps, xsq, y, cum;
436  int i;
437 
438  eps = 1e-20;
439 
440  y = fabs(x);
441  if (y <= 0.67448975) /* qnorm(3/4) = .6744.... -- earlier had 0.66291 */
442  {
443  if (y > eps)
444  {
445  xsq = x * x;
446  xnum = a[4] * xsq;
447  xden = xsq;
448  for (i = 0; i < 3; ++i)
449  {
450  xnum = (xnum + a[i]) * xsq;
451  xden = (xden + b[i]) * xsq;
452  }
453  }
454  else
455  xnum = xden = 0.0;
456 
457  temp = x * (xnum + a[3]) / (xden + b[3]);
458  cum = 0.5 + temp;
459  }
460  else if (y <= sqrt(32))
461  {
462  /* Evaluate pnorm for 0.674.. = qnorm(3/4) < |x| <= sqrt(32) ~= 5.657 */
463 
464  xnum = c[8] * y;
465  xden = y;
466  for (i = 0; i < 7; ++i)
467  {
468  xnum = (xnum + c[i]) * y;
469  xden = (xden + d[i]) * y;
470  }
471  temp = (xnum + c[7]) / (xden + d[7]);
472 
473  xsq = trunc(y * 16) / 16;
474  del = (y - xsq) * (y + xsq);
475  cum = exp(-xsq * xsq * 0.5) * exp(-del * 0.5) * temp;
476 
477  if (x > 0.)
478  cum = 1 - cum;
479  }
480  else if (-37.5193 < x && x < 8.2924)
481  {
482  xsq = 1.0 / (x * x);
483  xnum = p[5] * xsq;
484  xden = xsq;
485  for (i = 0; i < 4; ++i)
486  {
487  xnum = (xnum + p[i]) * xsq;
488  xden = (xden + q[i]) * xsq;
489  }
490  temp = xsq * (xnum + p[4]) / (xden + q[4]);
491  temp = (1 / sqrt(2 * M_PI) - temp) / y;
492 
493  xsq = trunc(x * 16) / 16;
494  del = (x - xsq) * (x + xsq);
495 
496  cum = exp(-xsq * xsq * 0.5) * exp(-del * 0.5) * temp;
497 
498  if (x > 0.)
499  cum = 1. - cum;
500  }
501  else /* no log_p , large x such that probs are 0 or 1 */
502  {
503  if (x > 0)
504  cum = 1.;
505  else
506  cum = 0.;
507  }
508 
509  return cum;
510 }
511 
512 double RandomTools::lnBeta(double alpha, double beta)
513 {
514  return lnGamma(alpha) + lnGamma(beta) - lnGamma(alpha + beta);
515 }
516 
517 double RandomTools::randBeta(double alpha, double beta, const RandomFactory& generator)
518 {
519  return RandomTools::qBeta(generator.drawNumber(), alpha, beta);
520 }
521 
522 
523 double RandomTools::qBeta(double prob, double alpha, double beta)
524 {
525  double lower = NumConstants::VERY_TINY();
526  double upper = 1 - NumConstants::VERY_TINY();
527  double const1 = 2.30753;
528  double const2 = 0.27061;
529  double const3 = 0.99229;
530  double const4 = 0.04481;
531 
532 
533  int swap_tail, i_pb, i_inn;
534  double a, adj, logbeta, g, h, pp, prev, qq, r, s, t, tx, w, y, yprev;
535  double acu;
536  volatile double xinbta;
537 
538  if (alpha <= 0. || beta < 0.)
539  throw ("RandomTools::qBeta wih non positive parameters");
540 
541  if (prob < 0. || prob > 1.)
542  throw ("RandomTools::qBeta wih bad probability");
543 
544  /* initialize */
545  logbeta = lnBeta(alpha, beta);
546 
547  /* change tail if necessary; afterwards 0 < a <= 1/2 */
548  if (prob <= 0.5)
549  {
550  a = prob; pp = alpha; qq = beta; swap_tail = 0;
551  }
552  else /* change tail, swap alpha <-> beta :*/
553  {
554  a = 1 - prob;
555  pp = beta; qq = alpha; swap_tail = 1;
556  }
557 
558  /* calculate the initial approximation */
559 
560  /* y := {fast approximation of} qnorm(1 - a) :*/
561  r = sqrt(-2 * log(a));
562  y = r - (const1 + const2 * r) / (1. + (const3 + const4 * r) * r);
563  if (pp > 1 && qq > 1)
564  {
565  r = (y * y - 3.) / 6.;
566  s = 1. / (pp + pp - 1.);
567  t = 1. / (qq + qq - 1.);
568  h = 2. / (s + t);
569  w = y * sqrt(h + r) / h - (t - s) * (r + 5. / 6. - 2. / (3. * h));
570  xinbta = pp / (pp + qq * exp(w + w));
571  }
572  else
573  {
574  r = qq + qq;
575  t = 1. / (9. * qq);
576  t = r * pow(1. - t + y * sqrt(t), 3.0);
577  if (t <= 0.)
578  xinbta = 1. - exp((log1p(-a) + log(qq) + logbeta) / qq);
579  else
580  {
581  t = (4. * pp + r - 2.) / t;
582  if (t <= 1.)
583  xinbta = exp((log(a * pp) + logbeta) / pp);
584  else
585  xinbta = 1. - 2. / (t + 1.);
586  }
587  }
588 
589  /* solve for x by a modified newton-raphson method, */
590  /* using the function pbeta_raw */
591 
592  r = 1 - pp;
593  t = 1 - qq;
594  yprev = 0.;
595  adj = 1;
596  /* Sometimes the approximation is negative! */
597  if (xinbta < lower)
598  xinbta = 0.5;
599  else if (xinbta > upper)
600  xinbta = 0.5;
601 
602  /* Desired accuracy should depend on (a,p)
603  * This is from Remark .. on AS 109, adapted.
604  * However, it's not clear if this is "optimal" for IEEE double prec.
605 
606  * acu = fmax2(lower, pow(10., -25. - 5./(pp * pp) - 1./(a * a)));
607 
608  * NEW: 'acu' accuracy NOT for squared adjustment, but simple;
609  * ---- i.e., "new acu" = sqrt(old acu)
610 
611  */
612  double po = pow(10., -13 - 2.5 / (pp * pp) - 0.5 / (a * a));
613  acu = (lower > po) ? lower : po;
614 
615  tx = prev = 0.; /* keep -Wall happy */
616 
617  for (i_pb = 0; i_pb < 1000; i_pb++)
618  {
619  y = incompleteBeta(xinbta, pp, qq);
620 // #ifdef IEEE_754
621 // if(!R_FINITE(y))
622 // #else
623 // if (errno)
624 // #endif
625 // ML_ERR_return_NAN;
626 
627  y = (y - a) *
628  exp(logbeta + r * log(xinbta) + t * log1p(-xinbta));
629  if (y * yprev <= 0.)
630  prev = (fabs(adj) > lower) ? fabs(adj) : lower;
631  g = 1;
632  for (i_inn = 0; i_inn < 1000; i_inn++)
633  {
634  adj = g * y;
635  if (fabs(adj) < prev)
636  {
637  tx = xinbta - adj; /* trial new x */
638  if (tx >= 0. && tx <= 1)
639  {
640  if ((prev <= acu) || (fabs(y) <= acu))
641  return swap_tail ? 1 - xinbta : xinbta;
642  if (tx != 0. && tx != 1)
643  break;
644  }
645  }
646  g /= 3;
647  }
648  if (fabs(tx - xinbta) < 1e-15 * xinbta)
649  return swap_tail ? 1 - xinbta : xinbta;
650 
651  xinbta = tx;
652  yprev = y;
653  }
654  // throw Exception("Bad precision in RandomTools::qBeta");
655 
656  return swap_tail ? 1 - xinbta : xinbta;
657 }
658 
659 double RandomTools::incompleteBeta(double x, double alpha, double beta)
660 {
661  double t;
662  double xc;
663  double w;
664  double y;
665  int flag;
666  double big;
667  double biginv;
668  double maxgam;
669  double minlog;
670  double maxlog;
671 
672  big = 4.503599627370496e15;
673  biginv = 2.22044604925031308085e-16;
674  maxgam = 171.624376956302725;
675  minlog = log(NumConstants::VERY_TINY());
676  maxlog = log(NumConstants::VERY_BIG());
677 
678  if ((alpha <= 0) || (beta <= 0))
679  throw Exception("RandomTools::incompleteBeta not valid with non-positive parameters");
680 
681  if ((x < 0) || (x > 1))
682  throw Exception("RandomTools::incompleteBeta out of bounds limit");
683 
684  if (x == 0)
685  return 0;
686 
687  if (x == 1)
688  return 1;
689 
690  flag = 0;
691  if ((beta * x <= 1.0) && (x <= 0.95))
692  {
693  return incompletebetaps(alpha, beta, x, maxgam);
694  }
695  w = 1.0 - x;
696 
697  if (x > alpha / (alpha + beta))
698  {
699  flag = 1;
700  t = alpha;
701  alpha = beta;
702  beta = t;
703  xc = x;
704  x = w;
705  }
706  else
707  {
708  xc = w;
709  }
710  if (flag == 1 && (beta * x <= 1.0) && (x <= 0.95) )
711  {
712  t = incompletebetaps(alpha, beta, x, maxgam);
713  if (t <= NumConstants::VERY_TINY())
714  return 1.0 - NumConstants::VERY_TINY();
715  else
716  return 1.0 - t;
717  }
718 
719  y = x * (alpha + beta - 2.0) - (alpha - 1.0);
720  if (y < 0.0)
721  {
722  w = incompletebetafe(alpha, beta, x, big, biginv);
723  }
724  else
725  {
726  w = incompletebetafe2(alpha, beta, x, big, biginv) / xc;
727  }
728  y = alpha * log(x);
729  t = beta * log(xc);
730  if ( (alpha + beta < maxgam) && (fabs(y) < maxlog) && (fabs(t) < maxlog) )
731  {
732  t = pow(xc, beta);
733  t = t * pow(x, alpha);
734  t = t / alpha;
735  t = t * w;
736  t = t * exp(lnGamma(alpha + beta) - (lnGamma(alpha) + lnGamma(beta)));
737  if (flag == 1)
738  {
739  if (t < NumConstants::VERY_TINY())
740  return 1.0 - NumConstants::VERY_TINY();
741  else
742  return 1.0 - t;
743  }
744  else
745  return t;
746  }
747  y = y + t + lnGamma(alpha + beta) - lnGamma(alpha) - lnGamma(beta);
748  y = y + log(w / alpha);
749  if (y < minlog)
750  {
751  t = 0.0;
752  }
753  else
754  {
755  t = exp(y);
756  }
757  if (flag == 1)
758  {
759  if (t < NumConstants::VERY_TINY())
760  t = 1.0 - NumConstants::VERY_TINY();
761  else
762  t = 1.0 - t;
763  }
764  return t;
765 }
766 
767 
768 /**********************************************/
769 
771  double b,
772  double x,
773  double big,
774  double biginv)
775 {
776  double result;
777  double xk;
778  double pk;
779  double pkm1;
780  double pkm2;
781  double qk;
782  double qkm1;
783  double qkm2;
784  double k1;
785  double k2;
786  double k3;
787  double k4;
788  double k5;
789  double k6;
790  double k7;
791  double k8;
792  double r;
793  double t;
794  double ans;
795  double thresh;
796  int n;
797 
798  k1 = a;
799  k2 = a + b;
800  k3 = a;
801  k4 = a + 1.0;
802  k5 = 1.0;
803  k6 = b - 1.0;
804  k7 = k4;
805  k8 = a + 2.0;
806  pkm2 = 0.0;
807  qkm2 = 1.0;
808  pkm1 = 1.0;
809  qkm1 = 1.0;
810  ans = 1.0;
811  r = 1.0;
812  n = 0;
813  thresh = 3.0 * NumConstants::VERY_TINY();
814  do
815  {
816  xk = -x * k1 * k2 / (k3 * k4);
817  pk = pkm1 + pkm2 * xk;
818  qk = qkm1 + qkm2 * xk;
819  pkm2 = pkm1;
820  pkm1 = pk;
821  qkm2 = qkm1;
822  qkm1 = qk;
823  xk = x * k5 * k6 / (k7 * k8);
824  pk = pkm1 + pkm2 * xk;
825  qk = qkm1 + qkm2 * xk;
826  pkm2 = pkm1;
827  pkm1 = pk;
828  qkm2 = qkm1;
829  qkm1 = qk;
830  if (qk != 0)
831  {
832  r = pk / qk;
833  }
834  if (r != 0)
835  {
836  t = fabs((ans - r) / r);
837  ans = r;
838  }
839  else
840  {
841  t = 1.0;
842  }
843  if (t < thresh)
844  {
845  break;
846  }
847  k1 = k1 + 1.0;
848  k2 = k2 + 1.0;
849  k3 = k3 + 2.0;
850  k4 = k4 + 2.0;
851  k5 = k5 + 1.0;
852  k6 = k6 - 1.0;
853  k7 = k7 + 2.0;
854  k8 = k8 + 2.0;
855  if (fabs(qk) + fabs(pk) > big)
856  {
857  pkm2 = pkm2 * biginv;
858  pkm1 = pkm1 * biginv;
859  qkm2 = qkm2 * biginv;
860  qkm1 = qkm1 * biginv;
861  }
862  if ((fabs(qk) < biginv) || (fabs(pk) < biginv))
863  {
864  pkm2 = pkm2 * big;
865  pkm1 = pkm1 * big;
866  qkm2 = qkm2 * big;
867  qkm1 = qkm1 * big;
868  }
869  n = n + 1;
870  }
871  while (n != 300);
872  result = ans;
873  return result;
874 }
875 
876 
877 /*************************************************************************
878  Continued fraction expansion #2
879  for incomplete beta integral
880 
881  Cephes Math Library, Release 2.8: June, 2000
882  Copyright 1984, 1995, 2000 by Stephen L. Moshier
883 *************************************************************************/
885  double b,
886  double x,
887  double big,
888  double biginv)
889 {
890  double result;
891  double xk;
892  double pk;
893  double pkm1;
894  double pkm2;
895  double qk;
896  double qkm1;
897  double qkm2;
898  double k1;
899  double k2;
900  double k3;
901  double k4;
902  double k5;
903  double k6;
904  double k7;
905  double k8;
906  double r;
907  double t;
908  double ans;
909  double z;
910  double thresh;
911  int n;
912 
913  k1 = a;
914  k2 = b - 1.0;
915  k3 = a;
916  k4 = a + 1.0;
917  k5 = 1.0;
918  k6 = a + b;
919  k7 = a + 1.0;
920  k8 = a + 2.0;
921  pkm2 = 0.0;
922  qkm2 = 1.0;
923  pkm1 = 1.0;
924  qkm1 = 1.0;
925  z = x / (1.0 - x);
926  ans = 1.0;
927  r = 1.0;
928  n = 0;
929  thresh = 3.0 * NumConstants::VERY_TINY();
930  do
931  {
932  xk = -z * k1 * k2 / (k3 * k4);
933  pk = pkm1 + pkm2 * xk;
934  qk = qkm1 + qkm2 * xk;
935  pkm2 = pkm1;
936  pkm1 = pk;
937  qkm2 = qkm1;
938  qkm1 = qk;
939  xk = z * k5 * k6 / (k7 * k8);
940  pk = pkm1 + pkm2 * xk;
941  qk = qkm1 + qkm2 * xk;
942  pkm2 = pkm1;
943  pkm1 = pk;
944  qkm2 = qkm1;
945  qkm1 = qk;
946  if (qk != 0)
947  {
948  r = pk / qk;
949  }
950  if (r != 0)
951  {
952  t = fabs((ans - r) / r);
953  ans = r;
954  }
955  else
956  {
957  t = 1.0;
958  }
959  if (t < thresh)
960  {
961  break;
962  }
963  k1 = k1 + 1.0;
964  k2 = k2 - 1.0;
965  k3 = k3 + 2.0;
966  k4 = k4 + 2.0;
967  k5 = k5 + 1.0;
968  k6 = k6 + 1.0;
969  k7 = k7 + 2.0;
970  k8 = k8 + 2.0;
971  if (fabs(qk) + fabs(pk) > big)
972  {
973  pkm2 = pkm2 * biginv;
974  pkm1 = pkm1 * biginv;
975  qkm2 = qkm2 * biginv;
976  qkm1 = qkm1 * biginv;
977  }
978  if ((fabs(qk) < biginv) || (fabs(pk) < biginv))
979  {
980  pkm2 = pkm2 * big;
981  pkm1 = pkm1 * big;
982  qkm2 = qkm2 * big;
983  qkm1 = qkm1 * big;
984  }
985  n = n + 1;
986  }
987  while (n != 300);
988  result = ans;
989  return result;
990 }
991 
992 
993 /*************************************************************************
994  Power series for incomplete beta integral.
995  Use when b*x is small and x not too close to 1.
996 
997  Cephes Math Library, Release 2.8: June, 2000
998  Copyright 1984, 1995, 2000 by Stephen L. Moshier
999 *************************************************************************/
1000 double RandomTools::incompletebetaps(double a, double b, double x, double maxgam)
1001 {
1002  double result;
1003  double s;
1004  double t;
1005  double u;
1006  double v;
1007  double n;
1008  double t1;
1009  double z;
1010  double ai;
1011 
1012  ai = 1.0 / a;
1013  u = (1.0 - b) * x;
1014  v = u / (a + 1.0);
1015  t1 = v;
1016  t = u;
1017  n = 2.0;
1018  s = 0.0;
1019  z = NumConstants::VERY_TINY() * ai;
1020  while (fabs(v) > z)
1021  {
1022  u = (n - b) * x / n;
1023  t = t * u;
1024  v = t / (a + n);
1025  s = s + v;
1026  n = n + 1.0;
1027  }
1028  s = s + t1;
1029  s = s + ai;
1030  u = a * log(x);
1031  if ((a + b < maxgam) && (fabs(u) < log(NumConstants::VERY_BIG())))
1032  {
1033  t = exp(lnGamma(a + b) - (lnGamma(a) + lnGamma(b)));
1034  s = s * t * pow(x, a);
1035  }
1036  else
1037  {
1038  t = lnGamma(a + b) - lnGamma(a) - lnGamma(b) + u + log(s);
1039  if (t < log(NumConstants::VERY_TINY()))
1040  {
1041  s = 0.0;
1042  }
1043  else
1044  {
1045  s = exp(t);
1046  }
1047  }
1048  result = s;
1049  return result;
1050 }
1051 
1052 /**************************************************************************/
1053 
static double pNorm(double z)
Normal cumulative function.
static RandomFactory * DEFAULT_GENERATOR
Definition: RandomTools.h:95
This class allows to perform a correspondence analysis.
static double incompletebetafe2(double a, double b, double x, double big, double biginv)
static T sum(const std::vector< T > &v1)
Definition: VectorTools.h:614
STL namespace.
static bool flipCoin(const RandomFactory &generator= *DEFAULT_GENERATOR)
Get a boolean random value.
Definition: RandomTools.cpp:70
static double randGamma(double dblAlpha, const RandomFactory &generator= *DEFAULT_GENERATOR)
Definition: RandomTools.cpp:80
static double DblGammaGreaterThanOne(double dblAlpha, const RandomFactory &generator)
static double VERY_TINY()
Definition: NumConstants.h:82
This is the interface for the Random Number Generators.
Definition: RandomFactory.h:52
static double qBeta(double prob, double alpha, double beta)
The Beta quantile function.
static double randGaussian(double mean, double variance, const RandomFactory &generator= *DEFAULT_GENERATOR)
Definition: RandomTools.cpp:75
static double incompleteGamma(double x, double alpha, double ln_gamma_alpha)
Returns the incomplete gamma ratio I(x,alpha).
static double qNorm(double prob)
Normal quantile function.
static double lnGamma(double alpha)
Computes given .
virtual double drawNumber() const =0
Return a random number.
static double VERY_BIG()
Definition: NumConstants.h:83
static void setSeed(long seed)
Set the default generator seed.
Definition: RandomTools.cpp:55
static double incompletebetafe(double a, double b, double x, double big, double biginv)
functions for the computation of incompleteBeta
static double DblGammaLessThanOne(double dblAlpha, const RandomFactory &generator)
Exception base class.
Definition: Exceptions.h:57
static double incompletebetaps(double a, double b, double x, double maxgam)
static double randBeta(double alpha, double beta, const RandomFactory &generator= *DEFAULT_GENERATOR)
static double giveRandomNumberBetweenZeroAndEntry(double entry, const RandomFactory &generator= *DEFAULT_GENERATOR)
Get a double random value (between 0 and specified range).
Definition: RandomTools.cpp:62
static std::vector< size_t > randMultinomial(size_t n, const std::vector< double > &probs)
Get a random state from a set of probabilities/scores.
static double qChisq(double prob, double v)
quantile function.
static double randExponential(double mean, const RandomFactory &generator= *DEFAULT_GENERATOR)
Definition: RandomTools.cpp:96
static double incompleteBeta(double x, double alpha, double beta)
Returns the regularized incomplete beta function .
A uniform random number generator.
Definition: Uniform01K.h:59
static double lnBeta(double alpha, double beta)
Computes given and .