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