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
%
% 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);
+
* 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>
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];
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;
}
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])
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;
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)
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;
#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)
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())
}
}
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);
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)
if (nargout > 2)
retval(2) = int(ret);
+ delete[] dc;
+
return retval;
}
--- /dev/null
+% 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").