------------------------------ deprecated ------------------------------ MATLAB 6.x support to be removed in a future version. -------------------------------------------------------------------------- MIPS6 MATLAB Interior Point Solver (for MATLAB 6.x). [X, F, EXITFLAG, OUTPUT, LAMBDA] = ... MIPS6(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT, VARARGIN) Primal-dual interior point method for NLP (nonlinear programming). 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) 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) verbose (0) - controls level of progress output displayed feastol (1e-6) - termination tolerance for feasibility condition gradtol (1e-6) - termination tolerance for gradient condition comptol (1e-6) - termination tolerance for complementarity condition costtol (1e-6) - termination tolerance for cost condition max_it (150) - maximum number of iterations step_control (0) - set to 1 to enable step-size control max_red (20) - maximum number of step-size reductions if step-control is on cost_mult (1) - cost multiplier used to scale the objective function for improved conditioning. Note: This value is also passed as the 3rd argument to the Hessian evaluation function so that it can appropriately scale the objective function term in the Hessian of the Lagrangian. 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 = first order optimality conditions satisfied 0 = maximum number of iterations reached -1 = numerically failed OUTPUT : output struct with fields: iterations - number of iterations performed hist - struct array with trajectories of the following: feascond, gradcond, compcond, costcond, gamma, stepsize, obj, alphap, alphad message - exit message 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] = ... mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, ... opt, varargin); x = mips6(f_fcn, x0); x = mips6(f_fcn, x0, A, l); x = mips6(f_fcn, x0, A, l, u); x = mips6(f_fcn, x0, A, l, u, xmin); x = mips6(f_fcn, x0, A, l, u, xmin, xmax); x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn); x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn); x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); x = mips6(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 = mips6(...); [x, f] = mips6(...); [x, f, exitflag] = mips6(...); [x, f, exitflag, output] = mips6(...); [x, f, exitflag, output, lambda] = mips6(...); Example: (problem from http://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', @f2, ... 'gh_fcn', @gh2, ... 'hess_fcn', @hess2, ... 'x0', [1; 1; 0], ... 'opt', struct('verbose', 2) ... ); [x, f, exitflag, output, lambda] = mips6(problem); Ported by Ray Zimmerman from C code written by H. Wang for his PhD dissertation: "On the Computation and Application of Multi-period Security-Constrained Optimal Power Flow for Real-time Electricity Market Operations", Cornell University, May 2007. See also: H. Wang, C. E. Murillo-S‡nchez, R. D. Zimmerman, R. J. Thomas, "On Computational Issues of Market-Based Optimal Power Flow", IEEE Transactions on Power Systems, Vol. 22, No. 3, Aug. 2007, pp. 1185-1193.
0001 function [x, f, eflag, output, lambda] = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt, varargin) 0002 %------------------------------ deprecated ------------------------------ 0003 % MATLAB 6.x support to be removed in a future version. 0004 %-------------------------------------------------------------------------- 0005 %MIPS6 MATLAB Interior Point Solver (for MATLAB 6.x). 0006 % [X, F, EXITFLAG, OUTPUT, LAMBDA] = ... 0007 % MIPS6(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT, VARARGIN) 0008 % Primal-dual interior point method for NLP (nonlinear programming). 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 % HESS_FCN : handle to function that computes the Hessian of the 0040 % Lagrangian for given values of X, lambda and mu, where 0041 % lambda and mu are the multipliers on the equality and 0042 % inequality constraints, g and h, respectively. The calling 0043 % syntax for this function is: 0044 % LXX = HESS_FCN(X, LAM) 0045 % where lambda = LAM.eqnonlin and mu = LAM.ineqnonlin. 0046 % OPT : optional options structure with the following fields, 0047 % all of which are also optional (default values shown in 0048 % parentheses) 0049 % verbose (0) - controls level of progress output displayed 0050 % feastol (1e-6) - termination tolerance for feasibility 0051 % condition 0052 % gradtol (1e-6) - termination tolerance for gradient 0053 % condition 0054 % comptol (1e-6) - termination tolerance for complementarity 0055 % condition 0056 % costtol (1e-6) - termination tolerance for cost condition 0057 % max_it (150) - maximum number of iterations 0058 % step_control (0) - set to 1 to enable step-size control 0059 % max_red (20) - maximum number of step-size reductions if 0060 % step-control is on 0061 % cost_mult (1) - cost multiplier used to scale the objective 0062 % function for improved conditioning. Note: This value is 0063 % also passed as the 3rd argument to the Hessian evaluation 0064 % function so that it can appropriately scale the 0065 % objective function term in the Hessian of the 0066 % Lagrangian. 0067 % PROBLEM : The inputs can alternatively be supplied in a single 0068 % PROBLEM struct with fields corresponding to the input arguments 0069 % described above: f_fcn, x0, A, l, u, xmin, xmax, 0070 % gh_fcn, hess_fcn, opt 0071 % 0072 % Outputs: 0073 % X : solution vector 0074 % F : final objective function value 0075 % EXITFLAG : exit flag 0076 % 1 = first order optimality conditions satisfied 0077 % 0 = maximum number of iterations reached 0078 % -1 = numerically failed 0079 % OUTPUT : output struct with fields: 0080 % iterations - number of iterations performed 0081 % hist - struct array with trajectories of the following: 0082 % feascond, gradcond, compcond, costcond, gamma, 0083 % stepsize, obj, alphap, alphad 0084 % message - exit message 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 % mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, ... 0103 % opt, varargin); 0104 % 0105 % x = mips6(f_fcn, x0); 0106 % x = mips6(f_fcn, x0, A, l); 0107 % x = mips6(f_fcn, x0, A, l, u); 0108 % x = mips6(f_fcn, x0, A, l, u, xmin); 0109 % x = mips6(f_fcn, x0, A, l, u, xmin, xmax); 0110 % x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn); 0111 % x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn); 0112 % x = mips6(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt); 0113 % x = mips6(problem); 0114 % where problem is a struct with fields: 0115 % f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt 0116 % all fields except 'f_fcn' and 'x0' are optional 0117 % x = mips6(...); 0118 % [x, f] = mips6(...); 0119 % [x, f, exitflag] = mips6(...); 0120 % [x, f, exitflag, output] = mips6(...); 0121 % [x, f, exitflag, output, lambda] = mips6(...); 0122 % 0123 % Example: (problem from http://en.wikipedia.org/wiki/Nonlinear_programming) 0124 % function [f, df, d2f] = f2(x) 0125 % f = -x(1)*x(2) - x(2)*x(3); 0126 % if nargout > 1 %% gradient is required 0127 % df = -[x(2); x(1)+x(3); x(2)]; 0128 % if nargout > 2 %% Hessian is required 0129 % d2f = -[0 1 0; 1 0 1; 0 1 0]; %% actually not used since 0130 % end %% 'hess_fcn' is provided 0131 % end 0132 % 0133 % function [h, g, dh, dg] = gh2(x) 0134 % h = [ 1 -1 1; 1 1 1] * x.^2 + [-2; -10]; 0135 % dh = 2 * [x(1) x(1); -x(2) x(2); x(3) x(3)]; 0136 % g = []; dg = []; 0137 % 0138 % function Lxx = hess2(x, lam, cost_mult) 0139 % if nargin < 3, cost_mult = 1; end 0140 % mu = lam.ineqnonlin; 0141 % Lxx = cost_mult * [0 -1 0; -1 0 -1; 0 -1 0] + ... 0142 % [2*[1 1]*mu 0 0; 0 2*[-1 1]*mu 0; 0 0 2*[1 1]*mu]; 0143 % 0144 % problem = struct( ... 0145 % 'f_fcn', @f2, ... 0146 % 'gh_fcn', @gh2, ... 0147 % 'hess_fcn', @hess2, ... 0148 % 'x0', [1; 1; 0], ... 0149 % 'opt', struct('verbose', 2) ... 0150 % ); 0151 % [x, f, exitflag, output, lambda] = mips6(problem); 0152 % 0153 % Ported by Ray Zimmerman from C code written by H. Wang for his 0154 % PhD dissertation: 0155 % "On the Computation and Application of Multi-period 0156 % Security-Constrained Optimal Power Flow for Real-time 0157 % Electricity Market Operations", Cornell University, May 2007. 0158 % 0159 % See also: 0160 % H. Wang, C. E. Murillo-S‡nchez, R. D. Zimmerman, R. J. Thomas, 0161 % "On Computational Issues of Market-Based Optimal Power Flow", 0162 % IEEE Transactions on Power Systems, Vol. 22, No. 3, Aug. 2007, 0163 % pp. 1185-1193. 0164 0165 % MIPS 0166 % $Id: mips6.m,v 1.17 2010/06/09 14:56:58 ray Exp $ 0167 % by Ray Zimmerman, PSERC Cornell 0168 % Copyright (c) 2009-2010 by Power System Engineering Research Center (PSERC) 0169 % 0170 % This file is part of MIPS. 0171 % See http://www.pserc.cornell.edu/matpower/ for more info. 0172 % 0173 % MIPS is free software: you can redistribute it and/or modify 0174 % it under the terms of the GNU General Public License as published 0175 % by the Free Software Foundation, either version 3 of the License, 0176 % or (at your option) any later version. 0177 % 0178 % MIPS is distributed in the hope that it will be useful, 0179 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0180 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0181 % GNU General Public License for more details. 0182 % 0183 % You should have received a copy of the GNU General Public License 0184 % along with MIPS. If not, see <http://www.gnu.org/licenses/>. 0185 % 0186 % Additional permission under GNU GPL version 3 section 7 0187 % 0188 % If you modify MIPS, or any covered work, to interface with 0189 % other modules (such as MATLAB code and MEX-files) available in a 0190 % MATLAB(R) or comparable environment containing parts covered 0191 % under other licensing terms, the licensors of MIPS grant 0192 % you additional permission to convey the resulting work. 0193 0194 %%----- input argument handling ----- 0195 %% gather inputs 0196 if nargin == 1 && isstruct(f_fcn) %% problem struct 0197 p = f_fcn; 0198 f_fcn = p.f_fcn; 0199 x0 = p.x0; 0200 nx = size(x0, 1); %% number of optimization variables 0201 if isfield(p, 'opt'), opt = p.opt; else, opt = []; end 0202 if isfield(p, 'hess_fcn'), hess_fcn = p.hess_fcn; else, hess_fcn = ''; end 0203 if isfield(p, 'gh_fcn'), gh_fcn = p.gh_fcn; else, gh_fcn = ''; end 0204 if isfield(p, 'xmax'), xmax = p.xmax; else, xmax = []; end 0205 if isfield(p, 'xmin'), xmin = p.xmin; else, xmin = []; end 0206 if isfield(p, 'u'), u = p.u; else, u = []; end 0207 if isfield(p, 'l'), l = p.l; else, l = []; end 0208 if isfield(p, 'A'), A = p.A; else, A=sparse(0,nx); end 0209 varargin = {p}; 0210 else %% individual args 0211 nx = size(x0, 1); %% number of optimization variables 0212 if nargin < 10 0213 opt = []; 0214 if nargin < 9 0215 hess_fcn = ''; 0216 if nargin < 8 0217 gh_fcn = ''; 0218 if nargin < 7 0219 xmax = []; 0220 if nargin < 6 0221 xmin = []; 0222 if nargin < 5 0223 u = []; 0224 if nargin < 4 0225 l = []; 0226 A = sparse(0,nx); 0227 end 0228 end 0229 end 0230 end 0231 end 0232 end 0233 end 0234 end 0235 %% set default argument values if missing 0236 if ~isempty(A) && (isempty(l) || all(l == -Inf)) && ... 0237 (isempty(u) || all(u == Inf)) 0238 A = sparse(0,nx); %% no limits => no linear constraints 0239 end 0240 nA = size(A, 1); %% number of original linear constraints 0241 if isempty(u) %% By default, linear inequalities are ... 0242 u = Inf * ones(nA, 1); %% ... unbounded above and ... 0243 end 0244 if isempty(l) 0245 l = -Inf * ones(nA, 1); %% ... unbounded below. 0246 end 0247 if isempty(xmin) %% By default, optimization variables are ... 0248 xmin = -Inf * ones(nx, 1); %% ... unbounded below and ... 0249 end 0250 if isempty(xmax) 0251 xmax = Inf * ones(nx, 1); %% ... unbounded above. 0252 end 0253 if isempty(gh_fcn) 0254 nonlinear = false; %% no nonlinear constraints present 0255 gn = []; hn = []; 0256 else 0257 nonlinear = true; %% we have some nonlinear constraints 0258 end 0259 0260 %% default options 0261 if isempty(opt) 0262 opt = struct('verbose', 0); 0263 end 0264 if ~isfield(opt, 'feastol') || isempty(opt.feastol) 0265 opt.feastol = 1e-6; 0266 end 0267 if ~isfield(opt, 'gradtol') || isempty(opt.gradtol) 0268 opt.gradtol = 1e-6; 0269 end 0270 if ~isfield(opt, 'comptol') || isempty(opt.comptol) 0271 opt.comptol = 1e-6; 0272 end 0273 if ~isfield(opt, 'costtol') || isempty(opt.costtol) 0274 opt.costtol = 1e-6; 0275 end 0276 if ~isfield(opt, 'max_it') || isempty(opt.max_it) 0277 opt.max_it = 150; 0278 end 0279 if ~isfield(opt, 'max_red') || isempty(opt.max_red) 0280 opt.max_red = 20; 0281 end 0282 if ~isfield(opt, 'step_control') || isempty(opt.step_control) 0283 opt.step_control = 0; 0284 end 0285 if ~isfield(opt, 'cost_mult') || isempty(opt.cost_mult) 0286 opt.cost_mult = 1; 0287 end 0288 if ~isfield(opt, 'verbose') || isempty(opt.verbose) 0289 opt.verbose = 0; 0290 end 0291 0292 %% initialize history 0293 hist(opt.max_it+1) = struct('feascond', 0, 'gradcond', 0, 'compcond', 0, ... 0294 'costcond', 0, 'gamma', 0, 'stepsize', 0, 'obj', 0, ... 0295 'alphap', 0, 'alphad', 0); 0296 0297 %%----- set up problem ----- 0298 %% constants 0299 xi = 0.99995; %% OPT_IPM_PHI 0300 sigma = 0.1; %% OPT_IPM_SIGMA 0301 z0 = 1; %% OPT_IPM_INIT_SLACK 0302 alpha_min = 1e-8; %% OPT_AP_AD_MIN 0303 rho_min = 0.95; %% OPT_IPM_QUAD_LOWTHRESH 0304 rho_max = 1.05; %% OPT_IPM_QUAD_HIGHTHRESH 0305 mu_threshold = 1e-5; %% SCOPF_MULTIPLIERS_FILTER_THRESH 0306 0307 %% initialize 0308 i = 0; %% iteration counter 0309 converged = 0; %% flag 0310 eflag = 0; %% exit flag 0311 0312 %% add var limits to linear constraints 0313 AA = [speye(nx); A]; 0314 ll = [xmin; l]; 0315 uu = [xmax; u]; 0316 0317 %% split up linear constraints 0318 ieq = find( abs(uu-ll) <= eps ); %% equality 0319 igt = find( uu >= 1e10 & ll > -1e10 ); %% greater than, unbounded above 0320 ilt = find( ll <= -1e10 & uu < 1e10 ); %% less than, unbounded below 0321 ibx = find( (abs(uu-ll) > eps) & (uu < 1e10) & (ll > -1e10) ); 0322 Ae = AA(ieq, :); 0323 be = uu(ieq); 0324 Ai = [ AA(ilt, :); -AA(igt, :); AA(ibx, :); -AA(ibx, :) ]; 0325 bi = [ uu(ilt); -ll(igt); uu(ibx); -ll(ibx)]; 0326 0327 %% evaluate cost f(x0) and constraints g(x0), h(x0) 0328 x = x0; 0329 [f, df] = feval(f_fcn, x, varargin{:}); %% cost 0330 f = f * opt.cost_mult; 0331 df = df * opt.cost_mult; 0332 if nonlinear 0333 [hn, gn, dhn, dgn] = feval(gh_fcn, x, varargin{:}); %% nonlinear constraints 0334 h = [hn; Ai * x - bi]; %% inequality constraints 0335 g = [gn; Ae * x - be]; %% equality constraints 0336 dh = [dhn Ai']; %% 1st derivative of inequalities 0337 dg = [dgn Ae']; %% 1st derivative of equalities 0338 else 0339 h = Ai * x - bi; %% inequality constraints 0340 g = Ae * x - be; %% equality constraints 0341 dh = Ai'; %% 1st derivative of inequalities 0342 dg = Ae'; %% 1st derivative of equalities 0343 end 0344 0345 %% grab some dimensions 0346 neq = size(g, 1); %% number of equality constraints 0347 niq = size(h, 1); %% number of inequality constraints 0348 neqnln = size(gn, 1); %% number of nonlinear equality constraints 0349 niqnln = size(hn, 1); %% number of nonlinear inequality constraints 0350 nlt = length(ilt); %% number of upper bounded linear inequalities 0351 ngt = length(igt); %% number of lower bounded linear inequalities 0352 nbx = length(ibx); %% number of doubly bounded linear inequalities 0353 0354 %% initialize gamma, lam, mu, z, e 0355 gamma = 1; %% barrier coefficient, r in Harry's code 0356 lam = zeros(neq, 1); 0357 z = z0 * ones(niq, 1); 0358 mu = z; 0359 k = find(h < -z0); 0360 z(k) = -h(k); 0361 k = find(gamma / z > z0); %% (seems k is always empty if gamma = z0 = 1) 0362 if ~isempty(k) 0363 mu(k) = gamma / z(k); 0364 end 0365 e = ones(niq, 1); 0366 0367 %% check tolerance 0368 f0 = f; 0369 if opt.step_control 0370 L = f + lam' * g + mu' * (h+z) - gamma * sum(log(z)); 0371 end 0372 Lx = df + dg * lam + dh * mu; 0373 feascond = max([norm(g, Inf), max(h)]) / (1 + max([ norm(x, Inf), norm(z, Inf) ])); 0374 gradcond = norm(Lx, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ])); 0375 compcond = (z' * mu) / (1 + norm(x, Inf)); 0376 costcond = abs(f - f0) / (1 + abs(f0)); 0377 %% save history 0378 hist(i+1) = struct('feascond', feascond, 'gradcond', gradcond, ... 0379 'compcond', compcond, 'costcond', costcond, 'gamma', gamma, ... 0380 'stepsize', 0, 'obj', f/opt.cost_mult, 'alphap', 0, 'alphad', 0); 0381 if opt.verbose 0382 if opt.step_control, s = '-sc'; else, s = ''; end 0383 v = mipsver('all'); 0384 fprintf('MATLAB Interior Point Solver -- MIPS%s, Version %s, %s', ... 0385 s, v.Version, v.Date); 0386 if opt.verbose > 1 0387 fprintf('\n it objective step size feascond gradcond compcond costcond '); 0388 fprintf('\n---- ------------ --------- ------------ ------------ ------------ ------------'); 0389 fprintf('\n%3d %12.8g %10s %12g %12g %12g %12g', ... 0390 i, f/opt.cost_mult, '', feascond, gradcond, compcond, costcond); 0391 end 0392 end 0393 if feascond < opt.feastol && gradcond < opt.gradtol && ... 0394 compcond < opt.comptol && costcond < opt.costtol 0395 converged = 1; 0396 if opt.verbose 0397 fprintf('\nConverged!\n'); 0398 end 0399 end 0400 0401 %%----- do Newton iterations ----- 0402 while (~converged && i < opt.max_it) 0403 %% update iteration counter 0404 i = i + 1; 0405 0406 %% compute update step 0407 lambda = struct('eqnonlin', lam(1:neqnln), 'ineqnonlin', mu(1:niqnln)); 0408 if nonlinear 0409 if isempty(hess_fcn) 0410 fprintf('mips6: Hessian evaluation via finite differences not yet implemented.\n Please provide your own hessian evaluation function.'); 0411 end 0412 Lxx = feval(hess_fcn, x, lambda, opt.cost_mult, varargin{:}); 0413 else 0414 [f_, df_, d2f] = feval(f_fcn, x, varargin{:}); %% cost 0415 Lxx = d2f * opt.cost_mult; 0416 end 0417 zinvdiag = sparse(1:niq, 1:niq, 1 ./ z, niq, niq); 0418 mudiag = sparse(1:niq, 1:niq, mu, niq, niq); 0419 dh_zinv = dh * zinvdiag; 0420 M = Lxx + dh_zinv * mudiag * dh'; 0421 N = Lx + dh_zinv * (mudiag * h + gamma * e); 0422 dxdlam = [M dg; dg' sparse(neq, neq)] \ [-N; -g]; 0423 % AAA = [ 0424 % M dg; 0425 % dg' sparse(neq, neq) 0426 % ]; 0427 % rc = 1/condest(AAA); 0428 % if rc < 1e-22 0429 % fprintf('my RCOND = %g\n', rc); 0430 % n = size(AAA, 1); 0431 % AAA = AAA + 1e-3 * speye(n,n); 0432 % end 0433 % bbb = [-N; -g]; 0434 % dxdlam = AAA \ bbb; 0435 if any(isnan(dxdlam)) 0436 if opt.verbose 0437 fprintf('\nNumerically Failed\n'); 0438 end 0439 eflag = -1; 0440 break; 0441 end 0442 dx = dxdlam(1:nx); 0443 dlam = dxdlam(nx+(1:neq)); 0444 dz = -h - z - dh' * dx; 0445 dmu = -mu + zinvdiag *(gamma*e - mudiag * dz); 0446 0447 %% optional step-size control 0448 sc = 0; 0449 if opt.step_control 0450 x1 = x + dx; 0451 0452 %% evaluate cost, constraints, derivatives at x1 0453 [f1, df1] = feval(f_fcn, x1, varargin{:}); %% cost 0454 f1 = f1 * opt.cost_mult; 0455 df1 = df1 * opt.cost_mult; 0456 if nonlinear 0457 [hn1, gn1, dhn1, dgn1] = feval(gh_fcn, x1, varargin{:}); %% nonlinear constraints 0458 h1 = [hn1; Ai * x1 - bi]; %% inequality constraints 0459 g1 = [gn1; Ae * x1 - be]; %% equality constraints 0460 dh1 = [dhn1 Ai']; %% 1st derivative of inequalities 0461 dg1 = [dgn1 Ae']; %% 1st derivative of equalities 0462 else 0463 h1 = Ai * x1 - bi; %% inequality constraints 0464 g1 = Ae * x1 - be; %% equality constraints 0465 dh1 = dh; %% 1st derivative of inequalities 0466 dg1 = dg; %% 1st derivative of equalities 0467 end 0468 0469 %% check tolerance 0470 Lx1 = df1 + dg1 * lam + dh1 * mu; 0471 feascond1 = max([norm(g1, Inf), max(h1)]) / (1 + max([ norm(x1, Inf), norm(z, Inf) ])); 0472 gradcond1 = norm(Lx1, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ])); 0473 0474 if feascond1 > feascond && gradcond1 > gradcond 0475 sc = 1; 0476 end 0477 end 0478 if sc 0479 alpha = 1; 0480 for j = 1:opt.max_red 0481 dx1 = alpha * dx; 0482 x1 = x + dx1; 0483 f1 = feval(f_fcn, x1, varargin{:}); %% cost 0484 f1 = f1 * opt.cost_mult; 0485 if nonlinear 0486 [hn1, gn1] = feval(gh_fcn, x1, varargin{:}); %% nonlinear constraints 0487 h1 = [hn1; Ai * x1 - bi]; %% inequality constraints 0488 g1 = [gn1; Ae * x1 - be]; %% equality constraints 0489 else 0490 h1 = Ai * x1 - bi; %% inequality constraints 0491 g1 = Ae * x1 - be; %% equality constraints 0492 end 0493 L1 = f1 + lam' * g1 + mu' * (h1+z) - gamma * sum(log(z)); 0494 if opt.verbose > 2 0495 fprintf('\n %3d %10g', -j, norm(dx1)); 0496 end 0497 rho = (L1 - L) / (Lx' * dx1 + 0.5 * dx1' * Lxx * dx1); 0498 if rho > rho_min && rho < rho_max 0499 break; 0500 else 0501 alpha = alpha / 2; 0502 end 0503 end 0504 dx = alpha * dx; 0505 dz = alpha * dz; 0506 dlam = alpha * dlam; 0507 dmu = alpha * dmu; 0508 end 0509 0510 %% do the update 0511 k = find(dz < 0); 0512 alphap = min( [xi * min(z(k) ./ -dz(k)) 1] ); 0513 k = find(dmu < 0); 0514 alphad = min( [xi * min(mu(k) ./ -dmu(k)) 1] ); 0515 x = x + alphap * dx; 0516 z = z + alphap * dz; 0517 lam = lam + alphad * dlam; 0518 mu = mu + alphad * dmu; 0519 if niq > 0 0520 gamma = sigma * (z' * mu) / niq; 0521 end 0522 0523 %% evaluate cost, constraints, derivatives 0524 [f, df] = feval(f_fcn, x, varargin{:}); %% cost 0525 f = f * opt.cost_mult; 0526 df = df * opt.cost_mult; 0527 if nonlinear 0528 [hn, gn, dhn, dgn] = feval(gh_fcn, x, varargin{:}); %% nonlinear constraints 0529 h = [hn; Ai * x - bi]; %% inequality constraints 0530 g = [gn; Ae * x - be]; %% equality constraints 0531 dh = [dhn Ai']; %% 1st derivative of inequalities 0532 dg = [dgn Ae']; %% 1st derivative of equalities 0533 else 0534 h = Ai * x - bi; %% inequality constraints 0535 g = Ae * x - be; %% equality constraints 0536 %% 1st derivatives are constant, still dh = Ai', dg = Ae' 0537 end 0538 0539 %% check tolerance 0540 Lx = df + dg * lam + dh * mu; 0541 feascond = max([norm(g, Inf), max(h)]) / (1 + max([ norm(x, Inf), norm(z, Inf) ])); 0542 gradcond = norm(Lx, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ])); 0543 compcond = (z' * mu) / (1 + norm(x, Inf)); 0544 costcond = abs(f - f0) / (1 + abs(f0)); 0545 %% save history 0546 hist(i+1) = struct('feascond', feascond, 'gradcond', gradcond, ... 0547 'compcond', compcond, 'costcond', costcond, 'gamma', gamma, ... 0548 'stepsize', norm(dx), 'obj', f/opt.cost_mult, ... 0549 'alphap', alphap, 'alphad', alphad); 0550 0551 if opt.verbose > 1 0552 fprintf('\n%3d %12.8g %10.5g %12g %12g %12g %12g', ... 0553 i, f/opt.cost_mult, norm(dx), feascond, gradcond, compcond, costcond); 0554 end 0555 if feascond < opt.feastol && gradcond < opt.gradtol && ... 0556 compcond < opt.comptol && costcond < opt.costtol 0557 converged = 1; 0558 if opt.verbose 0559 fprintf('\nConverged!\n'); 0560 end 0561 else 0562 if any(isnan(x)) || alphap < alpha_min || alphad < alpha_min || ... 0563 gamma < eps || gamma > 1/eps 0564 if opt.verbose 0565 fprintf('\nNumerically Failed\n'); 0566 end 0567 eflag = -1; 0568 break; 0569 end 0570 f0 = f; 0571 if opt.step_control 0572 L = f + lam' * g + mu' * (h+z) - gamma * sum(log(z)); 0573 end 0574 end 0575 end 0576 0577 if opt.verbose 0578 if ~converged 0579 fprintf('\nDid not converge in %d iterations.\n', i); 0580 end 0581 end 0582 0583 %%----- package up results ----- 0584 hist = hist(1:i+1); 0585 if eflag ~= -1 0586 eflag = converged; 0587 end 0588 output = struct('iterations', i, 'hist', hist, 'message', ''); 0589 if eflag == 0 0590 output.message = 'Did not converge'; 0591 elseif eflag == 1 0592 output.message = 'Converged'; 0593 elseif eflag == -1 0594 output.message = 'Numerically failed'; 0595 else 0596 output.message = 'Please hang up and dial again'; 0597 end 0598 0599 %% zero out multipliers on non-binding constraints 0600 mu(h < -opt.feastol & mu < mu_threshold) = 0; 0601 0602 %% un-scale cost and prices 0603 f = f / opt.cost_mult; 0604 lam = lam / opt.cost_mult; 0605 mu = mu / opt.cost_mult; 0606 0607 %% re-package multipliers into struct 0608 lam_lin = lam((neqnln+1):neq); %% lambda for linear constraints 0609 mu_lin = mu((niqnln+1):niq); %% mu for linear constraints 0610 kl = find(lam_lin < 0); %% lower bound binding 0611 ku = find(lam_lin > 0); %% upper bound binding 0612 0613 mu_l = zeros(nx+nA, 1); 0614 mu_l(ieq(kl)) = -lam_lin(kl); 0615 mu_l(igt) = mu_lin(nlt+(1:ngt)); 0616 mu_l(ibx) = mu_lin(nlt+ngt+nbx+(1:nbx)); 0617 0618 mu_u = zeros(nx+nA, 1); 0619 mu_u(ieq(ku)) = lam_lin(ku); 0620 mu_u(ilt) = mu_lin(1:nlt); 0621 mu_u(ibx) = mu_lin(nlt+ngt+(1:nbx)); 0622 0623 fields = { ... 0624 'mu_l', mu_l((nx+1):end), ... 0625 'mu_u', mu_u((nx+1):end), ... 0626 'lower', mu_l(1:nx), ... 0627 'upper', mu_u(1:nx) ... 0628 }; 0629 0630 if niqnln > 0 0631 fields = { ... 0632 'ineqnonlin', mu(1:niqnln), ... 0633 fields{:} ... 0634 }; 0635 end 0636 if neqnln > 0 0637 fields = { ... 0638 'eqnonlin', lam(1:neqnln), ... 0639 fields{:} ... 0640 }; 0641 end 0642 0643 lambda = struct(fields{:}); 0644 0645 % lambda = struct( ... 0646 % 'eqnonlin', lam(1:neqnln), ... 0647 % 'ineqnonlin', mu(1:niqnln), ... 0648 % 'mu_l', mu_l((nx+1):end), ... 0649 % 'mu_u', mu_u((nx+1):end), ... 0650 % 'lower', mu_l(1:nx), ... 0651 % 'upper', mu_u(1:nx) );