1function [hess,err] = hessian(fun,x0)
2% hessian: estimate elements of the Hessian matrix (array of 2nd partials)
3% usage: [hess,err] = hessian(fun,x0)
5% Hessian
is NOT a tool
for frequent use on an expensive
6% to evaluate objective function, especially in a large
7% number of dimensions. Its computation will use roughly
8% O(6*n^2) function evaluations
for n parameters.
11% fun - SCALAR analytical function to differentiate.
12% fun must be a function of the vector or array x0.
13% fun does not need to be vectorized.
15% x0 - vector location at which to compute the Hessian.
18% hess - nxn symmetric array of second partial derivatives
19% of fun, evaluated at x0.
21% err - nxn array of error estimates corresponding to
22% each second partial derivative in hess.
26% Rosenbrock function, minimized at [1,1]
27% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
29% [h,err] = hessian(rosen,[1 1])
34% 1.0662e-12 4.0061e-10
35% 4.0061e-10 2.6654e-13
40% Note:
this hessian matrix will be positive semi-definite
42% hessian(@(xy) cos(xy(1)-xy(2)),[0 0])
48% See also: derivest, gradient, gradest, hessdiag
51% Author: John D
'Errico
52% e-mail: woodchips@rochester.rr.com
54% Release date: 2/10/2007
56% parameters that we might allow to change
57params.StepRatio = 2.0000001;
58params.RombergTerms = 3;
60% get the size of x0 so we can reshape
64% was a string supplied?
69% total number of derivatives we will need to take
72% get the diagonal elements of the hessian (2nd partial
73% derivatives wrt each variable.)
74[hess,err] = hessdiag(fun,x0);
76% form the eventual hessian matrix, stuffing only
77% the diagonals for now.
81 % the hessian matrix is 1x1. all done
85% get the gradient vector. This is done only to decide
86% on intelligent step sizes for the mixed partials
87[grad,graderr,stepsize] = gradest(fun,x0);
89% Get params.RombergTerms+1 estimates of the upper
90% triangle of the hessian matrix
91dfac = params.StepRatio.^(-(0:params.RombergTerms)');
94 dij = zeros(params.RombergTerms+1,1);
95 for k = 1:(params.RombergTerms+1)
96 dij(k) = fun(x0 + swap2(zeros(sx),i, ...
97 dfac(k)*stepsize(i),j,dfac(k)*stepsize(j))) + ...
98 fun(x0 + swap2(zeros(sx),i, ...
99 -dfac(k)*stepsize(i),j,-dfac(k)*stepsize(j))) - ...
100 fun(x0 + swap2(zeros(sx),i, ...
101 dfac(k)*stepsize(i),j,-dfac(k)*stepsize(j))) - ...
102 fun(x0 + swap2(zeros(sx),i, ...
103 -dfac(k)*stepsize(i),j,dfac(k)*stepsize(j)));
106 dij = dij/4/prod(stepsize([i,j]));
107 dij = dij./(dfac.^2);
109 % Romberg extrapolation step
110 [hess(i,j),err(i,j)] = rombextrap(params.StepRatio,dij,[2 4]);
111 hess(j,i) = hess(i,j);
117end % mainline function end
119% =======================================
121% =======================================
122function vec = swap2(vec,ind1,val1,ind2,val2)
123% swaps val as element ind, into the vector vec
127end % sub-function end
130% ============================================
131% subfunction - romberg extrapolation
132% ============================================
133function [der_romb,errest] = rombextrap(StepRatio,der_init,rombexpon)
134%
do romberg extrapolation
for each estimate
136% StepRatio - Ratio decrease in step
137% der_init - initial derivative estimates
138% rombexpon - higher order terms to cancel
using the romberg step
140% der_romb - derivative estimates returned
141% errest - error estimates
142% amp - noise amplification factor due to the romberg step
146%
do nothing
if no romberg terms
147nexpon = length(rombexpon);
148rmat = ones(nexpon+2,nexpon+1);
151 % rmat
is simple: ones(2,1)
153 % only one romberg term
154 rmat(2,2) = srinv^rombexpon;
155 rmat(3,2) = srinv^(2*rombexpon);
158 rmat(2,2:3) = srinv.^rombexpon;
159 rmat(3,2:3) = srinv.^(2*rombexpon);
160 rmat(4,2:3) = srinv.^(3*rombexpon);
162 % three romberg terms
163 rmat(2,2:4) = srinv.^rombexpon;
164 rmat(3,2:4) = srinv.^(2*rombexpon);
165 rmat(4,2:4) = srinv.^(3*rombexpon);
166 rmat(5,2:4) = srinv.^(4*rombexpon);
169% qr factorization used for the extrapolation as well
170% as the uncertainty estimates
171[qromb,rromb] = qr(rmat,0);
173% the noise amplification
is further amplified by the Romberg step.
176% this does the extrapolation to a zero step size.
177ne = length(der_init);
178rombcoefs = rromb\(qromb'*der_init);
179der_romb = rombcoefs(1,:)';
181% uncertainty estimate of derivative prediction
182s = sqrt(sum((der_init - rmat*rombcoefs).^2,1));
183rinv = rromb\eye(nexpon+1);
184cov1 = sum(rinv.^2,2); % 1 spare dof
185errest = s'*12.7062047361747*sqrt(cov1(1));