optimize.c 29.3 KB
Newer Older
1
/* Copyright (c) 2007-2014 Massachusetts Institute of Technology
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 */

#include <stdlib.h>
#include <math.h>
#include <float.h>

#include "nlopt-internal.h"

/*********************************************************************/

#include "praxis.h"
#include "direct.h"

J
Julien Schueller 已提交
34
#ifdef NLOPT_CXX
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#  include "stogo.h"
#endif

#include "cdirect.h"

#include "luksan.h"

#include "crs.h"

#include "mlsl.h"
#include "mma.h"
#include "cobyla.h"
#include "newuoa.h"
#include "neldermead.h"
#include "auglag.h"
#include "bobyqa.h"
#include "isres.h"
S
stevenj 已提交
52
#include "esch.h"
53
#include "slsqp.h"
54 55 56 57 58 59

/*********************************************************************/

static double f_bound(int n, const double *x, void *data_)
{
     int i;
60
     nlopt_opt data = (nlopt_opt) data_;
61 62 63 64 65 66 67 68
     double f;

     /* some methods do not support bound constraints, but support
	discontinuous objectives so we can just return Inf for invalid x */
     for (i = 0; i < n; ++i)
	  if (x[i] < data->lb[i] || x[i] > data->ub[i])
	       return HUGE_VAL;

69
     f = data->f((unsigned) n, x, NULL, data->f_data);
70
     return (nlopt_isnan(f) || nlopt_isinf(f) ? HUGE_VAL : f);
71 72 73 74
}

static double f_noderiv(int n, const double *x, void *data_)
{
75
     nlopt_opt data = (nlopt_opt) data_;
76
     return data->f((unsigned) n, x, NULL, data->f_data);
77 78 79 80
}

static double f_direct(int n, const double *x, int *undefined, void *data_)
{
81
     nlopt_opt data = (nlopt_opt) data_;
82
     double *work = (double*) data->work;
83
     double f;
84
     unsigned i, j;
85
     f = data->f((unsigned) n, x, NULL, data->f_data);
86
     *undefined = nlopt_isnan(f) || nlopt_isinf(f);
87
     if (nlopt_get_force_stop(data)) return f;
88
     for (i = 0; i < data->m && !*undefined; ++i) {
89
	  nlopt_eval_constraint(work, NULL, data->fc+i, (unsigned) n, x);
90
	  if (nlopt_get_force_stop(data)) return f;
91
	  for (j = 0; j < data->fc[i].m; ++j)
92
	       if (work[j] > 0)
93 94
		    *undefined = 1;
     }
95 96 97 98 99 100 101 102
     return f;
}

/*********************************************************************/

/* get min(dx) for algorithms requiring a scalar initial step size */
static nlopt_result initial_step(nlopt_opt opt, const double *x, double *step)
{
103
     unsigned freedx = 0, i;
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

     if (!opt->dx) {
	  freedx = 1;
	  if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS)
	       return NLOPT_OUT_OF_MEMORY;
     }

     *step = HUGE_VAL;
     for (i = 0; i < opt->n; ++i)
	  if (*step > fabs(opt->dx[i]))
	       *step = fabs(opt->dx[i]);

     if (freedx) { free(opt->dx); opt->dx = NULL; }
     return NLOPT_SUCCESS;
}

/*********************************************************************/

122
/* return true if [lb,ub] is finite in every dimension (n dimensions) */
123
static int finite_domain(unsigned n, const double *lb, const double *ub)
124
{
125
     unsigned i;
126 127 128 129 130
     for (i = 0; i < n; ++i)
	  if (nlopt_isinf(ub[i] - lb[i])) return 0;
     return 1;
}

131 132 133 134 135 136 137 138 139 140 141 142
/*********************************************************************/
/* wrapper functions, only for derivative-free methods, that
   eliminate dimensions with lb == ub.   (The gradient-based methods
   should handle this case directly, since they operate on much
   larger vectors where I am loathe to make copies unnecessarily.) */

typedef struct {
     nlopt_func f;
     nlopt_mfunc mf;
     void *f_data;
     unsigned n; /* true dimension */
     double *x; /* scratch vector of length n */
S
stevenj 已提交
143
     double *grad; /* optional scratch vector of length n */
144 145 146 147 148
     const double *lb, *ub; /* bounds, of length n */
} elimdim_data;

static void *elimdim_makedata(nlopt_func f, nlopt_mfunc mf, void *f_data,
			      unsigned n, double *x, const double *lb,
S
stevenj 已提交
149
			      const double *ub, double *grad)
150 151 152 153 154
{
     elimdim_data *d = (elimdim_data *) malloc(sizeof(elimdim_data));
     if (!d) return NULL;
     d->f = f; d->mf = mf; d->f_data = f_data; d->n = n; d->x = x;
     d->lb = lb; d->ub = ub;
S
stevenj 已提交
155
     d->grad = grad;
156 157 158 159 160 161 162 163
     return d;
}

static double elimdim_func(unsigned n0, const double *x0, double *grad, void *d_)
{
     elimdim_data *d = (elimdim_data *) d_;
     double *x = d->x;
     const double *lb = d->lb, *ub = d->ub;
S
stevenj 已提交
164
     double val;
165 166 167 168 169 170 171 172 173
     unsigned n = d->n, i, j;

     (void) n0; /* unused */
     for (i = j = 0; i < n; ++i) {
	  if (lb[i] == ub[i])
	       x[i] = lb[i];
	  else /* assert: j < n0 */
	       x[i] = x0[j++];
     }
S
stevenj 已提交
174 175 176 177 178 179 180 181
     val = d->f(n, x, grad ? d->grad : NULL, d->f_data);
     if (grad) {
	  /* assert: d->grad != NULL */
	  for (i = j = 0; i < n; ++i)
	       if (lb[i] != ub[i])
		    grad[j++] = d->grad[i];
     }
     return val;
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
}


static void elimdim_mfunc(unsigned m, double *result,
			  unsigned n0, const double *x0, double *grad, void *d_)
{
     elimdim_data *d = (elimdim_data *) d_;
     double *x = d->x;
     const double *lb = d->lb, *ub = d->ub;
     unsigned n = d->n, i, j;

     (void) n0; /* unused */
     (void) grad; /* assert: grad == NULL */
     for (i = j = 0; i < n; ++i) {
	  if (lb[i] == ub[i])
	       x[i] = lb[i];
	  else /* assert: j < n0 */
	       x[i] = x0[j++];
     }
     d->mf(m, result, n, x, NULL, d->f_data);
}

/* compute the eliminated dimension: number of dims with lb[i] != ub[i] */
static unsigned elimdim_dimension(unsigned n, const double *lb, const double *ub)
{
     unsigned n0 = 0, i;
     for (i = 0; i < n; ++i) n0 += lb[i] != ub[i] ? 1U : 0;
     return n0;
}

212
/* modify v to "shrunk" version, with dimensions for lb[i] == ub[i] elim'ed */
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static void elimdim_shrink(unsigned n, double *v,
			   const double *lb, const double *ub)
{
     unsigned i, j;
     if (v)
	  for (i = j = 0; i < n; ++i)
	       if (lb[i] != ub[i])
		    v[j++] = v[i];
}

/* inverse of elimdim_shrink */
static void elimdim_expand(unsigned n, double *v,
			   const double *lb, const double *ub)
{
     unsigned i, j;
     if (v && n > 0) {
	  j = elimdim_dimension(n, lb, ub) - 1;
	  for (i = n - 1; i > 0; --i) {
	       if (lb[i] != ub[i])
		    v[i] = v[j--];
	       else
		    v[i] = lb[i];
	  }
	  if (lb[0] == ub[0])
	       v[0] = lb[0];
     }
}

/* given opt, create a new opt with equal-constraint dimensions eliminated */
static nlopt_opt elimdim_create(nlopt_opt opt)
{
S
fix #26  
Steven G. Johnson 已提交
244 245
     nlopt_opt opt0;
     nlopt_munge munge_copy_save = opt->munge_on_copy;
S
stevenj 已提交
246
     double *x, *grad = NULL;
247 248
     unsigned i;
     
S
fix #26  
Steven G. Johnson 已提交
249 250 251 252
     opt->munge_on_copy = 0; /* hack: since this is an internal copy,
                                we can leave it un-munged; see issue #26 */
     opt0 = nlopt_copy(opt);
     opt->munge_on_copy = munge_copy_save;
253 254 255 256
     if (!opt0) return NULL;
     x = (double *) malloc(sizeof(double) * opt->n);
     if (opt->n && !x) { nlopt_destroy(opt0); return NULL; }

S
stevenj 已提交
257 258 259 260 261 262
     if (opt->algorithm == NLOPT_GD_STOGO
         || opt->algorithm == NLOPT_GD_STOGO_RAND) {
	  grad = (double *) malloc(sizeof(double) * opt->n);
	  if (opt->n && !grad) goto bad;
     }

263 264 265 266 267 268 269 270 271 272
     opt0->n = elimdim_dimension(opt->n, opt->lb, opt->ub);
     elimdim_shrink(opt->n, opt0->lb, opt->lb, opt->ub);
     elimdim_shrink(opt->n, opt0->ub, opt->lb, opt->ub);
     elimdim_shrink(opt->n, opt0->xtol_abs, opt->lb, opt->ub);
     elimdim_shrink(opt->n, opt0->dx, opt->lb, opt->ub);

     opt0->munge_on_destroy = opt0->munge_on_copy = NULL;

     opt0->f = elimdim_func;
     opt0->f_data = elimdim_makedata(opt->f, NULL, opt->f_data,
S
stevenj 已提交
273
				     opt->n, x, opt->lb, opt->ub, grad);
274 275 276 277 278 279 280
     if (!opt0->f_data) goto bad;

     for (i = 0; i < opt->m; ++i) {
	  opt0->fc[i].f = elimdim_func;
	  opt0->fc[i].mf = elimdim_mfunc;
	  opt0->fc[i].f_data = elimdim_makedata(opt->fc[i].f, opt->fc[i].mf,
						opt->fc[i].f_data,
S
stevenj 已提交
281 282
						opt->n, x, opt->lb, opt->ub,
						NULL);
283 284 285 286 287 288 289 290
	  if (!opt0->fc[i].f_data) goto bad;
     }

     for (i = 0; i < opt->p; ++i) {
	  opt0->h[i].f = elimdim_func;
	  opt0->h[i].mf = elimdim_mfunc;
	  opt0->h[i].f_data = elimdim_makedata(opt->h[i].f, opt->h[i].mf,
					       opt->h[i].f_data,
S
stevenj 已提交
291 292
					       opt->n, x, opt->lb, opt->ub,
					       NULL);
293 294 295 296 297
	  if (!opt0->h[i].f_data) goto bad;
     }

     return opt0;
bad:
S
stevenj 已提交
298
     free(grad);
299 300 301 302 303 304 305 306 307 308 309 310
     free(x);
     nlopt_destroy(opt0);
     return NULL;
}

/* like nlopt_destroy, but also frees elimdim_data */
static void elimdim_destroy(nlopt_opt opt)
{
     unsigned i;
     if (!opt) return;

     free(((elimdim_data*) opt->f_data)->x);
S
stevenj 已提交
311
     free(((elimdim_data*) opt->f_data)->grad);
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
     free(opt->f_data); opt->f_data = NULL;

     for (i = 0; i < opt->m; ++i) {
	  free(opt->fc[i].f_data);
	  opt->fc[i].f_data = NULL;
     }
     for (i = 0; i < opt->p; ++i) {
	  free(opt->h[i].f_data);
	  opt->h[i].f_data = NULL;
     }

     nlopt_destroy(opt);
}

/* return whether to use elimdim wrapping. */
static int elimdim_wrapcheck(nlopt_opt opt)
{
     if (!opt) return 0;
     if (elimdim_dimension(opt->n, opt->lb, opt->ub) == opt->n) return 0;
     switch (opt->algorithm) {
	 case NLOPT_GN_DIRECT:
	 case NLOPT_GN_DIRECT_L: 
	 case NLOPT_GN_DIRECT_L_RAND: 
	 case NLOPT_GN_DIRECT_NOSCAL:
	 case NLOPT_GN_DIRECT_L_NOSCAL: 
	 case NLOPT_GN_DIRECT_L_RAND_NOSCAL: 
	 case NLOPT_GN_ORIG_DIRECT:
	 case NLOPT_GN_ORIG_DIRECT_L:
340
         case NLOPT_GN_CRS2_LM:
341
	 case NLOPT_LN_PRAXIS:
342 343 344 345
	 case NLOPT_LN_COBYLA:
	 case NLOPT_LN_NEWUOA:
	 case NLOPT_LN_NEWUOA_BOUND:
	 case NLOPT_LN_BOBYQA:
346 347
	 case NLOPT_LN_NELDERMEAD:
	 case NLOPT_LN_SBPLX:
348
	 case NLOPT_GN_ISRES:
S
stevenj 已提交
349
	 case NLOPT_GN_ESCH:
S
stevenj 已提交
350 351
	 case NLOPT_GD_STOGO:
         case NLOPT_GD_STOGO_RAND:
352
	      return 1;
S
stevenj 已提交
353

354 355 356 357
	 default: return 0;
     }
}

358 359
/*********************************************************************/

360 361 362 363 364
#define POP(defaultpop) (opt->stochastic_population > 0 ?		\
                         opt->stochastic_population :			\
                         (nlopt_stochastic_population > 0 ?		\
			  nlopt_stochastic_population : (defaultpop)))

365 366
/* unlike nlopt_optimize() below, only handles minimization case */
static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
367 368 369 370
{
     const double *lb, *ub;
     nlopt_algorithm algorithm;
     nlopt_func f; void *f_data;
371 372
     unsigned n, i;
     int ni;
373 374
     nlopt_stopping stop;

375
     if (!opt || !x || !minf || !opt->f
376 377
	 || opt->maximize) RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                                      "NULL args to nlopt_optimize_");
S
stevenj 已提交
378 379 380 381

     /* reset stopping flag */
     nlopt_set_force_stop(opt, 0);
     opt->force_stop_child = NULL;
382
     
383 384
     /* copy a few params to local vars for convenience */
     n = opt->n;
385
     ni = (int) n; /* most of the subroutines take "int" arg */
386 387 388 389 390
     lb = opt->lb; ub = opt->ub;
     algorithm = opt->algorithm;
     f = opt->f; f_data = opt->f_data;

     if (n == 0) { /* trivial case: no degrees of freedom */
391
	  *minf = opt->f(n, x, NULL, opt->f_data);
392 393 394 395 396 397
	  return NLOPT_SUCCESS;
     }

     *minf = HUGE_VAL;
     
     /* make sure rand generator is inited */
398
     nlopt_srand_time_default(); /* default is non-deterministic */
399 400 401

     /* check bound constraints */
     for (i = 0; i < n; ++i)
402 403 404 405 406
         if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i]) {
             nlopt_set_errmsg(opt, "bounds %d fail %g <= %g <= %g",
                              i, lb[i], x[i], ub[i]);
             return NLOPT_INVALID_ARGS;
         }
407 408

     stop.n = n;
409
     stop.minf_max = opt->stopval;
410 411 412 413 414 415 416 417
     stop.ftol_rel = opt->ftol_rel;
     stop.ftol_abs = opt->ftol_abs;
     stop.xtol_rel = opt->xtol_rel;
     stop.xtol_abs = opt->xtol_abs;
     stop.nevals = 0;
     stop.maxeval = opt->maxeval;
     stop.maxtime = opt->maxtime;
     stop.start = nlopt_seconds();
S
stevenj 已提交
418
     stop.force_stop = &(opt->force_stop);
419
     stop.stop_msg = &(opt->errmsg);
420 421 422 423 424

     switch (algorithm) {
	 case NLOPT_GN_DIRECT:
	 case NLOPT_GN_DIRECT_L: 
	 case NLOPT_GN_DIRECT_L_RAND: 
425 426 427
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
428
	      return cdirect(ni, f, f_data, 
429 430 431 432 433 434 435 436 437 438
			     lb, ub, x, minf, &stop, 0.0, 
			     (algorithm != NLOPT_GN_DIRECT)
			     + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND 
				    ? 2 : (algorithm != NLOPT_GN_DIRECT))
			     + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND 
				    ? 1 : (algorithm != NLOPT_GN_DIRECT)));
	      
	 case NLOPT_GN_DIRECT_NOSCAL:
	 case NLOPT_GN_DIRECT_L_NOSCAL: 
	 case NLOPT_GN_DIRECT_L_RAND_NOSCAL: 
439 440 441
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
442
	      return cdirect_unscaled(ni, f, f_data, lb, ub, x, minf, 
443 444 445 446 447 448
				      &stop, 0.0, 
				      (algorithm != NLOPT_GN_DIRECT)
				      + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
				      + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
	      
	 case NLOPT_GN_ORIG_DIRECT:
449 450
	 case NLOPT_GN_ORIG_DIRECT_L: {
	      direct_return_code dret;
451 452 453
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
454 455 456
	      opt->work = malloc(sizeof(double) *
				 nlopt_max_constraint_dim(opt->m,
							  opt->fc));
457 458
	      if (!opt->work) return NLOPT_OUT_OF_MEMORY;
	      dret = direct_optimize(f_direct, opt, ni, lb, ub, x, minf,
459 460 461
				     stop.maxeval, -1,
				     stop.start, stop.maxtime,
				     0.0, 0.0,
462
				     pow(stop.xtol_rel, (double) n), -1.0,
S
stevenj 已提交
463
				     stop.force_stop,
464 465 466 467 468 469 470
				     stop.minf_max, 0.0,
				     NULL, 
				     algorithm == NLOPT_GN_ORIG_DIRECT
				     ? DIRECT_ORIGINAL
				     : DIRECT_GABLONSKY);
	      free(opt->work); opt->work = NULL;
	      switch (dret) {
471
		  case DIRECT_INVALID_BOUNDS:
472 473
                      RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                                 "invalid bounds for DIRECT");
474
		  case DIRECT_MAXFEVAL_TOOBIG:
475 476
                      RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                                 "maxeval too big for DIRECT");
477 478 479
		  case DIRECT_INVALID_ARGS:
		       return NLOPT_INVALID_ARGS;
		  case DIRECT_INIT_FAILED:
480 481
                      RETURN_ERR(NLOPT_FAILURE, opt,
                                 "init failed for DIRECT");
482
		  case DIRECT_SAMPLEPOINTS_FAILED:
483 484
                      RETURN_ERR(NLOPT_FAILURE, opt,
                                 "sample-points failed for DIRECT");
485
		  case DIRECT_SAMPLE_FAILED:
486 487
                      RETURN_ERR(NLOPT_FAILURE, opt,
                                 "sample failed for DIRECT");
488 489 490
		  case DIRECT_MAXFEVAL_EXCEEDED:
		  case DIRECT_MAXITER_EXCEEDED:
		       return NLOPT_MAXEVAL_REACHED;
491 492
		  case DIRECT_MAXTIME_EXCEEDED:
		       return NLOPT_MAXTIME_REACHED;
493 494 495 496 497 498 499
		  case DIRECT_GLOBAL_FOUND:
		       return NLOPT_MINF_MAX_REACHED;
		  case DIRECT_VOLTOL:
		  case DIRECT_SIGMATOL:
		       return NLOPT_XTOL_REACHED;
		  case DIRECT_OUT_OF_MEMORY:
		       return NLOPT_OUT_OF_MEMORY;
S
stevenj 已提交
500 501
		  case DIRECT_FORCED_STOP:
		       return NLOPT_FORCED_STOP;
502
	      }
503 504 505 506 507
	      break;
	 }

	 case NLOPT_GD_STOGO:
	 case NLOPT_GD_STOGO_RAND:
J
Julien Schueller 已提交
508
#ifdef NLOPT_CXX
509 510 511
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
512
	      if (!stogo_minimize(ni, f, f_data, x, minf, lb, ub, &stop,
513
				  algorithm == NLOPT_GD_STOGO
514
				  ? 0 : (int) POP(2*n)))
515 516 517
		   return NLOPT_FAILURE;
	      break;
#else
518
	      return NLOPT_INVALID_ARGS;
519 520 521 522 523 524 525 526 527 528 529 530
#endif

#if 0
	      /* lacking a free/open-source license, we no longer use
		 Rowan's code, and instead use by "sbplx" re-implementation */
	 case NLOPT_LN_SUBPLEX: {
	      int iret, freedx = 0;
	      if (!opt->dx) {
		   freedx = 1;
		   if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS)
			return NLOPT_OUT_OF_MEMORY;
	      }		       
531
	      iret = nlopt_subplex(f_bound, minf, x, n, opt, &stop, opt->dx);
532 533 534
	      if (freedx) { free(opt->dx); opt->dx = NULL; }
	      switch (iret) {
		  case -2: return NLOPT_INVALID_ARGS;
535
		  case -20: return NLOPT_FORCED_STOP;
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
		  case -10: return NLOPT_MAXTIME_REACHED;
		  case -1: return NLOPT_MAXEVAL_REACHED;
		  case 0: return NLOPT_XTOL_REACHED;
		  case 1: return NLOPT_SUCCESS;
		  case 2: return NLOPT_MINF_MAX_REACHED;
		  case 20: return NLOPT_FTOL_REACHED;
		  case -200: return NLOPT_OUT_OF_MEMORY;
		  default: return NLOPT_FAILURE; /* unknown return code */
	      }
	      break;
	 }
#endif

	 case NLOPT_LN_PRAXIS: {
	      double step;
	      if (initial_step(opt, x, &step) != NLOPT_SUCCESS)
		   return NLOPT_OUT_OF_MEMORY;
	      return praxis_(0.0, DBL_EPSILON, 
554
			     step, ni, x, f_bound, opt, &stop, minf);
555 556 557
	 }

	 case NLOPT_LD_LBFGS: 
558
	      return luksan_plis(ni, f, f_data, lb, ub, x, minf, 
559
				 &stop, opt->vector_storage);
560 561 562

	 case NLOPT_LD_VAR1: 
	 case NLOPT_LD_VAR2: 
563
	      return luksan_plip(ni, f, f_data, lb, ub, x, minf, 
564
				 &stop, opt->vector_storage,
565
				 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
566 567 568 569 570

	 case NLOPT_LD_TNEWTON: 
	 case NLOPT_LD_TNEWTON_RESTART: 
	 case NLOPT_LD_TNEWTON_PRECOND: 
	 case NLOPT_LD_TNEWTON_PRECOND_RESTART: 
571
	      return luksan_pnet(ni, f, f_data, lb, ub, x, minf,
572
				 &stop, opt->vector_storage,
573 574 575 576
				 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
				 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);

	 case NLOPT_GN_CRS2_LM:
577 578 579
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
580 581
	      return crs_minimize(ni, f, f_data, lb, ub, x, minf, &stop, 
				  (int) POP(0), 0);
582

583 584
	 case NLOPT_G_MLSL:
	 case NLOPT_G_MLSL_LDS:
585 586 587 588 589 590
	 case NLOPT_GN_MLSL:
	 case NLOPT_GD_MLSL:
	 case NLOPT_GN_MLSL_LDS:
	 case NLOPT_GD_MLSL_LDS: {
	      nlopt_opt local_opt = opt->local_opt;
	      nlopt_result ret;
591 592 593
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
594 595
	      if (!local_opt && (algorithm == NLOPT_G_MLSL 
				 || algorithm == NLOPT_G_MLSL_LDS))
596 597
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "local optimizer must be specified for G_MLSL");
598
	      if (!local_opt) { /* default */
599 600 601 602 603 604 605 606 607 608 609
		   nlopt_algorithm local_alg = (algorithm == NLOPT_GN_MLSL ||
						algorithm == NLOPT_GN_MLSL_LDS)
			? nlopt_local_search_alg_nonderiv
			: nlopt_local_search_alg_deriv;
		   /* don't call MLSL recursively! */
		   if (local_alg >= NLOPT_GN_MLSL
		       && local_alg <= NLOPT_GD_MLSL_LDS)
			local_alg = (algorithm == NLOPT_GN_MLSL ||
				     algorithm == NLOPT_GN_MLSL_LDS)
			     ? NLOPT_LN_COBYLA : NLOPT_LD_MMA;
		   local_opt = nlopt_create(local_alg, n);
610 611
		   if (!local_opt) RETURN_ERR(NLOPT_FAILURE, opt,
                                              "failed to create local_opt");
612 613 614 615 616 617
		   nlopt_set_ftol_rel(local_opt, opt->ftol_rel);
		   nlopt_set_ftol_abs(local_opt, opt->ftol_abs);
		   nlopt_set_xtol_rel(local_opt, opt->xtol_rel);
		   nlopt_set_xtol_abs(local_opt, opt->xtol_abs);
		   nlopt_set_maxeval(local_opt, nlopt_local_search_maxeval);
	      }
618
	      if (opt->dx) nlopt_set_initial_step(local_opt, opt->dx);
619 620 621 622 623 624 625 626
	      for (i = 0; i < n && stop.xtol_abs[i] > 0; ++i) ;
	      if (local_opt->ftol_rel <= 0 && local_opt->ftol_abs <= 0 &&
		  local_opt->xtol_rel <= 0 && i < n) {
		   /* it is not sensible to call MLSL without *some*
		      nonzero tolerance for the local search */
		   nlopt_set_ftol_rel(local_opt, 1e-15);
		   nlopt_set_xtol_rel(local_opt, 1e-7);
	      }
S
stevenj 已提交
627
	      opt->force_stop_child = local_opt;
628 629
	      ret = mlsl_minimize(ni, f, f_data, lb, ub, x, minf, &stop,
				  local_opt, (int) POP(0),
630 631
				  algorithm >= NLOPT_GN_MLSL_LDS &&
				  algorithm != NLOPT_G_MLSL);
S
stevenj 已提交
632
	      opt->force_stop_child = NULL;
633 634 635 636
	      if (!opt->local_opt) nlopt_destroy(local_opt);
	      return ret;
	 }

637
	 case NLOPT_LD_MMA: case NLOPT_LD_CCSAQ: {
638 639 640 641 642
	      nlopt_opt dual_opt;
	      nlopt_result ret;
#define LO(param, def) (opt->local_opt ? opt->local_opt->param : (def))
	      dual_opt = nlopt_create(LO(algorithm,
					 nlopt_local_search_alg_deriv),
S
stevenj 已提交
643 644
				      nlopt_count_constraints(opt->m,
							      opt->fc));
645 646
	      if (!dual_opt) RETURN_ERR(NLOPT_FAILURE, opt,
                                        "failed creating dual optimizer");
647
	      nlopt_set_ftol_rel(dual_opt, LO(ftol_rel, 1e-14));
648 649 650 651
	      nlopt_set_ftol_abs(dual_opt, LO(ftol_abs, 0.0));
	      nlopt_set_maxeval(dual_opt, LO(maxeval, 100000));
#undef LO

652 653 654 655 656
	      if (algorithm == NLOPT_LD_MMA)
		   ret = mma_minimize(n, f, f_data, opt->m, opt->fc,
				      lb, ub, x, minf, &stop, dual_opt);
	      else
		   ret = ccsa_quadratic_minimize(
657
			n, f, f_data, opt->m, opt->fc, opt->pre,
658
			lb, ub, x, minf, &stop, dual_opt);
659 660 661 662 663
	      nlopt_destroy(dual_opt);
	      return ret;
	 }

	 case NLOPT_LN_COBYLA: {
664 665 666 667 668
	      nlopt_result ret;
	      int freedx = 0;
	      if (!opt->dx) {
		   freedx = 1;
		   if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS)
669 670
                       RETURN_ERR(NLOPT_OUT_OF_MEMORY, opt,
                                  "failed to allocate initial step");
671
	      }
S
fix #24  
Steven G. Johnson 已提交
672 673 674 675 676
	      ret = cobyla_minimize(n, f, f_data, 
                                    opt->m, opt->fc,
                                    opt->p, opt->h,
                                    lb, ub, x, minf, &stop,
                                    opt->dx);
677 678
	      if (freedx) { free(opt->dx); opt->dx = NULL; }
	      return ret;
679 680 681 682 683
	 }
				     
	 case NLOPT_LN_NEWUOA: {
	      double step;
	      if (initial_step(opt, x, &step) != NLOPT_SUCCESS)
684 685
                  RETURN_ERR(NLOPT_OUT_OF_MEMORY, opt,
                             "failed to allocate initial step");
686
	      return newuoa(ni, 2*n+1, x, 0, 0, step,
687
			    &stop, minf, f_noderiv, opt);
688 689 690 691 692
	 }
				     
	 case NLOPT_LN_NEWUOA_BOUND: {
	      double step;
	      if (initial_step(opt, x, &step) != NLOPT_SUCCESS)
693 694
                  RETURN_ERR(NLOPT_OUT_OF_MEMORY, opt,
                             "failed to allocate initial step");
695
	      return newuoa(ni, 2*n+1, x, lb, ub, step,
696
			    &stop, minf, f_noderiv, opt);
697 698 699
	 }

	 case NLOPT_LN_BOBYQA: {
700 701 702 703 704
	      nlopt_result ret;
	      int freedx = 0;
	      if (!opt->dx) {
		   freedx = 1;
		   if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS)
705 706
                       RETURN_ERR(NLOPT_OUT_OF_MEMORY, opt,
                                  "failed to allocate initial step");
707 708 709 710 711
	      }
	      ret = bobyqa(ni, 2*n+1, x, lb, ub, opt->dx,
			   &stop, minf, opt->f, opt->f_data);
	      if (freedx) { free(opt->dx); opt->dx = NULL; }
	      return ret;
712 713 714 715 716 717 718 719 720 721
	 }

	 case NLOPT_LN_NELDERMEAD: 
	 case NLOPT_LN_SBPLX: 
	 {
	      nlopt_result ret;
	      int freedx = 0;
	      if (!opt->dx) {
		   freedx = 1;
		   if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS)
722 723
                       RETURN_ERR(NLOPT_OUT_OF_MEMORY, opt,
                                  "failed to allocate initial step");
724 725
	      }
	      if (algorithm == NLOPT_LN_NELDERMEAD)
726
		   ret=nldrmd_minimize(ni,f,f_data,lb,ub,x,minf,opt->dx,&stop);
727
	      else
728
		   ret=sbplx_minimize(ni,f,f_data,lb,ub,x,minf,opt->dx,&stop);
729 730 731 732
	      if (freedx) { free(opt->dx); opt->dx = NULL; }
	      return ret;
	 }

733 734
	 case NLOPT_AUGLAG:
	 case NLOPT_AUGLAG_EQ:
735 736 737 738 739 740
	 case NLOPT_LN_AUGLAG:
	 case NLOPT_LN_AUGLAG_EQ:
	 case NLOPT_LD_AUGLAG:
	 case NLOPT_LD_AUGLAG_EQ: {
	      nlopt_opt local_opt = opt->local_opt;
	      nlopt_result ret;
741 742
	      if ((algorithm == NLOPT_AUGLAG || algorithm == NLOPT_AUGLAG_EQ)
		  && !local_opt)
743 744
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "local optimizer must be specified for AUGLAG");
745 746 747 748 749 750
	      if (!local_opt) { /* default */
		   local_opt = nlopt_create(
			algorithm == NLOPT_LN_AUGLAG || 
			algorithm == NLOPT_LN_AUGLAG_EQ
			? nlopt_local_search_alg_nonderiv
			: nlopt_local_search_alg_deriv, n);
751 752
		   if (!local_opt) RETURN_ERR(NLOPT_FAILURE, opt,
                                              "failed to create local_opt");
753 754 755 756
		   nlopt_set_ftol_rel(local_opt, opt->ftol_rel);
		   nlopt_set_ftol_abs(local_opt, opt->ftol_abs);
		   nlopt_set_xtol_rel(local_opt, opt->xtol_rel);
		   nlopt_set_xtol_abs(local_opt, opt->xtol_abs);
S
stevenj 已提交
757
		   nlopt_set_maxeval(local_opt, nlopt_local_search_maxeval);
758
	      }
759
	      if (opt->dx) nlopt_set_initial_step(local_opt, opt->dx);
S
stevenj 已提交
760
	      opt->force_stop_child = local_opt;
761
	      ret = auglag_minimize(ni, f, f_data, 
762 763 764 765
				    opt->m, opt->fc, 
				    opt->p, opt->h,
				    lb, ub, x, minf, &stop,
				    local_opt,
766 767
				    algorithm == NLOPT_AUGLAG_EQ
				    || algorithm == NLOPT_LN_AUGLAG_EQ
768
				    || algorithm == NLOPT_LD_AUGLAG_EQ);
S
stevenj 已提交
769
	      opt->force_stop_child = NULL;
770 771 772 773 774
	      if (!opt->local_opt) nlopt_destroy(local_opt);
	      return ret;
	 }

	 case NLOPT_GN_ISRES:
775 776 777
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
778 779 780
	      return isres_minimize(ni, f, f_data, 
				    (int) (opt->m), opt->fc,
				    (int) (opt->p), opt->h,
781
				    lb, ub, x, minf, &stop,
782
				    (int) POP(0));
783

S
stevenj 已提交
784
	case NLOPT_GN_ESCH:
785 786 787
              if (!finite_domain(n, lb, ub))
                  RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                             "finite domain required for global algorithm");
S
stevenj 已提交
788 789 790 791 792
	      return chevolutionarystrategy(n, f, f_data, 
					    lb, ub, x, minf, &stop,
					    (unsigned) POP(0),
					    (unsigned) (POP(0)*1.5));

793 794 795 796 797 798
	 case NLOPT_LD_SLSQP:
	      return nlopt_slsqp(n, f, f_data,
				 opt->m, opt->fc,
				 opt->p, opt->h,
				 lb, ub, x, minf, &stop);
				     
799 800 801 802 803 804 805 806 807
	 default:
	      return NLOPT_INVALID_ARGS;
     }

     return NLOPT_SUCCESS; /* never reached */
}

/*********************************************************************/

808 809
typedef struct {
     nlopt_func f;
810
     nlopt_precond pre;
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
     void *f_data;
} f_max_data;

/* wrapper for maximizing: just flip the sign of f and grad */
static double f_max(unsigned n, const double *x, double *grad, void *data)
{
     f_max_data *d = (f_max_data *) data;
     double val = d->f(n, x, grad, d->f_data);
     if (grad) {
	  unsigned i;
	  for (i = 0; i < n; ++i)
	       grad[i] = -grad[i];
     }
     return -val;
}

827 828 829 830 831
static void pre_max(unsigned n, const double *x, const double *v,
		    double *vpre, void *data)
{
     f_max_data *d = (f_max_data *) data;
     unsigned i;
832
     d->pre(n, x, v, vpre, d->f_data);
833 834 835
     for (i = 0; i < n; ++i) vpre[i] = -vpre[i];
}

836 837
nlopt_result 
NLOPT_STDCALL nlopt_optimize(nlopt_opt opt, double *x, double *opt_f)
838
{
839
     nlopt_func f; void *f_data; nlopt_precond pre;
840 841 842 843
     f_max_data fmd;
     int maximize;
     nlopt_result ret;

844 845 846
     nlopt_unset_errmsg(opt);
     if (!opt || !opt_f || !opt->f) RETURN_ERR(NLOPT_INVALID_ARGS, opt,
                                               "NULL args to nlopt_optimize");
847
     f = opt->f; f_data = opt->f_data; pre = opt->pre;
848 849 850 851

     /* for maximizing, just minimize the f_max wrapper, which 
	flips the sign of everything */
     if ((maximize = opt->maximize)) {
852
	  fmd.f = f; fmd.f_data = f_data; fmd.pre = pre;
853 854
	  opt->f = f_max; opt->f_data = &fmd; 
	  if (opt->pre) opt->pre = pre_max;
855
	  opt->stopval = -opt->stopval;
S
stevenj 已提交
856
	  opt->maximize = 0;
857 858
     }

859 860 861 862
     { /* possibly eliminate lb == ub dimensions for some algorithms */
	  nlopt_opt elim_opt = opt;
	  if (elimdim_wrapcheck(opt)) {
	       elim_opt = elimdim_create(opt);
863 864 865 866 867
	       if (!elim_opt) { 
                   nlopt_set_errmsg(opt, "failure allocating elim_opt");
                   ret = NLOPT_OUT_OF_MEMORY;
                   goto done;
               }
868 869 870 871 872 873 874 875 876 877
	       elimdim_shrink(opt->n, x, opt->lb, opt->ub);
	  }

	  ret = nlopt_optimize_(elim_opt, x, opt_f);

	  if (elim_opt != opt) {
	       elimdim_destroy(elim_opt);
	       elimdim_expand(opt->n, x, opt->lb, opt->ub);
	  }
     }
878

879
done:
880
     if (maximize) { /* restore original signs */
S
stevenj 已提交
881
	  opt->maximize = maximize;
882
	  opt->stopval = -opt->stopval;
883
	  opt->f = f; opt->f_data = f_data; opt->pre = pre;
884 885 886 887 888 889 890 891
     	  *opt_f = -*opt_f;
     }

     return ret;
}

/*********************************************************************/

892 893 894 895 896 897 898
nlopt_result nlopt_optimize_limited(nlopt_opt opt, double *x, double *minf,
				    int maxeval, double maxtime)
{
     int save_maxeval;
     double save_maxtime;
     nlopt_result ret;

899 900 901
     nlopt_unset_errmsg(opt);

     if (!opt) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "NULL opt arg");
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920

     save_maxeval = nlopt_get_maxeval(opt);
     save_maxtime = nlopt_get_maxtime(opt);
     
     /* override opt limits if maxeval and/or maxtime are more stringent */
     if (save_maxeval <= 0 || (maxeval > 0 && maxeval < save_maxeval))
	  nlopt_set_maxeval(opt, maxeval);
     if (save_maxtime <= 0 || (maxtime > 0 && maxtime < save_maxtime))
	  nlopt_set_maxtime(opt, maxtime);

     ret = nlopt_optimize(opt, x, minf);

     nlopt_set_maxeval(opt, save_maxeval);
     nlopt_set_maxtime(opt, save_maxtime);

     return ret;
}

/*********************************************************************/