From: stevenj Date: Wed, 2 Jun 2010 01:45:55 +0000 (-0400) Subject: streamlined C++ header by using only std::vector and little or no double*; also,... X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=a2327a3cca32635bb0f7ef0b92e7c662cc7ef52c;p=nlopt.git streamlined C++ header by using only std::vector and little or no double*; also, try to be somewhat exception-safe darcs-hash:20100602014555-c8de0-8b4cefb5e66fddd028f137a6d6b7b19ebca5445b.gz --- diff --git a/api/nlopt-in.hpp b/api/nlopt-in.hpp index 977d5aa..3f150aa 100644 --- a/api/nlopt-in.hpp +++ b/api/nlopt-in.hpp @@ -28,6 +28,7 @@ #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) { @@ -42,19 +43,12 @@ namespace nlopt { // 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()(unsigned n, const double *x, double *grad) = 0; - - // should return function value (x is length n) - virtual double operator()(unsigned n, const double *x) = 0; - }; + typedef nlopt_func func; // nlopt::func synoynm - // (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.) + // alternative to nlopt_func that takes std::vector + // but no data pointer ... mostly for SWIG + typedef double (*vfunc)(const std::vector &x, + std::vector &grad); ////////////////////////////////////////////////////////////////////// @@ -74,6 +68,7 @@ namespace nlopt { class opt { private: nlopt_opt o; + bool stopped_by_exception; void mythrow(nlopt_result ret) const { switch (ret) { @@ -86,46 +81,79 @@ namespace nlopt { } } - // nlopt_func wrapper around C++ "functional" - static double myfunc(unsigned n, const double *x, double *grad, void *f_) { - func *f = reinterpret_cast(f_); - return grad ? (*f)(n, x, grad) : (*f)(n, x); + typedef struct { + opt *o; + func f; void *f_data; + vfunc vf; + } myfunc_data; + + // nlopt_func wrapper that catches exceptions + static double myfunc(unsigned n, const double *x, double *grad, void *d_) { + myfunc_data *d = reinterpret_cast(d_); + try { + return d->f(n, x, grad, d->f_data); + } + catch (...) { + d->o->stopped_by_exception = true; + d->o->force_stop(); // stop gracefully, opt::optimize will re-throw + } + } + + // nlopt_func wrapper, using std::vector + static double myvfunc(unsigned n, const double *x, double *grad, void *d_){ + myfunc_data *d = reinterpret_cast(d_); + try { + std::vector xv(n); + for (unsigned i = 0; i < n; ++i) xv[i] = x[i]; + std::vector gradv(grad ? n : 0); + double val = d->vf(xv, gradv); + if (grad) for (unsigned i = 0; i < n; ++i) grad[i] = gradv[i]; + return val; + } + catch (...) { + d->o->stopped_by_exception = true; + d->o->force_stop(); // stop gracefully, opt::optimize will re-throw + } } public: // Constructors etc. - opt() : o(NULL) {} - opt(nlopt_algorithm a, unsigned n) : o(nlopt_create(a, n)) { + opt() : o(NULL), stopped_by_exception(false) {} + ~opt() { nlopt_destroy(o); } + opt(algorithm a, unsigned n) : + o(nlopt_create(nlopt_algorithm(a), n)), stopped_by_exception(false) { if (!o) throw std::bad_alloc(); + nlopt_set_free_f_data(o, 1); } - opt(algorithm a, unsigned n) : o(nlopt_create(nlopt_algorithm(a), n)) { + void reinit(algorithm a, unsigned n) { + if (o) nlopt_destroy(o); + o = nlopt_create(nlopt_algorithm(a), n); if (!o) throw std::bad_alloc(); + nlopt_set_free_f_data(o, 1); } - 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(); + mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data))); } 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(); + mythrow(nlopt_dup_f_data(o, sizeof(myfunc_data))); 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) { if (o && nlopt_get_dimension(o) != x.size()) throw std::invalid_argument("dimension mismatch"); - return optimize(x.empty() ? NULL : &x[0], opt_f); + stopped_by_exception = false; + nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f); + if (ret == NLOPT_FORCED_STOP && stopped_by_exception) + throw; // re-throw last-caught exception + mythrow(ret); + return result(ret); } // accessors: @@ -143,19 +171,29 @@ namespace nlopt { } // 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, void *f_data) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL; + mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o } - void set_min_objective(func *f) { - set_min_objective(myfunc, f); + void set_min_objective(vfunc vf) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = NULL; d->vf = vf; + mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o } - void set_max_objective(nlopt_func f, void *f_data) { - nlopt_result ret = nlopt_set_max_objective(o, f, f_data); - mythrow(ret); + void set_max_objective(func f, void *f_data) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL; + mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o } - void set_max_objective(func *f) { - set_max_objective(myfunc, f); + void set_max_objective(vfunc vf) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = NULL; d->vf = vf; + mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o } // Nonlinear constraints: @@ -164,35 +202,37 @@ namespace nlopt { 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, void *f_data, double tol=0) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL; + mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol)); } - void add_inequality_constraint(func *f, double tol=0) { - add_inequality_constraint(myfunc, f, tol); + void add_inequality_constraint(vfunc vf, double tol=0) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = NULL; d->vf = vf; + mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, 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, void *f_data, double tol=0) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->vf = NULL; + mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol)); } - void add_equality_constraint(func *f, double tol=0) { - add_equality_constraint(myfunc, f, tol); + void add_equality_constraint(vfunc vf, double tol=0) { + myfunc_data *d = (myfunc_data *) std::malloc(sizeof(myfunc_data)); + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = NULL; d->vf = vf; + mythrow(nlopt_add_equality_constraint(o, myvfunc, d, 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); \ @@ -200,7 +240,8 @@ namespace nlopt { void get_##name(std::vector &v) const { \ if (o && nlopt_get_dimension(o) != v.size()) \ throw std::invalid_argument("dimension mismatch"); \ - get_##name(v.empty() ? NULL : &v[0]); \ + nlopt_result ret = nlopt_get_##name(o, v.empty() ? NULL : &v[0]); \ + mythrow(ret); \ } \ std::vector get_##name(void) const { \ if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \ @@ -211,7 +252,8 @@ namespace nlopt { void set_##name(const std::vector &v) { \ if (o && nlopt_get_dimension(o) != v.size()) \ throw std::invalid_argument("dimension mismatch"); \ - set_##name(v.empty() ? NULL : &v[0]); \ + nlopt_result ret = nlopt_set_##name(o, v.empty() ? NULL : &v[0]); \ + mythrow(ret); \ } NLOPT_GETSET_VEC(lower_bounds) @@ -241,34 +283,26 @@ namespace nlopt { // 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_result ret = nlopt_set_local_optimizer(o, lo.o); + mythrow(ret); } NLOPT_GETSET(unsigned, 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); + nlopt_result ret + = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]); mythrow(ret); } void get_initial_step(const std::vector &x, std::vector &dx) const { if (o && (nlopt_get_dimension(o) != x.size() || 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]); + nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0], + dx.empty() ? NULL : &dx[0]); + mythrow(ret); } std::vector get_initial_step(const std::vector &x) const { if (!o) throw std::runtime_error("uninitialized nlopt::opt"); @@ -288,11 +322,8 @@ namespace nlopt { inline void version(int &major, int &minor, int &bugfix) { nlopt_version(&major, &minor, &bugfix); } - inline const char *algorithm_name(nlopt_algorithm a) { - return nlopt_algorithm_name(a); - } inline const char *algorithm_name(algorithm a) { - return algorithm_name(nlopt_algorithm(a)); + return nlopt_algorithm_name(nlopt_algorithm(a)); } ////////////////////////////////////////////////////////////////////// diff --git a/api/nlopt.h b/api/nlopt.h index ec3ed54..8d45723 100644 --- a/api/nlopt.h +++ b/api/nlopt.h @@ -23,7 +23,7 @@ #ifndef NLOPT_H #define NLOPT_H -#include /* for ptrdiff_t */ +#include /* for ptrdiff_t and size_t */ /* use stdcall convention under Windows, since this seems to be more standard there and is important for calling from .NET */ @@ -251,7 +251,8 @@ NLOPT_EXTERN nlopt_result nlopt_get_initial_step(const nlopt_opt opt, /* set to 1: nlopt_destroy should call free() on all of the f_data pointers (for the objective, constraints, etcetera) ... mainly for internal use */ NLOPT_EXTERN nlopt_result nlopt_set_free_f_data(nlopt_opt opt, int val); -NLOPT_EXTERN int nlopt_get_free_f_data(nlopt_opt opt); +NLOPT_EXTERN int nlopt_get_free_f_data(const nlopt_opt opt); +NLOPT_EXTERN nlopt_result nlopt_dup_f_data(nlopt_opt opt, size_t sz); /*************************** DEPRECATED API **************************/ /* The new "object-oriented" API is preferred, since it allows us to diff --git a/api/nlopt.hpp b/api/nlopt.hpp deleted file mode 100644 index cb2acd4..0000000 --- a/api/nlopt.hpp +++ /dev/null @@ -1,384 +0,0 @@ -/* Copyright (c) 2007-2010 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 - enum algorithm { - GN_DIRECT = 0, - GN_DIRECT_L, - GN_DIRECT_L_RAND, - GN_DIRECT_NOSCAL, - GN_DIRECT_L_NOSCAL, - GN_DIRECT_L_RAND_NOSCAL, - GN_ORIG_DIRECT, - GN_ORIG_DIRECT_L, - GD_STOGO, - GD_STOGO_RAND, - LD_LBFGS_NOCEDAL, - LD_LBFGS, - LN_PRAXIS, - LD_VAR1, - LD_VAR2, - LD_TNEWTON, - LD_TNEWTON_RESTART, - LD_TNEWTON_PRECOND, - LD_TNEWTON_PRECOND_RESTART, - GN_CRS2_LM, - GN_MLSL, - GD_MLSL, - GN_MLSL_LDS, - GD_MLSL_LDS, - LD_MMA, - LN_COBYLA, - LN_NEWUOA, - LN_NEWUOA_BOUND, - LN_NELDERMEAD, - LN_SBPLX, - LN_AUGLAG, - LD_AUGLAG, - LN_AUGLAG_EQ, - LD_AUGLAG_EQ, - LN_BOBYQA, - GN_ISRES, - NUM_ALGORITHMS /* not an algorithm, just the number of them */ - }; - enum result { - FAILURE = -1, /* generic failure code */ - INVALID_ARGS = -2, - OUT_OF_MEMORY = -3, - ROUNDOFF_LIMITED = -4, - FORCED_STOP = -5, - SUCCESS = 1, /* generic success code */ - STOPVAL_REACHED = 2, - FTOL_REACHED = 3, - XTOL_REACHED = 4, - MAXEVAL_REACHED = 5, - MAXTIME_REACHED = 6 - }; - // 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()(unsigned n, const double *x, double *grad) = 0; - - // should return function value (x is length n) - virtual double operator()(unsigned n, const double *x) = 0; - }; - - // alternative that uses std::vector for the arguments; note - // that this is less efficient as it requires a copy to be made - class vfunc { - public: - // should return function value, and set grad to gradient - // (x and grad are same length n, and length of grad must not be changed) - virtual double operator()(const std::vector &x, - std::vector &grad) = 0; - - // should return function value (x is length n) - virtual double operator()(const std::vector &x) = 0; - }; - - ////////////////////////////////////////////////////////////////////// - - // NLopt-specific exceptions (corresponding to error codes): - class roundoff_limited : public std::runtime_error { - public: - roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {} - }; - - class forced_stop : public std::runtime_error { - public: - forced_stop() : std::runtime_error("nlopt forced stop") {} - }; - - ////////////////////////////////////////////////////////////////////// - - 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 invalid argument"); - case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited(); - case NLOPT_FORCED_STOP: throw forced_stop(); - default: break; - } - } - - // nlopt_func wrapper around C++ "functional" - static double myfunc(unsigned n, const double *x, double *grad, void *f_) { - func *f = reinterpret_cast(f_); - return grad ? (*f)(n, x, grad) : (*f)(n, x); - } - - // nlopt_func wrapper around C++ "functional", using std::vector - static double myvfunc(unsigned n, const double *x, double *grad, void *f_){ - func *f = reinterpret_cast(f_); - std::vector xv(n); - for (unsigned i = 0; i < n; ++i) xv[i] = x[i]; - if (grad) { - std::vector gradv(n); - double val = (*f)(xv, gradv); - for (unsigned i = 0; i < n; ++i) grad[i] = gradv[i]; - return val; - } - else - return (*f)(xv); - } - - public: - // Constructors etc. - opt() : o(NULL) {} - opt(nlopt_algorithm a, unsigned n) : o(nlopt_create(a, n)) { - if (!o) throw std::bad_alloc(); - } - opt(algorithm a, unsigned 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) { - if (o && nlopt_get_dimension(o) != x.size()) - throw std::invalid_argument("dimension mismatch"); - return optimize(x.empty() ? NULL : &x[0], opt_f); - } - - // accessors: - algorithm get_algorithm() const { - if (!o) throw std::runtime_error("uninitialized nlopt::opt"); - return algorithm(nlopt_get_algorithm(o)); - } - const char *get_algorithm_name() const { - if (!o) throw std::runtime_error("uninitialized nlopt::opt"); - return nlopt_algorithm_name(nlopt_get_algorithm(o)); - } - unsigned get_dimension() const { - if (!o) throw std::runtime_error("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); - } - void set_min_objective(vfunc *f) { - set_min_objective(myvfunc, f); - } - void set_max_objective(nlopt_func f, void *f_data) { - nlopt_result ret = nlopt_set_max_objective(o, f, f_data); - mythrow(ret); - } - void set_max_objective(func *f) { - set_max_objective(myfunc, f); - } - void set_max_objective(vfunc *f) { - set_max_objective(myvfunc, 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 && 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::runtime_error("uninitialized nlopt::opt"); \ - std::vector v(nlopt_get_dimension(o)); \ - get_##name(v); \ - return v; \ - } \ - void set_##name(const std::vector &v) { \ - if (o && 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::runtime_error("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) - - NLOPT_GETSET(int, force_stop) - void force_stop() { set_force_stop(1); } - - // 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(unsigned, 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 && (nlopt_get_dimension(o) != x.size() - || 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::runtime_error("uninitialized nlopt::opt"); - std::vector v(nlopt_get_dimension(o)); - get_initial_step(x, v); - return v; - } - }; - -#undef NLOPT_GETSET -#undef NLOPT_GETSET_VEC - - ////////////////////////////////////////////////////////////////////// - - inline void srand(unsigned long seed) { nlopt_srand(seed); } - inline void srand_time(void) { nlopt_srand_time(); } - inline void version(int &major, int &minor, int &bugfix) { - nlopt_version(&major, &minor, &bugfix); - } - inline const char *algorithm_name(nlopt_algorithm a) { - return nlopt_algorithm_name(a); - } - inline const char *algorithm_name(algorithm a) { - return algorithm_name(nlopt_algorithm(a)); - } - - ////////////////////////////////////////////////////////////////////// - -} // namespace nlopt diff --git a/api/options.c b/api/options.c index b217827..614ec00 100644 --- a/api/options.c +++ b/api/options.c @@ -402,7 +402,9 @@ nlopt_result nlopt_set_force_stop(nlopt_opt opt, int force_stop) } GET(force_stop, int, force_stop) -nlopt_result nlopt_force_stop(nlopt_opt opt) { nlopt_set_force_stop(opt, 1); } +nlopt_result nlopt_force_stop(nlopt_opt opt) { + return nlopt_set_force_stop(opt, 1); +} /*************************************************************************/ @@ -526,4 +528,38 @@ nlopt_result nlopt_set_default_initial_step(nlopt_opt opt, const double *x) GETSET(free_f_data, int, free_f_data) +/* the dup_f_data function replaces all f_data pointers with a new + pointer to a duplicate block of memory, assuming all non-NULL + f_data pointers point to a block of sz bytes... this is pretty + exclusively intended for internal use (e.g. it may lead to a + double-free if one subsequently calles add_inequality_constraint + etc.), e.g. in the C++ API */ + +static int dup(void **p, size_t sz) { + if (*p) { + void *pdup = malloc(sz); + if (pdup) { + memcpy(pdup, *p, sz); + *p = pdup; + return 1; + } + else return 0; + } + else return 1; +} + +nlopt_result nlopt_dup_f_data(nlopt_opt opt, size_t sz) { + if (opt) { + unsigned i; + if (!dup(&opt->f_data, sz)) return NLOPT_OUT_OF_MEMORY; + for (i = 0; i < opt->m; ++i) + if (!dup(&opt->fc[i].f_data, sz)) return NLOPT_OUT_OF_MEMORY; + for (i = 0; i < opt->p; ++i) + if (!dup(&opt->h[i].f_data, sz)) return NLOPT_OUT_OF_MEMORY; + nlopt_set_free_f_data(opt, 1); // nlopt_destroy must now free f_data! + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; +} + /*************************************************************************/