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)",
54 "StoGO (global, derivative-based)",
55 "StoGO with randomized search (global, derivative-based)",
56 "Low-storage BFGS (LBFGS) (local, derivative-based)",
57 "Principal-axis, praxis (local, no-derivative)",
58 "Limited-memory variable-metric, rank 1 (local, derivative-based)",
59 "Limited-memory variable-metric, rank 2 (local, derivative-based)",
60 "Truncated Newton (local, derivative-based)",
61 "Truncated Newton with restarting (local, derivative-based)",
62 "Preconditioned truncated Newton (local, derivative-based)",
63 "Preconditioned truncated Newton with restarting (local, derivative-based)",
64 "Controlled random search (CRS2) with local mutation (global, no-derivative)",
65 "Controlled quasi-random search (CRS2) with local mutation (global, no-derivative), using Sobol' LDS",
69 const char *nlopt_algorithm_name(nlopt_algorithm a)
71 if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
72 return nlopt_algorithm_names[a];
75 /*************************************************************************/
77 static int nlopt_srand_called = 0;
78 void nlopt_srand(unsigned long seed) {
79 nlopt_srand_called = 1;
80 nlopt_init_genrand(seed);
83 void nlopt_srand_time() {
84 nlopt_srand(nlopt_time_seed());
87 /*************************************************************************/
92 const double *lb, *ub;
98 static double f_subplex(int n, const double *x, void *data_)
101 nlopt_data *data = (nlopt_data *) data_;
104 /* subplex does not support bound constraints, but it supports
105 discontinuous objectives so we can just return Inf for invalid x */
106 for (i = 0; i < n; ++i)
107 if (x[i] < data->lb[i] || x[i] > data->ub[i])
110 f = data->f(n, x, NULL, data->f_data);
111 return (isnan(f) ? MY_INF : f);
116 static double f_direct(int n, const double *x, int *undefined, void *data_)
118 nlopt_data *data = (nlopt_data *) data_;
120 f = data->f(n, x, NULL, data->f_data);
121 *undefined = isnan(f) || my_isinf(f);
133 /*************************************************************************/
135 /* for "hybrid" algorithms that combine global search with some
136 local search algorithm, most of the time we anticipate that people
137 will stick with the default local search algorithm, so we
138 don't add this as a parameter to nlopt_minimize. Instead, the user
139 can call nlopt_{set/get}_hybrid_local_algorithm to get/set the defaults. */
141 /* default local-search algorithms */
142 static nlopt_algorithm local_search_alg_deriv = NLOPT_LD_LBFGS;
143 static nlopt_algorithm local_search_alg_nonderiv = NLOPT_LN_SUBPLEX;
145 static int local_search_maxeval = -1; /* no maximum by default */
147 void nlopt_get_local_search_algorithm(nlopt_algorithm *deriv,
148 nlopt_algorithm *nonderiv,
151 *deriv = local_search_alg_deriv;
152 *nonderiv = local_search_alg_nonderiv;
153 *maxeval = local_search_maxeval;
156 void nlopt_set_local_search_algorithm(nlopt_algorithm deriv,
157 nlopt_algorithm nonderiv,
160 local_search_alg_deriv = deriv;
161 local_search_alg_nonderiv = nonderiv;
162 local_search_maxeval = maxeval;
165 /*************************************************************************/
167 /* same as nlopt_minimize, but xtol_abs is required to be non-NULL */
168 static nlopt_result nlopt_minimize_(
169 nlopt_algorithm algorithm,
170 int n, nlopt_func f, void *f_data,
171 const double *lb, const double *ub, /* bounds */
172 double *x, /* in: initial guess, out: minimizer */
173 double *minf, /* out: minimum */
174 double minf_max, double ftol_rel, double ftol_abs,
175 double xtol_rel, const double *xtol_abs,
176 int maxeval, double maxtime)
182 /* some basic argument checks */
183 if (n <= 0 || !f || !lb || !ub || !x || !minf)
184 return NLOPT_INVALID_ARGS;
191 /* make sure rand generator is inited */
192 if (!nlopt_srand_called)
193 nlopt_srand_time(); /* default is non-deterministic */
195 /* check bound constraints */
196 for (i = 0; i < n; ++i)
197 if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
198 return NLOPT_INVALID_ARGS;
201 stop.minf_max = (isnan(minf_max) || (my_isinf(minf_max) && minf_max < 0))
202 ? -MY_INF : minf_max;
203 stop.ftol_rel = ftol_rel;
204 stop.ftol_abs = ftol_abs;
205 stop.xtol_rel = xtol_rel;
206 stop.xtol_abs = xtol_abs;
208 stop.maxeval = maxeval;
209 stop.maxtime = maxtime;
210 stop.start = nlopt_seconds();
213 case NLOPT_GN_DIRECT:
214 case NLOPT_GN_DIRECT_L:
215 case NLOPT_GN_DIRECT_L_RAND:
216 return cdirect(n, f, f_data, lb, ub, x, minf, &stop, 0.0,
217 (algorithm != NLOPT_GN_DIRECT)
218 + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
219 + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
221 case NLOPT_GN_DIRECT_NOSCAL:
222 case NLOPT_GN_DIRECT_L_NOSCAL:
223 case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
224 return cdirect_unscaled(n, f, f_data, lb, ub, x, minf,
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_ORIG_DIRECT:
231 case NLOPT_GN_ORIG_DIRECT_L:
232 switch (direct_optimize(f_direct, &d, n, lb, ub, x, minf,
233 maxeval, -1, 0.0, 0.0,
234 pow(xtol_rel, (double) n), -1.0,
237 algorithm == NLOPT_GN_ORIG_DIRECT
239 : DIRECT_GABLONSKY)) {
240 case DIRECT_INVALID_BOUNDS:
241 case DIRECT_MAXFEVAL_TOOBIG:
242 case DIRECT_INVALID_ARGS:
243 return NLOPT_INVALID_ARGS;
244 case DIRECT_INIT_FAILED:
245 case DIRECT_SAMPLEPOINTS_FAILED:
246 case DIRECT_SAMPLE_FAILED:
247 return NLOPT_FAILURE;
248 case DIRECT_MAXFEVAL_EXCEEDED:
249 case DIRECT_MAXITER_EXCEEDED:
250 return NLOPT_MAXEVAL_REACHED;
251 case DIRECT_GLOBAL_FOUND:
252 return NLOPT_MINF_MAX_REACHED;
254 case DIRECT_SIGMATOL:
255 return NLOPT_XTOL_REACHED;
256 case DIRECT_OUT_OF_MEMORY:
257 return NLOPT_OUT_OF_MEMORY;
262 case NLOPT_GD_STOGO_RAND:
263 if (!stogo_minimize(n, f, f_data, x, minf, lb, ub, &stop,
264 algorithm == NLOPT_GD_STOGO
266 return NLOPT_FAILURE;
269 case NLOPT_LN_SUBPLEX: {
271 double *scale = (double *) malloc(sizeof(double) * n);
272 if (!scale) return NLOPT_OUT_OF_MEMORY;
273 for (i = 0; i < n; ++i) {
274 if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
275 scale[i] = (ub[i] - lb[i]) * 0.01;
276 else if (!my_isinf(lb[i]) && x[i] > lb[i])
277 scale[i] = (x[i] - lb[i]) * 0.01;
278 else if (!my_isinf(ub[i]) && x[i] < ub[i])
279 scale[i] = (ub[i] - x[i]) * 0.01;
281 scale[i] = 0.01 * x[i] + 0.0001;
283 iret = subplex(f_subplex, minf, x, n, &d, &stop, scale);
286 case -2: return NLOPT_INVALID_ARGS;
287 case -10: return NLOPT_MAXTIME_REACHED;
288 case -1: return NLOPT_MAXEVAL_REACHED;
289 case 0: return NLOPT_XTOL_REACHED;
290 case 1: return NLOPT_SUCCESS;
291 case 2: return NLOPT_MINF_MAX_REACHED;
292 case 20: return NLOPT_FTOL_REACHED;
293 case -200: return NLOPT_OUT_OF_MEMORY;
294 default: return NLOPT_FAILURE; /* unknown return code */
299 case NLOPT_LN_PRAXIS: {
300 double h0 = HUGE_VAL;
301 for (i = 0; i < n; ++i) {
302 if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
303 h0 = MIN(h0, (ub[i] - lb[i]) * 0.01);
304 else if (!my_isinf(lb[i]) && x[i] > lb[i])
305 h0 = MIN(h0, (x[i] - lb[i]) * 0.01);
306 else if (!my_isinf(ub[i]) && x[i] < ub[i])
307 h0 = MIN(h0, (ub[i] - x[i]) * 0.01);
309 h0 = MIN(h0, 0.01 * x[i] + 0.0001);
311 return praxis_(0.0, DBL_EPSILON, h0, n, x, f_subplex, &d,
316 return luksan_plis(n, f, f_data, lb, ub, x, minf, &stop);
320 return luksan_plip(n, f, f_data, lb, ub, x, minf, &stop,
321 algorithm == NLOPT_LD_VAR1 ? 1 : 2);
323 case NLOPT_LD_TNEWTON:
324 case NLOPT_LD_TNEWTON_RESTART:
325 case NLOPT_LD_TNEWTON_PRECOND:
326 case NLOPT_LD_TNEWTON_PRECOND_RESTART:
327 return luksan_pnet(n, f, f_data, lb, ub, x, minf, &stop,
328 1 + (algorithm - NLOPT_LD_TNEWTON) % 2,
329 1 + (algorithm - NLOPT_LD_TNEWTON) / 2);
331 case NLOPT_GN_CRS2_LM:
332 return crs_minimize(n, f, f_data, lb, ub, x, minf, &stop, 0);
335 return NLOPT_INVALID_ARGS;
338 return NLOPT_SUCCESS;
341 nlopt_result nlopt_minimize(
342 nlopt_algorithm algorithm,
343 int n, nlopt_func f, void *f_data,
344 const double *lb, const double *ub, /* bounds */
345 double *x, /* in: initial guess, out: minimizer */
346 double *minf, /* out: minimum */
347 double minf_max, double ftol_rel, double ftol_abs,
348 double xtol_rel, const double *xtol_abs,
349 int maxeval, double maxtime)
353 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
354 x, minf, minf_max, ftol_rel, ftol_abs,
355 xtol_rel, xtol_abs, maxeval, maxtime);
358 double *xtol = (double *) malloc(sizeof(double) * n);
359 if (!xtol) return NLOPT_OUT_OF_MEMORY;
360 for (i = 0; i < n; ++i) xtol[i] = -1;
361 ret = nlopt_minimize_(algorithm, n, f, f_data, lb, ub,
362 x, minf, minf_max, ftol_rel, ftol_abs,
363 xtol_rel, xtol, maxeval, maxtime);