Heidelberg Educational Numerics Library Version 0.24 (from 9 September 2011)

src/newton.hh

Go to the documentation of this file.
00001 // -*- tab-width: 4; indent-tabs-mode: nil -*-
00002 #ifndef HDNUM_NEWTON_HH
00003 #define HDNUM_NEWTON_HH
00004 
00005 #include "lr.hh"
00006 
00011 namespace hdnum {
00012 
00019   template<class N>
00020   class SquareRootProblem
00021   {
00022   public:
00024     typedef std::size_t size_type;
00025 
00027     typedef N number_type;
00028 
00030     SquareRootProblem (number_type a_)
00031       : a(a_)
00032     {}
00033 
00035     std::size_t size () const
00036     {
00037       return 1;
00038     }
00039 
00041     void F (const Vector<N>& x, Vector<N>& result) const
00042     {
00043       result[0] = x[0]*x[0] - a;
00044     }
00045 
00047     void F_x (const Vector<N>& x, DenseMatrix<N>& result) const
00048     {
00049       result[0][0] = number_type(2.0)*x[0];
00050     }
00051 
00052   private:
00053     number_type a;
00054   };
00055 
00056 
00063   class Newton
00064   {
00065     typedef std::size_t size_type;
00066 
00067   public:
00069     Newton ()
00070       : maxit(25), linesearchsteps(10), verbosity(0), 
00071         reduction(1e-14), abslimit(1e-30), converged(false)
00072     {}
00073 
00075     void set_maxit (size_type n)
00076     {
00077       maxit = n;
00078     }
00079 
00081     void set_linesearchsteps (size_type n)
00082     {
00083       linesearchsteps = n;
00084     }
00085 
00087     void set_verbosity (size_type n)
00088     {
00089       verbosity = n;
00090     }
00091 
00093     void set_abslimit (double l)
00094     {
00095       abslimit = l;
00096     }
00097 
00099     void set_reduction (double l)
00100     {
00101       reduction = l;
00102     }
00103 
00105     template<class M>
00106     void solve (const M& model, Vector<typename M::number_type> & x) const
00107     {
00108       typedef typename M::number_type N;
00109       Vector<N> r(model.size());              // residual
00110       DenseMatrix<N> A(model.size(),model.size()); // Jacobian matrix
00111       Vector<N> y(model.size());              // temporary solution in line search
00112       Vector<N> z(model.size());              // solution of linear system
00113       Vector<N> s(model.size());              // scaling factors
00114       Array<size_type> p(model.size());                 // row permutations
00115       Array<size_type> q(model.size());                 // column permutations
00116 
00117       model.F(x,r);                                     // compute nonlinear residual
00118       N R0(norm(r));                          // norm of initial residual
00119       N R(R0);                                // current residual norm
00120       if (verbosity>=1)
00121         {
00122           std::cout << "Newton " 
00123                     << "   norm=" << std::scientific << std::showpoint 
00124                     << std::setprecision(4) << R0
00125                     << std::endl;
00126         }
00127 
00128       converged = false;
00129       for (size_type i=1; i<=maxit; i++)                // do Newton iterations
00130         {
00131           // check absolute size of residual
00132           if (R<=abslimit)
00133             {
00134               converged = true;
00135               return;
00136             } 
00137 
00138           // solve Jacobian system for update
00139           model.F_x(x,A);                               // compute Jacobian matrix
00140           row_equilibrate(A,s);                         // equilibrate rows
00141           lr_fullpivot(A,p,q);                          // LR decomposition of A
00142           z = N(0.0);                                   // clear solution
00143           apply_equilibrate(s,r);                       // equilibration of right hand side
00144           permute_forward(p,r);                         // permutation of right hand side
00145           solveL(A,r,r);                                // forward substitution
00146           solveR(A,z,r);                                // backward substitution
00147           permute_backward(q,z);                        // backward permutation
00148 
00149           // line search
00150           N lambda(1.0);                      // start with lambda=1
00151           for (size_type k=0; k<linesearchsteps; k++)
00152             {
00153               y = x;                                    
00154               y.update(-lambda,z);                       // y = x+lambda*z
00155               model.F(y,r);                             // r = F(y)
00156               N newR(norm(r));                // compute norm
00157               if (verbosity>=3)
00158                 {
00159                   std::cout << "    line search "  << std::setw(2) << k 
00160                             << " lambda=" << std::scientific << std::showpoint 
00161                             << std::setprecision(4) << lambda
00162                             << " norm=" << std::scientific << std::showpoint 
00163                             << std::setprecision(4) << newR
00164                             << " red=" << std::scientific << std::showpoint 
00165                             << std::setprecision(4) << newR/R
00166                             << std::endl;
00167                 }
00168               if (newR<(1.0-0.25*lambda)*R)            // check convergence
00169                 {
00170                   if (verbosity>=2)
00171                     {
00172                       std::cout << "  step"  << std::setw(3) << i 
00173                                 << " norm=" << std::scientific << std::showpoint 
00174                                 << std::setprecision(4) << newR
00175                                 << " red=" << std::scientific << std::showpoint 
00176                                 << std::setprecision(4) << newR/R
00177                                 << std::endl;
00178                     }
00179                   x = y;
00180                   R = newR;
00181                   break;                                // continue with Newton loop
00182                 }
00183               else lambda *= 0.5;                       // reduce damping factor
00184               if (k==linesearchsteps-1)
00185                 {
00186                   if (verbosity>=3)
00187                     std::cout << "    line search not converged within " << linesearchsteps << " steps" << std::endl;
00188                   return;
00189                 }
00190             }
00191 
00192           // check convergence
00193           if (R<=reduction*R0)
00194             {
00195               if (verbosity>=1)
00196                 {
00197                   std::cout << "Newton converged in "  << i << " steps"
00198                             << " reduction=" << std::scientific << std::showpoint 
00199                             << std::setprecision(4) << R/R0
00200                             << std::endl;
00201                 }
00202               converged = true;
00203               return;
00204             }
00205           if (i==maxit)
00206             {
00207               if (verbosity>=2)
00208                 std::cout << "Newton not converged within " << maxit << " iterations" << std::endl;
00209             }
00210         }
00211     }
00212     
00213     bool has_converged () const
00214     {
00215       return converged;
00216     }
00217 
00218   private:
00219     size_type maxit;
00220     size_type linesearchsteps;
00221     size_type verbosity;
00222     double reduction;
00223     double abslimit;
00224     mutable bool converged;
00225   };
00226 
00227 
00228 
00229 
00237   class Banach
00238   {
00239     typedef std::size_t size_type;
00240 
00241   public:
00243     Banach ()
00244       : maxit(25), linesearchsteps(10), verbosity(0), 
00245         reduction(1e-14), abslimit(1e-30),  sigma(1.0), converged(false)
00246     {}
00247 
00249     void set_maxit (size_type n)
00250     {
00251       maxit = n;
00252     }
00253 
00255     void set_sigma (double sigma_)
00256     {
00257       sigma = sigma_;
00258     }
00259 
00261     void set_linesearchsteps (size_type n)
00262     {
00263       linesearchsteps = n;
00264     }
00265 
00267     void set_verbosity (size_type n)
00268     {
00269       verbosity = n;
00270     }
00271 
00273     void set_abslimit (double l)
00274     {
00275       abslimit = l;
00276     }
00277 
00279     void set_reduction (double l)
00280     {
00281       reduction = l;
00282     }
00283 
00285     template<class M>
00286     void solve (const M& model, Vector<typename M::number_type> x) const
00287     {
00288       typedef typename M::number_type N;
00289       Vector<N> r(model.size());              // residual
00290       Vector<N> y(model.size());              // temporary solution in line search
00291 
00292       model.F(x,r);                           // compute nonlinear residual
00293       N R0(norm(r));                          // norm of initial residual
00294       N R(R0);                                // current residual norm
00295       if (verbosity>=1)
00296         {
00297           std::cout << "Banach " 
00298                     << " norm=" << std::scientific << std::showpoint 
00299                     << std::setprecision(4) << R0
00300                     << std::endl;
00301         }
00302 
00303       converged = false;
00304       for (size_type i=1; i<=maxit; i++)                // do iterations
00305         {
00306           // check absolute size of residual
00307           if (R<=abslimit)
00308             {
00309               converged = true;
00310               return;
00311             } 
00312 
00313           // next iterate
00314           y = x;                                    
00315           y.update(-sigma,r);                       // y = x+lambda*z
00316           model.F(y,r);                             // r = F(y)
00317           N newR(norm(r));                // compute norm
00318           if (verbosity>=2)
00319             {
00320               std::cout << "    "  << std::setw(3) << i 
00321                         << " norm=" << std::scientific << std::showpoint 
00322                         << std::setprecision(4) << newR
00323                         << " red=" << std::scientific << std::showpoint 
00324                         << std::setprecision(4) << newR/R
00325                         << std::endl;
00326             }
00327           x = y;                                // accept new iterate
00328           R = newR;                             // remember new norm
00329 
00330           // check convergence
00331           if (R<=reduction*R0 || R<=abslimit)
00332             {
00333               if (verbosity>=1)
00334                 {
00335                   std::cout << "Banach converged in "  << i << " steps"
00336                             << " reduction=" << std::scientific << std::showpoint 
00337                             << std::setprecision(4) << R/R0
00338                             << std::endl;
00339                 }
00340               converged = true;
00341               return;
00342             }
00343         }
00344     }
00345     
00346     bool has_converged () const
00347     {
00348       return converged;
00349     }
00350 
00351   private:
00352     size_type maxit;
00353     size_type linesearchsteps;
00354     size_type verbosity;
00355     double reduction;
00356     double abslimit;
00357     double sigma;
00358     mutable bool converged;
00359   };
00360 
00361 } // namespace hdnum
00362 
00363 #endif