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"
31 /*************************************************************************/
33 void NLOPT_STDCALL nlopt_destroy(nlopt_opt opt)
36 if (opt->munge_on_destroy) {
37 nlopt_munge munge = opt->munge_on_destroy;
40 for (i = 0; i < opt->m; ++i)
41 munge(opt->fc[i].f_data);
42 for (i = 0; i < opt->p; ++i)
43 munge(opt->h[i].f_data);
45 free(opt->lb); free(opt->ub);
49 nlopt_destroy(opt->local_opt);
55 nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n)
59 if (((int) algorithm) < 0 || algorithm >= NLOPT_NUM_ALGORITHMS)
62 opt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
64 opt->algorithm = algorithm;
66 opt->f = NULL; opt->f_data = NULL;
68 opt->munge_on_destroy = opt->munge_on_copy = NULL;
70 opt->lb = opt->ub = NULL;
71 opt->m = opt->m_alloc = 0;
73 opt->p = opt->p_alloc = 0;
76 opt->stopval = -HUGE_VAL;
77 opt->ftol_rel = opt->ftol_abs = 0;
78 opt->xtol_rel = 0; opt->xtol_abs = NULL;
82 opt->force_stop_child = NULL;
84 opt->local_opt = NULL;
85 opt->stochastic_population = 0;
89 opt->lb = (double *) malloc(sizeof(double) * (n));
90 if (!opt->lb) goto oom;
91 opt->ub = (double *) malloc(sizeof(double) * (n));
92 if (!opt->ub) goto oom;
93 opt->xtol_abs = (double *) malloc(sizeof(double) * (n));
94 if (!opt->xtol_abs) goto oom;
95 nlopt_set_lower_bounds1(opt, -HUGE_VAL);
96 nlopt_set_upper_bounds1(opt, +HUGE_VAL);
97 nlopt_set_xtol_abs1(opt, 0.0);
108 nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
110 nlopt_opt nopt = NULL;
112 nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
114 nopt->lb = nopt->ub = nopt->xtol_abs = NULL;
115 nopt->fc = nopt->h = NULL;
116 nopt->m_alloc = nopt->p_alloc = 0;
117 nopt->local_opt = NULL;
119 opt->force_stop_child = NULL;
121 nlopt_munge munge = nopt->munge_on_copy;
122 if (munge && nopt->f_data)
123 if (!(nopt->f_data = munge(nopt->f_data))) goto oom;
126 nopt->lb = (double *) malloc(sizeof(double) * (opt->n));
127 if (!opt->lb) goto oom;
128 nopt->ub = (double *) malloc(sizeof(double) * (opt->n));
129 if (!opt->ub) goto oom;
130 nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n));
131 if (!opt->xtol_abs) goto oom;
133 memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n));
134 memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n));
135 memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
139 nopt->m_alloc = opt->m;
140 nopt->fc = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
142 if (!nopt->fc) goto oom;
143 memcpy(nopt->fc, opt->fc, sizeof(nlopt_constraint) * (opt->m));
145 for (unsigned i = 0; i < opt->m; ++i)
146 if (nopt->fc[i].f_data &&
148 = munge(nopt->fc[i].f_data)))
153 nopt->p_alloc = opt->p;
154 nopt->h = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
156 if (!nopt->h) goto oom;
157 memcpy(nopt->h, opt->h, sizeof(nlopt_constraint) * (opt->p));
159 for (unsigned i = 0; i < opt->p; ++i)
160 if (nopt->h[i].f_data &&
162 = munge(nopt->h[i].f_data)))
166 if (opt->local_opt) {
167 nopt->local_opt = nlopt_copy(opt->local_opt);
168 if (!nopt->local_opt) goto oom;
172 nopt->dx = (double *) malloc(sizeof(double) * (opt->n));
173 if (!nopt->dx) goto oom;
174 memcpy(nopt->dx, opt->dx, sizeof(double) * (opt->n));
180 nopt->munge_on_destroy = NULL; // better to leak mem than crash
185 /*************************************************************************/
187 nlopt_result NLOPT_STDCALL nlopt_set_min_objective(nlopt_opt opt,
188 nlopt_func f, void *f_data)
191 opt->f = f; opt->f_data = f_data;
193 if (nlopt_isinf(opt->stopval) && opt->stopval > 0)
194 opt->stopval = -HUGE_VAL; /* switch default from max to min */
195 return NLOPT_SUCCESS;
197 return NLOPT_INVALID_ARGS;
200 nlopt_result NLOPT_STDCALL nlopt_set_max_objective(nlopt_opt opt,
201 nlopt_func f, void *f_data)
204 opt->f = f; opt->f_data = f_data;
206 if (nlopt_isinf(opt->stopval) && opt->stopval < 0)
207 opt->stopval = +HUGE_VAL; /* switch default from min to max */
208 return NLOPT_SUCCESS;
210 return NLOPT_INVALID_ARGS;
213 /*************************************************************************/
216 NLOPT_STDCALL nlopt_set_lower_bounds(nlopt_opt opt, const double *lb)
218 if (opt && (opt->n == 0 || lb)) {
219 memcpy(opt->lb, lb, sizeof(double) * (opt->n));
220 return NLOPT_SUCCESS;
222 return NLOPT_INVALID_ARGS;
226 NLOPT_STDCALL nlopt_set_lower_bounds1(nlopt_opt opt, double lb)
230 for (i = 0; i < opt->n; ++i)
232 return NLOPT_SUCCESS;
234 return NLOPT_INVALID_ARGS;
238 NLOPT_STDCALL nlopt_get_lower_bounds(nlopt_opt opt, double *lb)
240 if (opt && (opt->n == 0 || lb)) {
241 memcpy(lb, opt->lb, sizeof(double) * (opt->n));
242 return NLOPT_SUCCESS;
244 return NLOPT_INVALID_ARGS;
248 NLOPT_STDCALL nlopt_set_upper_bounds(nlopt_opt opt, const double *ub)
250 if (opt && (opt->n == 0 || ub)) {
251 memcpy(opt->ub, ub, sizeof(double) * (opt->n));
252 return NLOPT_SUCCESS;
254 return NLOPT_INVALID_ARGS;
258 NLOPT_STDCALL nlopt_set_upper_bounds1(nlopt_opt opt, double ub)
262 for (i = 0; i < opt->n; ++i)
264 return NLOPT_SUCCESS;
266 return NLOPT_INVALID_ARGS;
270 NLOPT_STDCALL nlopt_get_upper_bounds(nlopt_opt opt, double *ub)
272 if (opt && (opt->n == 0 || ub)) {
273 memcpy(ub, opt->ub, sizeof(double) * (opt->n));
274 return NLOPT_SUCCESS;
276 return NLOPT_INVALID_ARGS;
279 /*************************************************************************/
281 #define AUGLAG_ALG(a) ((a) == NLOPT_AUGLAG || \
282 (a) == NLOPT_AUGLAG_EQ || \
283 (a) == NLOPT_LN_AUGLAG || \
284 (a) == NLOPT_LN_AUGLAG_EQ || \
285 (a) == NLOPT_LD_AUGLAG || \
286 (a) == NLOPT_LD_AUGLAG_EQ)
289 NLOPT_STDCALL nlopt_remove_inequality_constraints(nlopt_opt opt)
291 if (!opt) return NLOPT_INVALID_ARGS;
292 if (opt->munge_on_destroy) {
293 nlopt_munge munge = opt->munge_on_destroy;
294 for (unsigned i = 0; i < opt->m; ++i)
295 munge(opt->fc[i].f_data);
299 opt->m = opt->m_alloc = 0;
300 return NLOPT_SUCCESS;
303 static nlopt_result add_constraint(unsigned *m, unsigned *m_alloc,
304 nlopt_constraint **c,
305 nlopt_func fc, void *fc_data,
310 /* allocate by repeated doubling so that
311 we end up with O(log m) mallocs rather than O(m). */
313 *c = (nlopt_constraint *) realloc(*c,
314 sizeof(nlopt_constraint)
318 return NLOPT_OUT_OF_MEMORY;
323 (*c)[*m - 1].f_data = fc_data;
324 (*c)[*m - 1].tol = tol;
325 return NLOPT_SUCCESS;
329 NLOPT_STDCALL nlopt_add_inequality_constraint(nlopt_opt opt,
330 nlopt_func fc, void *fc_data,
333 if (opt && fc && tol >= 0) {
334 /* nonlinear constraints are only supported with some algorithms */
335 if (opt->algorithm != NLOPT_LD_MMA
336 && opt->algorithm != NLOPT_LN_COBYLA
337 && !AUGLAG_ALG(opt->algorithm)
338 && opt->algorithm != NLOPT_GN_ISRES
339 && opt->algorithm != NLOPT_GN_ORIG_DIRECT
340 && opt->algorithm != NLOPT_GN_ORIG_DIRECT_L)
341 return NLOPT_INVALID_ARGS;
342 return add_constraint(&opt->m, &opt->m_alloc, &opt->fc,
345 return NLOPT_INVALID_ARGS;
349 NLOPT_STDCALL nlopt_remove_equality_constraints(nlopt_opt opt)
351 if (!opt) return NLOPT_INVALID_ARGS;
352 if (opt->munge_on_destroy) {
353 nlopt_munge munge = opt->munge_on_destroy;
354 for (unsigned i = 0; i < opt->p; ++i)
355 munge(opt->h[i].f_data);
359 opt->p = opt->p_alloc = 0;
360 return NLOPT_SUCCESS;
364 NLOPT_STDCALL nlopt_add_equality_constraint(nlopt_opt opt,
365 nlopt_func h, void *h_data,
368 if (opt && h && tol >= 0) {
369 /* equality constraints (h(x) = 0) only via some algorithms */
370 if (!AUGLAG_ALG(opt->algorithm) && opt->algorithm != NLOPT_GN_ISRES
371 && opt->algorithm != NLOPT_LN_COBYLA)
372 return NLOPT_INVALID_ARGS;
373 return add_constraint(&opt->p, &opt->p_alloc, &opt->h,
376 return NLOPT_INVALID_ARGS;
379 /*************************************************************************/
381 #define SET(param, T, arg) \
382 nlopt_result NLOPT_STDCALL nlopt_set_##param(nlopt_opt opt, T arg) \
386 return NLOPT_SUCCESS; \
388 return NLOPT_INVALID_ARGS; \
392 #define GET(param, T, arg) T NLOPT_STDCALL \
393 nlopt_get_##param(const nlopt_opt opt) { \
397 #define GETSET(param, T, arg) GET(param, T, arg) SET(param, T, arg)
399 GETSET(stopval, double, stopval)
401 GETSET(ftol_rel, double, ftol_rel)
402 GETSET(ftol_abs, double, ftol_abs)
403 GETSET(xtol_rel, double, xtol_rel)
406 NLOPT_STDCALL nlopt_set_xtol_abs(nlopt_opt opt, const double *xtol_abs)
409 memcpy(opt->xtol_abs, xtol_abs, opt->n & sizeof(double));
410 return NLOPT_SUCCESS;
412 return NLOPT_INVALID_ARGS;
416 NLOPT_STDCALL nlopt_set_xtol_abs1(nlopt_opt opt, const double xtol_abs)
420 for (i = 0; i < opt->n; ++i)
421 opt->xtol_abs[i] = xtol_abs;
422 return NLOPT_SUCCESS;
424 return NLOPT_INVALID_ARGS;
428 NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs)
430 memcpy(xtol_abs, opt->xtol_abs, opt->n & sizeof(double));
431 return NLOPT_SUCCESS;
434 GETSET(maxeval, int, maxeval)
436 GETSET(maxtime, double, maxtime)
438 /*************************************************************************/
441 NLOPT_STDCALL nlopt_set_force_stop(nlopt_opt opt, int force_stop)
444 opt->force_stop = force_stop;
445 if (opt->force_stop_child)
446 return nlopt_set_force_stop(opt->force_stop_child, force_stop);
447 return NLOPT_SUCCESS;
449 return NLOPT_INVALID_ARGS;
452 GET(force_stop, int, force_stop)
453 nlopt_result NLOPT_STDCALL nlopt_force_stop(nlopt_opt opt) {
454 return nlopt_set_force_stop(opt, 1);
457 /*************************************************************************/
459 GET(algorithm, nlopt_algorithm, algorithm)
460 GET(dimension, unsigned, n)
462 /*************************************************************************/
465 NLOPT_STDCALL nlopt_set_local_optimizer(nlopt_opt opt,
466 const nlopt_opt local_opt)
469 if (local_opt && local_opt->n != opt->n) return NLOPT_INVALID_ARGS;
470 nlopt_destroy(opt->local_opt);
471 opt->local_opt = nlopt_copy(local_opt);
473 if (!opt->local_opt) return NLOPT_OUT_OF_MEMORY;
474 nlopt_set_lower_bounds(opt->local_opt, opt->lb);
475 nlopt_set_upper_bounds(opt->local_opt, opt->ub);
476 nlopt_remove_inequality_constraints(opt->local_opt);
477 nlopt_remove_equality_constraints(opt->local_opt);
478 nlopt_set_min_objective(opt->local_opt, NULL, NULL);
479 opt->local_opt->force_stop = 0;
481 return NLOPT_SUCCESS;
483 return NLOPT_INVALID_ARGS;
486 /*************************************************************************/
488 GETSET(population, unsigned, stochastic_population)
490 /*************************************************************************/
492 nlopt_result NLOPT_STDCALL nlopt_set_initial_step1(nlopt_opt opt, double dx)
495 if (!opt || dx == 0) return NLOPT_INVALID_ARGS;
496 if (!opt->dx && opt->n > 0) {
497 opt->dx = (double *) malloc(sizeof(double) * (opt->n));
498 if (!opt->dx) return NLOPT_OUT_OF_MEMORY;
500 for (i = 0; i < opt->n; ++i) opt->dx[i] = dx;
501 return NLOPT_SUCCESS;
505 NLOPT_STDCALL nlopt_set_initial_step(nlopt_opt opt, const double *dx)
508 if (!opt) return NLOPT_INVALID_ARGS;
510 free(opt->dx); opt->dx = NULL;
511 return NLOPT_SUCCESS;
513 for (i = 0; i < opt->n; ++i) if (dx[i] == 0) return NLOPT_INVALID_ARGS;
514 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
515 return NLOPT_OUT_OF_MEMORY;
516 memcpy(opt->dx, dx, sizeof(double) * (opt->n));
517 return NLOPT_SUCCESS;
521 NLOPT_STDCALL nlopt_get_initial_step(const nlopt_opt opt, const double *x,
524 if (!opt) return NLOPT_INVALID_ARGS;
525 if (!opt->n) return NLOPT_SUCCESS;
527 nlopt_opt o = (nlopt_opt) opt; /* discard const temporarily */
528 nlopt_result ret = nlopt_set_default_initial_step(o, x);
529 if (ret != NLOPT_SUCCESS) return ret;
530 memcpy(dx, o->dx, sizeof(double) * (opt->n));
531 free(o->dx); o->dx = NULL; /* don't save, since x-dependent */
534 memcpy(dx, opt->dx, sizeof(double) * (opt->n));
535 return NLOPT_SUCCESS;
539 NLOPT_STDCALL nlopt_set_default_initial_step(nlopt_opt opt, const double *x)
541 const double *lb, *ub;
544 if (!opt || !x) return NLOPT_INVALID_ARGS;
545 lb = opt->lb; ub = opt->ub;
547 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
548 return NLOPT_OUT_OF_MEMORY;
550 /* crude heuristics for initial step size of nonderivative algorithms */
551 for (i = 0; i < opt->n; ++i) {
552 double step = HUGE_VAL;
554 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i])
555 && (ub[i] - lb[i]) * 0.25 < step && ub[i] > lb[i])
556 step = (ub[i] - lb[i]) * 0.25;
557 if (!nlopt_isinf(ub[i])
558 && ub[i] - x[i] < step && ub[i] > x[i])
559 step = (ub[i] - x[i]) * 0.75;
560 if (!nlopt_isinf(lb[i])
561 && x[i] - lb[i] < step && x[i] > lb[i])
562 step = (x[i] - lb[i]) * 0.75;
564 if (nlopt_isinf(step)) {
565 if (!nlopt_isinf(ub[i])
566 && fabs(ub[i] - x[i]) < fabs(step))
567 step = (ub[i] - x[i]) * 1.1;
568 if (!nlopt_isinf(lb[i])
569 && fabs(x[i] - lb[i]) < fabs(step))
570 step = (x[i] - lb[i]) * 1.1;
572 if (nlopt_isinf(step) || step == 0) {
575 if (nlopt_isinf(step) || step == 0)
580 return NLOPT_SUCCESS;
583 /*************************************************************************/
585 void NLOPT_STDCALL nlopt_set_munge(nlopt_opt opt,
586 nlopt_munge munge_on_destroy,
587 nlopt_munge munge_on_copy) {
589 opt->munge_on_destroy = munge_on_destroy;
590 opt->munge_on_copy = munge_on_copy;
594 /*************************************************************************/