📄 qpsub.m
字号:
projSD = pinv(projH)*(-Zgf);
else % LLS
projH = HZ'*HZ;
Zgf = Z'*gf;
projSD = pinv(projH)*(-Zgf);
end
% Check if compatible
if norm(projH*projSD+Zgf) > 10*eps*(norm(projH) + norm(Zgf))
% system is incompatible --> it's a "chute": use SD from compdir
% unbounded in SD direction
if norm(SD) > errnorm
if normalize < 0
STEPMIN=abs((X(numberOfVariables)+1e-5)/(SD(numberOfVariables)+eps));
else
STEPMIN = 1e16;
end
X=X+STEPMIN*SD;
how='unbounded';
% was exitflag = 5;
exitflag = -1;
else % norm(SD) <= errnorm
how = 'ill posed';
%was exitflag = 6;
exitflag = -1;
end
if verbosity > 0
if norm(SD) > errnorm
disp('Exiting: The solution is unbounded and at infinity;')
disp(' the constraints are not restrictive enough.')
else
disp('Exiting: The search direction is close to zero; ')
disp(' the problem is ill-posed.')
disp(' The gradient of the objective function may be zero')
disp(' or the problem may be badly conditioned.')
end
end % if verbosity > 0
output.iterations = iterations;
return
else % Convex -- move to the minimum (compatible system)
SD = Z*projSD;
dirType = 'singular';
% First check if constraint is violated.
GSD=A*SD;
indf = find((GSD > errnorm * norm(SD)) & ~aix);
if isempty(indf) % No constraints to hit
STEPMIN=1;
delete_constr = 1;
dist=[]; ind2=[]; ind=[];
else % Find distance to the nearest constraint
dist = abs(cstr(indf)./GSD(indf));
[STEPMIN,ind2] = min(dist);
ind2 = find(dist == STEPMIN);
% Bland's rule for anti-cycling: if there is more than one
% blocking constraint then add the one with the smallest index.
ind=indf(min(ind2));
end
if STEPMIN > 1 % Overstepped minimum; reset STEPMIN
STEPMIN = 1;
delete_constr = 1;
end
X = X + STEPMIN*SD;
end
end % if ~is_qp | smallRealEig < -eps
end % if strcmp(dirType, NewtonStep)
end % if ~isempty(indf)& isfinite(STEPMIN) % Hit a constraint
if delete_constr
% Note: only reach here if a minimum in the current subspace found
if ACTCNT>0
if ACTCNT>=numberOfVariables-1,
% Avoid case when CIND is greater than ACTCNT
if CIND <= ACTCNT
ACTSET(CIND,:)=[];
ACTIND(CIND)=[];
end
end
if is_qp
rlambda = -R\(Q'*(H*X+f));
elseif LLS
rlambda = -R\(Q'*(H'*(H*X-f)));
% else: lp does not reach this point
end
actlambda = rlambda;
actlambda(eqix) = abs(rlambda(eqix));
indlam = find(actlambda < 0);
if (~length(indlam))
lambda(indepInd(ACTIND)) = normf * (rlambda./normA(ACTIND));
output.iterations = iterations;
return
end
% Remove constraint
lind = find(ACTIND == min(ACTIND(indlam)));
lind=lind(1);
ACTSET(lind,:) = [];
aix(ACTIND(lind)) = 0;
[Q,R]=qrdelete(Q,R,lind);
ACTIND(lind) = [];
ACTCNT = ACTCNT - 2;
simplex_iter = 0;
ind = 0;
else % ACTCNT == 0
output.iterations = iterations;
return
end
delete_constr = 0;
end
% Calculate gradient w.r.t objective at this point
if is_qp
gf=H*X+f;
elseif LLS % LLS
gf=H'*(H*X-f);
% else gf=f still true.
end
% Update X and calculate constraints
cstr = A*X-B;
cstr(eqix) = abs(cstr(eqix));
% Check no constraint is violated
if normalize < 0
if X(numberOfVariables,1) < eps
output.iterations = iterations;
return;
end
end
if max(cstr) > 1e5 * errnorm
if max(cstr) > norm(X) * errnorm
if ( verbosity > 0 ) & ( exitflag == 1 )
disp('Note: The problem is badly conditioned;')
disp(' the solution may not be reliable')
% verbosity = 0;
end
how='unreliable';
% exitflag = 2;
exitflag = -1;
if 0
X=X-STEPMIN*SD;
output.iterations = iterations;
return
end
end
end
if ind % Hit a constraint
aix(ind)=1;
ACTSET(CIND,:)=A(ind,:);
ACTIND(CIND)=ind;
[m,n]=size(ACTSET);
[Q,R] = qrinsert(Q,R,CIND,A(ind,:)');
end
if oldind
aix(oldind) = 0;
end
if ~simplex_iter
% Z = null(ACTSET);
[m,n]=size(ACTSET);
Z = Q(:,m+1:n);
ACTCNT=ACTCNT+1;
if ACTCNT == numberOfVariables - 1, simplex_iter = 1; end
CIND=ACTCNT+1;
oldind = 0;
else
rlambda = -R\(Q'*gf);
if isinf(rlambda(1)) & rlambda(1) < 0
fprintf(' Working set is singular; results may still be reliable.\n');
[m,n] = size(ACTSET);
rlambda = -(ACTSET + sqrt(eps)*randn(m,n))'\gf;
end
actlambda = rlambda;
actlambda(eqix)=abs(actlambda(eqix));
indlam = find(actlambda<0);
if length(indlam)
if STEPMIN > errnorm
% If there is no chance of cycling then pick the constraint
% which causes the biggest reduction in the cost function.
% i.e the constraint with the most negative Lagrangian
% multiplier. Since the constraints are normalized this may
% result in less iterations.
[minl,CIND] = min(actlambda);
else
% Bland's rule for anti-cycling: if there is more than one
% negative Lagrangian multiplier then delete the constraint
% with the smallest index in the active set.
CIND = find(ACTIND == min(ACTIND(indlam)));
end
[Q,R]=qrdelete(Q,R,CIND);
Z = Q(:,numberOfVariables);
oldind = ACTIND(CIND);
else
lambda(indepInd(ACTIND))= normf * (rlambda./normA(ACTIND));
output.iterations = iterations;
return
end
end %if ACTCNT<numberOfVariables
if (is_qp)
Zgf = Z'*gf;
if ~isempty(Zgf) & (norm(Zgf) < 1e-15)
SD = zeros(numberOfVariables,1);
else
[SD, dirType] = compdir(Z,H,gf,numberOfVariables,f);
end
elseif (LLS)
Zgf = Z'*gf;
HZ = H*Z;
if (norm(Zgf) < 1e-15)
SD = zeros(numberOfVariables,1);
else
HXf=H*X-f;
gf=H'*(HXf);
[mm,nn]=size(HZ);
if mm >= nn
[QHZ, RHZ] = qr(HZ);
Pd = QHZ'*HXf;
% SD = - Z*(RHZ(1:nn, 1:nn) \ Pd(1:nn,:));
% Now need to check which is dependent
if min(size(RHZ))==1 % Make sure RHZ isn't a vector
depInd = find( abs(RHZ(1,1)) < tolDep);
else
depInd = find( abs(diag(RHZ)) < tolDep );
end
end
if mm >= nn & isempty(depInd) % Newton step
SD = - Z*(RHZ(1:nn, 1:nn) \ Pd(1:nn,:));
dirType = NewtonStep;
else % steepest descent direction
SD = -Z*(Z'*gf);
dirType = SteepDescent;
end
end
else % LP
if ~simplex_iter
SD = -Z*(Z'*gf);
gradsd = norm(SD);
else
gradsd = Z'*gf;
if gradsd > 0
SD = -Z;
else
SD = Z;
end
end
if abs(gradsd) < 1e-10 % Search direction null
% Check whether any constraints can be deleted from active set.
% rlambda = -ACTSET'\gf;
if ~oldind
rlambda = -R\(Q'*gf);
end
actlambda = rlambda;
actlambda(1:neqcstr) = abs(actlambda(1:neqcstr));
indlam = find(actlambda < errnorm);
lambda(indepInd(ACTIND)) = normf * (rlambda./normA(ACTIND));
if ~length(indlam)
output.iterations = iterations;
return
end
cindmax = length(indlam);
cindcnt = 0;
newactcnt = 0;
while (abs(gradsd) < 1e-10) & (cindcnt < cindmax)
cindcnt = cindcnt + 1;
if oldind
% Put back constraint which we deleted
[Q,R] = qrinsert(Q,R,CIND,A(oldind,:)');
else
simplex_iter = 0;
if ~newactcnt
newactcnt = ACTCNT - 1;
end
end
CIND = indlam(cindcnt);
oldind = ACTIND(CIND);
[Q,R]=qrdelete(Q,R,CIND);
[m,n]=size(ACTSET);
Z = Q(:,m:n);
if m ~= numberOfVariables
SD = -Z*Z'*gf;
gradsd = norm(SD);
else
gradsd = Z'*gf;
if gradsd > 0
SD = -Z;
else
SD = Z;
end
end
end
if abs(gradsd) < 1e-10 % Search direction still null
output.iterations = iterations;
return;
end
lambda = zeros(ncstr,1);
if newactcnt
ACTCNT = newactcnt;
end
end
end
if simplex_iter & oldind
% Avoid case when CIND is greater than ACTCNT
if CIND <= ACTCNT
ACTIND(CIND)=[];
ACTSET(CIND,:)=[];
CIND = numberOfVariables;
end
end
end % while 1
if iterations > maxiter
exitflag = 0;
how = 'ill-conditioned';
end
output.iterations = iterations;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function[Q,R,A,B,CIND,X,Z,actlambda,how,...
ACTSET,ACTIND,ACTCNT,aix,eqix,neqcstr,ncstr,remove,exitflag]= ...
eqnsolv(A,B,eqix,neqcstr,ncstr,numberOfVariables,LLS,H,X,f,normf,normA,verbosity, ...
aix,how,exitflag)
% EQNSOLV Helper function for QPSUB.
% Finds a feasible point with respect to the equality constraints.
% If the equalities are dependent but not consistent, warning
% messages are given. If the equalities are dependent but consistent,
% the redundant constraints are removed and the corresponding variables
% adjusted.
% set tolerances
tolDep = 100*numberOfVariables*eps;
tolCons = 1e-10;
actlambda = [];
aix(eqix)=ones(neqcstr,1);
ACTSET=A(eqix,:);
ACTIND=eqix;
ACTCNT=neqcstr;
CIND=neqcstr+1;
Z=[]; Anew=[]; Bnew=[]; remove =[];
% See if the equalities form a consistent system:
% QR factorization of A
[Qa,Ra,Ea]=qr(A(eqix,:));
% Now need to check which is dependent
if min(size(Ra))==1 % Make sure Ra isn't a vector
depInd = find( abs(Ra(1,1)) < tolDep);
else
depInd = find( abs(diag(Ra)) < tolDep );
end
if neqcstr > numberOfVariables
depInd = [depInd; ((numberOfVariables+1):neqcstr)'];
end
if ~isempty(depInd)
if verbosity > 0
disp('The equality constraints are dependent.')
end
how='dependent';
exitflag = 1;
bdepInd = abs(Qa(:,depInd)'*B(eqix)) >= tolDep ;
if any( bdepInd ) % Not consistent
how='infeasible';
exitflag = 9;exitflag = -1;
if verbosity > 0
disp('The system of equality constraints is not consistent.');
if ncstr > neqcstr
disp('The inequality constraints may or may not be satisfied.');
end
disp(' There is no feasible solution.')
end
else % the equality constraints are consistent
numDepend = nnz(depInd);
% delete the redundant constraints:
% By QR factoring the transpose, we see which columns of A'
% (rows of A) move to the end
[Qat,Rat,Eat]=qr(ACTSET');
[i,j] = find(Eat); % Eat permutes the columns of A' (rows of A)
remove = i(depInd);
if verbosity > 0
disp('The system of equality constraints is consistent. Removing');
disp('the following dependent constraints before continuing:');
disp(remove)
end
A(eqix(remove),:)=[];
B(eqix(remove))=[];
neqcstr = neqcstr - nnz(remove);
ncstr = ncstr - nnz(remove);
eqix = 1:neqcstr;
aix=[ones(neqcstr,1); zeros(ncstr-neqcstr,1)];
ACTIND = eqix;
ACTSET=A(eqix,:);
CIND = neqcstr+1;
ACTCNT = neqcstr;
end % consistency check
end % dependency check
if ~strcmp(how,'infeasible')
% Find a feasible point
if max(abs(A(eqix,:)*X-B(eqix))) > tolCons
X = A(eqix,:)\B(eqix);
end
end
[Q,R]=qr(ACTSET');
Z = Q(:,neqcstr+1:numberOfVariables);
% End of eqnsolv.m
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -