1 /* Copyright (c) 2007-2010 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
53 // alternative to nlopt_func that takes std::vector<double>
54 // ... unfortunately requires a data copy
55 typedef double (*vfunc)(const std::vector<double> &x,
56 std::vector<double> &grad, void *data);
58 //////////////////////////////////////////////////////////////////////
60 // NLopt-specific exceptions (corresponding to error codes):
61 class roundoff_limited : public std::runtime_error {
63 roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
66 class forced_stop : public std::runtime_error {
68 forced_stop() : std::runtime_error("nlopt forced stop") {}
71 //////////////////////////////////////////////////////////////////////
77 void mythrow(nlopt_result ret) const {
79 case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
80 case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
81 case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt invalid argument");
82 case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
83 case NLOPT_FORCED_STOP: throw forced_stop();
92 nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
95 // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
96 static void *free_myfunc_data(void *p) {
97 myfunc_data *d = (myfunc_data *) p;
99 if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
104 static void *dup_myfunc_data(void *p) {
105 myfunc_data *d = (myfunc_data *) p;
108 if (d->f_data && d->munge_copy) {
109 f_data = d->munge_copy(d->f_data);
110 if (!f_data) return NULL;
114 myfunc_data *dnew = new myfunc_data;
117 dnew->f_data = f_data;
124 // nlopt_func wrapper that catches exceptions
125 static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
126 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
128 return d->f(n, x, grad, d->f_data);
130 catch (std::bad_alloc&)
131 { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
132 catch (std::invalid_argument&)
133 { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
134 catch (roundoff_limited&)
135 { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
137 { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
139 { d->o->forced_stop_reason = NLOPT_FAILURE; }
140 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
144 std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
146 // nlopt_func wrapper, using std::vector<double>
147 static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
148 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
150 std::vector<double> &xv = d->o->xtmp;
151 if (n) std::memcpy(&xv[0], x, n * sizeof(double));
152 double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
154 std::vector<double> &gradv = d->o->gradtmp;
155 std::memcpy(grad, &gradv[0], n * sizeof(double));
159 catch (std::bad_alloc&)
160 { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
161 catch (std::invalid_argument&)
162 { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
163 catch (roundoff_limited&)
164 { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
166 { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
168 { d->o->forced_stop_reason = NLOPT_FAILURE; }
169 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
174 if (xtmp.size() != nlopt_get_dimension(o)) {
175 xtmp = std::vector<double>(nlopt_get_dimension(o));
176 gradtmp = std::vector<double>(nlopt_get_dimension(o));
182 nlopt_result forced_stop_reason;
186 opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
187 last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
188 forced_stop_reason(NLOPT_FORCED_STOP) {}
189 ~opt() { nlopt_destroy(o); }
190 opt(algorithm a, unsigned n) :
191 o(nlopt_create(nlopt_algorithm(a), n)),
192 xtmp(0), gradtmp(0), gradtmp0(0),
193 last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
194 forced_stop_reason(NLOPT_FORCED_STOP) {
195 if (!o) throw std::bad_alloc();
196 nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
198 opt(const opt& f) : o(nlopt_copy(f.o)),
199 xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
200 last_result(f.last_result), last_optf(f.last_optf),
201 forced_stop_reason(f.forced_stop_reason) {
202 if (f.o && !o) throw std::bad_alloc();
204 opt& operator=(opt const& f) {
205 if (this == &f) return *this; // self-assignment
208 if (f.o && !o) throw std::bad_alloc();
209 xtmp = f.xtmp; gradtmp = f.gradtmp;
210 last_result = f.last_result; last_optf = f.last_optf;
211 forced_stop_reason = f.forced_stop_reason;
215 // Do the optimization:
216 result optimize(std::vector<double> &x, double &opt_f) {
217 if (o && nlopt_get_dimension(o) != x.size())
218 throw std::invalid_argument("dimension mismatch");
219 forced_stop_reason = NLOPT_FORCED_STOP;
220 nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
221 last_result = result(ret);
223 if (ret == NLOPT_FORCED_STOP)
224 mythrow(forced_stop_reason);
229 // variant mainly useful for SWIG wrappers:
230 std::vector<double> optimize(const std::vector<double> &x0) {
231 std::vector<double> x(x0);
232 last_result = optimize(x, last_optf);
235 result last_optimize_result() const { return last_result; }
236 double last_optimum_value() const { return last_optf; }
239 algorithm get_algorithm() const {
240 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
241 return algorithm(nlopt_get_algorithm(o));
243 const char *get_algorithm_name() const {
244 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
245 return nlopt_algorithm_name(nlopt_get_algorithm(o));
247 unsigned get_dimension() const {
248 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
249 return nlopt_get_dimension(o);
252 // Set the objective function
253 void set_min_objective(func f, void *f_data) {
254 myfunc_data *d = new myfunc_data;
255 if (!d) throw std::bad_alloc();
256 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
257 d->munge_destroy = d->munge_copy = NULL;
258 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
260 void set_min_objective(vfunc vf, void *f_data) {
261 myfunc_data *d = new myfunc_data;
262 if (!d) throw std::bad_alloc();
263 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
264 d->munge_destroy = d->munge_copy = NULL;
265 mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
268 void set_max_objective(func f, void *f_data) {
269 myfunc_data *d = new myfunc_data;
270 if (!d) throw std::bad_alloc();
271 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
272 d->munge_destroy = d->munge_copy = NULL;
273 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
275 void set_max_objective(vfunc vf, void *f_data) {
276 myfunc_data *d = new myfunc_data;
277 if (!d) throw std::bad_alloc();
278 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
279 d->munge_destroy = d->munge_copy = NULL;
280 mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
284 // for internal use in SWIG wrappers -- variant that
285 // takes ownership of f_data, with munging for destroy/copy
286 void set_min_objective(func f, void *f_data,
287 nlopt_munge md, nlopt_munge mc) {
288 myfunc_data *d = new myfunc_data;
289 if (!d) throw std::bad_alloc();
290 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
291 d->munge_destroy = md; d->munge_copy = mc;
292 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
294 void set_max_objective(func f, void *f_data,
295 nlopt_munge md, nlopt_munge mc) {
296 myfunc_data *d = new myfunc_data;
297 if (!d) throw std::bad_alloc();
298 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
299 d->munge_destroy = md; d->munge_copy = mc;
300 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
303 // Nonlinear constraints:
305 void remove_inequality_constraints() {
306 nlopt_result ret = nlopt_remove_inequality_constraints(o);
309 void add_inequality_constraint(func f, void *f_data, double tol=0) {
310 myfunc_data *d = new myfunc_data;
311 if (!d) throw std::bad_alloc();
312 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
313 d->munge_destroy = d->munge_copy = NULL;
314 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
316 void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
317 myfunc_data *d = new myfunc_data;
318 if (!d) throw std::bad_alloc();
319 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
320 d->munge_destroy = d->munge_copy = NULL;
321 mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
325 void remove_equality_constraints() {
326 nlopt_result ret = nlopt_remove_equality_constraints(o);
329 void add_equality_constraint(func f, void *f_data, double tol=0) {
330 myfunc_data *d = new myfunc_data;
331 if (!d) throw std::bad_alloc();
332 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
333 d->munge_destroy = d->munge_copy = NULL;
334 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
336 void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
337 myfunc_data *d = new myfunc_data;
338 if (!d) throw std::bad_alloc();
339 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
340 d->munge_destroy = d->munge_copy = NULL;
341 mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
345 // For internal use in SWIG wrappers (see also above)
346 void add_inequality_constraint(func f, void *f_data,
347 nlopt_munge md, nlopt_munge mc,
349 myfunc_data *d = new myfunc_data;
350 if (!d) throw std::bad_alloc();
351 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
352 d->munge_destroy = md; d->munge_copy = mc;
353 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
355 void add_equality_constraint(func f, void *f_data,
356 nlopt_munge md, nlopt_munge mc,
358 myfunc_data *d = new myfunc_data;
359 if (!d) throw std::bad_alloc();
360 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
361 d->munge_destroy = md; d->munge_copy = mc;
362 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
365 #define NLOPT_GETSET_VEC(name) \
366 void set_##name(double val) { \
367 mythrow(nlopt_set_##name##1(o, val)); \
369 void get_##name(std::vector<double> &v) const { \
370 if (o && nlopt_get_dimension(o) != v.size()) \
371 throw std::invalid_argument("dimension mismatch"); \
372 mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0])); \
374 std::vector<double> get_##name() const { \
375 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
376 std::vector<double> v(nlopt_get_dimension(o)); \
380 void set_##name(const std::vector<double> &v) { \
381 if (o && nlopt_get_dimension(o) != v.size()) \
382 throw std::invalid_argument("dimension mismatch"); \
383 mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0])); \
386 NLOPT_GETSET_VEC(lower_bounds)
387 NLOPT_GETSET_VEC(upper_bounds)
389 // stopping criteria:
391 #define NLOPT_GETSET(T, name) \
392 T get_##name() const { \
393 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
394 return nlopt_get_##name(o); \
396 void set_##name(T name) { \
397 mythrow(nlopt_set_##name(o, name)); \
399 NLOPT_GETSET(double, stopval)
400 NLOPT_GETSET(double, ftol_rel)
401 NLOPT_GETSET(double, ftol_abs)
402 NLOPT_GETSET(double, xtol_rel)
403 NLOPT_GETSET_VEC(xtol_abs)
404 NLOPT_GETSET(int, maxeval)
405 NLOPT_GETSET(double, maxtime)
407 NLOPT_GETSET(int, force_stop)
408 void force_stop() { set_force_stop(1); }
410 // algorithm-specific parameters:
412 void set_local_optimizer(const opt &lo) {
413 nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
417 NLOPT_GETSET(unsigned, population)
418 NLOPT_GETSET_VEC(initial_step)
420 void set_default_initial_step(const std::vector<double> &x) {
422 = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
425 void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
426 if (o && (nlopt_get_dimension(o) != x.size()
427 || nlopt_get_dimension(o) != dx.size()))
428 throw std::invalid_argument("dimension mismatch");
429 nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
430 dx.empty() ? NULL : &dx[0]);
433 std::vector<double> get_initial_step_(const std::vector<double> &x) const {
434 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
435 std::vector<double> v(nlopt_get_dimension(o));
436 get_initial_step(x, v);
442 #undef NLOPT_GETSET_VEC
444 //////////////////////////////////////////////////////////////////////
446 void srand(unsigned long seed) { nlopt_srand(seed); }
447 void srand_time() { nlopt_srand_time(); }
448 void version(int &major, int &minor, int &bugfix) {
449 nlopt_version(&major, &minor, &bugfix);
451 int version_major() {
452 int major, minor, bugfix;
453 nlopt_version(&major, &minor, &bugfix);
456 int version_minor() {
457 int major, minor, bugfix;
458 nlopt_version(&major, &minor, &bugfix);
461 int version_bugfix() {
462 int major, minor, bugfix;
463 nlopt_version(&major, &minor, &bugfix);
466 const char *algorithm_name(algorithm a) {
467 return nlopt_algorithm_name(nlopt_algorithm(a));
470 //////////////////////////////////////////////////////////////////////
474 #endif /* NLOPT_HPP */