NLPS_MASTER Nonlinear programming (NLP) Solver wrapper function. [X, F, EXITFLAG, OUTPUT, LAMBDA] = ... NLPS_MASTER(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT) [X, F, EXITFLAG, OUTPUT, LAMBDA] = NLPS_MASTER(PROBLEM) A common wrapper function for various NLP solvers. Solves the following NLP (nonlinear programming) problem: Minimize a function F(X) beginning from a starting point X0, subject to optional linear and nonlinear constraints and variable bounds. min F(X) X subject to G(X) = 0 (nonlinear equalities) H(X) <= 0 (nonlinear inequalities) L <= A*X <= U (linear constraints) XMIN <= X <= XMAX (variable bounds) Inputs (all optional except F_FCN and X0): F_FCN : handle to function that evaluates the objective function, its gradients and Hessian for a given value of X. If there are nonlinear constraints, the Hessian information is provided by the HESS_FCN function passed in the 9th argument and is not required here. Calling syntax for this function: [F, DF, D2F] = F_FCN(X) X0 : starting value of optimization vector X A, L, U : define the optional linear constraints. Default values for the elements of L and U are -Inf and Inf, respectively. XMIN, XMAX : optional lower and upper bounds on the X variables, defaults are -Inf and Inf, respectively. GH_FCN : handle to function that evaluates the optional nonlinear constraints and their gradients for a given value of X. Calling syntax for this function is: [H, G, DH, DG] = GH_FCN(X) where the columns of DH and DG are the gradients of the corresponding elements of H and G, i.e. DH and DG are transposes of the Jacobians of H and G, respectively. HESS_FCN : handle to function that computes the Hessian of the Lagrangian for given values of X, lambda and mu, where lambda and mu are the multipliers on the equality and inequality constraints, g and h, respectively. The calling syntax for this function is: LXX = HESS_FCN(X, LAM) where lambda = LAM.eqnonlin and mu = LAM.ineqnonlin. OPT : optional options structure with the following fields, all of which are also optional (default values shown in parentheses) alg ('DEFAULT') : determines which solver to use 'DEFAULT' : automatic, current default is MIPS 'MIPS' : MIPS, MATPOWER Interior Point Solver pure MATLAB implementation of a primal-dual interior point method, if mips_opt.step_control = 1 it uses MIPS-sc, a step controlled variant of MIPS 'FMINCON' : FMINCON, MATLAB Optimization Toolbox 'IPOPT' : IPOPT, requires MEX interface to IPOPT solver https://github.com/coin-or/Ipopt 'KNITRO' : Artelys Knitro, requires Artelys Knitro solver https://www.artelys.com/solvers/knitro/ verbose (0) - controls level of progress output displayed 0 = no progress output 1 = some progress output 2 = verbose progress output mips_opt - options struct for MIPS fmincon_opt - options struct for FMINCON ipopt_opt - options struct for IPOPT knitro_opt - options struct for Artelys Knitro PROBLEM : The inputs can alternatively be supplied in a single PROBLEM struct with fields corresponding to the input arguments described above: f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt Outputs: X : solution vector F : final objective function value EXITFLAG : exit flag 1 = converged 0 or negative values = solver specific failure codes OUTPUT : output struct with the following fields: alg - algorithm code of solver used (others) - algorithm specific fields LAMBDA : struct containing the Langrange and Kuhn-Tucker multipliers on the constraints, with fields: eqnonlin - nonlinear equality constraints ineqnonlin - nonlinear inequality constraints mu_l - lower (left-hand) limit on linear constraints mu_u - upper (right-hand) limit on linear constraints lower - lower bound on optimization variables upper - upper bound on optimization variables Note the calling syntax is almost identical to that of FMINCON from MathWorks' Optimization Toolbox. The main difference is that the linear constraints are specified with A, L, U instead of A, B, Aeq, Beq. The functions for evaluating the objective function, constraints and Hessian are identical. Calling syntax options: [x, f, exitflag, output, lambda] = ... nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); x = nlps_master(f_fcn, x0); x = nlps_master(f_fcn, x0, A, l); x = nlps_master(f_fcn, x0, A, l, u); x = nlps_master(f_fcn, x0, A, l, u, xmin); x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax); x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn); x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn); x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); x = nlps_master(problem); where problem is a struct with fields: f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt all fields except 'f_fcn' and 'x0' are optional x = nlps_master(...); [x, f] = nlps_master(...); [x, f, exitflag] = nlps_master(...); [x, f, exitflag, output] = nlps_master(...); [x, f, exitflag, output, lambda] = nlps_master(...); Example: (problem from https://en.wikipedia.org/wiki/Nonlinear_programming) function [f, df, d2f] = f2(x) f = -x(1)*x(2) - x(2)*x(3); if nargout > 1 %% gradient is required df = -[x(2); x(1)+x(3); x(2)]; if nargout > 2 %% Hessian is required d2f = -[0 1 0; 1 0 1; 0 1 0]; %% actually not used since end %% 'hess_fcn' is provided end function [h, g, dh, dg] = gh2(x) h = [ 1 -1 1; 1 1 1] * x.^2 + [-2; -10]; dh = 2 * [x(1) x(1); -x(2) x(2); x(3) x(3)]; g = []; dg = []; function Lxx = hess2(x, lam, cost_mult) if nargin < 3, cost_mult = 1; end mu = lam.ineqnonlin; Lxx = cost_mult * [0 -1 0; -1 0 -1; 0 -1 0] + ... [2*[1 1]*mu 0 0; 0 2*[-1 1]*mu 0; 0 0 2*[1 1]*mu]; problem = struct( ... 'f_fcn', @(x)f2(x), ... 'gh_fcn', @(x)gh2(x), ... 'hess_fcn', @(x, lam, cost_mult)hess2(x, lam, cost_mult), ... 'x0', [1; 1; 0], ... 'opt', struct('verbose', 2) ... ); [x, f, exitflag, output, lambda] = nlps_master(problem); See also MIPS, NLPS_FMINCON, NLPS_IPOPT, NLPS_KNITRO.
0001 function [x, f, eflag, output, lambda] = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt) 0002 %NLPS_MASTER Nonlinear programming (NLP) Solver wrapper function. 0003 % [X, F, EXITFLAG, OUTPUT, LAMBDA] = ... 0004 % NLPS_MASTER(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT) 0005 % [X, F, EXITFLAG, OUTPUT, LAMBDA] = NLPS_MASTER(PROBLEM) 0006 % A common wrapper function for various NLP solvers. 0007 % Solves the following NLP (nonlinear programming) problem: 0008 % 0009 % Minimize a function F(X) beginning from a starting point X0, subject to 0010 % optional linear and nonlinear constraints and variable bounds. 0011 % 0012 % min F(X) 0013 % X 0014 % 0015 % subject to 0016 % 0017 % G(X) = 0 (nonlinear equalities) 0018 % H(X) <= 0 (nonlinear inequalities) 0019 % L <= A*X <= U (linear constraints) 0020 % XMIN <= X <= XMAX (variable bounds) 0021 % 0022 % Inputs (all optional except F_FCN and X0): 0023 % F_FCN : handle to function that evaluates the objective function, 0024 % its gradients and Hessian for a given value of X. If there 0025 % are nonlinear constraints, the Hessian information is 0026 % provided by the HESS_FCN function passed in the 9th argument 0027 % and is not required here. Calling syntax for this function: 0028 % [F, DF, D2F] = F_FCN(X) 0029 % X0 : starting value of optimization vector X 0030 % A, L, U : define the optional linear constraints. Default 0031 % values for the elements of L and U are -Inf and Inf, 0032 % respectively. 0033 % XMIN, XMAX : optional lower and upper bounds on the 0034 % X variables, defaults are -Inf and Inf, respectively. 0035 % GH_FCN : handle to function that evaluates the optional 0036 % nonlinear constraints and their gradients for a given 0037 % value of X. Calling syntax for this function is: 0038 % [H, G, DH, DG] = GH_FCN(X) 0039 % where the columns of DH and DG are the gradients of the 0040 % corresponding elements of H and G, i.e. DH and DG are 0041 % transposes of the Jacobians of H and G, respectively. 0042 % HESS_FCN : handle to function that computes the Hessian of the 0043 % Lagrangian for given values of X, lambda and mu, where 0044 % lambda and mu are the multipliers on the equality and 0045 % inequality constraints, g and h, respectively. The calling 0046 % syntax for this function is: 0047 % LXX = HESS_FCN(X, LAM) 0048 % where lambda = LAM.eqnonlin and mu = LAM.ineqnonlin. 0049 % OPT : optional options structure with the following fields, 0050 % all of which are also optional (default values shown in 0051 % parentheses) 0052 % alg ('DEFAULT') : determines which solver to use 0053 % 'DEFAULT' : automatic, current default is MIPS 0054 % 'MIPS' : MIPS, MATPOWER Interior Point Solver 0055 % pure MATLAB implementation of a primal-dual 0056 % interior point method, if mips_opt.step_control = 1 0057 % it uses MIPS-sc, a step controlled variant of MIPS 0058 % 'FMINCON' : FMINCON, MATLAB Optimization Toolbox 0059 % 'IPOPT' : IPOPT, requires MEX interface to IPOPT solver 0060 % https://github.com/coin-or/Ipopt 0061 % 'KNITRO' : Artelys Knitro, requires Artelys Knitro solver 0062 % https://www.artelys.com/solvers/knitro/ 0063 % verbose (0) - controls level of progress output displayed 0064 % 0 = no progress output 0065 % 1 = some progress output 0066 % 2 = verbose progress output 0067 % mips_opt - options struct for MIPS 0068 % fmincon_opt - options struct for FMINCON 0069 % ipopt_opt - options struct for IPOPT 0070 % knitro_opt - options struct for Artelys Knitro 0071 % PROBLEM : The inputs can alternatively be supplied in a single 0072 % PROBLEM struct with fields corresponding to the input arguments 0073 % described above: f_fcn, x0, A, l, u, xmin, xmax, 0074 % gh_fcn, hess_fcn, opt 0075 % 0076 % Outputs: 0077 % X : solution vector 0078 % F : final objective function value 0079 % EXITFLAG : exit flag 0080 % 1 = converged 0081 % 0 or negative values = solver specific failure codes 0082 % OUTPUT : output struct with the following fields: 0083 % alg - algorithm code of solver used 0084 % (others) - algorithm specific fields 0085 % LAMBDA : struct containing the Langrange and Kuhn-Tucker 0086 % multipliers on the constraints, with fields: 0087 % eqnonlin - nonlinear equality constraints 0088 % ineqnonlin - nonlinear inequality constraints 0089 % mu_l - lower (left-hand) limit on linear constraints 0090 % mu_u - upper (right-hand) limit on linear constraints 0091 % lower - lower bound on optimization variables 0092 % upper - upper bound on optimization variables 0093 % 0094 % Note the calling syntax is almost identical to that of FMINCON 0095 % from MathWorks' Optimization Toolbox. The main difference is that 0096 % the linear constraints are specified with A, L, U instead of 0097 % A, B, Aeq, Beq. The functions for evaluating the objective 0098 % function, constraints and Hessian are identical. 0099 % 0100 % Calling syntax options: 0101 % [x, f, exitflag, output, lambda] = ... 0102 % nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0103 % 0104 % x = nlps_master(f_fcn, x0); 0105 % x = nlps_master(f_fcn, x0, A, l); 0106 % x = nlps_master(f_fcn, x0, A, l, u); 0107 % x = nlps_master(f_fcn, x0, A, l, u, xmin); 0108 % x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax); 0109 % x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn); 0110 % x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn); 0111 % x = nlps_master(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0112 % x = nlps_master(problem); 0113 % where problem is a struct with fields: 0114 % f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt 0115 % all fields except 'f_fcn' and 'x0' are optional 0116 % x = nlps_master(...); 0117 % [x, f] = nlps_master(...); 0118 % [x, f, exitflag] = nlps_master(...); 0119 % [x, f, exitflag, output] = nlps_master(...); 0120 % [x, f, exitflag, output, lambda] = nlps_master(...); 0121 % 0122 % Example: (problem from https://en.wikipedia.org/wiki/Nonlinear_programming) 0123 % function [f, df, d2f] = f2(x) 0124 % f = -x(1)*x(2) - x(2)*x(3); 0125 % if nargout > 1 %% gradient is required 0126 % df = -[x(2); x(1)+x(3); x(2)]; 0127 % if nargout > 2 %% Hessian is required 0128 % d2f = -[0 1 0; 1 0 1; 0 1 0]; %% actually not used since 0129 % end %% 'hess_fcn' is provided 0130 % end 0131 % 0132 % function [h, g, dh, dg] = gh2(x) 0133 % h = [ 1 -1 1; 1 1 1] * x.^2 + [-2; -10]; 0134 % dh = 2 * [x(1) x(1); -x(2) x(2); x(3) x(3)]; 0135 % g = []; dg = []; 0136 % 0137 % function Lxx = hess2(x, lam, cost_mult) 0138 % if nargin < 3, cost_mult = 1; end 0139 % mu = lam.ineqnonlin; 0140 % Lxx = cost_mult * [0 -1 0; -1 0 -1; 0 -1 0] + ... 0141 % [2*[1 1]*mu 0 0; 0 2*[-1 1]*mu 0; 0 0 2*[1 1]*mu]; 0142 % 0143 % problem = struct( ... 0144 % 'f_fcn', @(x)f2(x), ... 0145 % 'gh_fcn', @(x)gh2(x), ... 0146 % 'hess_fcn', @(x, lam, cost_mult)hess2(x, lam, cost_mult), ... 0147 % 'x0', [1; 1; 0], ... 0148 % 'opt', struct('verbose', 2) ... 0149 % ); 0150 % [x, f, exitflag, output, lambda] = nlps_master(problem); 0151 % 0152 % See also MIPS, NLPS_FMINCON, NLPS_IPOPT, NLPS_KNITRO. 0153 0154 % MP-Opt-Model 0155 % Copyright (c) 2010-2020, Power Systems Engineering Research Center (PSERC) 0156 % by Ray Zimmerman, PSERC Cornell 0157 % 0158 % This file is part of MP-Opt-Model. 0159 % Covered by the 3-clause BSD License (see LICENSE file for details). 0160 % See https://github.com/MATPOWER/mp-opt-model for more info. 0161 0162 %%----- input argument handling ----- 0163 %% gather inputs 0164 if nargin == 1 && isstruct(f_fcn) %% problem struct 0165 p = f_fcn; 0166 f_fcn = p.f_fcn; 0167 x0 = p.x0; 0168 nx = size(x0, 1); %% number of optimization variables 0169 if isfield(p, 'opt'), opt = p.opt; else, opt = []; end 0170 if isfield(p, 'hess_fcn'), hess_fcn = p.hess_fcn; else, hess_fcn = ''; end 0171 if isfield(p, 'gh_fcn'), gh_fcn = p.gh_fcn; else, gh_fcn = ''; end 0172 if isfield(p, 'xmax'), xmax = p.xmax; else, xmax = []; end 0173 if isfield(p, 'xmin'), xmin = p.xmin; else, xmin = []; end 0174 if isfield(p, 'u'), u = p.u; else, u = []; end 0175 if isfield(p, 'l'), l = p.l; else, l = []; end 0176 if isfield(p, 'A'), A = p.A; else, A=sparse(0,nx); end 0177 else %% individual args 0178 nx = size(x0, 1); %% number of optimization variables 0179 if nargin < 10 0180 opt = []; 0181 if nargin < 9 0182 hess_fcn = ''; 0183 if nargin < 8 0184 gh_fcn = ''; 0185 if nargin < 7 0186 xmax = []; 0187 if nargin < 6 0188 xmin = []; 0189 if nargin < 5 0190 u = []; 0191 if nargin < 4 0192 l = []; 0193 A = sparse(0,nx); 0194 end 0195 end 0196 end 0197 end 0198 end 0199 end 0200 end 0201 end 0202 0203 %% default options 0204 if ~isempty(opt) && isfield(opt, 'alg') && ~isempty(opt.alg) 0205 alg = opt.alg; 0206 else 0207 alg = 'DEFAULT'; 0208 end 0209 if ~isempty(opt) && isfield(opt, 'verbose') && ~isempty(opt.verbose) 0210 verbose = opt.verbose; 0211 else 0212 verbose = 0; 0213 end 0214 if strcmp(alg, 'DEFAULT') 0215 alg = 'MIPS'; 0216 end 0217 0218 %%----- call the appropriate solver ----- 0219 switch alg 0220 case 'MIPS' %% use MIPS 0221 %% set up options 0222 if ~isempty(opt) && isfield(opt, 'mips_opt') && ~isempty(opt.mips_opt) 0223 mips_opt = opt.mips_opt; 0224 else 0225 mips_opt = []; 0226 end 0227 mips_opt.verbose = verbose; 0228 0229 %% call solver 0230 [x, f, eflag, output, lambda] = ... 0231 mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, mips_opt); 0232 case 'FMINCON' %% use fmincon 0233 [x, f, eflag, output, lambda] = ... 0234 nlps_fmincon(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0235 case 'IPOPT' %% use IPOPT 0236 [x, f, eflag, output, lambda] = ... 0237 nlps_ipopt(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0238 case 'KNITRO' %% use Artelys Knitro 0239 [x, f, eflag, output, lambda] = ... 0240 nlps_knitro(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0241 otherwise 0242 error('nlps_master: ''%s'' is not a valid algorithm code', alg); 0243 end 0244 if ~isfield(output, 'alg') || isempty(output.alg) 0245 output.alg = alg; 0246 end