nlopt.c 8.5 KB
Newer Older
S
stevenj 已提交
1 2
#include <stdlib.h>
#include <math.h>
3
#include <string.h>
S
stevenj 已提交
4 5

#include "nlopt.h"
6
#include "nlopt-util.h"
S
stevenj 已提交
7 8
#include "config.h"

S
stevenj 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#define MIN(a,b) ((a) < (b) ? (a) : (b))

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

#ifdef INFINITY
#  define MY_INF INFINITY
#else
#  define MY_INF HUGE_VAL
#endif

static int my_isinf(double x) {
     return fabs(x) >= HUGE_VAL * 0.99
#ifdef HAVE_ISINF
	  || isinf(x)
#endif
	  ;
}

#ifndef HAVE_ISNAN
static int my_isnan(double x) { return x != x; }
#  define isnan my_isnan
#endif

/*************************************************************************/
33

S
stevenj 已提交
34 35 36 37 38 39 40
void nlopt_version(int *major, int *minor, int *bugfix)
{
     *major = MAJOR_VERSION;
     *minor = MINOR_VERSION;
     *bugfix = BUGFIX_VERSION;
}

S
stevenj 已提交
41 42 43 44 45
/*************************************************************************/

static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][128] = {
     "DIRECT (global)",
     "DIRECT-L (global)",
46
     "Randomized DIRECT-L (global)",
47 48
     "Original DIRECT version (global)",
     "Original DIRECT-L version (global)",
S
stevenj 已提交
49 50
     "Subplex (local)",
     "StoGO (global)",
51
     "StoGO with randomized search (global)",
S
stevenj 已提交
52 53 54
     "Low-storage BFGS (LBFGS) (local)"
};

55 56 57 58 59 60
const char *nlopt_algorithm_name(nlopt_algorithm a)
{
     if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
     return nlopt_algorithm_names[a];
}

S
stevenj 已提交
61 62
/*************************************************************************/

63 64 65 66 67 68 69 70 71 72
static int nlopt_srand_called = 0;
void nlopt_srand(unsigned long seed) {
     nlopt_srand_called = 1;
     nlopt_init_genrand(seed);
}

void nlopt_srand_time() {
     nlopt_srand(nlopt_time_seed());
}

S
stevenj 已提交
73
/*************************************************************************/
S
stevenj 已提交
74 75 76 77

typedef struct {
     nlopt_func f;
     void *f_data;
78
     const double *lb, *ub;
S
stevenj 已提交
79 80 81 82
} nlopt_data;

#include "subplex.h"

S
stevenj 已提交
83
static double f_subplex(int n, const double *x, void *data_)
S
stevenj 已提交
84
{
85
     int i;
S
stevenj 已提交
86
     nlopt_data *data = (nlopt_data *) data_;
S
stevenj 已提交
87
     double f;
88 89 90 91 92

     /* subplex does not support bound constraints, but it supports
	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])
S
stevenj 已提交
93
	       return MY_INF;
94

S
stevenj 已提交
95 96
     f = data->f(n, x, NULL, data->f_data);
     return (isnan(f) ? MY_INF : f);
S
stevenj 已提交
97 98 99 100
}

#include "direct.h"

S
stevenj 已提交
101
static double f_direct(int n, const double *x, int *undefined, void *data_)
S
stevenj 已提交
102 103
{
     nlopt_data *data = (nlopt_data *) data_;
104
     double f;
105
     f = data->f(n, x, NULL, data->f_data);
S
stevenj 已提交
106
     *undefined = isnan(f) || my_isinf(f);
S
stevenj 已提交
107 108 109
     return f;
}

S
stevenj 已提交
110
#include "stogo.h"
111

S
stevenj 已提交
112 113
#include "l-bfgs-b.h"

114 115
#include "cdirect.h"

S
stevenj 已提交
116
/*************************************************************************/
S
stevenj 已提交
117

118 119
/* same as nlopt_minimize, but xtol_abs is required to be non-NULL */
static nlopt_result nlopt_minimize_(
120
     nlopt_algorithm algorithm,
S
stevenj 已提交
121 122 123 124
     int n, nlopt_func f, void *f_data,
     const double *lb, const double *ub, /* bounds */
     double *x, /* in: initial guess, out: minimizer */
     double *fmin, /* out: minimum */
S
stevenj 已提交
125
     double fmin_max, double ftol_rel, double ftol_abs,
S
stevenj 已提交
126 127 128
     double xtol_rel, const double *xtol_abs,
     int maxeval, double maxtime)
{
129
     int i;
S
stevenj 已提交
130
     nlopt_data d;
131 132
     nlopt_stopping stop;

133 134 135 136
     /* some basic argument checks */
     if (n <= 0 || !f || !lb || !ub || !x || !fmin)
	  return NLOPT_INVALID_ARGS;

S
stevenj 已提交
137 138
     d.f = f;
     d.f_data = f_data;
139 140 141
     d.lb = lb;
     d.ub = ub;

142 143 144 145
     /* make sure rand generator is inited */
     if (!nlopt_srand_called)
	  nlopt_srand_time(); /* default is non-deterministic */

146 147 148 149
     /* check bound constraints */
     for (i = 0; i < n; ++i)
	  if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
	       return NLOPT_INVALID_ARGS;
S
stevenj 已提交
150

151 152 153 154 155 156 157 158 159 160 161 162
     stop.n = n;
     stop.fmin_max = (isnan(fmin_max) || (my_isinf(fmin_max) && fmin_max < 0))
	  ? -MY_INF : fmin_max;
     stop.ftol_rel = ftol_rel;
     stop.ftol_abs = ftol_abs;
     stop.xtol_rel = xtol_rel;
     stop.xtol_abs = xtol_abs;
     stop.nevals = 0;
     stop.maxeval = maxeval;
     stop.maxtime = maxtime;
     stop.start = nlopt_seconds();

163
     switch (algorithm) {
S
stevenj 已提交
164
	 case NLOPT_GLOBAL_DIRECT:
165
	 case NLOPT_GLOBAL_DIRECT_L: 
166 167
	 case NLOPT_GLOBAL_DIRECT_L_RANDOMIZED: 
	      return cdirect(n, f, f_data, lb, ub, x, fmin, &stop, 0.0, 
168 169 170
			     (algorithm != NLOPT_GLOBAL_DIRECT)
			     + 3 * (algorithm == NLOPT_GLOBAL_DIRECT_L_RANDOMIZED ? 2 : (algorithm != NLOPT_GLOBAL_DIRECT))
			     + 9 * (algorithm == NLOPT_GLOBAL_DIRECT_L_RANDOMIZED ? 1 : (algorithm != NLOPT_GLOBAL_DIRECT)));
171
	      
172 173
	 case NLOPT_GLOBAL_ORIG_DIRECT:
	 case NLOPT_GLOBAL_ORIG_DIRECT_L: 
174 175 176 177 178 179 180 181
	      switch (direct_optimize(f_direct, &d, n, lb, ub, x, fmin,
				      maxeval, -1, 0.0, 0.0,
				      pow(xtol_rel, (double) n), -1.0,
				      stop.fmin_max, 0.0,
				      NULL, 
				      algorithm == NLOPT_GLOBAL_ORIG_DIRECT
				      ? DIRECT_ORIGINAL
				      : DIRECT_GABLONSKY)) {
S
stevenj 已提交
182 183 184 185 186 187 188 189 190 191 192 193
		  case DIRECT_INVALID_BOUNDS:
		  case DIRECT_MAXFEVAL_TOOBIG:
		  case DIRECT_INVALID_ARGS:
		       return NLOPT_INVALID_ARGS;
		  case DIRECT_INIT_FAILED:
		  case DIRECT_SAMPLEPOINTS_FAILED:
		  case DIRECT_SAMPLE_FAILED:
		       return NLOPT_FAILURE;
		  case DIRECT_MAXFEVAL_EXCEEDED:
		  case DIRECT_MAXITER_EXCEEDED:
		       return NLOPT_MAXEVAL_REACHED;
		  case DIRECT_GLOBAL_FOUND:
194
		       return NLOPT_FMIN_MAX_REACHED;
S
stevenj 已提交
195 196 197 198 199
		  case DIRECT_VOLTOL:
		  case DIRECT_SIGMATOL:
		       return NLOPT_XTOL_REACHED;
		  case DIRECT_OUT_OF_MEMORY:
		       return NLOPT_OUT_OF_MEMORY;
S
stevenj 已提交
200
	      break;
201
	 }
S
stevenj 已提交
202 203

	 case NLOPT_GLOBAL_STOGO:
204 205 206 207 208
	 case NLOPT_GLOBAL_STOGO_RANDOMIZED:
	      if (!stogo_minimize(n, f, f_data, x, fmin, lb, ub, &stop,
				  algorithm == NLOPT_GLOBAL_STOGO
				  ? 0 : 2*n))
		   return NLOPT_FAILURE;
S
stevenj 已提交
209 210 211
	      break;

	 case NLOPT_LOCAL_SUBPLEX: {
212
	      int iret;
S
stevenj 已提交
213 214
	      double *scale = (double *) malloc(sizeof(double) * n);
	      if (!scale) return NLOPT_OUT_OF_MEMORY;
215 216 217 218 219 220 221 222 223 224
	      for (i = 0; i < n; ++i) {
		   if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
			scale[i] = (ub[i] - lb[i]) * 0.01;
		   else if (!my_isinf(lb[i]) && x[i] > lb[i])
			scale[i] = (x[i] - lb[i]) * 0.01;
		   else if (!my_isinf(ub[i]) && x[i] < ub[i])
			scale[i] = (ub[i] - x[i]) * 0.01;
		   else
			scale[i] = 0.01 * x[i] + 0.0001;
	      }
225
	      iret = subplex(f_subplex, fmin, x, n, &d, &stop, scale);
S
stevenj 已提交
226 227
	      free(scale);
	      switch (iret) {
S
stevenj 已提交
228
		  case -2: return NLOPT_INVALID_ARGS;
229
		  case -10: return NLOPT_MAXTIME_REACHED;
S
stevenj 已提交
230 231 232 233
		  case -1: return NLOPT_MAXEVAL_REACHED;
		  case 0: return NLOPT_XTOL_REACHED;
		  case 1: return NLOPT_SUCCESS;
		  case 2: return NLOPT_FMIN_MAX_REACHED;
234 235 236
		  case 20: return NLOPT_FTOL_REACHED;
		  case -200: return NLOPT_OUT_OF_MEMORY;
		  default: return NLOPT_FAILURE; /* unknown return code */
S
stevenj 已提交
237 238 239 240 241
	      }
	      break;
	 }

	 case NLOPT_LOCAL_LBFGS: {
242
	      int iret, *nbd = (int *) malloc(sizeof(int) * n);
S
stevenj 已提交
243 244
	      if (!nbd) return NLOPT_OUT_OF_MEMORY;
	      for (i = 0; i < n; ++i) {
S
stevenj 已提交
245 246
		   int linf = my_isinf(lb[i]) && lb[i] < 0;
		   int uinf = my_isinf(ub[i]) && ub[i] > 0;
S
stevenj 已提交
247 248 249 250
		   nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
	      }
	      iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
				     MIN(n, 5), 0.0, ftol_rel, 
S
whoops  
stevenj 已提交
251
				     xtol_abs ? *xtol_abs : xtol_rel,
S
stevenj 已提交
252 253 254 255
				     maxeval);
	      free(nbd);
	      if (iret <= 0) {
		   switch (iret) {
S
stevenj 已提交
256 257
		       case -1: return NLOPT_INVALID_ARGS;
		       case -2: default: return NLOPT_FAILURE;
S
stevenj 已提交
258 259 260 261 262
		   }
	      }
	      else {
		   *fmin = f(n, x, NULL, f_data);
		   switch (iret) {
S
stevenj 已提交
263 264 265
		       case 5: return NLOPT_MAXEVAL_REACHED;
		       case 2: return NLOPT_XTOL_REACHED;
		       case 1: return NLOPT_FTOL_REACHED;
S
stevenj 已提交
266 267 268 269 270 271 272 273 274 275 276 277
		       default: return NLOPT_SUCCESS;
		   }
	      }
	      break;
	 }

	 default:
	      return NLOPT_INVALID_ARGS;
     }

     return NLOPT_SUCCESS;
}
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305

nlopt_result nlopt_minimize(
     nlopt_algorithm algorithm,
     int n, nlopt_func f, void *f_data,
     const double *lb, const double *ub, /* bounds */
     double *x, /* in: initial guess, out: minimizer */
     double *fmin, /* out: minimum */
     double fmin_max, double ftol_rel, double ftol_abs,
     double xtol_rel, const double *xtol_abs,
     int maxeval, double maxtime)
{
     nlopt_result ret;
     if (xtol_abs)
	  ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
				x, fmin, fmin_max, ftol_rel, ftol_abs,
				xtol_rel, xtol_abs, maxeval, maxtime);
     else {
	  int i;
	  double *xtol = (double *) malloc(sizeof(double) * n);
	  if (!xtol) return NLOPT_OUT_OF_MEMORY;
	  for (i = 0; i < n; ++i) xtol[i] = -1;
	  ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
				x, fmin, fmin_max, ftol_rel, ftol_abs,
				xtol_rel, xtol, maxeval, maxtime);
	  free(xtol);
     }
     return ret;
}