1 /* Copyright (c) 2010 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.
29 /* Improved Stochastic Ranking Evolution Strategy (ISRES) algorithm
30 for nonlinearly-constrained global optimization, based on
31 the method described in:
33 Thomas Philip Runarsson and Xin Yao, "Search biases in constrained
34 evolutionary optimization," IEEE Trans. on Systems, Man, and Cybernetics
35 Part C: Applications and Reviews, vol. 35 (no. 2), pp. 233-243 (2005).
37 It is a refinement of an earlier method described in:
39 Thomas P. Runarsson and Xin Yao, "Stochastic ranking for constrained
40 evolutionary optimization," IEEE Trans. Evolutionary Computation,
41 vol. 4 (no. 3), pp. 284-294 (2000).
43 This is an independent implementation by S. G. Johnson (2009) based
44 on the papers above. Runarsson also has his own Matlab implemention
45 available from his web page: http://www3.hi.is/~tpr
48 static int key_compare(void *keys_, const void *a_, const void *b_)
50 const double *keys = (const double *) keys_;
51 const int *a = (const int *) a_;
52 const int *b = (const int *) b_;
53 return keys[*a] < keys[*b] ? -1 : (keys[*a] > keys[*b] ? +1 : 0);
56 nlopt_result isres_minimize(int n, nlopt_func f, void *f_data,
57 int m, nlopt_constraint *fc, /* fc <= 0 */
58 int p, nlopt_constraint *h, /* h == 0 */
59 const double *lb, const double *ub, /* bounds */
60 double *x, /* in: initial guess, out: minimizer */
63 int population) /* pop. size (= 0 for default) */
65 const double ALPHA = 0.2; /* smoothing factor from paper */
66 const double GAMMA = 0.85; /* step-reduction factor from paper */
67 const double PHI = 1.0; /* expected rate of convergence, from paper */
68 const double PF = 0.45; /* fitness probability, from paper */
69 const double SURVIVOR = 1.0/7.0; /* survivor fraction, from paper */
71 nlopt_result ret = NLOPT_SUCCESS;
72 double *sigmas = 0, *xs; /* population-by-n arrays (row-major) */
73 double *fval; /* population array of function vals */
74 double *penalty; /* population array of penalty vals */
79 double minf_penalty = HUGE_VAL, minf_gpenalty = HUGE_VAL;
84 if (!population) population = 20 * (n + 1);
85 if (population < 1) return NLOPT_INVALID_ARGS;
86 survivors = ceil(population * SURVIVOR);
88 taup = PHI / sqrt(2*n);
89 tau = PHI / sqrt(2*sqrt(n));
91 /* we don't handle unbounded search regions */
92 for (j = 0; j < n; ++j) if (nlopt_isinf(lb[j]) || nlopt_isinf(ub[j]))
93 return NLOPT_INVALID_ARGS;
95 sigmas = (double*) malloc(sizeof(double) * (population*n*2
99 if (!sigmas) return NLOPT_OUT_OF_MEMORY;
100 xs = sigmas + population*n;
101 fval = xs + population*n;
102 penalty = fval + population;
103 x0 = penalty + population;
105 irank = (int*) malloc(sizeof(int) * population);
106 if (!irank) { ret = NLOPT_OUT_OF_MEMORY; goto done; }
108 for (k = 0; k < population; ++k) {
109 for (j = 0; j < n; ++j) {
110 sigmas[k*n+j] = (ub[j] - lb[j]) / sqrt(n);
111 xs[k*n+j] = nlopt_urand(lb[j], ub[j]);
114 memcpy(xs, x, sizeof(double) * n); /* use input x for xs_0 */
116 while (1) { /* each loop body = one generation */
117 int all_feasible = 1;
119 /* evaluate f and constraint violations for whole population */
120 for (k = 0; k < population; ++k) {
124 fval[k] = f(n, xs + k*n, NULL, f_data);
126 for (c = 0; c < m; ++c) { /* inequality constraints */
127 double gval = fc[c].f(n, xs + k*n, NULL, fc[c].f_data);
128 if (gval > fc[c].tol) feasible = 0;
129 if (gval < 0) gval = 0;
130 penalty[k] += gval*gval;
132 gpenalty = penalty[k];
133 for (c = m; c < mp; ++c) { /* equality constraints */
134 double hval = h[c-m].f(n, xs + k*n, NULL, h[c-m].f_data);
135 if (fabs(hval) > h[c-m].tol) feasible = 0;
136 penalty[k] += hval*hval;
138 if (penalty[k] > 0) all_feasible = 0;
140 /* convergence criteria (FIXME: improve?) */
142 /* FIXME: with equality constraints, how do
143 we decide which solution is the "best" so far?
144 ... need some total order on the solutions? */
146 if ((penalty[k] <= minf_penalty || feasible)
147 && (fval[k] <= *minf || minf_gpenalty > 0)
148 && ((feasible ? 0 : penalty[k]) != minf_penalty
149 || fval[k] != *minf)) {
150 if (fval[k] < stop->minf_max && feasible)
151 ret = NLOPT_MINF_MAX_REACHED;
152 else if (!nlopt_isinf(*minf)) {
153 if (nlopt_stop_f(stop, fval[k], *minf)
154 && nlopt_stop_f(stop, feasible ? 0 : penalty[k],
156 ret = NLOPT_FTOL_REACHED;
157 else if (nlopt_stop_x(stop, xs+k*n, x))
158 ret = NLOPT_XTOL_REACHED;
160 memcpy(x, xs+k*n, sizeof(double)*n);
162 minf_penalty = feasible ? 0 : penalty[k];
163 minf_gpenalty = feasible ? 0 : gpenalty;
164 if (ret != NLOPT_SUCCESS) goto done;
167 if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
168 else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
169 if (ret != NLOPT_SUCCESS) goto done;
172 /* "selection" step: rank the population */
173 for (k = 0; k < population; ++k) irank[k] = k;
174 if (all_feasible) /* special case: rank by objective function */
175 nlopt_qsort_r(irank, population, sizeof(int), fval,key_compare);
177 /* Runarsson & Yao's stochastic ranking of the population */
178 for (i = 0; i < population; ++i) {
180 for (j = 0; j < population-1; ++j) {
181 double u = nlopt_urand(0,1);
182 if (u < PF || (penalty[irank[j]] == 0
183 && penalty[irank[j+1]] == 0)) {
184 if (fval[irank[j]] > fval[irank[j+1]]) {
185 int irankj = irank[j];
186 irank[j] = irank[j+1];
191 else if (penalty[irank[j]] > penalty[irank[j+1]]) {
192 int irankj = irank[j];
193 irank[j] = irank[j+1];
202 /* evolve the population:
203 differential evolution for the best survivors,
204 and standard mutation of the best survivors for the rest: */
205 for (k = survivors; k < population; ++k) { /* standard mutation */
206 double taup_rand = taup * nlopt_nrand(0,1);
207 int rk = irank[k], ri;
210 for (j = 0; j < n; ++j) {
211 double sigmamax = (ub[j] - lb[j]) / sqrt(n);
212 sigmas[rk*n+j] = sigmas[ri*n+j]
213 * exp(taup_rand + tau*nlopt_nrand(0,1));
214 if (sigmas[rk*n+j] > sigmamax)
215 sigmas[rk*n+j] = sigmamax;
217 xs[rk*n+j] = xs[ri*n+j]
218 + sigmas[rk*n+j] * nlopt_nrand(0,1);
219 } while (xs[rk*n+j] < lb[j] || xs[rk*n+j] > ub[j]);
220 sigmas[rk*n+j] = sigmas[ri*n+j] + ALPHA*(sigmas[rk*n+j]
224 memcpy(x0, xs, n * sizeof(double));
225 for (k = 0; k < survivors; ++k) { /* differential variation */
226 double taup_rand = taup * nlopt_nrand(0,1);
228 for (j = 0; j < n; ++j) {
229 double xi = xs[rk*n+j];
231 xs[rk*n+j] += GAMMA * (x0[j] - xs[(k+1)*n+j]);
233 || xs[rk*n+j] < lb[j] || xs[rk*n+j] > ub[j]) {
234 /* standard mutation for last survivor and
235 for any survivor components that are now
236 outside the bounds */
237 double sigmamax = (ub[j] - lb[j]) / sqrt(n);
238 double sigi = sigmas[rk*n+j];
239 sigmas[rk*n+j] *= exp(taup_rand
240 + tau*nlopt_nrand(0,1));
241 if (sigmas[rk*n+j] > sigmamax)
242 sigmas[rk*n+j] = sigmamax;
245 + sigmas[rk*n+j] * nlopt_nrand(0,1);
246 } while (xs[rk*n+j] < lb[j] || xs[rk*n+j] > ub[j]);
247 sigmas[rk*n+j] = sigi
248 + ALPHA * (sigmas[rk*n+j] - sigi);
255 if (irank) free(irank);
256 if (sigmas) free(sigmas);