realroot_doc 0.1.1
/Users/mourrain/Devel/mmx/realroot/include/realroot/system_descartes1d.hpp
Go to the documentation of this file.
00001 /********************************************************************
00002  *   This file is part of the source code of the realroot library.
00003  *   Author(s): J.P. Pavone, GALAAD, INRIA
00004  *   $Id: descartes1d.hpp,v 1.1 2005/07/11 10:03:57 jppavone Exp $
00005  ********************************************************************/
00006 #ifndef realroot_SOLVE_SBDSLV_USOLVER_DESCARTES1D_HPP
00007 #define realroot_SOLVE_SBDSLV_USOLVER_DESCARTES1D_HPP
00008 //--------------------------------------------------------------------
00009 #include <realroot/bernstein_bzenv.hpp>
00010 #include <realroot/loops_vctops.hpp>
00011 #include <realroot/loops_upoldse.hpp>
00012 #include <realroot/loops_brnops.hpp>
00013 //#include <arithmetix/TypeTests.h>
00014 //--------------------------------------------------------------------
00015 namespace mmx {
00016 //--------------------------------------------------------------------
00017 template< typename Prms >
00018 struct sign_wanted { typedef texp::false_t result_t; };
00019 
00020 namespace solvers
00021 {
00022   /* méthode locales */
00023   
00024   template<class real_t> 
00025   struct bsearch         /* bissection sous forme monomiale */
00026   {
00027     real_t * m_data;
00028     real_t * m_mons;
00029     unsigned m_sz;
00030     unsigned m_mxsz;
00031     
00032     template< class In > 
00033     /* initialisation: conversion sous forme monomiale */
00034     bsearch( const In&  bzrep,  unsigned sz ) : m_sz(sz) 
00035     {
00036       m_data = new real_t[ 2*sz ];
00037       std::copy( bzrep, bzrep + sz, m_data );
00038       m_mons = m_data + sz;
00039       std::copy( m_data, m_data + sz, m_mons );
00040       bernstein::bzenv<real_t>::_default_->toMonoms( m_mons, sz );
00041     };
00042     ~bsearch() { delete[] m_data; };
00043     /* bissection */
00044     void reach( real_t * lbzrep, real_t& a, real_t& b, const real_t& eps  ) 
00045     {
00046       real_t m;
00047       if ( lbzrep[m_sz-1] > lbzrep[0] ) 
00048         do
00049           if ( upoldse_::horner( m_mons, m_sz, m=(a+b)/2.0 ) < 0  ) a = m; else b = m; 
00050         while( b-a > eps ) ;
00051       else
00052         do
00053           if ( upoldse_::horner( m_mons, m_sz, m=(a+b)/2.0 ) < 0  ) b = m; else a = m;
00054         while( b-a > eps ); 
00055     };
00056   };
00057 
00058   template<class real_t> 
00059   struct bsearch_castel     /* bissection sous forme de Bernstein */
00060   {
00061     real_t * m_data;
00062     unsigned m_sz;
00063     template< class In >
00064     /* initialisation: copie de la forme de Bernstein */
00065     bsearch_castel( const In&  bzrep,  unsigned sz ) : m_sz(sz) 
00066     {
00067       m_data = new real_t[ sz ];
00068       std::copy( bzrep, bzrep + sz, m_data );
00069     };
00070     ~bsearch_castel() { delete[] m_data; };
00071     
00072     /* bissection */
00073     void reach( real_t * lbzrep, real_t& a, real_t& b, const real_t& eps  ) 
00074     {
00075       real_t m;
00076       if ( lbzrep[m_sz-1] > lbzrep[0] ) 
00077         do
00078           if ( brnops::eval( m_data, m_sz, m = (a+b)/2.0 ) < 0  ) a = m; else b = m; 
00079         while( b-a > eps ) ;
00080       else
00081         do
00082           if ( brnops::eval( m_data, m_sz, m = (a+b)/2.0 ) < 0  ) b = m; else a = m;
00083         while( b-a > eps ); 
00084     };
00085   };
00086   
00087   template<class real_t> 
00088   struct bsearch_newton       /* bissection / newton mix  */
00089   {
00090     real_t * m_data;
00091     real_t * m_mons;
00092     unsigned m_sz;
00093     template< class In >
00094     /* initialisation conversion sous forme monomiale */
00095     bsearch_newton( const In&  bzrep,  unsigned sz ) : m_sz(sz) 
00096     {
00097       m_data = new real_t[ 2*sz ];
00098       std::copy( bzrep, bzrep + sz, m_data );
00099       m_mons = m_data + sz;
00100       std::copy( m_data, m_data + sz, m_mons );
00101       bernstein::bzenv<real_t>::_default_->toMonoms( m_mons, sz );
00102     };
00103     ~bsearch_newton() { delete[] m_data; };
00104     
00105     /* bissection / newton mix */
00106     void reach( real_t * lbzrep, real_t& a, real_t& b, const real_t& eps  ) 
00107     {
00108       real_t m;
00109       if ( lbzrep[m_sz-1] > lbzrep[0] ) 
00110         do
00111           {
00112             real_t p,dp,x;
00113             /* évaluation du polynôme en m (p) et de sa derivée (dp) */
00114             upoldse_::dhorner( p, dp, m_mons, m_sz, m = (a+b)/2.0 );
00115             /* étape de bissection                                   */
00116             if ( p < 0  ) a = m; else b = m; 
00117             if ( dp > eps ) /* si la valeur de la derivée n'est pas trop faible */
00118               {
00119                 /* on fait une itération de la méthode de newton */
00120                 x = m - p/dp;
00121                 /* si le résultat est dans l'intervalle de la bissection */
00122                 if ( x > a && x < b )
00123                   {
00124                     /* évaluation du polynôme en ce point */
00125                     real_t xp = upoldse_::horner( m_mons, m_sz, x ); 
00126                     /* correction d'une des deux bornes */
00127                     if ( xp < 0 ) a = x; else b = x;
00128                     /* recherche de la seconde          */
00129                     if ( xp < 0 )
00130                       {
00131                         real_t step = eps;
00132                         while( xp < 0 && x < b )
00133                           {
00134                             x += step;
00135                             xp = upoldse_::horner( m_mons, m_sz, x );
00136                             step *= 2;
00137                           };
00138                         if ( x < b ) b = x;
00139                       }
00140                     else
00141                       {
00142                         real_t step = eps;
00143                         while( xp > 0 && x > a )
00144                           {
00145                             x -= step;
00146                             xp = upoldse_::horner( m_mons, m_sz, x );
00147                             step *= 2;
00148                           };
00149                         if ( x > a ) a = x;
00150                       };
00151                   };
00152               };
00153           }
00154         while( b-a > eps );
00155       else
00156         do
00157           {
00158             real_t p,dp,x;
00159             upoldse_::dhorner( p, dp, m_mons, m_sz, m = (a+b)/2.0 );
00160             if ( p < 0  ) b = m; else a = m; 
00161             if ( dp > eps )
00162               {
00163                 x = m - p/dp;        
00164                 if ( x > a && x < b )
00165                   {
00166                     real_t xp = upoldse_::horner( m_mons, m_sz, x );
00167                     if ( xp < 0 ) b = x; else a = x;
00168                     if ( xp < 0 )
00169                       {
00170                         real_t step = eps/2;
00171                         while( xp < 0 && x > a )
00172                           {
00173                             x -= step;
00174                             xp = upoldse_::horner( m_mons, m_sz, x );
00175                             step *= 2;
00176                           };
00177                         if ( x > a  ) a = x;
00178                       }
00179                     else
00180                       {
00181                         real_t step = eps/2;
00182                         while( xp > 0 && x < b )
00183                           {
00184                             x += step;
00185                             xp = upoldse_::horner( m_mons, m_sz, x );
00186                             step *= 2;
00187                           };
00188                         if ( x < b ) b = x;
00189                       };
00190                   };
00191               };
00192           }
00193         while( b-a > eps ); 
00194     };
00195   };
00196 
00197   template<class real_t> 
00198   struct bsearch_newton2
00199   {
00200     real_t * m_data;
00201     real_t * m_mons;
00202     unsigned m_sz;
00203     template< class In >
00204     bsearch_newton2( const In&  bzrep,  unsigned sz ) : m_sz(sz) 
00205     {
00206       m_data = new real_t[ 2*sz ];
00207       std::copy( bzrep, bzrep + sz, m_data );
00208       m_mons = m_data + sz;
00209       std::copy( m_data, m_data + sz, m_mons );
00210       bernstein::bzenv<real_t>::_default_->toMonoms( m_mons, sz );
00211     };
00212     ~bsearch_newton2() { delete[] m_data; };
00213     
00214     void reach( real_t * lbzrep, real_t& a, real_t& b, const real_t& eps  ) 
00215     {
00216       real_t m;
00217       if ( lbzrep[m_sz-1] > lbzrep[0] ) 
00218         do
00219           {
00220             //    -
00221             //     - 
00222             // -----------------
00223             //       -
00224             //        -
00225             //std::cout << (b-a) << std::endl;
00226             real_t p,dp,x;
00227             upoldse_::dhorner( p, dp, m_mons, m_sz, m = (a+b)/2.0 );
00228             if ( p < 0  ) a = m; else b = m; 
00229             if ( dp > eps )
00230               {
00231                 real_t ex;
00232                 int c = 0;
00233                 x = m;
00234                 do
00235                   {
00236                     ex = x;
00237                     x = x - p/dp;
00238                     c ++ ;
00239                     upoldse_::dhorner(p,dp,m_mons,m_sz,x);
00240                   }
00241                 while ( c < 6 );
00242                 if ( x > a && x < b ) 
00243                   {
00244                     if ( p < 0 ) 
00245                       {
00246                         a = x;
00247                         p = upoldse_::horner(m_mons,m_sz,x+eps/2);
00248                         if ( p > 0 ) b = x+eps;
00249                       }
00250                     else 
00251                       {
00252                         b = x;
00253                         p = upoldse_::horner(m_mons,m_sz,x-eps/2);
00254                         if ( p < 0 ) a = x-eps/2;
00255                       };
00256                   };
00257               };
00258           }
00259         while( b-a > eps );
00260       else
00261         do
00262           {
00263             //              std::cout << (b-a) << std::endl;
00264             real_t p,dp,x;
00265             upoldse_::dhorner( p, dp, m_mons, m_sz, m = (a+b)/2.0 );
00266             if ( p < 0  ) b = m; else a = m; 
00267             if  ( dp > eps )
00268               {
00269                 real_t ex;
00270                 int c = 0;
00271                 x = m;
00272                 do
00273                   {
00274                     ex = x;
00275                     x = x - p/dp;
00276                     c ++ ;
00277                     upoldse_::dhorner(p,dp,m_mons,m_sz,x);
00278                   }
00279                 while (c < 6 );
00280                 
00281                 if ( x > a && x < b ) 
00282                   {
00283                     if ( p < 0 ) 
00284                       {
00285                         b = x; 
00286                         p = upoldse_::horner(m_mons,m_sz,x-eps/2);
00287                         if ( p > 0 ) a = x-eps/2;
00288                       }
00289                     else 
00290                       {
00291                         a = x;
00292                         p = upoldse_::horner(m_mons,m_sz,x+eps/2);
00293                         if ( p < 0 ) b = x-eps/2;
00294                       };
00295                   };
00296               }
00297           }
00298         while( b-a > eps ); 
00299     };
00300   };
00301 
00302   template<class real_t, class local_method = bsearch< real_t > >
00303   class descartes_solver
00304   {
00305   public:
00306     unsigned m_sz, m_ssz;
00307     real_t        m_prec;
00308     real_t *      m_stck;
00309     local_method * m_lmth;
00310 
00311       
00312     void reset( unsigned sz, const real_t& prec )
00313     {
00314       if ( sz <= m_sz && prec >= m_prec ) 
00315         {
00316           m_sz = sz;
00317           m_prec = prec;
00318           return;
00319         };
00320       m_sz = sz; m_prec = prec; 
00321       this->alloc();
00322     };
00323     
00324     void split( real_t * r )
00325     {
00326       real_t * l = r+m_sz+2;
00327       brnops::decasteljau(r,l,m_sz);
00328       l[m_sz]   = r[m_sz];
00329       l[m_sz+1] = (r[m_sz]+r[m_sz+1])/2.0;
00330       r[m_sz]   = l[m_sz+1];
00331     };
00332     inline real_t precision( real_t * l ) { return l[m_sz+1]-l[m_sz] ; };
00333     bool precision_reached( real_t * l ) { return l[m_sz+1]-l[m_sz] < m_prec; };
00334     
00335   public:  
00336     /* main loop */
00337     /* 
00338        input : in  is a one dimensional vector containing bernstein coefficients (implement an operator[])
00339        output: out is a function called on each interval containing roots        (assumed to store the results)
00340        option: 0 to compute all the roots, n to compute the nth root
00341     */
00342     
00343     
00344 
00345     void rockwoodcuts( real_t * nxt, real_t * prv, real_t * mid )
00346     {
00347       //      [-------------] b
00348       //      [---][--------] b 
00349       //      [---][---][---] b
00350       real_t i0, i1;
00351       brnops::rockwood_cut( i0, nxt, m_sz );
00352       brnops::rockwood_cut( i1, nxt+m_sz-1, m_sz, -1 );
00353       std::cout << i0 << ", " << (1.0-i1) << std::endl;
00354       i1 = (1.0-i1);
00355       brnops::decasteljau(nxt,prv,m_sz,i0);
00356       brnops::decasteljau(nxt,mid,m_sz,(i1-i0)/(1.0-i0));
00357       i0 = (1.0-i0)*nxt[m_sz] + i0*nxt[m_sz+1];
00358       i1 = (1.0-i1)*nxt[m_sz] + i1*nxt[m_sz+1];
00359       prv[m_sz]   = nxt[m_sz];
00360       prv[m_sz+1] = i0;
00361       mid[m_sz]   = i0;
00362       mid[m_sz+1] = i1;
00363       nxt[m_sz]   = i1;
00364     };
00365     
00366     inline void set_sz( unsigned sz ) { m_sz = sz;};
00367     
00368     template< class Prms > inline 
00369     void output( Prms& prms, real_t * stck, const texp::true_t&  )
00370     { prms.output( stck[m_sz], stck[m_sz+1], stck[0] > 0, stck[m_sz-1] > 0 ); };
00371     template< class Prms > inline 
00372     void output( Prms& prms, real_t * stck, const texp::false_t& )
00373     { prms.output( stck[m_sz], stck[m_sz+1] ); };
00374     
00375     template< class Prms > inline
00376     void output( Prms& prms, real_t * stck )
00377     { output( prms, stck, sign_wanted< Prms >::result_t() ); };
00378      
00379     template<class Prms,class In>
00380     unsigned solve( Prms& prms, const In& in, int option = 0  )
00381     {
00382       for ( unsigned i = 0; i < m_sz; i ++ )  m_stck[i] = in[i]; 
00383       m_stck[m_sz] = 0.0; m_stck[m_sz+1] = 1.0;
00384       unsigned    roots = 0;
00385       const unsigned    inc  = m_sz+2;
00386       real_t * stck = m_stck;
00387       real_t * stop = stck-inc;
00388       do
00389         {
00390           unsigned sgn = vctops::sgncnt(stck,m_sz);
00391           switch( sgn )
00392             {
00393             case 0:
00394               stck -= inc;
00395               break;
00396             case 1:
00397               roots ++;
00398               if ( !option || (roots == option) )
00399                 {
00400                   if ( m_lmth == 0 ) m_lmth = new local_method(in,m_sz);
00401                   m_lmth->reach( stck, stck[m_sz], stck[m_sz+1], m_prec );
00402                   output( prms, stck );
00403                 };
00404               stck -= inc;
00405               break;
00406             default:
00407               if(  precision( stck ) < m_prec  )
00408                 { 
00409                   roots++; 
00410                   if ( !option || (roots == option) ) output(prms,stck);
00411                   stck -= inc;
00412                   break;
00413                 };
00414               split(stck);
00415               stck += inc;
00416               break;
00417             }
00418         }
00419       while( stck != stop  );
00420       if ( m_lmth ) { delete m_lmth; m_lmth = 0; };
00421       return roots;
00422     };
00423 
00424         
00425 
00426     descartes_solver( unsigned sz, const real_t& eps = 1e-12 ) 
00427     {
00428       m_stck = 0;
00429       m_sz   = sz;
00430       m_prec = eps;
00431       m_lmth = 0;
00432       unsigned maxdeep = 1;
00433       real_t ex = 1;
00434       while ( ex > m_prec ) { ex/=2; maxdeep ++ ; };
00435       //      std::cout << maxdeep << std::endl;
00436       maxdeep ++;
00437       maxdeep *= 3;
00438       unsigned tsz = maxdeep*(2+m_sz);
00439       m_stck = new real_t[ tsz ];
00440     };
00441     
00442     ~descartes_solver() { 
00443       delete[] m_stck; 
00444     };
00445   };
00446 };
00447 //--------------------------------------------------------------------
00448 } //namespace mmx
00449 /********************************************************************/
00450 #endif //