function [xc,histout,costdata] = cgtrust(x0,f,parms,resolution)
%function [xc,histout,costdata] = cgtrust(x0,f,parms,resolution)
%
%
% C. T. Kelley, Jan 13, 1998
%
% This code comes with no guarantee or warranty of any kind.
%
% function [x,histout] = cgtrust(x0,f,parms,resolution)
%
% Steihaug Newton-CG-Trust region algoirithm
% 
% Input: x0 = initial iterate
%        f = objective function,
%            the calling sequence for f should be
%            [fout,gout]=f(x) where fout=f(x) is a scalar
%              and gout = grad f(x) is a COLUMN vector
%        parms = [tol, eta, maxitnl, maxitl]
%        tol = termination criterion norm(grad) < tol
%        eta = forcing term in linear iteration (optional) default = .1
%        maxitnl = maximum nonlinear iterations (optional) default = 100
%        maxitl = maximum linear iterations (optional) default = 20
%        resolution = estimated accuracy in functions/gradients (optional)
%                     default = 1.d-12
%                     The finite difference increment in the difference
%                     Hessian is set to sqrt(resolution).
%
%
%
% Output: x = solution
%         histout = iteration history
%             Each row of histout is
%              [norm(grad), f, TR radius, inner iteration count]
%         costdata = [num f, num grad]
%
% Requires: dirdero.m
%
% trust region algorithm parameters
%
omegaup=2; omegadown=.5;
mu0=.25; mulow=.25; muhigh=.75;
%
% set maxit, the resolution, and the difference increment
%
debug=0;
tol=parms(1); np=length(parms); itc=1;
if np < 2; eta=.1; else eta = parms(2); end
if np < 3; maxit=100; else maxit = parms(3); end
if np < 4; maxitl=20; else maxitl = parms(4); end
if nargin < 5
resolution = 1.d-12;
end
numf=0; numg=0;
hdiff=sqrt(resolution);
t=100; itc=0; xc=x0; n=length(x0);
[fc,gc]=feval(f,xc); numf=1; numg=1; 
trrad=norm(x0)+0.0001; % Add a small value in case initial xo=0. (Henry/03)
ithist=zeros(maxit,4); ithist(itc+1,:)=[norm(gc), fc, trrad, 0];
%
paramstr=[eta,maxitl]; trcount=1;
while(norm(gc) > tol & itc <=maxit) & trcount < 30
    itc=itc+1;
    [s,dirs]=trcg(xc, f, gc, trrad, paramstr);
    vd=size(dirs); itsl=vd(2); numf=numf+itsl; numg=numg+itsl;
    xt=xc+s; ft=feval(f,xt); numf=numf+1; ared=ft-fc;
    w= dirdero(xc, s, f, gc); numg=numg+1;
    pred=gc'*s + .5*(w'*s); rat=ared/pred;
    if rat > mu0
       xc=xc+s; [fc,gc]=feval(f,xc); numf=numf+1;
       if rat > muhigh & norm(s) > trrad-1.d-8 trrad=omegaup*trrad; end
       if rat < mulow trrad=omegadown*trrad; end
    else
       for k=1:itsl dsums(k)=norm(sum(dirs(:,1:k),2)); end
       trcount=1;
       while rat <= mu0 & trcount < 30
         trrad=omegadown*min(trrad,norm(s));
         [s, kout]=tradj(trrad, dirs, itsl);
         xt=xc+s; ft=feval(f,xt); numf=numf+1; ared=ft-fc; 
%
%      Only compute a new pred if ared < 0 and there's some hope
%      that rat > mu0
%
         if ared < 0
             w= dirdero(xc, s, f, gc); numg=numg+1; pred=gc'*s + .5*(w'*s); 
         end
         rat=ared/pred;
         itsl=kout; trcount=trcount+1;
         if trcount > 30 
%           ithist(itc+1,:)=[norm(gc), fc, trrad, itsl];
%           histout=ithist(1:itc+1,:); costdata=[numf,numg];
           disp(' stagnation in CGTR')
         end
       end
       if trcount < 30
       xc=xt; [fc,gc]=feval(f,xc); numf=numf+1; numg=numg+1;
       end
    end
    ithist(itc+1,:)=[norm(gc), fc, trrad, itsl];
end
histout=ithist(1:itc+1,:); costdata=[numf,numg];
%
% find the point of intersetion of the TR boundary and the PL path
%
function [st, kout] = tradj(trrad, dirs, itsl)
st=dirs(:,1); inside=1;
if norm(st) > trrad | itsl == 1
    st=st*trrad/norm(st);
    kout=1;
else
    for k=2:itsl
      if norm(st+dirs(:,k)) > trrad  & inside == 1
        kout=k;
        p=dirs(:,k); ac=p'*p; bc=2*(st'*p); cc=st'*st - trrad*trrad;
        alpha=(-bc + sqrt(bc*bc - 4*ac*cc))/(2*ac); st=st+alpha*p;
        inside=0;
      else
        st=st+dirs(:,k);
      end
    end
end
%
%
%
function [x, directions]  = trcg(xc, f, gc, delta, params, pcv)
%
% Solve the trust region problem with preconditioned conjugate-gradient
%
% C. T. Kelley, January 13, 1997
%
% This code comes with no guarantee or warranty of any kind.
% function [x, directions]
%                    = trcg(xc, f, gc, delta)
%
%
%
% Input:        xc=current point
%               b=right hand side
%           f = function, the calling sequence is
%                               [fun,grad]=f(x)
%           gc = current gradient
%                gc has usually been computed
%                before the call to dirdero
%           delta = TR radius
%           params = two dimensional vector to control iteration
%                params(1) = relative residual reduction factor
%                params(2) = max number of iterations
%           pcv, a routine to apply the preconditioner
%                if omitted, the identity is used.
%                The format for pcv is 
%                       function px = pcv(x).
%
% Output:   x = trial step
%           directions = array of search directions TR radius reduction
% 
%

%
% initialization
%
n=length(xc); errtol = params(1); maxiters = params(2); 
x=zeros(n,1); b=-gc; r=b - dirdero(xc, x, f, gc);
if nargin == 5
    z=r;
else
    z = feval(pcv, r);
end
rho=z'*r;
tst=norm(r);
terminate=errtol*norm(b);
it=1;
directions=zeros(n,1);
hatdel=delta*(1-1.d-6);
while((tst > terminate) & (it <= maxiters) & norm(x) <= hatdel)
%
%
%
if(it==1) 
	p = z;
else
	beta=rho/rhoold;
	p = z + beta*p;
%
% end if
%
end
w = dirdero(xc, p, f, gc);
alpha=p'*w;
%
% If alpha <=0 head to the TR boundary and return
%
ineg=0;
if(alpha <= 0)
     ac=p'*p; bc=2*(x'*p); cc=x'*x - delta*delta;
     alpha=(-bc + sqrt(bc*bc - 4*ac*cc))/(2*ac);
     disp(' negative curvature')
else
     alpha=rho/alpha;
     if norm(x+alpha*p) > delta
         ac=p'*p; bc=2*(x'*p); cc=x'*x - delta*delta;
         alpha=(-bc + sqrt(bc*bc - 4*ac*cc))/(2*ac);
     end
end
x=x+alpha*p;
directions(:,it)=alpha*p;
r = r - alpha*w;
tst=norm(r);
rhoold=rho;
if nargin < 6 z=r; else z = feval(pcv, r); end
rho=z'*r;
it=it+1;
%
% end while
%
end
