5 #include "nlopt-util.h"
11 #define MIN(a,b) ((a) < (b) ? (a) : (b))
12 #define MAX(a,b) ((a) > (b) ? (a) : (b))
14 /***************************************************************************/
15 /* basic data structure:
17 * a hyper-rectangle is stored as an array of length L = 2n+2, where [0]
18 * is the value (f) of the function at the center, [1] is the "size"
19 * measure (d) of the rectangle, [2..n+1] are the coordinates of the
20 * center (c), and [n+2..2n+1] are the widths of the sides (w).
22 * a list of rectangles is just an array of N hyper-rectangles
23 * stored as an N x L in row-major order. Generally,
24 * we allocate more than we need, allocating Na hyper-rectangles.
29 #define RECT_LEN(n) (2*(n)+2) /* number of double values in a hyperrect */
31 /* parameters of the search algorithm and various information that
32 needs to be passed around */
34 int n; /* dimension */
35 int L; /* RECT_LEN(n) */
36 double *rects; /* the hyper-rectangles */
37 double magic_eps; /* Jones' epsilon parameter (1e-4 is recommended) */
38 int which_diam; /* which measure of hyper-rectangle diam to use:
39 0 = Jones, 1 = Gablonsky */
40 int which_div; /* which way to divide rects:
41 0: Gablonsky (cubes divide all, rects longest)
42 1: orig. Jones (divide all longest sides)
43 2: Jones Encyc. Opt.: pick random longest side */
44 const double *lb, *ub;
45 nlopt_stopping *stop; /* stopping criteria */
46 nlopt_func f; void *f_data;
47 double *work; /* workspace, of length >= 2*n */
48 int *iwork, iwork_len; /* workspace, of length iwork_len >= n */
49 double fmin, *xmin; /* minimum so far */
51 /* red-black tree of hyperrect indices, sorted by (d,f) in
52 lexographical order */
56 /***************************************************************************/
58 /* evaluate the "diameter" (d) of a rectangle of widths w[n] */
59 static double rect_diameter(int n, const double *w, const params *p)
62 if (p->which_diam == 0) { /* Jones measure */
64 for (i = 0; i < n; ++i)
66 return sqrt(sum) * 0.5; /* distance from center to a vertex */
68 else { /* Gablonsky measure */
70 for (i = 0; i < n; ++i)
73 return maxw * 0.5; /* half-width of longest side */
77 static double *alloc_rects(int n, int *Na, double *rects, int newN)
83 return realloc(rects, sizeof(double) * RECT_LEN(n) * (*Na));
86 #define ALLOC_RECTS(n, Nap, rects, newN) if (!(rects = alloc_rects(n, Nap, rects, newN))) return NLOPT_OUT_OF_MEMORY
88 static double *fv_qsort = 0;
89 static int sort_fv_compare(const void *a_, const void *b_)
91 int a = *((const int *) a_), b = *((const int *) b_);
92 double fa = MIN(fv_qsort[2*a], fv_qsort[2*a+1]);
93 double fb = MIN(fv_qsort[2*b], fv_qsort[2*b+1]);
101 static void sort_fv(int n, double *fv, int *isort)
104 for (i = 0; i < n; ++i) isort[i] = i;
105 fv_qsort = fv; /* not re-entrant, sigh... */
106 qsort(isort, (unsigned) n, sizeof(int), sort_fv_compare);
110 static double function_eval(const double *x, params *p) {
111 double f = p->f(p->n, x, NULL, p->f_data);
114 memcpy(p->xmin, x, sizeof(double) * p->n);
119 #define FUNCTION_EVAL(fv,x,p) fv = function_eval(x, p); if (p->fmin < p->stop->fmin_max) return NLOPT_FMIN_MAX_REACHED; else if (nlopt_stop_evals((p)->stop)) return NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time((p)->stop)) return NLOPT_MAXTIME_REACHED
121 #define THIRD (0.3333333333333333333333)
123 #define EQUAL_SIDE_TOL 5e-2 /* tolerance to equate side sizes */
125 /* divide rectangle idiv in the list p->rects */
126 static nlopt_result divide_rect(int *N, int *Na, int idiv, params *p)
129 const const int n = p->n;
131 double *r = p->rects;
132 double *c = r + L*idiv + 2; /* center of rect to divide */
133 double *w = c + n; /* widths of rect to divide */
135 int imax = 0, nlongest = 0;
138 for (i = 1; i < n; ++i)
141 for (i = 0; i < n; ++i)
142 if (wmax - w[i] <= wmax * EQUAL_SIDE_TOL)
144 if (p->which_div == 1 || (p->which_div == 0 && nlongest == n)) {
145 /* trisect all longest sides, in increasing order of the average
146 function value along that direction */
147 double *fv = p->work;
148 int *isort = p->iwork;
149 for (i = 0; i < n; ++i) {
150 if (wmax - w[i] <= wmax * EQUAL_SIDE_TOL) {
152 c[i] = csave - w[i] * THIRD;
153 FUNCTION_EVAL(fv[2*i], c, p);
154 c[i] = csave + w[i] * THIRD;
155 FUNCTION_EVAL(fv[2*i+1], c, p);
159 fv[2*i] = fv[2*i+1] = HUGE_VAL;
162 sort_fv(n, fv, isort);
163 ALLOC_RECTS(n, Na, r, (*N)+2*nlongest);
164 p->rects = r; c = r + L*idiv + 2; w = c + n;
165 for (i = 0; i < nlongest; ++i) {
167 if (!(node = rb_tree_find(&p->rtree, idiv)))
168 return NLOPT_FAILURE;
169 w[isort[i]] *= THIRD;
170 r[L*idiv + 1] = rect_diameter(n, w, p);
171 rb_tree_resort(&p->rtree, node);
172 for (k = 0; k <= 1; ++k) {
173 memcpy(r + L*(*N) + 1, c-1, sizeof(double) * (2*n+1));
174 r[L*(*N) + 2 + isort[i]] += w[isort[i]] * (2*k-1);
175 r[L*(*N)] = fv[2*isort[i]+k];
176 if (!rb_tree_insert(&p->rtree, *N))
177 return NLOPT_FAILURE;
184 if (nlongest > 1 && p->which_div == 2) {
185 /* randomly choose longest side */
186 i = nlopt_iurand(nlongest);
187 for (k = 0; k < n; ++k)
188 if (wmax - w[k] <= wmax * EQUAL_SIDE_TOL) {
189 if (!i) { i = k; break; }
194 i = imax; /* trisect longest side */
195 ALLOC_RECTS(n, Na, r, (*N)+2);
196 p->rects = r; c = r + L*idiv + 2; w = c + n;
197 if (!(node = rb_tree_find(&p->rtree, idiv)))
198 return NLOPT_FAILURE;
200 r[L*idiv + 1] = rect_diameter(n, w, p);
201 rb_tree_resort(&p->rtree, node);
202 for (k = 0; k <= 1; ++k) {
203 memcpy(r + L*(*N) + 1, c-1, sizeof(double) * (2*n+1));
204 r[L*(*N) + 2 + i] += w[i] * (2*k-1);
205 FUNCTION_EVAL(r[L*(*N)], r + L*(*N) + 2, p);
206 if (!rb_tree_insert(&p->rtree, *N))
207 return NLOPT_FAILURE;
211 return NLOPT_SUCCESS;
214 /***************************************************************************/
215 /* O(N log N) convex hull algorithm, used later to find the potentially
218 /* Find the lower convex hull of a set of points (xy[s*i+1], xy[s*i]), where
219 0 <= i < N and s >= 2.
221 The return value is the number of points in the hull, with indices
222 stored in ihull. ihull should point to arrays of length >= N.
223 rb_tree should be a red-black tree of indices (keys == i) sorted
224 in lexographic order by (xy[s*i+1], xy[s*i]).
226 static int convex_hull(int N, double *xy, int s, int *ihull, rb_tree *t)
230 double xmin, xmax, yminmin, ymaxmin;
233 if (N == 0) return 0;
235 /* Monotone chain algorithm [Andrew, 1979]. */
238 nmax = rb_tree_max(t);
240 xmin = xy[s*(n->k)+1];
241 yminmin = xy[s*(n->k)];
242 xmax = xy[s*(nmax->k)+1];
244 ihull[nhull = 1] = n->k;
245 if (xmin == xmax) return nhull;
247 /* set nmax = min mode with x == xmax */
248 while (xy[s*(nmax->k)+1] == xmax)
249 nmax = rb_tree_pred(t, nmax); /* non-NULL since xmin != xmax */
250 nmax = rb_tree_succ(t, nmax);
252 ymaxmin = xy[s*(nmax->k)];
253 minslope = (ymaxmin - yminmin) / (xmax - xmin);
255 /* set n = first node with x != xmin */
256 while (xy[s*(n->k)+1] == xmin)
257 n = rb_tree_succ(t, n); /* non-NULL since xmin != xmax */
259 for (; n != nmax; n = rb_tree_succ(t, n)) {
261 if (xy[s*k] > yminmin + (xy[s*k+1] - xmin) * minslope)
263 /* remove points until we are making a "left turn" to k */
265 int t1 = ihull[nhull - 1], t2 = ihull[nhull - 2];
266 /* cross product (t1-t2) x (k-t2) > 0 for a left turn: */
267 if ((xy[s*t1+1]-xy[s*t2+1]) * (xy[s*k]-xy[s*t2])
268 - (xy[s*t1]-xy[s*t2]) * (xy[s*k+1]-xy[s*t2+1]) > 0)
274 ihull[nhull++] = nmax->k;
278 /***************************************************************************/
280 static int small(double *w, params *p)
283 for (i = 0; i < p->n; ++i)
284 if (w[i] > p->stop->xtol_abs[i] &&
285 w[i] > (p->ub[i] - p->lb[i]) * p->stop->xtol_rel)
290 static nlopt_result divide_good_rects(int *N, int *Na, params *p)
294 int *ihull, nhull, i, xtol_reached = 1, divided_some = 0;
295 double *r = p->rects;
296 double magic_eps = p->magic_eps;
298 if (p->iwork_len < *N) {
299 p->iwork_len = p->iwork_len + *N;
300 p->iwork = (int *) realloc(p->iwork, sizeof(int) * p->iwork_len);
302 return NLOPT_OUT_OF_MEMORY;
305 nhull = convex_hull(*N, r, L, ihull, &p->rtree);
307 for (i = 0; i < nhull; ++i) {
308 double K1 = -HUGE_VAL, K2 = -HUGE_VAL, K;
310 K1 = (r[L*ihull[i]] - r[L*ihull[i-1]]) /
311 (r[L*ihull[i]+1] - r[L*ihull[i-1]+1]);
313 K1 = (r[L*ihull[i]] - r[L*ihull[i+1]]) /
314 (r[L*ihull[i]+1] - r[L*ihull[i+1]+1]);
316 if (r[L*ihull[i]] - K * r[L*ihull[i]+1]
317 <= p->fmin - magic_eps * fabs(p->fmin)) {
318 /* "potentially optimal" rectangle, so subdivide */
321 ret = divide_rect(N, Na, ihull[i], p);
322 r = p->rects; /* may have grown */
323 if (ret != NLOPT_SUCCESS) return ret;
324 xtol_reached = xtol_reached && small(r + L*ihull[i] + 2+n, p);
328 if (magic_eps != 0) {
330 goto divisions; /* try again */
332 else { /* WTF? divide largest rectangle */
335 for (i = 1; i < *N; ++i)
337 wmax = r[L*(imax=i)+1];
338 return divide_rect(N, Na, imax, p);
341 return xtol_reached ? NLOPT_XTOL_REACHED : NLOPT_SUCCESS;
344 /***************************************************************************/
346 /* lexographic sort order (d,f) of hyper-rects, for red-black tree */
347 static int hyperrect_compare(int i, int j, void *p_)
349 params *p = (params *) p_;
351 double *r = p->rects;
352 double di = r[i*L+1], dj = r[j*L+1], fi, fj;
353 if (di < dj) return -1;
354 if (dj < di) return +1;
355 fi = r[i*L]; fj = r[j*L];
356 if (fi < fj) return -1;
357 if (fj < fi) return +1;
361 /***************************************************************************/
363 nlopt_result cdirect_unscaled(int n, nlopt_func f, void *f_data,
364 const double *lb, const double *ub,
367 nlopt_stopping *stop,
368 double magic_eps, int which_alg)
371 int Na = 100, N = 1, i, x_center = 1;
372 nlopt_result ret = NLOPT_OUT_OF_MEMORY;
374 p.magic_eps = magic_eps;
375 p.which_diam = which_alg % 2;
377 p.lb = lb; p.ub = ub;
384 p.fmin = f(n, x, NULL, f_data); stop->nevals++;
389 if (!rb_tree_init(&p.rtree, hyperrect_compare, &p)) goto done;
390 p.work = (double *) malloc(sizeof(double) * 2*n);
391 if (!p.work) goto done;
392 p.rects = (double *) malloc(sizeof(double) * Na * RECT_LEN(n));
393 if (!p.rects) goto done;
394 p.iwork = (int *) malloc(sizeof(int) * (p.iwork_len = Na + n));
395 if (!p.iwork) goto done;
397 for (i = 0; i < n; ++i) {
398 p.rects[2+i] = 0.5 * (lb[i] + ub[i]);
400 && (fabs(p.rects[2+i]-x[i]) < 1e-13*(1+fabs(x[i])));
401 p.rects[2+n+i] = ub[i] - lb[i];
403 p.rects[1] = rect_diameter(n, p.rects+2+n, &p);
405 p.rects[0] = p.fmin; /* avoid computing f(center) twice */
407 p.rects[0] = function_eval(p.rects+2, &p);
408 if (!rb_tree_insert(&p.rtree, 0)) {
413 ret = divide_rect(&N, &Na, 0, &p);
414 if (ret != NLOPT_SUCCESS) goto done;
417 double fmin0 = p.fmin;
418 ret = divide_good_rects(&N, &Na, &p);
419 if (ret != NLOPT_SUCCESS) goto done;
420 if (nlopt_stop_f(p.stop, p.fmin, fmin0)) {
421 ret = NLOPT_FTOL_REACHED;
427 rb_tree_destroy(&p.rtree);
436 /* in the conventional DIRECT-type algorithm, we first rescale our
437 coordinates to a unit hypercube ... we do this simply by
438 wrapping cdirect() around cdirect_unscaled(). */
444 const double *lb, *ub;
446 static double uf(int n, const double *xu, double *grad, void *d_)
448 uf_data *d = (uf_data *) d_;
451 for (i = 0; i < n; ++i)
452 d->x[i] = d->lb[i] + xu[i] * (d->ub[i] - d->lb[i]);
453 f = d->f(n, d->x, grad, d->f_data);
455 for (i = 0; i < n; ++i)
456 grad[i] *= d->ub[i] - d->lb[i];
460 nlopt_result cdirect(int n, nlopt_func f, void *f_data,
461 const double *lb, const double *ub,
464 nlopt_stopping *stop,
465 double magic_eps, int which_alg)
469 const double *xtol_abs_save;
472 d.f = f; d.f_data = f_data; d.lb = lb; d.ub = ub;
473 d.x = (double *) malloc(sizeof(double) * n*4);
474 if (!d.x) return NLOPT_OUT_OF_MEMORY;
476 for (i = 0; i < n; ++i) {
477 x[i] = (x[i] - lb[i]) / (ub[i] - lb[i]);
480 d.x[3*n+i] = stop->xtol_abs[i] / (ub[i] - lb[i]);
482 xtol_abs_save = stop->xtol_abs;
483 stop->xtol_abs = d.x + 3*n;
484 ret = cdirect_unscaled(n, uf, &d, d.x+n, d.x+2*n, x, fmin, stop,
485 magic_eps, which_alg);
486 stop->xtol_abs = xtol_abs_save;
487 for (i = 0; i < n; ++i)
488 x[i] = lb[i]+ x[i] * (ub[i] - lb[i]);