packages feed

passage-0.1: cbits/runtime/src/templates/slice.c

#if !(defined(LEFT) && defined(RIGHT))
static double WIDTH(VAR) = 1;
#endif

/* Slice over the reals, or a sub-range of the reals. */
/* static inline */
double SLICE(VAR)(double x0)
{
  double x1;
  double r;
  double y;
#if !(defined(LEFT) && defined(RIGHT))
  double lo;
#endif
  double left;
  double right;

  r = genrand_real3();
  y = log(r) + LL_FUN(VAR)(x0);
#if !(defined(LEFT) && defined(RIGHT))
  lo= getRandomRange(0, WIDTH(VAR));
#endif

#if defined(LEFT)
  left = LEFT;
#else
  left = x0 - lo;
  while(LL_FUN(VAR)(left) > y) left -= WIDTH(VAR);
#endif

#if defined(RIGHT)
  right = RIGHT;
#else
  right = x0 - lo + WIDTH(VAR);
  while(LL_FUN(VAR)(right) > y) right += WIDTH(VAR);
#endif

  for ( x1 = getRandomRange(left, right)
      ; LL_FUN(VAR)(x1) < y
      ; x1 = getRandomRange(left, right)
      )  {
    if (x1 < x0) left = x1; else right = x1;
  }

  return x1;
}


#if !(defined(LEFT) && defined(RIGHT))

/* Slice over the reals */
/* static inline */
double SLICE_TUNE(VAR)(double x0)
{
  double x1;
  double r;
  double y;
  double lo;
  double left;
  double right;

  int steps_out = 0;
  int steps_in = 0;

  r = genrand_real3();
  y = log(r) + LL_FUN(VAR)(x0);
  lo= getRandomRange(0, WIDTH(VAR));

#if defined(LEFT)
  left = LEFT;
#else
  left = x0 - lo;
  while(LL_FUN(VAR)(left) > y)  { left -= WIDTH(VAR); ++steps_out; }
#endif

#if defined(RIGHT)
  right = RIGHT;
#else
  right = x0 - lo + WIDTH(VAR);
  while(LL_FUN(VAR)(right) > y) { right += WIDTH(VAR); ++steps_out; }
#endif

  for ( x1 = getRandomRange(left, right)
      ; LL_FUN(VAR)(x1) < y
      ; x1 = getRandomRange(left, right)
      )  {
    if (x1 < x0) left = x1; else right = x1;
    ++steps_in;
  }

  /* Trying to optimize the width, 
  assuming an average "step in" cuts the interval in half. 
  Current rule of thumb is to take the weighted average of the current width
  with the estimated ideal width */
  WIDTH(VAR) *= 0.75 + steps_out / ((double) (1 << (steps_in+2)));

  /* fprintf(stderr, "(%d, [(%f,%d)])\n", VAR, WIDTH(VAR), error); */
  return x1;
}

#endif