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.
23 // C++ style wrapper around NLopt API
24 // nlopt.hpp is AUTOMATICALLY GENERATED from nlopt-in.hpp - edit the latter!
38 // convenience overloading for below (not in nlopt:: since has nlopt_ prefix)
39 inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) {
40 return nlopt_get_initial_step(opt, (const double *) NULL, dx);
45 //////////////////////////////////////////////////////////////////////
46 // nlopt::* namespace versions of the C enumerated types
47 // AUTOMATICALLY GENERATED, DO NOT EDIT
49 //////////////////////////////////////////////////////////////////////
51 typedef nlopt_func func; // nlopt::func synoynm
52 typedef nlopt_mfunc mfunc; // nlopt::mfunc synoynm
54 // alternative to nlopt_func that takes std::vector<double>
55 // ... unfortunately requires a data copy
56 typedef double (*vfunc)(const std::vector<double> &x,
57 std::vector<double> &grad, void *data);
59 //////////////////////////////////////////////////////////////////////
61 // NLopt-specific exceptions (corresponding to error codes):
62 class roundoff_limited : public std::runtime_error {
64 roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
67 class forced_stop : public std::runtime_error {
69 forced_stop() : std::runtime_error("nlopt forced stop") {}
72 //////////////////////////////////////////////////////////////////////
78 void mythrow(nlopt_result ret) const {
80 case NLOPT_FAILURE: throw std::runtime_error(get_errmsg() ? get_errmsg() : "nlopt failure");
81 case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
82 case NLOPT_INVALID_ARGS: throw std::invalid_argument(get_errmsg() ? get_errmsg() : "nlopt invalid argument");
83 case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
84 case NLOPT_FORCED_STOP: throw forced_stop();
91 mfunc mf; func f; void *f_data;
93 nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
96 // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
97 static void *free_myfunc_data(void *p) {
98 myfunc_data *d = (myfunc_data *) p;
100 if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
105 static void *dup_myfunc_data(void *p) {
106 myfunc_data *d = (myfunc_data *) p;
109 if (d->f_data && d->munge_copy) {
110 f_data = d->munge_copy(d->f_data);
111 if (!f_data) return NULL;
115 myfunc_data *dnew = new myfunc_data;
118 dnew->f_data = f_data;
125 // nlopt_func wrapper that catches exceptions
126 static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
127 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
129 return d->f(n, x, grad, d->f_data);
131 catch (std::bad_alloc&)
132 { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
133 catch (std::invalid_argument&)
134 { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
135 catch (roundoff_limited&)
136 { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
138 { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
140 { d->o->forced_stop_reason = NLOPT_FAILURE; }
141 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
145 // nlopt_mfunc wrapper that catches exceptions
146 static void mymfunc(unsigned m, double *result,
147 unsigned n, const double *x, double *grad, void *d_) {
148 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
150 d->mf(m, result, n, x, grad, d->f_data);
153 catch (std::bad_alloc&)
154 { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
155 catch (std::invalid_argument&)
156 { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
157 catch (roundoff_limited&)
158 { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
160 { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
162 { d->o->forced_stop_reason = NLOPT_FAILURE; }
163 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
164 for (unsigned i = 0; i < m; ++i) result[i] = HUGE_VAL;
167 std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
169 // nlopt_func wrapper, using std::vector<double>
170 static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
171 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
173 std::vector<double> &xv = d->o->xtmp;
174 if (n) std::memcpy(&xv[0], x, n * sizeof(double));
175 double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
177 std::vector<double> &gradv = d->o->gradtmp;
178 std::memcpy(grad, &gradv[0], n * sizeof(double));
182 catch (std::bad_alloc&)
183 { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
184 catch (std::invalid_argument&)
185 { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
186 catch (roundoff_limited&)
187 { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
189 { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
191 { d->o->forced_stop_reason = NLOPT_FAILURE; }
192 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
197 if (xtmp.size() != nlopt_get_dimension(o)) {
198 xtmp = std::vector<double>(nlopt_get_dimension(o));
199 gradtmp = std::vector<double>(nlopt_get_dimension(o));
205 nlopt_result forced_stop_reason;
209 opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
210 last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
211 forced_stop_reason(NLOPT_FORCED_STOP) {}
212 ~opt() { nlopt_destroy(o); }
213 opt(algorithm a, unsigned n) :
214 o(nlopt_create(nlopt_algorithm(a), n)),
215 xtmp(0), gradtmp(0), gradtmp0(0),
216 last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
217 forced_stop_reason(NLOPT_FORCED_STOP) {
218 if (!o) throw std::bad_alloc();
219 nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
221 opt(const opt& f) : o(nlopt_copy(f.o)),
222 xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
223 last_result(f.last_result), last_optf(f.last_optf),
224 forced_stop_reason(f.forced_stop_reason) {
225 if (f.o && !o) throw std::bad_alloc();
227 opt& operator=(opt const& f) {
228 if (this == &f) return *this; // self-assignment
231 if (f.o && !o) throw std::bad_alloc();
232 xtmp = f.xtmp; gradtmp = f.gradtmp;
233 last_result = f.last_result; last_optf = f.last_optf;
234 forced_stop_reason = f.forced_stop_reason;
238 // Do the optimization:
239 result optimize(std::vector<double> &x, double &opt_f) {
240 if (o && nlopt_get_dimension(o) != x.size())
241 throw std::invalid_argument("dimension mismatch");
242 forced_stop_reason = NLOPT_FORCED_STOP;
243 nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
244 last_result = result(ret);
246 if (ret == NLOPT_FORCED_STOP)
247 mythrow(forced_stop_reason);
252 // variant mainly useful for SWIG wrappers:
253 std::vector<double> optimize(const std::vector<double> &x0) {
254 std::vector<double> x(x0);
255 last_result = optimize(x, last_optf);
258 result last_optimize_result() const { return last_result; }
259 double last_optimum_value() const { return last_optf; }
262 algorithm get_algorithm() const {
263 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
264 return algorithm(nlopt_get_algorithm(o));
266 const char *get_algorithm_name() const {
267 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
268 return nlopt_algorithm_name(nlopt_get_algorithm(o));
270 unsigned get_dimension() const {
271 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
272 return nlopt_get_dimension(o);
275 // Set the objective function
276 void set_min_objective(func f, void *f_data) {
277 myfunc_data *d = new myfunc_data;
278 if (!d) throw std::bad_alloc();
279 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
280 d->munge_destroy = d->munge_copy = NULL;
281 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
283 void set_min_objective(vfunc vf, void *f_data) {
284 myfunc_data *d = new myfunc_data;
285 if (!d) throw std::bad_alloc();
286 d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
287 d->munge_destroy = d->munge_copy = NULL;
288 mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
291 void set_max_objective(func f, void *f_data) {
292 myfunc_data *d = new myfunc_data;
293 if (!d) throw std::bad_alloc();
294 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
295 d->munge_destroy = d->munge_copy = NULL;
296 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
298 void set_max_objective(vfunc vf, void *f_data) {
299 myfunc_data *d = new myfunc_data;
300 if (!d) throw std::bad_alloc();
301 d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
302 d->munge_destroy = d->munge_copy = NULL;
303 mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
307 // for internal use in SWIG wrappers -- variant that
308 // takes ownership of f_data, with munging for destroy/copy
309 void set_min_objective(func f, void *f_data,
310 nlopt_munge md, nlopt_munge mc) {
311 myfunc_data *d = new myfunc_data;
312 if (!d) throw std::bad_alloc();
313 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
314 d->munge_destroy = md; d->munge_copy = mc;
315 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
317 void set_max_objective(func f, void *f_data,
318 nlopt_munge md, nlopt_munge mc) {
319 myfunc_data *d = new myfunc_data;
320 if (!d) throw std::bad_alloc();
321 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
322 d->munge_destroy = md; d->munge_copy = mc;
323 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
326 // Nonlinear constraints:
328 void remove_inequality_constraints() {
329 nlopt_result ret = nlopt_remove_inequality_constraints(o);
332 void add_inequality_constraint(func f, void *f_data, double tol=0) {
333 myfunc_data *d = new myfunc_data;
334 if (!d) throw std::bad_alloc();
335 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
336 d->munge_destroy = d->munge_copy = NULL;
337 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
339 void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
340 myfunc_data *d = new myfunc_data;
341 if (!d) throw std::bad_alloc();
342 d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
343 d->munge_destroy = d->munge_copy = NULL;
344 mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
347 void add_inequality_mconstraint(mfunc mf, void *f_data,
348 const std::vector<double> &tol) {
349 myfunc_data *d = new myfunc_data;
350 if (!d) throw std::bad_alloc();
351 d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
352 d->munge_destroy = d->munge_copy = NULL;
353 mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
354 tol.empty() ? NULL : &tol[0]));
357 void remove_equality_constraints() {
358 nlopt_result ret = nlopt_remove_equality_constraints(o);
361 void add_equality_constraint(func f, void *f_data, double tol=0) {
362 myfunc_data *d = new myfunc_data;
363 if (!d) throw std::bad_alloc();
364 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
365 d->munge_destroy = d->munge_copy = NULL;
366 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
368 void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
369 myfunc_data *d = new myfunc_data;
370 if (!d) throw std::bad_alloc();
371 d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
372 d->munge_destroy = d->munge_copy = NULL;
373 mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
376 void add_equality_mconstraint(mfunc mf, void *f_data,
377 const std::vector<double> &tol) {
378 myfunc_data *d = new myfunc_data;
379 if (!d) throw std::bad_alloc();
380 d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
381 d->munge_destroy = d->munge_copy = NULL;
382 mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
383 tol.empty() ? NULL : &tol[0]));
386 // For internal use in SWIG wrappers (see also above)
387 void add_inequality_constraint(func f, void *f_data,
388 nlopt_munge md, nlopt_munge mc,
390 myfunc_data *d = new myfunc_data;
391 if (!d) throw std::bad_alloc();
392 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
393 d->munge_destroy = md; d->munge_copy = mc;
394 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
396 void add_equality_constraint(func f, void *f_data,
397 nlopt_munge md, nlopt_munge mc,
399 myfunc_data *d = new myfunc_data;
400 if (!d) throw std::bad_alloc();
401 d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
402 d->munge_destroy = md; d->munge_copy = mc;
403 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
405 void add_inequality_mconstraint(mfunc mf, void *f_data,
406 nlopt_munge md, nlopt_munge mc,
407 const std::vector<double> &tol) {
408 myfunc_data *d = new myfunc_data;
409 if (!d) throw std::bad_alloc();
410 d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
411 d->munge_destroy = md; d->munge_copy = mc;
412 mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
413 tol.empty() ? NULL : &tol[0]));
415 void add_equality_mconstraint(mfunc mf, void *f_data,
416 nlopt_munge md, nlopt_munge mc,
417 const std::vector<double> &tol) {
418 myfunc_data *d = new myfunc_data;
419 if (!d) throw std::bad_alloc();
420 d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
421 d->munge_destroy = md; d->munge_copy = mc;
422 mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
423 tol.empty() ? NULL : &tol[0]));
426 #define NLOPT_GETSET_VEC(name) \
427 void set_##name(double val) { \
428 mythrow(nlopt_set_##name##1(o, val)); \
430 void get_##name(std::vector<double> &v) const { \
431 if (o && nlopt_get_dimension(o) != v.size()) \
432 throw std::invalid_argument("dimension mismatch"); \
433 mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0])); \
435 std::vector<double> get_##name() const { \
436 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
437 std::vector<double> v(nlopt_get_dimension(o)); \
441 void set_##name(const std::vector<double> &v) { \
442 if (o && nlopt_get_dimension(o) != v.size()) \
443 throw std::invalid_argument("dimension mismatch"); \
444 mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0])); \
447 NLOPT_GETSET_VEC(lower_bounds)
448 NLOPT_GETSET_VEC(upper_bounds)
450 // stopping criteria:
452 #define NLOPT_GETSET(T, name) \
453 T get_##name() const { \
454 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
455 return nlopt_get_##name(o); \
457 void set_##name(T name) { \
458 mythrow(nlopt_set_##name(o, name)); \
460 NLOPT_GETSET(double, stopval)
461 NLOPT_GETSET(double, ftol_rel)
462 NLOPT_GETSET(double, ftol_abs)
463 NLOPT_GETSET(double, xtol_rel)
464 NLOPT_GETSET_VEC(xtol_abs)
465 NLOPT_GETSET(int, maxeval)
466 NLOPT_GETSET(double, maxtime)
468 NLOPT_GETSET(int, force_stop)
469 void force_stop() { set_force_stop(1); }
471 const char *get_errmsg() const {
472 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
473 return nlopt_get_errmsg(o);
476 // algorithm-specific parameters:
478 void set_local_optimizer(const opt &lo) {
479 nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
483 NLOPT_GETSET(unsigned, population)
484 NLOPT_GETSET(unsigned, vector_storage)
485 NLOPT_GETSET_VEC(initial_step)
487 void set_default_initial_step(const std::vector<double> &x) {
489 = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
492 void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
493 if (o && (nlopt_get_dimension(o) != x.size()
494 || nlopt_get_dimension(o) != dx.size()))
495 throw std::invalid_argument("dimension mismatch");
496 nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
497 dx.empty() ? NULL : &dx[0]);
500 std::vector<double> get_initial_step_(const std::vector<double> &x) const {
501 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
502 std::vector<double> v(nlopt_get_dimension(o));
503 get_initial_step(x, v);
509 #undef NLOPT_GETSET_VEC
511 //////////////////////////////////////////////////////////////////////
513 inline void srand(unsigned long seed) { nlopt_srand(seed); }
514 inline void srand_time() { nlopt_srand_time(); }
515 inline void version(int &major, int &minor, int &bugfix) {
516 nlopt_version(&major, &minor, &bugfix);
518 inline int version_major() {
519 int major, minor, bugfix;
520 nlopt_version(&major, &minor, &bugfix);
523 inline int version_minor() {
524 int major, minor, bugfix;
525 nlopt_version(&major, &minor, &bugfix);
528 inline int version_bugfix() {
529 int major, minor, bugfix;
530 nlopt_version(&major, &minor, &bugfix);
533 inline const char *algorithm_name(algorithm a) {
534 return nlopt_algorithm_name(nlopt_algorithm(a));
537 //////////////////////////////////////////////////////////////////////
541 #endif /* NLOPT_HPP */