chiark / gitweb /
added octave plug-in
authorstevenj <stevenj@alum.mit.edu>
Thu, 30 Aug 2007 21:09:14 +0000 (17:09 -0400)
committerstevenj <stevenj@alum.mit.edu>
Thu, 30 Aug 2007 21:09:14 +0000 (17:09 -0400)
darcs-hash:20070830210914-c8de0-2ff67f1fb7eb4ac60968712d7b4259742593c445.gz

14 files changed:
Makefile.am
configure.ac
octave/Makefile.am [new file with mode: 0644]
octave/NLOPT_GLOBAL_DIRECT.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_DIRECT_L.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_DIRECT_L_RANDOMIZED.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_ORIG_DIRECT.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_ORIG_DIRECT_L.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_STOGO.m [new file with mode: 0644]
octave/NLOPT_GLOBAL_STOGO_RANDOMIZED.m [new file with mode: 0644]
octave/NLOPT_LOCAL_LBFGS.m [new file with mode: 0644]
octave/NLOPT_LOCAL_SUBPLEX.m [new file with mode: 0644]
octave/nlopt_minimize.cc [new file with mode: 0644]
octave/nlopt_minimize.m [new file with mode: 0644]

index cb31dc30cb017995d6f4263c8f899174dc652ae4..7e8c7411267e607a7285d62910a456aa36edfb83 100644 (file)
@@ -3,7 +3,7 @@ lib_LTLIBRARIES = libnlopt.la
 
 ACLOCAL_AMFLAGS=-I ./m4
 
-SUBDIRS= util lbfgs subplex direct cdirect stogo api . test
+SUBDIRS= util lbfgs subplex direct cdirect stogo api octave . test
 EXTRA_DIST=COPYRIGHT autogen.sh nlopt.pc.in m4
 
 libnlopt_la_SOURCES = 
index 46ca6b6fc162cc8cab8638e6ef0cc7179ae3af5e..7503edae666fbaca6f0634fbd26d28bd4c9b1d83 100644 (file)
@@ -54,6 +54,44 @@ if test "$ok" = "yes"; then
 fi
 AC_MSG_RESULT(${ok})
 
+dnl -----------------------------------------------------------------------
+dnl Compiling Octave plug-in
+
+AC_ARG_VAR(OCT_INSTALL_DIR, [where to install GNU Octave .oct plug-ins])
+AC_ARG_VAR(M_INSTALL_DIR, [where to install GNU Octave .m plug-ins])
+AC_ARG_VAR(MKOCTFILE, [name of mkoctfile program to compile Octave plug-ins])
+
+AC_CHECK_PROGS(MKOCTFILE, mkoctfile, echo)
+if test "$MKOCTFILE" = "echo"; then
+       AC_MSG_WARN([can't find mkoctfile: won't be able to compile GNU Octave plugin])
+elif test x"$OCT_INSTALL_DIR" = "x"; then
+       # try to find installation directory
+       AC_CHECK_PROGS(OCTAVE, octave, echo)
+       AC_MSG_CHECKING(for Octave loadpath)
+       OCTAVE_LOADPATH=`echo "DEFAULT_LOADPATH" | $OCTAVE -q | cut -d'=' -f2`
+       AC_MSG_RESULT($OCTAVE_LOADPATH)
+       AC_MSG_CHECKING(where Octave plugins go)
+       OCT_INSTALL_DIR=`echo "$OCTAVE_LOADPATH" | tr ':' '\n' | grep "site/oct" | head -1`
+       if test -n "$OCT_INSTALL_DIR"; then
+               AC_MSG_RESULT($OCT_INSTALL_DIR)
+       else
+               AC_MSG_RESULT(unknown)
+               AC_MSG_WARN([can't find where to install GNU Octave plugins])
+       fi
+       AC_MSG_CHECKING(where Octave scripts go)
+       M_INSTALL_DIR=`echo "$OCTAVE_LOADPATH" | tr ':' '\n' | grep "site/m" | head -1`
+       if test -n "$M_INSTALL_DIR"; then
+               AC_MSG_RESULT($M_INSTALL_DIR)
+       else
+               AC_MSG_RESULT(unknown)
+               AC_MSG_WARN([can't find where to install GNU Octave scripts])
+       fi
+fi
+AM_CONDITIONAL(WITH_OCTAVE, test x"$OCT_INSTALL_DIR" != "x")
+AC_SUBST(OCT_INSTALL_DIR)
+AC_SUBST(M_INSTALL_DIR)
+AC_SUBST(MKOCTFILE)
+
 dnl -----------------------------------------------------------------------
 dnl Debugging
 
@@ -95,6 +133,7 @@ AC_CONFIG_FILES([
    nlopt.pc
    api/Makefile
    util/Makefile
+   octave/Makefile
    direct/Makefile
    cdirect/Makefile
    stogo/Makefile
diff --git a/octave/Makefile.am b/octave/Makefile.am
new file mode 100644 (file)
index 0000000..3528aa3
--- /dev/null
@@ -0,0 +1,27 @@
+AM_CPPFLAGS = -I$(top_srcdir)/api 
+
+MFILES = NLOPT_GLOBAL_DIRECT_L.m NLOPT_GLOBAL_DIRECT_L_RANDOMIZED.m    \
+NLOPT_GLOBAL_DIRECT.m NLOPT_GLOBAL_ORIG_DIRECT_L.m                     \
+NLOPT_GLOBAL_ORIG_DIRECT.m NLOPT_GLOBAL_STOGO.m                                \
+NLOPT_GLOBAL_STOGO_RANDOMIZED.m NLOPT_LOCAL_LBFGS.m                    \
+NLOPT_LOCAL_SUBPLEX.m nlopt_minimize.m
+
+octdir = $(OCT_INSTALL_DIR)
+mdir = $(M_INSTALL_DIR)
+
+if WITH_OCTAVE
+oct_DATA = nlopt_minimize.oct
+m_DATA = $(MFILES)
+endif
+
+nlopt_minimize.oct: nlopt_minimize.cc nlopt_minimize_usage.h
+       $(MKOCTFILE) $(DEFS) $(CPPFLAGS) $(srcdir)/nlopt_minimize.cc $(LDFLAGS) -L$(top_builddir)/.libs -lnlopt
+
+nlopt_minimize_usage.h: $(srcdir)/nlopt_minimize.m
+       echo "#define NLOPT_MINIMIZE_USAGE \\" > $@
+       sed 's/\"/\\"/g' $(srcdir)/nlopt_minimize.m | sed 's,^% ,\",;s,^%,\",;s,$$,\\n\" \\,' >> $@
+       echo "" >> $@
+
+EXTRA_DIST = nlopt_minimize.cc $(MFILES)
+
+CLEANFILES = nlopt_minimize.oct nlopt_minimize_usage.h
diff --git a/octave/NLOPT_GLOBAL_DIRECT.m b/octave/NLOPT_GLOBAL_DIRECT.m
new file mode 100644 (file)
index 0000000..c0623d3
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_DIRECT
+  a = 0;
diff --git a/octave/NLOPT_GLOBAL_DIRECT_L.m b/octave/NLOPT_GLOBAL_DIRECT_L.m
new file mode 100644 (file)
index 0000000..ab749d2
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_DIRECT_L
+  a = 1;
diff --git a/octave/NLOPT_GLOBAL_DIRECT_L_RANDOMIZED.m b/octave/NLOPT_GLOBAL_DIRECT_L_RANDOMIZED.m
new file mode 100644 (file)
index 0000000..6dc8d38
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_DIRECT_L_RANDOMIZED
+  a = 2;
diff --git a/octave/NLOPT_GLOBAL_ORIG_DIRECT.m b/octave/NLOPT_GLOBAL_ORIG_DIRECT.m
new file mode 100644 (file)
index 0000000..9b749a5
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_ORIG_DIRECT
+  a = 3;
diff --git a/octave/NLOPT_GLOBAL_ORIG_DIRECT_L.m b/octave/NLOPT_GLOBAL_ORIG_DIRECT_L.m
new file mode 100644 (file)
index 0000000..f133cf3
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_ORIG_DIRECT_L
+  a = 4;
diff --git a/octave/NLOPT_GLOBAL_STOGO.m b/octave/NLOPT_GLOBAL_STOGO.m
new file mode 100644 (file)
index 0000000..3929ff0
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_STOGO
+  a = 6;
diff --git a/octave/NLOPT_GLOBAL_STOGO_RANDOMIZED.m b/octave/NLOPT_GLOBAL_STOGO_RANDOMIZED.m
new file mode 100644 (file)
index 0000000..06e6be6
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_GLOBAL_STOGO_RANDOMIZED
+  a = 7;
diff --git a/octave/NLOPT_LOCAL_LBFGS.m b/octave/NLOPT_LOCAL_LBFGS.m
new file mode 100644 (file)
index 0000000..c50e72f
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_LOCAL_LBFGS
+  a = 8;
diff --git a/octave/NLOPT_LOCAL_SUBPLEX.m b/octave/NLOPT_LOCAL_SUBPLEX.m
new file mode 100644 (file)
index 0000000..95c2fbc
--- /dev/null
@@ -0,0 +1,2 @@
+function a = NLOPT_LOCAL_SUBPLEX
+  a = 5;
diff --git a/octave/nlopt_minimize.cc b/octave/nlopt_minimize.cc
new file mode 100644 (file)
index 0000000..cc6fd57
--- /dev/null
@@ -0,0 +1,139 @@
+#include <octave/oct.h>
+#include <octave/oct-map.h>
+#include <octave/ov.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "nlopt.h"
+#include "nlopt_minimize_usage.h"
+
+static double struct_val_default(Octave_map &m, const std::string& k,
+                                double dflt)
+{
+  if (m.contains(k)) {
+    if (m.contents(k).length() == 1 && (m.contents(k))(0).is_real_scalar())
+      return (m.contents(k))(0).double_value();
+  }
+  return dflt;
+}
+
+static Matrix struct_val_default(Octave_map &m, const std::string& k,
+                                Matrix &dflt)
+{
+  if (m.contains(k)) {
+    if ((m.contents(k)).length() == 1) {
+      if ((m.contents(k))(0).is_real_scalar())
+       return Matrix(1, dflt.length(), (m.contents(k))(0).double_value());
+      else if ((m.contents(k))(0).is_real_matrix())
+       return (m.contents(k))(0).matrix_value();
+    }
+  }
+  return dflt;
+}
+
+typedef struct {
+  octave_function *f;
+  Cell f_data;
+} user_function_data;
+
+static double user_function(int n, const double *x,
+                           double *gradient, /* NULL if not needed */
+                           void *data_)
+{
+  user_function_data *data = (user_function_data *) data_;
+  octave_value_list args(1 + data->f_data.length(), 0);
+  Matrix xm(1,n);
+  for (int i = 0; i < n; ++i)
+    xm(i) = x[i];
+  args(0) = xm;
+  for (int i = 0; i < data->f_data.length(); ++i)
+    args(1 + i) = data->f_data(i);
+  octave_value_list res = data->f->do_multi_index_op(gradient ? 2 : 1, args); 
+  if (res.length() < (gradient ? 2 : 1))
+    gripe_user_supplied_eval("nlopt_minimize");
+  else if (!res(0).is_real_scalar()
+          || (gradient && !res(1).is_real_matrix()
+              && !(n == 1 && res(1).is_real_scalar())))
+    gripe_user_returned_invalid("nlopt_minimize");
+  else {
+    if (gradient) {
+      if (n == 1 && res(1).is_real_scalar())
+       gradient[0] = res(1).double_value();
+      else {
+       Matrix grad = res(1).matrix_value();
+       for (int i = 0; i < n; ++i)
+         gradient[i] = grad(i);
+      }
+    }
+    return res(0).double_value();
+  }
+  return 0;
+}                               
+
+#define CHECK(cond, msg) if (!(cond)) { fprintf(stderr, msg "\n\n"); print_usage("nlopt_minimize"); return retval; }
+
+DEFUN_DLD(nlopt_minimize, args, nargout, NLOPT_MINIMIZE_USAGE)
+{
+  octave_value_list retval;
+  double A;
+
+  CHECK(args.length() == 7 && nargout <= 3, "wrong number of args");
+
+  CHECK(args(0).is_real_scalar(), "n must be real scalar");
+  nlopt_algorithm algorithm = nlopt_algorithm(args(0).int_value());
+
+  user_function_data d;
+  CHECK(args(1).is_function() || args(1).is_function_handle(), 
+       "f must be function");
+  d.f = args(1).function_value();
+  CHECK(args(2).is_cell(), "f_data must be cell array");
+  d.f_data = args(2).cell_value();
+
+  CHECK(args(3).is_real_matrix() || args(3).is_real_scalar(),
+       "lb must be real vector");
+  Matrix lb = args(3).is_real_scalar() ?
+    Matrix(1, 1, args(3).double_value()) : args(3).matrix_value();
+  int n = lb.length();
+  
+  CHECK(args(4).is_real_matrix() || args(4).is_real_scalar(),
+       "ub must be real vector");
+  Matrix ub = args(4).is_real_scalar() ?
+    Matrix(1, 1, args(4).double_value()) : args(4).matrix_value();
+  CHECK(n == ub.length(), "lb and ub must have same length");
+
+  CHECK(args(5).is_real_matrix() || args(5).is_real_scalar(),
+       "x must be real vector");
+  Matrix x = args(5).is_real_scalar() ?
+    Matrix(1, 1, args(5).double_value()) : args(5).matrix_value();
+  CHECK(n == x.length(), "x and lb/ub must have same length");
+
+  CHECK(args(6).is_map(), "stop must be structure");
+  Octave_map stop = args(6).map_value();
+  double fmin_max = struct_val_default(stop, "fmin_max", -HUGE_VAL);
+  double ftol_rel = struct_val_default(stop, "ftol_rel", 0);
+  double ftol_abs = struct_val_default(stop, "ftol_abs", 0);
+  double xtol_rel = struct_val_default(stop, "xtol_rel", 0);
+  Matrix zeros(1, n, 0.0);
+  Matrix xtol_abs = struct_val_default(stop, "xtol_abs", zeros);
+  CHECK(n == xtol_abs.length(), "stop.xtol_abs must have same length as x");
+  int maxeval = int(struct_val_default(stop, "maxeval", -1));
+  double maxtime = struct_val_default(stop, "maxtime", -1);
+  
+  double fmin = HUGE_VAL;
+  nlopt_result ret = nlopt_minimize(algorithm,
+                                   n,
+                                   user_function, &d,
+                                   lb.data(), ub.data(),
+                                   x.fortran_vec(), &fmin,
+                                   fmin_max, ftol_rel, ftol_abs,
+                                   xtol_rel, xtol_abs.data(),
+                                   maxeval, maxtime);
+                                   
+  retval(0) = x;
+  if (nargout > 1)
+    retval(1) = fmin;
+  if (nargout > 2)
+    retval(2) = int(ret);
+
+  return retval;
+}
diff --git a/octave/nlopt_minimize.m b/octave/nlopt_minimize.m
new file mode 100644 (file)
index 0000000..45283ed
--- /dev/null
@@ -0,0 +1,61 @@
+% Usage: [xopt, fmin, retcode] = nlopt_minimize(algorithm, f, f_data, lb, ub,
+%                                               xinit, stop)
+%
+% Minimizes a nonlinear multivariable function f(x, f_data{:}), where
+% x is a row vector, returning the optimal x found (xopt) along with
+% the minimum function value (fmin = f(xopt)) and a return code (retcode).
+% A variety of local and global optimization algorithms can be used,
+% as specified by the algorithm parameter described below.  lb and ub
+% are row vectors giving the upper and lower bounds on x, xinit is
+% a row vector giving the initial guess for x, and stop is a struct
+% containing termination conditions (see below).
+%
+% This function is a front-end for the external routine nlopt_minimize
+% in the free NLopt nonlinear-optimization library, which is a wrapper
+% around a number of free/open-source optimization subroutines.  More
+% details can be found on the NLopt web page (ab-initio.mit.edu/nlopt)
+% and also under 'man nlopt_minimize' on Unix.
+%
+% f should be a handle (@) to a function of the form:
+%
+%    [val, gradient] = f(x, ...)
+%
+% where x is a row vector, val is the function value f(x), and gradient
+% is a row vector giving the gradient of the function with respect to x.
+% The gradient is only used for gradient-based optimization algorithms;
+% some of the algorithms (below) are derivative-free and only require
+% f to return val (its value).  f can take additional arguments (...)
+% which are passed via the argument f_data: f_data is a cell array
+% of the additional arguments to pass to f.  (Recall that cell arrays
+% are specified by curly brackets { ... }.  For example, pass f_data={}
+% for functions that require no additional arguments.)
+%
+% stop describes the termination criteria, and is a struct with a
+% number of optional fields:
+%     stop.ftol_rel = fractional tolerance on function value
+%     stop.ftol_abs = absolute tolerance on function value
+%     stop.xtol_rel = fractional tolerance on x
+%     stop.xtol_abs = row vector of absolute tolerances on x components
+%     stop.fmin_max = stop when f < fmin_max is found
+%     stop.maxeval = maximum number of function evaluations
+%     stop.maxtime = maximum run time in seconds
+% Minimization stops when any one of these conditions is met; any
+% condition that is omitted from stop will be ignored.  WARNING:
+% not all algorithms interpret the stopping criteria in exactly the
+% same way, and in any case ftol/xtol specify only a crude estimate
+% for the accuracy of the minimum function value/x.
+%
+% The algorithm should be one of the following constants (name and
+% interpretation are the same as for the C function):
+%
+% Derivative-free algorithms:
+%     NLOPT_GLOBAL_DIRECT, NLOPT_GLOBAL_DIRECT_L,
+%     NLOPT_GLOBAL_DIRECT_L_RANDOMIZED,
+%     NLOPT_GLOBAL_ORIG_DIRECT, NLOPT_GLOBAL_ORIG_DIRECT_L,
+%     NLOPT_LOCAL_SUBPLEX
+%
+% Gradient-based algorithms:
+%    NLOPT_GLOBAL_STOGO, NLOPT_GLOBAL_STOGO_RANDOMIZED, NLOPT_LOCAL_LBFGS
+%
+% For more information on individual functions, see their individual
+% help pages (e.g. "help NLOPT_LOCAL_SUBPLEX").