00001
00002
00003
00004
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
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
00023
00024 template<class real_t>
00025 struct bsearch
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
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
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
00060 {
00061 real_t * m_data;
00062 unsigned m_sz;
00063 template< class In >
00064
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
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
00089 {
00090 real_t * m_data;
00091 real_t * m_mons;
00092 unsigned m_sz;
00093 template< class In >
00094
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
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
00114 upoldse_::dhorner( p, dp, m_mons, m_sz, m = (a+b)/2.0 );
00115
00116 if ( p < 0 ) a = m; else b = m;
00117 if ( dp > eps )
00118 {
00119
00120 x = m - p/dp;
00121
00122 if ( x > a && x < b )
00123 {
00124
00125 real_t xp = upoldse_::horner( m_mons, m_sz, x );
00126
00127 if ( xp < 0 ) a = x; else b = x;
00128
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
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
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
00337
00338
00339
00340
00341
00342
00343
00344
00345 void rockwoodcuts( real_t * nxt, real_t * prv, real_t * mid )
00346 {
00347
00348
00349
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
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 }
00449
00450 #endif //