double PolyaGamma::rtigauss(double Z, RNG& r) { Z = fabs(Z); double t = __TRUNC; double X = t + 1.0; if (__TRUNC_RECIP > Z) { // mu > t double alpha = 0.0; while (r.unif() > alpha) { // X = t + 1.0; // while (X > t) // X = 1.0 / r.gamma_rate(0.5, 0.5); // Slightly faster to use truncated normal. double E1 = r.expon_rate(1.0); double E2 = r.expon_rate(1.0); while ( E1*E1 > 2 * E2 / t) { E1 = r.expon_rate(1.0); E2 = r.expon_rate(1.0); } X = 1 + E1 * t; X = t / (X * X); alpha = exp(-0.5 * Z*Z * X); } } else { double mu = 1.0 / Z; while (X > t) { double Y = r.norm(1.0); Y *= Y; double half_mu = 0.5 * mu; double mu_Y = mu * Y; X = mu + half_mu * mu_Y - half_mu * sqrt(4 * mu_Y + mu_Y * mu_Y); if (r.unif() > mu / (mu + X)) X = mu*mu / X; } } return X; }
double PolyaGamma::draw_like_devroye(double Z, RNG& r) { // Change the parameter. Z = fabs(Z) * 0.5; // Now sample 0.25 * J^*(1, Z := Z/2). double fz = 0.125 * __PI*__PI + 0.5 * Z*Z; // ... Problems with large Z? Try using q_over_p. // double p = 0.5 * __PI * exp(-1.0 * fz * __TRUNC) / fz; // double q = 2 * exp(-1.0 * Z) * pigauss(__TRUNC, Z); double X = 0.0; double S = 1.0; double Y = 0.0; // int iter = 0; If you want to keep track of iterations. while (true) { // if (r.unif() < p/(p+q)) if ( r.unif() < mass_texpon(Z) ) X = __TRUNC + r.expon_rate(1) / fz; else X = rtigauss(Z, r); S = a(0, X); Y = r.unif() * S; int n = 0; bool go = true; // Cap the number of iterations? while (go) { // Break infinite loop. Put first so it always checks n==0. #ifdef USE_R if (n % 1000 == 0) R_CheckUserInterrupt(); #endif ++n; if (n%2==1) { S = S - a(n, X); if ( Y<=S ) return 0.25 * X; } else { S = S + a(n, X); if ( Y>S ) go = false; } } // Need Y <= S in event that Y = S, e.g. when X = 0. } } // draw_like_devroye