Home > matpower7.0 > mips > lib > mips.m

mips

PURPOSE ^

MIPS MATPOWER Interior Point Solver.

SYNOPSIS ^

function [x, f, eflag, output, lambda] = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt)

DESCRIPTION ^

MIPS  MATPOWER Interior Point Solver.
   [X, F, EXITFLAG, OUTPUT, LAMBDA] = ...
       MIPS(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT)
   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
           linsolver ('') - linear system solver for solving update steps
               ''          = default solver (currently same as '\')
               '\'         = built-in \ operator
               'PARDISO'   = PARDISO solver (if available)
           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
           sc.red_it (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.
           xi (0.99995) - constant used in alpha updates*
           sigma (0.1) - centering parameter*
           z0 (1) - used to initialize slack variables*
           alpha_min (1e-8) - returns EXITFLAG = -1 if either alpha
               parameter becomes smaller than this value*
           rho_min (0.95) - lower bound on rho_t*
           rho_max (1.05) - upper bound on rho_t*
           mu_threshold (1e-5) - KT multipliers smaller than this value
               for non-binding constraints are forced to zero
           max_stepsize (1e10) - returns EXITFLAG = -1 if the 2-norm of
               the reduced Newton step exceeds this value*
               * see the corresponding Appendix in the manual for details
       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] = ...
           mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt);

       x = mips(f_fcn, x0);
       x = mips(f_fcn, x0, A, l);
       x = mips(f_fcn, x0, A, l, u);
       x = mips(f_fcn, x0, A, l, u, xmin);
       x = mips(f_fcn, x0, A, l, u, xmin, xmax);
       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn);
       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn);
       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt);
       x = mips(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 = mips(...);
       [x, f] = mips(...);
       [x, f, exitflag] = mips(...);
       [x, f, exitflag, output] = mips(...);
       [x, f, exitflag, output, lambda] = mips(...);

   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] = mips(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-Sanchez, 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.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [x, f, eflag, output, lambda] = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt)
0002 %MIPS  MATPOWER Interior Point Solver.
0003 %   [X, F, EXITFLAG, OUTPUT, LAMBDA] = ...
0004 %       MIPS(F_FCN, X0, A, L, U, XMIN, XMAX, GH_FCN, HESS_FCN, OPT)
0005 %   Primal-dual interior point method for NLP (nonlinear programming).
0006 %   Minimize a function F(X) beginning from a starting point X0, subject to
0007 %   optional linear and nonlinear constraints and variable bounds.
0008 %
0009 %       min F(X)
0010 %        X
0011 %
0012 %   subject to
0013 %
0014 %       G(X) = 0            (nonlinear equalities)
0015 %       H(X) <= 0           (nonlinear inequalities)
0016 %       L <= A*X <= U       (linear constraints)
0017 %       XMIN <= X <= XMAX   (variable bounds)
0018 %
0019 %   Inputs (all optional except F_FCN and X0):
0020 %       F_FCN : handle to function that evaluates the objective function,
0021 %           its gradients and Hessian for a given value of X. If there
0022 %           are nonlinear constraints, the Hessian information is
0023 %           provided by the HESS_FCN function passed in the 9th argument
0024 %           and is not required here. Calling syntax for this function:
0025 %               [F, DF, D2F] = F_FCN(X)
0026 %       X0 : starting value of optimization vector X
0027 %       A, L, U : define the optional linear constraints. Default
0028 %           values for the elements of L and U are -Inf and Inf,
0029 %           respectively.
0030 %       XMIN, XMAX : optional lower and upper bounds on the
0031 %           X variables, defaults are -Inf and Inf, respectively.
0032 %       GH_FCN : handle to function that evaluates the optional
0033 %           nonlinear constraints and their gradients for a given
0034 %           value of X. Calling syntax for this function is:
0035 %               [H, G, DH, DG] = GH_FCN(X)
0036 %       HESS_FCN : handle to function that computes the Hessian of the
0037 %           Lagrangian for given values of X, lambda and mu, where
0038 %           lambda and mu are the multipliers on the equality and
0039 %           inequality constraints, g and h, respectively. The calling
0040 %           syntax for this function is:
0041 %               LXX = HESS_FCN(X, LAM)
0042 %           where lambda = LAM.eqnonlin and mu = LAM.ineqnonlin.
0043 %       OPT : optional options structure with the following fields,
0044 %           all of which are also optional (default values shown in
0045 %           parentheses)
0046 %           verbose (0) - controls level of progress output displayed
0047 %           linsolver ('') - linear system solver for solving update steps
0048 %               ''          = default solver (currently same as '\')
0049 %               '\'         = built-in \ operator
0050 %               'PARDISO'   = PARDISO solver (if available)
0051 %           feastol (1e-6) - termination tolerance for feasibility
0052 %               condition
0053 %           gradtol (1e-6) - termination tolerance for gradient
0054 %               condition
0055 %           comptol (1e-6) - termination tolerance for complementarity
0056 %               condition
0057 %           costtol (1e-6) - termination tolerance for cost condition
0058 %           max_it (150) - maximum number of iterations
0059 %           step_control (0) - set to 1 to enable step-size control
0060 %           sc.red_it (20) - maximum number of step-size reductions if
0061 %               step-control is on
0062 %           cost_mult (1) - cost multiplier used to scale the objective
0063 %               function for improved conditioning. Note: This value is
0064 %               also passed as the 3rd argument to the Hessian evaluation
0065 %               function so that it can appropriately scale the
0066 %               objective function term in the Hessian of the
0067 %               Lagrangian.
0068 %           xi (0.99995) - constant used in alpha updates*
0069 %           sigma (0.1) - centering parameter*
0070 %           z0 (1) - used to initialize slack variables*
0071 %           alpha_min (1e-8) - returns EXITFLAG = -1 if either alpha
0072 %               parameter becomes smaller than this value*
0073 %           rho_min (0.95) - lower bound on rho_t*
0074 %           rho_max (1.05) - upper bound on rho_t*
0075 %           mu_threshold (1e-5) - KT multipliers smaller than this value
0076 %               for non-binding constraints are forced to zero
0077 %           max_stepsize (1e10) - returns EXITFLAG = -1 if the 2-norm of
0078 %               the reduced Newton step exceeds this value*
0079 %               * see the corresponding Appendix in the manual for details
0080 %       PROBLEM : The inputs can alternatively be supplied in a single
0081 %           PROBLEM struct with fields corresponding to the input arguments
0082 %           described above: f_fcn, x0, A, l, u, xmin, xmax,
0083 %                            gh_fcn, hess_fcn, opt
0084 %
0085 %   Outputs:
0086 %       X : solution vector
0087 %       F : final objective function value
0088 %       EXITFLAG : exit flag
0089 %           1 = first order optimality conditions satisfied
0090 %           0 = maximum number of iterations reached
0091 %           -1 = numerically failed
0092 %       OUTPUT : output struct with fields:
0093 %           iterations - number of iterations performed
0094 %           hist - struct array with trajectories of the following:
0095 %                   feascond, gradcond, compcond, costcond, gamma,
0096 %                   stepsize, obj, alphap, alphad
0097 %           message - exit message
0098 %       LAMBDA : struct containing the Langrange and Kuhn-Tucker
0099 %           multipliers on the constraints, with fields:
0100 %           eqnonlin - nonlinear equality constraints
0101 %           ineqnonlin - nonlinear inequality constraints
0102 %           mu_l - lower (left-hand) limit on linear constraints
0103 %           mu_u - upper (right-hand) limit on linear constraints
0104 %           lower - lower bound on optimization variables
0105 %           upper - upper bound on optimization variables
0106 %
0107 %   Note the calling syntax is almost identical to that of FMINCON
0108 %   from MathWorks' Optimization Toolbox. The main difference is that
0109 %   the linear constraints are specified with A, L, U instead of
0110 %   A, B, Aeq, Beq. The functions for evaluating the objective
0111 %   function, constraints and Hessian are identical.
0112 %
0113 %   Calling syntax options:
0114 %       [x, f, exitflag, output, lambda] = ...
0115 %           mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt);
0116 %
0117 %       x = mips(f_fcn, x0);
0118 %       x = mips(f_fcn, x0, A, l);
0119 %       x = mips(f_fcn, x0, A, l, u);
0120 %       x = mips(f_fcn, x0, A, l, u, xmin);
0121 %       x = mips(f_fcn, x0, A, l, u, xmin, xmax);
0122 %       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn);
0123 %       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn);
0124 %       x = mips(f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt);
0125 %       x = mips(problem);
0126 %               where problem is a struct with fields:
0127 %                   f_fcn, x0, A, l, u, xmin, xmax, gh_fcn, hess_fcn, opt
0128 %                   all fields except 'f_fcn' and 'x0' are optional
0129 %       x = mips(...);
0130 %       [x, f] = mips(...);
0131 %       [x, f, exitflag] = mips(...);
0132 %       [x, f, exitflag, output] = mips(...);
0133 %       [x, f, exitflag, output, lambda] = mips(...);
0134 %
0135 %   Example: (problem from https://en.wikipedia.org/wiki/Nonlinear_programming)
0136 %       function [f, df, d2f] = f2(x)
0137 %       f = -x(1)*x(2) - x(2)*x(3);
0138 %       if nargout > 1           %% gradient is required
0139 %           df = -[x(2); x(1)+x(3); x(2)];
0140 %           if nargout > 2       %% Hessian is required
0141 %               d2f = -[0 1 0; 1 0 1; 0 1 0];   %% actually not used since
0142 %           end                                 %% 'hess_fcn' is provided
0143 %       end
0144 %
0145 %       function [h, g, dh, dg] = gh2(x)
0146 %       h = [ 1 -1 1; 1 1 1] * x.^2 + [-2; -10];
0147 %       dh = 2 * [x(1) x(1); -x(2) x(2); x(3) x(3)];
0148 %       g = []; dg = [];
0149 %
0150 %       function Lxx = hess2(x, lam, cost_mult)
0151 %       if nargin < 3, cost_mult = 1; end
0152 %       mu = lam.ineqnonlin;
0153 %       Lxx = cost_mult * [0 -1 0; -1 0 -1; 0 -1 0] + ...
0154 %               [2*[1 1]*mu 0 0; 0 2*[-1 1]*mu 0; 0 0 2*[1 1]*mu];
0155 %
0156 %       problem = struct( ...
0157 %           'f_fcn',    @(x)f2(x), ...
0158 %           'gh_fcn',   @(x)gh2(x), ...
0159 %           'hess_fcn', @(x, lam, cost_mult)hess2(x, lam, cost_mult), ...
0160 %           'x0',       [1; 1; 0], ...
0161 %           'opt',      struct('verbose', 2) ...
0162 %       );
0163 %       [x, f, exitflag, output, lambda] = mips(problem);
0164 %
0165 %   Ported by Ray Zimmerman from C code written by H. Wang for his
0166 %   PhD dissertation:
0167 %     "On the Computation and Application of Multi-period
0168 %     Security-Constrained Optimal Power Flow for Real-time
0169 %     Electricity Market Operations", Cornell University, May 2007.
0170 %
0171 %   See also:
0172 %     H. Wang, C. E. Murillo-Sanchez, R. D. Zimmerman, R. J. Thomas,
0173 %     "On Computational Issues of Market-Based Optimal Power Flow",
0174 %     IEEE Transactions on Power Systems, Vol. 22, No. 3, Aug. 2007,
0175 %     pp. 1185-1193.
0176 
0177 %   MIPS
0178 %   Copyright (c) 2009-2018, Power Systems Engineering Research Center (PSERC)
0179 %   by Ray Zimmerman, PSERC Cornell
0180 %
0181 %   This file is part of MIPS.
0182 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0183 %   See https://github.com/MATPOWER/mips for more info.
0184 
0185 %%----- input argument handling  -----
0186 %% gather inputs
0187 if nargin == 1 && isstruct(f_fcn)       %% problem struct
0188     p = f_fcn;
0189     f_fcn = p.f_fcn;
0190     x0 = p.x0;
0191     nx = size(x0, 1);       %% number of optimization variables
0192     if isfield(p, 'opt'),       opt = p.opt;            else,   opt = [];       end
0193     if isfield(p, 'hess_fcn'),  hess_fcn = p.hess_fcn;  else,   hess_fcn = '';  end
0194     if isfield(p, 'gh_fcn'),    gh_fcn = p.gh_fcn;      else,   gh_fcn = '';    end
0195     if isfield(p, 'xmax'),      xmax = p.xmax;          else,   xmax = [];      end
0196     if isfield(p, 'xmin'),      xmin = p.xmin;          else,   xmin = [];      end
0197     if isfield(p, 'u'),         u = p.u;                else,   u = [];         end
0198     if isfield(p, 'l'),         l = p.l;                else,   l = [];         end
0199     if isfield(p, 'A'),         A = p.A;                else,   A=sparse(0,nx); end
0200 else                                    %% individual args
0201     nx = size(x0, 1);       %% number of optimization variables
0202     if nargin < 10
0203         opt = [];
0204         if nargin < 9
0205             hess_fcn = '';
0206             if nargin < 8
0207                 gh_fcn = '';
0208                 if nargin < 7
0209                     xmax = [];
0210                     if nargin < 6
0211                         xmin = [];
0212                         if nargin < 5
0213                             u = [];
0214                             if nargin < 4
0215                                 l = [];
0216                                 A = sparse(0,nx);
0217                             end
0218                         end
0219                     end
0220                 end
0221             end
0222         end
0223     end
0224 end
0225 %% set default argument values if missing
0226 if isempty(A) || (~isempty(A) && (isempty(l) || all(l == -Inf)) && ...
0227                                  (isempty(u) || all(u == Inf)))
0228     A = sparse(0,nx);           %% no limits => no linear constraints
0229 end
0230 nA = size(A, 1);                %% number of original linear constraints
0231 if isempty(u)                   %% By default, linear inequalities are ...
0232     u = Inf(nA, 1);             %% ... unbounded above and ...
0233 end
0234 if isempty(l)
0235     l = -Inf(nA, 1);            %% ... unbounded below.
0236 end
0237 if isempty(xmin)                %% By default, optimization variables are ...
0238     xmin = -Inf(nx, 1);         %% ... unbounded below and ...
0239 end
0240 if isempty(xmax)
0241     xmax = Inf(nx, 1);          %% ... unbounded above.
0242 end
0243 if isempty(gh_fcn)
0244     nonlinear = false;          %% no nonlinear constraints present
0245     gn = []; hn = [];
0246 else
0247     nonlinear = true;           %% we have some nonlinear constraints
0248 end
0249 
0250 %% default options
0251 if isempty(opt)
0252     opt = struct('verbose', 0);
0253 end
0254 if ~isfield(opt, 'linsolver') || isempty(opt.linsolver)
0255     opt.linsolver = '';
0256 end
0257 if ~isfield(opt, 'feastol') || isempty(opt.feastol) || opt.feastol == 0
0258     opt.feastol = 1e-6;
0259 end
0260 if ~isfield(opt, 'gradtol') || isempty(opt.gradtol) || opt.gradtol == 0
0261     opt.gradtol = 1e-6;
0262 end
0263 if ~isfield(opt, 'comptol') || isempty(opt.comptol) || opt.comptol == 0
0264     opt.comptol = 1e-6;
0265 end
0266 if ~isfield(opt, 'costtol') || isempty(opt.costtol) || opt.costtol == 0
0267     opt.costtol = 1e-6;
0268 end
0269 if ~isfield(opt, 'max_it') || isempty(opt.max_it)
0270     opt.max_it = 150;
0271 end
0272 if ~isfield(opt, 'sc') || ~isfield(opt.sc, 'red_it') || isempty(opt.sc.red_it)
0273     opt.sc.red_it = 20;
0274 end
0275 if ~isfield(opt, 'step_control') || isempty(opt.step_control)
0276     opt.step_control = 0;
0277 end
0278 if ~isfield(opt, 'cost_mult') || isempty(opt.cost_mult)
0279     opt.cost_mult = 1;
0280 end
0281 if ~isfield(opt, 'verbose') || isempty(opt.verbose)
0282     opt.verbose = 0;
0283 end
0284 %% algorithm constants
0285 if ~isfield(opt, 'xi') || isempty(opt.xi)
0286     opt.xi = 0.99995;           %% OPT_IPM_PHI
0287 end
0288 if ~isfield(opt, 'sigma') || isempty(opt.sigma)
0289     opt.sigma = 0.1;            %% OPT_IPM_SIGMA, centering parameter
0290 end
0291 if ~isfield(opt, 'z0') || isempty(opt.z0)
0292     opt.z0 = 1;                 %% OPT_IPM_INIT_SLACK
0293 end
0294 if ~isfield(opt, 'alpha_min') || isempty(opt.alpha_min)
0295     opt.alpha_min = 1e-8;       %% OPT_AP_AD_MIN
0296 end
0297 if ~isfield(opt, 'rho_min') || isempty(opt.rho_min)
0298     opt.rho_min = 0.95;         %% OPT_IPM_QUAD_LOWTHRESH
0299 end
0300 if ~isfield(opt, 'rho_max') || isempty(opt.rho_max)
0301     opt.rho_max = 1.05;         %% OPT_IPM_QUAD_HIGHTHRESH
0302 end
0303 if ~isfield(opt, 'mu_threshold') || isempty(opt.mu_threshold)
0304     opt.mu_threshold = 1e-5;    %% SCOPF_MULTIPLIERS_FILTER_THRESH
0305 end
0306 if ~isfield(opt, 'max_stepsize') || isempty(opt.max_stepsize)
0307     opt.max_stepsize = 1e10;
0308 end
0309 
0310 %% initialize history
0311 hist(opt.max_it+1) = struct('feascond', 0, 'gradcond', 0, 'compcond', 0, ...
0312     'costcond', 0, 'gamma', 0, 'stepsize', 0, 'obj', 0, ...
0313     'alphap', 0, 'alphad', 0);
0314 
0315 %%-----  set up problem  -----
0316 %% constants
0317 [xi, sigma, z0, alpha_min, rho_min, rho_max, mu_threshold, max_stepsize] = ...
0318     deal(opt.xi, opt.sigma, opt.z0, opt.alpha_min, ...
0319         opt.rho_min, opt.rho_max, opt.mu_threshold, opt.max_stepsize);
0320 if xi >= 1 || xi < 0.5
0321     error('mips: opt.xi (%g) must be a number slightly less than 1', opt.xi);
0322 end
0323 if sigma > 1 || sigma <= 0
0324     error('mips: opt.sigma (%g) must be a number between 0 and 1', opt.sigma);
0325 end
0326 
0327 %% initialize
0328 i = 0;                      %% iteration counter
0329 converged = 0;              %% flag
0330 eflag = 0;                  %% exit flag
0331 
0332 %% add var limits to linear constraints
0333 AA = [speye(nx); A];
0334 ll = [xmin; l];
0335 uu = [xmax; u];
0336 
0337 %% split up linear constraints
0338 ieq = find( abs(uu-ll) <= eps );            %% equality
0339 igt = find( uu >=  1e10 & ll > -1e10 );     %% greater than, unbounded above
0340 ilt = find( ll <= -1e10 & uu <  1e10 );     %% less than, unbounded below
0341 ibx = find( (abs(uu-ll) > eps) & (uu < 1e10) & (ll > -1e10) );
0342 Ae = AA(ieq, :);
0343 be = uu(ieq, 1);
0344 Ai  = [ AA(ilt, :); -AA(igt, :); AA(ibx, :); -AA(ibx, :) ];
0345 bi  = [ uu(ilt, 1); -ll(igt, 1); uu(ibx, 1); -ll(ibx, 1) ];
0346 
0347 %% evaluate cost f(x0) and constraints g(x0), h(x0)
0348 x = x0;
0349 [f, df] = f_fcn(x);             %% cost
0350 f = f * opt.cost_mult;
0351 df = df * opt.cost_mult;
0352 if nonlinear
0353     [hn, gn, dhn, dgn] = gh_fcn(x); %% nonlinear constraints
0354     h = [hn; Ai * x - bi];          %% inequality constraints
0355     g = [gn; Ae * x - be];          %% equality constraints
0356     dh = [dhn Ai'];                 %% 1st derivative of inequalities
0357     dg = [dgn Ae'];                 %% 1st derivative of equalities
0358 else
0359     h = Ai * x - bi;                %% inequality constraints
0360     g = Ae * x - be;                %% equality constraints
0361     dh = Ai';                       %% 1st derivative of inequalities
0362     dg = Ae';                       %% 1st derivative of equalities
0363 end
0364 
0365 %% grab some dimensions
0366 neq = size(g, 1);           %% number of equality constraints
0367 niq = size(h, 1);           %% number of inequality constraints
0368 neqnln = size(gn, 1);       %% number of nonlinear equality constraints
0369 niqnln = size(hn, 1);       %% number of nonlinear inequality constraints
0370 nlt = length(ilt);          %% number of upper bounded linear inequalities
0371 ngt = length(igt);          %% number of lower bounded linear inequalities
0372 nbx = length(ibx);          %% number of doubly bounded linear inequalities
0373 
0374 %% initialize gamma, lam, mu, z, e
0375 gamma = 1;                  %% barrier coefficient, r in Harry's code
0376 lam = zeros(neq, 1);
0377 z   = z0 * ones(niq, 1);
0378 mu  = z;
0379 k = find(h < -z0);
0380 z(k) = -h(k);
0381 k = find(gamma / z > z0);   %% (seems k is always empty if gamma = z0 = 1)
0382 if ~isempty(k)
0383     mu(k) = gamma / z(k);
0384 end
0385 e = ones(niq, 1);
0386 
0387 %% check tolerance
0388 f0 = f;
0389 if opt.step_control
0390     L = f + lam' * g + mu' * (h+z) - gamma * sum(log(z));
0391 end
0392 Lx = df + dg * lam + dh * mu;
0393 if isempty(h)
0394     maxh = zeros(1,0);
0395 else
0396     maxh = max(h);
0397 end
0398 feascond = max([norm(g, Inf), maxh]) / (1 + max([ norm(x, Inf), norm(z, Inf) ]));
0399 gradcond = norm(Lx, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ]));
0400 compcond = (z' * mu) / (1 + norm(x, Inf));
0401 costcond = abs(f - f0) / (1 + abs(f0));
0402 %% save history
0403 hist(i+1) = struct('feascond', feascond, 'gradcond', gradcond, ...
0404     'compcond', compcond, 'costcond', costcond, 'gamma', gamma, ...
0405     'stepsize', 0, 'obj', f/opt.cost_mult, 'alphap', 0, 'alphad', 0);
0406 if strcmp(upper(opt.linsolver), 'PARDISO')
0407     ls = 'PARDISO';
0408     mplinsolve_opt = struct('pardiso', ...
0409                             struct('mtype', -2, ...
0410                                    'iparm', [8, 1;  %% max it refinement steps
0411                                              10, 12;%% eps pivot
0412                                              11, 1; %% use scaling vectors
0413                                              13, 2; %% improved accuracy
0414                                              18, 0; %% do not determine nnz in LU
0415                                              21, 3; %% ? undocumented pivoting
0416                                              ] ));
0417     if ~have_fcn('pardiso')
0418         warning('mips: PARDISO linear solver not available, using default');
0419         opt.linsolver = '';
0420         ls = 'built-in';
0421     end
0422 else
0423     ls = 'built-in';
0424     mplinsolve_opt = [];
0425 end
0426 if opt.verbose
0427     if opt.step_control, s = '-sc'; else, s = ''; end
0428     v = mipsver('all');
0429     fprintf('MATPOWER Interior Point Solver -- MIPS%s, Version %s, %s\n (using %s linear solver)', ...
0430         s, v.Version, v.Date, ls);
0431     if opt.verbose > 1
0432         fprintf('\n it    objective   step size   feascond     gradcond     compcond     costcond  ');
0433         fprintf('\n----  ------------ --------- ------------ ------------ ------------ ------------');
0434         fprintf('\n%3d  %12.8g %10s %12g %12g %12g %12g', ...
0435             i, f/opt.cost_mult, '', feascond, gradcond, compcond, costcond);
0436     end
0437 end
0438 if feascond < opt.feastol && gradcond < opt.gradtol && ...
0439                 compcond < opt.comptol && costcond < opt.costtol
0440     converged = 1;
0441     if opt.verbose
0442         fprintf('\nConverged!\n');
0443     end
0444 end
0445 
0446 %%-----  do Newton iterations  -----
0447 while (~converged && i < opt.max_it)
0448     %% update iteration counter
0449     i = i + 1;
0450 
0451     %% compute update step
0452     lambda = struct('eqnonlin', lam(1:neqnln), 'ineqnonlin', mu(1:niqnln));
0453     if nonlinear
0454         if isempty(hess_fcn)
0455             fprintf('mips: Hessian evaluation via finite differences not yet implemented.\n       Please provide your own hessian evaluation function.');
0456         end
0457         Lxx = hess_fcn(x, lambda, opt.cost_mult);
0458     else
0459         [f_, df_, d2f] = f_fcn(x);      %% cost
0460         Lxx = d2f * opt.cost_mult;
0461     end
0462     zinvdiag = sparse(1:niq, 1:niq, 1 ./ z, niq, niq);
0463     mudiag = sparse(1:niq, 1:niq, mu, niq, niq);
0464     dh_zinv = dh * zinvdiag;
0465     M = Lxx + dh_zinv * mudiag * dh';
0466     N = Lx + dh_zinv * (mudiag * h + gamma * e);
0467     dxdlam = mplinsolve([M dg; dg' sparse(neq, neq)], [-N; -g], opt.linsolver, mplinsolve_opt);
0468 %     AAA = [
0469 %         M  dg;
0470 %         dg'  sparse(neq, neq)
0471 %     ];
0472 %     rc = 1/condest(AAA);
0473 %     if rc < 1e-22
0474 %         fprintf('my RCOND = %g\n', rc);
0475 %         n = size(AAA, 1);
0476 %         AAA = AAA + 1e-3 * speye(n,n);
0477 %     end
0478 %     bbb = [-N; -g];
0479 %     dxdlam = AAA \ bbb;
0480     if any(isnan(dxdlam)) || norm(dxdlam) > max_stepsize
0481         if opt.verbose
0482             fprintf('\nNumerically Failed\n');
0483         end
0484         eflag = -1;
0485         break;
0486     end
0487     dx = dxdlam(1:nx, 1);
0488     dlam = dxdlam(nx+(1:neq), 1);
0489     dz = -h - z - dh' * dx;
0490     dmu = -mu + zinvdiag *(gamma*e - mudiag * dz);
0491 
0492     %% optional step-size control
0493     sc = 0;
0494     if opt.step_control
0495         x1 = x + dx;
0496 
0497         %% evaluate cost, constraints, derivatives at x1
0498         [f1, df1] = f_fcn(x1);          %% cost
0499         f1 = f1 * opt.cost_mult;
0500         df1 = df1 * opt.cost_mult;
0501         if nonlinear
0502             [hn1, gn1, dhn1, dgn1] = gh_fcn(x1); %% nonlinear constraints
0503             h1 = [hn1; Ai * x1 - bi];       %% inequality constraints
0504             g1 = [gn1; Ae * x1 - be];       %% equality constraints
0505             dh1 = [dhn1 Ai'];               %% 1st derivative of inequalities
0506             dg1 = [dgn1 Ae'];               %% 1st derivative of equalities
0507         else
0508             h1 = Ai * x1 - bi;              %% inequality constraints
0509             g1 = Ae * x1 - be;              %% equality constraints
0510             dh1 = dh;                       %% 1st derivative of inequalities
0511             dg1 = dg;                       %% 1st derivative of equalities
0512         end
0513 
0514         %% check tolerance
0515         Lx1 = df1 + dg1 * lam + dh1 * mu;
0516         if isempty(h1)
0517             maxh1 = zeros(1,0);
0518         else
0519             maxh1 = max(h1);
0520         end
0521         feascond1 = max([norm(g1, Inf), maxh1]) / (1 + max([ norm(x1, Inf), norm(z, Inf) ]));
0522         gradcond1 = norm(Lx1, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ]));
0523 
0524         if feascond1 > feascond && gradcond1 > gradcond
0525             sc = 1;
0526         end
0527     end
0528     if sc
0529         alpha = 1;
0530         for j = 1:opt.sc.red_it
0531             dx1 = alpha * dx;
0532             x1 = x + dx1;
0533             f1 = f_fcn(x1);                 %% cost
0534             f1 = f1 * opt.cost_mult;
0535             if nonlinear
0536                 [hn1, gn1] = gh_fcn(x1);    %% nonlinear constraints
0537                 h1 = [hn1; Ai * x1 - bi];   %% inequality constraints
0538                 g1 = [gn1; Ae * x1 - be];   %% equality constraints
0539             else
0540                 h1 = Ai * x1 - bi;          %% inequality constraints
0541                 g1 = Ae * x1 - be;          %% equality constraints
0542             end
0543             L1 = f1 + lam' * g1 + mu' * (h1+z) - gamma * sum(log(z));
0544             if opt.verbose > 2
0545                 fprintf('\n   %3d            %10g', -j, norm(dx1));
0546             end
0547             rho = (L1 - L) / (Lx' * dx1 + 0.5 * dx1' * Lxx * dx1);
0548             if rho > rho_min && rho < rho_max
0549                 break;
0550             else
0551                 alpha = alpha / 2;
0552             end
0553         end
0554         dx = alpha * dx;
0555         dz = alpha * dz;
0556         dlam = alpha * dlam;
0557         dmu = alpha * dmu;
0558     end
0559 
0560     %% do the update
0561     k = find(dz < 0);
0562     if isempty(k)
0563         alphap = 1;
0564     else
0565         alphap = min( [xi * min(z(k) ./ -dz(k)) 1] );
0566     end
0567     k = find(dmu < 0);
0568     if isempty(k)
0569         alphad = 1;
0570     else
0571         alphad = min( [xi * min(mu(k) ./ -dmu(k)) 1] );
0572     end
0573     x = x + alphap * dx;
0574     z = z + alphap * dz;
0575     lam = lam + alphad * dlam;
0576     mu  = mu  + alphad * dmu;
0577     if niq > 0
0578         gamma = sigma * (z' * mu) / niq;
0579     end
0580 
0581     %% evaluate cost, constraints, derivatives
0582     [f, df] = f_fcn(x);                 %% cost
0583     f = f * opt.cost_mult;
0584     df = df * opt.cost_mult;
0585     if nonlinear
0586         [hn, gn, dhn, dgn] = gh_fcn(x); %% nonlinear constraints
0587         h = [hn; Ai * x - bi];          %% inequality constraints
0588         g = [gn; Ae * x - be];          %% equality constraints
0589         dh = [dhn Ai'];                 %% 1st derivative of inequalities
0590         dg = [dgn Ae'];                 %% 1st derivative of equalities
0591     else
0592         h = Ai * x - bi;                %% inequality constraints
0593         g = Ae * x - be;                %% equality constraints
0594         %% 1st derivatives are constant, still dh = Ai', dg = Ae'
0595     end
0596 
0597     %% check tolerance
0598     Lx = df + dg * lam + dh * mu;
0599     if isempty(h)
0600         maxh = zeros(1,0);
0601     else
0602         maxh = max(h);
0603     end
0604     feascond = max([norm(g, Inf), maxh]) / (1 + max([ norm(x, Inf), norm(z, Inf) ]));
0605     gradcond = norm(Lx, Inf) / (1 + max([ norm(lam, Inf), norm(mu, Inf) ]));
0606     compcond = (z' * mu) / (1 + norm(x, Inf));
0607     costcond = abs(f - f0) / (1 + abs(f0));
0608     %% save history
0609     hist(i+1) = struct('feascond', feascond, 'gradcond', gradcond, ...
0610         'compcond', compcond, 'costcond', costcond, 'gamma', gamma, ...
0611         'stepsize', norm(dx), 'obj', f/opt.cost_mult, ...
0612         'alphap', alphap, 'alphad', alphad);
0613 
0614     if opt.verbose > 1
0615         fprintf('\n%3d  %12.8g %10.5g %12g %12g %12g %12g', ...
0616             i, f/opt.cost_mult, norm(dx), feascond, gradcond, compcond, costcond);
0617     end
0618     if feascond < opt.feastol && gradcond < opt.gradtol && ...
0619                     compcond < opt.comptol && costcond < opt.costtol
0620         converged = 1;
0621         if opt.verbose
0622             fprintf('\nConverged!\n');
0623         end
0624     else
0625         if any(isnan(x)) || alphap < alpha_min || alphad < alpha_min || ...
0626                 gamma < eps || gamma > 1/eps
0627             if opt.verbose
0628                 fprintf('\nNumerically Failed\n');
0629             end
0630             eflag = -1;
0631             break;
0632         end
0633         f0 = f;
0634         if opt.step_control
0635             L = f + lam' * g + mu' * (h+z) - gamma * sum(log(z));
0636         end
0637     end
0638 end
0639 
0640 if opt.verbose
0641     if ~converged
0642         fprintf('\nDid not converge in %d iterations.\n', i);
0643     end
0644 end
0645 
0646 %%-----  package up results  -----
0647 hist = hist(1:i+1);
0648 if eflag ~= -1
0649     eflag = converged;
0650 end
0651 output = struct('iterations', i, 'hist', hist, 'message', '');
0652 if eflag == 0
0653     output.message = 'Did not converge';
0654 elseif eflag == 1
0655     output.message = 'Converged';
0656 elseif eflag == -1
0657     output.message = 'Numerically failed';
0658 else
0659     output.message = 'Please hang up and dial again';
0660 end
0661 
0662 %% zero out multipliers on non-binding constraints
0663 mu(h < -opt.feastol & mu < mu_threshold) = 0;
0664 
0665 %% un-scale cost and prices
0666 f   = f   / opt.cost_mult;
0667 lam = lam / opt.cost_mult;
0668 mu  = mu  / opt.cost_mult;
0669 
0670 %% re-package multipliers into struct
0671 lam_lin = lam((neqnln+1):neq);              %% lambda for linear constraints
0672 mu_lin  = mu((niqnln+1):niq);               %% mu for linear constraints
0673 kl = find(lam_lin < 0);                     %% lower bound binding
0674 ku = find(lam_lin > 0);                     %% upper bound binding
0675 
0676 mu_l = zeros(nx+nA, 1);
0677 mu_l(ieq(kl)) = -lam_lin(kl);
0678 mu_l(igt) = mu_lin(nlt+(1:ngt));
0679 mu_l(ibx) = mu_lin(nlt+ngt+nbx+(1:nbx));
0680 
0681 mu_u = zeros(nx+nA, 1);
0682 mu_u(ieq(ku)) = lam_lin(ku);
0683 mu_u(ilt) = mu_lin(1:nlt);
0684 mu_u(ibx) = mu_lin(nlt+ngt+(1:nbx));
0685 
0686 fields = { ...
0687     'mu_l', mu_l((nx+1):end), ...
0688     'mu_u', mu_u((nx+1):end), ...
0689     'lower', mu_l(1:nx), ...
0690     'upper', mu_u(1:nx) ...
0691 };
0692 
0693 if niqnln > 0
0694     fields = { ...
0695         'ineqnonlin', mu(1:niqnln), ...
0696         fields{:} ...
0697     };
0698 end
0699 if neqnln > 0
0700     fields = { ...
0701         'eqnonlin', lam(1:neqnln), ...
0702         fields{:} ...
0703     };
0704 end
0705 
0706 lambda = struct(fields{:});
0707 
0708 % lambda = struct( ...
0709 %     'eqnonlin', lam(1:neqnln), ...
0710 %     'ineqnonlin', mu(1:niqnln), ...
0711 %     'mu_l', mu_l((nx+1):end), ...
0712 %     'mu_u', mu_u((nx+1):end), ...
0713 %     'lower', mu_l(1:nx), ...
0714 %     'upper', mu_u(1:nx) );

Generated on Mon 24-Jun-2019 15:58:45 by m2html © 2005