1 /* Copyright (c) 2007-2011 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 #ifndef NLOPT_HPP
27 #define NLOPT_HPP
28 
29 #include <nlopt.h>
30 
31 #include <vector>
32 #include <stdexcept>
33 #include <new>
34 #include <cstdlib>
35 #include <cstring>
36 #include <cmath>
37 
38 // convenience overloading for below (not in nlopt:: since has nlopt_ prefix)
nlopt_get_initial_step(const nlopt_opt opt,double * dx)39 inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) {
40       return nlopt_get_initial_step(opt, (const double *) NULL, dx);
41 }
42 
43 namespace nlopt {
44 
45   //////////////////////////////////////////////////////////////////////
46   // nlopt::* namespace versions of the C enumerated types
47   //          AUTOMATICALLY GENERATED, DO NOT EDIT
48   // GEN_ENUMS_HERE
49   enum algorithm {
50      GN_DIRECT = 0,
51      GN_DIRECT_L,
52      GN_DIRECT_L_RAND,
53      GN_DIRECT_NOSCAL,
54      GN_DIRECT_L_NOSCAL,
55      GN_DIRECT_L_RAND_NOSCAL,
56      GN_ORIG_DIRECT,
57      GN_ORIG_DIRECT_L,
58      GD_STOGO,
59      GD_STOGO_RAND,
60      LD_LBFGS_NOCEDAL,
61      LD_LBFGS,
62      LN_PRAXIS,
63      LD_VAR1,
64      LD_VAR2,
65      LD_TNEWTON,
66      LD_TNEWTON_RESTART,
67      LD_TNEWTON_PRECOND,
68      LD_TNEWTON_PRECOND_RESTART,
69      GN_CRS2_LM,
70      GN_MLSL,
71      GD_MLSL,
72      GN_MLSL_LDS,
73      GD_MLSL_LDS,
74      LD_MMA,
75      LN_COBYLA,
76      LN_NEWUOA,
77      LN_NEWUOA_BOUND,
78      LN_NELDERMEAD,
79      LN_SBPLX,
80      LN_AUGLAG,
81      LD_AUGLAG,
82      LN_AUGLAG_EQ,
83      LD_AUGLAG_EQ,
84      LN_BOBYQA,
85      GN_ISRES,
86      AUGLAG,
87      AUGLAG_EQ,
88      G_MLSL,
89      G_MLSL_LDS,
90      LD_SLSQP,
91      LD_CCSAQ,
92      GN_ESCH,
93      NUM_ALGORITHMS /* not an algorithm, just the number of them */
94   };
95   enum result {
96      FAILURE = -1, /* generic failure code */
97      INVALID_ARGS = -2,
98      OUT_OF_MEMORY = -3,
99      ROUNDOFF_LIMITED = -4,
100      FORCED_STOP = -5,
101      SUCCESS = 1, /* generic success code */
102      STOPVAL_REACHED = 2,
103      FTOL_REACHED = 3,
104      XTOL_REACHED = 4,
105      MAXEVAL_REACHED = 5,
106      MAXTIME_REACHED = 6
107   };
108   // GEN_ENUMS_HERE
109   //////////////////////////////////////////////////////////////////////
110 
111   typedef nlopt_func func; // nlopt::func synoynm
112   typedef nlopt_mfunc mfunc; // nlopt::mfunc synoynm
113 
114   // alternative to nlopt_func that takes std::vector<double>
115   // ... unfortunately requires a data copy
116   typedef double (*vfunc)(const std::vector<double> &x,
117 			  std::vector<double> &grad, void *data);
118 
119   //////////////////////////////////////////////////////////////////////
120 
121   // NLopt-specific exceptions (corresponding to error codes):
122   class roundoff_limited : public std::runtime_error {
123   public:
roundoff_limited()124     roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {}
125   };
126 
127   class forced_stop : public std::runtime_error {
128   public:
forced_stop()129     forced_stop() : std::runtime_error("nlopt forced stop") {}
130   };
131 
132   //////////////////////////////////////////////////////////////////////
133 
134   class opt {
135   private:
136     nlopt_opt o;
137 
mythrow(nlopt_result ret) const138     void mythrow(nlopt_result ret) const {
139       switch (ret) {
140       case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
141       case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc();
142       case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt invalid argument");
143       case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited();
144       case NLOPT_FORCED_STOP: throw forced_stop();
145       default: break;
146       }
147     }
148 
149     typedef struct {
150       opt *o;
151       mfunc mf; func f; void *f_data;
152       vfunc vf;
153       nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
154     } myfunc_data;
155 
156     // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
free_myfunc_data(void * p)157     static void *free_myfunc_data(void *p) {
158       myfunc_data *d = (myfunc_data *) p;
159       if (d) {
160 	if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
161 	delete d;
162       }
163       return NULL;
164     }
dup_myfunc_data(void * p)165     static void *dup_myfunc_data(void *p) {
166       myfunc_data *d = (myfunc_data *) p;
167       if (d) {
168 	void *f_data;
169 	if (d->f_data && d->munge_copy) {
170 	  f_data = d->munge_copy(d->f_data);
171 	  if (!f_data) return NULL;
172 	}
173 	else
174 	  f_data = d->f_data;
175 	myfunc_data *dnew = new myfunc_data;
176 	if (dnew) {
177 	  *dnew = *d;
178 	  dnew->f_data = f_data;
179 	}
180 	return (void*) dnew;
181       }
182       else return NULL;
183     }
184 
185     // nlopt_func wrapper that catches exceptions
myfunc(unsigned n,const double * x,double * grad,void * d_)186     static double myfunc(unsigned n, const double *x, double *grad, void *d_) {
187       myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
188       try {
189 	return d->f(n, x, grad, d->f_data);
190       }
191       catch (std::bad_alloc&)
192 	{ d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
193       catch (std::invalid_argument&)
194 	{ d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
195       catch (roundoff_limited&)
196 	{ d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
197       catch (forced_stop&)
198 	{ d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
199       catch (...)
200 	{ d->o->forced_stop_reason = NLOPT_FAILURE; }
201       d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
202       return HUGE_VAL;
203     }
204 
205     // nlopt_mfunc wrapper that catches exceptions
mymfunc(unsigned m,double * result,unsigned n,const double * x,double * grad,void * d_)206     static void mymfunc(unsigned m, double *result,
207 			unsigned n, const double *x, double *grad, void *d_) {
208       myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
209       try {
210 	d->mf(m, result, n, x, grad, d->f_data);
211 	return;
212       }
213       catch (std::bad_alloc&)
214 	{ d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
215       catch (std::invalid_argument&)
216 	{ d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
217       catch (roundoff_limited&)
218 	{ d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
219       catch (forced_stop&)
220 	{ d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
221       catch (...)
222 	{ d->o->forced_stop_reason = NLOPT_FAILURE; }
223       d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
224       for (unsigned i = 0; i < m; ++i) result[i] = HUGE_VAL;
225     }
226 
227     std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
228 
229     // nlopt_func wrapper, using std::vector<double>
myvfunc(unsigned n,const double * x,double * grad,void * d_)230     static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
231       myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
232       try {
233 	std::vector<double> &xv = d->o->xtmp;
234 	if (n) std::memcpy(&xv[0], x, n * sizeof(double));
235 	double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
236 	if (grad && n) {
237 	  std::vector<double> &gradv = d->o->gradtmp;
238 	  std::memcpy(grad, &gradv[0], n * sizeof(double));
239 	}
240 	return val;
241       }
242       catch (std::bad_alloc&)
243 	{ d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
244       catch (std::invalid_argument&)
245 	{ d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
246       catch (roundoff_limited&)
247 	{ d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
248       catch (forced_stop&)
249 	{ d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
250       catch (...)
251 	{ d->o->forced_stop_reason = NLOPT_FAILURE; }
252       d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
253       return HUGE_VAL;
254     }
255 
alloc_tmp()256     void alloc_tmp() {
257       if (xtmp.size() != nlopt_get_dimension(o)) {
258 	xtmp = std::vector<double>(nlopt_get_dimension(o));
259 	gradtmp = std::vector<double>(nlopt_get_dimension(o));
260       }
261     }
262 
263     result last_result;
264     double last_optf;
265     nlopt_result forced_stop_reason;
266 
267   public:
268     // Constructors etc.
opt()269     opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
270 	    last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
271 	    forced_stop_reason(NLOPT_FORCED_STOP) {}
~opt()272     ~opt() { nlopt_destroy(o); }
opt(algorithm a,unsigned n)273     opt(algorithm a, unsigned n) :
274       o(nlopt_create(nlopt_algorithm(a), n)),
275       xtmp(0), gradtmp(0), gradtmp0(0),
276       last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
277       forced_stop_reason(NLOPT_FORCED_STOP) {
278       if (!o) throw std::bad_alloc();
279       nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
280     }
opt(const opt & f)281     opt(const opt& f) : o(nlopt_copy(f.o)),
282 			xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
283 			last_result(f.last_result), last_optf(f.last_optf),
284 			forced_stop_reason(f.forced_stop_reason) {
285       if (f.o && !o) throw std::bad_alloc();
286     }
operator =(opt const & f)287     opt& operator=(opt const& f) {
288       if (this == &f) return *this; // self-assignment
289       nlopt_destroy(o);
290       o = nlopt_copy(f.o);
291       if (f.o && !o) throw std::bad_alloc();
292       xtmp = f.xtmp; gradtmp = f.gradtmp;
293       last_result = f.last_result; last_optf = f.last_optf;
294       forced_stop_reason = f.forced_stop_reason;
295       return *this;
296     }
297 
298     // Do the optimization:
optimize(std::vector<double> & x,double & opt_f)299     result optimize(std::vector<double> &x, double &opt_f) {
300       if (o && nlopt_get_dimension(o) != x.size())
301         throw std::invalid_argument("dimension mismatch");
302       forced_stop_reason = NLOPT_FORCED_STOP;
303       nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
304       last_result = result(ret);
305       last_optf = opt_f;
306       if (ret == NLOPT_FORCED_STOP)
307 	mythrow(forced_stop_reason);
308       mythrow(ret);
309       return last_result;
310     }
311 
312     // variant mainly useful for SWIG wrappers:
optimize(const std::vector<double> & x0)313     std::vector<double> optimize(const std::vector<double> &x0) {
314       std::vector<double> x(x0);
315       last_result = optimize(x, last_optf);
316       return x;
317     }
last_optimize_result() const318     result last_optimize_result() const { return last_result; }
last_optimum_value() const319     double last_optimum_value() const { return last_optf; }
320 
321     // accessors:
get_algorithm() const322     algorithm get_algorithm() const {
323       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
324       return algorithm(nlopt_get_algorithm(o));
325     }
get_algorithm_name() const326     const char *get_algorithm_name() const {
327       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
328       return nlopt_algorithm_name(nlopt_get_algorithm(o));
329     }
get_dimension() const330     unsigned get_dimension() const {
331       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
332       return nlopt_get_dimension(o);
333     }
334 
335     // Set the objective function
set_min_objective(func f,void * f_data)336     void set_min_objective(func f, void *f_data) {
337       myfunc_data *d = new myfunc_data;
338       if (!d) throw std::bad_alloc();
339       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
340       d->munge_destroy = d->munge_copy = NULL;
341       mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
342     }
set_min_objective(vfunc vf,void * f_data)343     void set_min_objective(vfunc vf, void *f_data) {
344       myfunc_data *d = new myfunc_data;
345       if (!d) throw std::bad_alloc();
346       d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
347       d->munge_destroy = d->munge_copy = NULL;
348       mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
349       alloc_tmp();
350     }
set_max_objective(func f,void * f_data)351     void set_max_objective(func f, void *f_data) {
352       myfunc_data *d = new myfunc_data;
353       if (!d) throw std::bad_alloc();
354       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
355       d->munge_destroy = d->munge_copy = NULL;
356       mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
357     }
set_max_objective(vfunc vf,void * f_data)358     void set_max_objective(vfunc vf, void *f_data) {
359       myfunc_data *d = new myfunc_data;
360       if (!d) throw std::bad_alloc();
361       d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
362       d->munge_destroy = d->munge_copy = NULL;
363       mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
364       alloc_tmp();
365     }
366 
367     // for internal use in SWIG wrappers -- variant that
368     // takes ownership of f_data, with munging for destroy/copy
set_min_objective(func f,void * f_data,nlopt_munge md,nlopt_munge mc)369     void set_min_objective(func f, void *f_data,
370 			   nlopt_munge md, nlopt_munge mc) {
371       myfunc_data *d = new myfunc_data;
372       if (!d) throw std::bad_alloc();
373       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
374       d->munge_destroy = md; d->munge_copy = mc;
375       mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
376     }
set_max_objective(func f,void * f_data,nlopt_munge md,nlopt_munge mc)377     void set_max_objective(func f, void *f_data,
378 			   nlopt_munge md, nlopt_munge mc) {
379       myfunc_data *d = new myfunc_data;
380       if (!d) throw std::bad_alloc();
381       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
382       d->munge_destroy = md; d->munge_copy = mc;
383       mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
384     }
385 
386     // Nonlinear constraints:
387 
remove_inequality_constraints()388     void remove_inequality_constraints() {
389       nlopt_result ret = nlopt_remove_inequality_constraints(o);
390       mythrow(ret);
391     }
add_inequality_constraint(func f,void * f_data,double tol=0)392     void add_inequality_constraint(func f, void *f_data, double tol=0) {
393       myfunc_data *d = new myfunc_data;
394       if (!d) throw std::bad_alloc();
395       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
396       d->munge_destroy = d->munge_copy = NULL;
397       mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
398     }
add_inequality_constraint(vfunc vf,void * f_data,double tol=0)399     void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) {
400       myfunc_data *d = new myfunc_data;
401       if (!d) throw std::bad_alloc();
402       d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
403       d->munge_destroy = d->munge_copy = NULL;
404       mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
405       alloc_tmp();
406     }
add_inequality_mconstraint(mfunc mf,void * f_data,const std::vector<double> & tol)407     void add_inequality_mconstraint(mfunc mf, void *f_data,
408 				    const std::vector<double> &tol) {
409       myfunc_data *d = new myfunc_data;
410       if (!d) throw std::bad_alloc();
411       d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
412       d->munge_destroy = d->munge_copy = NULL;
413       mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
414 					       tol.empty() ? NULL : &tol[0]));
415     }
416 
remove_equality_constraints()417     void remove_equality_constraints() {
418       nlopt_result ret = nlopt_remove_equality_constraints(o);
419       mythrow(ret);
420     }
add_equality_constraint(func f,void * f_data,double tol=0)421     void add_equality_constraint(func f, void *f_data, double tol=0) {
422       myfunc_data *d = new myfunc_data;
423       if (!d) throw std::bad_alloc();
424       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
425       d->munge_destroy = d->munge_copy = NULL;
426       mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
427     }
add_equality_constraint(vfunc vf,void * f_data,double tol=0)428     void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
429       myfunc_data *d = new myfunc_data;
430       if (!d) throw std::bad_alloc();
431       d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
432       d->munge_destroy = d->munge_copy = NULL;
433       mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
434       alloc_tmp();
435     }
add_equality_mconstraint(mfunc mf,void * f_data,const std::vector<double> & tol)436     void add_equality_mconstraint(mfunc mf, void *f_data,
437 				  const std::vector<double> &tol) {
438       myfunc_data *d = new myfunc_data;
439       if (!d) throw std::bad_alloc();
440       d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
441       d->munge_destroy = d->munge_copy = NULL;
442       mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
443 					     tol.empty() ? NULL : &tol[0]));
444     }
445 
446     // For internal use in SWIG wrappers (see also above)
add_inequality_constraint(func f,void * f_data,nlopt_munge md,nlopt_munge mc,double tol=0)447     void add_inequality_constraint(func f, void *f_data,
448 				   nlopt_munge md, nlopt_munge mc,
449 				   double tol=0) {
450       myfunc_data *d = new myfunc_data;
451       if (!d) throw std::bad_alloc();
452       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
453       d->munge_destroy = md; d->munge_copy = mc;
454       mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
455     }
add_equality_constraint(func f,void * f_data,nlopt_munge md,nlopt_munge mc,double tol=0)456     void add_equality_constraint(func f, void *f_data,
457 				 nlopt_munge md, nlopt_munge mc,
458 				 double tol=0) {
459       myfunc_data *d = new myfunc_data;
460       if (!d) throw std::bad_alloc();
461       d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
462       d->munge_destroy = md; d->munge_copy = mc;
463       mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
464     }
add_inequality_mconstraint(mfunc mf,void * f_data,nlopt_munge md,nlopt_munge mc,const std::vector<double> & tol)465     void add_inequality_mconstraint(mfunc mf, void *f_data,
466 				    nlopt_munge md, nlopt_munge mc,
467 				    const std::vector<double> &tol) {
468       myfunc_data *d = new myfunc_data;
469       if (!d) throw std::bad_alloc();
470       d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
471       d->munge_destroy = md; d->munge_copy = mc;
472       mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
473 					       tol.empty() ? NULL : &tol[0]));
474     }
add_equality_mconstraint(mfunc mf,void * f_data,nlopt_munge md,nlopt_munge mc,const std::vector<double> & tol)475     void add_equality_mconstraint(mfunc mf, void *f_data,
476 				  nlopt_munge md, nlopt_munge mc,
477 				  const std::vector<double> &tol) {
478       myfunc_data *d = new myfunc_data;
479       if (!d) throw std::bad_alloc();
480       d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
481       d->munge_destroy = md; d->munge_copy = mc;
482       mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
483 					     tol.empty() ? NULL : &tol[0]));
484     }
485 
486 #define NLOPT_GETSET_VEC(name)						\
487     void set_##name(double val) {					\
488       mythrow(nlopt_set_##name##1(o, val));				\
489     }									\
490     void get_##name(std::vector<double> &v) const {			\
491       if (o && nlopt_get_dimension(o) != v.size())			\
492         throw std::invalid_argument("dimension mismatch");		\
493       mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0]));		\
494     }									\
495     std::vector<double> get_##name() const {			\
496       if (!o) throw std::runtime_error("uninitialized nlopt::opt");	\
497       std::vector<double> v(nlopt_get_dimension(o));			\
498       get_##name(v);							\
499       return v;								\
500     }			 						\
501     void set_##name(const std::vector<double> &v) {			\
502       if (o && nlopt_get_dimension(o) != v.size())			\
503         throw std::invalid_argument("dimension mismatch");		\
504       mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0]));		\
505     }
506 
507     NLOPT_GETSET_VEC(lower_bounds)
NLOPT_GETSET_VEC(upper_bounds)508     NLOPT_GETSET_VEC(upper_bounds)
509 
510     // stopping criteria:
511 
512 #define NLOPT_GETSET(T, name)						\
513     T get_##name() const {						\
514       if (!o) throw std::runtime_error("uninitialized nlopt::opt");	\
515       return nlopt_get_##name(o);					\
516     }									\
517     void set_##name(T name) {						\
518       mythrow(nlopt_set_##name(o, name));				\
519     }
520     NLOPT_GETSET(double, stopval)
521     NLOPT_GETSET(double, ftol_rel)
522     NLOPT_GETSET(double, ftol_abs)
523     NLOPT_GETSET(double, xtol_rel)
524     NLOPT_GETSET_VEC(xtol_abs)
525     NLOPT_GETSET(int, maxeval)
526     NLOPT_GETSET(double, maxtime)
527 
528     NLOPT_GETSET(int, force_stop)
529     void force_stop() { set_force_stop(1); }
530 
531     // algorithm-specific parameters:
532 
set_local_optimizer(const opt & lo)533     void set_local_optimizer(const opt &lo) {
534       nlopt_result ret = nlopt_set_local_optimizer(o, lo.o);
535       mythrow(ret);
536     }
537 
NLOPT_GETSET(unsigned,population)538     NLOPT_GETSET(unsigned, population)
539     NLOPT_GETSET(unsigned, vector_storage)
540     NLOPT_GETSET_VEC(initial_step)
541 
542     void set_default_initial_step(const std::vector<double> &x) {
543       nlopt_result ret
544 	= nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
545       mythrow(ret);
546     }
get_initial_step(const std::vector<double> & x,std::vector<double> & dx) const547     void get_initial_step(const std::vector<double> &x, std::vector<double> &dx) const {
548       if (o && (nlopt_get_dimension(o) != x.size()
549 		|| nlopt_get_dimension(o) != dx.size()))
550         throw std::invalid_argument("dimension mismatch");
551       nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0],
552 						dx.empty() ? NULL : &dx[0]);
553       mythrow(ret);
554     }
get_initial_step_(const std::vector<double> & x) const555     std::vector<double> get_initial_step_(const std::vector<double> &x) const {
556       if (!o) throw std::runtime_error("uninitialized nlopt::opt");
557       std::vector<double> v(nlopt_get_dimension(o));
558       get_initial_step(x, v);
559       return v;
560     }
561   };
562 
563 #undef NLOPT_GETSET
564 #undef NLOPT_GETSET_VEC
565 
566   //////////////////////////////////////////////////////////////////////
567 
srand(unsigned long seed)568   inline void srand(unsigned long seed) { nlopt_srand(seed); }
srand_time()569   inline void srand_time() { nlopt_srand_time(); }
version(int & major,int & minor,int & bugfix)570   inline void version(int &major, int &minor, int &bugfix) {
571     nlopt_version(&major, &minor, &bugfix);
572   }
version_major()573   inline int version_major() {
574     int major, minor, bugfix;
575     nlopt_version(&major, &minor, &bugfix);
576     return major;
577   }
version_minor()578   inline int version_minor() {
579     int major, minor, bugfix;
580     nlopt_version(&major, &minor, &bugfix);
581     return minor;
582   }
version_bugfix()583   inline int version_bugfix() {
584     int major, minor, bugfix;
585     nlopt_version(&major, &minor, &bugfix);
586     return bugfix;
587   }
algorithm_name(algorithm a)588   inline const char *algorithm_name(algorithm a) {
589     return nlopt_algorithm_name(nlopt_algorithm(a));
590   }
591 
592   //////////////////////////////////////////////////////////////////////
593 
594 } // namespace nlopt
595 
596 #endif /* NLOPT_HPP */
597