chiark / gitweb /
first stab at nlopt_minimize_constrained Matlab/Octave wrappers
authorstevenj <stevenj@alum.mit.edu>
Tue, 11 Nov 2008 02:41:21 +0000 (21:41 -0500)
committerstevenj <stevenj@alum.mit.edu>
Tue, 11 Nov 2008 02:41:21 +0000 (21:41 -0500)
darcs-hash:20081111024121-c8de0-db5892685407b546fc41139d3e2034cd39b898c9.gz

octave/Makefile.am
octave/nlopt_minimize.m
octave/nlopt_minimize_constrained-mex.c [moved from octave/nlopt_minimize-mex.c with 61% similarity]
octave/nlopt_minimize_constrained-oct.cc [moved from octave/nlopt_minimize-oct.cc with 70% similarity]
octave/nlopt_minimize_constrained.m [new file with mode: 0644]

index a3b76e63f8a2068b6073d0963e871d9ad1c7c00f..0639567b8c51718dded21251377eebb90cdf5bab 100644 (file)
@@ -6,29 +6,29 @@ MFILES = NLOPT_GN_DIRECT.m NLOPT_GN_DIRECT_L.m NLOPT_GN_DIRECT_L_RAND.m NLOPT_GN
 octdir = $(OCT_INSTALL_DIR)
 mdir = $(M_INSTALL_DIR)
 if WITH_OCTAVE
-oct_DATA = nlopt_minimize.oct
-m_DATA = $(MFILES) nlopt_minimize.m
+oct_DATA = nlopt_minimize_constrained.oct
+m_DATA = $(MFILES) nlopt_minimize.m nlopt_minimize_constrained.m
 endif
 
-nlopt_minimize.oct: nlopt_minimize-oct.cc nlopt_minimize_usage.h
-       $(MKOCTFILE) -o $@ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(srcdir)/nlopt_minimize-oct.cc $(LDFLAGS) -L$(top_builddir)/.libs -lnlopt@NLOPT_SUFFIX@
+nlopt_minimize_constrained.oct: nlopt_minimize_constrained-oct.cc nlopt_minimize_constrained_usage.h
+       $(MKOCTFILE) -o $@ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(srcdir)/nlopt_minimize_constrained-oct.cc $(LDFLAGS) -L$(top_builddir)/.libs -lnlopt@NLOPT_SUFFIX@
 
-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\" \\,' >> $@
+nlopt_minimize_constrained_usage.h: $(srcdir)/nlopt_minimize_constrained.m
+       echo "#define NLOPT_MINIMIZE_CONSTRAINED_USAGE \\" > $@
+       sed 's/\"/\\"/g' $(srcdir)/nlopt_minimize_constrained.m | sed 's,^% ,\",;s,^%,\",;s,$$,\\n\" \\,' >> $@
        echo "" >> $@
 
 #######################################################################
 mexdir = $(MEX_INSTALL_DIR)
 if WITH_MATLAB
-mex_DATA = nlopt_minimize.$(MEXSUFF) $(MFILES) nlopt_minimize.m
+mex_DATA = nlopt_minimize_constrained.$(MEXSUFF) $(MFILES) nlopt_minimize.m nlopt_minimize_constrained.m
 endif
 
-nlopt_minimize.$(MEXSUFF): nlopt_minimize-mex.c
-       $(MEX) -output nlopt_minimize -O $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(srcdir)/nlopt_minimize-mex.c $(LDFLAGS) -L$(top_builddir)/.libs -lnlopt@NLOPT_SUFFIX@
+nlopt_minimize_constrained.$(MEXSUFF): nlopt_minimize_constrained-mex.c
+       $(MEX) -output nlopt_minimize_constrained -O $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(srcdir)/nlopt_minimize_constrained-mex.c $(LDFLAGS) -L$(top_builddir)/.libs -lnlopt@NLOPT_SUFFIX@
 
 #######################################################################
 
-EXTRA_DIST = nlopt_minimize-oct.cc nlopt_minimize-mex.c $(MFILES) nlopt_minimize.m
+EXTRA_DIST = nlopt_minimize_constrained-oct.cc nlopt_minimize_constrained-mex.c $(MFILES) nlopt_minimize.m nlopt_minimize_constrained.m
 
-CLEANFILES = nlopt_minimize.oct nlopt_minimize_usage.h nlopt_minimize.$(MEXSUFF) nlopt_minimize-oct.o
+CLEANFILES = nlopt_minimize_constrained.oct nlopt_minimize_constrained_usage.h nlopt_minimize_constrained.$(MEXSUFF) nlopt_minimize_constrained-oct.o
index 3c95e0c65dbc86b277493da43e715c10182360de..5dc64e1599ad6bb0eadd2a04f2c833d5bd932aef 100644 (file)
@@ -64,3 +64,7 @@
 %
 % For more information on individual functions, see their individual
 % help pages (e.g. "help NLOPT_LN_SUBPLEX").
+[xopt, fmin, retcode] = nlopt_minimize(algorithm, f, f_data, lb, ub, xinit, stop)
+
+  [xopt, fmin, retcode] = nlopt_minimize_constrained(algorithm, f, f_data, {}, {}, lb, ub, xinit, stop);
+
similarity index 61%
rename from octave/nlopt_minimize-mex.c
rename to octave/nlopt_minimize_constrained-mex.c
index f36b0c3d60bf23ef61ba7e60b257d897be3ea5c6..92620f387b31617879d66625b9344b77f073d8fd 100644 (file)
@@ -20,7 +20,7 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  */
 
-/* Matlab MEX interface to NLopt, and in particular to nlopt_minimize */
+/* Matlab MEX interface to NLopt, and in particular to nlopt_minimize_constrained */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -46,8 +46,8 @@ static double struct_val_default(const mxArray *s, const char *name, double dflt
      return dflt;
 }
 
-#define FLEN 1024 /* max length of user function name */
-#define MAXRHS 1024 /* max nrhs for user function */
+#define FLEN 128 /* max length of user function name */
+#define MAXRHS 128 /* max nrhs for user function */
 typedef struct {
      char f[FLEN];
      mxArray *plhs[2];
@@ -84,7 +84,7 @@ static double user_function(int n, const double *x,
      mxDestroyArray(d->plhs[1]);
   }
   d->neval++;
-  if (d->verbose) mexPrintf("nlopt_minimize eval #%d: %g\n", d->neval, f);
+  if (d->verbose) mexPrintf("nlopt_minimize_constrained eval #%d: %g\n", d->neval, f);
   return f;
 }                               
 
@@ -92,16 +92,16 @@ void mexFunction(int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
 {
      nlopt_algorithm algorithm;
-     int n, i;
+     int n, m, i, j;
      double *lb, *ub, *x, *x0;
      double minf_max, ftol_rel, ftol_abs, xtol_rel, *xtol_abs, maxtime;
      int maxeval;
      nlopt_result ret;
      mxArray *x_mx;
      double minf = HUGE_VAL;
-     user_function_data d;
+     user_function_data d, *dc;
 
-     CHECK(nrhs == 7 && nlhs <= 3, "wrong number of arguments");
+     CHECK(nrhs == 9 && nlhs <= 3, "wrong number of arguments");
 
      /* algorithm = prhs[0] */
      CHECK(mxIsNumeric(prhs[0]) && !mxIsComplex(prhs[0]) 
@@ -121,7 +121,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
          d.xrhs = 0;
      }
      else {
-         d.prhs[0] = prhs[1];
+         d.prhs[0] = (mxArray *) prhs[1];
          strcpy(d.f, "feval");
          d.nrhs = 2;
          d.xrhs = 1;
@@ -135,39 +135,80 @@ void mexFunction(int nlhs, mxArray *plhs[],
      for (i = 0; i < d.nrhs - (1+d.xrhs); ++i)
          d.prhs[(1+d.xrhs)+i] = mxGetCell(prhs[2], i);
 
-     /* lb = prhs[3] */
-     CHECK(mxIsDouble(prhs[3]) && !mxIsComplex(prhs[3])
-          && (mxGetM(prhs[3]) == 1 || mxGetN(prhs[3]) == 1),
+     /* m = length(fc = prhs[3]) = length(fc_data = prhs[4])  */
+     CHECK(mxIsCell(prhs[3]), "fc must be a Cell array");
+     CHECK(mxIsCell(prhs[4]), "fc_data must be a Cell array");
+     m = mxGetM(prhs[3]) * mxGetN(prhs[3]);
+     CHECK(m == mxGetM(prhs[4]) * mxGetN(prhs[4]), "fc and fc_data must have the same length");
+     dc = (user_function_data *) malloc(sizeof(user_function_data) * m);
+
+     for (j = 0; j < m; ++j) {
+         mxArray *fc, *fc_data;
+
+         /* function fc = phrs[3] */
+         fc = mxGetCell(prhs[3], j);
+         CHECK(mxIsChar(fc) || mxIsFunctionHandle(fc),
+               "fc must be Cell array of function handles or function names");
+         if (mxIsChar(fc)) {
+              CHECK(mxGetString(fc, dc[j].f, FLEN) == 0,
+                    "error reading function name string (too long?)");
+              dc[j].nrhs = 1;
+              dc[j].xrhs = 0;
+         }
+         else {
+              dc[j].prhs[0] = fc;
+              strcpy(dc[j].f, "feval");
+              dc[j].nrhs = 2;
+              dc[j].xrhs = 1;
+         }
+         
+         /* Cell fc_data = prhs[4] */
+         fc_data = mxGetCell(prhs[4], j);
+         CHECK(mxIsCell(fc_data), "fc_data must be a Cell array of Cell arrays");
+         CHECK(mxGetM(fc_data) * mxGetN(fc_data) + 1 <= MAXRHS,
+               "user function cannot have more than " STRIZE(MAXRHS) " arguments");
+         dc[j].nrhs += mxGetM(fc_data) * mxGetN(fc_data);
+         for (i = 0; i < dc[j].nrhs - (1+dc[j].xrhs); ++i)
+              dc[j].prhs[(1+dc[j].xrhs)+i] = mxGetCell(fc_data, i);
+     }
+
+     /* lb = prhs[5] */
+     CHECK(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5])
+          && (mxGetM(prhs[5]) == 1 || mxGetN(prhs[5]) == 1),
           "lb must be real row or column vector");
-     lb = mxGetPr(prhs[3]);
-     n = mxGetM(prhs[3]) * mxGetN(prhs[3]);
+     lb = mxGetPr(prhs[5]);
+     n = mxGetM(prhs[5]) * mxGetN(prhs[5]);
 
-     /* ub = prhs[4] */
-     CHECK(mxIsDouble(prhs[4]) && !mxIsComplex(prhs[4])
-          && (mxGetM(prhs[4]) == 1 || mxGetN(prhs[4]) == 1)
-          && mxGetM(prhs[4]) * mxGetN(prhs[4]) == n,
+     /* ub = prhs[6] */
+     CHECK(mxIsDouble(prhs[6]) && !mxIsComplex(prhs[6])
+          && (mxGetM(prhs[6]) == 1 || mxGetN(prhs[6]) == 1)
+          && mxGetM(prhs[6]) * mxGetN(prhs[6]) == n,
           "ub must be real row or column vector of same length as lb");
-     ub = mxGetPr(prhs[4]);
+     ub = mxGetPr(prhs[6]);
 
-     /* x0 = prhs[5] */
-     CHECK(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5])
-          && (mxGetM(prhs[5]) == 1 || mxGetN(prhs[5]) == 1)
-          && mxGetM(prhs[5]) * mxGetN(prhs[5]) == n,
+     /* x0 = prhs[7] */
+     CHECK(mxIsDouble(prhs[7]) && !mxIsComplex(prhs[7])
+          && (mxGetM(prhs[7]) == 1 || mxGetN(prhs[7]) == 1)
+          && mxGetM(prhs[7]) * mxGetN(prhs[7]) == n,
           "x must be real row or column vector of same length as lb");
-     x0 = mxGetPr(prhs[5]);
-
-     /* stopping criteria = prhs[6] */
-     CHECK(mxIsStruct(prhs[6]), "stopping criteria must be a struct");
-     minf_max = struct_val_default(prhs[6], "minf_max", -HUGE_VAL);
-     ftol_rel = struct_val_default(prhs[6], "ftol_rel", 0);
-     ftol_abs = struct_val_default(prhs[6], "ftol_abs", 0);
-     xtol_rel = struct_val_default(prhs[6], "xtol_rel", 0);
-     maxeval = (int) (struct_val_default(prhs[6], "maxeval", -1) + 0.5);
-     maxtime = struct_val_default(prhs[6], "maxtime", -1);
-     d.verbose = (int) struct_val_default(prhs[6], "verbose", 0);
+     x0 = mxGetPr(prhs[7]);
+
+     /* stopping criteria = prhs[8] */
+     CHECK(mxIsStruct(prhs[8]), "stopping criteria must be a struct");
+     minf_max = struct_val_default(prhs[8], "minf_max", -HUGE_VAL);
+     ftol_rel = struct_val_default(prhs[8], "ftol_rel", 0);
+     ftol_abs = struct_val_default(prhs[8], "ftol_abs", 0);
+     xtol_rel = struct_val_default(prhs[8], "xtol_rel", 0);
+     maxeval = (int) (struct_val_default(prhs[8], "maxeval", -1) + 0.5);
+     maxtime = struct_val_default(prhs[8], "maxtime", -1);
+     d.verbose = (int) struct_val_default(prhs[8], "verbose", 0);
      d.neval = 0;
+     for (i = 0; i < m; ++i) {
+         dc[i].verbose = d.verbose > 1;
+         dc[i].neval = 0;
+     }
      {
-         mxArray *val = mxGetField(prhs[6], 0, "xtol_abs");
+         mxArray *val = mxGetField(prhs[8], 0, "xtol_abs");
          if (val) {
               CHECK(mxIsNumeric(val) && !mxIsComplex(val) 
                     && (mxGetM(val) == 1 || mxGetN(val) == 1)
@@ -185,23 +226,26 @@ void mexFunction(int nlhs, mxArray *plhs[],
      memcpy(x, x0, sizeof(double) * n);
 
      d.prhs[d.xrhs] = mxCreateDoubleMatrix(1, n, mxREAL);
+     for (i = 0; i < m;++i)
+         dc[i].prhs[dc[i].xrhs] = d.prhs[d.xrhs];
      
-     ret = nlopt_minimize(algorithm,
-                         n,
-                         user_function, &d,
-                         lb, ub, x, &minf,
-                         minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs,
-                         maxeval, maxtime);
+     ret = nlopt_minimize_constrained(algorithm,
+                                     n,
+                                     user_function, &d,
+                                     m, user_function, dc,
+                                     sizeof(user_function_data),
+                                     lb, ub, x, &minf, minf_max, 
+                                     ftol_rel, ftol_abs, xtol_rel, xtol_abs,
+                                     maxeval, maxtime);
 
      mxDestroyArray(d.prhs[d.xrhs]);
+     free(dc);
 
      plhs[0] = x_mx;
      if (nlhs > 1) {
          plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL);
          *(mxGetPr(plhs[1])) = minf;
      }
-     else
-         mxDestroyArray(d.plhs[0]);
      if (nlhs > 2) {
          plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL);
          *(mxGetPr(plhs[2])) = (int) ret;
similarity index 70%
rename from octave/nlopt_minimize-oct.cc
rename to octave/nlopt_minimize_constrained-oct.cc
index 953f9584f1da045962b5375ba0e5d7d253de403f..ba75c7a407cc2f1486104f6de127dbd193cf0170 100644 (file)
@@ -27,7 +27,7 @@
 #include <stdio.h>
 
 #include "nlopt.h"
-#include "nlopt_minimize_usage.h"
+#include "nlopt_minimize_constrained_usage.h"
 
 static double struct_val_default(Octave_map &m, const std::string& k,
                                 double dflt)
@@ -73,11 +73,11 @@ static double user_function(int n, const double *x,
     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");
+    gripe_user_supplied_eval("nlopt_minimize_constrained");
   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");
+    gripe_user_returned_invalid("nlopt_minimize_constrained");
   else {
     if (gradient) {
       if (n == 1 && res(1).is_real_scalar())
@@ -89,52 +89,69 @@ static double user_function(int n, const double *x,
       }
     }
     data->neval++;
-    if (data->verbose) printf("nlopt_minimize eval #%d: %g\n", 
+    if (data->verbose) printf("nlopt_minimize_constrained eval #%d: %g\n", 
                              data->neval, res(0).double_value());
     return res(0).double_value();
   }
   return 0;
 }                               
 
-#define CHECK(cond, msg) if (!(cond)) { fprintf(stderr, msg "\n\n"); print_usage("nlopt_minimize"); return retval; }
+#define CHECK(cond, msg) if (!(cond)) { fprintf(stderr, msg "\n\n"); print_usage("nlopt_minimize_constrained"); return retval; }
 
-DEFUN_DLD(nlopt_minimize, args, nargout, NLOPT_MINIMIZE_USAGE)
+DEFUN_DLD(nlopt_minimize_constrained, args, nargout, NLOPT_MINIMIZE_CONSTRAINED_USAGE)
 {
   octave_value_list retval;
   double A;
 
-  CHECK(args.length() == 7 && nargout <= 3, "wrong number of args");
+  CHECK(args.length() == 9 && 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");
+       "f must be a function handle");
   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(),
+  CHECK(args(3).is_cell(), "fc must be cell array");
+  CHECK(args(4).is_cell(), "fc_data must be cell array");
+  int m = args(3).length();
+  CHECK(m == args(4).length(), "fc and fc_data must have the same length");
+  user_function_data *dc = new user_function_data[m];
+  {
+    Cell fc = args(3).cell_value();
+    Cell fc_data = args(4).cell_value();
+    for (int i; i < m; ++i) {
+      CHECK(fc(i).is_function() || fc(i).is_function_handle(),
+           "fc must be a cell array of function handles");
+      dc[i].f = fc(i).function_value();
+      CHECK(fc_data(i).is_cell(), "fc_data must be cell array of cell arrays");
+      dc[i].f_data = fc_data(i).cell_value();
+    }
+  }
+
+  CHECK(args(5).is_real_matrix() || args(5).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();
+  Matrix lb = args(5).is_real_scalar() ?
+    Matrix(1, 1, args(5).double_value()) : args(5).matrix_value();
   int n = lb.length();
   
-  CHECK(args(4).is_real_matrix() || args(4).is_real_scalar(),
+  CHECK(args(6).is_real_matrix() || args(6).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();
+  Matrix ub = args(6).is_real_scalar() ?
+    Matrix(1, 1, args(6).double_value()) : args(6).matrix_value();
   CHECK(n == ub.length(), "lb and ub must have same length");
 
-  CHECK(args(5).is_real_matrix() || args(5).is_real_scalar(),
+  CHECK(args(7).is_real_matrix() || args(7).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();
+  Matrix x = args(7).is_real_scalar() ?
+    Matrix(1, 1, args(7).double_value()) : args(7).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();
+  CHECK(args(8).is_map(), "stop must be structure");
+  Octave_map stop = args(8).map_value();
   double minf_max = struct_val_default(stop, "minf_max", -HUGE_VAL);
   double ftol_rel = struct_val_default(stop, "ftol_rel", 0);
   double ftol_abs = struct_val_default(stop, "ftol_abs", 0);
@@ -146,14 +163,15 @@ DEFUN_DLD(nlopt_minimize, args, nargout, NLOPT_MINIMIZE_USAGE)
   double maxtime = struct_val_default(stop, "maxtime", -1);
   
   double minf = HUGE_VAL;
-  nlopt_result ret = nlopt_minimize(algorithm,
-                                   n,
-                                   user_function, &d,
-                                   lb.data(), ub.data(),
-                                   x.fortran_vec(), &minf,
-                                   minf_max, ftol_rel, ftol_abs,
-                                   xtol_rel, xtol_abs.data(),
-                                   maxeval, maxtime);
+  nlopt_result ret = nlopt_minimize_constrained(algorithm,
+                                               n, user_function, &d,
+                                               m, user_function, dc, 
+                                               sizeof(user_function_data),
+                                               lb.data(), ub.data(),
+                                               x.fortran_vec(), &minf,
+                                               minf_max, ftol_rel, ftol_abs,
+                                               xtol_rel, xtol_abs.data(),
+                                               maxeval, maxtime);
                                    
   retval(0) = x;
   if (nargout > 1)
@@ -161,5 +179,7 @@ DEFUN_DLD(nlopt_minimize, args, nargout, NLOPT_MINIMIZE_USAGE)
   if (nargout > 2)
     retval(2) = int(ret);
 
+  delete[] dc;
+
   return retval;
 }
diff --git a/octave/nlopt_minimize_constrained.m b/octave/nlopt_minimize_constrained.m
new file mode 100644 (file)
index 0000000..271b35d
--- /dev/null
@@ -0,0 +1,87 @@
+% Usage: [xopt, fmin, retcode] = nlopt_minimize_constrained
+%                                          (algorithm, f, f_data,
+%                                           fc, fc_data, lb, ub,
+%                                           xinit, stop)
+%
+% Minimizes a nonlinear multivariable function f(x, f_data{:}), subject
+% to nonlinear constraints described by fc and fc_data (see below), 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_constrained 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_constrained' 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.)
+%
+% A few of the algorithms (below) support nonlinear constraints,
+% in particular NLOPT_LD_MMA and NLOPT_LN_COBYLA.  These (if any)
+% are specified by fc and fc_data.  fc is a cell array of
+% function handles, and fc_data is a cell array of cell arrays of the
+% corresponding arguments.  Both must have the same length m, the
+% number of nonlinear constraints.  That is, fc{i} is a handle
+% to a function of the form:
+%
+%   [val, gradient] = fc(x, ...)
+%
+% (where the gradient is only used for gradient-based algorithms),
+% and the ... arguments are given by fc_data{i}{:}.
+%
+% If you have no nonlinear constraints, i.e. fc = fc_data = {}, then
+% it is equivalent to calling the the nlopt_minimize() function, 
+% which omits the fc and fc_data 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
+%     stop.verbose = > 0 indicates verbose output
+% 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).  Names with
+% _G*_ are global optimization, and names with _L*_ are local
+% optimization.  Names with _*N_ are derivative-free, while names
+% with _*D_ are gradient-based algorithms.  Algorithms:
+%
+% NLOPT_GD_MLSL_LDS, NLOPT_GD_MLSL, NLOPT_GD_STOGO, NLOPT_GD_STOGO_RAND,
+% NLOPT_GN_CRS2_LM, NLOPT_GN_DIRECT_L, NLOPT_GN_DIRECT_L_NOSCAL,
+% NLOPT_GN_DIRECT_L_RAND, NLOPT_GN_DIRECT_L_RAND_NOSCAL, NLOPT_GN_DIRECT,
+% NLOPT_GN_DIRECT_NOSCAL, NLOPT_GN_MLSL_LDS, NLOPT_GN_MLSL,
+% NLOPT_GN_ORIG_DIRECT_L, NLOPT_GN_ORIG_DIRECT, NLOPT_LD_LBFGS, 
+% NLOPT_LD_MMA, NLOPT_LD_TNEWTON, NLOPT_LD_TNEWTON_PRECOND,
+% NLOPT_LD_TNEWTON_PRECOND_RESTART, NLOPT_LD_TNEWTON_RESTART,
+% NLOPT_LD_VAR1, NLOPT_LD_VAR2, NLOPT_LN_COBYLA, NLOPT_LN_NELDERMEAD,
+% NLOPT_LN_NEWUOA_BOUND, NLOPT_LN_NEWUOA, NLOPT_LN_PRAXIS, NLOPT_LN_SBPLX
+%
+% For more information on individual functions, see their individual
+% help pages (e.g. "help NLOPT_LN_SUBPLEX").