1 /* Copyright (c) 2007-2008 Massachusetts Institute of Technology
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "neldermead.h"
30 /* Nelder-Mead simplex algorithm, used as a subroutine for the Rowan's
31 subplex algorithm. Modified to handle bound constraints ala
32 Richardson and Kuester (1973), as mentioned below. */
34 /* heuristic "strategy" constants: */
35 static const double alpha = 1, beta = 0.5, gamm = 2, delta = 0.5;
37 /* sort order in red-black tree: keys [f(x), x] are sorted by f(x) */
38 static int simplex_compare(double *k1, double *k2)
40 if (*k1 < *k2) return -1;
41 if (*k1 > *k2) return +1;
42 return k1 - k2; /* tie-breaker */
45 /* pin x to lie within the given lower and upper bounds; this is
46 probably a suboptimal way to handle bound constraints, but I don't
47 know a better way and it is the method suggested by J. A. Richardson
48 and J. L. Kuester, "The complex method for constrained optimization,"
49 Commun. ACM 16(8), 487-489 (1973). */
50 static void pin(int n, double *x, const double *lb, const double *ub) {
52 for (i = 0; i < n; ++i) {
53 if (x[i] < lb[i]) x[i] = lb[i];
54 else if (x[i] > ub[i]) x[i] = ub[i];
59 #define CHECK_EVAL(xc,fc) \
60 if ((fc) <= *minf) { \
61 *minf = (fc); memcpy(x, (xc), n * sizeof(double)); \
62 if (*minf < stop->minf_max) { ret=NLOPT_MINF_MAX_REACHED; goto done; } \
65 if (nlopt_stop_evals(stop)) { ret=NLOPT_MAXEVAL_REACHED; goto done; } \
66 if (nlopt_stop_time(stop)) { ret=NLOPT_MAXTIME_REACHED; goto done; }
68 /* if psi > 0, then it *replaces* xtol and ftol in stop with the condition
69 that the simplex diameter |xl - xh| must be reduced by a factor of psi
70 ... this is for when nldrmd is used within the subplex method; for
71 ordinary termination tests, set psi = 0. */
72 nlopt_result nldrmd_minimize(int n, nlopt_func f, void *f_data,
73 const double *lb, const double *ub, /* bounds */
74 double *x, /* in: initial guess, out: minimizer */
76 const double *xstep, /* initial step sizes */
80 double *pts; /* (n+1) x (n+1) array of n+1 points plus function val [0] */
81 double *c; /* centroid * n */
82 double *xcur; /* current point */
83 rb_tree t; /* red-black tree of simplex, sorted by f(x) */
85 double ninv = 1.0 / n;
86 nlopt_result ret = NLOPT_SUCCESS;
89 pts = (double*) malloc(sizeof(double) * (n+1) * (n+1));
90 if (!pts) return NLOPT_OUT_OF_MEMORY;
91 c = (double*) malloc(sizeof(double) * n * 2);
92 if (!c) { free(pts); return NLOPT_OUT_OF_MEMORY; }
95 /* initialize the simplex based on the starting xstep */
96 memcpy(pts+1, x, sizeof(double)*n);
97 *minf = pts[0] = f(n, pts+1, NULL, f_data);
98 CHECK_EVAL(pts+1, pts[0]);
99 for (i = 0; i < n; ++i) {
100 double *pt = pts + (i+1)*(n+1);
101 memcpy(pt+1, x, sizeof(double)*n);
102 if (x[i] + xstep[i] <= ub[i])
104 else if (x[i] - xstep[i] >= lb[i])
106 else if (ub[i] - x[i] > x[i] - lb[i])
107 pt[1+i] += 0.5 * (ub[i] - x[i]);
109 pt[1+i] -= 0.5 * (x[i] - lb[i]);
110 pt[0] = f(n, pt+1, NULL, f_data);
111 CHECK_EVAL(pt+1, pt[0]);
114 rb_tree_init(&t, simplex_compare);
116 for (i = 0; i < n + 1; ++i)
117 if (!rb_tree_insert(&t, pts + i*(n+1))) {
118 ret = NLOPT_OUT_OF_MEMORY;
123 rb_node *low = rb_tree_min(&t);
124 rb_node *high = rb_tree_max(&t);
125 double fl = low->k[0], *xl = low->k + 1;
126 double fh = high->k[0], *xh = high->k + 1;
129 if (init_diam == 0) /* initialize diam. for psi convergence test */
130 for (i = 0; i < n; ++i) init_diam = fabs(xl[i] - xh[i]);
132 if (psi <= 0 && nlopt_stop_f(stop, fl, fh)) {
133 ret = NLOPT_FTOL_REACHED;
137 /* compute centroid ... if we cared about the perfomance of this,
138 we could do it iteratively by updating the centroid on
139 each step, but then we would have to be more careful about
140 accumulation of rounding errors... anyway n is unlikely to
141 be very large for Nelder-Mead in practical cases */
142 memset(c, 0, sizeof(double)*n);
143 for (i = 0; i < n + 1; ++i) {
144 double *xi = pts + i*(n+1) + 1;
146 for (j = 0; j < n; ++j)
149 for (i = 0; i < n; ++i) c[i] *= ninv;
151 /* x convergence check: find xcur = max radius from centroid */
152 memset(xcur, 0, sizeof(double)*n);
153 for (i = 0; i < n + 1; ++i) {
154 double *xi = pts + i*(n+1) + 1;
155 for (j = 0; j < n; ++j) {
156 double dx = fabs(xi[j] - c[j]);
157 if (dx > xcur[j]) xcur[j] = dx;
160 for (i = 0; i < n; ++i) xcur[i] += c[i];
163 for (i = 0; i < n; ++i) diam += fabs(xl[i] - xh[i]);
164 if (diam < psi * init_diam) {
165 ret = NLOPT_XTOL_REACHED;
169 else if (nlopt_stop_x(stop, c, xcur)) {
170 ret = NLOPT_XTOL_REACHED;
175 for (i = 0; i < n; ++i) xcur[i] = c[i] + alpha * (c[i] - xh[i]);
176 pin(n, xcur, lb, ub);
177 fr = f(n, xcur, NULL, f_data);
178 CHECK_EVAL(xcur, fr);
180 if (fr < fl) { /* new best point, expand simplex */
181 for (i = 0; i < n; ++i) xh[i] = c[i] + gamm * (c[i] - xh[i]);
183 fh = f(n, xh, NULL, f_data);
185 if (fh >= fr) { /* expanding didn't improve */
187 memcpy(xh, xcur, sizeof(double)*n);
190 else if (fr < rb_tree_pred(high)->k[0]) { /* accept new point */
191 memcpy(xh, xcur, sizeof(double)*n);
194 else { /* new worst point, contract */
197 for (i = 0; i < n; ++i) xcur[i] = c[i] - beta*(c[i]-xh[i]);
199 for (i = 0; i < n; ++i) xcur[i] = c[i] + beta*(c[i]-xh[i]);
200 pin(n, xcur, lb, ub);
201 fc = f(n, xcur, NULL, f_data);
202 CHECK_EVAL(xcur, fc);
203 if (fc < fr && fc < fh) { /* successful contraction */
204 memcpy(xh, xcur, sizeof(double)*n);
207 else { /* failed contraction, shrink simplex */
209 rb_tree_init(&t, simplex_compare);
210 for (i = 0; i < n+1; ++i) {
211 double *pt = pts + i * (n+1);
213 for (j = 0; j < n; ++j)
214 pt[1+j] = xl[j] + delta * (pt[1+j] - xl[j]);
215 pt[0] = f(n, pt+1, NULL, f_data);
216 CHECK_EVAL(pt+1, pt[0]);
224 rb_tree_resort(&t, high);