www.gusucode.com > optim 工具箱 matlab 源码程序 > optim/private/sqpbox.m

    function [x,val,csnrm,it,npcg,exitflag,LAMBDA,msg] = sqpbox(c,H,mtxmpy,l,u,xstart,options,defaultopt,...
    numberOfVariables,verb,computeLambda,varargin)
%SQPBOX Minimize box-constrained quadratic function
%
%   Locate a (local) solution to the box-constrained QP:
%
%        min { q(x) = .5x'Hx + c'x :  l <= x <= u}.
%
%   where H is sparse symmetric, c is a col vector,
%   l,u are vectors of lower and upper bounds respectively.

%   Copyright 1990-2015 The MathWorks, Inc.

% Retrieving options

% Add Preconditioner to defaultopt. This is not a documented option for quadprog, 
% and is not added to defaultopt at the user-facing function level.
defaultopt.Preconditioner = @hprecon;

pcmtx = optimget(options,'Preconditioner',defaultopt,'fast');
kmax = optimget(options,'MaxPCGIter',defaultopt,'fast');
typx = optimget(options,'TypicalX',defaultopt,'fast');
if ischar(kmax)
    if isequal(lower(kmax),'max(1,floor(numberofvariables/2))')
        kmax = max(1,floor(numberOfVariables/2));
    elseif isequal(lower(kmax),'numberofvariables')
        kmax = numberOfVariables;
    else
        error(message('optim:sqpbox:InvalidMaxPCGIter'))
    end
end
if ischar(typx)
    if isequal(lower(typx),'ones(numberofvariables,1)')
        typx = ones(numberOfVariables,1);
    else
        error(message('optim:sqpbox:InvalidTypicalX'))
    end
end
checkoptionsize('TypicalX', size(typx), numberOfVariables);
pcflags = optimget(options,'PrecondBandWidth',defaultopt,'fast') ;
tolx = optimget(options,'TolX',defaultopt,'fast') ;
tolfun = optimget(options,'TolFun',defaultopt,'fast');
tolfunvalue = optimget(options,'TolFunValue',defaultopt,'fast');
pcgtol = optimget(options,'TolPCG',defaultopt,'fast') ;  % pcgtol = .1;
itb = optimget(options,'MaxIter',defaultopt,'fast') ;

%   INITIALIZATIONS
if nargin <= 1
    error(message('optim:sqpbox:NotEnoughInputs'))
end
n = length(c);
it = 0;
cvec = c;

if n == 0
    error(message('optim:sqpbox:InvalidN'))
end
if nargin <= 2
    l = -inf*ones(n,1);
end
if nargin <= 3,
    u = inf*ones(n,1);
end
if isempty(l),
    l = -inf*ones(n,1);
end
if isempty(u),
    u = inf*ones(n,1);
end
arg = (u >= 1e10);
arg2 = (l <= -1e10);
u(arg) = inf;
l(arg2) = -inf;
if min(u-l) <= 0
    error(message('optim:sqpbox:InconsistentBnds'))
end
lvec = l; uvec = u;

pcgit = 0;
tolfun2 = sqrt(tolfunvalue);
[xstart,l,u,ds,DS,c] = shiftsc(xstart,l,u,typx,'sqpbox',mtxmpy,cvec,H,varargin{:});
dellow = 1.;
delup = 10^3;
npcg = 0;
digits = inf;
done = false;
v = zeros(n,1);
dv = ones(n,1);
del = 10*eps;
posdef = 1;
x = xstart;
y = x;
sigma = ones(n,1);
g = zeros(n,1);
oval = inf;
prev_diff = 0;
[val,g] = fquad(x,c,H,'sqpbox',mtxmpy,DS,varargin{:});
[v,dv] = definev(g,x,l,u);
csnrm = norm(v.*g,inf);
if csnrm == 0
    % If initial point is a 1st order point then randomly perturb the
    % initial point a little while keeping it feasible and reinitialize.
    dir = zeros(n,1);
    pos = u-x > x-l;
    neg = u-x <= x-l;
    dir(pos) = 1; dir(neg) = -1;
    % Get random noise, but "put it back" so we don't affect anyone
    dflt = RandStream.getGlobalStream;
    randstate = dflt.State;
    x = x + dir.*rand(n,1).*max(u-x,x-l).*1e-1;
    dflt.State = randstate;
    y = x;
    [val,g] = fquad(x,c,H,'sqpbox',mtxmpy,DS,varargin{:});
end

%
%   MAIN LOOP: GENERATE FEAS. SEQ.  x(it) S.T. q(x(it)) IS DECREASING.
while ~done
    it = it + 1;
    %     Update and display
    [v,dv] = definev(g,x,l,u);
    csnrm = norm(v.*g,inf);
    r = abs(min(u-x,x-l));
    
    delta = max(dellow,norm(v));
    delta = min(delta,delup);

    %
    %     TEST FOR CONVERGENCE
    diff = abs(oval-val);
    if it > 1,
        digits = (prev_diff)/max(diff,eps);
    end
    prev_diff = diff;
    oval = val;
    if diff < tolfunvalue*(1+abs(oval)),
        exitflag = 3; done = true;
        msg = sprintf(['Optimization terminated: relative function value changing by\n' ...
            ' less than OPTIONS.FunctionTolerance.']);
        if verb > 0
            disp(msg)
        end
    elseif ((diff < tolfun2*(1+abs(oval))) & (digits < 3.5)) & posdef,
        exitflag = 3; done = true;
        msg = sprintf(['Optimization terminated: relative function value changing by less\n' ...
            ' than sqrt(OPTIONS.FunctionTolerance), no negative curvature detected in current\n' ...
            ' trust region model and the rate of progress (change in f(x)) is slow.']);
        if verb > 0
            disp(msg)
        end
    elseif ((csnrm < tolfun) & posdef & it > 1),
        exitflag = 1; done = true;
        msg = sprintf(['Optimization terminated: no negative curvature detected in current\n' ...
            ' trust region model and first order optimality measure < OPTIONS.OptimalityTolerance.']);
        if verb > 0
            disp(msg)
        end
    end
    %
    if ~done            
        %       DETERMINE THE SEARCH DIRECTION
        dd = abs(v);
        D = sparse(1:n,1:n,full(sqrt(dd).*sigma));
        grad = D*g;
        normg = norm(grad);     

        [s,posdef,pcgit] = drqpbox(D,DS,grad,delta,g,dv,mtxmpy,...
            pcmtx,pcflags,pcgtol,H,0,kmax,varargin{:});

        npcg = npcg + pcgit;
        %
        %       DO A REFLECTIVE (BISECTION) LINE SEARCH. UPDATE x,y,sigma.
        strg= s'*(sigma.*g);
        ox = x;
        osig = sigma;
        ostrg = strg;
        if strg >= 0,
            exitflag = -2; done = true;
            msg = sprintf(['Optimization terminated: loss of feasibility with respect to the\n' ...
                ' constraints detected.']);
            if verb > 0
                disp(msg);
            end
        else
            [x,sigma,alpha] = biqpbox(s,c,ostrg,ox,y,osig,l,u,oval,posdef,...
                normg,DS,mtxmpy,H,0,varargin{:});
            if alpha == 0,
                exitflag = -4; done = true;
                msg = sprintf(['Optimization terminated: current direction not descent direction;\n' ...
                    ' the problem may be ill-conditioned.']);
                if verb > 0
                    disp(msg)
                end

            end
            y = y + alpha*s;
            %
            %          PERTURB x AND y ?
            [~,x,y] = perturbTrustRegionReflective(x,l,u,del,y,sigma);
            %
            %          EVALUATE NEW FUNCTION VALUE, GRADIENT.
            [val,g] = fquad(x,c,H,'sqpbox',mtxmpy,DS,varargin{:});
        end
        if it >= itb,
            exitflag = 0; done = true;
            msg = sprintf('Maximum number of iterations exceeded; increase options.MaxIterations');
            if verb > 0
                disp(msg)
            end
        end
    end
end

%
%   RESCALE, UNSHIFT, AND EXIT.
x = unshsca(x,lvec,uvec,DS);
% unscaled so leave out DS
[val,g] = fquad(x,cvec,H,'sqpbox',mtxmpy,[],varargin{:});

if computeLambda
    LAMBDA = formBoxLambda(g,lvec,uvec);
else
    LAMBDA = [];
end