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