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