function [optx,zmin] = quad_prog(G,d,A,b,toler,maxiter) % usage: [xopt,zmin] = quad_prog(G,d,A,b,toler,maxiter) % description: This code solves the quadratic program % minimize z = x'*G*x + d'*x % sbj to A*x >= b, x >= 0. % It assumes that A is mxn and that G is % nxn positive definite, d is nx1 and b is mx1. Arguments % tol (termination criterion tolerance) and maxit (maximum % number of iterations) are optional. It uses a % gradient projection method whose code is taken from % the program gradproj.m due to C. T. Kelley. persistent Hp dp if (nargin >1 && nargin < 4) error('quad_prog: arguments G,d,A,b are required') elseif (nargin == 1) % this is a subfunction call optx = 0.5*G'*Hp*G + G'*dp; zmin = Hp*G + dp; else % this is the main call % set stopping parms if nargin < 5 tol=1e-6; else tol = toler; end if nargin < 6 maxit=10; else maxit = maxiter; end % set some constants and minimal bulletproofing [m,n] = size(A); if (size(b) ~= [m,1]) error('quad_solv: b must be mx1, where A is mxn'); end if (size(G) ~= [n,n]) error('quad_solv: G must be nxn, where A is mxn'); end if (size(d) ~= [n,1]) error('quad_solv: d must be nx1, where A is mxn'); end % test for consistency of equations [optx,zmin,is_bounded,sol] = lp(ones(n+m,1),[A,-eye(m)],b); if (~sol) error('quad_prog: system Ax >= b, x >= 0 has no solution'); end % symmetrize G and account for 1/2 factor Hp = G+G'; invG = inv(Hp); A = [A; eye(n)]; % adjust to account for x >= 0 b = [b; zeros(n,1)]; Hp = A*invG*A'; dp = -(b + A*invG*d); % set up for Kelley iteration x0 = zeros(m+n,1); % initial guess f = 'quad_prog'; low = zeros(m+n,1); up = Inf*zeros(m+n,1); % The gradient projection method commences here xc=x0; ndim=length(up); kku=zeros(ndim,1); kkl=zeros(ndim,1); for i=1:ndim kku(i)=up(i); kkl(i)=low(i); if kkl(i) > kku(i) error(' lower bound exceeds upper bound') end end % % put initial iterate in feasible set % if norm(xc - max(kkl,min(kku,xc))) > 0 disp(' initial iterate not feasibile '); xc=max(kkl,min(kku,xc)); end alp=1.d-4; if nargin < 6 maxit=1000; end if nargin < 5 tol=1.d-6; end itc=1; [fc,gc]=feval(f,xc); numf=1; numg=1; numh=0; ithist=zeros(maxit,5); xt=max(kkl,min(kku,xc-gc)); pgc=xc - max(kkl,min(kku,xc-gc)); ia=0; for i=1:ndim; if(xc(i)==kku(i) | xc(i)==kkl(i)) ia=ia+1; end; end; ithist(1,5)=ia/ndim; ithist(1,1)=norm(pgc); ithist(1,2) = fc; ithist(1,4)=itc-1; ithist(1,3)=0; while(norm(pgc) > tol & itc <= maxit) lambda=1; xt=max(kkl,min(kku,xc-lambda*gc)); ft=feval(f,xt); numf=numf+1; iarm=0; itc=itc+1; pl=xc - xt; fgoal=fc-(pl'*pl)*(alp/lambda); % % simple line search % q0=fc; qp0=-gc'*gc; qc=ft; while(ft > fgoal) lambda=lambda*.1; iarm=iarm+1; xt=max(kkl,min(kku,xc-lambda*gc)); pl=xc-xt; ft=feval(f,xt); numf = numf+1; if(iarm > 10) disp(' Armijo error in gradient projection') histout=ithist(1:itc,:); costdata=[numf, numg, numh]; return; end fgoal=fc-(pl'*pl)*(alp/lambda); end xc=xt; [fc,gc]=feval(f,xc); numf=numf+1; numg=numg+1; pgc=xc-max(kkl,min(kku,xc-gc)); ithist(itc,1)=norm(pgc); ithist(itc,2) = fc; ithist(itc,4)=itc-1; ithist(itc,3)=iarm; ia=0; for i=1:ndim; if(xc(i)==kku(i) | xc(i)==kkl(i)) ia=ia+1; end; end; ithist(itc,5)=ia/ndim; end x=xc; histout=ithist(1:itc,:); costdata=[numf, numg, numh]; % projected gradient ends here % now make corrections for fact that x is really lambda optx = invG*(A'*x-d); zmin = optx'*G*optx + d'*optx; end