chiark / gitweb /
add set_max_objective to automate the sign flip for maximization
[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
32 // convenience overloading for below (not in nlopt:: since has nlopt_ prefix)
33 inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) {
34       return nlopt_get_initial_step(opt, (const double *) NULL, dx);
35 }
36
37 namespace nlopt {
38
39   //////////////////////////////////////////////////////////////////////
40   // nlopt::* namespace versions of the C enumerated types
41   //          AUTOMATICALLY GENERATED, DO NOT EDIT
42   // GEN_ENUMS_HERE
43   //////////////////////////////////////////////////////////////////////
44
45   // virtual base class for objective function and constraints:
46   class func {
47   public:
48     // should return function value, and set grad to gradient
49     // (x and grad are length n)
50     virtual double operator()(unsigned n, const double *x, double *grad) = 0;
51
52     // should return function value (x is length n)
53     virtual double operator()(unsigned n, const double *x) = 0;
54   };
55
56   // (Note: it is inefficient to use std::vector<double> for the arguments,
57   //  since that would require a copy to be made of NLopt's double* data.)
58
59   //////////////////////////////////////////////////////////////////////
60
61   class opt {
62   private:
63     nlopt_opt o;
64     
65     void mythrow(nlopt_result ret) const {
66       switch (ret) {
67       case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
68       case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
69       case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt");
70       case NLOPT_ROUNDOFF_LIMITED: throw std::runtime_error("nlopt roundoff");
71       default: break;
72       }
73     }
74
75     // nlopt_func wrapper around C++ "functional"
76     static double myfunc(unsigned n, const double *x, double *grad, void *f_) {
77       func *f = reinterpret_cast<func*>(f_);
78       return grad ? (*f)(n, x, grad) : (*f)(n, x);
79     }
80
81   public:
82     // Constructors etc.
83     opt() : o(NULL) {}
84     opt(nlopt_algorithm a, unsigned n) : o(nlopt_create(a, n)) {
85       if (!o) throw std::bad_alloc();
86     }
87     opt(algorithm a, unsigned n) : o(nlopt_create(nlopt_algorithm(a), n)) {
88       if (!o) throw std::bad_alloc();
89     }
90     opt(const nlopt_opt o0) : o(nlopt_copy(o0)) {
91       if (o0 && !o) throw std::bad_alloc();
92     }
93     ~opt() { nlopt_destroy(o); }
94     opt(const opt& from) : o(nlopt_copy(from.o)) {
95       if (from.o && !o) throw std::bad_alloc();
96     }
97     opt& operator=(opt const& f) {
98       if (this == &f) return *this; // self-assignment
99       nlopt_destroy(o);
100       o = nlopt_copy(f.o);
101       if (f.o && !o) throw std::bad_alloc();
102       return *this;
103     }
104
105     // Do the optimization:
106     result optimize(double *x, double &opt_f) {
107       nlopt_result ret = nlopt_optimize(o, x, &opt_f);
108       mythrow(ret);
109       return result(ret);
110     }
111     result optimize(std::vector<double> &x, double &opt_f) {
112       return optimize(x.empty() ? NULL : &x[0], opt_f);
113     }
114
115     // accessors:
116     algorithm get_algorithm() const {
117       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
118       return algorithm(nlopt_get_algorithm(o));
119     }
120     unsigned get_dimension() const {
121       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
122       return nlopt_get_dimension(o);
123     }
124
125     // Set the objective function
126     void set_min_objective(nlopt_func f, void *f_data) {
127       nlopt_result ret = nlopt_set_min_objective(o, f, f_data);
128       mythrow(ret);
129     }
130     void set_min_objective(func *f) {
131       set_min_objective(myfunc, f);
132     }
133     void set_max_objective(nlopt_func f, void *f_data) {
134       nlopt_result ret = nlopt_set_max_objective(o, f, f_data);
135       mythrow(ret);
136     }
137     void set_max_objective(func *f) {
138       set_max_objective(myfunc, f);
139     }
140
141     // Nonlinear constraints:
142
143     void remove_inequality_constraints(void) {
144       nlopt_result ret = nlopt_remove_inequality_constraints(o);
145       mythrow(ret);
146     }
147     void add_inequality_constraint(nlopt_func f, void *f_data, double tol=0) {
148       nlopt_result ret = nlopt_add_inequality_constraint(o, f, f_data, tol);
149       mythrow(ret);
150     }
151     void add_inequality_constraint(func *f, double tol=0) {
152       add_inequality_constraint(myfunc, f, tol);
153     }
154
155     void remove_equality_constraints(void) {
156       nlopt_result ret = nlopt_remove_equality_constraints(o);
157       mythrow(ret);
158     }
159     void add_equality_constraint(nlopt_func f, void *f_data, double tol=0) {
160       nlopt_result ret = nlopt_add_equality_constraint(o, f, f_data, tol);
161       mythrow(ret);
162     }
163     void add_equality_constraint(func *f, double tol=0) {
164       add_equality_constraint(myfunc, f, tol);
165     }
166
167 #define NLOPT_GETSET_VEC(name)                                          \
168     void get_##name(double *v) const {                                  \
169       nlopt_result ret = nlopt_get_##name(o, v);                        \
170       mythrow(ret);                                                     \
171     }                                                                   \
172     void set_##name(const double *v) {                                  \
173       nlopt_result ret = nlopt_set_##name(o, v);                        \
174       mythrow(ret);                                                     \
175     }                                                                   \
176     void set_##name(double val) {                                       \
177       nlopt_result ret = nlopt_set_##name##1(o, val);                   \
178       mythrow(ret);                                                     \
179     }                                                                   \
180     void get_##name(std::vector<double> &v) const {                     \
181       if (o && nlopt_get_dimension(o) != v.size())                      \
182         throw std::invalid_argument("dimension mismatch");              \
183       get_##name(v.empty() ? NULL : &v[0]);                             \
184     }                                                                   \
185     std::vector<double> get_##name(void) const {                        \
186       if (!o) throw std::runtime_error("uninitialized nlopt::opt");     \
187       std::vector<double> v(nlopt_get_dimension(o));                    \
188       get_##name(v);                                                    \
189       return v;                                                         \
190     }                                                                   \
191     void set_##name(const std::vector<double> &v) {                     \
192       if (o && nlopt_get_dimension(o) != v.size())                      \
193         throw std::invalid_argument("dimension mismatch");              \
194       set_##name(v.empty() ? NULL : &v[0]);                             \
195     }
196
197     NLOPT_GETSET_VEC(lower_bounds)
198     NLOPT_GETSET_VEC(upper_bounds)
199
200     // stopping criteria:
201
202 #define NLOPT_GETSET(T, name)                                           \
203     T get_##name() const {                                              \
204       if (!o) throw std::runtime_error("uninitialized nlopt::opt");     \
205       return nlopt_get_##name(o);                                       \
206     }                                                                   \
207     void set_##name(T name) {                                           \
208       nlopt_result ret = nlopt_set_##name(o, name);                     \
209       mythrow(ret);                                                     \
210     }
211     NLOPT_GETSET(double, stopval)
212     NLOPT_GETSET(double, ftol_rel)
213     NLOPT_GETSET(double, ftol_abs)
214     NLOPT_GETSET(double, xtol_rel)
215     NLOPT_GETSET_VEC(xtol_abs)
216     NLOPT_GETSET(int, maxeval)
217     NLOPT_GETSET(double, maxtime)
218
219     // algorithm-specific parameters:
220
221     void set_local_optimizer(const nlopt_opt lo) {
222       nlopt_result ret = nlopt_set_local_optimizer(o, lo);
223       mythrow(ret);
224     }
225     void set_local_optimizer(const opt &lo) {
226       set_local_optimizer(lo.o);
227     }
228
229     NLOPT_GETSET(unsigned, population)
230     NLOPT_GETSET_VEC(initial_step)
231
232     void set_default_initial_step(const double *x) {
233       nlopt_result ret = nlopt_set_default_initial_step(o, x);
234       mythrow(ret);
235     }
236     void set_default_initial_step(const std::vector<double> &x) {
237       set_default_initial_step(x.empty() ? NULL : &x[0]);
238     }
239     void get_initial_step(const double *x, double *dx) const {
240       nlopt_result ret = nlopt_get_initial_step(o, x, dx);
241       mythrow(ret);
242     }
243     void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
244       if (o && (nlopt_get_dimension(o) != x.size()
245                 || nlopt_get_dimension(o) != dx.size()))
246         throw std::invalid_argument("dimension mismatch");
247       get_initial_step(x.empty() ? NULL : &x[0],
248                        dx.empty() ? NULL : &dx[0]);
249     }
250     std::vector<double> get_initial_step(const std::vector<double> &x) const {
251       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
252       std::vector<double> v(nlopt_get_dimension(o));
253       get_initial_step(x, v);
254       return v;
255     }
256   };
257
258 #undef NLOPT_GETSET
259 #undef NLOPT_GETSET_VEC
260
261   //////////////////////////////////////////////////////////////////////
262
263 } // namespace nlopt