Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

guma_newton.cpp

Go to the documentation of this file.
00001 /* LIBGUL - Geometry Utility Library
00002  * Copyright (C) 1998-1999 Norbert Irmer
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include "stdafx.h"
00021 
00022 #include <iostream>
00023 
00024 #include "gul_types.h"
00025 #include "gul_matrix.h"
00026 #include "guma_lineq.h"
00027 #include "guma_newton.h"
00028 
00029 
00030 namespace guma {
00031 
00032 using gul::Ptr;
00033 using gul::rtr;
00034 using gul::Max;
00035 using gul::MCopy;
00036 
00037 /********************************************************************
00038 
00039   This file contains Newton-Iteration related functions,
00040   taken from "Numerical Recipes in C"
00041 
00042 *********************************************************************/
00043 
00044 /*-------------------------------------------------------------------
00045   Search along a direction 'P' for a point, where function values have
00046   decreased sufficiently (<ALF)
00047 ---------------------------------------------------------------------*/
00048 
00049 template< class T >
00050 bool LinearSearch( 
00051               const Ptr<T>& p,     /* Newton direction (domain) */
00052               const Ptr<T>& xold,  /* starting point (domain) */
00053               T fold,              /* function value at start point */
00054               const Ptr<T>& g,     /* gradient of function at 'xold' */
00055               const Ptr<T>& x1,    /* bounds for x */
00056               const Ptr<T>& x2,
00057               newton_info<T>& I,   /* defines function and tolerances */
00058  
00059               bool&    found,
00060               bool&    check,      /* returns if convergence must be checked */
00061                                    /* (i.e. |x_{i+1}-x_{i}| < TOLX)          */
00062               Ptr<T>&  x,          /* return: point in domain */
00063               T       *fx          /* return: function value there */
00064             )
00065 {
00066   T sum, slope, test, temp, alamin, alam, alphamin, alpha, stpmax;
00067   T a, b, alam2, disc, f2, fold2, rhs1, rhs2, tmplam;
00068   int i, n;
00069   T f;
00070   
00071   found = false;
00072   n = I.dim;
00073 
00074   // maximale Schrittweite bestimmen
00075 
00076   alphamin = 1.0;
00077   
00078   for( i = 0; i < n; i++ )
00079   {
00080     if( xold[i] + p[i] < x1[i] )
00081       alpha = (x1[i] - xold[i]) / p[i];
00082     else if( xold[i] + p[i] > x2[i] )
00083       alpha = (x2[i] - xold[i]) / p[i];
00084     else
00085       alpha = 1.0;
00086 
00087     if( rtr<T>::fabs(alpha) == 0.0 )
00088     {
00089       p[i] = 0.0;
00090       alpha = 1.0;   
00091     }
00092   
00093     if( alpha < alphamin )
00094       alphamin = alpha;  
00095   }        
00096     
00097   for( sum = 0.0, i = 0; i < n; i++ )
00098     sum += p[i] * p[i];
00099 
00100   stpmax = rtr<T>::fabs(alphamin) * rtr<T>::sqrt(sum);
00101 
00102   /*-------------------------------------------------------------*/
00103 
00104   for( sum = 0.0, i = 0; i < n; i++ )
00105     sum += p[i] * p[i];
00106   sum = rtr<T>::sqrt( sum );  
00107   
00108   if( sum > stpmax )
00109     for( i = 0; i < n; i++ )
00110       p[i] *= stpmax / sum;      /* Skalieren, falls Schritt zu gross */
00111       
00112   for( slope = 0.0, i = 0; i < n; i++ )
00113     slope += g[i] * p[i];      
00114       
00115   test = 0.0;
00116   
00117   for( i = 0; i < n; i++ )
00118   {
00119     temp = rtr<T>::fabs(p[i]) / Max(rtr<T>::fabs(xold[i]),(T)1);     
00120     if( temp > test ) test = temp;
00121   }
00122   if( test == (T)0 ) test = rtr<T>::tiny();
00123   
00124   alamin = I.tolx / test;
00125   alam = (T)1;              /* Im ersten Durchgang volle Schrittweite */
00126       
00127   for( ;; )
00128   {
00129     for( i = 0; i < n; i++ )            
00130     {
00131       x[i] = xold[i] + alam * p[i];
00132 
00133       if( x[i] < x1[i] ) x[i] = x1[i];
00134       else if( x[i] > x2[i] ) x[i] = x2[i];
00135     } 
00136 
00137     found = I.calcf( x, &f );
00138     if( found ) { check = false; break; }
00139     
00140     if( alam < alamin )           /* Konvergenz von dx,                     */
00141     {                             /* aufrufendes Programm sollte Konvergenz */
00142       for( i = 0; i < n; i++ )    /* verifizieren                           */
00143         x[i] = xold[i];
00144       check = true;
00145       break;  
00146     }
00147 
00148     if( f <= fold + I.alf * alam * slope )  /* Funktionswert nimmt stark */
00149     { check = false;  break; }              /* genug ab */
00150 
00151     if( alam == (T)1 )                             /* falls 1.Durchgang */
00152       tmplam = -slope / ((T)2 * (f-fold-slope));
00153     else  
00154     {
00155       rhs1 = f - fold - alam * slope;
00156       rhs2 = f2 - fold2 - alam2 * slope;
00157       a = (rhs1/(alam*alam) - rhs2/(alam2*alam2)) / (alam-alam2);
00158       b = (-alam2*rhs1/(alam*alam) + alam*rhs2/(alam2*alam2)) / (alam-alam2);
00159        
00160       if( a == (T)0 )
00161         tmplam = -slope/((T)2*b);
00162       else
00163       {
00164         disc = b*b - (T)3*a*slope;
00165 
00166         if( disc < (T)0 )     /* roundoff problem */
00167           return false;    
00168 
00169         tmplam = (-b + rtr<T>::sqrt(disc)) / ((T)3*a);
00170       }
00171       
00172       if( tmplam > (T)0.5 * alam )
00173         tmplam = (T)0.5 * alam;        /* lambda <= 0.5 * lambda1  */            
00174     }        
00175     
00176     alam2 = alam;
00177     f2 = f;
00178     fold2 = fold;
00179     alam = Max( tmplam, (T)0.1*alam );   /* lambda >= 0.1 * lambda1  */ 
00180   }  
00181     
00182   *fx = f;
00183   return true;  
00184 }    
00185 // template instantiations
00186 template bool LinearSearch( 
00187               const Ptr<float>& p,     /* Newton direction (domain) */
00188               const Ptr<float>& xold,  /* starting point (domain) */
00189               float fold,              /* function value at start point */
00190               const Ptr<float>& g,     /* gradient of function at 'xold' */
00191               const Ptr<float>& x1,    /* bounds for x */
00192               const Ptr<float>& x2,   
00193               newton_info<float>& I,   /* defines function and tolerances */
00194 
00195               bool& found,
00196               bool& check,         /* returns if convergence must be checked */
00197                                    /* (i.e. |x_{i+1}-x_{i}| < TOLX)          */
00198               Ptr<float>& x,           /* return: point in domain */
00199               float *fx                /* return: function value there */
00200             );
00201 
00202 
00203 
00204 /*------------------------------------------------------------------------
00205   Searches a root of a function, with n-dimensional domain and 
00206   n-dimensional function values. (see "Numerical Recipes in C")
00207   in:
00208     domain:           [x1[0],x2[0]] * ... * [x1[n-1],x2[n-1]]
00209     start value:      (x[0],...,x[n-1])
00210   out:
00211     root:             (x[0],...,x[n-1])
00212 -----------------------------------------------------------------------*/
00213 
00214 template< class T >
00215 bool Newton(
00216          Ptr<T>& x,
00217          const Ptr<T>& x1,
00218          const Ptr<T>& x2,
00219          newton_info<T>& I,
00220          int maxits )
00221 {
00222   int its, i, j, n;
00223   T f, fold, sum, temp, test;
00224   bool result, found, check;
00225   Ptr<int> indx;
00226   Ptr<T> g,p,xold;
00227   Ptr< Ptr<T> > A;
00228   int sign;
00229 
00230   n = I.dim;
00231 
00232   A.reserve_pool(n);
00233   for( i = 0; i < n; i++ )
00234     A[i].reserve_pool(n);
00235 
00236   indx.reserve_pool(n);
00237   g.reserve_pool(n);
00238   p.reserve_pool(n);
00239   xold.reserve_pool(n);
00240      
00241   /* ------- Hauptschleife: ---------------------------------------- */  
00242 
00243   found = I.calcf( x, &f );
00244   if( found ) { return true; }
00245 
00246   for( its = 1; its < maxits; its++ )
00247   { 
00248     for( i = 0; i < n; i++ )              /* Gradient von f=1/2*F*F */
00249     {                                     /* berechnen (=> df = F*J */
00250       for( sum = 0.0, j = 0; j < n; j++ )
00251         sum += I.fvec[j] * I.fjac[j][i];
00252       g[i] = sum;  
00253     }
00254 
00255     for( i = 0; i < n; i++ )
00256       xold[i] = x[i];
00257     fold = f;
00258     
00259     for( i = 0; i < n; i++ )
00260       p[i] = -I.fvec[i];              /* rechte Seite der Gleichung */
00261 
00262     MCopy(n,n,I.fjac,A);
00263     result = LUDecomposition( n, A, &sign, indx );
00264     if( !result ) return(false);
00265     LUBackSubstitution( n, indx, A, p );
00266 
00267     /* ------------------------------------------------------------------- */
00268 
00269     result = LinearSearch( p, xold, fold, g, x1, x2, I, found, check, x, &f );  
00270     // if( (!result) || check ) return false;
00271     if( !result ) return false;
00272 
00273     // convergence of dx may happen when there is no better solution then a
00274     // point on the border of the surface, so for the time beeing i am
00275     // simply ignoring the 'check' flag (i am not sure, if this is allright
00276     // in all cases)
00277 
00278     if( found ) { return true; }
00279 
00280     test = 0.0;
00281     for( i = 0; i < n; i++ )
00282     {
00283       temp = (rtr<T>::fabs(x[i]-xold[i])) / Max(rtr<T>::fabs(x[i]),(T)1);
00284       if( temp > test ) test = temp;
00285     }  
00286     if( test < I.tolx ) return true;
00287   }
00288 
00289   /* maximum iterations exceeded */
00290   return false;
00291 }    
00292 // template instantiations
00293 template bool Newton(
00294          Ptr<float>& x,
00295          const Ptr<float>& x1,
00296          const Ptr<float>& x2,
00297          newton_info<float>& I,
00298          int maxits );
00299 template bool Newton(
00300          Ptr<double>& x,
00301          const Ptr<double>& x1,
00302          const Ptr<double>& x2,
00303          newton_info<double>& I,
00304          int maxits );
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 #if 0
00313 
00314 *******************************************************************
00315 old version
00316 *******************************************************************
00317 
00318 
00319 /*------------------------------------------------------------------------
00320   Searches a root of a function, with n-dimensional domain and 
00321   n-dimensional function values. (see "Numerical Recipes in C")
00322   in:
00323     domain:           [x1[0],x2[0]] x ... x [x1[n-1],x2[n-1]]
00324     start value:      (x[0],...,x[n-1])
00325     function values:  fvec
00326     Jacobi Matrix:    fjac
00327   out:
00328     root:             (x[0],...,x[n-1])
00329     check:            if TRUE(!=0), try again with another start value
00330 -----------------------------------------------------------------------*/
00331 
00332 template< class T >
00333 bool Newton(
00334          Ptr<T>& x,
00335          const Ptr<T>& x1,
00336          const Ptr<T>& x2,
00337          newton_info<T>& I,
00338          int maxits,
00339          bool& check
00340        )
00341 {
00342   T a;
00343   int its, i, j, n;
00344   T den, f, fold, stpmax, sum, temp, test;
00345   T alpha, alphamin;
00346   bool result;
00347   Ptr<int> indx;
00348   Ptr<T> g,p,xold;
00349   Ptr< Ptr<T> > A;
00350   int sign;
00351 
00352   n = I.dim;
00353 
00354   A.reserve_pool(n);
00355   for( i = 0; i < n; i++ )
00356     A[i].reserve_pool(n);
00357 
00358   indx.reserve_pool(n);
00359   g.reserve_pool(n);
00360   p.reserve_pool(n);
00361   xold.reserve_pool(n);
00362 
00363   f = I.calcf( x );
00364 
00365   for( test = (T)0, i = 0; i < n; i++ ) /* Pruefen ob Startwert Nullstelle */  
00366   {
00367     a = rtr<T>::fabs(I.fvec[i]);
00368     if( a > test ) test = a;
00369   }
00370   if( test < (T)0.01 * I.tolf )             /* falls ja */
00371   {
00372     check = false;
00373     return true;    
00374   }      
00375 
00376   /*
00377   // maximale Schrittweite fuer LinearSearch bestimmen:
00378   for( sum = 0.0, i = 0; i < n; i++ )
00379   sum += x[i] * x[i];
00380     
00381   stpmax = STPMAX * NUAR_MAX( sqrt(sum), (NURational)n );
00382   */
00383      
00384   /* ------- Hauptschleife: ---------------------------------------- */  
00385 
00386   for( its = 1; its < maxits; its++ )
00387   {
00388     I.Fjac( x );     /* Jakobi Matrix berechnen */  
00389 
00390     for( i = 0; i < n; i++ )              /* Gradient von f=1/2*F*F */
00391     {                                     /* berechnen (=> df = F*J */
00392       for( sum = 0.0, j = 0; j < n; j++ )
00393         sum += I.fvec[j] * I.fjac[j][i];
00394       g[i] = sum;  
00395     }
00396 
00397     for( i = 0; i < n; i++ )
00398       xold[i] = x[i];
00399     fold = f;
00400     
00401     for( i = 0; i < n; i++ )
00402       p[i] = -I.fvec[i];              /* rechte Seite der Gleichung */
00403 
00404     MCopy(n,n,I.fjac,A);
00405     result = LUDecomposition( n, A, &sign, indx );
00406     if( !result ) return(false);
00407     LUBackSubstitution( n, indx, A, p );
00408 
00409     /* --- maximale Schrittweite fuer LinearSearch bestimmen: ----------- */ 
00410 
00411     alphamin = 1.0;
00412   
00413     for( i = 0; i < n; i++ )
00414     {
00415       if( xold[i] + p[i] < x1[i] )
00416         alpha = (x1[i] - xold[i]) / p[i];
00417       else if( xold[i] + p[i] > x2[i] )
00418         alpha = (x2[i] - xold[i]) / p[i];
00419       else
00420         alpha = 1.0;
00421 
00422       if( rtr<T>::fabs(alpha) == 0.0 )
00423       {
00424         p[i] = 0.0;
00425         alpha = 1.0;   
00426       }
00427   
00428       if( alpha < alphamin )
00429         alphamin = alpha;  
00430     }        
00431     
00432     for( sum = 0.0, i = 0; i < n; i++ )
00433       sum += p[i] * p[i];
00434 
00435     stpmax = rtr<T>::fabs(alphamin) * rtr<T>::sqrt(sum);
00436 
00437     /* ------------------------------------------------------------------- */
00438 
00439     result = LinearSearch( p, xold, fold, g, stpmax, I, check, x, &f );  
00440     if( !result ) return false;
00441     
00442     for( i = 0; i < n; i++ )
00443     {
00444       if( x[i] < x1[i] )
00445         x[i] = x1[i];
00446       else if( x[i] > x2[i] )
00447         x[i] = x2[i];  
00448     }
00449 
00450     for( test = 0.0, i = 0; i < n; i++ ) /* Pruefen: Funktionswerte konvergent*/
00451       if( fabs(I.fvec[i]) > test )
00452         test = rtr<T>::fabs(I.fvec[i]);
00453     if( test < 0.01 * I.tolf )  
00454     {
00455       check = false;              /* falls ja, Erfolg, Ende */
00456       return true;    
00457     }      
00458 
00459     if( check )                /* Pruefen ob Gradient von f = 1/2*F*F = 0 ist,*/
00460     {                          /* falls ja, besteht die Moeglichkeit, dass das*/
00461       test = 0.0;              /* Minimum von f nicht die gesuchte Nullstelle */
00462       den = Max( f, (T)0.5*(T)n );   /* von F ist !!!!!!                     */
00463       
00464       for( i = 0; i < n; i++ )
00465       {
00466         temp = rtr<T>::fabs(g[i])*Max(rtr<T>::fabs(x[i]), (T)1) / den;
00467         if( temp > test ) test = temp;
00468       }
00469       check = (test < I.tolmin ? true : false);
00470       return true;   
00471     }
00472 
00473     test = 0.0;
00474     for( i = 0; i < n; i++ )
00475     {
00476       temp = (rtr<T>::fabs(x[i]-xold[i])) / Max(rtr<T>::fabs(x[i]),(T)1);
00477       if( temp > test ) test = temp;
00478     }  
00479     if( test < I.tolx ) return true;
00480   }
00481 
00482   /* maximum iterations exceeded */
00483   return false;
00484 }    
00485 // template instantiations
00486 template bool Newton(
00487          Ptr<float>& x,
00488          const Ptr<float>& x1,
00489          const Ptr<float>& x2,
00490          newton_info<float>& I,
00491          int maxits );
00492 #endif
00493 
00494 
00495 
00496 }
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 

Generated on Mon Jan 21 04:17:34 2002 for GUL 0.6 - Geometry Utility Library by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001