// Find the upper and lower limits of a slice containing x for a // potentially multimodal distribution. Uses Neal's (2003 Annals of // Statistics) doubling algorithm. bool SSS::find_limits_unbounded(double x){ hi_ = x + suggested_dx_; lo_ = x - suggested_dx_; logphi_ = logf_(hi_); logplo_ = logf_(lo_); if(unimodal_){ find_limits_unbounded_unimodal(x); return true; }else{ int doubling_count = 0; while(!done_doubling()){ double u = runif_mt(rng(), -1, 1); if(u>0) double_hi(x); else double_lo(x); if (++doubling_count > 100) { // The slice has been doubled 100 times. This is almost // certainly beecause of an error in the target distribution // or a crazy starting value. return false; } } } check_upper_limit(x); check_lower_limit(x); return true; }
// Driver function to find the limits of a slice containing 'x'. // Logic varies according to whether the distribution is bounded // above, below, both, or neither. void SSS::find_limits(double x){ logp_slice_ = logf_(x) - rexp_mt(rng(), 1.0); check_finite(x,logp_slice_); bool limits_successfully_found = true; if(doubly_bounded()){ lo_ = lower_bound_; logplo_ = logf_(lo_); hi_ = upper_bound_; logphi_ = logf_(hi_); }else if (lower_bounded()){ lo_ = lower_bound_; logplo_ = logf_(lo_); limits_successfully_found = find_upper_limit(x); }else if(upper_bounded()){ limits_successfully_found = find_lower_limit(x); hi_ = upper_bound_; logphi_ = logf_(hi_); }else{ // unbounded limits_successfully_found = find_limits_unbounded(x); } check_slice(x); if (limits_successfully_found) { check_probs(x); } }
// Find the upper and lower limits of a slice when the target // distribution is known to be unimodal. void SSS::find_limits_unbounded_unimodal(double x){ hi_ = x + suggested_dx_; logphi_ = logf_(hi_); while(logphi_ >= logp_slice_) double_hi(x); check_upper_limit(x); lo_ = x - suggested_dx_; logplo_ = logf_(lo_); while(logplo_ >= logp_slice_) double_lo(x); check_lower_limit(x); }
// Makes the upper end of the slice twice as far away from x, and // updates the density value void SSS::double_hi(double x){ double dx = hi_ - x; hi_ = x + 2 * dx; if(!std::isfinite(hi_)){ handle_error("infinite upper limit", x); } logphi_ = logf_(hi_); }
bool SSS::find_lower_limit(double x){ lo_ = x - suggested_dx_; logplo_ = logf_(lo_); int doubling_count = 0; while(logplo_ >= logp_slice_ || (!unimodal_ && runif_mt(rng()) > .5)){ double_lo(x); if (++doubling_count > 100) { // The slice has been doubled over 100 times. This is almost // certainly because of an error in the implementation of the // target distribution, or a crazy starting value. return false; } } check_lower_limit(x); return true; }
double SSS::draw(double x){ find_limits(x); double logp_cand = 0; int number_of_tries = 0; do{ double x_cand = runif_mt(rng(), lo_, hi_); logp_cand = logf_(x_cand); if(logp_cand < logp_slice_){ contract(x,x_cand, logp_cand); ++number_of_tries; } else return x_cand; if(number_of_tries > 100){ ostringstream err; err << "number of tries exceeded. candidate value is " << x_cand << " with logp_cand = " << logp_cand << endl; handle_error(err.str(), x); } }while(logp_cand < logp_slice_); handle_error("should never get here", x); return 0; }
double SSS::logp(double x)const{ return logf_(x);}
// Makes the lower end of the slice twice as far away from x, and // updates the density value void SSS::double_lo(double x){ double dx = x - lo_; lo_ = x-2*dx; if(!std::isfinite(lo_)) handle_error("infinite lower limit", x); logplo_ = logf_(lo_); }
virtual double operator()(double u, double &g, double &h)const{ double ans = logf_(u,g,h) + s_ * u; g += s_; // derivative is with respect to u return ans; }
virtual double operator()(double u)const{ return logf_(u) + s_ * u; }
double DBARS::f(double x)const{return logf_(x);}