double search_interval(double x0,double& L, double& R, slice_function& g,double logy) { // assert(g(x0) > g(L) and g(x0) > g(R)); assert(g(x0) >= logy); assert(L < R); assert(L <= x0 and x0 <= R); double L0 = L, R0 = R; // std::cerr<<"** L0 = "<<L0<<" x0 = "<<x0<<" R0 = "<<R0<<std::endl; for(int i=0;i<200;i++) { double x1 = L + uniform()*(R-L); double gx1 = g(x1); // std::cerr<<" L = "<<L <<" x = "<<g.current_value()<<" R = "<<R<<std::endl; // std::cerr<<" logy = "<<logy<<"\n"; // logy_x0 = "<<logy_x0<<" logy_current = "<<g()<<std::endl; if (gx1 >= logy) return x1; if (x1 > x0) R = x1; else L = x1; } std::cerr<<"Warning! Is size of the interval really ZERO?"<<std::endl; double logy_x0 = g(x0); std::cerr<<" L0 = "<<L0<<" x0 = "<<x0<<" R0 = "<<R0<<std::endl; std::cerr<<" L = "<<L <<" x = "<<g.current_value()<<" R = "<<R<<std::endl; std::cerr<<" logy = "<<logy<<" logy_x0 = "<<logy_x0<<" logy_current = "<<g()<<std::endl; std::abort(); return x0; }
inline static void inc(double& x, double w, const slice_function& g, bool& hit_upper_bound) { x += w; if (g.above_upper_bound(x)) { x = g.upper_bound; hit_upper_bound = true; } }
inline static void dec(double& x, double w, const slice_function& g, bool& hit_lower_bound) { x -= w; if (g.below_lower_bound(x)) { x = g.lower_bound; hit_lower_bound=true; } }
std::pair<double,double> find_slice_boundaries_stepping_out(double x0,slice_function& g,double logy, double w,int m) { assert(g.in_range(x0)); double u = uniform()*w; double L = x0 - u; double R = x0 + (w-u); // Expand the interval until its ends are outside the slice, or until // the limit on steps is reached. // std::cerr<<"!! L0 = "<<L<<" x0 = "<<x0<<" R0 = "<<R<<"\n"; if (m>1) { int J = uniform(0,m-1); int K = (m-1)-J; while (J>0 and (not g.below_lower_bound(L)) and g(L)>logy) { L -= w; J--; // std::cerr<<" g("<<L<<") = "<<g()<<" > "<<logy<<"\n"; // std::cerr<<"<- L0 = "<<L<<" x0 = "<<x0<<" R0 = "<<R<<"\n"; } while (K>0 and (not g.above_upper_bound(R)) and g(R)>logy) { R += w; K--; // std::cerr<<" g("<<R<<") = "<<g()<<" > "<<logy<<"\n"; // std::cerr<<"-> L0 = "<<L<<" x0 = "<<x0<<" R0 = "<<R<<"\n"; } } else { while ((not g.below_lower_bound(L)) and g(L)>logy) L -= w; while ((not g.above_upper_bound(R)) and g(R)>logy) R += w; } // Shrink interval to lower and upper bounds. if (g.below_lower_bound(L)) L = g.lower_bound; if (g.above_upper_bound(R)) R = g.upper_bound; assert(L < R); // std::cerr<<"[] L0 = "<<L<<" x0 = "<<x0<<" R0 = "<<R<<"\n"; return std::pair<double,double>(L,R); }
double slice_sample(double x0, slice_function& g,double w, int m) { assert(g.in_range(x0)); double gx0 = g(); volatile double diff = gx0 - g(x0); assert(std::abs(diff) < 1.0e-9); // Determine the slice level, in log terms. double logy = gx0 - exponential(1); // Find the initial interval to sample from. std::pair<double,double> interval = find_slice_boundaries_stepping_out(x0,g,logy,w,m); double L = interval.first; double R = interval.second; // Sample from the interval, shrinking it on each rejection return search_interval(x0,L,R,g,logy); }
std::pair<double,double> find_slice_boundaries_stepping_out(double x0,slice_function& g,double logy, double w,int m) { double u = uniform()*w; double L = x0 - u; double R = x0 + (w-u); // Expand the interval until its ends are outside the slice, or until // the limit on steps is reached. if (m>1) { int J = floor(uniform()*m); int K = (m-1)-J; while (J>0 and (not g.below_lower_bound(L)) and g(L)>logy) { L -= w; J--; } while (K>0 and (not g.above_upper_bound(R)) and g(R)>logy) { R += w; K--; } } else { while ((not g.below_lower_bound(L)) and g(L)>logy) L -= w; while ((not g.above_upper_bound(R)) and g(R)>logy) R += w; } // Shrink interval to lower and upper bounds. if (g.below_lower_bound(L)) L = g.lower_bound; if (g.above_upper_bound(R)) R = g.upper_bound; return std::pair<double,double>(L,R); }
// Assumes uni-modal std::pair<double,double> find_slice_boundaries_search(double& x0,slice_function& g,double logy, double w,int /*m*/) { // the initial point should be within the bounds, if the exist assert(not g.below_lower_bound(x0)); assert(not g.above_upper_bound(x0)); bool hit_lower_bound=false; bool hit_upper_bound=false; double gx0 = g(x0); double L = x0; double R = L; inc(R,w,g,hit_upper_bound); // if (gx > logy) return find_slice_boundaries_stepping_out(x,g,logy,w,m,lower_bound,lower,upper_bound,upper); int state = -1; while(1) { double gL = g(L); double gR = g(R); if (gx0 < logy and gL > gx0) { x0 = L; gx0 = gL; } if (gx0 < logy and gR > gx0) { x0 = R; gx0 = gR; } // below bound, and slopes upwards to the right if (gR < logy and gL < gR) { if (state == 2) break; else if (state == 1) { inc(R,w,g,hit_upper_bound); break; } state = 0; hit_lower_bound=false; L = R; inc(R,w,g,hit_upper_bound); } // below bound, and slopes upwards to the left else if (gL < logy and gR < gL) { if (state == 2) break; if (state == 1) { dec(L,w,g,hit_lower_bound); break; } state = 1; hit_upper_bound=false; R = L; dec(L,w,g,hit_lower_bound); } else { state = 2; bool moved = false; if (gL >= logy and not hit_lower_bound) { moved = true; dec(L,w,g,hit_lower_bound); } if (gR >= logy and not hit_upper_bound) { moved = true; inc(R,w,g,hit_upper_bound); } if (not moved) break; } } return std::pair<double,double>(L,R); }
double slice_sample(slice_function& g, double w, int m) { double x0 = g.current_value(); return slice_sample(x0,g,w,m); }