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!
33 // convenience overloading for below (not in nlopt:: since has nlopt_ prefix)
34 inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) {
35 return nlopt_get_initial_step(opt, (const double *) NULL, dx);
40 //////////////////////////////////////////////////////////////////////
41 // nlopt::* namespace versions of the C enumerated types
42 // AUTOMATICALLY GENERATED, DO NOT EDIT
44 //////////////////////////////////////////////////////////////////////
46 typedef nlopt_func func; // nlopt::func synoynm
48 // alternative to nlopt_func that takes std::vector<double>
49 // ... unfortunately requires a data copy
50 typedef double (*vfunc)(const std::vector<double> &x,
51 std::vector<double> &grad, void *data);
53 //////////////////////////////////////////////////////////////////////
55 // NLopt-specific exceptions (corresponding to error codes):
56 class roundoff_limited : public std::runtime_error {
58 roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
61 class forced_stop : public std::runtime_error {
63 forced_stop() : std::runtime_error("nlopt forced stop") {}
66 //////////////////////////////////////////////////////////////////////
71 bool stopped_by_exception;
73 void mythrow(nlopt_result ret) const {
75 case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
76 case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
77 case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt invalid argument");
78 case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
79 case NLOPT_FORCED_STOP: throw forced_stop();
90 // nlopt_func wrapper that catches exceptions
91 static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
92 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
94 return d->f(n, x, grad, d->f_data);
97 d->o->stopped_by_exception = true;
98 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
102 // nlopt_func wrapper, using std::vector<double>
103 static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
104 myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
106 std::vector<double> xv(n);
107 for (unsigned i = 0; i < n; ++i) xv[i] = x[i];
108 std::vector<double> gradv(grad ? n : 0);
109 double val = d->vf(xv, gradv, d->f_data);
110 if (grad) for (unsigned i = 0; i < n; ++i) grad[i] = gradv[i];
114 d->o->stopped_by_exception = true;
115 d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
121 opt() : o(NULL), stopped_by_exception(false) {}
122 ~opt() { nlopt_destroy(o); }
123 opt(algorithm a, unsigned n) :
124 o(nlopt_create(nlopt_algorithm(a), n)), stopped_by_exception(false) {
125 if (!o) throw std::bad_alloc();
126 nlopt_set_free_f_data(o, 1);
128 void reinit(algorithm a, unsigned n) {
129 if (o) nlopt_destroy(o);
130 o = nlopt_create(nlopt_algorithm(a), n);
131 if (!o) throw std::bad_alloc();
132 nlopt_set_free_f_data(o, 1);
134 opt(const opt& from) : o(nlopt_copy(from.o)) {
135 if (from.o && !o) throw std::bad_alloc();
136 mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data)));
138 opt& operator=(opt const& f) {
139 if (this == &f) return *this; // self-assignment
142 if (f.o && !o) throw std::bad_alloc();
143 mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data)));
147 // Do the optimization:
148 result optimize(std::vector<double> &x, double &opt_f) {
149 if (o && nlopt_get_dimension(o) != x.size())
150 throw std::invalid_argument("dimension mismatch");
151 stopped_by_exception = false;
152 nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
153 if (ret == NLOPT_FORCED_STOP && stopped_by_exception)
154 throw; // re-throw last-caught exception
160 algorithm get_algorithm() const {
161 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
162 return algorithm(nlopt_get_algorithm(o));
164 const char *get_algorithm_name() const {
165 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
166 return nlopt_algorithm_name(nlopt_get_algorithm(o));
168 unsigned get_dimension() const {
169 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
170 return nlopt_get_dimension(o);
173 // Set the objective function
174 void set_min_objective(func f, void *f_data) {
175 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
176 if (!d) throw std::bad_alloc();
177 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
178 mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
180 void set_min_objective(vfunc vf, void *f_data) {
181 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
182 if (!d) throw std::bad_alloc();
183 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
184 mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
186 void set_max_objective(func f, void *f_data) {
187 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
188 if (!d) throw std::bad_alloc();
189 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
190 mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
192 void set_max_objective(vfunc vf, void *f_data) {
193 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
194 if (!d) throw std::bad_alloc();
195 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
196 mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
199 // Nonlinear constraints:
201 void remove_inequality_constraints(void) {
202 nlopt_result ret = nlopt_remove_inequality_constraints(o);
205 void add_inequality_constraint(func f, void *f_data, double tol=0) {
206 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
207 if (!d) throw std::bad_alloc();
208 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
209 mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
211 void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
212 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
213 if (!d) throw std::bad_alloc();
214 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
215 mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
218 void remove_equality_constraints(void) {
219 nlopt_result ret = nlopt_remove_equality_constraints(o);
222 void add_equality_constraint(func f, void *f_data, double tol=0) {
223 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
224 if (!d) throw std::bad_alloc();
225 d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL;
226 mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
228 void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
229 myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data));
230 if (!d) throw std::bad_alloc();
231 d->o = this; d->f = NULL; d->f_data = f_data; d->vf = vf;
232 mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
235 #define NLOPT_GETSET_VEC(name) \
236 void set_##name(double val) { \
237 nlopt_result ret = nlopt_set_##name##1(o, val); \
240 void get_##name(std::vector<double> &v) const { \
241 if (o && nlopt_get_dimension(o) != v.size()) \
242 throw std::invalid_argument("dimension mismatch"); \
243 nlopt_result ret = nlopt_get_##name(o, v.empty() ? NULL : &v[0]); \
246 std::vector<double> get_##name(void) const { \
247 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
248 std::vector<double> v(nlopt_get_dimension(o)); \
252 void set_##name(const std::vector<double> &v) { \
253 if (o && nlopt_get_dimension(o) != v.size()) \
254 throw std::invalid_argument("dimension mismatch"); \
255 nlopt_result ret = nlopt_set_##name(o, v.empty() ? NULL : &v[0]); \
259 NLOPT_GETSET_VEC(lower_bounds)
260 NLOPT_GETSET_VEC(upper_bounds)
262 // stopping criteria:
264 #define NLOPT_GETSET(T, name) \
265 T get_##name() const { \
266 if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \
267 return nlopt_get_##name(o); \
269 void set_##name(T name) { \
270 nlopt_result ret = nlopt_set_##name(o, name); \
273 NLOPT_GETSET(double, stopval)
274 NLOPT_GETSET(double, ftol_rel)
275 NLOPT_GETSET(double, ftol_abs)
276 NLOPT_GETSET(double, xtol_rel)
277 NLOPT_GETSET_VEC(xtol_abs)
278 NLOPT_GETSET(int, maxeval)
279 NLOPT_GETSET(double, maxtime)
281 NLOPT_GETSET(int, force_stop)
282 void force_stop() { set_force_stop(1); }
284 // algorithm-specific parameters:
286 void set_local_optimizer(const opt &lo) {
287 nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
291 NLOPT_GETSET(unsigned, population)
292 NLOPT_GETSET_VEC(initial_step)
294 void set_default_initial_step(const std::vector<double> &x) {
296 = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
299 void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
300 if (o && (nlopt_get_dimension(o) != x.size()
301 || nlopt_get_dimension(o) != dx.size()))
302 throw std::invalid_argument("dimension mismatch");
303 nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
304 dx.empty() ? NULL : &dx[0]);
307 std::vector<double> get_initial_step(const std::vector<double> &x) const {
308 if (!o) throw std::runtime_error("uninitialized nlopt::opt");
309 std::vector<double> v(nlopt_get_dimension(o));
310 get_initial_step(x, v);
316 #undef NLOPT_GETSET_VEC
318 //////////////////////////////////////////////////////////////////////
320 inline void srand(unsigned long seed) { nlopt_srand(seed); }
321 inline void srand_time(void) { nlopt_srand_time(); }
322 inline void version(int &major, int &minor, int &bugfix) {
323 nlopt_version(&major, &minor, &bugfix);
325 inline const char *algorithm_name(algorithm a) {
326 return nlopt_algorithm_name(nlopt_algorithm(a));
329 //////////////////////////////////////////////////////////////////////