1 /* Copyright (c) 2007-2011 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.
28 #include "nlopt_config.h"
36 int opterr = 1, /* if error message should be printed */
37 optind = 1, /* index into parent argv vector */
38 optopt, /* character checked for validity */
39 optreset; /* reset getopt */
40 char *optarg; /* argument associated with option */
42 #define BADCH (int)'?'
43 #define BADARG (int)':'
48 * Parse argc/argv argument vector.
51 getopt(int nargc, char * const nargv[], const char *ostr)
53 static char *place = EMSG; /* option letter processing */
54 const char *oli; /* option letter list index */
56 if (optreset || !*place) { /* update scanning pointer */
58 if (optind >= nargc || *(place = nargv[optind]) != '-') {
62 if (place[1] && *++place == '-') { /* found "--" */
67 } /* option letter okay? */
68 if ((optopt = (int)*place++) == (int)':' ||
69 !(oli = strchr(ostr, optopt))) {
71 * if the user didn't specify '-' as an option,
74 if (optopt == (int)'-')
78 if (opterr && *ostr != ':')
79 (void)printf("illegal option -- %c\n", optopt);
82 if (*++oli != ':') { /* don't need argument */
87 else { /* need an argument */
88 if (*place) /* no white space */
90 else if (nargc <= ++optind) { /* no arg */
95 (void)printf("option requires an argument -- %c\n", optopt);
98 else /* white space */
99 optarg = nargv[optind];
103 return (optopt); /* dump back option letter */
107 #define USE_FEENABLEEXCEPT 0
108 #if USE_FEENABLEEXCEPT
110 extern "C" int feenableexcept (int EXCEPTS);
115 #include "nlopt-util.h"
116 #include "testfuncs.h"
118 static nlopt_algorithm algorithm = NLOPT_GN_DIRECT_L;
119 static double ftol_rel = 0, ftol_abs = 0, xtol_rel = 0, xtol_abs = 0, minf_max_delta = -HUGE_VAL;
120 static int maxeval = 1000, iterations = 1, center_start = 0;
121 static double maxtime = 0.0;
122 static double xinit_tol = -1;
123 static int force_constraints = 0;
124 static int fix_bounds[100] = {0,0,0,0,0,0,0,0,0,0,
125 0,0,0,0,0,0,0,0,0,0,
126 0,0,0,0,0,0,0,0,0,0,
127 0,0,0,0,0,0,0,0,0,0,
128 0,0,0,0,0,0,0,0,0,0,
129 0,0,0,0,0,0,0,0,0,0,
130 0,0,0,0,0,0,0,0,0,0,
131 0,0,0,0,0,0,0,0,0,0,
132 0,0,0,0,0,0,0,0,0,0,
133 0,0,0,0,0,0,0,0,0,0};
135 static void listalgs(FILE *f)
138 fprintf(f, "Available algorithms:\n");
139 for (i = 0; i < NLOPT_NUM_ALGORITHMS; ++i)
140 fprintf(f, " %2d: %s\n", i, nlopt_algorithm_name((nlopt_algorithm) i));
143 static void listfuncs(FILE *f)
146 fprintf(f, "Available objective functions:\n");
147 for (i = 0; i < NTESTFUNCS; ++i)
148 fprintf(f, " %2d: %s (%d dims)\n", i, testfuncs[i].name, testfuncs[i].n);
152 const double *lb, *ub;
157 static double bounds_wrap_func(int n, const double *x, double *grad, void *d_)
159 bounds_wrap_data *d = (bounds_wrap_data *) d_;
162 for (i = 0; i < n; ++i) {
163 if (x[i] < d->lb[i]) {
167 else if (x[i] > d->ub[i]) {
173 fprintf(stderr, "WARNING: bounds violated by x[%d] = %g = %g + %g\n",
174 i, x[i], b, x[i] - b);
175 return d->f(n, x, grad, d->f_data);
178 static int test_function(int ifunc)
182 double *x, minf, minf_max, f0, *xtabs, *lb, *ub;
184 double start = nlopt_seconds();
185 int total_count = 0, max_count = 0, min_count = 1<<30;
186 double total_err = 0, max_err = 0;
189 if (ifunc < 0 || ifunc >= NTESTFUNCS) {
190 fprintf(stderr, "testopt: invalid function %d\n", ifunc);
194 func = testfuncs[ifunc];
195 x = (double *) malloc(sizeof(double) * func.n * 5);
196 if (!x) { fprintf(stderr, "testopt: Out of memory!\n"); return 0; }
200 xtabs = x + func.n * 2;
204 bw.f_data = func.f_data;
206 for (i = 0; i < func.n; ++i) xtabs[i] = xtol_abs;
207 minf_max = minf_max_delta > (-HUGE_VAL) ? minf_max_delta + func.minf : (-HUGE_VAL);
209 printf("-----------------------------------------------------------\n");
210 printf("Optimizing %s (%d dims) using %s algorithm\n",
211 func.name, func.n, nlopt_algorithm_name(algorithm));
212 printf("lower bounds at lb = [");
213 for (i = 0; i < func.n; ++i) printf(" %g", func.lb[i]);
215 printf("upper bounds at ub = [");
216 for (i = 0; i < func.n; ++i) printf(" %g", func.ub[i]);
218 memcpy(lb, func.lb, func.n * sizeof(double));
219 memcpy(ub, func.ub, func.n * sizeof(double));
220 for (i = 0; i < func.n; ++i) if (fix_bounds[i]) {
221 printf("fixing bounds for dim[%d] to xmin[%d]=%g\n",
223 lb[i] = ub[i] = func.xmin[i];
225 if (force_constraints) {
226 for (i = 0; i < func.n; ++i) {
227 if (nlopt_iurand(2) == 0)
228 ub[i] = nlopt_urand(lb[i], func.xmin[i]);
230 lb[i] = nlopt_urand(func.xmin[i], ub[i]);
232 printf("adjusted lower bounds at lb = [");
233 for (i = 0; i < func.n; ++i) printf(" %g", lb[i]);
235 printf("adjusted upper bounds at ub = [");
236 for (i = 0; i < func.n; ++i) printf(" %g", ub[i]);
240 if (fabs(func.f(func.n, func.xmin, 0, func.f_data) - func.minf) > 1e-8) {
241 fprintf(stderr, "BUG: function does not achieve given lower bound!\n");
242 fprintf(stderr, "f(%g", func.xmin[0]);
243 for (i = 1; i < func.n; ++i) fprintf(stderr, ", %g", func.xmin[i]);
244 fprintf(stderr, ") = %0.16g instead of %0.16g, |diff| = %g\n",
245 func.f(func.n, func.xmin, 0, func.f_data), func.minf,
246 fabs(func.f(func.n, func.xmin, 0, func.f_data) - func.minf));
250 for (iter = 0; iter < iterations; ++iter) {
252 testfuncs_counter = 0;
254 printf("Starting guess x = [");
255 for (i = 0; i < func.n; ++i) {
257 x[i] = (ub[i] + lb[i]) * 0.5;
258 else if (xinit_tol < 0) { /* random starting point near center of box */
259 double dx = (ub[i] - lb[i]) * 0.25;
260 double xm = 0.5 * (ub[i] + lb[i]);
261 x[i] = nlopt_urand(xm - dx, xm + dx);
264 x[i] = nlopt_urand(-xinit_tol, xinit_tol)
265 + (1 + nlopt_urand(-xinit_tol, xinit_tol)) * func.xmin[i];
266 if (x[i] > ub[i]) x[i] = ub[i];
267 else if (x[i] < lb[i]) x[i] = lb[i];
272 f0 = func.f(func.n, x, x + func.n, func.f_data);
273 printf("Starting function value = %g\n", f0);
275 if (iter == 0 && testfuncs_verbose && func.has_gradient) {
276 printf("checking gradient:\n");
277 for (i = 0; i < func.n; ++i) {
280 f = func.f(func.n, x, NULL, func.f_data);
282 printf(" grad[%d] = %g vs. numerical derivative %g\n",
283 i, x[i + func.n], (f - f0) / (x[i] * 1e-6));
287 testfuncs_counter = 0;
288 ret = nlopt_minimize(algorithm,
289 func.n, bounds_wrap_func, &bw,
292 minf_max, ftol_rel, ftol_abs, xtol_rel, xtabs,
294 printf("finished after %g seconds.\n", nlopt_seconds() - start);
295 printf("return code %d from nlopt_minimize\n", ret);
296 if (ret < 0 && ret != NLOPT_ROUNDOFF_LIMITED
297 && ret != NLOPT_FORCED_STOP) {
298 fprintf(stderr, "testopt: error in nlopt_minimize\n");
302 printf("Found minimum f = %g after %d evaluations.\n",
303 minf, testfuncs_counter);
304 total_count += testfuncs_counter;
305 if (testfuncs_counter > max_count) max_count = testfuncs_counter;
306 if (testfuncs_counter < min_count) min_count = testfuncs_counter;
307 printf("Minimum at x = [");
308 for (i = 0; i < func.n; ++i) printf(" %g", x[i]);
311 printf("|f - minf| = %g\n", fabs(minf - func.minf));
313 printf("|f - minf| = %g, |f - minf| / |minf| = %e\n",
314 fabs(minf - func.minf), fabs(minf - func.minf) / fabs(func.minf));
315 total_err += fabs(minf - func.minf);
316 if (fabs(minf - func.minf) > max_err)
317 max_err = fabs(minf - func.minf);
318 printf("vs. global minimum f = %g at x = [", func.minf);
319 for (i = 0; i < func.n; ++i) printf(" %g", func.xmin[i]);
322 val = func.f(func.n, x, NULL, func.f_data);
324 fprintf(stderr, "Mismatch %g between returned minf=%g and f(x) = %g\n",
325 minf - val, minf, val);
331 printf("average #evaluations = %g (%d-%d)\naverage |f-minf| = %g, max |f-minf| = %g\n", total_count * 1.0 / iterations, min_count, max_count, total_err / iterations, max_err);
337 static void usage(FILE *f)
339 fprintf(f, "Usage: testopt [OPTIONS]\n"
341 " -h : print this help\n"
342 " -L : list available algorithms and objective functions\n"
343 " -v : verbose mode\n"
344 " -a <n> : use optimization algorithm <n>\n"
345 " -o <n> : use objective function <n>\n"
346 " -0 <x> : starting guess within <x> + (1+<x>) * optimum\n"
347 " -b <dim0,dim1,...>: eliminate given dims by equating bounds\n"
348 " -c : starting guess at center of cell\n"
349 " -C : put optimum outside of bound constraints\n"
350 " -e <n> : use at most <n> evals (default: %d, 0 to disable)\n"
351 " -t <t> : use at most <t> seconds (default: disabled)\n"
352 " -x <t> : relative tolerance <t> on x (default: disabled)\n"
353 " -X <t> : absolute tolerance <t> on x (default: disabled)\n"
354 " -f <t> : relative tolerance <t> on f (default: disabled)\n"
355 " -F <t> : absolute tolerance <t> on f (default: disabled)\n"
356 " -m <m> : stop when minf+<m> is reached (default: disabled)\n"
357 " -i <n> : iterate optimization <n> times (default: 1)\n"
358 " -r <s> : use random seed <s> for starting guesses\n"
362 int main(int argc, char **argv)
367 testfuncs_verbose = 0;
372 #if USE_FEENABLEEXCEPT
373 feenableexcept(FE_INVALID);
376 while ((c = getopt(argc, argv, "hLvCc0:r:a:o:i:e:t:x:X:f:F:m:b:")) != -1)
386 testfuncs_verbose = 1;
389 force_constraints = 1;
392 nlopt_srand((unsigned long) atoi(optarg));
396 if (c < 0 || c >= NLOPT_NUM_ALGORITHMS) {
397 fprintf(stderr, "testopt: invalid algorithm %d\n", c);
401 algorithm = (nlopt_algorithm) c;
404 if (!test_function(atoi(optarg)))
408 maxeval = atoi(optarg);
411 iterations = atoi(optarg);
414 maxtime = atof(optarg);
417 xtol_rel = atof(optarg);
420 xtol_abs = atof(optarg);
423 ftol_rel = atof(optarg);
426 ftol_abs = atof(optarg);
429 minf_max_delta = atof(optarg);
436 xinit_tol = atof(optarg);
439 const char *s = optarg;
442 if (b < 0 || b >= 100) {
443 fprintf(stderr, "invalid -b argument");
447 s = strchr(s, ','); if (s) ++s;
452 fprintf(stderr, "harminv: invalid argument -%c\n", c);