chiark / gitweb /
add C++ style API
authorstevenj <stevenj@alum.mit.edu>
Mon, 5 Apr 2010 04:49:54 +0000 (00:49 -0400)
committerstevenj <stevenj@alum.mit.edu>
Mon, 5 Apr 2010 04:49:54 +0000 (00:49 -0400)
darcs-hash:20100405044954-c8de0-9c3737452317f7a0619d9acff42fd48a847ef894.gz

api/Makefile.am
api/nlopt-in.hpp [new file with mode: 0644]
api/nlopt.h
api/options.c

index 7b9cfb4ab13279f50124aa02f0d6467ea7acb6a6..29d8ebe1ed3f8b2ada7b732cf1c231e7b72ee4db 100644 (file)
@@ -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 (file)
index 0000000..1e76826
--- /dev/null
@@ -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 <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
+  //////////////////////////////////////////////////////////////////////
+
+  // 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<double> 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<func*>(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<double> &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<double> &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<double> get_##name(void) const {                       \
+      if (!o) throw std::invalid_argument("uninitialized nlopt::opt"); \
+      std::vector<double> v(unsigned(nlopt_get_dimension(o)));         \
+      get_##name(v);                                                   \
+      return v;                                                                \
+    }                                                                  \
+    void set_##name(const std::vector<double> &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<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 && (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<double> get_initial_step(const std::vector<double> &x) const {
+      if (!o) throw std::invalid_argument("uninitialized nlopt::opt");
+      std::vector<double> v(unsigned(nlopt_get_dimension(o)));
+      get_initial_step(x, v);
+      return v;
+    }
+  };
+
+  //////////////////////////////////////////////////////////////////////
+
+} // namespace nlopt
index 6d19f14c2474a660298606ad796f363a375e762e..39c56d189195da06ab83eb6c5ad62c074a079373 100644 (file)
@@ -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);
index 50fcfa42d55b6ec6e66939a2754aa8b15e30e61b..6e7e1a942a83b6300a2d90a48b0bcfbd5cf3e226 100644 (file)
@@ -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));