From 13e0f27769e24fcbef15029a96f03278f445b0f2 Mon Sep 17 00:00:00 2001 From: stevenj Date: Mon, 5 Apr 2010 00:49:54 -0400 Subject: [PATCH] add C++ style API darcs-hash:20100405044954-c8de0-9c3737452317f7a0619d9acff42fd48a847ef894.gz --- api/Makefile.am | 11 ++- api/nlopt-in.hpp | 253 +++++++++++++++++++++++++++++++++++++++++++++++ api/nlopt.h | 9 +- api/options.c | 35 +++++-- 4 files changed, 295 insertions(+), 13 deletions(-) create mode 100644 api/nlopt-in.hpp diff --git a/api/Makefile.am b/api/Makefile.am index 7b9cfb4..29d8ebe 100644 --- a/api/Makefile.am +++ b/api/Makefile.am @@ -1,19 +1,24 @@ AM_CPPFLAGS = -I$(top_srcdir)/cdirect -I$(top_srcdir)/direct -I$(top_srcdir)/stogo -I$(top_srcdir)/praxis -I$(top_srcdir)/lbfgs -I$(top_srcdir)/luksan -I$(top_srcdir)/crs -I$(top_srcdir)/mlsl -I$(top_srcdir)/mma -I$(top_srcdir)/cobyla -I$(top_srcdir)/newuoa -I$(top_srcdir)/neldermead -I$(top_srcdir)/auglag -I$(top_srcdir)/bobyqa -I$(top_srcdir)/isres -I$(top_srcdir)/util -include_HEADERS = nlopt.h nlopt.f +include_HEADERS = nlopt.h nlopt.f nlopt.hpp noinst_LTLIBRARIES = libapi.la dist_man_MANS = nlopt_minimize.3 nlopt_minimize_constrained.3 libapi_la_SOURCES = general.c options.c optimize.c deprecated.c \ nlopt-internal.h nlopt.h f77api.c f77funcs.h -BUILT_SOURCES = nlopt.f +BUILT_SOURCES = nlopt.f nlopt.hpp +EXTRA_DIST = nlopt-in.hpp if MAINTAINER_MODE -# convert constants to F77 parameter statements +# convert constants to F77 parameter statements & C++ nlopt.f: nlopt.h rm -f $@ (i=0; egrep 'NLOPT_[LG][DN]' $(srcdir)/nlopt.h | tr -d ' =0,' | while read n; do echo " integer $$n"; echo " parameter ($$n=$$i)"; i=`expr $$i + 1`; done; tail -n +`grep -n enum $(srcdir)/nlopt.h |cut -d: -f1 |tail -n 1` $(srcdir)/nlopt.h | grep NLOPT | grep -v NLOPT_EXTERN | cut -d, -f1 | tr -d ' ' | perl -pe 's/([A-Za-z0-9_]+)=([-+0-9]+)/ integer \1\n parameter (\1=\2)/') > $@ +nlopt.hpp: nlopt.h nlopt-in.hpp + rm -f $@ + (n=`grep -n GEN_ENUMS_HERE nlopt-in.hpp | cut -d: -f1`; head -n $$n $(srcdir)/nlopt-in.hpp; echo " enum algorithm {"; egrep 'NLOPT_[LG][DN]|NLOPT_NUM_ALGORITHMS' $(srcdir)/nlopt.h | sed 's/NLOPT_//g'; echo " };"; echo " enum result {"; egrep 'NLOPT_[A-Z_]* =' $(srcdir)/nlopt.h | egrep -v 'NLOPT_[LG][DN]' | sed 's/NLOPT_//g'; echo " };"; tail -n +$$n $(srcdir)/nlopt-in.hpp) > $@ + endif diff --git a/api/nlopt-in.hpp b/api/nlopt-in.hpp new file mode 100644 index 0000000..1e76826 --- /dev/null +++ b/api/nlopt-in.hpp @@ -0,0 +1,253 @@ +/* Copyright (c) 2007-2009 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// C++ style wrapper around NLopt API +// nlopt.hpp is AUTOMATICALLY GENERATED from nlopt-in.hpp - edit the latter! + +#include + +#include +#include +#include + +// convenience overloading for below (not in nlopt:: since has nlopt_ prefix) +inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) { + return nlopt_get_initial_step(opt, (const double *) NULL, dx); +} + +namespace nlopt { + + ////////////////////////////////////////////////////////////////////// + // nlopt::* namespace versions of the C enumerated types + // AUTOMATICALLY GENERATED, DO NOT EDIT + // GEN_ENUMS_HERE + ////////////////////////////////////////////////////////////////////// + + // virtual base class for objective function and constraints: + class func { + public: + // should return function value, and set grad to gradient + // (x and grad are length n) + virtual double operator()(int n, const double *x, double *grad) = 0; + + // should return function value (x is length n) + virtual double operator()(int n, const double *x) = 0; + }; + + // (Note: it is inefficient to use std::vector for the arguments, + // since that would require a copy to be made of NLopt's double* data.) + + ////////////////////////////////////////////////////////////////////// + + class opt { + private: + nlopt_opt o; + + void mythrow(nlopt_result ret) const { + switch (ret) { + case NLOPT_FAILURE: throw std::runtime_error("nlopt failure"); + case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc(); + case NLOPT_INVALID_ARGS: throw std::invalid_argument("nlopt"); + case NLOPT_ROUNDOFF_LIMITED: throw std::runtime_error("nlopt roundoff"); + default: break; + } + } + + // nlopt_func wrapper around C++ "functional" + static double myfunc(int n, const double *x, double *grad, void *f_) { + func *f = reinterpret_cast(f_); + return grad ? (*f)(n, x, grad) : (*f)(n, x); + } + + public: + // Constructors etc. + opt() : o(NULL) {} + opt(nlopt_algorithm a, int n) : o(nlopt_create(a, n)) { + if (!o) throw std::bad_alloc(); + } + opt(algorithm a, int n) : o(nlopt_create(nlopt_algorithm(a), n)) { + if (!o) throw std::bad_alloc(); + } + opt(const nlopt_opt o0) : o(nlopt_copy(o0)) { + if (o0 && !o) throw std::bad_alloc(); + } + ~opt() { nlopt_destroy(o); } + opt(const opt& from) : o(nlopt_copy(from.o)) { + if (from.o && !o) throw std::bad_alloc(); + } + opt& operator=(opt const& f) { + if (this == &f) return *this; // self-assignment + nlopt_destroy(o); + o = nlopt_copy(f.o); + if (f.o && !o) throw std::bad_alloc(); + return *this; + } + + // Do the optimization: + result optimize(double *x, double &opt_f) { + nlopt_result ret = nlopt_optimize(o, x, &opt_f); + mythrow(ret); + return result(ret); + } + result optimize(std::vector &x, double &opt_f) { + return optimize(x.empty() ? NULL : &x[0], opt_f); + } + + // accessors: + algorithm get_algorithm() const { + if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); + return algorithm(nlopt_get_algorithm(o)); + } + int get_dimension() const { + if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); + return nlopt_get_dimension(o); + } + + // Set the objective function + void set_min_objective(nlopt_func f, void *f_data) { + nlopt_result ret = nlopt_set_min_objective(o, f, f_data); + mythrow(ret); + } + void set_min_objective(func *f) { + set_min_objective(myfunc, f); + } + + // Nonlinear constraints: + + void remove_inequality_constraints(void) { + nlopt_result ret = nlopt_remove_inequality_constraints(o); + mythrow(ret); + } + void add_inequality_constraint(nlopt_func f, void *f_data, double tol=0) { + nlopt_result ret = nlopt_add_inequality_constraint(o, f, f_data, tol); + mythrow(ret); + } + void add_inequality_constraint(func *f, double tol=0) { + add_inequality_constraint(myfunc, f, tol); + } + + void remove_equality_constraints(void) { + nlopt_result ret = nlopt_remove_equality_constraints(o); + mythrow(ret); + } + void add_equality_constraint(nlopt_func f, void *f_data, double tol=0) { + nlopt_result ret = nlopt_add_equality_constraint(o, f, f_data, tol); + mythrow(ret); + } + void add_equality_constraint(func *f, double tol=0) { + add_equality_constraint(myfunc, f, tol); + } + +#define NLOPT_GETSET_VEC(name) \ + void get_##name(double *v) const { \ + nlopt_result ret = nlopt_get_##name(o, v); \ + mythrow(ret); \ + } \ + void set_##name(const double *v) { \ + nlopt_result ret = nlopt_set_##name(o, v); \ + mythrow(ret); \ + } \ + void set_##name(double val) { \ + nlopt_result ret = nlopt_set_##name##1(o, val); \ + mythrow(ret); \ + } \ + void get_##name(std::vector &v) const { \ + if (o && unsigned(nlopt_get_dimension(o)) != v.size()) \ + throw std::invalid_argument("dimension mismatch"); \ + get_##name(v.empty() ? NULL : &v[0]); \ + } \ + std::vector get_##name(void) const { \ + if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); \ + std::vector v(unsigned(nlopt_get_dimension(o))); \ + get_##name(v); \ + return v; \ + } \ + void set_##name(const std::vector &v) { \ + if (o && unsigned(nlopt_get_dimension(o)) != v.size()) \ + throw std::invalid_argument("dimension mismatch"); \ + set_##name(v.empty() ? NULL : &v[0]); \ + } + + NLOPT_GETSET_VEC(lower_bounds) + NLOPT_GETSET_VEC(upper_bounds) + + // stopping criteria: + +#define NLOPT_GETSET(T, name) \ + T get_##name() const { \ + if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); \ + return nlopt_get_##name(o); \ + } \ + void set_##name(T name) { \ + nlopt_result ret = nlopt_set_##name(o, name); \ + mythrow(ret); \ + } + NLOPT_GETSET(double, stopval) + NLOPT_GETSET(double, ftol_rel) + NLOPT_GETSET(double, ftol_abs) + NLOPT_GETSET(double, xtol_rel) + NLOPT_GETSET_VEC(xtol_abs) + NLOPT_GETSET(int, maxeval) + NLOPT_GETSET(double, maxtime) + + // algorithm-specific parameters: + + void set_local_optimizer(const nlopt_opt lo) { + nlopt_result ret = nlopt_set_local_optimizer(o, lo); + mythrow(ret); + } + void set_local_optimizer(const opt &lo) { + set_local_optimizer(lo.o); + } + + NLOPT_GETSET(int, population) + NLOPT_GETSET_VEC(initial_step) + + void set_default_initial_step(const double *x) { + nlopt_result ret = nlopt_set_default_initial_step(o, x); + mythrow(ret); + } + void set_default_initial_step(const std::vector &x) { + set_default_initial_step(x.empty() ? NULL : &x[0]); + } + void get_initial_step(const double *x, double *dx) const { + nlopt_result ret = nlopt_get_initial_step(o, x, dx); + mythrow(ret); + } + void get_initial_step(const std::vector &x, std::vector &dx) const { + if (o && (unsigned(nlopt_get_dimension(o)) != x.size() + || unsigned(nlopt_get_dimension(o)) != dx.size())) + throw std::invalid_argument("dimension mismatch"); + get_initial_step(x.empty() ? NULL : &x[0], + dx.empty() ? NULL : &dx[0]); + } + std::vector get_initial_step(const std::vector &x) const { + if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); + std::vector v(unsigned(nlopt_get_dimension(o))); + get_initial_step(x, v); + return v; + } + }; + + ////////////////////////////////////////////////////////////////////// + +} // namespace nlopt diff --git a/api/nlopt.h b/api/nlopt.h index 6d19f14..39c56d1 100644 --- a/api/nlopt.h +++ b/api/nlopt.h @@ -182,11 +182,13 @@ NLOPT_EXTERN int nlopt_get_dimension(const nlopt_opt opt); NLOPT_EXTERN nlopt_result nlopt_set_lower_bounds(nlopt_opt opt, const double *lb); NLOPT_EXTERN nlopt_result nlopt_set_lower_bounds1(nlopt_opt opt, double lb); -NLOPT_EXTERN void nlopt_get_lower_bounds(const nlopt_opt opt, double *lb); +NLOPT_EXTERN nlopt_result nlopt_get_lower_bounds(const nlopt_opt opt, + double *lb); NLOPT_EXTERN nlopt_result nlopt_set_upper_bounds(nlopt_opt opt, const double *ub); NLOPT_EXTERN nlopt_result nlopt_set_upper_bounds1(nlopt_opt opt, double ub); -NLOPT_EXTERN void nlopt_get_upper_bounds(const nlopt_opt opt, double *ub); +NLOPT_EXTERN nlopt_result nlopt_get_upper_bounds(const nlopt_opt opt, + double *ub); NLOPT_EXTERN nlopt_result nlopt_remove_inequality_constraints(nlopt_opt opt); NLOPT_EXTERN nlopt_result nlopt_add_inequality_constraint(nlopt_opt opt, @@ -214,7 +216,8 @@ NLOPT_EXTERN nlopt_result nlopt_set_xtol_rel(nlopt_opt opt, double tol); NLOPT_EXTERN double nlopt_get_xtol_rel(const nlopt_opt opt); NLOPT_EXTERN nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, double tol); NLOPT_EXTERN nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); -NLOPT_EXTERN void nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); +NLOPT_EXTERN nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, + double *tol); NLOPT_EXTERN nlopt_result nlopt_set_maxeval(nlopt_opt opt, int maxeval); NLOPT_EXTERN int nlopt_get_maxeval(nlopt_opt opt); diff --git a/api/options.c b/api/options.c index 50fcfa4..6e7e1a9 100644 --- a/api/options.c +++ b/api/options.c @@ -169,7 +169,7 @@ nlopt_result nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void *f_data) nlopt_result nlopt_set_lower_bounds(nlopt_opt opt, const double *lb) { - if (opt) { + if (opt && (opt->n == 0 || lb)) { memcpy(opt->lb, lb, sizeof(double) * U(opt->n)); return NLOPT_SUCCESS; } @@ -187,9 +187,18 @@ nlopt_result nlopt_set_lower_bounds1(nlopt_opt opt, double lb) return NLOPT_INVALID_ARGS; } +nlopt_result nlopt_get_lower_bounds(nlopt_opt opt, double *lb) +{ + if (opt && (opt->n == 0 || lb)) { + memcpy(lb, opt->lb, sizeof(double) * U(opt->n)); + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; +} + nlopt_result nlopt_set_upper_bounds(nlopt_opt opt, const double *ub) { - if (opt) { + if (opt && (opt->n == 0 || ub)) { memcpy(opt->ub, ub, sizeof(double) * U(opt->n)); return NLOPT_SUCCESS; } @@ -207,6 +216,15 @@ nlopt_result nlopt_set_upper_bounds1(nlopt_opt opt, double ub) return NLOPT_INVALID_ARGS; } +nlopt_result nlopt_get_upper_bounds(nlopt_opt opt, double *ub) +{ + if (opt && (opt->n == 0 || ub)) { + memcpy(ub, opt->ub, sizeof(double) * U(opt->n)); + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; +} + /*************************************************************************/ #define AUGLAG_ALG(a) ((a) == NLOPT_LN_AUGLAG || \ @@ -333,9 +351,10 @@ nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, const double xtol_abs) return NLOPT_INVALID_ARGS; } -void nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs) +nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_abs) { memcpy(xtol_abs, opt->xtol_abs, opt->n & sizeof(double)); + return NLOPT_SUCCESS; } GETSET(maxeval, int, maxeval) @@ -397,15 +416,17 @@ nlopt_result nlopt_set_initial_step(nlopt_opt opt, const double *dx) return NLOPT_SUCCESS; } -nlopt_result nlopt_get_initial_step(nlopt_opt opt, const double *x, double *dx) +nlopt_result nlopt_get_initial_step(const nlopt_opt opt, const double *x, + double *dx) { if (!opt) return NLOPT_INVALID_ARGS; if (!opt->n) return NLOPT_SUCCESS; if (!opt->dx) { - nlopt_result ret = nlopt_set_default_initial_step(opt, x); + nlopt_opt o = (nlopt_opt) opt; /* discard const temporarily */ + nlopt_result ret = nlopt_set_default_initial_step(o, x); if (ret != NLOPT_SUCCESS) return ret; - memcpy(dx, opt->dx, sizeof(double) * U(opt->n)); - free(opt->dx); opt->dx = NULL; /* don't save, since x-dependent */ + memcpy(dx, o->dx, sizeof(double) * U(opt->n)); + free(o->dx); o->dx = NULL; /* don't save, since x-dependent */ } else memcpy(dx, opt->dx, sizeof(double) * U(opt->n)); -- 2.30.2