chiark / gitweb /
Use trusty
[nlopt.git] / api / nlopt-in.hpp
index a4d91440ed5d7b3a979168c92dfacc2f0defd1b5..582c676fd9704e7dd073d6e8a043356f4ae9bf2a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2010 Massachusetts Institute of Technology
+/* Copyright (c) 2007-2011 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
 // C++ style wrapper around NLopt API
 // nlopt.hpp is AUTOMATICALLY GENERATED from nlopt-in.hpp - edit the latter!
 
+#ifndef NLOPT_HPP
+#define NLOPT_HPP
+
 #include <nlopt.h>
 
 #include <vector>
 #include <stdexcept>
 #include <new>
+#include <cstdlib>
+#include <cstring>
+#include <cmath>
 
 // 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 +48,26 @@ 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;
+  typedef nlopt_func func; // nlopt::func synoynm
+  typedef nlopt_mfunc mfunc; // nlopt::mfunc synoynm
+
+  // alternative to nlopt_func that takes std::vector<double>
+  // ... unfortunately requires a data copy
+  typedef double (*vfunc)(const std::vector<double> &x,
+                         std::vector<double> &grad, void *data);
 
-    // should return function value (x is length n)
-    virtual double operator()(unsigned n, const 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") {}
   };
 
-  // (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 forced_stop : public std::runtime_error {
+  public:
+    forced_stop() : std::runtime_error("nlopt forced stop") {}
+  };
 
   //////////////////////////////////////////////////////////////////////
 
@@ -64,125 +77,362 @@ namespace nlopt {
     
     void mythrow(nlopt_result ret) const {
       switch (ret) {
-      case NLOPT_FAILURE: throw std::runtime_error("nlopt failure");
+      case NLOPT_FAILURE: throw std::runtime_error(get_errmsg() ? get_errmsg() : "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");
+      case NLOPT_INVALID_ARGS: throw std::invalid_argument(get_errmsg() ? get_errmsg() : "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);
+    typedef struct {
+      opt *o;
+      mfunc mf; func f; void *f_data;
+      vfunc vf;
+      nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers
+    } myfunc_data;
+
+    // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
+    static void *free_myfunc_data(void *p) { 
+      myfunc_data *d = (myfunc_data *) p;
+      if (d) {
+       if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
+       delete d;
+      }
+      return NULL;
+    }
+    static void *dup_myfunc_data(void *p) {
+      myfunc_data *d = (myfunc_data *) p;
+      if (d) {
+       void *f_data;
+       if (d->f_data && d->munge_copy) {
+         f_data = d->munge_copy(d->f_data);
+         if (!f_data) return NULL;
+       }
+       else
+         f_data = d->f_data;
+       myfunc_data *dnew = new myfunc_data;
+       if (dnew) {
+         *dnew = *d;
+         dnew->f_data = f_data;
+       }
+       return (void*) dnew;
+      }
+      else return NULL;
     }
 
-  public:
-    // Constructors etc.
-    opt() : o(NULL) {}
-    opt(nlopt_algorithm a, unsigned n) : o(nlopt_create(a, n)) {
-      if (!o) throw std::bad_alloc();
+    // 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 (std::bad_alloc&)
+       { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
+      catch (std::invalid_argument&)
+       { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
+      catch (roundoff_limited&)
+       { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
+      catch (forced_stop&)
+       { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
+      catch (...)
+       { d->o->forced_stop_reason = NLOPT_FAILURE; }
+      d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
+      return HUGE_VAL;
     }
-    opt(algorithm a, unsigned n) : o(nlopt_create(nlopt_algorithm(a), n)) {
-      if (!o) throw std::bad_alloc();
+
+    // nlopt_mfunc wrapper that catches exceptions
+    static void mymfunc(unsigned m, double *result,
+                       unsigned n, const double *x, double *grad, void *d_) {
+      myfunc_data *d = reinterpret_cast<myfunc_data*>(d_);
+      try {
+       d->mf(m, result, n, x, grad, d->f_data);
+       return;
+      }
+      catch (std::bad_alloc&)
+       { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
+      catch (std::invalid_argument&)
+       { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
+      catch (roundoff_limited&)
+       { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
+      catch (forced_stop&)
+       { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
+      catch (...)
+       { d->o->forced_stop_reason = NLOPT_FAILURE; }
+      d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
+      for (unsigned i = 0; i < m; ++i) result[i] = HUGE_VAL;
     }
-    opt(const nlopt_opt o0) : o(nlopt_copy(o0)) {
-      if (o0 && !o) throw std::bad_alloc();
+
+    std::vector<double> xtmp, gradtmp, gradtmp0; // scratch for myvfunc
+
+    // 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 = d->o->xtmp;
+       if (n) std::memcpy(&xv[0], x, n * sizeof(double));
+       double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data);
+       if (grad && n) {
+         std::vector<double> &gradv = d->o->gradtmp;
+         std::memcpy(grad, &gradv[0], n * sizeof(double));
+       }
+       return val;
+      }
+      catch (std::bad_alloc&)
+       { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; }
+      catch (std::invalid_argument&)
+       { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; }
+      catch (roundoff_limited&)
+       { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; }
+      catch (forced_stop&)
+       { d->o->forced_stop_reason = NLOPT_FORCED_STOP; }
+      catch (...)
+       { d->o->forced_stop_reason = NLOPT_FAILURE; }
+      d->o->force_stop(); // stop gracefully, opt::optimize will re-throw
+      return HUGE_VAL;
     }
+
+    void alloc_tmp() {
+      if (xtmp.size() != nlopt_get_dimension(o)) {
+       xtmp = std::vector<double>(nlopt_get_dimension(o));
+       gradtmp = std::vector<double>(nlopt_get_dimension(o));
+      }
+    }
+
+    result last_result;
+    double last_optf;
+    nlopt_result forced_stop_reason;
+
+  public:
+    // Constructors etc.
+    opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0), 
+           last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
+           forced_stop_reason(NLOPT_FORCED_STOP) {}
     ~opt() { nlopt_destroy(o); }
-    opt(const opt& from) : o(nlopt_copy(from.o)) {
-      if (from.o && !o) throw std::bad_alloc();
+    opt(algorithm a, unsigned n) : 
+      o(nlopt_create(nlopt_algorithm(a), n)), 
+      xtmp(0), gradtmp(0), gradtmp0(0),
+      last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
+      forced_stop_reason(NLOPT_FORCED_STOP) {
+      if (!o) throw std::bad_alloc();
+      nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
+    }
+    opt(const opt& f) : o(nlopt_copy(f.o)), 
+                       xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
+                       last_result(f.last_result), last_optf(f.last_optf),
+                       forced_stop_reason(f.forced_stop_reason) {
+      if (f.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();
+      xtmp = f.xtmp; gradtmp = f.gradtmp;
+      last_result = f.last_result; last_optf = f.last_optf;
+      forced_stop_reason = f.forced_stop_reason;
       return *this;
     }
 
     // Do the optimization:
-    result optimize(double *x, double &opt_f) {
-      nlopt_result ret = nlopt_optimize(o, x, &opt_f);
+    result optimize(std::vector<double> &x, double &opt_f) {
+      if (o && nlopt_get_dimension(o) != x.size())
+        throw std::invalid_argument("dimension mismatch");
+      forced_stop_reason = NLOPT_FORCED_STOP;
+      nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f);
+      last_result = result(ret);
+      last_optf = opt_f;
+      if (ret == NLOPT_FORCED_STOP)
+       mythrow(forced_stop_reason);
       mythrow(ret);
-      return result(ret);
+      return last_result;
     }
-    result optimize(std::vector<double> &x, double &opt_f) {
-      return optimize(x.empty() ? NULL : &x[0], opt_f);
+
+    // variant mainly useful for SWIG wrappers:
+    std::vector<double> optimize(const std::vector<double> &x0) {
+      std::vector<double> x(x0);
+      last_result = optimize(x, last_optf);
+      return x;
     }
+    result last_optimize_result() const { return last_result; }
+    double last_optimum_value() const { return last_optf; }
 
     // 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, void *f_data) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = 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, void *f_data) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o
+      alloc_tmp();
     }
-    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 = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = 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, void *f_data) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o
+      alloc_tmp();
+    }
+
+    // for internal use in SWIG wrappers -- variant that
+    // takes ownership of f_data, with munging for destroy/copy
+    void set_min_objective(func f, void *f_data,
+                          nlopt_munge md, nlopt_munge mc) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o
+    }
+    void set_max_objective(func f, void *f_data,
+                          nlopt_munge md, nlopt_munge mc) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o
     }
 
     // Nonlinear constraints:
 
-    void remove_inequality_constraints(void) {
+    void remove_inequality_constraints() {
       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 = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = 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, void *f_data, double tol=0) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
+      alloc_tmp();
+    }
+    void add_inequality_mconstraint(mfunc mf, void *f_data, 
+                                   const std::vector<double> &tol) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d, 
+                                              tol.empty() ? NULL : &tol[0]));
     }
 
-    void remove_equality_constraints(void) {
+    void remove_equality_constraints() {
       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 = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
+    }
+    void add_equality_constraint(vfunc vf, void *f_data, double tol=0) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
+      alloc_tmp();
+    }
+    void add_equality_mconstraint(mfunc mf, void *f_data, 
+                                 const std::vector<double> &tol) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
+      d->munge_destroy = d->munge_copy = NULL;
+      mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d, 
+                                            tol.empty() ? NULL : &tol[0]));
+    }
+
+    // For internal use in SWIG wrappers (see also above)
+    void add_inequality_constraint(func f, void *f_data, 
+                                  nlopt_munge md, nlopt_munge mc,
+                                  double tol=0) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
+    }
+    void add_equality_constraint(func f, void *f_data, 
+                                nlopt_munge md, nlopt_munge mc,
+                                double tol=0) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
+    }
+    void add_inequality_mconstraint(mfunc mf, void *f_data, 
+                                   nlopt_munge md, nlopt_munge mc,
+                                   const std::vector<double> &tol) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d, 
+                                              tol.empty() ? NULL : &tol[0]));
     }
-    void add_equality_constraint(func *f, double tol=0) {
-      add_equality_constraint(myfunc, f, tol);
+    void add_equality_mconstraint(mfunc mf, void *f_data, 
+                                 nlopt_munge md, nlopt_munge mc,
+                                 const std::vector<double> &tol) {
+      myfunc_data *d = new myfunc_data;
+      if (!d) throw std::bad_alloc();
+      d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
+      d->munge_destroy = md; d->munge_copy = mc;
+      mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d, 
+                                            tol.empty() ? NULL : &tol[0]));
     }
 
 #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);                                                    \
+      mythrow(nlopt_set_##name##1(o, val));                            \
     }                                                                  \
     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]);                            \
+      mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0]));          \
     }                                                                  \
-    std::vector<double> get_##name(void) const {                       \
+    std::vector<double> get_##name() const {                   \
       if (!o) throw std::runtime_error("uninitialized nlopt::opt");    \
       std::vector<double> v(nlopt_get_dimension(o));                   \
       get_##name(v);                                                   \
@@ -191,7 +441,7 @@ 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]);                            \
+      mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0]));          \
     }
 
     NLOPT_GETSET_VEC(lower_bounds)
@@ -205,8 +455,7 @@ namespace nlopt {
       return nlopt_get_##name(o);                                      \
     }                                                                  \
     void set_##name(T name) {                                          \
-      nlopt_result ret = nlopt_set_##name(o, name);                    \
-      mythrow(ret);                                                    \
+      mythrow(nlopt_set_##name(o, name));                              \
     }
     NLOPT_GETSET(double, stopval)
     NLOPT_GETSET(double, ftol_rel)
@@ -216,38 +465,39 @@ namespace nlopt {
     NLOPT_GETSET(int, maxeval)
     NLOPT_GETSET(double, maxtime)
 
-    // algorithm-specific parameters:
+    NLOPT_GETSET(int, force_stop)
+    void force_stop() { set_force_stop(1); }
 
-    void set_local_optimizer(const nlopt_opt lo) {
-      nlopt_result ret = nlopt_set_local_optimizer(o, lo);
-      mythrow(ret);
+    const char *get_errmsg() const { 
+        if (!o) throw std::runtime_error("uninitialized nlopt::opt");
+        return nlopt_get_errmsg(o);
     }
+
+    // algorithm-specific parameters:
+
     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(unsigned, vector_storage)
     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 {
+    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);
@@ -260,4 +510,32 @@ namespace nlopt {
 
   //////////////////////////////////////////////////////////////////////
 
+  inline void srand(unsigned long seed) { nlopt_srand(seed); }
+  inline void srand_time() { nlopt_srand_time(); }
+  inline void version(int &major, int &minor, int &bugfix) {
+    nlopt_version(&major, &minor, &bugfix);
+  }
+  inline int version_major() {
+    int major, minor, bugfix;
+    nlopt_version(&major, &minor, &bugfix);
+    return major;
+  }
+  inline int version_minor() {
+    int major, minor, bugfix;
+    nlopt_version(&major, &minor, &bugfix);
+    return minor;
+  }
+  inline int version_bugfix() {
+    int major, minor, bugfix;
+    nlopt_version(&major, &minor, &bugfix);
+    return bugfix;
+  }
+  inline const char *algorithm_name(algorithm a) {
+    return nlopt_algorithm_name(nlopt_algorithm(a));
+  }
+
+  //////////////////////////////////////////////////////////////////////
+
 } // namespace nlopt
+
+#endif /* NLOPT_HPP */