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 const double *lb, const double *ub, /* bounds */
194 double *x, /* in: initial guess, out: minimizer */
195 double *minf, /* out: minimum */
196 double minf_max, double ftol_rel, double ftol_abs,
197 double xtol_rel, const double *xtol_abs,
198 int maxeval, double maxtime)
204 /* some basic argument checks */
205 if (!minf || !f) return NLOPT_INVALID_ARGS;
206 if (n == 0) { /* trivial case: no degrees of freedom */
207 *minf = f(n, x, NULL, f_data);
208 return NLOPT_SUCCESS;
210 else if (n < 0 || !lb || !ub || !x)
211 return NLOPT_INVALID_ARGS;
218 /* make sure rand generator is inited */
219 if (!nlopt_srand_called)
220 nlopt_srand_time(); /* default is non-deterministic */
222 /* check bound constraints */
223 for (i = 0; i < n; ++i)
224 if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
225 return NLOPT_INVALID_ARGS;
228 stop.minf_max = (isnan(minf_max)
229 || (nlopt_isinf(minf_max) && minf_max < 0))
230 ? -MY_INF : minf_max;
231 stop.ftol_rel = ftol_rel;
232 stop.ftol_abs = ftol_abs;
233 stop.xtol_rel = xtol_rel;
234 stop.xtol_abs = xtol_abs;
236 stop.maxeval = maxeval;
237 stop.maxtime = maxtime;
238 stop.start = nlopt_seconds();
241 case NLOPT_GN_DIRECT:
242 case NLOPT_GN_DIRECT_L:
243 case NLOPT_GN_DIRECT_L_RAND:
244 return cdirect(n, f, f_data, lb, ub, x, minf, &stop, 0.0,
245 (algorithm != NLOPT_GN_DIRECT)
246 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
247 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
249 case NLOPT_GN_DIRECT_NOSCAL:
250 case NLOPT_GN_DIRECT_L_NOSCAL:
251 case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
252 return cdirect_unscaled(n, f, f_data, lb, ub, x, minf,
254 (algorithm != NLOPT_GN_DIRECT)
255 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
256 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
258 case NLOPT_GN_ORIG_DIRECT:
259 case NLOPT_GN_ORIG_DIRECT_L:
260 switch (direct_optimize(f_direct, &d, n, lb, ub, x, minf,
261 maxeval, -1, 0.0, 0.0,
262 pow(xtol_rel, (double) n), -1.0,
265 algorithm == NLOPT_GN_ORIG_DIRECT
267 : DIRECT_GABLONSKY)) {
268 case DIRECT_INVALID_BOUNDS:
269 case DIRECT_MAXFEVAL_TOOBIG:
270 case DIRECT_INVALID_ARGS:
271 return NLOPT_INVALID_ARGS;
272 case DIRECT_INIT_FAILED:
273 case DIRECT_SAMPLEPOINTS_FAILED:
274 case DIRECT_SAMPLE_FAILED:
275 return NLOPT_FAILURE;
276 case DIRECT_MAXFEVAL_EXCEEDED:
277 case DIRECT_MAXITER_EXCEEDED:
278 return NLOPT_MAXEVAL_REACHED;
279 case DIRECT_GLOBAL_FOUND:
280 return NLOPT_MINF_MAX_REACHED;
282 case DIRECT_SIGMATOL:
283 return NLOPT_XTOL_REACHED;
284 case DIRECT_OUT_OF_MEMORY:
285 return NLOPT_OUT_OF_MEMORY;
290 case NLOPT_GD_STOGO_RAND:
292 if (!stogo_minimize(n, f, f_data, x, minf, lb, ub, &stop,
293 algorithm == NLOPT_GD_STOGO
295 return NLOPT_FAILURE;
298 return NLOPT_FAILURE;
301 case NLOPT_LN_SUBPLEX: {
303 double *scale = (double *) malloc(sizeof(double) * n);
304 if (!scale) return NLOPT_OUT_OF_MEMORY;
305 for (i = 0; i < n; ++i) {
306 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
307 scale[i] = (ub[i] - lb[i]) * 0.01;
308 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
309 scale[i] = (x[i] - lb[i]) * 0.01;
310 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
311 scale[i] = (ub[i] - x[i]) * 0.01;
313 scale[i] = 0.01 * x[i] + 0.0001;
315 iret = nlopt_subplex(f_subplex, minf, x, n, &d, &stop, scale);
318 case -2: return NLOPT_INVALID_ARGS;
319 case -10: return NLOPT_MAXTIME_REACHED;
320 case -1: return NLOPT_MAXEVAL_REACHED;
321 case 0: return NLOPT_XTOL_REACHED;
322 case 1: return NLOPT_SUCCESS;
323 case 2: return NLOPT_MINF_MAX_REACHED;
324 case 20: return NLOPT_FTOL_REACHED;
325 case -200: return NLOPT_OUT_OF_MEMORY;
326 default: return NLOPT_FAILURE; /* unknown return code */
331 case NLOPT_LN_PRAXIS: {
332 double h0 = HUGE_VAL;
333 for (i = 0; i < n; ++i) {
334 if (!nlopt_isinf(ub[i]) && !nlopt_isinf(lb[i]))
335 h0 = MIN(h0, (ub[i] - lb[i]) * 0.01);
336 else if (!nlopt_isinf(lb[i]) && x[i] > lb[i])
337 h0 = MIN(h0, (x[i] - lb[i]) * 0.01);
338 else if (!nlopt_isinf(ub[i]) && x[i] < ub[i])
339 h0 = MIN(h0, (ub[i] - x[i]) * 0.01);
341 h0 = MIN(h0, 0.01 * x[i] + 0.0001);
343 return praxis_(0.0, DBL_EPSILON, h0, n, x, f_subplex, &d,
348 case NLOPT_LD_LBFGS_NOCEDAL: {
349 int iret, *nbd = (int *) malloc(sizeof(int) * n);
350 if (!nbd) return NLOPT_OUT_OF_MEMORY;
351 for (i = 0; i < n; ++i) {
352 int linf = nlopt_isinf(lb[i]) && lb[i] < 0;
353 int uinf = nlopt_isinf(ub[i]) && ub[i] > 0;
354 nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
356 iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
357 MIN(n, 5), 0.0, ftol_rel,
358 xtol_abs ? *xtol_abs : xtol_rel,
363 case -1: return NLOPT_INVALID_ARGS;
364 case -2: default: return NLOPT_FAILURE;
368 *minf = f(n, x, NULL, f_data);
370 case 5: return NLOPT_MAXEVAL_REACHED;
371 case 2: return NLOPT_XTOL_REACHED;
372 case 1: return NLOPT_FTOL_REACHED;
373 default: return NLOPT_SUCCESS;
381 return luksan_plis(n, f, f_data, lb, ub, x, minf, &stop);
385 return luksan_plip(n, f, f_data, lb, ub, x, minf, &stop,
386 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
388 case NLOPT_LD_TNEWTON:
389 case NLOPT_LD_TNEWTON_RESTART:
390 case NLOPT_LD_TNEWTON_PRECOND:
391 case NLOPT_LD_TNEWTON_PRECOND_RESTART:
392 return luksan_pnet(n, f, f_data, lb, ub, x, minf, &stop,
393 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
394 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);
396 case NLOPT_GN_CRS2_LM:
397 return crs_minimize(n, f, f_data, lb, ub, x, minf, &stop, 0);
401 case NLOPT_GN_MLSL_LDS:
402 case NLOPT_GD_MLSL_LDS:
403 return mlsl_minimize(n, f, f_data, lb, ub, x, minf, &stop,
404 (algorithm == NLOPT_GN_MLSL ||
405 algorithm == NLOPT_GN_MLSL_LDS)
406 ? local_search_alg_nonderiv
407 : local_search_alg_deriv,
408 local_search_maxeval,
409 algorithm >= NLOPT_GN_MLSL_LDS);
412 return mma_minimize(n, f, f_data, 0, NULL, NULL, 0,
413 lb, ub, x, minf, &stop,
414 local_search_alg_deriv, 1e-8, 100000);
417 return NLOPT_INVALID_ARGS;
420 return NLOPT_SUCCESS;
423 nlopt_result nlopt_minimize(
424 nlopt_algorithm algorithm,
425 int n, nlopt_func f, void *f_data,
426 const double *lb, const double *ub, /* bounds */
427 double *x, /* in: initial guess, out: minimizer */
428 double *minf, /* out: minimum */
429 double minf_max, double ftol_rel, double ftol_abs,
430 double xtol_rel, const double *xtol_abs,
431 int maxeval, double maxtime)
435 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
436 x, minf, minf_max, ftol_rel, ftol_abs,
437 xtol_rel, xtol_abs, maxeval, maxtime);
440 double *xtol = (double *) malloc(sizeof(double) * n);
441 if (!xtol) return NLOPT_OUT_OF_MEMORY;
442 for (i = 0; i < n; ++i) xtol[i] = -1;
443 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
444 x, minf, minf_max, ftol_rel, ftol_abs,
445 xtol_rel, xtol, maxeval, maxtime);