The code below represents a typical speedup of the order of to over Mathematica's FindRoot (depending on the size of the problem). However, this example will only find real roots of a system of equations and is thus less robust. The limitation here is the linear solution routine (not the translation of complex-valued expressions into FORTRAN). Analogous linear solution routines for complex systems exist (see routines cgesv.f and zgesv.f from [1]), but are considerably more expensive to implement in terms of the arithmetic overhead involved.
In[4]:= !!newton.mf program newton implicit double precision(a-h,o-z) double precision jac logical fconv,xconv integer dim dimension x(<* SetOptions[FortranAssign,AssignToArray->{x}]; (***** General problem formulation. *****) (* Input equations in variables x[i]. *) f = { Sin[x[1] x[2]^2] - 1, Exp[ Cos[x[1]/x[2]] ] - 1 }; (* Input initial values - must the same dimension as f. *) init = {1.,.5}; (***** End of required input. *****) dim = Length[f]; vars = Array[x,dim]; dim *>) dimension jac(<* dim *>,<* dim *>),ipiv(<* dim *>) dimension f(<* dim *>),xnew(<* dim *>) data dim/<* dim *>/ c c Specify convergence criteria and maximum number of iterations. c data maxit/30/,relerr/1.d-10/,abserr/1.d-10/,fmaxerr/5.d-9/ <* (***** Assign initial values to x. *****) FortranAssign[x,init] *> do 10 i = 1,dim xnew(i) = x(i) 10 continue do 20 k = 1,maxit <* (***** Calculate Jacobian Matrix. *****) FortranAssign[jac,Outer[D,f,vars]] *> <* FortranAssign[f,f] *> c c LU decomposition of Jacobian matrix. c call dgetrf(dim,dim,jac,dim,ipiv,info) c c Linear solution routine overwriting f with solution. c call dgetrs('No transpose',dim,1,jac,dim,ipiv,f,dim,info) c c Update solution and error indicators. c fconv = .true. xconv = .true. xmaxdiff = 0.d0 xmax = 0.d0 do 30 i = 1,dim xnew(i) = x(i) - f(i) if (abs(f(i)).gt.fmaxerr) then fconv = .false. endif xnewabs = abs(xnew(i)) if (xnewabs.gt.xmax) then xmax = xnewabs endif xdiff = abs(xnewabs - abs(x(i))) if (xdiff.gt.xmaxdiff) then xmaxdiff = xdiff endif 30 continue do 40 i = 1,dim x(i) = xnew(i) 40 continue if (xmaxdiff.gt.(relerr*xmax+abserr)) then xconv = .false. endif c c Test if convergence criteria are satisfied. c if (fconv.and.xconv) then goto 50 else if (k.eq.maxit) then write(*,100) k endif endif 20 continue c c Output solution vector. c 50 do 60 i = 1,dim write(*,*) x(i) 60 continue 100 format('Newton scheme did not converge after ', & i2,' iterations') stop endThe template file is then processed as follows.
In[5]:= Splice["newton.mf",FormatType->OutputForm]; In[6]:= !!newton.f program newton implicit double precision(a-h,o-z) double precision jac logical fconv,xconv integer dim dimension x(2) dimension jac(2,2),ipiv(2) dimension f(2),xnew(2) data dim/2/ c c Specify convergence criteria and maximum number of iterations. c data maxit/30/,relerr/1.d-10/,abserr/1.d-10/,fmaxerr/5.d-9/ x(1)=1. x(2)=0.5 do 10 i = 1,dim xnew(i) = x(i) 10 continue do 20 k = 1,maxit jac(1,1)=cos(x(1)*x(2)**2)*x(2)**2 jac(1,2)=2.*cos(x(1)*x(2)**2)*x(1)*x(2) jac(2,1)=-(exp(cos(x(1)/x(2)))*sin(x(1)/x(2))/x(2)) jac(2,2)=exp(cos(x(1)/x(2)))*sin(x(1)/x(2))*x(1)/x(2)**2 f(1)=-1.+sin(x(1)*x(2)**2) f(2)=-1.+exp(cos(x(1)/x(2))) c c LU decomposition of Jacobian matrix. c call dgetrf(dim,dim,jac,dim,ipiv,info) c c Linear solution routine overwriting f with solution. c call dgetrs('No transpose',dim,1,jac,dim,ipiv,f,dim,info) c c Update solution and error indicators. c fconv = .true. xconv = .true. xmaxdiff = 0.d0 xmax = 0.d0 do 30 i = 1,dim xnew(i) = x(i) - f(i) if (abs(f(i)).gt.fmaxerr) then fconv = .false. endif xnewabs = abs(xnew(i)) if (xnewabs.gt.xmax) then xmax = xnewabs endif xdiff = abs(xnewabs - abs(x(i))) if (xdiff.gt.xmaxdiff) then xmaxdiff = xdiff endif 30 continue do 40 i = 1,dim x(i) = xnew(i) 40 continue if (xmaxdiff.gt.(relerr*xmax+abserr)) then xconv = .false. endif c c Test if convergence criteria are satisfied. c if (fconv.and.xconv) then goto 50 else if (k.eq.maxit) then write(*,100) k endif endif 20 continue c c Output solution vector. c 50 do 60 i = 1,dim write(*,*) x(i) 60 continue 100 format('Newton scheme did not converge after ', & i2,' iterations') stop end