7 #include "nlopt-util.h"
10 #define MIN(a,b) ((a) < (b) ? (a) : (b))
12 /*************************************************************************/
15 # define MY_INF INFINITY
17 # define MY_INF HUGE_VAL
20 int nlopt_isinf(double x) {
21 return fabs(x) >= HUGE_VAL * 0.99
29 static int my_isnan(double x) { return x != x; }
30 # define isnan my_isnan
33 /*************************************************************************/
35 void nlopt_version(int *major, int *minor, int *bugfix)
37 *major = MAJOR_VERSION;
38 *minor = MINOR_VERSION;
39 *bugfix = BUGFIX_VERSION;
42 /*************************************************************************/
44 static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][256] = {
45 "DIRECT (global, no-derivative)",
46 "DIRECT-L (global, no-derivative)",
47 "Randomized DIRECT-L (global, no-derivative)",
48 "Unscaled DIRECT (global, no-derivative)",
49 "Unscaled DIRECT-L (global, no-derivative)",
50 "Unscaled Randomized DIRECT-L (global, no-derivative)",
51 "Original DIRECT version (global, no-derivative)",
52 "Original DIRECT-L version (global, no-derivative)",
53 "Subplex (local, no-derivative)",
55 "StoGO (global, derivative-based)",
56 "StoGO with randomized search (global, derivative-based)",
58 "StoGO (NOT COMPILED)",
59 "StoGO randomized (NOT COMPILED)",
61 #ifdef WITH_NOCEDAL_LBFGS
62 "original NON-FREE L-BFGS code by Nocedal et al. (local, deriv.-based)",
64 "original NON-FREE L-BFGS code by Nocedal et al. (NOT COMPILED)",
66 "Limited-memory BFGS (L-BFGS) (local, derivative-based)",
67 "Principal-axis, praxis (local, no-derivative)",
68 "Limited-memory variable-metric, rank 1 (local, derivative-based)",
69 "Limited-memory variable-metric, rank 2 (local, derivative-based)",
70 "Truncated Newton (local, derivative-based)",
71 "Truncated Newton with restarting (local, derivative-based)",
72 "Preconditioned truncated Newton (local, derivative-based)",
73 "Preconditioned truncated Newton with restarting (local, derivative-based)",
74 "Controlled random search (CRS2) with local mutation (global, no-derivative)",
75 "Multi-level single-linkage (MLSL), random (global, no-derivative)",
76 "Multi-level single-linkage (MLSL), random (global, derivative)",
77 "Multi-level single-linkage (MLSL), quasi-random (global, no-derivative)",
78 "Multi-level single-linkage (MLSL), quasi-random (global, derivative)",
79 "Method of Moving Asymptotes (MMA) (local, derivative)"
82 const char *nlopt_algorithm_name(nlopt_algorithm a)
84 if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
85 return nlopt_algorithm_names[a];
88 /*************************************************************************/
90 static int nlopt_srand_called = 0;
91 void nlopt_srand(unsigned long seed) {
92 nlopt_srand_called = 1;
93 nlopt_init_genrand(seed);
96 void nlopt_srand_time() {
97 nlopt_srand(nlopt_time_seed());
100 /*************************************************************************/
105 const double *lb, *ub;
111 static double f_subplex(int n, const double *x, void *data_)
114 nlopt_data *data = (nlopt_data *) data_;
117 /* subplex does not support bound constraints, but it supports
118 discontinuous objectives so we can just return Inf for invalid x */
119 for (i = 0; i < n; ++i)
120 if (x[i] < data->lb[i] || x[i] > data->ub[i])
123 f = data->f(n, x, NULL, data->f_data);
124 return (isnan(f) ? MY_INF : f);
129 static double f_direct(int n, const double *x, int *undefined, void *data_)
131 nlopt_data *data = (nlopt_data *) data_;
133 f = data->f(n, x, NULL, data->f_data);
134 *undefined = isnan(f) || nlopt_isinf(f);
145 # include "l-bfgs-b.h"
155 /*************************************************************************/
157 /* for "hybrid" algorithms that combine global search with some
158 local search algorithm, most of the time we anticipate that people
159 will stick with the default local search algorithm, so we
160 don't add this as a parameter to nlopt_minimize. Instead, the user
161 can call nlopt_{set/get}_hybrid_local_algorithm to get/set the defaults. */
163 /* default local-search algorithms */
164 static nlopt_algorithm local_search_alg_deriv = NLOPT_LD_LBFGS;
165 static nlopt_algorithm local_search_alg_nonderiv = NLOPT_LN_SUBPLEX;
167 static int local_search_maxeval = -1; /* no maximum by default */
169 void nlopt_get_local_search_algorithm(nlopt_algorithm *deriv,
170 nlopt_algorithm *nonderiv,
173 *deriv = local_search_alg_deriv;
174 *nonderiv = local_search_alg_nonderiv;
175 *maxeval = local_search_maxeval;
178 void nlopt_set_local_search_algorithm(nlopt_algorithm deriv,
179 nlopt_algorithm nonderiv,
182 local_search_alg_deriv = deriv;
183 local_search_alg_nonderiv = nonderiv;
184 local_search_maxeval = maxeval;
187 /*************************************************************************/
189 /* same as nlopt_minimize, but xtol_abs is required to be non-NULL */
190 static nlopt_result nlopt_minimize_(
191 nlopt_algorithm algorithm,
192 int n, nlopt_func f, void *f_data,
193 int m, nlopt_func fc, void *fc_data, ptrdiff_t fc_datum_size,
194 const double *lb, const double *ub, /* bounds */
195 double *x, /* in: initial guess, out: minimizer */
196 double *minf, /* out: minimum */
197 double minf_max, double ftol_rel, double ftol_abs,
198 double xtol_rel, const double *xtol_abs,
199 int maxeval, double maxtime)
205 /* some basic argument checks */
206 if (!minf || !f || n < 0 || m < 0
207 || (m > 0 && !fc)) return NLOPT_INVALID_ARGS;
208 if (n == 0) { /* trivial case: no degrees of freedom */
209 *minf = f(n, x, NULL, f_data);
210 return NLOPT_SUCCESS;
212 else if (n < 0 || !lb || !ub || !x)
213 return NLOPT_INVALID_ARGS;
215 /* nonlinear constraints are only supported with MMA */
216 if (m != 0 && algorithm != NLOPT_LD_MMA) return NLOPT_INVALID_ARGS;
223 /* make sure rand generator is inited */
224 if (!nlopt_srand_called)
225 nlopt_srand_time(); /* default is non-deterministic */
227 /* check bound constraints */
228 for (i = 0; i < n; ++i)
229 if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
230 return NLOPT_INVALID_ARGS;
233 stop.minf_max = (isnan(minf_max)
234 || (nlopt_isinf(minf_max) && minf_max < 0))
235 ? -MY_INF : minf_max;
236 stop.ftol_rel = ftol_rel;
237 stop.ftol_abs = ftol_abs;
238 stop.xtol_rel = xtol_rel;
239 stop.xtol_abs = xtol_abs;
241 stop.maxeval = maxeval;
242 stop.maxtime = maxtime;
243 stop.start = nlopt_seconds();
246 case NLOPT_GN_DIRECT:
247 case NLOPT_GN_DIRECT_L:
248 case NLOPT_GN_DIRECT_L_RAND:
249 return cdirect(n, f, f_data, lb, ub, x, minf, &stop, 0.0,
250 (algorithm != NLOPT_GN_DIRECT)
251 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
252 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
254 case NLOPT_GN_DIRECT_NOSCAL:
255 case NLOPT_GN_DIRECT_L_NOSCAL:
256 case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
257 return cdirect_unscaled(n, f, f_data, lb, ub, x, minf,
259 (algorithm != NLOPT_GN_DIRECT)
260 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
261 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
263 case NLOPT_GN_ORIG_DIRECT:
264 case NLOPT_GN_ORIG_DIRECT_L:
265 switch (direct_optimize(f_direct, &d, n, lb, ub, x, minf,
266 maxeval, -1, 0.0, 0.0,
267 pow(xtol_rel, (double) n), -1.0,
270 algorithm == NLOPT_GN_ORIG_DIRECT
272 : DIRECT_GABLONSKY)) {
273 case DIRECT_INVALID_BOUNDS:
274 case DIRECT_MAXFEVAL_TOOBIG:
275 case DIRECT_INVALID_ARGS:
276 return NLOPT_INVALID_ARGS;
277 case DIRECT_INIT_FAILED:
278 case DIRECT_SAMPLEPOINTS_FAILED:
279 case DIRECT_SAMPLE_FAILED:
280 return NLOPT_FAILURE;
281 case DIRECT_MAXFEVAL_EXCEEDED:
282 case DIRECT_MAXITER_EXCEEDED:
283 return NLOPT_MAXEVAL_REACHED;
284 case DIRECT_GLOBAL_FOUND:
285 return NLOPT_MINF_MAX_REACHED;
287 case DIRECT_SIGMATOL:
288 return NLOPT_XTOL_REACHED;
289 case DIRECT_OUT_OF_MEMORY:
290 return NLOPT_OUT_OF_MEMORY;
295 case NLOPT_GD_STOGO_RAND:
297 if (!stogo_minimize(n, f, f_data, x, minf, lb, ub, &stop,
298 algorithm == NLOPT_GD_STOGO
300 return NLOPT_FAILURE;
303 return NLOPT_FAILURE;
306 case NLOPT_LN_SUBPLEX: {
308 double *scale = (double *) malloc(sizeof(double) * n);
309 if (!scale) return NLOPT_OUT_OF_MEMORY;
310 for (i = 0; i < n; ++i) {
311 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
312 scale[i] = (ub[i] - lb[i]) * 0.01;
313 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
314 scale[i] = (x[i] - lb[i]) * 0.01;
315 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
316 scale[i] = (ub[i] - x[i]) * 0.01;
318 scale[i] = 0.01 * x[i] + 0.0001;
320 iret = nlopt_subplex(f_subplex, minf, x, n, &d, &stop, scale);
323 case -2: return NLOPT_INVALID_ARGS;
324 case -10: return NLOPT_MAXTIME_REACHED;
325 case -1: return NLOPT_MAXEVAL_REACHED;
326 case 0: return NLOPT_XTOL_REACHED;
327 case 1: return NLOPT_SUCCESS;
328 case 2: return NLOPT_MINF_MAX_REACHED;
329 case 20: return NLOPT_FTOL_REACHED;
330 case -200: return NLOPT_OUT_OF_MEMORY;
331 default: return NLOPT_FAILURE; /* unknown return code */
336 case NLOPT_LN_PRAXIS: {
337 double h0 = HUGE_VAL;
338 for (i = 0; i < n; ++i) {
339 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
340 h0 = MIN(h0, (ub[i] - lb[i]) * 0.01);
341 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
342 h0 = MIN(h0, (x[i] - lb[i]) * 0.01);
343 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
344 h0 = MIN(h0, (ub[i] - x[i]) * 0.01);
346 h0 = MIN(h0, 0.01 * x[i] + 0.0001);
348 return praxis_(0.0, DBL_EPSILON, h0, n, x, f_subplex, &d,
353 case NLOPT_LD_LBFGS_NOCEDAL: {
354 int iret, *nbd = (int *) malloc(sizeof(int) * n);
355 if (!nbd) return NLOPT_OUT_OF_MEMORY;
356 for (i = 0; i < n; ++i) {
357 int linf = nlopt_isinf(lb[i]) && lb[i] < 0;
358 int uinf = nlopt_isinf(ub[i]) && ub[i] > 0;
359 nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
361 iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
362 MIN(n, 5), 0.0, ftol_rel,
363 xtol_abs ? *xtol_abs : xtol_rel,
368 case -1: return NLOPT_INVALID_ARGS;
369 case -2: default: return NLOPT_FAILURE;
373 *minf = f(n, x, NULL, f_data);
375 case 5: return NLOPT_MAXEVAL_REACHED;
376 case 2: return NLOPT_XTOL_REACHED;
377 case 1: return NLOPT_FTOL_REACHED;
378 default: return NLOPT_SUCCESS;
386 return luksan_plis(n, f, f_data, lb, ub, x, minf, &stop);
390 return luksan_plip(n, f, f_data, lb, ub, x, minf, &stop,
391 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
393 case NLOPT_LD_TNEWTON:
394 case NLOPT_LD_TNEWTON_RESTART:
395 case NLOPT_LD_TNEWTON_PRECOND:
396 case NLOPT_LD_TNEWTON_PRECOND_RESTART:
397 return luksan_pnet(n, f, f_data, lb, ub, x, minf, &stop,
398 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
399 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);
401 case NLOPT_GN_CRS2_LM:
402 return crs_minimize(n, f, f_data, lb, ub, x, minf, &stop, 0);
406 case NLOPT_GN_MLSL_LDS:
407 case NLOPT_GD_MLSL_LDS:
408 return mlsl_minimize(n, f, f_data, lb, ub, x, minf, &stop,
409 (algorithm == NLOPT_GN_MLSL ||
410 algorithm == NLOPT_GN_MLSL_LDS)
411 ? local_search_alg_nonderiv
412 : local_search_alg_deriv,
413 local_search_maxeval,
414 algorithm >= NLOPT_GN_MLSL_LDS);
417 return mma_minimize(n, f, f_data, m, fc, fc_data, fc_datum_size,
418 lb, ub, x, minf, &stop,
419 local_search_alg_deriv, 1e-12, 100000);
422 return NLOPT_INVALID_ARGS;
425 return NLOPT_SUCCESS;
428 nlopt_result nlopt_minimize_constrained(
429 nlopt_algorithm algorithm,
430 int n, nlopt_func f, void *f_data,
431 int m, nlopt_func fc, void *fc_data, ptrdiff_t fc_datum_size,
432 const double *lb, const double *ub, /* bounds */
433 double *x, /* in: initial guess, out: minimizer */
434 double *minf, /* out: minimum */
435 double minf_max, double ftol_rel, double ftol_abs,
436 double xtol_rel, const double *xtol_abs,
437 int maxeval, double maxtime)
441 ret = nlopt_minimize_(algorithm, n, f, f_data,
442 m, fc, fc_data, fc_datum_size, lb, ub,
443 x, minf, minf_max, ftol_rel, ftol_abs,
444 xtol_rel, xtol_abs, maxeval, maxtime);
447 double *xtol = (double *) malloc(sizeof(double) * n);
448 if (!xtol) return NLOPT_OUT_OF_MEMORY;
449 for (i = 0; i < n; ++i) xtol[i] = -1;
450 ret = nlopt_minimize_(algorithm, n, f, f_data,
451 m, fc, fc_data, fc_datum_size, lb, ub,
452 x, minf, minf_max, ftol_rel, ftol_abs,
453 xtol_rel, xtol, maxeval, maxtime);
459 nlopt_result nlopt_minimize(
460 nlopt_algorithm algorithm,
461 int n, nlopt_func f, void *f_data,
462 const double *lb, const double *ub, /* bounds */
463 double *x, /* in: initial guess, out: minimizer */
464 double *minf, /* out: minimum */
465 double minf_max, double ftol_rel, double ftol_abs,
466 double xtol_rel, const double *xtol_abs,
467 int maxeval, double maxtime)
469 return nlopt_minimize_constrained(
470 algorithm, n, f, f_data, 0, NULL, NULL, 0,
471 lb, ub, x, minf, minf_max, ftol_rel, ftol_abs,
472 xtol_rel, xtol_abs, maxeval, maxtime);