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