8 int mma_verbose = 0; /* > 0 for verbose output */
10 #define MIN(a,b) ((a) < (b) ? (a) : (b))
11 #define MAX(a,b) ((a) > (b) ? (a) : (b))
13 /* magic minimum value for rho in MMA ... the 2002 paper says it should
14 be a "fixed, strictly positive `small' number, e.g. 1e-5"
15 ... grrr, I hate these magic numbers, which seem like they
16 should depend on the objective function in some way ... in particular,
17 note that rho is dimensionful (= dimensions of objective function) */
18 #define MMA_RHOMIN 1e-5
20 /***********************************************************************/
21 /* function for MMA's dual optimization of the approximant function */
24 int n; /* must be set on input to dimension of x */
25 const double *x, *lb, *ub, *sigma, *dfdx; /* arrays of length n */
26 const double *dfcdx; /* m-by-n array of fc gradients */
27 double fval, rho; /* must be set on input */
28 const double *fcval, *rhoc; /* arrays of length m */
29 double *xcur; /* array of length n, output each time */
30 double gval, wval, *gcval; /* output each time (array length m) */
33 static double dual_func(int m, const double *y, double *grad, void *d_)
35 dual_data *d = (dual_data *) d_;
37 const double *x = d->x, *lb = d->lb, *ub = d->ub, *sigma = d->sigma,
39 const double *dfcdx = d->dfcdx;
40 double rho = d->rho, fval = d->fval;
41 const double *rhoc = d->rhoc, *fcval = d->fcval;
42 double *xcur = d->xcur;
43 double *gcval = d->gcval;
49 for (i = 0; i < m; ++i) val += y[i] * (gcval[i] = fcval[i]);
50 if (grad) { for (i = 0; i < m; ++i) grad[i] = fcval[i]; }
52 for (j = 0; j < n; ++j) {
54 double a, b, dx, denom, denominv, ca, cb, sigma2;
56 /* first, compute xcur[j] for y */
58 b = fabs(dfdx[j]) * sigma[j] + 0.5 * rho;
59 for (i = 0; i < m; ++i) {
60 a += dfcdx[i*n + j] * y[i];
61 b += (fabs(dfcdx[i*n + j]) * sigma[j] + 0.5 * rhoc[i]) * y[i];
63 sigma2 = sigma[j] * sigma[j];
66 if (xcur[j] > ub[j]) xcur[j] = ub[j];
67 if (xcur[j] < lb[j]) xcur[j] = lb[j];
68 if (xcur[j] > x[j] + 0.9*sigma[j]) xcur[j] = x[j] + 0.9*sigma[j];
69 if (xcur[j] < x[j] - 0.9*sigma[j]) xcur[j] = x[j] - 0.9*sigma[j];
70 x_pinned = xcur[j] != x[j] + dx;
74 denom = sigma2 - dx*dx;
75 denominv = 1.0 / denom;
78 val += (a*ca + b*cb) * denominv;
80 /* update gval, wval, gcval */
81 d->gval += (dfdx[j] * ca + (fabs(dfdx[j])*sigma[j] + 0.5*rho) * cb)
83 d->wval += 0.5 * cb * denominv;
84 for (i = 0; i < m; ++i)
85 gcval[i] += (dfcdx[i*n+j] * ca
86 + (fabs(dfcdx[i*n+j])*sigma[j] + 0.5*rhoc[j]) * cb)
91 for (i = 0; i < m; ++i) {
93 dady = dfcdx[i*n + j];
94 dbdy = fabs(dfcdx[i*n + j]) * sigma[j] + 0.5 * rhoc[i];
95 grad[i] += (dady*ca + dbdy*cb) * denominv;
96 if (!x_pinned) { /* dx/dy nonzero */
99 dxdy = (a*dbdy - dady*b) * (sigma2 / (b*b));
101 ((sigma2 * dfdx[j] + 2 * (fabs(dfdx[j])*sigma[j]
104 + 2*dx * (dfdx[j]*ca + (fabs(dfdx[j])*sigma[j]
106 * (denominv*denominv * dxdy);
107 for (k = 0; k < m; ++k)
109 ((sigma2 * dfcdx[k*n + j]
110 + 2 * (fabs(dfcdx[k*n + j])*sigma[j]
113 + 2*dx * (dfcdx[k*n + j]*ca
114 + (fabs(dfcdx[k*n + j])*sigma[j]
115 + 0.5*rhoc[k]) * cb))
116 * (denominv*denominv * dxdy) * y[k];
121 /* negate because we are maximizing */
122 if (grad) { for (i = 0; i < m; ++i) grad[i] = -grad[i]; }
126 /***********************************************************************/
128 nlopt_result mma_minimize(int n, nlopt_func f, void *f_data,
129 int m, nlopt_func fc,
130 void *fc_data_, ptrdiff_t fc_data_size,
131 const double *lb, const double *ub, /* bounds */
132 double *x, /* in: initial guess, out: minimizer */
134 nlopt_stopping *stop,
135 nlopt_algorithm dual_alg,
136 double dual_tolrel, int dual_maxeval)
138 nlopt_result ret = NLOPT_SUCCESS;
139 double *xcur, rho, *sigma, *dfdx, *dfdx_cur, *xprev, *xprevprev, fcur;
140 double *dfcdx, *dfcdx_cur, *fcval, *rhoc, *gcval, *y, *dual_lb, *dual_ub;
142 char *fc_data = (char *) fc_data_;
146 sigma = (double *) malloc(sizeof(double) * (6*n + 2*m*n + m*6));
147 if (!sigma) return NLOPT_OUT_OF_MEMORY;
152 xprevprev = xprev + n;
153 fcval = xprevprev + n;
157 dual_ub = dual_lb + m;
160 dfcdx_cur = dfcdx + m*n;
174 for (j = 0; j < n; ++j) {
175 if (nlopt_isinf(ub[j]) || nlopt_isinf(lb[j]))
176 sigma[j] = 1.0; /* arbitrary default */
178 sigma[j] = 0.5 * (ub[j] - lb[j]);
181 for (i = 0; i < m; ++i) {
183 dual_lb[i] = y[i] = 0.0;
184 dual_ub[i] = HUGE_VAL;
187 dd.fval = fcur = *minf = f(n, x, dfdx, f_data);
190 for (i = 0; i < m; ++i) {
191 fcval[i] = fc(n, x, dfcdx + i*n, fc_data + fc_data_size * i);
192 feasible = feasible && (fcval[i] <= 0);
194 memcpy(xcur, x, sizeof(double) * n);
196 if (!feasible) { ret = NLOPT_FAILURE; goto done; } /* TODO: handle this */
198 while (1) { /* outer iterations */
200 if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
201 else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
202 else if (*minf < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED;
203 if (ret != NLOPT_SUCCESS) goto done;
204 if (++k > 1) memcpy(xprevprev, xprev, sizeof(double) * n);
205 memcpy(xprev, xcur, sizeof(double) * n);
207 while (1) { /* inner iterations */
209 int feasible_cur, inner_done;
211 /* solve dual problem */
213 nlopt_minimize(dual_alg, m, dual_func, &dd,
214 dual_lb, dual_ub, y, &min_dual,
215 -HUGE_VAL, dual_tolrel, 0, 0, NULL, dual_maxeval,
216 stop->maxtime - (nlopt_seconds() - stop->start));
217 dual_func(m, y, NULL, &dd); /* evaluate final xcur etc. */
219 fcur = f(n, xcur, dfdx_cur, f_data);
221 inner_done = dd.gval >= fcur;
223 for (i = 0; i < m; ++i) {
224 fcval_cur[i] = fc(n, xcur, dfcdx_cur + i*n,
225 fc_data + fc_data_size * i);
226 feasible_cur = feasible_cur && (fcval_cur[i] <= 0);
227 inner_done = inner_done && (dd.gcval[i] >= fcval_cur[i]);
230 if (fcur < *minf && (feasible_cur || !feasible)) {
231 feasible = feasible_cur;
232 dd.fval = *minf = fcur;
233 memcpy(fcval, fcval_cur, sizeof(double)*m);
234 memcpy(x, xcur, sizeof(double)*n);
235 memcpy(dfdx, dfdx_cur, sizeof(double)*n);
236 memcpy(dfcdx, dfcdx_cur, sizeof(double)*n*m);
238 if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
239 else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
240 else if (*minf < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED;
241 if (ret != NLOPT_SUCCESS) goto done;
243 if (inner_done) break;
246 rho = MIN(10*rho, 1.1 * (rho + (fcur-dd.gval) / dd.wval));
247 for (i = 0; i < m; ++i)
248 if (fcval_cur[i] > dd.gcval[i])
251 1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i])
255 printf("MMA inner iteration: rho -> %g\n", rho);
258 if (nlopt_stop_ftol(stop, fcur, fprev))
259 ret = NLOPT_FTOL_REACHED;
260 if (nlopt_stop_x(stop, xcur, xprev))
261 ret = NLOPT_XTOL_REACHED;
262 if (ret != NLOPT_SUCCESS) goto done;
264 /* update rho and sigma for iteration k+1 */
265 rho = MAX(0.1 * rho, MMA_RHOMIN);
267 printf("MMA outer iteration: rho -> %g\n", rho);
268 for (i = 0; i < m; ++i)
269 rhoc[i] = MAX(0.1 * rhoc[i], MMA_RHOMIN);
271 for (j = 0; j < n; ++j) {
272 double dx2 = (xcur[j]-xprev[j]) * (xprev[j]-xprevprev[j]);
273 double gam = dx2 < 0 ? 0.7 : (dx2 > 0 ? 1.2 : 1);
275 sigma[j] = MIN(sigma[j], 10*(ub[j]-lb[j]));
276 sigma[j] = MAX(sigma[j], 0.01*(ub[j]-lb[j]));