1 /* Copyright (c) 2007-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 #include "nlopt-internal.h"
30 #include "nlopt-util.h"
32 /*************************************************************************/
34 void nlopt_destroy(nlopt_opt opt)
37 free(opt->lb); free(opt->ub);
41 nlopt_destroy(opt->local_opt);
47 nlopt_opt nlopt_create(nlopt_algorithm algorithm, unsigned n)
51 if (((int) algorithm) < 0 || algorithm >= NLOPT_NUM_ALGORITHMS)
54 opt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
56 opt->algorithm = algorithm;
58 opt->f = NULL; opt->f_data = NULL;
61 opt->lb = opt->ub = NULL;
62 opt->m = opt->m_alloc = 0;
64 opt->p = opt->p_alloc = 0;
67 opt->stopval = -HUGE_VAL;
68 opt->ftol_rel = opt->ftol_abs = 0;
69 opt->xtol_rel = 0; opt->xtol_abs = NULL;
73 opt->local_opt = NULL;
74 opt->stochastic_population = 0;
78 opt->lb = (double *) malloc(sizeof(double) * (n));
79 if (!opt->lb) goto oom;
80 opt->ub = (double *) malloc(sizeof(double) * (n));
81 if (!opt->ub) goto oom;
82 opt->xtol_abs = (double *) malloc(sizeof(double) * (n));
83 if (!opt->xtol_abs) goto oom;
84 nlopt_set_lower_bounds1(opt, -HUGE_VAL);
85 nlopt_set_upper_bounds1(opt, +HUGE_VAL);
86 nlopt_set_xtol_abs1(opt, 0.0);
97 nlopt_opt nlopt_copy(const nlopt_opt opt)
99 nlopt_opt nopt = NULL;
101 nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
103 nopt->lb = nopt->ub = nopt->xtol_abs = NULL;
104 nopt->fc = nopt->h = NULL;
105 nopt->m_alloc = nopt->p_alloc = 0;
106 nopt->local_opt = NULL;
110 nopt->lb = (double *) malloc(sizeof(double) * (opt->n));
111 if (!opt->lb) goto oom;
112 nopt->ub = (double *) malloc(sizeof(double) * (opt->n));
113 if (!opt->ub) goto oom;
114 nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n));
115 if (!opt->xtol_abs) goto oom;
117 memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n));
118 memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n));
119 memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
123 nopt->m_alloc = opt->m;
124 nopt->fc = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
126 if (!nopt->fc) goto oom;
127 memcpy(nopt->fc, opt->fc, sizeof(nlopt_constraint) * (opt->m));
131 nopt->p_alloc = opt->p;
132 nopt->h = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
134 if (!nopt->h) goto oom;
135 memcpy(nopt->h, opt->h, sizeof(nlopt_constraint) * (opt->p));
138 if (opt->local_opt) {
139 nopt->local_opt = nlopt_copy(opt->local_opt);
140 if (!nopt->local_opt) goto oom;
144 nopt->dx = (double *) malloc(sizeof(double) * (opt->n));
145 if (!nopt->dx) goto oom;
146 memcpy(nopt->dx, opt->dx, sizeof(double) * (opt->n));
156 /*************************************************************************/
158 nlopt_result nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void *f_data)
161 opt->f = f; opt->f_data = f_data;
163 if (nlopt_isinf(opt->stopval) && opt->stopval > 0)
164 opt->stopval = -HUGE_VAL;
165 return NLOPT_SUCCESS;
167 return NLOPT_INVALID_ARGS;
170 nlopt_result nlopt_set_max_objective(nlopt_opt opt, nlopt_func f, void *f_data)
173 opt->f = f; opt->f_data = f_data;
175 if (nlopt_isinf(opt->stopval) && opt->stopval < 0)
176 opt->stopval = +HUGE_VAL;
177 return NLOPT_SUCCESS;
179 return NLOPT_INVALID_ARGS;
182 /*************************************************************************/
184 nlopt_result nlopt_set_lower_bounds(nlopt_opt opt, const double *lb)
186 if (opt && (opt->n == 0 || lb)) {
187 memcpy(opt->lb, lb, sizeof(double) * (opt->n));
188 return NLOPT_SUCCESS;
190 return NLOPT_INVALID_ARGS;
193 nlopt_result nlopt_set_lower_bounds1(nlopt_opt opt, double lb)
197 for (i = 0; i < opt->n; ++i)
199 return NLOPT_SUCCESS;
201 return NLOPT_INVALID_ARGS;
204 nlopt_result nlopt_get_lower_bounds(nlopt_opt opt, double *lb)
206 if (opt && (opt->n == 0 || lb)) {
207 memcpy(lb, opt->lb, sizeof(double) * (opt->n));
208 return NLOPT_SUCCESS;
210 return NLOPT_INVALID_ARGS;
213 nlopt_result nlopt_set_upper_bounds(nlopt_opt opt, const double *ub)
215 if (opt && (opt->n == 0 || ub)) {
216 memcpy(opt->ub, ub, sizeof(double) * (opt->n));
217 return NLOPT_SUCCESS;
219 return NLOPT_INVALID_ARGS;
222 nlopt_result nlopt_set_upper_bounds1(nlopt_opt opt, double ub)
226 for (i = 0; i < opt->n; ++i)
228 return NLOPT_SUCCESS;
230 return NLOPT_INVALID_ARGS;
233 nlopt_result nlopt_get_upper_bounds(nlopt_opt opt, double *ub)
235 if (opt && (opt->n == 0 || ub)) {
236 memcpy(ub, opt->ub, sizeof(double) * (opt->n));
237 return NLOPT_SUCCESS;
239 return NLOPT_INVALID_ARGS;
242 /*************************************************************************/
244 #define AUGLAG_ALG(a) ((a) == NLOPT_LN_AUGLAG || \
245 (a) == NLOPT_LN_AUGLAG_EQ || \
246 (a) == NLOPT_LD_AUGLAG || \
247 (a) == NLOPT_LD_AUGLAG_EQ)
249 nlopt_result nlopt_remove_inequality_constraints(nlopt_opt opt)
253 opt->m = opt->m_alloc = 0;
254 return NLOPT_SUCCESS;
257 static nlopt_result add_constraint(unsigned *m, unsigned *m_alloc,
258 nlopt_constraint **c,
259 nlopt_func fc, void *fc_data,
264 /* allocate by repeated doubling so that
265 we end up with O(log m) mallocs rather than O(m). */
267 *c = (nlopt_constraint *) realloc(*c,
268 sizeof(nlopt_constraint)
272 return NLOPT_OUT_OF_MEMORY;
277 (*c)[*m - 1].f_data = fc_data;
278 (*c)[*m - 1].tol = tol;
279 return NLOPT_SUCCESS;
282 nlopt_result nlopt_add_inequality_constraint(nlopt_opt opt,
283 nlopt_func fc, void *fc_data,
286 if (opt && fc && tol >= 0) {
287 /* nonlinear constraints are only supported with some algorithms */
288 if (opt->algorithm != NLOPT_LD_MMA
289 && opt->algorithm != NLOPT_LN_COBYLA
290 && !AUGLAG_ALG(opt->algorithm)
291 && opt->algorithm != NLOPT_GN_ISRES)
292 return NLOPT_INVALID_ARGS;
294 return add_constraint(&opt->m, &opt->m_alloc, &opt->fc,
297 return NLOPT_INVALID_ARGS;
300 nlopt_result nlopt_remove_equality_constraints(nlopt_opt opt)
304 opt->p = opt->p_alloc = 0;
305 return NLOPT_SUCCESS;
308 nlopt_result nlopt_add_equality_constraint(nlopt_opt opt,
309 nlopt_func h, void *h_data,
312 if (opt && h && tol >= 0) {
313 /* equality constraints (h(x) = 0) only via some algorithms */
314 if (!AUGLAG_ALG(opt->algorithm) && opt->algorithm != NLOPT_GN_ISRES)
315 return NLOPT_INVALID_ARGS;
317 return add_constraint(&opt->p, &opt->p_alloc, &opt->h,
320 return NLOPT_INVALID_ARGS;
323 /*************************************************************************/
325 #define SET(param, T, arg) \
326 nlopt_result nlopt_set_##param(nlopt_opt opt, T arg) \
330 return NLOPT_SUCCESS; \
332 return NLOPT_INVALID_ARGS; \
336 #define GET(param, T, arg) T nlopt_get_##param(const nlopt_opt opt) { \
340 #define GETSET(param, T, arg) GET(param, T, arg) SET(param, T, arg)
342 GETSET(stopval, double, stopval)
344 GETSET(ftol_rel, double, ftol_rel)
345 GETSET(ftol_abs, double, ftol_abs)
346 GETSET(xtol_rel, double, xtol_rel)
348 nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double *xtol_abs)
351 memcpy(opt->xtol_abs, xtol_abs, opt->n & sizeof(double));
352 return NLOPT_SUCCESS;
354 return NLOPT_INVALID_ARGS;
357 nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, const double xtol_abs)
361 for (i = 0; i < opt->n; ++i)
362 opt->xtol_abs[i] = xtol_abs;
363 return NLOPT_SUCCESS;
365 return NLOPT_INVALID_ARGS;
368 nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs)
370 memcpy(xtol_abs, opt->xtol_abs, opt->n & sizeof(double));
371 return NLOPT_SUCCESS;
374 GETSET(maxeval, int, maxeval)
376 GETSET(maxtime, double, maxtime)
378 /*************************************************************************/
380 GET(algorithm, nlopt_algorithm, algorithm)
381 GET(dimension, unsigned, n)
383 /*************************************************************************/
385 nlopt_result nlopt_set_local_optimizer(nlopt_opt opt,
386 const nlopt_opt local_opt)
389 if (local_opt && local_opt->n != opt->n) return NLOPT_INVALID_ARGS;
390 nlopt_destroy(opt->local_opt);
391 opt->local_opt = nlopt_copy(local_opt);
393 if (!opt->local_opt) return NLOPT_OUT_OF_MEMORY;
394 nlopt_set_lower_bounds(opt->local_opt, opt->lb);
395 nlopt_set_upper_bounds(opt->local_opt, opt->ub);
396 nlopt_remove_inequality_constraints(opt->local_opt);
397 nlopt_remove_equality_constraints(opt->local_opt);
399 return NLOPT_SUCCESS;
401 return NLOPT_INVALID_ARGS;
404 /*************************************************************************/
406 GETSET(population, unsigned, stochastic_population)
408 /*************************************************************************/
410 nlopt_result nlopt_set_initial_step1(nlopt_opt opt, double dx)
413 if (!opt || dx == 0) return NLOPT_INVALID_ARGS;
414 if (!opt->dx && opt->n > 0) {
415 opt->dx = (double *) malloc(sizeof(double) * (opt->n));
416 if (!opt->dx) return NLOPT_OUT_OF_MEMORY;
418 for (i = 0; i < opt->n; ++i) opt->dx[i] = dx;
419 return NLOPT_SUCCESS;
422 nlopt_result nlopt_set_initial_step(nlopt_opt opt, const double *dx)
425 if (!opt || !dx) return NLOPT_INVALID_ARGS;
426 for (i = 0; i < opt->n; ++i) if (dx[i] == 0) return NLOPT_INVALID_ARGS;
427 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
428 return NLOPT_OUT_OF_MEMORY;
429 memcpy(opt->dx, dx, sizeof(double) * (opt->n));
430 return NLOPT_SUCCESS;
433 nlopt_result nlopt_get_initial_step(const nlopt_opt opt, const double *x,
436 if (!opt) return NLOPT_INVALID_ARGS;
437 if (!opt->n) return NLOPT_SUCCESS;
439 nlopt_opt o = (nlopt_opt) opt; /* discard const temporarily */
440 nlopt_result ret = nlopt_set_default_initial_step(o, x);
441 if (ret != NLOPT_SUCCESS) return ret;
442 memcpy(dx, o->dx, sizeof(double) * (opt->n));
443 free(o->dx); o->dx = NULL; /* don't save, since x-dependent */
446 memcpy(dx, opt->dx, sizeof(double) * (opt->n));
447 return NLOPT_SUCCESS;
450 nlopt_result nlopt_set_default_initial_step(nlopt_opt opt, const double *x)
452 const double *lb, *ub;
455 if (!opt || !x) return NLOPT_INVALID_ARGS;
456 lb = opt->lb; ub = opt->ub;
458 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
459 return NLOPT_OUT_OF_MEMORY;
461 /* crude heuristics for initial step size of nonderivative algorithms */
462 for (i = 0; i < opt->n; ++i) {
463 double step = HUGE_VAL;
465 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i])
466 && (ub[i] - lb[i]) * 0.25 < step && ub[i] > lb[i])
467 step = (ub[i] - lb[i]) * 0.25;
468 if (!nlopt_isinf(ub[i])
469 && ub[i] - x[i] < step && ub[i] > x[i])
470 step = (ub[i] - x[i]) * 0.75;
471 if (!nlopt_isinf(lb[i])
472 && x[i] - lb[i] < step && x[i] > lb[i])
473 step = (x[i] - lb[i]) * 0.75;
475 if (nlopt_isinf(step)) {
476 if (!nlopt_isinf(ub[i])
477 && fabs(ub[i] - x[i]) < fabs(step))
478 step = (ub[i] - x[i]) * 1.1;
479 if (!nlopt_isinf(lb[i])
480 && fabs(x[i] - lb[i]) < fabs(step))
481 step = (x[i] - lb[i]) * 1.1;
483 if (nlopt_isinf(step) || step == 0) {
486 if (nlopt_isinf(step) || step == 0)
491 return NLOPT_SUCCESS;
494 /*************************************************************************/