1 module rmathd.beta; 2 3 public import rmathd.common; 4 public import rmathd.toms708; 5 6 /* 7 ** dmd beta.d common.d && ./beta 8 */ 9 10 T lbeta(T: double)(T a, T b) 11 { 12 T corr, p, q; 13 14 if(isNaN(a) || isNaN(b)) 15 return a + b; 16 17 p = q = a; 18 if(b < p) p = b;/* := min(a,b) */ 19 if(b > q) q = b;/* := max(a,b) */ 20 21 /* both arguments must be >= 0 */ 22 if (p < 0) 23 return T.nan; 24 else if (p == 0) { 25 return T.infinity; 26 } 27 else if (!isFinite(q)) { /* q == +Inf */ 28 return -T.infinity; 29 } 30 31 if (p >= 10) { 32 /* p and q are big. */ 33 corr = lgammacor!T(p) + lgammacor!T(q) - lgammacor!T(p + q); 34 return log(q) * -0.5 + M_LN_SQRT_2PI + corr + (p - 0.5) * log(p / (p + q)) + q * log1p(-p / (p + q)); 35 } else if (q >= 10) { 36 /* p is small, but q is big. */ 37 corr = lgammacor!T(q) - lgammacor!T(p + q); 38 return lgammafn!T(p) + corr + p - p * log(p + q) 39 + (q - 0.5) * log1p(-p / (p + q)); 40 } 41 else { 42 /* p and q are small: p <= q < 10. */ 43 /* R change for very small args */ 44 if (p < 1e-306) 45 return lgamma!T(p) + (lgamma!T(q) - lgamma!T(p + q)); 46 else return log(gammafn!T(p)*(gammafn!T(q)/gammafn!T(p + q))); 47 } 48 } 49 50 51 T beta(T: double)(T a, T b) 52 { 53 //#ifdef NOMORE_FOR_THREADS 54 static T xmin, xmax = 0;/*-> typically = 171.61447887 for IEEE */ 55 static T lnsml = 0;/*-> typically = -708.3964185 */ 56 57 if (xmax == 0) { 58 gammalims!T(&xmin, &xmax); 59 lnsml = log(d1mach!T(1)); 60 } 61 //#else 62 ///* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 : 63 // * xmin, xmax : see ./gammalims.c 64 // * lnsml = log(DBL_MIN) = log(2 ^ -1022) = -1022 * log(2) 65 //*/ 66 //# define xmin -170.5674972726612 67 //# define xmax 171.61447887182298 68 //# define lnsml -708.39641853226412 69 //#endif 70 71 /* NaNs propagated correctly */ 72 if(isNaN(a) || isNaN(b)) 73 return a + b; 74 75 if (a < 0 || b < 0) 76 return T.nan; 77 else if (a == 0 || b == 0) 78 return T.infinity; 79 else if (!isFinite(a) || !isFinite(b)) 80 return 0; 81 82 if (a + b < xmax) {/* ~= 171.61 for IEEE */ 83 // return gammafn(a) * gammafn(b) / gammafn(a+b); 84 /* All the terms are positive, and all can be large for large 85 or small arguments. They are never much less than one. 86 gammafn(x) can still overflow for x ~ 1e-308, 87 but the result would too. 88 */ 89 return (1/gammafn!T(a + b)) * gammafn!T(a) * gammafn!T(b); 90 } else { 91 T val = lbeta!T(a, b); 92 // underflow to 0 is not harmful per se; exp(-999) also gives no warning 93 if (val < lnsml) { 94 /* a and/or b so big that beta underflows */ 95 //ML_ERROR(ME_UNDERFLOW, "beta"); 96 /* return ML_UNDERFLOW; pointless giving incorrect value */ 97 } 98 return exp(val); 99 } 100 } 101 102 103 T dbeta(T: double)(T x, T a, T b, int give_log) 104 { 105 mixin R_D__0!give_log; 106 /* NaNs propagated correctly */ 107 if (isNaN(x) || isNaN(a) || isNaN(b)) 108 return x + a + b; 109 110 if (a < 0 || b < 0) 111 return T.nan; 112 if (x < 0 || x > 1) 113 return(R_D__0); 114 115 // limit cases for (a,b), leading to point masses 116 if(a == 0 || b == 0 || !isFinite(a) || !isFinite(b)) { 117 if(a == 0 && b == 0) { // point mass 1/2 at each of {0,1} : 118 if (x == 0 || x == 1) 119 return T.infinity; 120 else 121 return R_D__0; 122 } 123 if (a == 0 || a/b == 0) { // point mass 1 at 0 124 if (x == 0) return T.infinity; else return R_D__0; 125 } 126 if (b == 0 || b/a == 0) { // point mass 1 at 1 127 if (x == 1) return T.infinity; else return R_D__0; 128 } 129 // else, remaining case: a = b = Inf : point mass 1 at 1/2 130 if (x == 0.5) return T.infinity; else return R_D__0; 131 } 132 133 if (x == 0) { 134 if(a > 1) 135 return R_D__0; 136 if(a < 1) 137 return T.infinity; 138 /* a == 1 : */ return R_D_val!T(b, give_log); 139 } 140 if (x == 1) { 141 if(b > 1) 142 return R_D__0; 143 if(b < 1) 144 return(T.infinity); 145 /* b == 1 : */ return R_D_val!T(a, give_log); 146 } 147 148 T lval; 149 if (a <= 2 || b <= 2) 150 lval = (a - 1)*log(x) + (b - 1)*log1p(-x) - lbeta!T(a, b); 151 else 152 lval = log(a + b - 1) + dbinom_raw!T(a - 1, a + b - 2, x, 1 - x, 1); 153 154 return R_D_exp!T(lval, give_log); 155 } 156 157 158 T pbeta_raw(T)(T x, T a, T b, int lower_tail, int log_p) 159 { 160 // treat limit cases correctly here: 161 if(a == 0 || b == 0 || !isFinite(a) || !isFinite(b)) { 162 // NB: 0 < x < 1 : 163 if(a == 0 && b == 0) // point mass 1/2 at each of {0,1} : 164 return (log_p ? -M_LN2 : 0.5); 165 if (a == 0 || a/b == 0) // point mass 1 at 0 ==> P(X <= x) = 1, all x > 0 166 return R_DT_1!T(lower_tail, log_p); 167 if (b == 0 || b/a == 0) // point mass 1 at 1 ==> P(X <= x) = 0, all x < 1 168 return R_DT_0!T(lower_tail, log_p); 169 // else, remaining case: a = b = Inf : point mass 1 at 1/2 170 if (x < 0.5) 171 return R_DT_0!T(lower_tail, log_p); 172 else 173 return R_DT_1!T(lower_tail, log_p); 174 } 175 // Now: 0 < a < Inf; 0 < b < Inf 176 177 T x1 = 0.5 - x + 0.5, w, wc; 178 int ierr; 179 //==== 180 bratio!T(a, b, x, x1, &w, &wc, &ierr, log_p); /* -> ./toms708.c */ 181 //==== 182 // ierr in {10,14} <==> bgrat() error code ierr-10 in 1:4; for 1 and 4, warned *there* 183 //if(ierr && ierr != 11 && ierr != 14) 184 // MATHLIB_WARNING4(_("pbeta_raw(%g, a=%g, b=%g, ..) -> bratio() gave error code %d"), x, a,b, ierr); 185 return lower_tail ? w : wc; 186 } /* pbeta_raw() */ 187 188 T pbeta(T: double)(T x, T a, T b, int lower_tail, int log_p) 189 { 190 if (isNaN(x) || isNaN(a) || isNaN(b)) 191 return x + a + b; 192 193 if (a < 0 || b < 0) 194 return T.nan; 195 // allowing a==0 and b==0 <==> treat as one- or two-point mass 196 197 if (x <= 0) 198 return R_DT_0!T(lower_tail, log_p); 199 if (x >= 1) 200 return R_DT_1!T(lower_tail, log_p); 201 202 return pbeta_raw!T(x, a, b, lower_tail, log_p); 203 } 204 205 enum USE_LOG_X_CUTOFF = -5.; 206 enum n_NEWTON_FREE = 4; 207 enum MLOGICAL_NA = -1; 208 209 static const double DBL_very_MIN = DBL_MIN / 4., 210 DBL_log_v_MIN = M_LN2*(DBL_MIN_EXP - 2), DBL_1__eps = 0x1.fffffffffffffp-1; 211 212 enum fpu = 3e-308; 213 enum acu_min = 1e-300; 214 enum p_lo = fpu; 215 enum p_hi = 1-2.22e-16; 216 217 enum const1 = 2.30753; 218 enum const2 = 0.27061; 219 enum const3 = 0.99229; 220 enum const4 = 0.04481; 221 222 immutable(string) return_q_0(){ 223 return `if(give_log_q){ 224 qb[0] = T.infinity; qb[1] = 0; 225 } else { 226 qb[0] = 0; qb[1] = 1; 227 } 228 return;`; 229 } 230 231 immutable(string) return_q_1(){ 232 return `if(give_log_q){ 233 qb[0] = 0; qb[1] = -T.infinity; 234 } else { 235 qb[0] = 1; qb[1] = 0; 236 } 237 return;`; 238 } 239 240 immutable(string) return_q_half(){ 241 return `if(give_log_q) 242 qb[0] = qb[1] = -M_LN2; 243 else 244 qb[0] = qb[1] = 0.5; 245 return;`; 246 } 247 248 void qbeta_raw(T)(T alpha, T p, T q, int lower_tail, int log_p, 249 int swap_01, // {TRUE, NA, FALSE}: if NA, algorithm decides swap_tail 250 T log_q_cut, /* if == Inf: return log(qbeta(..)); 251 otherwise, if finite: the bound for 252 switching to log(x)-scale; see use_log_x */ 253 int n_N, // number of "unconstrained" Newton steps before switching to constrained 254 T *qb) // = qb[0:1] = { qbeta(), 1 - qbeta() } 255 { 256 //Rboolean 257 int swap_choose = (swap_01 == MLOGICAL_NA), 258 swap_tail, log_, give_log_q = (log_q_cut == T.infinity), 259 use_log_x = give_log_q, // or u < log_q_cut below 260 warned = 0, add_N_step = 1; 261 int i_pb, i_inn, bad_init, bad_u; 262 T adj = 1.; 263 T a, la, logbeta, g, h, pp, p_, qq, r, s, t, w, y = -1., u_n; 264 T wprev, prev; 265 /* volatile */ T u, xinbta; 266 267 // Assuming p >= 0, q >= 0 here ... 268 269 // Deal with boundary cases here: 270 if(alpha == R_DT_0!T(lower_tail, log_p)){ 271 //#define return_q_0 \ 272 // if(give_log_q) { qb[0] = ML_NEGINF; qb[1] = 0; } \ 273 // else { qb[0] = 0; qb[1] = 1; } \ 274 // return 275 mixin (return_q_0()); 276 } 277 if(alpha == R_DT_1!T(lower_tail, log_p)){ 278 //#define return_q_1 \ 279 // if(give_log_q) { qb[0] = 0; qb[1] = ML_NEGINF; } \ 280 // else { qb[0] = 1; qb[1] = 0; } \ 281 // return 282 mixin (return_q_1()); 283 } 284 285 // check alpha {*before* transformation which may all accuracy}: 286 if((log_p && alpha > 0) || (!log_p && (alpha < 0 || alpha > 1))) { // alpha is outside 287 //R_ifDEBUG_printf("qbeta(alpha=%g, %g, %g, .., log_p=%d): %s%s\n", 288 // alpha, p,q, log_p, "alpha not in ", log_p ? "[-Inf, 0]" : "[0,1]"); 289 //ML_ERROR(ME_DOMAIN, ""); 290 qb[0] = qb[1] = T.nan; return; 291 } 292 293 // p==0, q==0, p = Inf, q = Inf <==> treat as one- or two-point mass 294 if(p == 0 || q == 0 || !isFinite(p) || !isFinite(q)) { 295 // We know 0 < T(alpha) < 1 : pbeta() is constant and trivial in {0, 1/2, 1} 296 //R_ifDEBUG_printf( 297 // "qbeta(%g, %g, %g, lower_t=%d, log_p=%d): (p,q)-boundary: trivial\n", alpha, p,q, lower_tail, log_p); 298 if(p == 0 && q == 0) { // point mass 1/2 at each of {0,1} : 299 if(alpha < R_D_half(log_p)){ 300 return_q_0; 301 } 302 if(alpha > R_D_half(log_p)){ 303 return_q_1; 304 } 305 // else: alpha == "1/2" 306 //#define return_q_half \ 307 // if(give_log_q) qb[0] = qb[1] = -M_LN2; \ 308 // else qb[0] = qb[1] = 0.5; \ 309 // return 310 311 mixin (return_q_half()); 312 } else if (p == 0 || p/q == 0) { // point mass 1 at 0 - "flipped around" 313 return_q_0; 314 } else if (q == 0 || q/p == 0) { // point mass 1 at 0 - "flipped around" 315 return_q_1; 316 } 317 // else: p = q = Inf : point mass 1 at 1/2 318 mixin (return_q_half()); 319 } 320 321 mixin R_DT_qIv!(alpha); 322 mixin R_DT_CIv!(alpha); 323 /* initialize */ 324 p_ = R_DT_qIv;/* lower_tail prob (in any case) */ 325 // Conceptually, 0 < p_ < 1 (but can be 0 or 1 because of cancellation!) 326 logbeta = lbeta!T(p, q); 327 328 swap_tail = (swap_choose) ? (p_ > 0.5) : swap_01; 329 // change tail; default (swap_01 = NA): afterwards 0 < a <= 1/2 330 if(swap_tail) { /* change tail, swap p <-> q :*/ 331 a = R_DT_CIv; // = 1 - p_ < 1/2 332 /* la := log(a), but without numerical cancellation: */ 333 la = R_DT_Clog!T(alpha, lower_tail, log_p); 334 pp = q; qq = p; 335 } 336 else { 337 a = p_; 338 la = R_DT_log!T(alpha, lower_tail); 339 pp = p; qq = q; 340 } 341 342 /* calculate the initial approximation */ 343 344 /* Desired accuracy for Newton iterations (below) should depend on (a,p) 345 * This is from Remark .. on AS 109, adapted. 346 * However, it's not clear if this is "optimal" for IEEE double prec. 347 348 * acu = fmax2(acu_min, pow(10., -25. - 5./(pp * pp) - 1./(a * a))); 349 350 * NEW: 'acu' accuracy NOT for squared adjustment, but simple; 351 * ---- i.e., "new acu" = sqrt(old acu) 352 */ 353 T acu = fmax2(acu_min, pow(10., -13. - 2.5/(pp * pp) - 0.5/(a * a))); 354 // try to catch "extreme left tail" early 355 T tx, u0 = (la + log(pp) + logbeta) / pp; // = log(x_0) 356 static const T log_eps_c = M_LN2 * (1. - DBL_MANT_DIG);// = log(DBL_EPSILON) = -36.04.. 357 r = pp*(1. - qq)/(pp + 1.); 358 359 t = 0.2; 360 // FIXME: Factor 0.2 is a bit arbitrary; '1' is clearly much too much. 361 362 //R_ifDEBUG_printf( 363 //"qbeta(%g, %g, %g, lower_t=%d, log_p=%d):%s\n" 364 //" swap_tail=%d, la=%#8g, u0=%#8g (bnd: %g (%g)) ", 365 //alpha, p,q, lower_tail, log_p, 366 //(log_p && (p_ == 0. || p_ == 1.)) ? (p_==0.?" p_=0":" p_=1") : "", 367 //swap_tail, la, u0, 368 //(t*log_eps_c - log(fabs(pp*(1.-qq)*(2.-qq)/(2.*(pp+2.)))))/2., 369 // t*log_eps_c - log(fabs(r)) 370 //); 371 372 if(M_LN2 * DBL_MIN_EXP < u0 && // cannot allow exp(u0) = 0 ==> exp(u1) = exp(u0) = 0 373 u0 < -0.01 && // (must: u0 < 0, but too close to 0 <==> x = exp(u0) = 0.99..) 374 // qq <= 2 && // <--- "arbitrary" 375 // u0 < t*log_eps_c - log(fabs(r)) && 376 u0 < (t*log_eps_c - log(fabs(pp*(1. - qq)*(2. - qq)/(2.*(pp + 2.)))))/2.) 377 { 378 // TODO: maybe jump here from below, when initial u "fails" ? 379 // L_tail_u: 380 // MM's one-step correction (cheaper than 1 Newton!) 381 r = r*exp(u0);// = r*x0 382 if(r > -1.) { 383 u = u0 - log1p(r)/pp; 384 //R_ifDEBUG_printf("u1-u0=%9.3g --> choosing u = u1\n", u-u0); 385 } else { 386 u = u0; 387 //R_ifDEBUG_printf("cannot cheaply improve u0\n"); 388 } 389 tx = xinbta = exp(u); 390 use_log_x = 1; // or (u < log_q_cut) ?? 391 goto L_Newton; 392 } 393 394 // y := y_\alpha in AS 64 := Hastings(1955) approximation of qnorm(1 - a) : 395 r = sqrt(-2 * la); 396 y = r - (const1 + const2 * r) / (1. + (const3 + const4 * r) * r); 397 398 if (pp > 1 && qq > 1) { // use Carter(1947), see AS 109, remark '5.' 399 r = (y * y - 3.) / 6.; 400 s = 1. / (pp + pp - 1.); 401 t = 1. / (qq + qq - 1.); 402 h = 2. / (s + t); 403 w = y * sqrt(h + r) / h - (t - s) * (r + 5. / 6. - 2. / (3. * h)); 404 //R_ifDEBUG_printf("p,q > 1 => w=%g", w); 405 if(w > 300) { // exp(w+w) is huge or overflows 406 t = w+w + log(qq) - log(pp); // = argument of log1pexp(.) 407 u = // log(xinbta) = - log1p(qq/pp * exp(w+w)) = -log(1 + exp(t)) 408 (t <= 18) ? -log1p(exp(t)) : -t - exp(-t); 409 xinbta = exp(u); 410 } else { 411 xinbta = pp / (pp + qq * exp(w + w)); 412 u = // log(xinbta) 413 - log1p(qq/pp * exp(w + w)); 414 } 415 } else { // use the original AS 64 proposal, Scheffé-Tukey (1944) and Wilson-Hilferty 416 r = qq + qq; 417 /* A slightly more stable version of t := \chi^2_{alpha} of AS 64 418 * t = 1. / (9. * qq); t = r * R_pow_di(1. - t + y * sqrt(t), 3); */ 419 t = 1. / (3. * sqrt(qq)); 420 t = r * R_pow_di!T(1. + t*(-t + y), 3);// = \chi^2_{alpha} of AS 64 421 s = 4. * pp + r - 2.;// 4p + 2q - 2 = numerator of new t = (...) / chi^2 422 //R_ifDEBUG_printf("min(p,q) <= 1: t=%g", t); 423 if (t == 0 || (t < 0. && s >= t)) { // cannot use chisq approx 424 // x0 = 1 - { (1-a)*q*B(p,q) } ^{1/q} {AS 65} 425 // xinbta = 1. - exp((log(1-a)+ log(qq) + logbeta) / qq); 426 T l1ma;/* := log(1-a), directly from alpha (as 'la' above): 427 * FIXME: not worth it? log1p(-a) always the same ?? */ 428 if(swap_tail) 429 l1ma = R_DT_log!T(alpha, lower_tail); 430 else 431 l1ma = R_DT_Clog!T(alpha, lower_tail, log_p); 432 //R_ifDEBUG_printf(" t <= 0 : log1p(-a)=%.15g, better l1ma=%.15g\n", log1p(-a), l1ma); 433 T xx = (l1ma + log(qq) + logbeta) / qq; 434 if(xx <= 0.) { 435 xinbta = -expm1(xx); 436 u = R_Log1_Exp!T(xx);// = log(xinbta) = log(1 - exp(...A...)) 437 } else { // xx > 0 ==> 1 - e^xx < 0 .. is nonsense 438 //R_ifDEBUG_printf(" xx=%g > 0: xinbta:= 1-e^xx < 0\n", xx); 439 xinbta = 0; u = -T.infinity; /// FIXME can do better? 440 } 441 } else { 442 t = s / t; 443 //R_ifDEBUG_printf(" t > 0 or s < t < 0: new t = %g ( > 1 ?)\n", t); 444 if (t <= 1.) { // cannot use chisq, either 445 u = (la + log(pp) + logbeta) / pp; 446 xinbta = exp(u); 447 } else { // (1+x0)/(1-x0) = t, solved for x0 : 448 xinbta = 1. - 2. / (t + 1.); 449 u = log1p(-2. / (t + 1.)); 450 } 451 } 452 } 453 454 // Problem: If initial u is completely wrong, we make a wrong decision here 455 if(swap_choose && (( swap_tail && u >= -exp( log_q_cut)) || // ==> "swap back" 456 (!swap_tail && u >= -exp(4*log_q_cut) && pp / qq < 1000.) // ==> "swap now" 457 )) { 458 // "revert swap" -- and use_log_x 459 swap_tail = !swap_tail; 460 //R_ifDEBUG_printf(" u = %g (e^u = xinbta = %.16g) ==> ", u, xinbta); 461 if(swap_tail) { // "swap now" (much less easily) 462 a = R_DT_CIv; // needed ? 463 la = R_DT_Clog!T(alpha, lower_tail, log_p); 464 pp = q; qq = p; 465 } 466 else { // swap back : 467 a = p_; 468 la = R_DT_log!T(alpha, lower_tail); 469 pp = p; qq = q; 470 } 471 //R_ifDEBUG_printf("\"%s\"; la = %g\n", (swap_tail ? "swap now" : "swap back"), la); 472 // we could redo computations above, but this should be stable 473 u = R_Log1_Exp!T(u); 474 xinbta = exp(u); 475 476 /* Careful: "swap now" should not fail if 477 1) the above initial xinbta is "completely wrong" 478 2) The correction step can go outside (u_n > 0 ==> e^u > 1 is illegal) 479 e.g., for qbeta(0.2066, 0.143891, 0.05) 480 */ 481 } //else R_ifDEBUG_printf("\n"); 482 483 if(!use_log_x) 484 use_log_x = (u < log_q_cut);// <==> xinbta = e^u < exp(log_q_cut) 485 //Rboolean 486 bad_u = !isFinite(u); 487 bad_init = bad_u || xinbta > p_hi; 488 489 //R_ifDEBUG_printf(" -> u = %g, e^u = xinbta = %.16g, (Newton acu=%g%s%s%s)\n", 490 // u, xinbta, acu, (bad_u ? ", ** bad u **" : ""), 491 // ((bad_init && !bad_u) ? ", ** bad_init **" : ""), 492 // (use_log_x ? ", on u = LOG(x) SCALE" : "")); 493 494 u_n = 1.; // -Wall 495 tx = xinbta; // keeping "original initial x" (for now) 496 497 if(bad_u || u < log_q_cut) { 498 /* e.g. 499 qbeta(0.21, .001, 0.05) 500 try "left border" quickly, i.e., 501 try at smallest positive number: */ 502 w = pbeta_raw!T(DBL_very_MIN, pp, qq, 1, log_p); 503 if(w > (log_p ? la : a)) { 504 //R_ifDEBUG_printf( 505 //" quantile is left of %g; \"convergence\"\n", DBL_very_MIN); 506 if(log_p || fabs(w - a) < fabs(0 - a)) { // DBL_very_MIN is better than 0 507 tx = DBL_very_MIN; 508 u_n = DBL_log_v_MIN;// = log(DBL_very_MIN) 509 } else { 510 tx = 0.; 511 u_n = -T.infinity; 512 } 513 use_log_x = log_p; add_N_step = 0; goto L_return; 514 } else { 515 //R_ifDEBUG_printf(" pbeta(%g, *) = %g <= %g (= %s) --> continuing\n", 516 // DBL_log_v_MIN, w, (log_p ? la : a), (log_p ? "la" : "a")); 517 if(u < DBL_log_v_MIN) { 518 u = DBL_log_v_MIN;// = log(DBL_very_MIN) 519 xinbta = DBL_very_MIN; 520 } 521 } 522 } 523 524 525 /* Sometimes the approximation is negative (and == 0 is also not "ok") */ 526 if (bad_init && !(use_log_x && tx > 0)) { 527 if(u == -T.infinity) { 528 //R_ifDEBUG_printf(" u = -Inf;"); 529 u = M_LN2 * DBL_MIN_EXP; 530 xinbta = DBL_MIN; 531 } else { 532 //R_ifDEBUG_printf(" bad_init: u=%g, xinbta=%g;", u,xinbta); 533 xinbta = (xinbta > 1.1) // i.e. "way off" 534 ? 0.5 // otherwise, keep the respective boundary: 535 : ((xinbta < p_lo) ? exp(u) : p_hi); 536 if(bad_u) 537 u = log(xinbta); 538 // otherwise: not changing "potentially better" u than the above 539 } 540 //R_ifDEBUG_printf(" -> (partly)new u=%g, xinbta=%g\n", u,xinbta); 541 } 542 543 L_Newton: 544 /* -------------------------------------------------------------------- 545 546 * Solve for x by a modified Newton-Raphson method, using pbeta_raw() 547 */ 548 r = 1 - pp; 549 t = 1 - qq; 550 wprev = 0., prev = 1.; // -Wall 551 552 if(use_log_x) { // find log(xinbta) -- work in u := log(x) scale 553 // if(bad_init && tx > 0) xinbta = tx;// may have been better 554 for (i_pb = 0; i_pb < 1000; i_pb++) { 555 // using log_p == TRUE unconditionally here 556 /* FIXME: if exp(u) = xinbta underflows to 0, 557 * want different formula pbeta_log(u, ..) */ 558 y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, 1); 559 560 /* w := Newton step size for L(u) = log F(e^u) =!= 0; u := log(x) 561 * = (L(.) - la) / L'(.); L'(u)= (F'(e^u) * e^u ) / F(e^u) 562 * = (L(.) - la)*F(.) / {F'(e^u) * e^u } = 563 * = (L(.) - la) * e^L(.) * e^{-log F'(e^u) - u} 564 * = ( y - la) * e^{ y - u -log F'(e^u)} 565 and -log F'(x)= -log f(x) = - -logbeta + (1-p) log(x) + (1-q) log(1-x) 566 = logbeta + (1-p) u + (1-q) log(1-e^u) 567 */ 568 w = (y == -T.infinity) // y = -Inf well possible: we are on log scale! 569 ? 0. : (y - la) * exp(y - u + logbeta + r * u + t * R_Log1_Exp(u)); 570 if(!isFinite(w)) 571 break; 572 if (i_pb >= n_N && w * wprev <= 0.) 573 prev = fmax2!T(fabs(adj),fpu); 574 //R_ifDEBUG_printf( 575 //"N(i=%2d): u=%#20.16g, pb(e^u)=%#15.9g, w=%#15.9g, %s prev=%g,", 576 //i_pb, u, y, w, (i_pb >= n_N && w * wprev <= 0.) ? "new" : "old", prev); 577 g = 1; 578 for (i_inn = 0; i_inn < 1000; i_inn++) { 579 adj = g * w; 580 // safe guard (here, from the very beginning) 581 if (fabs(adj) < prev) { 582 u_n = u - adj; // u_{n+1} = u_n - g*w 583 if (u_n <= 0.) { // <==> 0 < xinbta := e^u <= 1 584 if (prev <= acu || fabs(w) <= acu) { 585 //R_ifDEBUG_printf(" it{in}=%d, -adj=%g, %s <= acu ==> convergence\n", 586 //i_inn, -adj, (prev <= acu) ? "prev" : "|w|"); 587 goto L_converged; 588 } 589 // if (u_n != ML_NEGINF && u_n != 1) 590 break; 591 } 592 } 593 g /= 3; 594 } 595 // (cancellation in (u_n -u) => may differ from adj: 596 T D = fmin2!T(fabs(adj), fabs(u_n - u)); 597 /* R_ifDEBUG_printf(" delta(u)=%g\n", u_n - u); */ 598 //R_ifDEBUG_printf(" it{in}=%d, delta(u)=%9.3g, D/|.|=%.3g\n", 599 // i_inn, u_n - u, D/fabs(u_n + u)); 600 if (D <= 4e-16 * fabs(u_n + u)) 601 goto L_converged; 602 u = u_n; 603 xinbta = exp(u); 604 wprev = w; 605 } // for(i ) 606 607 } else { // "normal scale" Newton 608 609 for (i_pb=0; i_pb < 1000; i_pb++) { 610 y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, log_p); 611 // delta{y} : d_y = y - (log_p ? la : a); 612 if(!isFinite(y) && !(log_p && y == T.infinity))// y = -Inf is ok if(log_p) 613 { // ML_ERR_return_NAN : 614 //ML_ERROR(ME_DOMAIN, ""); 615 qb[0] = qb[1] = T.nan; return; 616 } 617 618 619 /* w := Newton step size (F(.) - a) / F'(.) or, 620 * -- log: (lF - la) / (F' / F) = exp(lF) * (lF - la) / F' 621 */ 622 w = log_p 623 ? (y - la) * exp(y + logbeta + r * log(xinbta) + t * log1p(-xinbta)) 624 : (y - a) * exp( logbeta + r * log(xinbta) + t * log1p(-xinbta)); 625 if (i_pb >= n_N && w * wprev <= 0.) 626 prev = fmax2!T(fabs(adj),fpu); 627 //R_ifDEBUG_printf( 628 //"N(i=%2d): x0=%#17.15g, pb(x0)=%#15.9g, w=%#15.9g, %s prev=%g,", 629 //i_pb, xinbta, y, w, 630 //(i_pb >= n_N && w * wprev <= 0.) ? "new" : "old", prev); 631 g = 1; 632 for (i_inn = 0; i_inn < 1000; i_inn++) { 633 adj = g * w; 634 // take full Newton steps at the beginning; only then safe guard: 635 if (i_pb < n_N || fabs(adj) < prev) { 636 tx = xinbta - adj; // x_{n+1} = x_n - g*w 637 if (0. <= tx && tx <= 1.) { 638 if (prev <= acu || fabs(w) <= acu) { 639 //R_ifDEBUG_printf(" it{in}=%d, delta(x)=%g, %s <= acu ==> convergence\n", 640 // i_inn, -adj, (prev <= acu) ? "prev" : "|w|"); 641 goto L_converged; 642 } 643 if (tx != 0. && tx != 1) 644 break; 645 } 646 } 647 g /= 3; 648 } 649 //R_ifDEBUG_printf(" it{in}=%d, delta(x)=%g\n", i_inn, tx - xinbta); 650 if (fabs(tx - xinbta) <= 4e-16 * (tx + xinbta)) // "<=" : (.) == 0 651 goto L_converged; 652 xinbta = tx; 653 if(tx == 0) // "we have lost" 654 break; 655 wprev = w; 656 } // for( i_pb ..) 657 658 } // end{else : normal scale Newton} 659 660 /*-- NOT converged: Iteration count --*/ 661 warned = 1; 662 //ML_ERROR(ME_PRECISION, "qbeta"); 663 664 L_converged: 665 log_ = log_p || use_log_x; // only for printing 666 //R_ifDEBUG_printf(" %s: Final delta(y) = %g%s\n", 667 // warned ? "_NO_ convergence" : "converged", 668 // y - (log_ ? la : a), (log_ ? " (log_)" : "")); 669 if((log_ && y == -T.infinity) || (!log_ && y == 0)) { 670 // stuck at left, try if smallest positive number is "better" 671 w = pbeta_raw!T(DBL_very_MIN, pp, qq, 1, log_); 672 if(log_ || fabs(w - a) <= fabs(y - a)) { 673 tx = DBL_very_MIN; 674 u_n = DBL_log_v_MIN;// = log(DBL_very_MIN) 675 } 676 add_N_step = 0; // not trying to do better anymore 677 } 678 else if(!warned && (log_ ? fabs(y - la) > 3 : fabs(y - a) > 1e-4)) { 679 if(!(log_ && y == -T.infinity && pbeta_raw!T(DBL_1__eps, pp, qq, 1, 1) > la + 2)) 680 doNothing(); 681 //MATHLIB_WARNING2( // low accuracy for more platform independent output: 682 //"qbeta(a, *) =: x0 with |pbeta(x0,*%s) - alpha| = %.5g is not accurate", 683 //(log_ ? ", log_" : ""), fabs(y - (log_ ? la : a))); 684 } 685 L_return: 686 if(give_log_q) { // ==> use_log_x , too 687 if(!use_log_x) // (see if claim above is true) 688 //MATHLIB_WARNING( 689 //"qbeta() L_return, u_n=%g; give_log_q=TRUE but use_log_x=FALSE -- please report!", u_n); 690 r = R_Log1_Exp!T(u_n); 691 if(swap_tail) { 692 qb[0] = r; qb[1] = u_n; 693 } else { 694 qb[0] = u_n; qb[1] = r; 695 } 696 } else { 697 if(use_log_x) { 698 if(add_N_step) { 699 /* add one last Newton step on original x scale, e.g., for 700 qbeta(2^-98, 0.125, 2^-96) */ 701 xinbta = exp(u_n); 702 y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, log_p); 703 w = log_p 704 ? (y - la) * exp(y + logbeta + r * log(xinbta) + t * log1p(-xinbta)) 705 : (y - a) * exp(logbeta + r * log(xinbta) + t * log1p(-xinbta)); 706 tx = xinbta - w; 707 //R_ifDEBUG_printf(" Final Newton correction(non-log scale):\n" 708 // // \n xinbta=%.16g 709 // " xinbta=%.16g, y=%g, w=-Delta(x)=%g. \n=> new x=%.16g\n", 710 // xinbta, y, w, tx); 711 } else { 712 if(swap_tail){ 713 qb[0] = -expm1(u_n); qb[1] = exp(u_n); 714 } else { 715 qb[0] = exp(u_n); qb[1] = -expm1(u_n); 716 } 717 return; 718 } 719 } 720 if(swap_tail){ 721 qb[0] = 1 - tx; qb[1] = tx; 722 } else { 723 qb[0] = tx; qb[1] = 1 - tx; 724 } 725 } 726 return; 727 } 728 729 T qbeta(T: double)(T alpha, T p, T q, int lower_tail, int log_p) 730 { 731 732 /* test for admissibility of parameters */ 733 if (isNaN(p) || isNaN(q) || isNaN(alpha)) 734 return p + q + alpha; 735 if(p < 0. || q < 0.) 736 return T.nan; 737 // allowing p==0 and q==0 <==> treat as one- or two-point mass 738 739 T[2] qbet;// = { qbeta(), 1 - qbeta() } 740 qbeta_raw!T(alpha, p, q, lower_tail, log_p, MLOGICAL_NA, USE_LOG_X_CUTOFF, n_NEWTON_FREE, qbet.ptr); 741 return qbet[0]; 742 } 743 744 enum expmax = (DBL_MAX_EXP * M_LN2); /* = log(DBL_MAX) */ 745 746 immutable(string) v_w_from__u1_bet_b(){ 747 return `v = beta * log(u1 / (1.0 - u1)); 748 if (v <= expmax) { 749 w = b * exp(v); 750 if(!isFinite(w)) w = DBL_MAX; 751 } else 752 w = DBL_MAX;`; 753 } 754 755 immutable(string) v_w_from__u1_bet_a(){ 756 return `v = beta * log(u1 / (1.0 - u1)); 757 if (v <= expmax) { 758 w = a * exp(v); 759 if(!isFinite(w)) w = DBL_MAX; 760 } else 761 w = DBL_MAX;`; 762 } 763 764 T rbeta(T: double)(T aa, T bb) 765 { 766 if (isNaN(aa) || isNaN(bb) || aa < 0. || bb < 0.) 767 return T.nan; 768 if (!isFinite(aa) && !isFinite(bb)) // a = b = Inf : all mass at 1/2 769 return 0.5; 770 if (aa == 0. && bb == 0.) // point mass 1/2 at each of {0,1} : 771 return (unif_rand!T() < 0.5) ? 0. : 1.; 772 // now, at least one of a, b is finite and positive 773 if (!isFinite(aa) || bb == 0.) 774 return 1.0; 775 if (!isFinite(bb) || aa == 0.) 776 return 0.0; 777 778 T a, b, alpha; 779 T r, s, t, u1, u2, v, w, y, z; 780 int qsame; 781 /* FIXME: Keep Globals (properly) for threading */ 782 /* Uses these GLOBALS to save time when many rv's are generated : */ 783 static T beta, gamma, delta, k1, k2; 784 static T olda = -1.0; 785 static T oldb = -1.0; 786 787 /* Test if we need new "initializing" */ 788 qsame = (olda == aa) && (oldb == bb); 789 if (!qsame) { olda = aa; oldb = bb; } 790 791 a = fmin2(aa, bb); 792 b = fmax2(aa, bb); /* a <= b */ 793 alpha = a + b; 794 795 //#define v_w_from__u1_bet(AA) \ 796 // v = beta * log(u1 / (1.0 - u1)); \ 797 // if (v <= expmax) { \ 798 // w = AA * exp(v); \ 799 // if(!R_FINITE(w)) w = DBL_MAX; \ 800 // } else \ 801 // w = DBL_MAX 802 803 804 if (a <= 1.0) { /* --- Algorithm BC --- */ 805 806 /* changed notation, now also a <= b (was reversed) */ 807 808 if (!qsame) { /* initialize */ 809 beta = 1.0 / a; 810 delta = 1.0 + b - a; 811 k1 = delta * (0.0138889 + 0.0416667 * a) / (b * beta - 0.777778); 812 k2 = 0.25 + (0.5 + 0.25 / delta) * a; 813 } 814 /* FIXME: "do { } while()", but not trivially because of "continue"s:*/ 815 for(;;) { 816 u1 = unif_rand!T(); 817 u2 = unif_rand!T(); 818 if (u1 < 0.5) { 819 y = u1 * u2; 820 z = u1 * y; 821 if (0.25 * u2 + z - y >= k1) 822 continue; 823 } else { 824 z = u1 * u1 * u2; 825 if (z <= 0.25) { 826 mixin (v_w_from__u1_bet_b()); 827 break; 828 } 829 if (z >= k2) 830 continue; 831 } 832 833 mixin (v_w_from__u1_bet_b()); 834 835 if (alpha * (log(alpha / (a + w)) + v) - 1.3862944 >= log(z)) 836 break; 837 } 838 return (aa == a) ? a / (a + w) : w / (a + w); 839 840 } else { /* Algorithm BB */ 841 842 if (!qsame) { /* initialize */ 843 beta = sqrt((alpha - 2.0) / (2.0 * a * b - alpha)); 844 gamma = a + 1.0 / beta; 845 } 846 do { 847 u1 = unif_rand!T(); 848 u2 = unif_rand!T(); 849 850 mixin (v_w_from__u1_bet_a()); 851 852 z = u1 * u1 * u2; 853 r = gamma * v - 1.3862944; 854 s = a + r - w; 855 if (s + 2.609438 >= 5.0 * z) 856 break; 857 t = log(z); 858 if (s > t) 859 break; 860 } while (r + alpha * log(alpha / (b + w)) < t); 861 862 return (aa != a) ? b / (b + w) : w / (b + w); 863 } 864 } 865 866 867 868 void test_beta(){ 869 import std.stdio: writeln; 870 writeln("beta: ", beta(2., 4.)); 871 writeln("dbeta: ", dbeta(.7, 3., 5., 1)); 872 writeln("pbeta: ", pbeta(.7, 3., 5., 1, 0)); 873 writeln("qbeta: ", qbeta(.7, 3., 5., 1, 0)); 874 writeln("rbeta: ", rbeta(3., 5.), ", rbeta: ", rbeta(3., 5.), ", rbeta: ", rbeta(3., 5.)); 875 }