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); }