% Script: rootfind % Programmer: t. shores % Last Rev: 7/1/02 % Description: % A package of functions for solving the vector equation f(x)=0. % Some routines may be oriented towards optimization. % not a function file: 1; % preliminary tools function retval = arrayf(fname,arr) % usage: arrayf(fname,arr) % description: this returns the matrix resulting from replacing % each coordinate of arr by its evaluation by the function with % name fname. % local variables % ii,jj: index variables % nr,nc: number of rows, cols [nr,nc] = size(arr); retval = zeros(nr,nc); for ii = 1:nr for jj = 1:nc retval(ii,jj) = feval(fname,arr(ii,jj)); end; end; endfunction % function retval = testfn(x) retval = zeros(3,1); retval(1) = 3*x(1)-cos(x(2)*x(3))-0.5; retval(2) = x(1)^2-81*(x(2)+0.1)^2+sin(x(3))+1.06; retval(3) = exp(-x(1)*x(2))+20*x(3)+(10*pi-3)/3; endfunction % function retval = testf(x) retval = testfn(x)'*testfn(x); endfunction % function retval = jacob(fname,x,h,m) % usage: retval = jacob(fname,x,h,m) % description: An unsophisticated Jacobian calculation using % certered differences. fname(x) and x are *assumed* vector and % fname(x) is *assumed* a column vector of length m. % local variables % jj: index variable % nx: length of x nx = length(x); retval = zeros(m,nx); for jj = 1:nx dx = zeros(size(x)); dx(jj) = h; retval(:,jj) = (feval(fname,x+dx)-feval(fname,x-dx))/(2*h); end; endfunction % rootfinders function [x,resid] = newton(fname,x0,iterlim,h) % usage: [x,resid] = newton(fname,x0,iterlim,h) % description: Classical Newton method for vector equation % f(x)=0, with f,x n-vectors. Input function name, initial % vector guess, iteration limit and stepsize for numerical % derivative. Output final x, optionally norm of residual % at final x. Stopping criterion is reaching iterlim. % local variables % kk: iteration counter % x: looping values of x iterates % n: length of x and f x = x0; n = length(x); for ii = 1:iterlim x = x - jacob(fname,x,h,n)\feval(fname,x); end; resid = norm(feval(fname,x),inf); endfunction % function [xnew,resid,kk,nn] = modnewton(fname,x0,iterlim,h) % usage: [x,res,kk,nn] = modnewton(fname,x0,iterlim,h) % description: a modified Newton's method applied to % nonlinear equation fn(x) = 0. Input function name, initial % vector guess, iteration limit and stepsize for numerical % derivative. Output final x, optionally norm of residual % at final x, iteration number and restart number. % Uses Armijo search, restart and stopping criteria. Stores % full Jacobian. % local variables: % stopr,stopa: relative and absolute stopping coefficients % kk,nn: iteration counter, restart counter % xold, xnew: vectors for iteration % n: length of x and f % B: inverse of Jacobian or approximation matrix % s: search direction % lambda: search direction parameter % p: difference in x steps % q: difference of residuals % restartf: restart flag % normf0: norm of initial function value % initialization stopr = 1e-7; stopa = 1e-11; xold = x0; n = length(xold); normf0 = norm(feval(fname,x0),inf); B = inv(jacob(fname,xold,h,n)); nn = 1; restartf = 1; for kk = 1:iterlim s = -B*feval(fname,xold); lambda = search(fname,xold,s); if (lambda == 0) if (restartf ==1) disp('Failure of Newton direction to reduce ||f(x)||'); resid = norm(feval(fname,xold),inf); return; else % need to really do a restart B = inv(jacob(fname,xold,h,n)); nn = nn + 1; restart = 1; continue; end end % can now assume search direction succeeded xnew = xold + lambda*s; % so do a Broyden update p = xnew - xold; q = feval(fname,xnew) - feval(fname,xold); u = B*q-p; v = p/(p'*p); B = (eye(n) - u*v'/(1+v'*u))*B; restart = 0; xold = xnew; % test for termination if (norm(feval(fname,xnew),inf) <= stopr*normf0 + stopa) break; end end resid = norm(feval(fname,xold),inf); endfunction % function lambda = search(fname,x,d) % usage: lambda = search(fname,x,d) % a routine to calculate search direction parameter lambda<=1 % for a modified Newton method. Failure signalled by lambda=0. % local variables: % alpha: sufficient decrease parameter % maxhalf: maximum number of halvings % jj: index variable % xtmp,ftmp,normfx: temporaries alpha = 1e-4; maxhalf = 8; jj = 0; lambda = 2; normfx = norm(feval(fname,x),inf); while (jj < maxhalf) lambda = lambda/2; xtmp = x + lambda*d; ftmp = feval(fname,xtmp); if (norm(ftmp,inf) < (1-alpha*lambda)*normfx) break; end; jj = jj + 1; end if (jj == maxhalf) lambda = 0; end endfunction %