chiark / gitweb /
streamlined C++ header by using only std::vector and little or no double*; also,...
authorstevenj <stevenj@alum.mit.edu>
Wed, 2 Jun 2010 01:45:55 +0000 (21:45 -0400)
committerstevenj <stevenj@alum.mit.edu>
Wed, 2 Jun 2010 01:45:55 +0000 (21:45 -0400)
darcs-hash:20100602014555-c8de0-8b4cefb5e66fddd028f137a6d6b7b19ebca5445b.gz

api/nlopt-in.hpp
api/nlopt.h
api/nlopt.hpp [deleted file]
api/options.c

index 977d5aa6eaa94ab0d0af27662bce42f1d38e8ecf..3f150aa0aafbaa9f1f7ac1aeefdf16b23c9ddb8a 100644 (file)
@@ -28,6 +28,7 @@
 #include <vector>
 #include <stdexcept>
 #include <new>
+#include <cstdlib>
 
 // 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<double> 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<double>
+  // but no data pointer ... mostly for SWIG
+  typedef double (*vfunc)(const std::vector<double> &x,
+                         std::vector<double> &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<func*>(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<myfunc_data*>(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<double>
+    static double myvfunc(unsigned n, const double *x, double *grad, void *d_){
+      myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
+      try {
+       std::vector<double> xv(n);
+       for (unsigned i = 0; i < n; ++i) xv[i] = x[i];
+       std::vector<double> 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<double> &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<double> &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<double> 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<double> &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<double> &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<double> &x, std::vector<double> &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<double> get_initial_step(const std::vector<double> &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));
   }
 
   //////////////////////////////////////////////////////////////////////
index ec3ed54e901d4145a3b57c68642e7e5ec99be518..8d45723732a882f1b55e11e68d563ce5dfaedb02 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef NLOPT_H
 #define NLOPT_H
 
-#include <stddef.h> /* for ptrdiff_t */
+#include <stddef.h> /* 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 (file)
index cb2acd4..0000000
+++ /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 <nlopt.h>
-
-#include <vector>
-#include <stdexcept>
-#include <new>
-
-// 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<double> 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<double> &x, 
-                             std::vector<double> &grad) = 0;
-
-    // should return function value (x is length n)
-    virtual double operator()(const std::vector<double> &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<func*>(f_);
-      return grad ? (*f)(n, x, grad) : (*f)(n, x);
-    }
-
-    // nlopt_func wrapper around C++ "functional", using std::vector<double>
-    static double myvfunc(unsigned n, const double *x, double *grad, void *f_){
-      func *f = reinterpret_cast<vfunc*>(f_);
-      std::vector<double> xv(n);
-      for (unsigned i = 0; i < n; ++i) xv[i] = x[i];
-      if (grad) {
-       std::vector<double> 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<double> &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<double> &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<double> get_##name(void) const {                       \
-      if (!o) throw std::runtime_error("uninitialized nlopt::opt");    \
-      std::vector<double> v(nlopt_get_dimension(o));                   \
-      get_##name(v);                                                   \
-      return v;                                                                \
-    }                                                                  \
-    void set_##name(const std::vector<double> &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<double> &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<double> &x, std::vector<double> &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<double> get_initial_step(const std::vector<double> &x) const {
-      if (!o) throw std::runtime_error("uninitialized nlopt::opt");
-      std::vector<double> 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
index b217827e7af42a18e9dfab97f5bb58aa77e32e2a..614ec005bf55e8fdd2e1e610f1a489eb4ea0b9c6 100644 (file)
@@ -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;
+}
+
 /*************************************************************************/