1 /* Copyright (c) 2007-2014 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.
30 #include "nlopt-internal.h"
32 /*************************************************************************/
34 void NLOPT_STDCALL nlopt_destroy(nlopt_opt opt)
38 if (opt->munge_on_destroy) {
39 nlopt_munge munge = opt->munge_on_destroy;
41 for (i = 0; i < opt->m; ++i)
42 munge(opt->fc[i].f_data);
43 for (i = 0; i < opt->p; ++i)
44 munge(opt->h[i].f_data);
46 for (i = 0; i < opt->m; ++i)
48 for (i = 0; i < opt->p; ++i)
50 free(opt->lb); free(opt->ub);
54 nlopt_destroy(opt->local_opt);
62 nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n)
66 if (((int) algorithm) < 0 || algorithm >= NLOPT_NUM_ALGORITHMS)
69 opt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
71 opt->algorithm = algorithm;
73 opt->f = NULL; opt->f_data = NULL; opt->pre = NULL;
75 opt->munge_on_destroy = opt->munge_on_copy = NULL;
77 opt->lb = opt->ub = NULL;
78 opt->m = opt->m_alloc = 0;
80 opt->p = opt->p_alloc = 0;
83 opt->stopval = -HUGE_VAL;
84 opt->ftol_rel = opt->ftol_abs = 0;
85 opt->xtol_rel = 0; opt->xtol_abs = NULL;
89 opt->force_stop_child = NULL;
91 opt->local_opt = NULL;
92 opt->stochastic_population = 0;
93 opt->vector_storage = 0;
99 opt->lb = (double *) malloc(sizeof(double) * (n));
100 if (!opt->lb) goto oom;
101 opt->ub = (double *) malloc(sizeof(double) * (n));
102 if (!opt->ub) goto oom;
103 opt->xtol_abs = (double *) malloc(sizeof(double) * (n));
104 if (!opt->xtol_abs) goto oom;
105 nlopt_set_lower_bounds1(opt, -HUGE_VAL);
106 nlopt_set_upper_bounds1(opt, +HUGE_VAL);
107 nlopt_set_xtol_abs1(opt, 0.0);
118 nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
120 nlopt_opt nopt = NULL;
124 nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
126 nopt->lb = nopt->ub = nopt->xtol_abs = NULL;
127 nopt->fc = nopt->h = NULL;
128 nopt->m_alloc = nopt->p_alloc = 0;
129 nopt->local_opt = NULL;
133 nopt->force_stop_child = NULL;
135 munge = nopt->munge_on_copy;
136 if (munge && nopt->f_data)
137 if (!(nopt->f_data = munge(nopt->f_data))) goto oom;
140 nopt->lb = (double *) malloc(sizeof(double) * (opt->n));
141 if (!opt->lb) goto oom;
142 nopt->ub = (double *) malloc(sizeof(double) * (opt->n));
143 if (!opt->ub) goto oom;
144 nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n));
145 if (!opt->xtol_abs) goto oom;
147 memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n));
148 memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n));
149 memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
153 nopt->m_alloc = opt->m;
154 nopt->fc = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
156 if (!nopt->fc) goto oom;
157 memcpy(nopt->fc, opt->fc, sizeof(nlopt_constraint) * (opt->m));
158 for (i = 0; i < opt->m; ++i) nopt->fc[i].tol = NULL;
160 for (i = 0; i < opt->m; ++i)
161 if (nopt->fc[i].f_data &&
163 = munge(nopt->fc[i].f_data)))
165 for (i = 0; i < opt->m; ++i)
166 if (opt->fc[i].tol) {
167 nopt->fc[i].tol = (double *) malloc(sizeof(double)
169 if (!nopt->fc[i].tol) goto oom;
170 memcpy(nopt->fc[i].tol, opt->fc[i].tol,
171 sizeof(double) * nopt->fc[i].m);
176 nopt->p_alloc = opt->p;
177 nopt->h = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
179 if (!nopt->h) goto oom;
180 memcpy(nopt->h, opt->h, sizeof(nlopt_constraint) * (opt->p));
181 for (i = 0; i < opt->p; ++i) nopt->h[i].tol = NULL;
183 for (i = 0; i < opt->p; ++i)
184 if (nopt->h[i].f_data &&
186 = munge(nopt->h[i].f_data)))
188 for (i = 0; i < opt->p; ++i)
190 nopt->h[i].tol = (double *) malloc(sizeof(double)
192 if (!nopt->h[i].tol) goto oom;
193 memcpy(nopt->h[i].tol, opt->h[i].tol,
194 sizeof(double) * nopt->h[i].m);
198 if (opt->local_opt) {
199 nopt->local_opt = nlopt_copy(opt->local_opt);
200 if (!nopt->local_opt) goto oom;
204 nopt->dx = (double *) malloc(sizeof(double) * (opt->n));
205 if (!nopt->dx) goto oom;
206 memcpy(nopt->dx, opt->dx, sizeof(double) * (opt->n));
212 nopt->munge_on_destroy = NULL; // better to leak mem than crash
217 /*************************************************************************/
219 nlopt_result NLOPT_STDCALL nlopt_set_precond_min_objective(nlopt_opt opt,
225 if (opt->munge_on_destroy) opt->munge_on_destroy(opt->f_data);
226 opt->f = f; opt->f_data = f_data; opt->pre = pre;
228 if (nlopt_isinf(opt->stopval) && opt->stopval > 0)
229 opt->stopval = -HUGE_VAL; /* switch default from max to min */
230 return NLOPT_SUCCESS;
232 return NLOPT_INVALID_ARGS;
235 nlopt_result NLOPT_STDCALL nlopt_set_min_objective(nlopt_opt opt,
236 nlopt_func f, void *f_data)
238 return nlopt_set_precond_min_objective(opt, f, NULL, f_data);
241 nlopt_result NLOPT_STDCALL nlopt_set_precond_max_objective(nlopt_opt opt,
247 if (opt->munge_on_destroy) opt->munge_on_destroy(opt->f_data);
248 opt->f = f; opt->f_data = f_data; opt->pre = pre;
250 if (nlopt_isinf(opt->stopval) && opt->stopval < 0)
251 opt->stopval = +HUGE_VAL; /* switch default from min to max */
252 return NLOPT_SUCCESS;
254 return NLOPT_INVALID_ARGS;
257 nlopt_result NLOPT_STDCALL nlopt_set_max_objective(nlopt_opt opt,
258 nlopt_func f, void *f_data)
260 return nlopt_set_precond_max_objective(opt, f, NULL, f_data);
263 /*************************************************************************/
266 NLOPT_STDCALL nlopt_set_lower_bounds(nlopt_opt opt, const double *lb)
268 if (opt && (opt->n == 0 || lb)) {
269 memcpy(opt->lb, lb, sizeof(double) * (opt->n));
270 return NLOPT_SUCCESS;
272 return NLOPT_INVALID_ARGS;
276 NLOPT_STDCALL nlopt_set_lower_bounds1(nlopt_opt opt, double lb)
280 for (i = 0; i < opt->n; ++i)
282 return NLOPT_SUCCESS;
284 return NLOPT_INVALID_ARGS;
288 NLOPT_STDCALL nlopt_get_lower_bounds(const nlopt_opt opt, double *lb)
290 if (opt && (opt->n == 0 || lb)) {
291 memcpy(lb, opt->lb, sizeof(double) * (opt->n));
292 return NLOPT_SUCCESS;
294 return NLOPT_INVALID_ARGS;
298 NLOPT_STDCALL nlopt_set_upper_bounds(nlopt_opt opt, const double *ub)
300 if (opt && (opt->n == 0 || ub)) {
301 memcpy(opt->ub, ub, sizeof(double) * (opt->n));
302 return NLOPT_SUCCESS;
304 return NLOPT_INVALID_ARGS;
308 NLOPT_STDCALL nlopt_set_upper_bounds1(nlopt_opt opt, double ub)
312 for (i = 0; i < opt->n; ++i)
314 return NLOPT_SUCCESS;
316 return NLOPT_INVALID_ARGS;
320 NLOPT_STDCALL nlopt_get_upper_bounds(const nlopt_opt opt, double *ub)
322 if (opt && (opt->n == 0 || ub)) {
323 memcpy(ub, opt->ub, sizeof(double) * (opt->n));
324 return NLOPT_SUCCESS;
326 return NLOPT_INVALID_ARGS;
329 /*************************************************************************/
331 #define AUGLAG_ALG(a) ((a) == NLOPT_AUGLAG || \
332 (a) == NLOPT_AUGLAG_EQ || \
333 (a) == NLOPT_LN_AUGLAG || \
334 (a) == NLOPT_LN_AUGLAG_EQ || \
335 (a) == NLOPT_LD_AUGLAG || \
336 (a) == NLOPT_LD_AUGLAG_EQ)
339 NLOPT_STDCALL nlopt_remove_inequality_constraints(nlopt_opt opt)
342 if (!opt) return NLOPT_INVALID_ARGS;
343 if (opt->munge_on_destroy) {
344 nlopt_munge munge = opt->munge_on_destroy;
345 for (i = 0; i < opt->m; ++i)
346 munge(opt->fc[i].f_data);
348 for (i = 0; i < opt->m; ++i)
349 free(opt->fc[i].tol);
352 opt->m = opt->m_alloc = 0;
353 return NLOPT_SUCCESS;
356 static nlopt_result add_constraint(unsigned *m, unsigned *m_alloc,
357 nlopt_constraint **c,
358 unsigned fm, nlopt_func fc, nlopt_mfunc mfc,
366 if ((fc && mfc) || (fc && fm != 1) || (!fc && !mfc))
367 return NLOPT_INVALID_ARGS;
369 for (i = 0; i < fm; ++i) if (tol[i] < 0) return NLOPT_INVALID_ARGS;
371 tolcopy = (double *) malloc(sizeof(double) * fm);
372 if (fm && !tolcopy) return NLOPT_OUT_OF_MEMORY;
374 memcpy(tolcopy, tol, sizeof(double) * fm);
376 for (i = 0; i < fm; ++i) tolcopy[i] = 0;
380 /* allocate by repeated doubling so that
381 we end up with O(log m) mallocs rather than O(m). */
383 *c = (nlopt_constraint *) realloc(*c,
384 sizeof(nlopt_constraint)
389 return NLOPT_OUT_OF_MEMORY;
395 (*c)[*m - 1].pre = pre;
396 (*c)[*m - 1].mf = mfc;
397 (*c)[*m - 1].f_data = fc_data;
398 (*c)[*m - 1].tol = tolcopy;
399 return NLOPT_SUCCESS;
402 static int inequality_ok(nlopt_algorithm algorithm) {
403 /* nonlinear constraints are only supported with some algorithms */
404 return (algorithm == NLOPT_LD_MMA || algorithm == NLOPT_LD_CCSAQ
405 || algorithm == NLOPT_LD_SLSQP
406 || algorithm == NLOPT_LN_COBYLA
407 || AUGLAG_ALG(algorithm)
408 || algorithm == NLOPT_GN_ISRES
409 || algorithm == NLOPT_GN_ORIG_DIRECT
410 || algorithm == NLOPT_GN_ORIG_DIRECT_L);
414 NLOPT_STDCALL nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m,
415 nlopt_mfunc fc, void *fc_data,
419 if (!m) { /* empty constraints are always ok */
420 if (opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data);
421 return NLOPT_SUCCESS;
423 if (!opt || !inequality_ok(opt->algorithm)) ret = NLOPT_INVALID_ARGS;
424 else ret = add_constraint(&opt->m, &opt->m_alloc, &opt->fc,
425 m, NULL, fc, NULL, fc_data, tol);
426 if (ret < 0 && opt && opt->munge_on_destroy)
427 opt->munge_on_destroy(fc_data);
432 NLOPT_STDCALL nlopt_add_precond_inequality_constraint(nlopt_opt opt,
439 if (!opt || !inequality_ok(opt->algorithm)) ret = NLOPT_INVALID_ARGS;
440 else ret = add_constraint(&opt->m, &opt->m_alloc, &opt->fc,
441 1, fc, NULL, pre, fc_data, &tol);
442 if (ret < 0 && opt && opt->munge_on_destroy)
443 opt->munge_on_destroy(fc_data);
448 NLOPT_STDCALL nlopt_add_inequality_constraint(nlopt_opt opt,
449 nlopt_func fc, void *fc_data,
452 return nlopt_add_precond_inequality_constraint(opt, fc, NULL, fc_data,
457 NLOPT_STDCALL nlopt_remove_equality_constraints(nlopt_opt opt)
460 if (!opt) return NLOPT_INVALID_ARGS;
461 if (opt->munge_on_destroy) {
462 nlopt_munge munge = opt->munge_on_destroy;
463 for (i = 0; i < opt->p; ++i)
464 munge(opt->h[i].f_data);
466 for (i = 0; i < opt->p; ++i)
470 opt->p = opt->p_alloc = 0;
471 return NLOPT_SUCCESS;
474 static int equality_ok(nlopt_algorithm algorithm) {
475 /* equality constraints (h(x) = 0) only via some algorithms */
476 return (AUGLAG_ALG(algorithm)
477 || algorithm == NLOPT_LD_SLSQP
478 || algorithm == NLOPT_GN_ISRES
479 || algorithm == NLOPT_LN_COBYLA);
483 NLOPT_STDCALL nlopt_add_equality_mconstraint(nlopt_opt opt, unsigned m,
484 nlopt_mfunc fc, void *fc_data,
488 if (!m) { /* empty constraints are always ok */
489 if (opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data);
490 return NLOPT_SUCCESS;
492 if (!opt || !equality_ok(opt->algorithm)
493 || nlopt_count_constraints(opt->p, opt->h) + m > opt->n)
494 ret = NLOPT_INVALID_ARGS;
495 else ret = add_constraint(&opt->p, &opt->p_alloc, &opt->h,
496 m, NULL, fc, NULL, fc_data, tol);
497 if (ret < 0 && opt && opt->munge_on_destroy)
498 opt->munge_on_destroy(fc_data);
503 NLOPT_STDCALL nlopt_add_precond_equality_constraint(nlopt_opt opt,
510 if (!opt || !equality_ok(opt->algorithm)
511 || nlopt_count_constraints(opt->p, opt->h) + 1 > opt->n)
512 ret = NLOPT_INVALID_ARGS;
513 else ret = add_constraint(&opt->p, &opt->p_alloc, &opt->h,
514 1, fc, NULL, pre, fc_data, &tol);
515 if (ret < 0 && opt && opt->munge_on_destroy)
516 opt->munge_on_destroy(fc_data);
521 NLOPT_STDCALL nlopt_add_equality_constraint(nlopt_opt opt,
522 nlopt_func fc, void *fc_data,
525 return nlopt_add_precond_equality_constraint(opt, fc, NULL, fc_data, tol);
528 /*************************************************************************/
530 #define SET(param, T, arg) \
531 nlopt_result NLOPT_STDCALL nlopt_set_##param(nlopt_opt opt, T arg) \
535 return NLOPT_SUCCESS; \
537 return NLOPT_INVALID_ARGS; \
541 #define GET(param, T, arg) T NLOPT_STDCALL \
542 nlopt_get_##param(const nlopt_opt opt) { \
546 #define GETSET(param, T, arg) GET(param, T, arg) SET(param, T, arg)
548 GETSET(stopval, double, stopval)
550 GETSET(ftol_rel, double, ftol_rel)
551 GETSET(ftol_abs, double, ftol_abs)
552 GETSET(xtol_rel, double, xtol_rel)
555 NLOPT_STDCALL nlopt_set_xtol_abs(nlopt_opt opt, const double *xtol_abs)
558 memcpy(opt->xtol_abs, xtol_abs, opt->n * sizeof(double));
559 return NLOPT_SUCCESS;
561 return NLOPT_INVALID_ARGS;
565 NLOPT_STDCALL nlopt_set_xtol_abs1(nlopt_opt opt, double xtol_abs)
569 for (i = 0; i < opt->n; ++i)
570 opt->xtol_abs[i] = xtol_abs;
571 return NLOPT_SUCCESS;
573 return NLOPT_INVALID_ARGS;
577 NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs)
579 memcpy(xtol_abs, opt->xtol_abs, opt->n * sizeof(double));
580 return NLOPT_SUCCESS;
583 GETSET(maxeval, int, maxeval)
585 GETSET(maxtime, double, maxtime)
587 /*************************************************************************/
590 NLOPT_STDCALL nlopt_set_force_stop(nlopt_opt opt, int force_stop)
593 opt->force_stop = force_stop;
594 if (opt->force_stop_child)
595 return nlopt_set_force_stop(opt->force_stop_child, force_stop);
596 return NLOPT_SUCCESS;
598 return NLOPT_INVALID_ARGS;
601 GET(force_stop, int, force_stop)
602 nlopt_result NLOPT_STDCALL nlopt_force_stop(nlopt_opt opt) {
603 return nlopt_set_force_stop(opt, 1);
606 /*************************************************************************/
608 GET(algorithm, nlopt_algorithm, algorithm)
609 GET(dimension, unsigned, n)
611 /*************************************************************************/
614 NLOPT_STDCALL nlopt_set_local_optimizer(nlopt_opt opt,
615 const nlopt_opt local_opt)
618 if (local_opt && local_opt->n != opt->n) return NLOPT_INVALID_ARGS;
619 nlopt_destroy(opt->local_opt);
620 opt->local_opt = nlopt_copy(local_opt);
622 if (!opt->local_opt) return NLOPT_OUT_OF_MEMORY;
623 nlopt_set_lower_bounds(opt->local_opt, opt->lb);
624 nlopt_set_upper_bounds(opt->local_opt, opt->ub);
625 nlopt_remove_inequality_constraints(opt->local_opt);
626 nlopt_remove_equality_constraints(opt->local_opt);
627 nlopt_set_min_objective(opt->local_opt, NULL, NULL);
628 nlopt_set_munge(opt->local_opt, NULL, NULL);
629 opt->local_opt->force_stop = 0;
631 return NLOPT_SUCCESS;
633 return NLOPT_INVALID_ARGS;
636 /*************************************************************************/
638 GETSET(population, unsigned, stochastic_population)
639 GETSET(vector_storage, unsigned, vector_storage)
641 /*************************************************************************/
643 nlopt_result NLOPT_STDCALL nlopt_set_initial_step1(nlopt_opt opt, double dx)
646 if (!opt || dx == 0) return NLOPT_INVALID_ARGS;
647 if (!opt->dx && opt->n > 0) {
648 opt->dx = (double *) malloc(sizeof(double) * (opt->n));
649 if (!opt->dx) return NLOPT_OUT_OF_MEMORY;
651 for (i = 0; i < opt->n; ++i) opt->dx[i] = dx;
652 return NLOPT_SUCCESS;
656 NLOPT_STDCALL nlopt_set_initial_step(nlopt_opt opt, const double *dx)
659 if (!opt) return NLOPT_INVALID_ARGS;
661 free(opt->dx); opt->dx = NULL;
662 return NLOPT_SUCCESS;
664 for (i = 0; i < opt->n; ++i) if (dx[i] == 0) return NLOPT_INVALID_ARGS;
665 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
666 return NLOPT_OUT_OF_MEMORY;
667 memcpy(opt->dx, dx, sizeof(double) * (opt->n));
668 return NLOPT_SUCCESS;
672 NLOPT_STDCALL nlopt_get_initial_step(const nlopt_opt opt, const double *x,
675 if (!opt) return NLOPT_INVALID_ARGS;
676 if (!opt->n) return NLOPT_SUCCESS;
678 nlopt_opt o = (nlopt_opt) opt; /* discard const temporarily */
679 nlopt_result ret = nlopt_set_default_initial_step(o, x);
680 if (ret != NLOPT_SUCCESS) return ret;
681 memcpy(dx, o->dx, sizeof(double) * (opt->n));
682 free(o->dx); o->dx = NULL; /* don't save, since x-dependent */
685 memcpy(dx, opt->dx, sizeof(double) * (opt->n));
686 return NLOPT_SUCCESS;
690 NLOPT_STDCALL nlopt_set_default_initial_step(nlopt_opt opt, const double *x)
692 const double *lb, *ub;
695 if (!opt || !x) return NLOPT_INVALID_ARGS;
696 lb = opt->lb; ub = opt->ub;
698 if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
699 return NLOPT_OUT_OF_MEMORY;
701 /* crude heuristics for initial step size of nonderivative algorithms */
702 for (i = 0; i < opt->n; ++i) {
703 double step = HUGE_VAL;
705 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i])
706 && (ub[i] - lb[i]) * 0.25 < step && ub[i] > lb[i])
707 step = (ub[i] - lb[i]) * 0.25;
708 if (!nlopt_isinf(ub[i])
709 && ub[i] - x[i] < step && ub[i] > x[i])
710 step = (ub[i] - x[i]) * 0.75;
711 if (!nlopt_isinf(lb[i])
712 && x[i] - lb[i] < step && x[i] > lb[i])
713 step = (x[i] - lb[i]) * 0.75;
715 if (nlopt_isinf(step)) {
716 if (!nlopt_isinf(ub[i])
717 && fabs(ub[i] - x[i]) < fabs(step))
718 step = (ub[i] - x[i]) * 1.1;
719 if (!nlopt_isinf(lb[i])
720 && fabs(x[i] - lb[i]) < fabs(step))
721 step = (x[i] - lb[i]) * 1.1;
723 if (nlopt_isinf(step) || step == 0) {
726 if (nlopt_isinf(step) || step == 0)
731 return NLOPT_SUCCESS;
734 /*************************************************************************/
736 void NLOPT_STDCALL nlopt_set_munge(nlopt_opt opt,
737 nlopt_munge munge_on_destroy,
738 nlopt_munge munge_on_copy) {
740 opt->munge_on_destroy = munge_on_destroy;
741 opt->munge_on_copy = munge_on_copy;
745 void NLOPT_STDCALL nlopt_munge_data(nlopt_opt opt,
746 nlopt_munge2 munge, void *data) {
749 opt->f_data = munge(opt->f_data, data);
750 for (i = 0; i < opt->m; ++i)
751 opt->fc[i].f_data = munge(opt->fc[i].f_data, data);
752 for (i = 0; i < opt->p; ++i)
753 opt->h[i].f_data = munge(opt->h[i].f_data, data);
757 /*************************************************************************/
759 const char *nlopt_set_errmsg(nlopt_opt opt, const char *format, ...)
762 va_start(ap, format);
763 opt->errmsg = nlopt_vsprintf(opt->errmsg, format, ap);
768 void nlopt_unset_errmsg(nlopt_opt opt)
774 const char *nlopt_get_errmsg(nlopt_opt opt)
779 /*************************************************************************/