https://github.com/Data2Dynamics/d2d
Tip revision: d72d4c223fb8adc0e3e44a1d3d1eafce18b995ae authored by Andreas Raue on 06 March 2015, 00:17:07 UTC
Increase C version code, after Joep's submits today to prevent compatibility problems
Increase C version code, after Joep's submits today to prevent compatibility problems
Tip revision: d72d4c2
arNLS.m
% [p,resnorm,res,exitflag,output] = arNLS(fun,p,lb,ub,options,submethod)
%
% use like LSQNONLIN
%
% exitflag:
% 0 Too many function evaluations or iterations.
% 1 Converged to a solution.
% 2 Change in p too small.
% 3 Change in resnorm too small.
% 4 Computed search direction too small.
%
% sub-method:
% 0 = trust region (based on modified trust.m)
% 1 = Levenberg-Marquardt
% 2 = Newton (with maximal step length mu)
% 3 = gradient descent (with steplength mu)
% 4 = gradient descent (to cauchy point with steplength mu)
% 5 = dogleg
% 6 = generalized trust region (based on modified trust.m)
% 7 = MATLABs trdog
% 8 = Newton pcgr (with maximal step length mu)
% 9 = trdog pcgr (with maximal step length mu)
% 10 = dogleg Newton pcgr
% 11 = dogleg trdog pcgr
% 12 = trdog pcgr (no DM)
% 13 = trdog pcgr (no DG)
% 14 = trdog pcgr Levenberg-Marquardt
% 15 = trdog pcgr 2D subspace
% 16 = trdog pcgr (no DM) 2D subspace
% 17 = trdog pcgr (no DM) 3D subspace
function [p,resnorm,res,exitflag,output,lambda,jac] = arNLS(fun,p,lb,ub,options,submethod)
if(nargin==0)
p = arNLSstep;
return;
end
if(~exist('submethod','var'))
submethod = 0;
end
% check bounds
if (sum(ub<=lb)>0)
error('arNLS: bounds are inconsistent');
end
if(sum(p>ub | p<lb)>0)
error('arNLS: parameters inconsistent with bounds');
end
% not used
lambda = [];
jac = [];
exitflag = 1;
if(nargin>4)
options = optimset(optimset('lsqnonlin'), options);
else
options = optimset('lsqnonlin');
end
% output level
switch(options.Display)
case('off')
debug = 0;
case('notify')
debug = 1;
case('final')
debug = 2;
case('iter')
debug = 3;
end
% inertia effect using memory
% 0 = no
% useInertia has to be < 1
useInertia = 0;
dpmem = [];
% initial trust region size
if(isempty(options.InitTrustRegionRadius))
mu = 1;
else
mu = options.InitTrustRegionRadius;
end
if(submethod==6)
mu = eye(length(p))*mu;
end
% trust region size scale factor
mu_fac = 2;
% counters
iter = 0;
funevals = 0;
solver_calls = 0;
% initial function evaluation
funevals = funevals + 1;
if(nargout(fun)==2 || nargout(fun)==-1)
[res, sres] = feval(fun, p);
H = 2*(sres'*sres); % Hessian matrix approximation
elseif(nargout(fun)==3)
[res, sres, H] = feval(fun, p); % user Hessian matrix
elseif(nargout(fun)==4)
[res, sres, H, ssres] = feval(fun, p); % user second derivatives
else
error('nargout(fun)==2 or 3');
end
resnorm = sum(res.^2);
resnorm_start = resnorm;
llh = sum(res.^2); % objective function
g = -2*res*sres; % gradient
% calculate first order optimality criterion
onbound = [p==ub; p==lb];
exbounds = [g>0; g<0];
firstorderopt = norm(g(sum(onbound & exbounds,1)==0));
% output
if(debug>2)
fprintf('%3i/%3i resnorm=%-8.2g norm(g)=%-8.2g\n', iter, options.MaxIter, resnorm, firstorderopt);
end
if(~isempty(options.OutputFcn))
feval(options.OutputFcn,p,[],'iter');
end
q_converged = false;
while(iter < options.MaxIter && ~q_converged)
iter = iter + 1;
% solve subproblem - get trial point
[dp, solver_calls, qred, grad_dir_frac, resnorm_expect, normdpmu_type] = ...
arNLSstep(llh, g, H, sres, mu, p, lb, ub, solver_calls, dpmem, submethod);
pt = p + dp;
% ensure strict feasibility - the hard way
pt(pt<lb) = lb(pt<lb);
pt(pt>ub) = ub(pt>ub);
% evaluate trial point
try
if(nargout(fun)==2 || nargout(fun)==-1)
[rest, srest] = feval(fun, pt);
elseif(nargout(fun)==3 && nargin(fun)==1)
[rest, srest, Ht] = feval(fun, pt);
elseif(nargout(fun)==3 && nargin(fun)==5)
[rest, srest, Ht] = feval(fun, pt, p, res, sres, H);
elseif(nargout(fun)==4 && nargin(fun)==5)
[rest, srest, Ht, ssrest] = feval(fun, pt, p, res, sres, ssres);
end
resnormt = sum(rest.^2);
catch
resnormt = Inf;
end
funevals = funevals + 1;
% fit improvement statistics
dresnorm = resnormt - resnorm;
dresnorm_expect = resnorm_expect - resnorm;
% approximation quality
approx_qual = dresnorm/dresnorm_expect;
q_approx_qual = approx_qual > 0.75;
% calculate first order optimality criterion
onbound = [p==ub; p==lb];
exbounds = [g>0; g<0];
firstorderopt = norm(g(sum(onbound & exbounds,1)==0));
% reduction achieved ?
q_reduction = dresnorm<0;
% accept step ?
% q_accept_step = q_reduction;
q_accept_step = q_reduction && q_approx_qual;
% output
if(debug>2)
printiter(iter, options.MaxIter, resnorm, mu, norm(dp), normdpmu_type, dresnorm, ...
firstorderopt, find(qred), grad_dir_frac, approx_qual, q_accept_step, cond(H));
end
% call output function
if(~isempty(options.OutputFcn))
feval(options.OutputFcn,p,[],'iter');
end
% call plot function
if(~isempty(options.PlotFcns))
feval(options.PlotFcns, p, H, mu);
end
% update if step was accepted
if(q_accept_step)
p = pt;
res = rest;
sres = srest;
resnorm = resnormt;
llh = sum(res.^2); % objective function
g = -2*res*sres; % gradient
if(nargout(fun)==2 || nargout(fun)==-1)
H = 2*(sres'*sres); % Hessian matrix approximation
elseif(nargout(fun)==3)
H = Ht; % user Hessian matrix
elseif(nargout(fun)==4)
H = Ht; % user Hessian matrix
ssres = ssrest; % user second derivatives
end
% inertial effect using memory
if(~isempty(dpmem))
dpmem = useInertia*dpmem + (1-useInertia)*dp;
else
dpmem = dp;
end
end
% update schedule for trust region
if(normdpmu_type == -1)
q_enlarge = q_reduction && q_approx_qual && (norm(dp)/mu) > 0.9;
elseif(normdpmu_type > 0)
q_enlarge = q_reduction && q_approx_qual && normdpmu_type > 0.9;
else
q_enlarge = q_reduction && q_approx_qual;
end
q_shrink = ~q_reduction || ~q_approx_qual;
dmu = 0;
if(q_enlarge) % enlarge trust region
mu = arNLSTrustTrafo(mu, mu_fac, dp, false);
dmu = 1;
elseif(q_shrink) % shrink trust region
mu_red_fac = 1/mu_fac;
if(isscalar(mu) && normdpmu_type==-1)
mu_red_fac = min([mu_red_fac mu_red_fac*norm(dp)/mu]);
end
mu = arNLSTrustTrafo(mu, mu_red_fac, dp, false);
dmu = -1;
end
% check convergence
if(isscalar(mu))
q_converged = mu < options.TolX || firstorderopt < 1e-6;
else
q_converged = norm(dp) < options.TolX || firstorderopt < 1e-6;
end
end
% exit condition
if(iter==options.MaxIter)
exitflag = 0;
end
if(mu < options.TolX || norm(dp) < options.TolX)
exitflag = 2;
end
if(firstorderopt < 1e-6)
exitflag = 1;
end
% assign output structure
if(nargout>4)
output = struct([]);
output(1).iterations = iter;
output.funcCount = funevals;
output.solverCount = solver_calls;
output.algorithm = 'arNLS';
output.firstorderopt = firstorderopt;
output.H = H;
switch(exitflag)
case(0)
output.message = 'Too many function evaluations or iterations.';
case(1)
output.message = 'Converged to a solution.';
case(2)
output.message = 'Change in p too small.';
end
output.totalimprove = resnorm_start - resnorm;
end
if(nargout>5)
jac = sres;
end
% output
if(debug>1 || (debug>0 && exitflag==0))
switch(exitflag)
case(0)
fprintf('NLS_TRUST: Too many function evaluations or iterations.');
case(1)
fprintf('NLS_TRUST: Converged to a solution.');
case(2)
fprintf('NLS_TRUST: Change in p too small.');
end
fprintf(' Achieved improvement %g in %i/%i iterations.\n', resnorm_start - resnorm, iter, options.MaxIter);
end
% print iteration
function printiter(iter, maxIter, resnorm, mu, norm_dp, normdpmu, dresnorm, ...
norm_gred, dim_red, grad_dir_frac, approx_qual, step_accept, condition_number)
if(~step_accept)
outstream = 2;
else
outstream = 1;
end
fprintf(outstream, '%3i/%3i resnorm=%-8.2g ', iter, maxIter, resnorm);
if(~isscalar(mu))
figure(1)
subplot(3,1,1)
plot(log10(real(eig(mu))),'*-');
subplot(3,1,2:3)
maxmu = max(abs(mu(:)));
imagesc(mu, [-maxmu maxmu]);
colorbar;
drawnow;
fprintf(outstream, 'mu=%-8.2g (det=%-8.2g cond=%-8.2g maxeig=%-8.2g) ', normdpmu, det(mu), cond(mu), max(eig(mu)));
else
fprintf(outstream, 'mu=%-8.2g ', mu);
if(normdpmu>0)
fprintf(outstream, '(%-5.2f) ', normdpmu);
end
end
fprintf(outstream, 'norm(dp)=%-8.2g dresnorm=%-8.2g ', norm_dp, dresnorm);
fprintf(outstream, 'approx_qual=%-8.2g norm(g)=%-8.2g grad_dir=%3.1f cond(H)=%-8.2g dim_red: ', ...
approx_qual, norm_gred, grad_dir_frac, condition_number);
fprintf(outstream, '%i ', dim_red);
fprintf(outstream, '\n');