function [hessian_mat, gg, htol1, ihh, hh_mat0] = mr_hessian(func,x,hflag,htol0,varargin) % [hessian_mat, gg, htol1, ihh, hh_mat0] = mr_hessian(func,x,hflag,htol0,varargin) % % numerical gradient and Hessian, with 'automatic' check of numerical % error % % adapted from Michel Juillard original rutine hessian.m % % func = name of the function: func must give two outputs: % - the log-likelihood AND the single contributions at times t=1,...,T % of the log-likelihood to compute outer product gradient % x = parameter values % hflag = 0, Hessian computed with outer product gradient, one point % increments for partial derivatives in gradients % hflag = 1, 'mixed' Hessian: diagonal elements computed with numerical second order derivatives % with correlation structure as from outer product gradient; % two point evaluation of derivatives for partial derivatives % in gradients % hflag = 2, full numerical Hessian, computes second order partial derivatives % uses Abramowitz and Stegun (1965) formulas 25.3.24 and 25.3.27 % p. 884. % htol0 = 'precision' of increment of function values for numerical % derivatives % % varargin: other parameters of func % Copyright (C) 2004-2008 Dynare Team % % This file is part of Dynare. % % Dynare is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % Dynare is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with Dynare. If not, see . global options_ bayestopt_ persistent h1 htol gstep_=options_.gstep; if isempty(htol), htol = 1.e-4; end func = str2func(func); [f0, ff0]=feval(func,x,varargin{:}); n=size(x,1); h2=bayestopt_.ub-bayestopt_.lb; hmax=bayestopt_.ub-x; hmax=min(hmax,x-bayestopt_.lb); %h1=max(abs(x),gstep_*ones(n,1))*eps^(1/3); %h1=max(abs(x),sqrt(gstep_)*ones(n,1))*eps^(1/6); if isempty(h1), h1=max(abs(x),sqrt(gstep_)*ones(n,1))*eps^(1/4); end h1 = min(h1,0.5.*hmax); if htol0(2*htol), % c=mr_nlincon(xh1,varargin{:}); % while c % h1(i)=h1(i)*0.9; % xh1(i)=x(i)+h1(i); % c=mr_nlincon(xh1,varargin{:}); % ic=1; % end % if ic, % [fx, ffx]=feval(func,xh1,varargin{:}); % dx=(fx-f0); % end % end icount = 0; h0=h1(i); while (abs(dx(it))<0.5*htol | abs(dx(it))>(2*htol)) & icount<10 & ic==0, %while abs(dx(it))<0.5*htol & icount< 10 & ic==0, icount=icount+1; %if abs(dx(it)) ~= 0, if abs(dx(it))<0.5*htol if abs(dx(it)) ~= 0, h1(i)=min(max(1.e-10,0.3*abs(x(i))), 0.9*htol/abs(dx(it))*h1(i)); else h1(i)=2.1*h1(i); end h1(i) = min(h1(i),0.5*hmax(i)); xh1(i)=x(i)+h1(i); % c=mr_nlincon(xh1,varargin{:}); % while c % h1(i)=h1(i)*0.9; % xh1(i)=x(i)+h1(i); % c=mr_nlincon(xh1,varargin{:}); % ic=1; % end try [fx, ffx]=feval(func,xh1,varargin{:}); catch fx=1.e8; end end if abs(dx(it))>(2*htol), h1(i)= htol/abs(dx(it))*h1(i); xh1(i)=x(i)+h1(i); try [fx, ffx]=feval(func,xh1,varargin{:}); catch fx=1.e8; end while (fx-f0)==0, h1(i)= h1(i)*2; xh1(i)=x(i)+h1(i); [fx, ffx]=feval(func,xh1,varargin{:}); ic=1; end end it=it+1; dx(it)=(fx-f0); h0(it)=h1(i); if h1(i)<1.e-12*min(1,h2(i)) & h1(i)<0.5*hmax(i), ic=1; hcheck=1; end %else % h1(i)=1; % ic=1; %end end % if (it>2 & dx(1)<10^(log10(htol)/2)) , % [dum, is]=sort(h0); % if find(diff(sign(diff(dx(is))))); % hcheck=1; % end % elseif (it>3 & dx(1)>10^(log10(htol)/2)) , % [dum, is]=sort(h0); % if find(diff(sign(diff(dx(is(1:end-1)))))); % hcheck=1; % end % end f1(:,i)=fx; if any(isnan(ffx)), ff1=ones(size(ff0)).*fx/length(ff0); else ff1=ffx; end if hflag, % two point based derivatives xh1(i)=x(i)-h1(i); % c=mr_nlincon(xh1,varargin{:}); % ic=0; % while c % h1(i)=h1(i)*0.9; % xh1(i)=x(i)-h1(i); % c=mr_nlincon(xh1,varargin{:}); % ic = 1; % end [fx, ffx]=feval(func,xh1,varargin{:}); f_1(:,i)=fx; if any(isnan(ffx)), ff_1=ones(size(ff0)).*fx/length(ff0); else ff_1=ffx; end % if ic, % xh1(i)=x(i)+h1(i); % [f1(:,i), ff1]=feval(func,xh1,varargin{:}); % end ggh(:,i)=(ff1-ff_1)./(2.*h1(i)); else ggh(:,i)=(ff1-ff0)./h1(i); end xh1(i)=x(i); if hcheck & htol<1, htol=min(1,max(min(abs(dx))*2,htol*10)); h1(i)=h10; i=0; end save hess end h_1=h1; xh1=x; xh_1=xh1; if hflag, gg=(f1'-f_1')./(2.*h1); else gg=(f1'-f0)./h1; end if hflag==2, gg=(f1'-f_1')./(2.*h1); hessian_mat = zeros(size(f0,1),n*n); for i=1:n if i > 1 k=[i:n:n*(i-1)]; hessian_mat(:,(i-1)*n+1:(i-1)*n+i-1)=hessian_mat(:,k); end hessian_mat(:,(i-1)*n+i)=(f1(:,i)+f_1(:,i)-2*f0)./(h1(i)*h_1(i)); temp=f1+f_1-f0*ones(1,n); for j=i+1:n xh1(i)=x(i)+h1(i); xh1(j)=x(j)+h_1(j); xh_1(i)=x(i)-h1(i); xh_1(j)=x(j)-h_1(j); %hessian_mat(:,(i-1)*n+j)=-(-feval(func,xh1,varargin{:})-feval(func,xh_1,varargin{:})+temp(:,i)+temp(:,j))./(2*h1(i)*h_1(j)); %temp1 = feval(func,xh1,varargin{:}); % c=mr_nlincon(xh1,varargin{:}); % lam=1; % while c, % lam=lam*0.9; % xh1(i)=x(i)+h1(i)*lam; % xh1(j)=x(j)+h_1(j)*lam; % %disp( ['hessian warning cross ', num2str(c) ]), % c=mr_nlincon(xh1,varargin{:}); % end % temp1 = f0+(feval(func,xh1,varargin{:})-f0)/lam; temp1 = feval(func,xh1,varargin{:}); % c=mr_nlincon(xh_1,varargin{:}); % while c, % lam=lam*0.9; % xh_1(i)=x(i)-h1(i)*lam; % xh_1(j)=x(j)-h_1(j)*lam; % %disp( ['hessian warning cross ', num2str(c) ]), % c=mr_nlincon(xh_1,varargin{:}); % end % temp2 = f0+(feval(func,xh_1,varargin{:})-f0)/lam; temp2 = feval(func,xh_1,varargin{:}); hessian_mat(:,(i-1)*n+j)=-(-temp1 -temp2+temp(:,i)+temp(:,j))./(2*h1(i)*h_1(j)); xh1(i)=x(i); xh1(j)=x(j); xh_1(i)=x(i); xh_1(j)=x(j); j=j+1; save hess end i=i+1; end elseif hflag==1, hessian_mat = zeros(size(f0,1),n*n); for i=1:n, dum = (f1(:,i)+f_1(:,i)-2*f0)./(h1(i)*h_1(i)); if dum>eps, hessian_mat(:,(i-1)*n+i)=dum; else hessian_mat(:,(i-1)*n+i)=max(eps, gg(i)^2); end end %hessian_mat2=hh_mat(:)'; end gga=ggh.*kron(ones(size(ff1)),2.*h1'); % re-scaled gradient hh_mat=gga'*gga; % rescaled outer product hessian hh_mat0=ggh'*ggh; % outer product hessian A=diag(2.*h1); % rescaling matrix igg=inv(hh_mat); % inverted rescaled outer product hessian ihh=A'*igg*A; % inverted outer product hessian if hflag>0 & min(eig(reshape(hessian_mat,n,n)))>0, hh0 = A*reshape(hessian_mat,n,n)*A'; %rescaled second order derivatives hh = reshape(hessian_mat,n,n); %rescaled second order derivatives sd0=sqrt(diag(hh0)); %rescaled 'standard errors' using second order derivatives sd=sqrt(diag(hh_mat)); %rescaled 'standard errors' using outer product hh_mat=hh_mat./(sd*sd').*(sd0*sd0'); %rescaled inverse outer product with 'true' std's igg=inv(hh_mat); % rescaled outer product hessian with 'true' std's ihh=A'*igg*A; % inverted outer product hessian hh_mat0=inv(A)'*hh_mat*inv(A); % outer product hessian with 'true' std's sd=sqrt(diag(ihh)); %standard errors sdh=sqrt(1./diag(hh)); %diagonal standard errors for j=1:length(sd), sd0(j,1)=min(bayestopt_.p2(j), sd(j)); %prior std sd0(j,1)=10^(0.5*(log10(sd0(j,1))+log10(sdh(j,1)))); %sd0(j,1)=0.5*(sd0(j,1)+sdh(j,1)); end ihh=ihh./(sd*sd').*(sd0*sd0'); %inverse outer product with modified std's igg=inv(A)'*ihh*inv(A); % inverted rescaled outer product hessian with modified std's hh_mat=inv(igg); % outer product rescaled hessian with modified std's hh_mat0=inv(A)'*hh_mat*inv(A); % outer product hessian with modified std's % sd0=sqrt(1./diag(hh0)); %rescaled 'standard errors' using second order derivatives % sd=sqrt(diag(igg)); %rescaled 'standard errors' using outer product % igg=igg./(sd*sd').*(sd0*sd0'); %rescaled inverse outer product with 'true' std's % hh_mat=inv(igg); % rescaled outer product hessian with 'true' std's % ihh=A'*igg*A; % inverted outer product hessian % hh_mat0=inv(A)'*hh_mat*inv(A); % outer product hessian with 'true' std's end if hflag<2, hessian_mat=hh_mat0(:); end if any(isnan(hessian_mat)), hh_mat0=eye(length(hh_mat0)); ihh=hh_mat0; hessian_mat=hh_mat0(:); end hh1=h1; htol1=htol; save hess % 11/25/03 SA Created from Hessian_sparse (removed sparse)