realroot_doc 0.1.1
|
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 //