% reduced_Newton.m
%
% This MATLAB m-file uses a reduced-Newton
algorithm with a
% weak line search to solve a set of non-linear
algebraic
% equations.
%
% The input parameters are :
%
% x0 = a column vector of the initial guess
of the unknowns
%
% calc_f = the name of a MATLAB function
that calculates
% the function
vector
%
% calc_Jac = the name of a function that
calculates the Jacobian
%
% Options = a data structure containing
optional flags
% .max_iter = max # of Newton's method
iterations
% .max_iter_LS = max # of weak line search
iterations
% .rtol = relative tolerance
% .atol = absolute tolerance
% .step_tol = abs. tolerance below which we
switch to full Newton's method
% .verbose = return a trajectory matrices
containing the history
%
of the Newton's method iterations
% .use_range = if non-zero, limit the
maximum magitude of the full Newton
%
step so that the change in each component is not greater than
%
that in the vector .range
% .range = a vector of the ranges for each
of the unknowns. Each component
%
of the Newton step
%
% Param = a data structure containing
parameters that are to be passed to
%
the calc_f and calc_Jac functions
%
% The output parameters are :
%
% x = the final estimate of the solution
%
% iflag = an integer flag that is 1 for
convergence,
% 0 for no
convergence, and negative for an error
%
% iter_conv = number of iterations required
for convergence
%
% x_traj = a matrix where row # j is the
solution estimate at iteration j-1
% f_traj = a matrix where row # j is the
function vector at iteration j-1
function [x,iflag,iter_conv,x_traj,f_traj] =
...
reduced_Newton(x0,calc_f,calc_Jac,Options,Param);
% First, signal no convergence.
iflag = 0;
% Set number of iterations required for
convergence.
iter_conv = 0;
% Extract number of state variables.
Nvar = length(x0);
% Initialize solution estimate.
x = x0;
% Calculate initial function vector.
f = feval(calc_f,x,Param);
if(length(f) ~= Nvar)
iflag = -1;
error('reduced_Newton:
calc_f returns vector of improper length');
end
% ensure f is a column vector
if(size(f,1)~=Nvar)
f = f';
end
% Obtain initial norm of the function vector
for later
% convergence tests.
f0_norm_inf = max(abs(f));
f_norm_2sq = dot(f,f);
% Record initial state and function vectors
in trajectory.
count_traj = 1;
x_traj(count_traj,:) = x';
f_traj(count_traj,:) = f';
% Set the flag telling us to perform weak
line searches.
i_do_LS = 1;
% Begin Newton's method iterations
for iter = 1:Options.max_iter
% calculate the Jacobian
Jac = feval(calc_Jac,x,Param);
% Solve the set of linear
equations for the full line step
try
p
= Jac\(-f);
catch
iflag
= -2;
error('reduced_Newton:
full Newton step calculation error');
end
% Now, reduce the
magnitude of the Newton step if the user has
% specified a maximum
change allowable for each component.
if(Options.use_range)
%
Calculate the unit vector lying in the Newton line search
%
direction.
p_length
= norm(p,2);
p_unit
= p/p_length;
%
Calculate the maximum step in this direction allowable under
%
the condition that each state variable must not change by
%
a magnitude greater than the specified range for that variable.
step_allow
= max(abs(Options.range));
for
ivar=1:Nvar
try
step_ivar = abs(Options.range(ivar)/p_unit(ivar));
if(step_ivar < step_allow)
step_allow = step_ivar;
end
end
end
step_allow
= min(step_allow,p_length);
p
= p_unit*step_allow;
end
% Begin the weak line
search
if(i_do_LS) %
perform a weak line search
for
iter_LS = 0:Options.max_iter_LS
iconv_LS = 0;
% Calculate fractional step length
lambda
= 2^(-iter_LS);
% Calculate new solution estimate
x_new = x + lambda*p;
% Calculate function at the new solution estimate
f_new = feval(calc_f,x_new,Param);
% Check descent criterion
f_new_norm_2sq = dot(f_new,f_new);
if(f_new_norm_2sq <= f_norm_2sq)
x = x_new;
f = f_new;
f_norm_2sq = f_new_norm_2sq;
iconv_LS = 1;
break;
end
end
%
If we did not satisfy descent condition, update
%
with final result.
if(~iconv_LS)
x = x_new;
f = f_new;
f_norm_2sq = f_new_norm_2sq;
end
else % use full
Newton step instead
%
Calculate new solution estimate
x
= x + p;
%
Calculate function at the new solution estimate
f
= feval(calc_f,x,Param);
end
% if in verbose mode,
record state and function vectors
if(Options.verbose)
count_traj
= count_traj + 1;
x_traj(count_traj,:)
= x';
f_traj(count_traj,:)
= f';
end
% check for convergence
to the solution
f_norm_inf = max(abs(f));
i_conv_rel = 0;
if(f_norm_inf <=
Options.rtol*f0_norm_inf)
i_conv_rel
= 1;
end
i_conv_abs = 0;
if(f_norm_inf <=
Options.atol)
i_conv_abs
= 1;
end
if((i_conv_rel==1)&(i_conv_abs==1))
iter_conv
= iter;
iflag
= 1;
break;
end
% Check to see whether
need to perform a line search
% at the next step.
if(f_norm_inf <=
Options.step_tol)
i_do_LS
= 0;
else
i_do_LS
= 1;
end
end
return;