chiark / gitweb /
untabify source files, make indenting more uniform with GNU indent -kr --no-tabs...
[nlopt.git] / src / api / options.c
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
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         free(opt->lb);
53         free(opt->ub);
54         free(opt->xtol_abs);
55         free(opt->fc);
56         free(opt->h);
57         nlopt_destroy(opt->local_opt);
58         free(opt->dx);
59         free(opt->work);
60         free(opt->errmsg);
61         free(opt);
62     }
63 }
64
65 nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n)
66 {
67     nlopt_opt opt;
68
69     if (((int) algorithm) < 0 || algorithm >= NLOPT_NUM_ALGORITHMS)
70         return NULL;
71
72     opt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
73     if (opt) {
74         opt->algorithm = algorithm;
75         opt->n = n;
76         opt->f = NULL;
77         opt->f_data = NULL;
78         opt->pre = NULL;
79         opt->maximize = 0;
80         opt->munge_on_destroy = opt->munge_on_copy = NULL;
81
82         opt->lb = opt->ub = NULL;
83         opt->m = opt->m_alloc = 0;
84         opt->fc = NULL;
85         opt->p = opt->p_alloc = 0;
86         opt->h = NULL;
87
88         opt->stopval = -HUGE_VAL;
89         opt->ftol_rel = opt->ftol_abs = 0;
90         opt->xtol_rel = 0;
91         opt->xtol_abs = NULL;
92         opt->maxeval = 0;
93         opt->numevals = 0;
94         opt->maxtime = 0;
95         opt->force_stop = 0;
96         opt->force_stop_child = NULL;
97
98         opt->local_opt = NULL;
99         opt->stochastic_population = 0;
100         opt->vector_storage = 0;
101         opt->dx = NULL;
102         opt->work = NULL;
103         opt->errmsg = NULL;
104
105         if (n > 0) {
106             opt->lb = (double *) calloc(n, sizeof(double));
107             if (!opt->lb)
108                 goto oom;
109             opt->ub = (double *) calloc(n, sizeof(double));
110             if (!opt->ub)
111                 goto oom;
112             opt->xtol_abs = (double *) calloc(n, sizeof(double));
113             if (!opt->xtol_abs)
114                 goto oom;
115             nlopt_set_lower_bounds1(opt, -HUGE_VAL);
116             nlopt_set_upper_bounds1(opt, +HUGE_VAL);
117             nlopt_set_xtol_abs1(opt, 0.0);
118         }
119     }
120
121     return opt;
122
123   oom:
124     nlopt_destroy(opt);
125     return NULL;
126 }
127
128 nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
129 {
130     nlopt_opt nopt = NULL;
131     unsigned i;
132     if (opt) {
133         nlopt_munge munge;
134         nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s));
135         *nopt = *opt;
136         nopt->lb = nopt->ub = nopt->xtol_abs = NULL;
137         nopt->fc = nopt->h = NULL;
138         nopt->m_alloc = nopt->p_alloc = 0;
139         nopt->local_opt = NULL;
140         nopt->dx = NULL;
141         nopt->work = NULL;
142         nopt->errmsg = NULL;
143         nopt->force_stop_child = NULL;
144
145         munge = nopt->munge_on_copy;
146         if (munge && nopt->f_data)
147             if (!(nopt->f_data = munge(nopt->f_data)))
148                 goto oom;
149
150         if (opt->n > 0) {
151             nopt->lb = (double *) malloc(sizeof(double) * (opt->n));
152             if (!opt->lb)
153                 goto oom;
154             nopt->ub = (double *) malloc(sizeof(double) * (opt->n));
155             if (!opt->ub)
156                 goto oom;
157             nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n));
158             if (!opt->xtol_abs)
159                 goto oom;
160
161             memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n));
162             memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n));
163             memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n));
164         }
165
166         if (opt->m) {
167             nopt->m_alloc = opt->m;
168             nopt->fc = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
169                                                    * (opt->m));
170             if (!nopt->fc)
171                 goto oom;
172             memcpy(nopt->fc, opt->fc, sizeof(nlopt_constraint) * (opt->m));
173             for (i = 0; i < opt->m; ++i)
174                 nopt->fc[i].tol = NULL;
175             if (munge)
176                 for (i = 0; i < opt->m; ++i)
177                     if (nopt->fc[i].f_data && !(nopt->fc[i].f_data = munge(nopt->fc[i].f_data)))
178                         goto oom;
179             for (i = 0; i < opt->m; ++i)
180                 if (opt->fc[i].tol) {
181                     nopt->fc[i].tol = (double *) malloc(sizeof(double)
182                                                         * nopt->fc[i].m);
183                     if (!nopt->fc[i].tol)
184                         goto oom;
185                     memcpy(nopt->fc[i].tol, opt->fc[i].tol, sizeof(double) * nopt->fc[i].m);
186                 }
187         }
188
189         if (opt->p) {
190             nopt->p_alloc = opt->p;
191             nopt->h = (nlopt_constraint *) malloc(sizeof(nlopt_constraint)
192                                                   * (opt->p));
193             if (!nopt->h)
194                 goto oom;
195             memcpy(nopt->h, opt->h, sizeof(nlopt_constraint) * (opt->p));
196             for (i = 0; i < opt->p; ++i)
197                 nopt->h[i].tol = NULL;
198             if (munge)
199                 for (i = 0; i < opt->p; ++i)
200                     if (nopt->h[i].f_data && !(nopt->h[i].f_data = munge(nopt->h[i].f_data)))
201                         goto oom;
202             for (i = 0; i < opt->p; ++i)
203                 if (opt->h[i].tol) {
204                     nopt->h[i].tol = (double *) malloc(sizeof(double)
205                                                        * nopt->h[i].m);
206                     if (!nopt->h[i].tol)
207                         goto oom;
208                     memcpy(nopt->h[i].tol, opt->h[i].tol, sizeof(double) * nopt->h[i].m);
209                 }
210         }
211
212         if (opt->local_opt) {
213             nopt->local_opt = nlopt_copy(opt->local_opt);
214             if (!nopt->local_opt)
215                 goto oom;
216         }
217
218         if (opt->dx) {
219             nopt->dx = (double *) malloc(sizeof(double) * (opt->n));
220             if (!nopt->dx)
221                 goto oom;
222             memcpy(nopt->dx, opt->dx, sizeof(double) * (opt->n));
223         }
224     }
225     return nopt;
226
227   oom:
228     nopt->munge_on_destroy = NULL;      /* better to leak mem than crash */
229     nlopt_destroy(nopt);
230     return NULL;
231 }
232
233 /*************************************************************************/
234
235 nlopt_result NLOPT_STDCALL nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data)
236 {
237     if (opt) {
238         nlopt_unset_errmsg(opt);
239         if (opt->munge_on_destroy)
240             opt->munge_on_destroy(opt->f_data);
241         opt->f = f;
242         opt->f_data = f_data;
243         opt->pre = pre;
244         opt->maximize = 0;
245         if (nlopt_isinf(opt->stopval) && opt->stopval > 0)
246             opt->stopval = -HUGE_VAL;   /* switch default from max to min */
247         return NLOPT_SUCCESS;
248     }
249     return NLOPT_INVALID_ARGS;
250 }
251
252 nlopt_result NLOPT_STDCALL nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void *f_data)
253 {
254     return nlopt_set_precond_min_objective(opt, f, NULL, f_data);
255 }
256
257 nlopt_result NLOPT_STDCALL nlopt_set_precond_max_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data)
258 {
259     if (opt) {
260         nlopt_unset_errmsg(opt);
261         if (opt->munge_on_destroy)
262             opt->munge_on_destroy(opt->f_data);
263         opt->f = f;
264         opt->f_data = f_data;
265         opt->pre = pre;
266         opt->maximize = 1;
267         if (nlopt_isinf(opt->stopval) && opt->stopval < 0)
268             opt->stopval = +HUGE_VAL;   /* switch default from min to max */
269         return NLOPT_SUCCESS;
270     }
271     return NLOPT_INVALID_ARGS;
272 }
273
274 nlopt_result NLOPT_STDCALL nlopt_set_max_objective(nlopt_opt opt, nlopt_func f, void *f_data)
275 {
276     return nlopt_set_precond_max_objective(opt, f, NULL, f_data);
277 }
278
279 /*************************************************************************/
280
281 nlopt_result NLOPT_STDCALL nlopt_set_lower_bounds(nlopt_opt opt, const double *lb)
282 {
283     nlopt_unset_errmsg(opt);
284     if (opt && (opt->n == 0 || lb)) {
285         unsigned int i;
286         if (opt->n > 0)
287             memcpy(opt->lb, lb, sizeof(double) * (opt->n));
288         for (i = 0; i < opt->n; ++i)
289             if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
290                 opt->lb[i] = opt->ub[i];
291         return NLOPT_SUCCESS;
292     }
293     return NLOPT_INVALID_ARGS;
294 }
295
296 nlopt_result NLOPT_STDCALL nlopt_set_lower_bounds1(nlopt_opt opt, double lb)
297 {
298     nlopt_unset_errmsg(opt);
299     if (opt) {
300         unsigned i;
301         for (i = 0; i < opt->n; ++i) {
302             opt->lb[i] = lb;
303             if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
304                 opt->lb[i] = opt->ub[i];
305         }
306         return NLOPT_SUCCESS;
307     }
308     return NLOPT_INVALID_ARGS;
309 }
310
311 nlopt_result NLOPT_STDCALL nlopt_get_lower_bounds(const nlopt_opt opt, double *lb)
312 {
313     nlopt_unset_errmsg(opt);
314     if (opt && (opt->n == 0 || lb)) {
315         memcpy(lb, opt->lb, sizeof(double) * (opt->n));
316         return NLOPT_SUCCESS;
317     }
318     return NLOPT_INVALID_ARGS;
319 }
320
321 nlopt_result NLOPT_STDCALL nlopt_set_upper_bounds(nlopt_opt opt, const double *ub)
322 {
323     nlopt_unset_errmsg(opt);
324     if (opt && (opt->n == 0 || ub)) {
325         unsigned int i;
326         if (opt->n > 0)
327             memcpy(opt->ub, ub, sizeof(double) * (opt->n));
328         for (i = 0; i < opt->n; ++i)
329             if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
330                 opt->ub[i] = opt->lb[i];
331         return NLOPT_SUCCESS;
332     }
333     return NLOPT_INVALID_ARGS;
334 }
335
336 nlopt_result NLOPT_STDCALL nlopt_set_upper_bounds1(nlopt_opt opt, double ub)
337 {
338     nlopt_unset_errmsg(opt);
339     if (opt) {
340         unsigned i;
341         for (i = 0; i < opt->n; ++i) {
342             opt->ub[i] = ub;
343             if (opt->lb[i] < opt->ub[i] && nlopt_istiny(opt->ub[i] - opt->lb[i]))
344                 opt->ub[i] = opt->lb[i];
345         }
346         return NLOPT_SUCCESS;
347     }
348     return NLOPT_INVALID_ARGS;
349 }
350
351 nlopt_result NLOPT_STDCALL nlopt_get_upper_bounds(const nlopt_opt opt, double *ub)
352 {
353     nlopt_unset_errmsg(opt);
354     if (opt && (opt->n == 0 || ub)) {
355         memcpy(ub, opt->ub, sizeof(double) * (opt->n));
356         return NLOPT_SUCCESS;
357     }
358     return NLOPT_INVALID_ARGS;
359 }
360
361 /*************************************************************************/
362
363 #define AUGLAG_ALG(a) ((a) == NLOPT_AUGLAG ||           \
364                        (a) == NLOPT_AUGLAG_EQ ||        \
365                        (a) == NLOPT_LN_AUGLAG ||        \
366                        (a) == NLOPT_LN_AUGLAG_EQ ||     \
367                        (a) == NLOPT_LD_AUGLAG ||        \
368                        (a) == NLOPT_LD_AUGLAG_EQ)
369
370 nlopt_result NLOPT_STDCALL nlopt_remove_inequality_constraints(nlopt_opt opt)
371 {
372     unsigned i;
373     nlopt_unset_errmsg(opt);
374     if (!opt)
375         return NLOPT_INVALID_ARGS;
376     if (opt->munge_on_destroy) {
377         nlopt_munge munge = opt->munge_on_destroy;
378         for (i = 0; i < opt->m; ++i)
379             munge(opt->fc[i].f_data);
380     }
381     for (i = 0; i < opt->m; ++i)
382         free(opt->fc[i].tol);
383     free(opt->fc);
384     opt->fc = NULL;
385     opt->m = opt->m_alloc = 0;
386     return NLOPT_SUCCESS;
387 }
388
389 static nlopt_result add_constraint(nlopt_opt opt,
390                                    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)
391 {
392     double *tolcopy;
393     unsigned i;
394
395     if ((fc && mfc) || (fc && fm != 1) || (!fc && !mfc))
396         return NLOPT_INVALID_ARGS;
397     if (tol)
398         for (i = 0; i < fm; ++i)
399             if (tol[i] < 0)
400                 return ERR(NLOPT_INVALID_ARGS, opt, "negative constraint tolerance");
401
402     tolcopy = (double *) malloc(sizeof(double) * fm);
403     if (fm && !tolcopy)
404         return NLOPT_OUT_OF_MEMORY;
405     if (tol)
406         memcpy(tolcopy, tol, sizeof(double) * fm);
407     else
408         for (i = 0; i < fm; ++i)
409             tolcopy[i] = 0;
410
411     *m += 1;
412     if (*m > *m_alloc) {
413         /* allocate by repeated doubling so that 
414            we end up with O(log m) mallocs rather than O(m). */
415         *m_alloc = 2 * (*m);
416         *c = (nlopt_constraint *) realloc(*c, sizeof(nlopt_constraint)
417                                           * (*m_alloc));
418         if (!*c) {
419             *m_alloc = *m = 0;
420             free(tolcopy);
421             return NLOPT_OUT_OF_MEMORY;
422         }
423     }
424
425     (*c)[*m - 1].m = fm;
426     (*c)[*m - 1].f = fc;
427     (*c)[*m - 1].pre = pre;
428     (*c)[*m - 1].mf = mfc;
429     (*c)[*m - 1].f_data = fc_data;
430     (*c)[*m - 1].tol = tolcopy;
431     return NLOPT_SUCCESS;
432 }
433
434 static int inequality_ok(nlopt_algorithm algorithm)
435 {
436     /* nonlinear constraints are only supported with some algorithms */
437     return (algorithm == NLOPT_LD_MMA || algorithm == NLOPT_LD_CCSAQ || algorithm == NLOPT_LD_SLSQP || algorithm == NLOPT_LN_COBYLA || AUGLAG_ALG(algorithm)
438             || algorithm == NLOPT_GN_ISRES || algorithm == NLOPT_GN_ORIG_DIRECT || algorithm == NLOPT_GN_ORIG_DIRECT_L || algorithm == NLOPT_GN_AGS);
439 }
440
441 nlopt_result NLOPT_STDCALL nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol)
442 {
443     nlopt_result ret;
444     nlopt_unset_errmsg(opt);
445     if (!m) {                   /* empty constraints are always ok */
446         if (opt && opt->munge_on_destroy)
447             opt->munge_on_destroy(fc_data);
448         return NLOPT_SUCCESS;
449     }
450     if (!opt)
451         ret = NLOPT_INVALID_ARGS;
452     else if (!inequality_ok(opt->algorithm))
453         ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
454     else
455         ret = add_constraint(opt, &opt->m, &opt->m_alloc, &opt->fc, m, NULL, fc, NULL, fc_data, tol);
456     if (ret < 0 && opt && opt->munge_on_destroy)
457         opt->munge_on_destroy(fc_data);
458     return ret;
459 }
460
461 nlopt_result NLOPT_STDCALL nlopt_add_precond_inequality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol)
462 {
463     nlopt_result ret;
464     nlopt_unset_errmsg(opt);
465     if (!opt)
466         ret = NLOPT_INVALID_ARGS;
467     else if (!inequality_ok(opt->algorithm))
468         ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
469     else
470         ret = add_constraint(opt, &opt->m, &opt->m_alloc, &opt->fc, 1, fc, NULL, pre, fc_data, &tol);
471     if (ret < 0 && opt && opt->munge_on_destroy)
472         opt->munge_on_destroy(fc_data);
473     return ret;
474 }
475
476 nlopt_result NLOPT_STDCALL nlopt_add_inequality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol)
477 {
478     return nlopt_add_precond_inequality_constraint(opt, fc, NULL, fc_data, tol);
479 }
480
481 nlopt_result NLOPT_STDCALL nlopt_remove_equality_constraints(nlopt_opt opt)
482 {
483     unsigned i;
484     nlopt_unset_errmsg(opt);
485     if (!opt)
486         return NLOPT_INVALID_ARGS;
487     if (opt->munge_on_destroy) {
488         nlopt_munge munge = opt->munge_on_destroy;
489         for (i = 0; i < opt->p; ++i)
490             munge(opt->h[i].f_data);
491     }
492     for (i = 0; i < opt->p; ++i)
493         free(opt->h[i].tol);
494     free(opt->h);
495     opt->h = NULL;
496     opt->p = opt->p_alloc = 0;
497     return NLOPT_SUCCESS;
498 }
499
500 static int equality_ok(nlopt_algorithm algorithm)
501 {
502     /* equality constraints (h(x) = 0) only via some algorithms */
503     return (AUGLAG_ALG(algorithm)
504             || algorithm == NLOPT_LD_SLSQP || algorithm == NLOPT_GN_ISRES || algorithm == NLOPT_LN_COBYLA);
505 }
506
507 nlopt_result NLOPT_STDCALL nlopt_add_equality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol)
508 {
509     nlopt_result ret;
510     nlopt_unset_errmsg(opt);
511     if (!m) {                   /* empty constraints are always ok */
512         if (opt && opt->munge_on_destroy)
513             opt->munge_on_destroy(fc_data);
514         return NLOPT_SUCCESS;
515     }
516     if (!opt)
517         ret = NLOPT_INVALID_ARGS;
518     else if (!equality_ok(opt->algorithm))
519         ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
520     else if (nlopt_count_constraints(opt->p, opt->h) + m > opt->n)
521         ret = ERR(NLOPT_INVALID_ARGS, opt, "too many equality constraints");
522     else
523         ret = add_constraint(opt, &opt->p, &opt->p_alloc, &opt->h, m, NULL, fc, NULL, fc_data, tol);
524     if (ret < 0 && opt && opt->munge_on_destroy)
525         opt->munge_on_destroy(fc_data);
526     return ret;
527 }
528
529 nlopt_result NLOPT_STDCALL nlopt_add_precond_equality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol)
530 {
531     nlopt_result ret;
532     nlopt_unset_errmsg(opt);
533     if (!opt)
534         ret = NLOPT_INVALID_ARGS;
535     else if (!equality_ok(opt->algorithm))
536         ret = ERR(NLOPT_INVALID_ARGS, opt, "invalid algorithm for constraints");
537     else if (nlopt_count_constraints(opt->p, opt->h) + 1 > opt->n)
538         ret = ERR(NLOPT_INVALID_ARGS, opt, "too many equality constraints");
539     else
540         ret = add_constraint(opt, &opt->p, &opt->p_alloc, &opt->h, 1, fc, NULL, pre, fc_data, &tol);
541     if (ret < 0 && opt && opt->munge_on_destroy)
542         opt->munge_on_destroy(fc_data);
543     return ret;
544 }
545
546 nlopt_result NLOPT_STDCALL nlopt_add_equality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol)
547 {
548     return nlopt_add_precond_equality_constraint(opt, fc, NULL, fc_data, tol);
549 }
550
551 /*************************************************************************/
552
553 #define SET(param, T, arg)                                              \
554    nlopt_result NLOPT_STDCALL nlopt_set_##param(nlopt_opt opt, T arg)   \
555    {                                                                    \
556         if (opt) {                                                      \
557              nlopt_unset_errmsg(opt);                                   \
558              opt->arg = arg;                                            \
559              return NLOPT_SUCCESS;                                      \
560         }                                                               \
561         return NLOPT_INVALID_ARGS;                                      \
562    }
563
564
565 #define GET(param, T, arg) T NLOPT_STDCALL      \
566    nlopt_get_##param(const nlopt_opt opt) {     \
567         return opt->arg;                        \
568    }
569
570 #define GETSET(param, T, arg) GET(param, T, arg) SET(param, T, arg)
571
572 GETSET(stopval, double, stopval)
573
574 GETSET(ftol_rel, double, ftol_rel) GETSET(ftol_abs, double, ftol_abs) GETSET(xtol_rel, double, xtol_rel)
575  nlopt_result NLOPT_STDCALL nlopt_set_xtol_abs(nlopt_opt opt, const double *xtol_abs)
576 {
577     if (opt) {
578         nlopt_unset_errmsg(opt);
579         memcpy(opt->xtol_abs, xtol_abs, opt->n * sizeof(double));
580         return NLOPT_SUCCESS;
581     }
582     return NLOPT_INVALID_ARGS;
583 }
584
585 nlopt_result NLOPT_STDCALL nlopt_set_xtol_abs1(nlopt_opt opt, double xtol_abs)
586 {
587     if (opt) {
588         unsigned i;
589         nlopt_unset_errmsg(opt);
590         for (i = 0; i < opt->n; ++i)
591             opt->xtol_abs[i] = xtol_abs;
592         return NLOPT_SUCCESS;
593     }
594     return NLOPT_INVALID_ARGS;
595 }
596
597 nlopt_result NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs)
598 {
599     memcpy(xtol_abs, opt->xtol_abs, opt->n * sizeof(double));
600     return NLOPT_SUCCESS;
601 }
602
603 GETSET(maxeval, int, maxeval)
604
605     GET(numevals, int, numevals)
606  GETSET(maxtime, double, maxtime)
607
608 /*************************************************************************/
609 nlopt_result NLOPT_STDCALL nlopt_set_force_stop(nlopt_opt opt, int force_stop)
610 {
611     if (opt) {
612         nlopt_unset_errmsg(opt);
613         opt->force_stop = force_stop;
614         if (opt->force_stop_child)
615             return nlopt_set_force_stop(opt->force_stop_child, force_stop);
616         return NLOPT_SUCCESS;
617     }
618     return NLOPT_INVALID_ARGS;
619 }
620
621 GET(force_stop, int, force_stop)
622 nlopt_result NLOPT_STDCALL nlopt_force_stop(nlopt_opt opt)
623 {
624     return nlopt_set_force_stop(opt, 1);
625 }
626
627 /*************************************************************************/
628
629 GET(algorithm, nlopt_algorithm, algorithm)
630     GET(dimension, unsigned, n)
631
632 /*************************************************************************/
633     nlopt_result NLOPT_STDCALL nlopt_set_local_optimizer(nlopt_opt opt, const nlopt_opt local_opt)
634 {
635     if (opt) {
636         nlopt_unset_errmsg(opt);
637         if (local_opt && local_opt->n != opt->n)
638             return ERR(NLOPT_INVALID_ARGS, opt, "dimension mismatch in local optimizer");
639         nlopt_destroy(opt->local_opt);
640         opt->local_opt = nlopt_copy(local_opt);
641         if (local_opt) {
642             if (!opt->local_opt)
643                 return NLOPT_OUT_OF_MEMORY;
644             nlopt_set_lower_bounds(opt->local_opt, opt->lb);
645             nlopt_set_upper_bounds(opt->local_opt, opt->ub);
646             nlopt_remove_inequality_constraints(opt->local_opt);
647             nlopt_remove_equality_constraints(opt->local_opt);
648             nlopt_set_min_objective(opt->local_opt, NULL, NULL);
649             nlopt_set_munge(opt->local_opt, NULL, NULL);
650             opt->local_opt->force_stop = 0;
651         }
652         return NLOPT_SUCCESS;
653     }
654     return NLOPT_INVALID_ARGS;
655 }
656
657 /*************************************************************************/
658
659 GETSET(population, unsigned, stochastic_population)
660     GETSET(vector_storage, unsigned, vector_storage)
661
662 /*************************************************************************/
663 nlopt_result NLOPT_STDCALL nlopt_set_initial_step1(nlopt_opt opt, double dx)
664 {
665     unsigned i;
666     if (!opt)
667         return NLOPT_INVALID_ARGS;
668     nlopt_unset_errmsg(opt);
669     if (dx == 0)
670         return ERR(NLOPT_INVALID_ARGS, opt, "zero step size");
671     if (!opt->dx && opt->n > 0) {
672         opt->dx = (double *) malloc(sizeof(double) * (opt->n));
673         if (!opt->dx)
674             return NLOPT_OUT_OF_MEMORY;
675     }
676     for (i = 0; i < opt->n; ++i)
677         opt->dx[i] = dx;
678     return NLOPT_SUCCESS;
679 }
680
681 nlopt_result NLOPT_STDCALL nlopt_set_initial_step(nlopt_opt opt, const double *dx)
682 {
683     unsigned i;
684     if (!opt)
685         return NLOPT_INVALID_ARGS;
686     nlopt_unset_errmsg(opt);
687     if (!dx) {
688         free(opt->dx);
689         opt->dx = NULL;
690         return NLOPT_SUCCESS;
691     }
692     for (i = 0; i < opt->n; ++i)
693         if (dx[i] == 0)
694             return ERR(NLOPT_INVALID_ARGS, opt, "zero step size");
695     if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
696         return NLOPT_OUT_OF_MEMORY;
697     memcpy(opt->dx, dx, sizeof(double) * (opt->n));
698     return NLOPT_SUCCESS;
699 }
700
701 nlopt_result NLOPT_STDCALL nlopt_get_initial_step(const nlopt_opt opt, const double *x, double *dx)
702 {
703     if (!opt)
704         return NLOPT_INVALID_ARGS;
705     nlopt_unset_errmsg(opt);
706     if (!opt->n)
707         return NLOPT_SUCCESS;
708     if (!opt->dx) {
709         nlopt_opt o = (nlopt_opt) opt;  /* discard const temporarily */
710         nlopt_result ret = nlopt_set_default_initial_step(o, x);
711         if (ret != NLOPT_SUCCESS)
712             return ret;
713         memcpy(dx, o->dx, sizeof(double) * (opt->n));
714         free(o->dx);
715         o->dx = NULL;           /* don't save, since x-dependent */
716     } else
717         memcpy(dx, opt->dx, sizeof(double) * (opt->n));
718     return NLOPT_SUCCESS;
719 }
720
721 nlopt_result NLOPT_STDCALL nlopt_set_default_initial_step(nlopt_opt opt, const double *x)
722 {
723     const double *lb, *ub;
724     unsigned i;
725
726     nlopt_unset_errmsg(opt);
727     if (!opt || !x)
728         return NLOPT_INVALID_ARGS;
729     lb = opt->lb;
730     ub = opt->ub;
731
732     if (!opt->dx && nlopt_set_initial_step1(opt, 1) == NLOPT_OUT_OF_MEMORY)
733         return NLOPT_OUT_OF_MEMORY;
734
735     /* crude heuristics for initial step size of nonderivative algorithms */
736     for (i = 0; i < opt->n; ++i) {
737         double step = HUGE_VAL;
738
739         if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i])
740             && (ub[i] - lb[i]) * 0.25 < step && ub[i] > lb[i])
741             step = (ub[i] - lb[i]) * 0.25;
742         if (!nlopt_isinf(ub[i])
743             && ub[i] - x[i] < step && ub[i] > x[i])
744             step = (ub[i] - x[i]) * 0.75;
745         if (!nlopt_isinf(lb[i])
746             && x[i] - lb[i] < step && x[i] > lb[i])
747             step = (x[i] - lb[i]) * 0.75;
748
749         if (nlopt_isinf(step)) {
750             if (!nlopt_isinf(ub[i])
751                 && fabs(ub[i] - x[i]) < fabs(step))
752                 step = (ub[i] - x[i]) * 1.1;
753             if (!nlopt_isinf(lb[i])
754                 && fabs(x[i] - lb[i]) < fabs(step))
755                 step = (x[i] - lb[i]) * 1.1;
756         }
757         if (nlopt_isinf(step) || nlopt_istiny(step)) {
758             step = x[i];
759         }
760         if (nlopt_isinf(step) || step == 0.0)
761             step = 1;
762
763         opt->dx[i] = step;
764     }
765     return NLOPT_SUCCESS;
766 }
767
768 /*************************************************************************/
769
770 void NLOPT_STDCALL nlopt_set_munge(nlopt_opt opt, nlopt_munge munge_on_destroy, nlopt_munge munge_on_copy)
771 {
772     if (opt) {
773         opt->munge_on_destroy = munge_on_destroy;
774         opt->munge_on_copy = munge_on_copy;
775     }
776 }
777
778 void NLOPT_STDCALL nlopt_munge_data(nlopt_opt opt, nlopt_munge2 munge, void *data)
779 {
780     if (opt && munge) {
781         unsigned i;
782         opt->f_data = munge(opt->f_data, data);
783         for (i = 0; i < opt->m; ++i)
784             opt->fc[i].f_data = munge(opt->fc[i].f_data, data);
785         for (i = 0; i < opt->p; ++i)
786             opt->h[i].f_data = munge(opt->h[i].f_data, data);
787     }
788 }
789
790 /*************************************************************************/
791
792 const char *nlopt_set_errmsg(nlopt_opt opt, const char *format, ...)
793 {
794     va_list ap;
795     va_start(ap, format);
796     opt->errmsg = nlopt_vsprintf(opt->errmsg, format, ap);
797     va_end(ap);
798     return opt->errmsg;
799 }
800
801 void nlopt_unset_errmsg(nlopt_opt opt)
802 {
803     if (opt) {
804         free(opt->errmsg);
805         opt->errmsg = NULL;
806     }
807 }
808
809 const char *nlopt_get_errmsg(nlopt_opt opt)
810 {
811     return opt->errmsg;
812 }
813
814 /*************************************************************************/