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