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!
35 // convenience overloading for below (not in nlopt:: since has nlopt_ prefix)
36 inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) {
37 return nlopt_get_initial_step(opt, (const double *) NULL, dx);
42 //////////////////////////////////////////////////////////////////////
43 // nlopt::* namespace versions of the C enumerated types
44 // AUTOMATICALLY GENERATED, DO NOT EDIT
46 //////////////////////////////////////////////////////////////////////
48 typedef nlopt_func func; // nlopt::func synoynm
50 // alternative to nlopt_func that takes std::vector<double>
51 // ... unfortunately requires a data copy
52 typedef double (*vfunc)(const std::vector<double> &x,
53 std::vector<double> &grad, void *data);
55 //////////////////////////////////////////////////////////////////////
57 // NLopt-specific exceptions (corresponding to error codes):
58 class roundoff_limited : public std::runtime_error {
60 roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
63 class forced_stop : public std::runtime_error {
65 forced_stop() : std::runtime_error("nlopt forced stop") {}
68 //////////////////////////////////////////////////////////////////////
74 void mythrow(nlopt_result ret) const {
76 case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
77 case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
78 case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt invalid argument");
79 case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
80 case NLOPT_FORCED_STOP: throw forced_stop();
89 nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
92 // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
93 static void *free_myfunc_data(void *p) {
94 myfunc_data *d = (myfunc_data *) p;
96 if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
101 static void *dup_myfunc_data(void *p) {
102 myfunc_data *d = (myfunc_data *) p;
105 if (d->f_data && d->munge_copy) {
106 f_data = d->munge_copy(d->f_data);
107 if (!f_data) return NULL;
111 myfunc_data *dnew = new myfunc_data;
114 dnew->f_data = f_data;
121 // nlopt_func wrapper that catches exceptions
122 static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
123 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
125 return d->f(n, x, grad, d->f_data);
128 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
133 std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
135 // nlopt_func wrapper, using std::vector<double>
136 static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
137 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
139 std::vector<double> &xv = d->o->xtmp;
140 if (n) std::memcpy(&xv[0], x, n * sizeof(double));
141 double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
143 std::vector<double> &gradv = d->o->gradtmp;
144 std::memcpy(grad, &gradv[0], n * sizeof(double));
149 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
155 if (xtmp.size() != nlopt_get_dimension(o)) {
156 xtmp = std::vector<double>(nlopt_get_dimension(o));
157 gradtmp = std::vector<double>(nlopt_get_dimension(o));
166 opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
167 last_result(nlopt::FAILURE), last_optf(HUGE_VAL) {}
168 ~opt() { nlopt_destroy(o); }
169 opt(algorithm a, unsigned n) :
170 o(nlopt_create(nlopt_algorithm(a), n)),
171 xtmp(0), gradtmp(0), gradtmp0(0),
172 last_result(nlopt::FAILURE), last_optf(HUGE_VAL) {
173 if (!o) throw std::bad_alloc();
174 nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
176 opt(const opt& f) : o(nlopt_copy(f.o)),
177 xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
178 last_result(f.last_result), last_optf(f.last_optf) {
179 if (f.o && !o) throw std::bad_alloc();
181 opt& operator=(opt const& f) {
182 if (this == &f) return *this; // self-assignment
185 if (f.o && !o) throw std::bad_alloc();
186 xtmp = f.xtmp; gradtmp = f.gradtmp;
187 last_result = f.last_result; last_optf = f.last_optf;
191 // Do the optimization:
192 result optimize(std::vector<double> &x, double &opt_f) {
193 if (o && nlopt_get_dimension(o) != x.size())
194 throw std::invalid_argument("dimension mismatch");
195 nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
196 last_result = result(ret);
202 // variant mainly useful for SWIG wrappers:
203 std::vector<double> optimize(const std::vector<double> &x0) {
204 std::vector<double> x(x0);
205 last_result = optimize(x, last_optf);
208 result last_optimize_result() const { return last_result; }
209 double last_optimum_value() const { return last_optf; }
212 algorithm get_algorithm() const {
213 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
214 return algorithm(nlopt_get_algorithm(o));
216 const char *get_algorithm_name() const {
217 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
218 return nlopt_algorithm_name(nlopt_get_algorithm(o));
220 unsigned get_dimension() const {
221 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
222 return nlopt_get_dimension(o);
225 // Set the objective function
226 void set_min_objective(func f, void *f_data) {
227 myfunc_data *d = new myfunc_data;
228 if (!d) throw std::bad_alloc();
229 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
230 d->munge_destroy = d->munge_copy = NULL;
231 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
233 void set_min_objective(vfunc vf, void *f_data) {
234 myfunc_data *d = new myfunc_data;
235 if (!d) throw std::bad_alloc();
236 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
237 d->munge_destroy = d->munge_copy = NULL;
238 mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
241 void set_max_objective(func f, void *f_data) {
242 myfunc_data *d = new myfunc_data;
243 if (!d) throw std::bad_alloc();
244 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
245 d->munge_destroy = d->munge_copy = NULL;
246 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
248 void set_max_objective(vfunc vf, void *f_data) {
249 myfunc_data *d = new myfunc_data;
250 if (!d) throw std::bad_alloc();
251 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
252 d->munge_destroy = d->munge_copy = NULL;
253 mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
257 // for internal use in SWIG wrappers -- variant that
258 // takes ownership of f_data, with munging for destroy/copy
259 void set_min_objective(func f, void *f_data,
260 nlopt_munge md, nlopt_munge mc) {
261 myfunc_data *d = new myfunc_data;
262 if (!d) throw std::bad_alloc();
263 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
264 d->munge_destroy = md; d->munge_copy = mc;
265 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
267 void set_max_objective(func f, void *f_data,
268 nlopt_munge md, nlopt_munge mc) {
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 = md; d->munge_copy = mc;
273 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
276 // Nonlinear constraints:
278 void remove_inequality_constraints() {
279 nlopt_result ret = nlopt_remove_inequality_constraints(o);
282 void add_inequality_constraint(func f, void *f_data, double tol=0) {
283 myfunc_data *d = new myfunc_data;
284 if (!d) throw std::bad_alloc();
285 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
286 d->munge_destroy = d->munge_copy = NULL;
287 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
289 void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
290 myfunc_data *d = new myfunc_data;
291 if (!d) throw std::bad_alloc();
292 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
293 d->munge_destroy = d->munge_copy = NULL;
294 mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
298 void remove_equality_constraints() {
299 nlopt_result ret = nlopt_remove_equality_constraints(o);
302 void add_equality_constraint(func f, void *f_data, double tol=0) {
303 myfunc_data *d = new myfunc_data;
304 if (!d) throw std::bad_alloc();
305 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
306 d->munge_destroy = d->munge_copy = NULL;
307 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
309 void add_equality_constraint(vfunc vf, 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 = NULL; d->f_data = f_data; d->vf = vf;
313 d->munge_destroy = d->munge_copy = NULL;
314 mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
318 // For internal use in SWIG wrappers (see also above)
319 void add_inequality_constraint(func f, void *f_data,
320 nlopt_munge md, nlopt_munge mc,
322 myfunc_data *d = new myfunc_data;
323 if (!d) throw std::bad_alloc();
324 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
325 d->munge_destroy = md; d->munge_copy = mc;
326 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
328 void add_equality_constraint(func f, void *f_data,
329 nlopt_munge md, nlopt_munge mc,
331 myfunc_data *d = new myfunc_data;
332 if (!d) throw std::bad_alloc();
333 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
334 d->munge_destroy = md; d->munge_copy = mc;
335 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
338 #define NLOPT_GETSET_VEC(name) \
339 void set_##name(double val) { \
340 mythrow(nlopt_set_##name##1(o, val)); \
342 void get_##name(std::vector<double> &v) const { \
343 if (o && nlopt_get_dimension(o) != v.size()) \
344 throw std::invalid_argument("dimension mismatch"); \
345 mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0])); \
347 std::vector<double> get_##name() const { \
348 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
349 std::vector<double> v(nlopt_get_dimension(o)); \
353 void set_##name(const std::vector<double> &v) { \
354 if (o && nlopt_get_dimension(o) != v.size()) \
355 throw std::invalid_argument("dimension mismatch"); \
356 mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0])); \
359 NLOPT_GETSET_VEC(lower_bounds)
360 NLOPT_GETSET_VEC(upper_bounds)
362 // stopping criteria:
364 #define NLOPT_GETSET(T, name) \
365 T get_##name() const { \
366 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
367 return nlopt_get_##name(o); \
369 void set_##name(T name) { \
370 mythrow(nlopt_set_##name(o, name)); \
372 NLOPT_GETSET(double, stopval)
373 NLOPT_GETSET(double, ftol_rel)
374 NLOPT_GETSET(double, ftol_abs)
375 NLOPT_GETSET(double, xtol_rel)
376 NLOPT_GETSET_VEC(xtol_abs)
377 NLOPT_GETSET(int, maxeval)
378 NLOPT_GETSET(double, maxtime)
380 NLOPT_GETSET(int, force_stop)
381 void force_stop() { set_force_stop(1); }
383 // algorithm-specific parameters:
385 void set_local_optimizer(const opt &lo) {
386 nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
390 NLOPT_GETSET(unsigned, population)
391 NLOPT_GETSET_VEC(initial_step)
393 void set_default_initial_step(const std::vector<double> &x) {
395 = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
398 void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
399 if (o && (nlopt_get_dimension(o) != x.size()
400 || nlopt_get_dimension(o) != dx.size()))
401 throw std::invalid_argument("dimension mismatch");
402 nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
403 dx.empty() ? NULL : &dx[0]);
406 std::vector<double> get_initial_step_(const std::vector<double> &x) const {
407 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
408 std::vector<double> v(nlopt_get_dimension(o));
409 get_initial_step(x, v);
415 #undef NLOPT_GETSET_VEC
417 //////////////////////////////////////////////////////////////////////
419 void srand(unsigned long seed) { nlopt_srand(seed); }
420 void srand_time() { nlopt_srand_time(); }
421 void version(int &major, int &minor, int &bugfix) {
422 nlopt_version(&major, &minor, &bugfix);
424 int version_major() {
425 int major, minor, bugfix;
426 nlopt_version(&major, &minor, &bugfix);
429 int version_minor() {
430 int major, minor, bugfix;
431 nlopt_version(&major, &minor, &bugfix);
434 int version_bugfix() {
435 int major, minor, bugfix;
436 nlopt_version(&major, &minor, &bugfix);
439 const char *algorithm_name(algorithm a) {
440 return nlopt_algorithm_name(nlopt_algorithm(a));
443 //////////////////////////////////////////////////////////////////////