void rb_tree_destroy_with_keys(rb_tree *t)
{
     rb_node *n = rb_tree_min(t);
     while (n) {
	  free(n->k); n->k = NULL;
	  n = rb_tree_succ(n);
     }
     rb_tree_destroy(t);
}
/* given newpt, which presumably has just been added to our
   tree, update all pts with a greater function value in case
   newpt is closer to them than their previous closest_pt ...
   we can ignore already-minimized points since we never do
   local minimization from the same point twice */
static void pts_update_newpt(int n, rb_tree *pts, pt *newpt)
{
     rb_node *node = rb_tree_find_gt(pts, (rb_key) newpt);
     while (node) {
	  pt *p = (pt *) node->k;
	  if (!p->minimized) {
	       double d = distance2(n, newpt->x, p->x);
	       if (d < p->closest_pt_d) p->closest_pt_d = d;
	  }
	  node = rb_tree_succ(node);
     }
}
/* given newlm, which presumably has just been added to our
   tree, update all pts with a greater function value in case
   newlm is closer to them than their previous closest_lm ...
   we can ignore already-minimized points since we never do
   local minimization from the same point twice */
static void pts_update_newlm(int n, rb_tree *pts, double *newlm)
{
     pt tmp_pt;
     rb_node *node;
     tmp_pt.f = newlm[0];
     node = rb_tree_find_gt(pts, (rb_key) &tmp_pt);
     while (node) {
	  pt *p = (pt *) node->k;
	  if (!p->minimized) {
	       double d = distance2(n, newlm+1, p->x);
	       if (d < p->closest_lm_d) p->closest_lm_d = d;
	  }
	  node = rb_tree_succ(node);
     }
}
Exemplo n.º 4
0
/* Find the lower convex hull of a set of points (x,y) stored in a rb-tree
   of pointers to {x,y} arrays sorted in lexographic order by (x,y).

   Unlike standard convex hulls, we allow redundant points on the hull,
   and even allow duplicate points if allow_dups is nonzero.

   The return value is the number of points in the hull, with pointers
   stored in hull[i] (should be an array of length >= t->N).
*/
static int convex_hull(rb_tree *t, double **hull, int allow_dups)
{
     int nhull = 0;
     double minslope;
     double xmin, xmax, yminmin, ymaxmin;
     rb_node *n, *nmax;

     /* Monotone chain algorithm [Andrew, 1979]. */

     n = rb_tree_min(t);
     if (!n) return 0;
     nmax = rb_tree_max(t);

     xmin = n->k[0];
     yminmin = n->k[1];
     xmax = nmax->k[0];

     if (allow_dups)
	  do { /* include any duplicate points at (xmin,yminmin) */
	       hull[nhull++] = n->k;
	       n = rb_tree_succ(n);
	  } while (n && n->k[0] == xmin && n->k[1] == yminmin);
     else
	  hull[nhull++] = n->k;

     if (xmin == xmax) return nhull;

     /* set nmax = min mode with x == xmax */
#if 0
     while (nmax->k[0] == xmax)
	  nmax = rb_tree_pred(nmax); /* non-NULL since xmin != xmax */
     nmax = rb_tree_succ(nmax);
#else
     /* performance hack (see also below) */
     {
	  double kshift[2];
	  kshift[0] = xmax * (1 - 1e-13);
	  kshift[1] = -HUGE_VAL;
	  nmax = rb_tree_find_gt(t, kshift); /* non-NULL since xmin != xmax */
     }
#endif

     ymaxmin = nmax->k[1];
     minslope = (ymaxmin - yminmin) / (xmax - xmin);

     /* set n = first node with x != xmin */
#if 0
     while (n->k[0] == xmin)
	  n = rb_tree_succ(n); /* non-NULL since xmin != xmax */
#else
     /* performance hack (see also below) */
     {
	  double kshift[2];
	  kshift[0] = xmin * (1 + 1e-13);
	  kshift[1] = -HUGE_VAL;
	  n = rb_tree_find_gt(t, kshift); /* non-NULL since xmin != xmax */
     }
#endif

     for (; n != nmax; n = rb_tree_succ(n)) { 
	  double *k = n->k;
	  if (k[1] > yminmin + (k[0] - xmin) * minslope)
	       continue;

	  /* performance hack: most of the points in DIRECT lie along
	     vertical lines at a few x values, and we can exploit this */
	  if (nhull && k[0] == hull[nhull - 1][0]) { /* x == previous x */
	       if (k[1] > hull[nhull - 1][1]) {
		    double kshift[2];
		    /* because of the round to float in rect_diameter, above,
		       it shouldn't be possible for two diameters (x values)
		       to have a fractional difference < 1e-13.  Note
		       that k[0] > 0 always in DIRECT */
		    kshift[0] = k[0] * (1 + 1e-13);
		    kshift[1] = -HUGE_VAL;
		    n = rb_tree_pred(rb_tree_find_gt(t, kshift));
		    continue;
	       }
	       else { /* equal y values, add to hull */
		    if (allow_dups)
			 hull[nhull++] = k;
		    continue;
	       }
	  }

	  /* remove points until we are making a "left turn" to k */
	  while (nhull > 1) {
	       double *t1 = hull[nhull - 1], *t2;

	       /* because we allow equal points in our hull, we have
		  to modify the standard convex-hull algorithm slightly:
		  we need to look backwards in the hull list until we
		  find a point t2 != t1 */
	       int it2 = nhull - 2;
	       do {
		    t2 = hull[it2--];
	       } while (it2 >= 0 && t2[0] == t1[0] && t2[1] == t1[1]);
	       if (it2 < 0) break;

	       /* cross product (t1-t2) x (k-t2) > 0 for a left turn: */
	       if ((t1[0]-t2[0]) * (k[1]-t2[1])
		   - (t1[1]-t2[1]) * (k[0]-t2[0]) >= 0)
		    break;
	       --nhull;
	  }
	  hull[nhull++] = k;
     }

     if (allow_dups)
	  do { /* include any duplicate points at (xmax,ymaxmin) */
	       hull[nhull++] = nmax->k;
	       nmax = rb_tree_succ(nmax);
	  } while (nmax && nmax->k[0] == xmax && nmax->k[1] == ymaxmin);
     else
	  hull[nhull++] = nmax->k;

     return nhull;
}
nlopt_result mlsl_minimize(int n, nlopt_func f, void *f_data,
			   const double *lb, const double *ub, /* bounds */
			   double *x, /* in: initial guess, out: minimizer */
			   double *minf,
			   nlopt_stopping *stop,
			   nlopt_opt local_opt,
			   int Nsamples, /* #samples/iteration (0=default) */
			   int lds) /* random or low-discrepancy seq. (lds) */
{
     nlopt_result ret = NLOPT_SUCCESS;
     mlsl_data d;
     int i;
     pt *p;

     if (!Nsamples)
	  d.N = 4; /* FIXME: what is good number of samples per iteration? */
     else
	  d.N = Nsamples;
     if (d.N < 1) return NLOPT_INVALID_ARGS;

     d.n = n;
     d.lb = lb; d.ub = ub;
     d.stop = stop;
     d.f = f; d.f_data = f_data;
     rb_tree_init(&d.pts, pt_compare);
     rb_tree_init(&d.lms, lm_compare);
     d.s = lds ? nlopt_sobol_create((unsigned) n) : NULL;

     nlopt_set_min_objective(local_opt, fcount, &d);
     nlopt_set_lower_bounds(local_opt, lb);
     nlopt_set_upper_bounds(local_opt, ub);
     nlopt_set_stopval(local_opt, stop->minf_max);

     d.gamma = MLSL_GAMMA;

     d.R_prefactor = sqrt(2./K2PI) * pow(gam(n) * MLSL_SIGMA, 1.0/n);
     for (i = 0; i < n; ++i)
	  d.R_prefactor *= pow(ub[i] - lb[i], 1.0/n);

     /* MLSL also suggests setting some minimum distance from points
	to previous local minimiza and to the boundaries; I don't know
	how to choose this as a fixed number, so I set it proportional
	to R; see also the comments at top.  dlm and dbound are the
	proportionality constants. */
     d.dlm = 1.0; /* min distance/R to local minima (FIXME: good value?) */
     d.dbound = 1e-6; /* min distance/R to ub/lb boundaries (good value?) */
     

     p = alloc_pt(n);
     if (!p) { ret = NLOPT_OUT_OF_MEMORY; goto done; }

     /* FIXME: how many sobol points to skip, if any? */
     nlopt_sobol_skip(d.s, (unsigned) (10*n+d.N), p->x);

     memcpy(p->x, x, n * sizeof(double));
     p->f = f(n, x, NULL, f_data);
     stop->nevals++;
     if (!rb_tree_insert(&d.pts, (rb_key) p)) { 
	  free(p); ret = NLOPT_OUT_OF_MEMORY; 
     }
     if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
     else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
     else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
     else if (p->f < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED;

     while (ret == NLOPT_SUCCESS) {
	  rb_node *node;
	  double R;

	  get_minf(&d, minf, x);

	  /* sampling phase: add random/quasi-random points */
	  for (i = 0; i < d.N && ret == NLOPT_SUCCESS; ++i) {
	       p = alloc_pt(n);
	       if (!p) { ret = NLOPT_OUT_OF_MEMORY; goto done; }
	       if (d.s) nlopt_sobol_next(d.s, p->x, lb, ub);
	       else { /* use random points instead of LDS */
		    int j;
		    for (j = 0; j < n; ++j) p->x[j] = nlopt_urand(lb[j],ub[j]);
	       }
	       p->f = f(n, p->x, NULL, f_data);
	       stop->nevals++;
	       if (!rb_tree_insert(&d.pts, (rb_key) p)) { 
		    free(p); ret = NLOPT_OUT_OF_MEMORY;
	       }
	       if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
	       else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
	       else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
	       else if (p->f < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED;
	       else {
		    find_closest_pt(n, &d.pts, p);
		    find_closest_lm(n, &d.lms, p);
		    pts_update_newpt(n, &d.pts, p);
	       }
	  }

	  /* distance threshhold parameter R in MLSL */
	  R = d.R_prefactor 
	       * pow(log((double) d.pts.N) / d.pts.N, 1.0 / n);

	  /* local search phase: do local opt. for promising points */
	  node = rb_tree_min(&d.pts);
	  for (i = (int) (ceil(d.gamma * d.pts.N) + 0.5); 
	       node && i > 0 && ret == NLOPT_SUCCESS; --i) {
	       p = (pt *) node->k;
	       if (is_potential_minimizer(&d, p, 
					  R, d.dlm*R, d.dbound*R)) {
		    nlopt_result lret;
		    double *lm;
		    double t = nlopt_seconds();

		    if (nlopt_stop_forced(stop)) {
			 ret = NLOPT_FORCED_STOP; break;
		    }
		    if (nlopt_stop_evals(stop)) {
                         ret = NLOPT_MAXEVAL_REACHED; break;
		    }
		    if (stop->maxtime > 0 &&
			t - stop->start >= stop->maxtime) {
			 ret = NLOPT_MAXTIME_REACHED; break;
		    }
		    lm = (double *) malloc(sizeof(double) * (n+1));
		    if (!lm) { ret = NLOPT_OUT_OF_MEMORY; goto done; }
		    memcpy(lm+1, p->x, sizeof(double) * n);
		    lret = nlopt_optimize_limited(local_opt, lm+1, lm,
						  stop->maxeval - stop->nevals,
						  stop->maxtime -
						  (t - stop->start));
		    p->minimized = 1;
		    if (lret < 0) { free(lm); ret = lret; goto done; }
		    if (!rb_tree_insert(&d.lms, lm)) { 
			 free(lm); ret = NLOPT_OUT_OF_MEMORY;
		    }
		    else if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
		    else if (*lm < stop->minf_max) 
			 ret = NLOPT_MINF_MAX_REACHED;
		    else if (nlopt_stop_evals(stop))
			 ret = NLOPT_MAXEVAL_REACHED;
		    else if (nlopt_stop_time(stop))
			 ret = NLOPT_MAXTIME_REACHED;
		    else
			 pts_update_newlm(n, &d.pts, lm);
	       }

	       /* TODO: additional stopping criteria based
		  e.g. on improvement in function values, etc? */
	       
	       node = rb_tree_succ(node);
	  }
     }

     get_minf(&d, minf, x);

 done:
     nlopt_sobol_destroy(d.s);
     rb_tree_destroy_with_keys(&d.lms);
     rb_tree_destroy_with_keys(&d.pts);
     return ret;
}
Exemplo n.º 6
0
int main(int argc, char **argv)
{
    int N, M;
    int *k;
    double kd;
    rb_tree t;
    rb_node *n;
    int i, j;

    if (argc < 2) {
        fprintf(stderr, "Usage: redblack_test Ntest [rand seed]\n");
        return 1;
    }

    N = atoi(argv[1]);
    k = (int *) malloc(N * sizeof(int));
    rb_tree_init(&t, comp);

    srand((unsigned) (argc > 2 ? atoi(argv[2]) : time(NULL)));
    for (i = 0; i < N; ++i) {
        double *newk = (double *) malloc(sizeof(double));
        *newk = (k[i] = rand() % N);
        if (!rb_tree_insert(&t, newk)) {
            fprintf(stderr, "error in rb_tree_insert\n");
            return 1;
        }
        if (!rb_tree_check(&t)) {
            fprintf(stderr, "rb_tree_check_failed after insert!\n");
            return 1;
        }
    }

    if (t.N != N) {
        fprintf(stderr, "incorrect N (%d) in tree (vs. %d)\n", t.N, N);
        return 1;
    }

    for (i = 0; i < N; ++i) {
        kd = k[i];
        if (!rb_tree_find(&t, &kd)) {
            fprintf(stderr, "rb_tree_find lost %d!\n", k[i]);
            return 1;
        }
    }

    n = rb_tree_min(&t);
    for (i = 0; i < N; ++i) {
        if (!n) {
            fprintf(stderr, "not enough successors %d\n!", i);
            return 1;
        }
        printf("%d: %g\n", i, n->k[0]);
        n = rb_tree_succ(n);
    }
    if (n) {
        fprintf(stderr, "too many successors!\n");
        return 1;
    }

    n = rb_tree_max(&t);
    for (i = 0; i < N; ++i) {
        if (!n) {
            fprintf(stderr, "not enough predecessors %d\n!", i);
            return 1;
        }
        printf("%d: %g\n", i, n->k[0]);
        n = rb_tree_pred(n);
    }
    if (n) {
        fprintf(stderr, "too many predecessors!\n");
        return 1;
    }

    for (M = N; M > 0; --M) {
        int knew = rand() % N;  /* random new key */
        j = rand() % M;         /* random original key to replace */
        for (i = 0; i < N; ++i)
            if (k[i] >= 0)
                if (j-- == 0)
                    break;
        if (i >= N)
            abort();
        kd = k[i];
        if (!(n = rb_tree_find(&t, &kd))) {
            fprintf(stderr, "rb_tree_find lost %d!\n", k[i]);
            return 1;
        }
        n->k[0] = knew;
        if (!rb_tree_resort(&t, n)) {
            fprintf(stderr, "error in rb_tree_resort\n");
            return 1;
        }
        if (!rb_tree_check(&t)) {
            fprintf(stderr, "rb_tree_check_failed after change %d!\n", N - M + 1);
            return 1;
        }
        k[i] = -1 - knew;
    }

    if (t.N != N) {
        fprintf(stderr, "incorrect N (%d) in tree (vs. %d)\n", t.N, N);
        return 1;
    }

    for (i = 0; i < N; ++i)
        k[i] = -1 - k[i];       /* undo negation above */

    for (i = 0; i < N; ++i) {
        rb_node *le, *gt;
        double lek, gtk;
        kd = 0.01 * (rand() % (N * 150) - N * 25);
        le = rb_tree_find_le(&t, &kd);
        gt = rb_tree_find_gt(&t, &kd);
        n = rb_tree_min(&t);
        lek = le ? le->k[0] : -HUGE_VAL;
        gtk = gt ? gt->k[0] : +HUGE_VAL;
        printf("%g <= %g < %g\n", lek, kd, gtk);
        if (n->k[0] > kd) {
            if (le) {
                fprintf(stderr, "found invalid le %g for %g\n", lek, kd);
                return 1;
            }
            if (gt != n) {
                fprintf(stderr, "gt is not first node for k=%g\n", kd);
                return 1;
            }
        } else {
            rb_node *succ = n;
            do {
                n = succ;
                succ = rb_tree_succ(n);
            } while (succ && succ->k[0] <= kd);
            if (n != le) {
                fprintf(stderr, "rb_tree_find_le gave wrong result for k=%g\n", kd);
                return 1;
            }
            if (succ != gt) {
                fprintf(stderr, "rb_tree_find_gt gave wrong result for k=%g\n", kd);
                return 1;
            }
        }
    }

    for (M = N; M > 0; --M) {
        j = rand() % M;
        for (i = 0; i < N; ++i)
            if (k[i] >= 0)
                if (j-- == 0)
                    break;
        if (i >= N)
            abort();
        kd = k[i];
        if (!(n = rb_tree_find(&t, &kd))) {
            fprintf(stderr, "rb_tree_find lost %d!\n", k[i]);
            return 1;
        }
        n = rb_tree_remove(&t, n);
        free(n->k);
        free(n);
        if (!rb_tree_check(&t)) {
            fprintf(stderr, "rb_tree_check_failed after remove!\n");
            return 1;
        }
        k[i] = -1 - k[i];
    }

    if (t.N != 0) {
        fprintf(stderr, "nonzero N (%d) in tree at end\n", t.N);
        return 1;
    }

    rb_tree_destroy(&t);
    free(k);

    printf("SUCCESS.\n");
    return 0;
}