1 /* Copyright (c) 2007-2014 Massachusetts Institute of Technology
2 *
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:
10 *
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
13 *
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.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27 #include <float.h>
28 #include <stdarg.h>
29
30 #include "nlopt-internal.h"
31
32 #define ERR(err, opt, msg) (nlopt_set_errmsg(opt, msg) ? err : err)
33
34 /*************************************************************************/
35
nlopt_destroy(nlopt_opt opt)36 void NLOPT_STDCALL nlopt_destroy(nlopt_opt opt)
37 {
38 if (opt) {
39 unsigned i;
40 if (opt->munge_on_destroy) {
41 nlopt_munge munge = opt->munge_on_destroy;
42 munge(opt->f_data);
43 for (i = 0; i < opt->m; ++i)
44 munge(opt->fc[i].f_data);
45 for (i = 0; i < opt->p; ++i)
46 munge(opt->h[i].f_data);
47 }
48 for (i = 0; i < opt->m; ++i)
49 free(opt->fc[i].tol);
50 for (i = 0; i < opt->p; ++i)
51 free(opt->h[i].tol);
52 for (i = 0; i < opt->nparams; ++i)
53 free(opt->params[i].name);
54 free(opt->params);
55 free(opt->lb);
56 free(opt->ub);
57 free(opt->xtol_abs);
58 free(opt->x_weights);
59 free(opt->fc);
60 free(opt->h);
61 nlopt_destroy(opt->local_opt);
62 free(opt->dx);
63 free(opt->work);
64 free(opt->errmsg);
65 free(opt);
66 }
67 }
68
nlopt_create(nlopt_algorithm algorithm,unsigned n)69 nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n)
70 {
71 nlopt_opt opt;
72
73 if (((int) algorithm) < 0 || algorithm >= NLOPT_NUM_ALGORITHMS)
74 return NULL;
75
76 opt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
77 if (opt) {
78 opt->algorithm = algorithm;
79 opt->n = n;
80 opt->f = NULL;
81 opt->f_data = NULL;
82 opt->pre = NULL;
83 opt->maximize = 0;
84 opt->munge_on_destroy = opt->munge_on_copy = NULL;
85
86 opt->lb = opt->ub = NULL;
87 opt->m = opt->m_alloc = 0;
88 opt->fc = NULL;
89 opt->p = opt->p_alloc = 0;
90 opt->h = NULL;
91 opt->params = NULL;
92 opt->nparams = 0;
93
94 opt->stopval = -HUGE_VAL;
95 opt->ftol_rel = opt->ftol_abs = 0;
96 opt->xtol_rel = 0;
97 opt->x_weights = NULL;
98 opt->xtol_abs = NULL;
99 opt->maxeval = 0;
100 opt->numevals = 0;
101 opt->maxtime = 0;
102 opt->force_stop = 0;
103 opt->force_stop_child = NULL;
104
105 opt->local_opt = NULL;
106 opt->stochastic_population = 0;
107 opt->vector_storage = 0;
108 opt->dx = NULL;
109 opt->work = NULL;
110 opt->errmsg = NULL;
111
112 if (n > 0) {
113 opt->lb = (double *) calloc(n, sizeof(double));
114 if (!opt->lb)
115 goto oom;
116 opt->ub = (double *) calloc(n, sizeof(double));
117 if (!opt->ub)
118 goto oom;
119 nlopt_set_lower_bounds1(opt, -HUGE_VAL);
120 nlopt_set_upper_bounds1(opt, +HUGE_VAL);
121 }
122 }
123
124 return opt;
125
126 oom:
127 nlopt_destroy(opt);
128 return NULL;
129 }
130
nlopt_copy(const nlopt_opt opt)131 nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
132 {
133 nlopt_opt nopt = NULL;
134 unsigned i;
135 if (opt) {
136 nlopt_munge munge;
137 nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
138 *nopt = *opt;
139 nopt->lb = nopt->ub = nopt->xtol_abs = nopt->x_weights = NULL;
140 nopt->fc = nopt->h = NULL;
141 nopt->m_alloc = nopt->p_alloc = 0;
142 nopt->local_opt = NULL;
143 nopt->dx = NULL;
144 nopt->work = NULL;
145 nopt->errmsg = NULL;
146 nopt->force_stop_child = NULL;
147 nopt->params = NULL;
148 nopt->nparams = 0;
149
150 munge = nopt->munge_on_copy;
151 if (munge && nopt->f_data)
152 if (!(nopt->f_data = munge(nopt->f_data)))
153 goto oom;
154
155 if (opt->n > 0) {
156 nopt->lb = (double *) malloc(sizeof(double) * (opt->n));
157 if (!opt->lb)
158 goto oom;
159 nopt->ub = (double *) malloc(sizeof(double) * (opt->n));
160 if (!opt->ub)
161 goto oom;
162 if (opt->xtol_abs) {
163 nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n));
164 if (!opt->xtol_abs)
165 goto oom;
166 }
167 if (opt->x_weights) {
168 nopt->x_weights = (double *) malloc(sizeof(double) * (opt->n));
169 if (!opt->x_weights)
170 goto oom;
171 memcpy(nopt->x_weights, opt->x_weights, sizeof(double) * (opt->n));
172 }
173
174 memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n));
175 memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n));
176 if (opt->xtol_abs) {
177 memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
178 }
179 }
180
181 if (opt->m) {
182 nopt->m_alloc = opt->m;
183 nopt->fc = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
184 * (opt->m));
185 if (!nopt->fc)
186 goto oom;
187 memcpy(nopt->fc, opt->fc, sizeof(nlopt_constraint) * (opt->m));
188 for (i = 0; i < opt->m; ++i)
189 nopt->fc[i].tol = NULL;
190 if (munge)
191 for (i = 0; i < opt->m; ++i)
192 if (nopt->fc[i].f_data && !(nopt->fc[i].f_data = munge(nopt->fc[i].f_data)))
193 goto oom;
194 for (i = 0; i < opt->m; ++i)
195 if (opt->fc[i].tol) {
196 nopt->fc[i].tol = (double *) malloc(sizeof(double)
197 * nopt->fc[i].m);
198 if (!nopt->fc[i].tol)
199 goto oom;
200 memcpy(nopt->fc[i].tol, opt->fc[i].tol, sizeof(double) * nopt->fc[i].m);
201 }
202 }
203
204 if (opt->p) {
205 nopt->p_alloc = opt->p;
206 nopt->h = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
207 * (opt->p));
208 if (!nopt->h)
209 goto oom;
210 memcpy(nopt->h, opt->h, sizeof(nlopt_constraint) * (opt->p));
211 for (i = 0; i < opt->p; ++i)
212 nopt->h[i].tol = NULL;
213 if (munge)
214 for (i = 0; i < opt->p; ++i)
215 if (nopt->h[i].f_data && !(nopt->h[i].f_data = munge(nopt->h[i].f_data)))
216 goto oom;
217 for (i = 0; i < opt->p; ++i)
218 if (opt->h[i].tol) {
219 nopt->h[i].tol = (double *) malloc(sizeof(double)
220 * nopt->h[i].m);
221 if (!nopt->h[i].tol)
222 goto oom;
223 memcpy(nopt->h[i].tol, opt->h[i].tol, sizeof(double) * nopt->h[i].m);
224 }
225 }
226
227 if (opt->nparams) {
228 nopt->nparams = opt->nparams;
229 nopt->params = (nlopt_opt_param *) calloc(opt->nparams, sizeof(nlopt_opt_param));
230 if (!nopt->params) goto oom;
231 for (i = 0; i < opt->nparams; ++i) {
232 size_t len = strlen(opt->params[i].name) + 1;
233 nopt->params[i].name = (char *) malloc(len);
234 if (!nopt->params[i].name) goto oom;
235 memcpy(nopt->params[i].name, opt->params[i].name, len);
236 nopt->params[i].val = opt->params[i].val;
237 }
238 }
239
240 if (opt->local_opt) {
241 nopt->local_opt = nlopt_copy(opt->local_opt);
242 if (!nopt->local_opt)
243 goto oom;
244 }
245
246 if (opt->dx) {
247 nopt->dx = (double *) malloc(sizeof(double) * (opt->n));
248 if (!nopt->dx)
249 goto oom;
250 memcpy(nopt->dx, opt->dx, sizeof(double) * (opt->n));
251 }
252 }
253 return nopt;
254
255 oom:
256 nopt->munge_on_destroy = NULL; /* better to leak mem than crash */
257 nlopt_destroy(nopt);
258 return NULL;
259 }
260
261 /*************************************************************************/
262 /* generic algorithm parameters, implemented as a simple array of (name,val)
263 pairs that can interpreted as needed by individual algorithms.
264
265 (No point in a fancier data structure since only a handful of these
266 should be set in practice). */
267
nlopt_set_param(nlopt_opt opt,const char * name,double val)268 nlopt_result nlopt_set_param(nlopt_opt opt, const char *name, double val) {
269 size_t len;
270 unsigned i;
271 if (!opt) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL opt");
272 if (!name) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL parameter name");
273 len = strnlen(name, 1024) + 1;
274 if (len > 1024) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "parameter name must be < 1024 bytes");
275 for (i = 0; i < opt->nparams; ++i)
276 if (!strcmp(name, opt->params[i].name))
277 break;
278 if (i == opt->nparams) { /* allocate new parameter */
279 opt->nparams++;
280 opt->params = (nlopt_opt_param *) realloc(opt->params, sizeof(nlopt_opt_param) * opt->nparams);
281 if (!opt->params) return NLOPT_OUT_OF_MEMORY;
282 opt->params[i].name = (char *) malloc(len);
283 if (!opt->params[i].name) return NLOPT_OUT_OF_MEMORY;
284 memcpy(opt->params[i].name, name, len);
285 }
286 opt->params[i].val = val;
287 return NLOPT_SUCCESS;
288 }
289
nlopt_get_param(const nlopt_opt opt,const char * name,double defaultval)290 double nlopt_get_param(const nlopt_opt opt, const char *name, double defaultval)
291 {
292 unsigned i;
293 if (!opt || !name || strnlen(name, 1024) == 1024) return defaultval;
294 for (i = 0; i < opt->nparams; ++i)
295 if (!strcmp(name, opt->params[i].name))
296 return opt->params[i].val;
297 return defaultval;
298 }
299
nlopt_has_param(const nlopt_opt opt,const char * name)300 int nlopt_has_param(const nlopt_opt opt, const char *name)
301 {
302 unsigned i;
303 if (!opt || !name || strnlen(name, 1024) == 1024) return 0;
304 for (i = 0; i < opt->nparams; ++i)
305 if (!strcmp(name, opt->params[i].name))
306 return 1;
307 return 0;
308 }
309
nlopt_num_params(const nlopt_opt opt)310 unsigned nlopt_num_params(const nlopt_opt opt)
311 {
312 return opt ? opt->nparams : 0;
313 }
314
nlopt_nth_param(const nlopt_opt opt,unsigned n)315 const char *nlopt_nth_param(const nlopt_opt opt, unsigned n)
316 {
317 return opt && n < opt->nparams ? opt->params[n].name : NULL;
318 }
319
320 /*************************************************************************/
321
nlopt_set_precond_min_objective(nlopt_opt opt,nlopt_func f,nlopt_precond pre,void * f_data)322 nlopt_result NLOPT_STDCALL nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data)
323 {
324 if (opt) {
325 nlopt_unset_errmsg(opt);
326 if (opt->munge_on_destroy)
327 opt->munge_on_destroy(opt->f_data);
328 opt->f = f;
329 opt->f_data = f_data;
330 opt->pre = pre;
331 opt->maximize = 0;
332 if (nlopt_isinf(opt->stopval) && opt->stopval > 0)
333 opt->stopval = -HUGE_VAL; /* switch default from max to min */
334 return NLOPT_SUCCESS;
335 }
336 return NLOPT_INVALID_ARGS;
337 }
338
nlopt_set_min_objective(nlopt_opt opt,nlopt_func f,void * f_data)339 nlopt_result NLOPT_STDCALL nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void *f_data)
340 {
341 return nlopt_set_precond_min_objective(opt, f, NULL, f_data);
342 }
343
nlopt_set_precond_max_objective(nlopt_opt opt,nlopt_func f,nlopt_precond pre,void * f_data)344 nlopt_result NLOPT_STDCALL nlopt_set_precond_max_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data)
345 {
346 if (opt) {
347 nlopt_unset_errmsg(opt);
348 if (opt->munge_on_destroy)
349 opt->munge_on_destroy(opt->f_data);
350 opt->f = f;
351 opt->f_data = f_data;
352 opt->pre = pre;
353 opt->maximize = 1;
354 if (nlopt_isinf(opt->stopval) && opt->stopval < 0)
355 opt->stopval = +HUGE_VAL; /* switch default from min to max */
356 return NLOPT_SUCCESS;
357 }
358 return NLOPT_INVALID_ARGS;
359 }
360
nlopt_set_max_objective(nlopt_opt opt,nlopt_func f,void * f_data)361 nlopt_result NLOPT_STDCALL nlopt_set_max_objective(nlopt_opt opt, nlopt_func f, void *f_data)
362 {
363 return nlopt_set_precond_max_objective(opt, f, NULL, f_data);
364 }
365
366 /*************************************************************************/
367
nlopt_set_lower_bounds(nlopt_opt opt,const double * lb)368 nlopt_result NLOPT_STDCALL nlopt_set_lower_bounds(nlopt_opt opt, const double *lb)
369 {
370 nlopt_unset_errmsg(opt);
371 if (opt && (opt->n == 0 || lb)) {
372 unsigned int i;
373 if (opt->n > 0)
374 memcpy(opt->lb, lb, sizeof(double) * (opt->n));
375 for (i = 0; i < opt->n; ++i)
376 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
377 opt->lb[i] = opt->ub[i];
378 return NLOPT_SUCCESS;
379 }
380 return NLOPT_INVALID_ARGS;
381 }
382
nlopt_set_lower_bounds1(nlopt_opt opt,double lb)383 nlopt_result NLOPT_STDCALL nlopt_set_lower_bounds1(nlopt_opt opt, double lb)
384 {
385 nlopt_unset_errmsg(opt);
386 if (opt) {
387 unsigned i;
388 for (i = 0; i < opt->n; ++i) {
389 opt->lb[i] = lb;
390 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
391 opt->lb[i] = opt->ub[i];
392 }
393 return NLOPT_SUCCESS;
394 }
395 return NLOPT_INVALID_ARGS;
396 }
397
nlopt_set_lower_bound(nlopt_opt opt,int i,double lb)398 nlopt_result NLOPT_STDCALL nlopt_set_lower_bound(nlopt_opt opt, int i, double lb)
399 {
400 nlopt_unset_errmsg(opt);
401 if (opt) {
402 if (i < 0 || i >= (int) opt->n)
403 return ERR(NLOPT_INVALID_ARGS, opt, "invalid bound index");
404 opt->lb[i] = lb;
405 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
406 opt->lb[i] = opt->ub[i];
407 return NLOPT_SUCCESS;
408 }
409 return NLOPT_INVALID_ARGS;
410 }
411
nlopt_get_lower_bounds(const nlopt_opt opt,double * lb)412 nlopt_result NLOPT_STDCALL nlopt_get_lower_bounds(const nlopt_opt opt, double *lb)
413 {
414 nlopt_unset_errmsg(opt);
415 if (opt && (opt->n == 0 || lb)) {
416 memcpy(lb, opt->lb, sizeof(double) * (opt->n));
417 return NLOPT_SUCCESS;
418 }
419 return NLOPT_INVALID_ARGS;
420 }
421
nlopt_set_upper_bounds(nlopt_opt opt,const double * ub)422 nlopt_result NLOPT_STDCALL nlopt_set_upper_bounds(nlopt_opt opt, const double *ub)
423 {
424 nlopt_unset_errmsg(opt);
425 if (opt && (opt->n == 0 || ub)) {
426 unsigned int i;
427 if (opt->n > 0)
428 memcpy(opt->ub, ub, sizeof(double) * (opt->n));
429 for (i = 0; i < opt->n; ++i)
430 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
431 opt->ub[i] = opt->lb[i];
432 return NLOPT_SUCCESS;
433 }
434 return NLOPT_INVALID_ARGS;
435 }
436
nlopt_set_upper_bounds1(nlopt_opt opt,double ub)437 nlopt_result NLOPT_STDCALL nlopt_set_upper_bounds1(nlopt_opt opt, double ub)
438 {
439 nlopt_unset_errmsg(opt);
440 if (opt) {
441 unsigned i;
442 for (i = 0; i < opt->n; ++i) {
443 opt->ub[i] = ub;
444 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
445 opt->ub[i] = opt->lb[i];
446 }
447 return NLOPT_SUCCESS;
448 }
449 return NLOPT_INVALID_ARGS;
450 }
451
nlopt_set_upper_bound(nlopt_opt opt,int i,double ub)452 nlopt_result NLOPT_STDCALL nlopt_set_upper_bound(nlopt_opt opt, int i, double ub)
453 {
454 nlopt_unset_errmsg(opt);
455 if (opt) {
456 if (i < 0 || i >= (int) opt->n)
457 return ERR(NLOPT_INVALID_ARGS, opt, "invalid bound index");
458 opt->ub[i] = ub;
459 if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
460 opt->ub[i] = opt->lb[i];
461 return NLOPT_SUCCESS;
462 }
463 return NLOPT_INVALID_ARGS;
464 }
465
nlopt_get_upper_bounds(const nlopt_opt opt,double * ub)466 nlopt_result NLOPT_STDCALL nlopt_get_upper_bounds(const nlopt_opt opt, double *ub)
467 {
468 nlopt_unset_errmsg(opt);
469 if (opt && (opt->n == 0 || ub)) {
470 memcpy(ub, opt->ub, sizeof(double) * (opt->n));
471 return NLOPT_SUCCESS;
472 }
473 return NLOPT_INVALID_ARGS;
474 }
475
476 /*************************************************************************/
477
478 #define AUGLAG_ALG(a) ((a) == NLOPT_AUGLAG || \
479 (a) == NLOPT_AUGLAG_EQ || \
480 (a) == NLOPT_LN_AUGLAG || \
481 (a) == NLOPT_LN_AUGLAG_EQ || \
482 (a) == NLOPT_LD_AUGLAG || \
483 (a) == NLOPT_LD_AUGLAG_EQ)
484
nlopt_remove_inequality_constraints(nlopt_opt opt)485 nlopt_result NLOPT_STDCALL nlopt_remove_inequality_constraints(nlopt_opt opt)
486 {
487 unsigned i;
488 nlopt_unset_errmsg(opt);
489 if (!opt)
490 return NLOPT_INVALID_ARGS;
491 if (opt->munge_on_destroy) {
492 nlopt_munge munge = opt->munge_on_destroy;
493 for (i = 0; i < opt->m; ++i)
494 munge(opt->fc[i].f_data);
495 }
496 for (i = 0; i < opt->m; ++i)
497 free(opt->fc[i].tol);
498 free(opt->fc);
499 opt->fc = NULL;
500 opt->m = opt->m_alloc = 0;
501 return NLOPT_SUCCESS;
502 }
503
add_constraint(nlopt_opt opt,unsigned * m,unsigned * m_alloc,nlopt_constraint ** c,unsigned fm,nlopt_func fc,nlopt_mfunc mfc,nlopt_precond pre,void * fc_data,const double * tol)504 static nlopt_result add_constraint(nlopt_opt opt,
505 unsigned *m, unsigned *m_alloc, nlopt_constraint ** c, unsigned fm, nlopt_func fc, nlopt_mfunc mfc, nlopt_precond pre, void *fc_data, const double *tol)
506 {
507 double *tolcopy;
508 unsigned i;
509
510 if ((fc && mfc) || (fc && fm != 1) || (!fc && !mfc))
511 return NLOPT_INVALID_ARGS;
512 if (tol)
513 for (i = 0; i < fm; ++i)
514 if (tol[i] < 0)
515 return ERR(NLOPT_INVALID_ARGS, opt, "negative constraint tolerance");
516
517 tolcopy = (double *) malloc(sizeof(double) * fm);
518 if (fm && !tolcopy)
519 return NLOPT_OUT_OF_MEMORY;
520 if (tol)
521 memcpy(tolcopy, tol, sizeof(double) * fm);
522 else
523 for (i = 0; i < fm; ++i)
524 tolcopy[i] = 0;
525
526 *m += 1;
527 if (*m > *m_alloc) {
528 /* allocate by repeated doubling so that
529 we end up with O(log m) mallocs rather than O(m). */
530 *m_alloc = 2 * (*m);
531 *c = (nlopt_constraint *) realloc(*c, sizeof(nlopt_constraint)
532 * (*m_alloc));
533 if (!*c) {
534 *m_alloc = *m = 0;
535 free(tolcopy);
536 return NLOPT_OUT_OF_MEMORY;
537 }
538 }
539
540 (*c)[*m - 1].m = fm;
541 (*c)[*m - 1].f = fc;
542 (*c)[*m - 1].pre = pre;
543 (*c)[*m - 1].mf = mfc;
544 (*c)[*m - 1].f_data = fc_data;
545 (*c)[*m - 1].tol = tolcopy;
546 return NLOPT_SUCCESS;
547 }
548
inequality_ok(nlopt_algorithm algorithm)549 static int inequality_ok(nlopt_algorithm algorithm)
550 {
551 /* nonlinear constraints are only supported with some algorithms */
552 return (algorithm == NLOPT_LD_MMA || algorithm == NLOPT_LD_CCSAQ || algorithm == NLOPT_LD_SLSQP || algorithm == NLOPT_LN_COBYLA || AUGLAG_ALG(algorithm)
553 || algorithm == NLOPT_GN_ISRES || algorithm == NLOPT_GN_ORIG_DIRECT || algorithm == NLOPT_GN_ORIG_DIRECT_L || algorithm == NLOPT_GN_AGS);
554 }
555
nlopt_add_inequality_mconstraint(nlopt_opt opt,unsigned m,nlopt_mfunc fc,void * fc_data,const double * tol)556 nlopt_result NLOPT_STDCALL nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol)
557 {
558 nlopt_result ret;
559 nlopt_unset_errmsg(opt);
560 if (!m) { /* empty constraints are always ok */
561 if (opt && opt->munge_on_destroy)
562 opt->munge_on_destroy(fc_data);
563 return NLOPT_SUCCESS;
564 }
565 if (!opt)
566 ret = NLOPT_INVALID_ARGS;
567 else if (!inequality_ok(opt->algorithm))
568 ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
569 else
570 ret = add_constraint(opt, &opt->m, &opt->m_alloc, &opt->fc, m, NULL, fc, NULL, fc_data, tol);
571 if (ret < 0 && opt && opt->munge_on_destroy)
572 opt->munge_on_destroy(fc_data);
573 return ret;
574 }
575
nlopt_add_precond_inequality_constraint(nlopt_opt opt,nlopt_func fc,nlopt_precond pre,void * fc_data,double tol)576 nlopt_result NLOPT_STDCALL nlopt_add_precond_inequality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol)
577 {
578 nlopt_result ret;
579 nlopt_unset_errmsg(opt);
580 if (!opt)
581 ret = NLOPT_INVALID_ARGS;
582 else if (!inequality_ok(opt->algorithm))
583 ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
584 else
585 ret = add_constraint(opt, &opt->m, &opt->m_alloc, &opt->fc, 1, fc, NULL, pre, fc_data, &tol);
586 if (ret < 0 && opt && opt->munge_on_destroy)
587 opt->munge_on_destroy(fc_data);
588 return ret;
589 }
590
nlopt_add_inequality_constraint(nlopt_opt opt,nlopt_func fc,void * fc_data,double tol)591 nlopt_result NLOPT_STDCALL nlopt_add_inequality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol)
592 {
593 return nlopt_add_precond_inequality_constraint(opt, fc, NULL, fc_data, tol);
594 }
595
nlopt_remove_equality_constraints(nlopt_opt opt)596 nlopt_result NLOPT_STDCALL nlopt_remove_equality_constraints(nlopt_opt opt)
597 {
598 unsigned i;
599 nlopt_unset_errmsg(opt);
600 if (!opt)
601 return NLOPT_INVALID_ARGS;
602 if (opt->munge_on_destroy) {
603 nlopt_munge munge = opt->munge_on_destroy;
604 for (i = 0; i < opt->p; ++i)
605 munge(opt->h[i].f_data);
606 }
607 for (i = 0; i < opt->p; ++i)
608 free(opt->h[i].tol);
609 free(opt->h);
610 opt->h = NULL;
611 opt->p = opt->p_alloc = 0;
612 return NLOPT_SUCCESS;
613 }
614
equality_ok(nlopt_algorithm algorithm)615 static int equality_ok(nlopt_algorithm algorithm)
616 {
617 /* equality constraints (h(x) = 0) only via some algorithms */
618 return (AUGLAG_ALG(algorithm)
619 || algorithm == NLOPT_LD_SLSQP || algorithm == NLOPT_GN_ISRES || algorithm == NLOPT_LN_COBYLA);
620 }
621
nlopt_add_equality_mconstraint(nlopt_opt opt,unsigned m,nlopt_mfunc fc,void * fc_data,const double * tol)622 nlopt_result NLOPT_STDCALL nlopt_add_equality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol)
623 {
624 nlopt_result ret;
625 nlopt_unset_errmsg(opt);
626 if (!m) { /* empty constraints are always ok */
627 if (opt && opt->munge_on_destroy)
628 opt->munge_on_destroy(fc_data);
629 return NLOPT_SUCCESS;
630 }
631 if (!opt)
632 ret = NLOPT_INVALID_ARGS;
633 else if (!equality_ok(opt->algorithm))
634 ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
635 else if (nlopt_count_constraints(opt->p, opt->h) + m > opt->n)
636 ret = ERR(NLOPT_INVALID_ARGS, opt, "too many equality constraints");
637 else
638 ret = add_constraint(opt, &opt->p, &opt->p_alloc, &opt->h, m, NULL, fc, NULL, fc_data, tol);
639 if (ret < 0 && opt && opt->munge_on_destroy)
640 opt->munge_on_destroy(fc_data);
641 return ret;
642 }
643
nlopt_add_precond_equality_constraint(nlopt_opt opt,nlopt_func fc,nlopt_precond pre,void * fc_data,double tol)644 nlopt_result NLOPT_STDCALL nlopt_add_precond_equality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol)
645 {
646 nlopt_result ret;
647 nlopt_unset_errmsg(opt);
648 if (!opt)
649 ret = NLOPT_INVALID_ARGS;
650 else if (!equality_ok(opt->algorithm))
651 ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
652 else if (nlopt_count_constraints(opt->p, opt->h) + 1 > opt->n)
653 ret = ERR(NLOPT_INVALID_ARGS, opt, "too many equality constraints");
654 else
655 ret = add_constraint(opt, &opt->p, &opt->p_alloc, &opt->h, 1, fc, NULL, pre, fc_data, &tol);
656 if (ret < 0 && opt && opt->munge_on_destroy)
657 opt->munge_on_destroy(fc_data);
658 return ret;
659 }
660
nlopt_add_equality_constraint(nlopt_opt opt,nlopt_func fc,void * fc_data,double tol)661 nlopt_result NLOPT_STDCALL nlopt_add_equality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol)
662 {
663 return nlopt_add_precond_equality_constraint(opt, fc, NULL, fc_data, tol);
664 }
665
666 /*************************************************************************/
667
668 #define SET(param, T, arg) \
669 nlopt_result NLOPT_STDCALL nlopt_set_##param(nlopt_opt opt, T arg) \
670 { \
671 if (opt) { \
672 nlopt_unset_errmsg(opt); \
673 opt->arg = arg; \
674 return NLOPT_SUCCESS; \
675 } \
676 return NLOPT_INVALID_ARGS; \
677 }
678
679
680 #define GET(param, T, arg) T NLOPT_STDCALL \
681 nlopt_get_##param(const nlopt_opt opt) { \
682 return opt->arg; \
683 }
684
685 #define GETSET(param, T, arg) GET(param, T, arg) SET(param, T, arg)
686
GETSET(stopval,double,stopval)687 GETSET(stopval, double, stopval)
688
689 GETSET(ftol_rel, double, ftol_rel) GETSET(ftol_abs, double, ftol_abs) GETSET(xtol_rel, double, xtol_rel)
690 nlopt_result NLOPT_STDCALL nlopt_set_xtol_abs(nlopt_opt opt, const double *xtol_abs)
691 {
692 if (opt) {
693 nlopt_unset_errmsg(opt);
694 if (!opt->xtol_abs && opt->n > 0) {
695 opt->xtol_abs = (double *) calloc(opt->n, sizeof(double));
696 if (!opt->xtol_abs) return NLOPT_OUT_OF_MEMORY;
697 }
698 memcpy(opt->xtol_abs, xtol_abs, opt->n * sizeof(double));
699 return NLOPT_SUCCESS;
700 }
701 return NLOPT_INVALID_ARGS;
702 }
703
nlopt_set_xtol_abs1(nlopt_opt opt,double xtol_abs)704 nlopt_result NLOPT_STDCALL nlopt_set_xtol_abs1(nlopt_opt opt, double xtol_abs)
705 {
706 if (opt) {
707 unsigned i;
708 nlopt_unset_errmsg(opt);
709 if (!opt->xtol_abs && opt->n > 0) {
710 opt->xtol_abs = (double *) calloc(opt->n, sizeof(double));
711 if (!opt->xtol_abs) return NLOPT_OUT_OF_MEMORY;
712 }
713 for (i = 0; i < opt->n; ++i)
714 opt->xtol_abs[i] = xtol_abs;
715 return NLOPT_SUCCESS;
716 }
717 return NLOPT_INVALID_ARGS;
718 }
719
nlopt_get_xtol_abs(const nlopt_opt opt,double * xtol_abs)720 nlopt_result NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs)
721 {
722 nlopt_unset_errmsg(opt);
723 if (opt && (opt->n == 0 || xtol_abs)) {
724 if (opt->xtol_abs) {
725 memcpy(xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
726 } else {
727 unsigned i;
728 for (i = 0; i < opt->n; ++i)
729 xtol_abs[i] = 0;
730 }
731 return NLOPT_SUCCESS;
732 }
733 return NLOPT_INVALID_ARGS;
734 }
735
nlopt_set_x_weights(nlopt_opt opt,const double * x_weights)736 nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_weights)
737 {
738 if (opt) {
739 unsigned i;
740 nlopt_unset_errmsg(opt);
741 for (i = 0; i < opt->n; i++)
742 if (x_weights[i] < 0)
743 return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight");
744 if (!opt->x_weights && opt->n > 0) {
745 opt->x_weights = (double *) calloc(opt->n, sizeof(double));
746 if (!opt->x_weights) return NLOPT_OUT_OF_MEMORY;
747 }
748 if (opt->n > 0) memcpy(opt->x_weights, x_weights, opt->n * sizeof(double));
749 return NLOPT_SUCCESS;
750 }
751 return NLOPT_INVALID_ARGS;
752 }
753
nlopt_set_x_weights1(nlopt_opt opt,double x_weight)754 nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weight)
755 {
756 if (opt) {
757 unsigned i;
758 if (x_weight < 0) return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight");
759 nlopt_unset_errmsg(opt);
760 if (!opt->x_weights && opt->n > 0) {
761 opt->x_weights = (double *) calloc(opt->n, sizeof(double));
762 if (!opt->x_weights) return NLOPT_OUT_OF_MEMORY;
763 }
764 for (i = 0; i < opt->n; ++i)
765 opt->x_weights[i] = x_weight;
766 return NLOPT_SUCCESS;
767 }
768 return NLOPT_INVALID_ARGS;
769 }
770
nlopt_get_x_weights(const nlopt_opt opt,double * x_weights)771 nlopt_result NLOPT_STDCALL nlopt_get_x_weights(const nlopt_opt opt, double *x_weights)
772 {
773 if (opt) {
774 if (opt->n > 0 && !x_weights) return ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL weights");
775 nlopt_unset_errmsg(opt);
776 if (opt->x_weights) {
777 memcpy(x_weights, opt->x_weights, sizeof(double) * (opt->n));
778 } else {
779 unsigned i;
780 for (i = 0; i < opt->n; ++i)
781 x_weights[i] = 1;
782 }
783 return NLOPT_SUCCESS;
784 }
785 return NLOPT_INVALID_ARGS;
786 }
787
GETSET(maxeval,int,maxeval)788 GETSET(maxeval, int, maxeval)
789
790 GET(numevals, int, numevals)
791 GETSET(maxtime, double, maxtime)
792
793 /*************************************************************************/
794 nlopt_result NLOPT_STDCALL nlopt_set_force_stop(nlopt_opt opt, int force_stop)
795 {
796 if (opt) {
797 nlopt_unset_errmsg(opt);
798 opt->force_stop = force_stop;
799 if (opt->force_stop_child)
800 return nlopt_set_force_stop(opt->force_stop_child, force_stop);
801 return NLOPT_SUCCESS;
802 }
803 return NLOPT_INVALID_ARGS;
804 }
805
GET(force_stop,int,force_stop)806 GET(force_stop, int, force_stop)
807 nlopt_result NLOPT_STDCALL nlopt_force_stop(nlopt_opt opt)
808 {
809 return nlopt_set_force_stop(opt, 1);
810 }
811
812 /*************************************************************************/
813
GET(algorithm,nlopt_algorithm,algorithm)814 GET(algorithm, nlopt_algorithm, algorithm)
815 GET(dimension, unsigned, n)
816
817 /*************************************************************************/
818 nlopt_result NLOPT_STDCALL nlopt_set_local_optimizer(nlopt_opt opt, const nlopt_opt local_opt)
819 {
820 if (opt) {
821 nlopt_unset_errmsg(opt);
822 if (local_opt && local_opt->n != opt->n)
823 return ERR(NLOPT_INVALID_ARGS, opt, "dimension mismatch in local optimizer");
824 nlopt_destroy(opt->local_opt);
825 opt->local_opt = nlopt_copy(local_opt);
826 if (local_opt) {
827 if (!opt->local_opt)
828 return NLOPT_OUT_OF_MEMORY;
829 nlopt_set_lower_bounds(opt->local_opt, opt->lb);
830 nlopt_set_upper_bounds(opt->local_opt, opt->ub);
831 nlopt_remove_inequality_constraints(opt->local_opt);
832 nlopt_remove_equality_constraints(opt->local_opt);
833 nlopt_set_min_objective(opt->local_opt, NULL, NULL);
834 nlopt_set_munge(opt->local_opt, NULL, NULL);
835 opt->local_opt->force_stop = 0;
836 }
837 return NLOPT_SUCCESS;
838 }
839 return NLOPT_INVALID_ARGS;
840 }
841
842 /*************************************************************************/
843
GETSET(population,unsigned,stochastic_population)844 GETSET(population, unsigned, stochastic_population)
845 GETSET(vector_storage, unsigned, vector_storage)
846
847 /*************************************************************************/
848 nlopt_result NLOPT_STDCALL nlopt_set_initial_step1(nlopt_opt opt, double dx)
849 {
850 unsigned i;
851 if (!opt)
852 return NLOPT_INVALID_ARGS;
853 nlopt_unset_errmsg(opt);
854 if (dx == 0)
855 return ERR(NLOPT_INVALID_ARGS, opt, "zero step size");
856 if (!opt->dx && opt->n > 0) {
857 opt->dx = (double *) malloc(sizeof(double) * (opt->n));
858 if (!opt->dx)
859 return NLOPT_OUT_OF_MEMORY;
860 }
861 for (i = 0; i < opt->n; ++i)
862 opt->dx[i] = dx;
863 return NLOPT_SUCCESS;
864 }
865
nlopt_set_initial_step(nlopt_opt opt,const double * dx)866 nlopt_result NLOPT_STDCALL nlopt_set_initial_step(nlopt_opt opt, const double *dx)
867 {
868 unsigned i;
869 if (!opt)
870 return NLOPT_INVALID_ARGS;
871 nlopt_unset_errmsg(opt);
872 if (!dx) {
873 free(opt->dx);
874 opt->dx = NULL;
875 return NLOPT_SUCCESS;
876 }
877 for (i = 0; i < opt->n; ++i)
878 if (dx[i] == 0)
879 return ERR(NLOPT_INVALID_ARGS, opt, "zero step size");
880 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
881 return NLOPT_OUT_OF_MEMORY;
882 memcpy(opt->dx, dx, sizeof(double) * (opt->n));
883 return NLOPT_SUCCESS;
884 }
885
nlopt_get_initial_step(const nlopt_opt opt,const double * x,double * dx)886 nlopt_result NLOPT_STDCALL nlopt_get_initial_step(const nlopt_opt opt, const double *x, double *dx)
887 {
888 if (!opt)
889 return NLOPT_INVALID_ARGS;
890 nlopt_unset_errmsg(opt);
891 if (!opt->n)
892 return NLOPT_SUCCESS;
893 if (!opt->dx) {
894 nlopt_opt o = (nlopt_opt) opt; /* discard const temporarily */
895 nlopt_result ret = nlopt_set_default_initial_step(o, x);
896 if (ret != NLOPT_SUCCESS)
897 return ret;
898 memcpy(dx, o->dx, sizeof(double) * (opt->n));
899 free(o->dx);
900 o->dx = NULL; /* don't save, since x-dependent */
901 } else
902 memcpy(dx, opt->dx, sizeof(double) * (opt->n));
903 return NLOPT_SUCCESS;
904 }
905
nlopt_set_default_initial_step(nlopt_opt opt,const double * x)906 nlopt_result NLOPT_STDCALL nlopt_set_default_initial_step(nlopt_opt opt, const double *x)
907 {
908 const double *lb, *ub;
909 unsigned i;
910
911 nlopt_unset_errmsg(opt);
912 if (!opt || !x)
913 return NLOPT_INVALID_ARGS;
914 lb = opt->lb;
915 ub = opt->ub;
916
917 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
918 return NLOPT_OUT_OF_MEMORY;
919
920 /* crude heuristics for initial step size of nonderivative algorithms */
921 for (i = 0; i < opt->n; ++i) {
922 double step = HUGE_VAL;
923
924 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i])
925 && (ub[i] - lb[i]) * 0.25 < step && ub[i] > lb[i])
926 step = (ub[i] - lb[i]) * 0.25;
927 if (!nlopt_isinf(ub[i])
928 && ub[i] - x[i] < step && ub[i] > x[i])
929 step = (ub[i] - x[i]) * 0.75;
930 if (!nlopt_isinf(lb[i])
931 && x[i] - lb[i] < step && x[i] > lb[i])
932 step = (x[i] - lb[i]) * 0.75;
933
934 if (nlopt_isinf(step)) {
935 if (!nlopt_isinf(ub[i])
936 && fabs(ub[i] - x[i]) < fabs(step))
937 step = (ub[i] - x[i]) * 1.1;
938 if (!nlopt_isinf(lb[i])
939 && fabs(x[i] - lb[i]) < fabs(step))
940 step = (x[i] - lb[i]) * 1.1;
941 }
942 if (nlopt_isinf(step) || nlopt_istiny(step)) {
943 step = x[i];
944 }
945 if (nlopt_isinf(step) || step == 0.0)
946 step = 1;
947
948 opt->dx[i] = step;
949 }
950 return NLOPT_SUCCESS;
951 }
952
953 /*************************************************************************/
954
nlopt_set_munge(nlopt_opt opt,nlopt_munge munge_on_destroy,nlopt_munge munge_on_copy)955 void NLOPT_STDCALL nlopt_set_munge(nlopt_opt opt, nlopt_munge munge_on_destroy, nlopt_munge munge_on_copy)
956 {
957 if (opt) {
958 opt->munge_on_destroy = munge_on_destroy;
959 opt->munge_on_copy = munge_on_copy;
960 }
961 }
962
nlopt_munge_data(nlopt_opt opt,nlopt_munge2 munge,void * data)963 void NLOPT_STDCALL nlopt_munge_data(nlopt_opt opt, nlopt_munge2 munge, void *data)
964 {
965 if (opt && munge) {
966 unsigned i;
967 opt->f_data = munge(opt->f_data, data);
968 for (i = 0; i < opt->m; ++i)
969 opt->fc[i].f_data = munge(opt->fc[i].f_data, data);
970 for (i = 0; i < opt->p; ++i)
971 opt->h[i].f_data = munge(opt->h[i].f_data, data);
972 }
973 }
974
975 /*************************************************************************/
976
nlopt_set_errmsg(nlopt_opt opt,const char * format,...)977 const char *nlopt_set_errmsg(nlopt_opt opt, const char *format, ...)
978 {
979 va_list ap;
980 va_start(ap, format);
981 opt->errmsg = nlopt_vsprintf(opt->errmsg, format, ap);
982 va_end(ap);
983 return opt->errmsg;
984 }
985
nlopt_unset_errmsg(nlopt_opt opt)986 void nlopt_unset_errmsg(nlopt_opt opt)
987 {
988 if (opt) {
989 free(opt->errmsg);
990 opt->errmsg = NULL;
991 }
992 }
993
nlopt_get_errmsg(nlopt_opt opt)994 const char *nlopt_get_errmsg(nlopt_opt opt)
995 {
996 return opt->errmsg;
997 }
998
999 /*************************************************************************/
1000