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