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 static int my_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 "Low-storage BFGS (LBFGS) (local, derivative-based)",
62 "Principal-axis, praxis (local, no-derivative)",
63 "Limited-memory variable-metric, rank 1 (local, derivative-based)",
64 "Limited-memory variable-metric, rank 2 (local, derivative-based)",
65 "Truncated Newton (local, derivative-based)",
66 "Truncated Newton with restarting (local, derivative-based)",
67 "Preconditioned truncated Newton (local, derivative-based)",
68 "Preconditioned truncated Newton with restarting (local, derivative-based)",
69 "Controlled random search (CRS2) with local mutation (global, no-derivative)",
70 "Multi-level single-linkage (MLSL), random (global, no-derivative)",
71 "Multi-level single-linkage (MLSL), random (global, derivative)",
72 "Multi-level single-linkage (MLSL), quasi-random (global, no-derivative)",
73 "Multi-level single-linkage (MLSL), quasi-random (global, derivative)"
76 const char *nlopt_algorithm_name(nlopt_algorithm a)
78 if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
79 return nlopt_algorithm_names[a];
82 /*************************************************************************/
84 static int nlopt_srand_called = 0;
85 void nlopt_srand(unsigned long seed) {
86 nlopt_srand_called = 1;
87 nlopt_init_genrand(seed);
90 void nlopt_srand_time() {
91 nlopt_srand(nlopt_time_seed());
94 /*************************************************************************/
99 const double *lb, *ub;
105 static double f_subplex(int n, const double *x, void *data_)
108 nlopt_data *data = (nlopt_data *) data_;
111 /* subplex does not support bound constraints, but it supports
112 discontinuous objectives so we can just return Inf for invalid x */
113 for (i = 0; i < n; ++i)
114 if (x[i] < data->lb[i] || x[i] > data->ub[i])
117 f = data->f(n, x, NULL, data->f_data);
118 return (isnan(f) ? MY_INF : f);
123 static double f_direct(int n, const double *x, int *undefined, void *data_)
125 nlopt_data *data = (nlopt_data *) data_;
127 f = data->f(n, x, NULL, data->f_data);
128 *undefined = isnan(f) || my_isinf(f);
142 /*************************************************************************/
144 /* for "hybrid" algorithms that combine global search with some
145 local search algorithm, most of the time we anticipate that people
146 will stick with the default local search algorithm, so we
147 don't add this as a parameter to nlopt_minimize. Instead, the user
148 can call nlopt_{set/get}_hybrid_local_algorithm to get/set the defaults. */
150 /* default local-search algorithms */
151 static nlopt_algorithm local_search_alg_deriv = NLOPT_LD_LBFGS;
152 static nlopt_algorithm local_search_alg_nonderiv = NLOPT_LN_SUBPLEX;
154 static int local_search_maxeval = -1; /* no maximum by default */
156 void nlopt_get_local_search_algorithm(nlopt_algorithm *deriv,
157 nlopt_algorithm *nonderiv,
160 *deriv = local_search_alg_deriv;
161 *nonderiv = local_search_alg_nonderiv;
162 *maxeval = local_search_maxeval;
165 void nlopt_set_local_search_algorithm(nlopt_algorithm deriv,
166 nlopt_algorithm nonderiv,
169 local_search_alg_deriv = deriv;
170 local_search_alg_nonderiv = nonderiv;
171 local_search_maxeval = maxeval;
174 /*************************************************************************/
176 /* same as nlopt_minimize, but xtol_abs is required to be non-NULL */
177 static nlopt_result nlopt_minimize_(
178 nlopt_algorithm algorithm,
179 int n, nlopt_func f, void *f_data,
180 const double *lb, const double *ub, /* bounds */
181 double *x, /* in: initial guess, out: minimizer */
182 double *minf, /* out: minimum */
183 double minf_max, double ftol_rel, double ftol_abs,
184 double xtol_rel, const double *xtol_abs,
185 int maxeval, double maxtime)
191 /* some basic argument checks */
192 if (n <= 0 || !f || !lb || !ub || !x || !minf)
193 return NLOPT_INVALID_ARGS;
200 /* make sure rand generator is inited */
201 if (!nlopt_srand_called)
202 nlopt_srand_time(); /* default is non-deterministic */
204 /* check bound constraints */
205 for (i = 0; i < n; ++i)
206 if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
207 return NLOPT_INVALID_ARGS;
210 stop.minf_max = (isnan(minf_max) || (my_isinf(minf_max) && minf_max < 0))
211 ? -MY_INF : minf_max;
212 stop.ftol_rel = ftol_rel;
213 stop.ftol_abs = ftol_abs;
214 stop.xtol_rel = xtol_rel;
215 stop.xtol_abs = xtol_abs;
217 stop.maxeval = maxeval;
218 stop.maxtime = maxtime;
219 stop.start = nlopt_seconds();
222 case NLOPT_GN_DIRECT:
223 case NLOPT_GN_DIRECT_L:
224 case NLOPT_GN_DIRECT_L_RAND:
225 return cdirect(n, f, f_data, lb, ub, x, minf, &stop, 0.0,
226 (algorithm != NLOPT_GN_DIRECT)
227 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
228 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
230 case NLOPT_GN_DIRECT_NOSCAL:
231 case NLOPT_GN_DIRECT_L_NOSCAL:
232 case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
233 return cdirect_unscaled(n, f, f_data, lb, ub, x, minf,
235 (algorithm != NLOPT_GN_DIRECT)
236 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
237 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
239 case NLOPT_GN_ORIG_DIRECT:
240 case NLOPT_GN_ORIG_DIRECT_L:
241 switch (direct_optimize(f_direct, &d, n, lb, ub, x, minf,
242 maxeval, -1, 0.0, 0.0,
243 pow(xtol_rel, (double) n), -1.0,
246 algorithm == NLOPT_GN_ORIG_DIRECT
248 : DIRECT_GABLONSKY)) {
249 case DIRECT_INVALID_BOUNDS:
250 case DIRECT_MAXFEVAL_TOOBIG:
251 case DIRECT_INVALID_ARGS:
252 return NLOPT_INVALID_ARGS;
253 case DIRECT_INIT_FAILED:
254 case DIRECT_SAMPLEPOINTS_FAILED:
255 case DIRECT_SAMPLE_FAILED:
256 return NLOPT_FAILURE;
257 case DIRECT_MAXFEVAL_EXCEEDED:
258 case DIRECT_MAXITER_EXCEEDED:
259 return NLOPT_MAXEVAL_REACHED;
260 case DIRECT_GLOBAL_FOUND:
261 return NLOPT_MINF_MAX_REACHED;
263 case DIRECT_SIGMATOL:
264 return NLOPT_XTOL_REACHED;
265 case DIRECT_OUT_OF_MEMORY:
266 return NLOPT_OUT_OF_MEMORY;
271 case NLOPT_GD_STOGO_RAND:
273 if (!stogo_minimize(n, f, f_data, x, minf, lb, ub, &stop,
274 algorithm == NLOPT_GD_STOGO
276 return NLOPT_FAILURE;
279 return NLOPT_FAILURE;
282 case NLOPT_LN_SUBPLEX: {
284 double *scale = (double *) malloc(sizeof(double) * n);
285 if (!scale) return NLOPT_OUT_OF_MEMORY;
286 for (i = 0; i < n; ++i) {
287 if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
288 scale[i] = (ub[i] - lb[i]) * 0.01;
289 else if (!my_isinf(lb[i]) && x[i] > lb[i])
290 scale[i] = (x[i] - lb[i]) * 0.01;
291 else if (!my_isinf(ub[i]) && x[i] < ub[i])
292 scale[i] = (ub[i] - x[i]) * 0.01;
294 scale[i] = 0.01 * x[i] + 0.0001;
296 iret = nlopt_subplex(f_subplex, minf, x, n, &d, &stop, scale);
299 case -2: return NLOPT_INVALID_ARGS;
300 case -10: return NLOPT_MAXTIME_REACHED;
301 case -1: return NLOPT_MAXEVAL_REACHED;
302 case 0: return NLOPT_XTOL_REACHED;
303 case 1: return NLOPT_SUCCESS;
304 case 2: return NLOPT_MINF_MAX_REACHED;
305 case 20: return NLOPT_FTOL_REACHED;
306 case -200: return NLOPT_OUT_OF_MEMORY;
307 default: return NLOPT_FAILURE; /* unknown return code */
312 case NLOPT_LN_PRAXIS: {
313 double h0 = HUGE_VAL;
314 for (i = 0; i < n; ++i) {
315 if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
316 h0 = MIN(h0, (ub[i] - lb[i]) * 0.01);
317 else if (!my_isinf(lb[i]) && x[i] > lb[i])
318 h0 = MIN(h0, (x[i] - lb[i]) * 0.01);
319 else if (!my_isinf(ub[i]) && x[i] < ub[i])
320 h0 = MIN(h0, (ub[i] - x[i]) * 0.01);
322 h0 = MIN(h0, 0.01 * x[i] + 0.0001);
324 return praxis_(0.0, DBL_EPSILON, h0, n, x, f_subplex, &d,
329 return luksan_plis(n, f, f_data, lb, ub, x, minf, &stop);
333 return luksan_plip(n, f, f_data, lb, ub, x, minf, &stop,
334 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
336 case NLOPT_LD_TNEWTON:
337 case NLOPT_LD_TNEWTON_RESTART:
338 case NLOPT_LD_TNEWTON_PRECOND:
339 case NLOPT_LD_TNEWTON_PRECOND_RESTART:
340 return luksan_pnet(n, f, f_data, lb, ub, x, minf, &stop,
341 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
342 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);
344 case NLOPT_GN_CRS2_LM:
345 return crs_minimize(n, f, f_data, lb, ub, x, minf, &stop, 0);
349 case NLOPT_GN_MLSL_LDS:
350 case NLOPT_GD_MLSL_LDS:
351 return mlsl_minimize(n, f, f_data, lb, ub, x, minf, &stop,
352 (algorithm == NLOPT_GN_MLSL ||
353 algorithm == NLOPT_GN_MLSL_LDS)
354 ? local_search_alg_nonderiv
355 : local_search_alg_deriv,
356 local_search_maxeval,
357 algorithm >= NLOPT_GN_MLSL_LDS);
360 return NLOPT_INVALID_ARGS;
363 return NLOPT_SUCCESS;
366 nlopt_result nlopt_minimize(
367 nlopt_algorithm algorithm,
368 int n, nlopt_func f, void *f_data,
369 const double *lb, const double *ub, /* bounds */
370 double *x, /* in: initial guess, out: minimizer */
371 double *minf, /* out: minimum */
372 double minf_max, double ftol_rel, double ftol_abs,
373 double xtol_rel, const double *xtol_abs,
374 int maxeval, double maxtime)
378 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
379 x, minf, minf_max, ftol_rel, ftol_abs,
380 xtol_rel, xtol_abs, maxeval, maxtime);
383 double *xtol = (double *) malloc(sizeof(double) * n);
384 if (!xtol) return NLOPT_OUT_OF_MEMORY;
385 for (i = 0; i < n; ++i) xtol[i] = -1;
386 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
387 x, minf, minf_max, ftol_rel, ftol_abs,
388 xtol_rel, xtol, maxeval, maxtime);