1 /* Copyright (c) 2007-2008 Massachusetts Institute of Technology
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:
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
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.
29 #include "nlopt-util.h"
32 #define MIN(a,b) ((a) < (b) ? (a) : (b))
34 /*************************************************************************/
37 # define MY_INF INFINITY
39 # define MY_INF HUGE_VAL
42 int nlopt_isinf(double x) {
43 return fabs(x) >= HUGE_VAL * 0.99
51 static int my_isnan(double x) { return x != x; }
52 # define isnan my_isnan
55 /*************************************************************************/
57 void nlopt_version(int *major, int *minor, int *bugfix)
59 *major = MAJOR_VERSION;
60 *minor = MINOR_VERSION;
61 *bugfix = BUGFIX_VERSION;
64 /*************************************************************************/
66 static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][256] = {
67 "DIRECT (global, no-derivative)",
68 "DIRECT-L (global, no-derivative)",
69 "Randomized DIRECT-L (global, no-derivative)",
70 "Unscaled DIRECT (global, no-derivative)",
71 "Unscaled DIRECT-L (global, no-derivative)",
72 "Unscaled Randomized DIRECT-L (global, no-derivative)",
73 "Original DIRECT version (global, no-derivative)",
74 "Original DIRECT-L version (global, no-derivative)",
75 "Subplex (local, no-derivative)",
77 "StoGO (global, derivative-based)",
78 "StoGO with randomized search (global, derivative-based)",
80 "StoGO (NOT COMPILED)",
81 "StoGO randomized (NOT COMPILED)",
83 #ifdef WITH_NOCEDAL_LBFGS
84 "original NON-FREE L-BFGS code by Nocedal et al. (local, deriv.-based)",
86 "original NON-FREE L-BFGS code by Nocedal et al. (NOT COMPILED)",
88 "Limited-memory BFGS (L-BFGS) (local, derivative-based)",
89 "Principal-axis, praxis (local, no-derivative)",
90 "Limited-memory variable-metric, rank 1 (local, derivative-based)",
91 "Limited-memory variable-metric, rank 2 (local, derivative-based)",
92 "Truncated Newton (local, derivative-based)",
93 "Truncated Newton with restarting (local, derivative-based)",
94 "Preconditioned truncated Newton (local, derivative-based)",
95 "Preconditioned truncated Newton with restarting (local, derivative-based)",
96 "Controlled random search (CRS2) with local mutation (global, no-derivative)",
97 "Multi-level single-linkage (MLSL), random (global, no-derivative)",
98 "Multi-level single-linkage (MLSL), random (global, derivative)",
99 "Multi-level single-linkage (MLSL), quasi-random (global, no-derivative)",
100 "Multi-level single-linkage (MLSL), quasi-random (global, derivative)",
101 "Method of Moving Asymptotes (MMA) (local, derivative)"
104 const char *nlopt_algorithm_name(nlopt_algorithm a)
106 if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
107 return nlopt_algorithm_names[a];
110 /*************************************************************************/
112 static int nlopt_srand_called = 0;
113 void nlopt_srand(unsigned long seed) {
114 nlopt_srand_called = 1;
115 nlopt_init_genrand(seed);
118 void nlopt_srand_time() {
119 nlopt_srand(nlopt_time_seed());
122 /*************************************************************************/
127 const double *lb, *ub;
133 static double f_subplex(int n, const double *x, void *data_)
136 nlopt_data *data = (nlopt_data *) data_;
139 /* subplex does not support bound constraints, but it supports
140 discontinuous objectives so we can just return Inf for invalid x */
141 for (i = 0; i < n; ++i)
142 if (x[i] < data->lb[i] || x[i] > data->ub[i])
145 f = data->f(n, x, NULL, data->f_data);
146 return (isnan(f) ? MY_INF : f);
151 static double f_direct(int n, const double *x, int *undefined, void *data_)
153 nlopt_data *data = (nlopt_data *) data_;
155 f = data->f(n, x, NULL, data->f_data);
156 *undefined = isnan(f) || nlopt_isinf(f);
167 # include "l-bfgs-b.h"
177 /*************************************************************************/
179 /* for "hybrid" algorithms that combine global search with some
180 local search algorithm, most of the time we anticipate that people
181 will stick with the default local search algorithm, so we
182 don't add this as a parameter to nlopt_minimize. Instead, the user
183 can call nlopt_{set/get}_hybrid_local_algorithm to get/set the defaults. */
185 /* default local-search algorithms */
186 static nlopt_algorithm local_search_alg_deriv = NLOPT_LD_LBFGS;
187 static nlopt_algorithm local_search_alg_nonderiv = NLOPT_LN_SUBPLEX;
189 static int local_search_maxeval = -1; /* no maximum by default */
191 void nlopt_get_local_search_algorithm(nlopt_algorithm *deriv,
192 nlopt_algorithm *nonderiv,
195 *deriv = local_search_alg_deriv;
196 *nonderiv = local_search_alg_nonderiv;
197 *maxeval = local_search_maxeval;
200 void nlopt_set_local_search_algorithm(nlopt_algorithm deriv,
201 nlopt_algorithm nonderiv,
204 local_search_alg_deriv = deriv;
205 local_search_alg_nonderiv = nonderiv;
206 local_search_maxeval = maxeval;
209 /*************************************************************************/
211 /* same as nlopt_minimize, but xtol_abs is required to be non-NULL */
212 static nlopt_result nlopt_minimize_(
213 nlopt_algorithm algorithm,
214 int n, nlopt_func f, void *f_data,
215 int m, nlopt_func fc, void *fc_data, ptrdiff_t fc_datum_size,
216 const double *lb, const double *ub, /* bounds */
217 double *x, /* in: initial guess, out: minimizer */
218 double *minf, /* out: minimum */
219 double minf_max, double ftol_rel, double ftol_abs,
220 double xtol_rel, const double *xtol_abs,
221 int maxeval, double maxtime)
227 /* some basic argument checks */
228 if (!minf || !f || n < 0 || m < 0
229 || (m > 0 && !fc)) return NLOPT_INVALID_ARGS;
230 if (n == 0) { /* trivial case: no degrees of freedom */
231 *minf = f(n, x, NULL, f_data);
232 return NLOPT_SUCCESS;
234 else if (n < 0 || !lb || !ub || !x)
235 return NLOPT_INVALID_ARGS;
237 /* nonlinear constraints are only supported with MMA */
238 if (m != 0 && algorithm != NLOPT_LD_MMA) return NLOPT_INVALID_ARGS;
245 /* make sure rand generator is inited */
246 if (!nlopt_srand_called)
247 nlopt_srand_time(); /* default is non-deterministic */
249 /* check bound constraints */
250 for (i = 0; i < n; ++i)
251 if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
252 return NLOPT_INVALID_ARGS;
255 stop.minf_max = (isnan(minf_max)
256 || (nlopt_isinf(minf_max) && minf_max < 0))
257 ? -MY_INF : minf_max;
258 stop.ftol_rel = ftol_rel;
259 stop.ftol_abs = ftol_abs;
260 stop.xtol_rel = xtol_rel;
261 stop.xtol_abs = xtol_abs;
263 stop.maxeval = maxeval;
264 stop.maxtime = maxtime;
265 stop.start = nlopt_seconds();
268 case NLOPT_GN_DIRECT:
269 case NLOPT_GN_DIRECT_L:
270 case NLOPT_GN_DIRECT_L_RAND:
271 return cdirect(n, f, f_data, lb, ub, x, minf, &stop, 0.0,
272 (algorithm != NLOPT_GN_DIRECT)
273 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
274 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
276 case NLOPT_GN_DIRECT_NOSCAL:
277 case NLOPT_GN_DIRECT_L_NOSCAL:
278 case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
279 return cdirect_unscaled(n, f, f_data, lb, ub, x, minf,
281 (algorithm != NLOPT_GN_DIRECT)
282 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
283 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
285 case NLOPT_GN_ORIG_DIRECT:
286 case NLOPT_GN_ORIG_DIRECT_L:
287 switch (direct_optimize(f_direct, &d, n, lb, ub, x, minf,
288 maxeval, -1, 0.0, 0.0,
289 pow(xtol_rel, (double) n), -1.0,
292 algorithm == NLOPT_GN_ORIG_DIRECT
294 : DIRECT_GABLONSKY)) {
295 case DIRECT_INVALID_BOUNDS:
296 case DIRECT_MAXFEVAL_TOOBIG:
297 case DIRECT_INVALID_ARGS:
298 return NLOPT_INVALID_ARGS;
299 case DIRECT_INIT_FAILED:
300 case DIRECT_SAMPLEPOINTS_FAILED:
301 case DIRECT_SAMPLE_FAILED:
302 return NLOPT_FAILURE;
303 case DIRECT_MAXFEVAL_EXCEEDED:
304 case DIRECT_MAXITER_EXCEEDED:
305 return NLOPT_MAXEVAL_REACHED;
306 case DIRECT_GLOBAL_FOUND:
307 return NLOPT_MINF_MAX_REACHED;
309 case DIRECT_SIGMATOL:
310 return NLOPT_XTOL_REACHED;
311 case DIRECT_OUT_OF_MEMORY:
312 return NLOPT_OUT_OF_MEMORY;
317 case NLOPT_GD_STOGO_RAND:
319 if (!stogo_minimize(n, f, f_data, x, minf, lb, ub, &stop,
320 algorithm == NLOPT_GD_STOGO
322 return NLOPT_FAILURE;
325 return NLOPT_FAILURE;
328 case NLOPT_LN_SUBPLEX: {
330 double *scale = (double *) malloc(sizeof(double) * n);
331 if (!scale) return NLOPT_OUT_OF_MEMORY;
332 for (i = 0; i < n; ++i) {
333 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
334 scale[i] = (ub[i] - lb[i]) * 0.01;
335 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
336 scale[i] = (x[i] - lb[i]) * 0.01;
337 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
338 scale[i] = (ub[i] - x[i]) * 0.01;
340 scale[i] = 0.01 * x[i] + 0.0001;
342 iret = nlopt_subplex(f_subplex, minf, x, n, &d, &stop, scale);
345 case -2: return NLOPT_INVALID_ARGS;
346 case -10: return NLOPT_MAXTIME_REACHED;
347 case -1: return NLOPT_MAXEVAL_REACHED;
348 case 0: return NLOPT_XTOL_REACHED;
349 case 1: return NLOPT_SUCCESS;
350 case 2: return NLOPT_MINF_MAX_REACHED;
351 case 20: return NLOPT_FTOL_REACHED;
352 case -200: return NLOPT_OUT_OF_MEMORY;
353 default: return NLOPT_FAILURE; /* unknown return code */
358 case NLOPT_LN_PRAXIS: {
359 double h0 = HUGE_VAL;
360 for (i = 0; i < n; ++i) {
361 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
362 h0 = MIN(h0, (ub[i] - lb[i]) * 0.01);
363 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
364 h0 = MIN(h0, (x[i] - lb[i]) * 0.01);
365 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
366 h0 = MIN(h0, (ub[i] - x[i]) * 0.01);
368 h0 = MIN(h0, 0.01 * x[i] + 0.0001);
370 return praxis_(0.0, DBL_EPSILON, h0, n, x, f_subplex, &d,
375 case NLOPT_LD_LBFGS_NOCEDAL: {
376 int iret, *nbd = (int *) malloc(sizeof(int) * n);
377 if (!nbd) return NLOPT_OUT_OF_MEMORY;
378 for (i = 0; i < n; ++i) {
379 int linf = nlopt_isinf(lb[i]) && lb[i] < 0;
380 int uinf = nlopt_isinf(ub[i]) && ub[i] > 0;
381 nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
383 iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
384 MIN(n, 5), 0.0, ftol_rel,
385 xtol_abs ? *xtol_abs : xtol_rel,
390 case -1: return NLOPT_INVALID_ARGS;
391 case -2: default: return NLOPT_FAILURE;
395 *minf = f(n, x, NULL, f_data);
397 case 5: return NLOPT_MAXEVAL_REACHED;
398 case 2: return NLOPT_XTOL_REACHED;
399 case 1: return NLOPT_FTOL_REACHED;
400 default: return NLOPT_SUCCESS;
408 return luksan_plis(n, f, f_data, lb, ub, x, minf, &stop);
412 return luksan_plip(n, f, f_data, lb, ub, x, minf, &stop,
413 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
415 case NLOPT_LD_TNEWTON:
416 case NLOPT_LD_TNEWTON_RESTART:
417 case NLOPT_LD_TNEWTON_PRECOND:
418 case NLOPT_LD_TNEWTON_PRECOND_RESTART:
419 return luksan_pnet(n, f, f_data, lb, ub, x, minf, &stop,
420 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
421 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);
423 case NLOPT_GN_CRS2_LM:
424 return crs_minimize(n, f, f_data, lb, ub, x, minf, &stop, 0);
428 case NLOPT_GN_MLSL_LDS:
429 case NLOPT_GD_MLSL_LDS:
430 return mlsl_minimize(n, f, f_data, lb, ub, x, minf, &stop,
431 (algorithm == NLOPT_GN_MLSL ||
432 algorithm == NLOPT_GN_MLSL_LDS)
433 ? local_search_alg_nonderiv
434 : local_search_alg_deriv,
435 local_search_maxeval,
436 algorithm >= NLOPT_GN_MLSL_LDS);
439 return mma_minimize(n, f, f_data, m, fc, fc_data, fc_datum_size,
440 lb, ub, x, minf, &stop,
441 local_search_alg_deriv, 1e-12, 100000);
444 return NLOPT_INVALID_ARGS;
447 return NLOPT_SUCCESS;
450 nlopt_result nlopt_minimize_constrained(
451 nlopt_algorithm algorithm,
452 int n, nlopt_func f, void *f_data,
453 int m, nlopt_func fc, void *fc_data, ptrdiff_t fc_datum_size,
454 const double *lb, const double *ub, /* bounds */
455 double *x, /* in: initial guess, out: minimizer */
456 double *minf, /* out: minimum */
457 double minf_max, double ftol_rel, double ftol_abs,
458 double xtol_rel, const double *xtol_abs,
459 int maxeval, double maxtime)
463 ret = nlopt_minimize_(algorithm, n, f, f_data,
464 m, fc, fc_data, fc_datum_size, lb, ub,
465 x, minf, minf_max, ftol_rel, ftol_abs,
466 xtol_rel, xtol_abs, maxeval, maxtime);
469 double *xtol = (double *) malloc(sizeof(double) * n);
470 if (!xtol) return NLOPT_OUT_OF_MEMORY;
471 for (i = 0; i < n; ++i) xtol[i] = -1;
472 ret = nlopt_minimize_(algorithm, n, f, f_data,
473 m, fc, fc_data, fc_datum_size, lb, ub,
474 x, minf, minf_max, ftol_rel, ftol_abs,
475 xtol_rel, xtol, maxeval, maxtime);
481 nlopt_result nlopt_minimize(
482 nlopt_algorithm algorithm,
483 int n, nlopt_func f, void *f_data,
484 const double *lb, const double *ub, /* bounds */
485 double *x, /* in: initial guess, out: minimizer */
486 double *minf, /* out: minimum */
487 double minf_max, double ftol_rel, double ftol_abs,
488 double xtol_rel, const double *xtol_abs,
489 int maxeval, double maxtime)
491 return nlopt_minimize_constrained(
492 algorithm, n, f, f_data, 0, NULL, NULL, 0,
493 lb, ub, x, minf, minf_max, ftol_rel, ftol_abs,
494 xtol_rel, xtol_abs, maxeval, maxtime);