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 //////////////////////////////////////////////////////////////////////
73 bool stopped_by_exception;
75 void mythrow(nlopt_result ret) const {
77 case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
78 case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
79 case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt invalid argument");
80 case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
81 case NLOPT_FORCED_STOP: throw forced_stop();
92 // nlopt_func wrapper that catches exceptions
93 static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
94 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
96 return d->f(n, x, grad, d->f_data);
99 d->o->stopped_by_exception = true;
100 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
105 std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
107 // nlopt_func wrapper, using std::vector<double>
108 static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
109 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
111 std::vector<double> &xv = d->o->xtmp;
112 if (n) std::memcpy(&xv[0], x, n * sizeof(double));
113 double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
115 std::vector<double> &gradv = d->o->gradtmp;
116 std::memcpy(grad, &gradv[0], n * sizeof(double));
121 d->o->stopped_by_exception = true;
122 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
128 if (xtmp.size() != nlopt_get_dimension(o)) {
129 xtmp = std::vector<double>(nlopt_get_dimension(o));
130 gradtmp = std::vector<double>(nlopt_get_dimension(o));
137 o(NULL), stopped_by_exception(false), xtmp(0), gradtmp(0), gradtmp0(0) {}
138 ~opt() { nlopt_destroy(o); }
139 opt(algorithm a, unsigned n) :
140 o(nlopt_create(nlopt_algorithm(a), n)), stopped_by_exception(false),
141 xtmp(0), gradtmp(0), gradtmp0(0) {
142 if (!o) throw std::bad_alloc();
143 nlopt_set_free_f_data(o, 1);
145 opt(const opt& from) : o(nlopt_copy(from.o)) {
146 if (from.o && !o) throw std::bad_alloc();
147 mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data)));
149 opt& operator=(opt const& f) {
150 if (this == &f) return *this; // self-assignment
153 if (f.o && !o) throw std::bad_alloc();
154 mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data)));
158 // Do the optimization:
159 result optimize(std::vector<double> &x, double &opt_f) {
160 if (o && nlopt_get_dimension(o) != x.size())
161 throw std::invalid_argument("dimension mismatch");
162 stopped_by_exception = false;
163 nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
164 if (ret == NLOPT_FORCED_STOP && stopped_by_exception)
165 throw; // re-throw last-caught exception
171 algorithm get_algorithm() const {
172 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
173 return algorithm(nlopt_get_algorithm(o));
175 const char *get_algorithm_name() const {
176 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
177 return nlopt_algorithm_name(nlopt_get_algorithm(o));
179 unsigned get_dimension() const {
180 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
181 return nlopt_get_dimension(o);
184 // Set the objective function
185 void set_min_objective(func f, void *f_data) {
186 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
187 if (!d) throw std::bad_alloc();
188 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
189 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
191 void set_min_objective(vfunc vf, void *f_data) {
192 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
193 if (!d) throw std::bad_alloc();
194 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
195 mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
198 void set_max_objective(func f, void *f_data) {
199 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
200 if (!d) throw std::bad_alloc();
201 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
202 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
204 void set_max_objective(vfunc vf, void *f_data) {
205 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
206 if (!d) throw std::bad_alloc();
207 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
208 mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
212 // Nonlinear constraints:
214 void remove_inequality_constraints(void) {
215 nlopt_result ret = nlopt_remove_inequality_constraints(o);
218 void add_inequality_constraint(func f, void *f_data, double tol=0) {
219 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
220 if (!d) throw std::bad_alloc();
221 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
222 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
224 void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
225 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
226 if (!d) throw std::bad_alloc();
227 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
228 mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
232 void remove_equality_constraints(void) {
233 nlopt_result ret = nlopt_remove_equality_constraints(o);
236 void add_equality_constraint(func f, void *f_data, double tol=0) {
237 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
238 if (!d) throw std::bad_alloc();
239 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
240 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
242 void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
243 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
244 if (!d) throw std::bad_alloc();
245 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
246 mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
250 #define NLOPT_GETSET_VEC(name) \
251 void set_##name(double val) { \
252 nlopt_result ret = nlopt_set_##name##1(o, val); \
255 void get_##name(std::vector<double> &v) const { \
256 if (o && nlopt_get_dimension(o) != v.size()) \
257 throw std::invalid_argument("dimension mismatch"); \
258 nlopt_result ret = nlopt_get_##name(o, v.empty() ? NULL : &v[0]); \
261 std::vector<double> get_##name(void) const { \
262 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
263 std::vector<double> v(nlopt_get_dimension(o)); \
267 void set_##name(const std::vector<double> &v) { \
268 if (o && nlopt_get_dimension(o) != v.size()) \
269 throw std::invalid_argument("dimension mismatch"); \
270 nlopt_result ret = nlopt_set_##name(o, v.empty() ? NULL : &v[0]); \
274 NLOPT_GETSET_VEC(lower_bounds)
275 NLOPT_GETSET_VEC(upper_bounds)
277 // stopping criteria:
279 #define NLOPT_GETSET(T, name) \
280 T get_##name() const { \
281 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
282 return nlopt_get_##name(o); \
284 void set_##name(T name) { \
285 nlopt_result ret = nlopt_set_##name(o, name); \
288 NLOPT_GETSET(double, stopval)
289 NLOPT_GETSET(double, ftol_rel)
290 NLOPT_GETSET(double, ftol_abs)
291 NLOPT_GETSET(double, xtol_rel)
292 NLOPT_GETSET_VEC(xtol_abs)
293 NLOPT_GETSET(int, maxeval)
294 NLOPT_GETSET(double, maxtime)
296 NLOPT_GETSET(int, force_stop)
297 void force_stop() { set_force_stop(1); }
299 // algorithm-specific parameters:
301 void set_local_optimizer(const opt &lo) {
302 nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
306 NLOPT_GETSET(unsigned, population)
307 NLOPT_GETSET_VEC(initial_step)
309 void set_default_initial_step(const std::vector<double> &x) {
311 = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
314 void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
315 if (o && (nlopt_get_dimension(o) != x.size()
316 || nlopt_get_dimension(o) != dx.size()))
317 throw std::invalid_argument("dimension mismatch");
318 nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
319 dx.empty() ? NULL : &dx[0]);
322 std::vector<double> get_initial_step(const std::vector<double> &x) const {
323 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
324 std::vector<double> v(nlopt_get_dimension(o));
325 get_initial_step(x, v);
331 #undef NLOPT_GETSET_VEC
333 //////////////////////////////////////////////////////////////////////
335 inline void srand(unsigned long seed) { nlopt_srand(seed); }
336 inline void srand_time(void) { nlopt_srand_time(); }
337 inline void version(int &major, int &minor, int &bugfix) {
338 nlopt_version(&major, &minor, &bugfix);
340 inline const char *algorithm_name(algorithm a) {
341 return nlopt_algorithm_name(nlopt_algorithm(a));
344 //////////////////////////////////////////////////////////////////////