chiark / gitweb /
silence compiler warning
[nlopt.git] / api / nlopt-in.hpp
1 /* Copyright (c) 2007-2010 Massachusetts Institute of Technology
2  *
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:
10  * 
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  * 
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. 
21  */
22
23 // C++ style wrapper around NLopt API
24 // nlopt.hpp is AUTOMATICALLY GENERATED from nlopt-in.hpp - edit the latter!
25
26 #include <nlopt.h>
27
28 #include <vector>
29 #include <stdexcept>
30 #include <new>
31 #include <cstdlib>
32 #include <cstring>
33 #include <cmath>
34
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);
38 }
39
40 namespace nlopt {
41
42   //////////////////////////////////////////////////////////////////////
43   // nlopt::* namespace versions of the C enumerated types
44   //          AUTOMATICALLY GENERATED, DO NOT EDIT
45   // GEN_ENUMS_HERE
46   //////////////////////////////////////////////////////////////////////
47
48   typedef nlopt_func func; // nlopt::func synoynm
49
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);
54
55   //////////////////////////////////////////////////////////////////////
56   
57   // NLopt-specific exceptions (corresponding to error codes):
58   class roundoff_limited : public std::runtime_error {
59   public:
60     roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
61   };
62
63   class forced_stop : public std::runtime_error {
64   public:
65     forced_stop() : std::runtime_error("nlopt forced stop") {}
66   };
67
68   //////////////////////////////////////////////////////////////////////
69
70   class opt {
71   private:
72     nlopt_opt o;
73     
74     void mythrow(nlopt_result ret) const {
75       switch (ret) {
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();
81       default: break;
82       }
83     }
84
85     typedef struct {
86       opt *o;
87       func f; void *f_data;
88       vfunc vf;
89       nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
90     } myfunc_data;
91
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;
95       if (d) {
96         if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
97         delete d;
98       }
99       return NULL;
100     }
101     static void *dup_myfunc_data(void *p) {
102       myfunc_data *d = (myfunc_data *) p;
103       if (d) {
104         void *f_data;
105         if (d->f_data && d->munge_copy) {
106           f_data = d->munge_copy(d->f_data);
107           if (!f_data) return NULL;
108         }
109         else
110           f_data = d->f_data;
111         myfunc_data *dnew = new myfunc_data;
112         if (dnew) {
113           *dnew = *d;
114           dnew->f_data = f_data;
115         }
116         return (void*) dnew;
117       }
118       else return NULL;
119     }
120
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_);
124       try {
125         return d->f(n, x, grad, d->f_data);
126       }
127       catch (...) {
128         d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
129         return HUGE_VAL;
130       }
131     }
132
133     std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
134
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_);
138       try {
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);
142         if (grad && n) {
143           std::vector<double> &gradv = d->o->gradtmp;
144           std::memcpy(grad, &gradv[0], n * sizeof(double));
145         }
146         return val;
147       }
148       catch (...) {
149         d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
150         return HUGE_VAL;
151       }
152     }
153
154     void alloc_tmp() {
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));
158       }
159     }
160
161     result last_result;
162     double last_optf;
163
164   public:
165     // Constructors etc.
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);
175     }
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();
180     }
181     opt& operator=(opt const& f) {
182       if (this == &f) return *this; // self-assignment
183       nlopt_destroy(o);
184       o = nlopt_copy(f.o);
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;
188       return *this;
189     }
190
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);
197       last_optf = opt_f;
198       mythrow(ret);
199       return last_result;
200     }
201
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);
206       return x;
207     }
208     result last_optimize_result() const { return last_result; }
209     double last_optimum_value() const { return last_optf; }
210
211     // accessors:
212     algorithm get_algorithm() const {
213       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
214       return algorithm(nlopt_get_algorithm(o));
215     }
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));
219     }
220     unsigned get_dimension() const {
221       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
222       return nlopt_get_dimension(o);
223     }
224
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
232     }
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
239       alloc_tmp();
240     }
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
247     }
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
254       alloc_tmp();
255     }
256
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
266     }
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
274     }
275
276     // Nonlinear constraints:
277
278     void remove_inequality_constraints() {
279       nlopt_result ret = nlopt_remove_inequality_constraints(o);
280       mythrow(ret);
281     }
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));
288     }
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));
295       alloc_tmp();
296     }
297
298     void remove_equality_constraints() {
299       nlopt_result ret = nlopt_remove_equality_constraints(o);
300       mythrow(ret);
301     }
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));
308     }
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));
315       alloc_tmp();
316     }
317
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,
321                                    double tol=0) {
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));
327     }
328     void add_equality_constraint(func f, void *f_data, 
329                                  nlopt_munge md, nlopt_munge mc,
330                                  double tol=0) {
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));
336     }
337
338 #define NLOPT_GETSET_VEC(name)                                          \
339     void set_##name(double val) {                                       \
340       mythrow(nlopt_set_##name##1(o, val));                             \
341     }                                                                   \
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]));           \
346     }                                                                   \
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));                    \
350       get_##name(v);                                                    \
351       return v;                                                         \
352     }                                                                   \
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]));           \
357     }
358
359     NLOPT_GETSET_VEC(lower_bounds)
360     NLOPT_GETSET_VEC(upper_bounds)
361
362     // stopping criteria:
363
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);                                       \
368     }                                                                   \
369     void set_##name(T name) {                                           \
370       mythrow(nlopt_set_##name(o, name));                               \
371     }
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)
379
380     NLOPT_GETSET(int, force_stop)
381     void force_stop() { set_force_stop(1); }
382
383     // algorithm-specific parameters:
384
385     void set_local_optimizer(const opt &lo) {
386       nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
387       mythrow(ret);
388     }
389
390     NLOPT_GETSET(unsigned, population)
391     NLOPT_GETSET_VEC(initial_step)
392
393     void set_default_initial_step(const std::vector<double> &x) {
394       nlopt_result ret 
395         = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
396       mythrow(ret);
397     }
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]);
404       mythrow(ret);
405     }
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);
410       return v;
411     }
412   };
413
414 #undef NLOPT_GETSET
415 #undef NLOPT_GETSET_VEC
416
417   //////////////////////////////////////////////////////////////////////
418
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);
423   }
424   int version_major() {
425     int major, minor, bugfix;
426     nlopt_version(&major, &minor, &bugfix);
427     return major;
428   }
429   int version_minor() {
430     int major, minor, bugfix;
431     nlopt_version(&major, &minor, &bugfix);
432     return minor;
433   }
434   int version_bugfix() {
435     int major, minor, bugfix;
436     nlopt_version(&major, &minor, &bugfix);
437     return bugfix;
438   }
439   const char *algorithm_name(algorithm a) {
440     return nlopt_algorithm_name(nlopt_algorithm(a));
441   }
442
443   //////////////////////////////////////////////////////////////////////
444
445 } // namespace nlopt