realroot_doc 0.1.1
|
00001 /******************************************************************* 00002 * This file is part of the source code of the realroot kernel. 00003 * Author(s): Elias P. TSIGARIDAS <et@di.uoa.gr> 00004 * J.P. Pavone, GALAAD, INRIA 00005 * V. Sharma, GALAAD, INRIA 00006 ********************************************************************/ 00008 #ifndef realroot_UPOL_BOUND_H 00009 #define realroot_UPOL_BOUND_H 00010 00011 #include <realroot/rounding_mode.hpp> 00012 #include <realroot/texp_rationalof.hpp> 00013 #include <realroot/univariate.hpp> 00014 #include <vector> 00015 #include <stack> 00016 #include <queue> 00017 00018 00019 namespace mmx { 00020 00021 using univariate::lcoeff; 00022 00023 #ifndef MMX_ABS_FCT 00024 #define MMX_ABS_FCT 00025 template<typename T> inline T abs(const T& x) { return (x < 0 ? -x : x); } 00026 #endif 00027 00028 00029 template<class T> 00030 T pow2(int i) 00031 { 00032 assert(i>=0); 00033 if(i == 1) return 2; 00034 if(i > 0) 00035 { 00036 T y(2); 00037 T z(1); 00038 unsigned int n = i; 00039 unsigned int m; 00040 while (n > 0) { 00041 m = n / 2; 00042 if (n %2 ) 00043 { 00044 z *= y; 00045 } 00046 y = y * y; 00047 n = m; 00048 } 00049 return z; 00050 } 00051 return T(1); 00052 } 00053 00054 00056 template<class C> struct NISP 00057 { 00058 //-------------------------------------------------------------------- 00067 template <typename POLY> static 00068 C upper_bound(const POLY& p) 00069 { 00070 typedef typename texp::rationalof<C>::T rational; 00071 // typedef typename NTR::T FT; 00072 //typedef double FT; 00073 C max(0), sum(0); 00074 00075 unsigned i; 00076 unsigned n = p.size(); 00077 00078 // check the degree 00079 i = n; while ( p[--i] == 0 ) ; n = i+1; 00080 if ( p[i] > 0 ) 00081 { 00082 i = 0; 00083 while ( p[i] > 0 && i < n ) i++; 00084 if ( i == n ) return 0; 00085 00086 for ( unsigned k = i+1; k < n; k ++ ) 00087 if ( p[k] > 0 ) sum += p[k]; 00088 00089 for ( unsigned k = i; k < n; k ++ ) 00090 { 00091 if ( p[k] < 0 ) 00092 { rational tmp = -p[k]/sum; if ( tmp > max ) max = tmp; } 00093 else 00094 sum -= p[k]; 00095 }; 00096 } 00097 else 00098 { 00099 i = 0; 00100 while ( p[i] < 0 && i < n ) i++; 00101 if ( i == n ) return 0; 00102 for ( unsigned k = i+1; k < n; k ++ ) 00103 if ( p[k] < 0 ) sum += p[k]; 00104 for ( unsigned k = i; k < n; k ++ ) 00105 if ( p[k] > 0 ) { rational tmp = -p[k]/sum; if ( tmp > max ) max = tmp; } 00106 else sum -= p[k]; 00107 }; 00108 max += 1; 00109 return max; 00110 } 00111 00112 00113 template <typename POLY> static 00114 C lower_bound(const POLY& p) 00115 { 00116 typedef typename texp::rationalof<C>::T rational; 00117 using univariate::degree; 00118 00119 POLY r(p); 00120 reverse(r,degree(r)); 00121 rational m = NISP<rational>::upper_bound(r); 00122 return denominator(m)/numerator(m); 00123 } 00124 }; 00125 00127 template<class FT> struct NISN 00128 { 00137 template <typename POLY> static 00138 FT upper_bound(const POLY& p) 00139 { 00140 POLY tmp = p; 00141 for ( unsigned i = 1; i < p.size(); i += 2 ) 00142 tmp[i] = -tmp[i]; 00143 return -NISP<FT>::upper_bound(tmp); 00144 } 00145 }; 00146 00147 //==================================================================== 00148 template < typename T > 00149 struct abs_max : public std::unary_function<T, void> 00150 { 00151 abs_max() : max(T(-1)) {} 00152 void operator() (const T& x) 00153 { 00154 // using std::abs; 00155 T temp = abs(x); 00156 if (temp > max) max = temp; 00157 } 00158 T max; 00159 }; 00160 00162 template<class C> struct Cauchy 00163 { 00164 //-------------------------------------------------------------------- 00185 template<class Poly> static 00186 C upper_bound(const Poly& p) 00187 { 00188 // DEBUG::print("Cauchy"); 00189 typedef typename Poly::value_type RT; 00190 typedef typename texp::rationalof<RT>::T rational; 00191 00192 //using std::abs; 00193 abs_max<RT> M = std::for_each(p.begin(), p.end()-1, abs_max<RT>()); 00194 RT an = abs(lcoeff(p)); 00195 // rational val= rational(M.max)/an + rational(1); 00196 C res= C(M.max/an) + C(1); 00197 // C res; let::assign(res, val); 00198 return res; 00199 } 00200 00209 template<class Poly> 00210 C lower_bound(const Poly& f) const 00211 { 00212 using univariate::degree; 00213 00214 typedef C RT; 00215 long deg = degree( f); 00216 long l = 0; 00217 00218 for (int i = 1; i <= deg; ++i) { 00219 if ( sign( f[i]) * sign( f[0]) < 0 ) { 00220 ++l; 00221 } 00222 } 00223 00224 long ba0 = bit_size(f[0]) - 1; /* puiss de 2 < an */ 00225 bool bound_set = false; 00226 long K = 0; 00227 00228 for (int i = 1; i <= deg; ++i) { 00229 if ( sign( f[i]) * sign( f[0]) < 0 ) { 00230 long bai = bit_size( RT( l * f[i])) - 1; 00231 long p = bai - ba0 - 1 ; 00232 long k = i; 00233 long q = p / k; 00234 long r = p % k; 00235 00236 long rq = 0; 00237 if (r <= k-2) { 00238 rq = q + 1; 00239 } else { 00240 rq = q + 2; 00241 } 00242 00243 if ( (bound_set == false) || (K < rq) ) { 00244 K = rq; 00245 bound_set = true; 00246 } 00247 } 00248 } 00249 if ( K < 0 ) {return pow2<RT>( abs( K) );} 00250 00251 return 0; 00252 } 00253 00254 // Return only the power of 2. 00255 template<class Poly> 00256 long lower_power_2(const Poly& f) const 00257 { 00258 using univariate::degree; 00259 00260 typedef typename Poly::value_type RT; 00261 00262 long deg = degree( f); 00263 long l = 0; 00264 00265 for (int i = 1; i <= deg; ++i) { 00266 if ( sign( f[i]) * sign( f[0]) < 0 ) { 00267 ++l; 00268 } 00269 } 00270 00271 long ba0 = bit_size(f[0]) - 1; /* puiss de 2 < an */ 00272 bool bound_set = false; 00273 long K = 0; 00274 00275 for (int i = 1; i <= deg; ++i) { 00276 if ( sign( f[i]) * sign( f[0]) < 0 ) { 00277 long bai = bit_size( RT( l * f[i])) - 1; 00278 long p = bai - ba0 - 1 ; 00279 long k = i; 00280 long q = p / k; 00281 long r = p % k; 00282 00283 long rq = 0; 00284 if (r <= k-2) { 00285 rq = q + 1; 00286 } else { 00287 rq = q + 2; 00288 } 00289 00290 if ( (bound_set == false) || (K < rq) ) { 00291 K = rq; 00292 bound_set = true; 00293 } 00294 } 00295 } 00296 if ( K < 0 ) { abs( K);} 00297 00298 return -1; 00299 } 00300 00301 }; 00302 00303 template<> 00304 template<class Poly> 00305 double Cauchy<double>::upper_bound(const Poly& p) 00306 { 00307 typedef typename Poly::value_type coeff_t; 00308 numerics::rounding<double> rnd( numerics::rnd_up() ); 00309 //using std::abs; 00310 coeff_t M=0; 00311 for(unsigned i=0;i< p.size(); i++) M = std::max(M, coeff_t(abs(p[i]))); 00312 // abs_max<coeff_t> M = std::for_each(p.begin(), p.end()-1, abs_max<coeff_t>()); 00313 00314 coeff_t an = coeff_t(abs(univariate::lcoeff(p))); 00315 //std::cout <<M<<" "<<an<<" "<<std::endl; 00316 00317 double res=as<double>(coeff_t(M/an)) + 1; 00318 // std::cout <<res<<std::endl; 00319 return res; 00320 } 00321 //==================================================================== 00322 00323 // /** 00324 // * @brief Prototype function, Computes an upper bound for the real roots. 00325 // * 00326 // * @param p Univariate Polynomial 00327 // * @param mth Method that we use in order to compute the root bound 00328 // * @param AsType<T> The return type 00329 // */ 00330 // template < typename POLY, 00331 // typename M, 00332 // typename T > 00333 // T bound(const POLY& p, const M& mth, texp::As<T>) 00334 // { 00335 // return T(0); 00336 // } 00337 00338 00339 00340 template <typename FT, typename POLY> 00341 FT bound_root(const POLY& p, const Cauchy<FT>& m) 00342 { 00343 return m.upper_bound(p); 00344 } 00345 00346 00347 template < typename FT, typename POLY> 00348 FT max_bound(const POLY& p, const Cauchy<FT>& m) 00349 { 00350 return bound_root(p,m); 00351 } 00352 00353 template < typename FT, typename POLY> 00354 FT 00355 min_bound(const POLY& p, Cauchy<FT>) 00356 { 00357 using univariate::degree; 00358 00359 POLY f(p); 00360 univariate::reverse(f, degree(p)); 00361 FT tmp = bound_root(f, Cauchy<FT>()); 00362 // let::convert(denominator(tmp), numerator(tmp), texp::As<FT>()); 00363 return FT(1)/tmp; 00364 } 00365 00366 00367 00368 00369 //==================================================================== 00375 template<class RT> struct HongBound 00376 { 00377 template < typename Poly > static 00378 RT lower_bound( const Poly& f) 00379 { 00380 using univariate::degree; 00381 00382 unsigned deg = degree(f); 00383 00384 long lB=0, gB=0; 00385 bool localBoundSet = false, globalBoundSet = false; 00386 long temp, q; 00387 int s = sign(f[0]); 00388 //std::cout << "f[0]= " << f[0] << std::endl; 00389 for(int i= deg; i > 0; i--){ 00390 //std::cout << "f["<< i << "]" << " = " << f[i] << std::endl; 00391 if(sign(f[i]) * s < 0){ 00392 for(int k=i-1; k >= 0; k--){ 00393 if(sign(f[k]) * s > 0){ 00394 temp = bit_size( RT(f[i]) ) - bit_size( RT(f[k]) ) - 1; 00395 q = temp /(i-k); 00396 if(!localBoundSet || lB > q + 2){// Choose the minimum among localBounds 00397 localBoundSet = true; 00398 lB = q+2; 00399 } 00400 } 00401 } 00402 localBoundSet = false; 00403 if(!globalBoundSet || gB < lB){// Choose the maximum among globalBounds 00404 globalBoundSet = true; 00405 gB = lB; 00406 } 00407 } 00408 //std::cout << "Cout gb after " << i << " loop = "<< gB << std::endl; 00409 } 00410 if ( gB+1 < 0 ) return pow2<RT>( abs( gB+1) ); 00411 return 0; 00412 } 00413 }; 00414 00415 //==================================================================== 00424 template<class RT> 00425 struct AkritasBound 00426 { 00427 00428 template < typename Poly > static 00429 RT lower_bound( const Poly& f) 00430 { 00431 using univariate::degree; 00432 00433 // std::cout <<"Poly is " << f << std::endl; 00434 typedef std::pair<RT, int> Coeff_deg; 00435 Coeff_deg T1, T2; 00436 00437 unsigned deg=degree(f); 00438 int s=sign(f[0]);//, len; 00439 long B=0;// The logarithm of the bound to be returned 00440 bool boundSet=false;// The bound is not set initially 00441 long temp,q; 00442 int posCounter=0, negCounter=0, nPosCounter=0; 00443 // The coefficients from posCounter to negCounter-1 have the same sign 00444 // as f[0]; the coefficients from negCounter to nPosCounter-1 have the 00445 // opposite sign of f[0]. 00446 std::queue< Coeff_deg > Neg;// Queue that stores the negative (between 00447 // negCounter and nPosCounter) coefficients. 00448 std::stack< Coeff_deg > Pos; // Stack that stores the positive (between 00449 // posCounter and negCounter) coefficients. 00450 00451 int l1, l2;// size of the above two queues 00452 00453 while(posCounter != int(deg+1)){ 00454 // Find the first change in sign larger than posCounter and assign negCounter 00455 // to this value. If no such sign variation occurs then 00456 // set negCounter to -1. 00457 negCounter = -1;// By default there is no such coefficient 00458 //Pos.push(Coeff_deg(RT(f[posCounter]), posCounter));// Push the first "positive" coefficient 00459 Pos.push(Coeff_deg(RT(f[posCounter]), posCounter));// Push the first "positive" coefficient 00460 for(unsigned i=posCounter + 1;i <= deg; i++){ 00461 if(sign(f[i]) * s < 0){ 00462 negCounter=i; break; 00463 } 00464 if(sign(f[i]) *s > 0){// Store the list of "positive" coefficients 00465 //Pos.push(Coeff_deg(RT(f[i]), i));// Note the actual degree is deg-i, but 00466 // later we subtract degrees so we store only i 00467 Pos.push(Coeff_deg(RT(f[i]), i)); 00468 } 00469 } 00470 if(negCounter == -1){ 00471 // std::cout <<"Returning the lower bound " << B << std::endl; 00472 if ( B < 0 ) 00473 return pow2<RT>( abs(B) ); 00474 else 00475 return 0; 00476 } 00477 // Now find the next coefficient that has the same sign as f[0]. 00478 nPosCounter = deg+1;// By default this is deg+1 00479 Neg.push(Coeff_deg(RT(f[negCounter]), negCounter)); 00480 for(unsigned i=negCounter + 1;i <= deg; i++){ 00481 if(sign(f[i]) * s > 0){ 00482 nPosCounter=i; break; 00483 } 00484 if(sign(f[i]) *s < 0)// Store the list of "negative" coefficients 00485 Neg.push(Coeff_deg(RT(f[i]), i)); 00486 } 00487 00488 // std::cout <<" Assigning to the queues done" << std::endl; 00489 // Start computing the bound 00490 // If the number of "positive" terms from posCounter to negCounter -1 are 00491 // greater or equal to the number of "negative" terms from negCounter to 00492 // nPosCounter -1 then we have the straightforward matching of "negative" 00493 // coefficients with the "positive" ones. 00494 l1 = Neg.size(); l2 = Pos.size(); 00495 if(l2 >= l1){ 00496 // std::cout <<"Pos length " << l2 << " greater than Neg length " 00497 // << l1 << std::endl; 00498 // or equally negCounter - posCounter >= nPosCounter - negCounter 00499 for(int i=0; i < l1; i++){ 00500 T1= Neg.front(); Neg.pop(); 00501 //T2= Pos.front(); Pos.pop(); 00502 T2=Pos.top();Pos.pop(); 00503 // std::cout <<"Neg coeff " << T1.first << " Pos coeff " << T2.first 00504 // << " Deg difference " << T1.second - T2.second 00505 // << std::endl; 00506 temp = bit_size( T1.first ) - bit_size( T2.first ) - 1; 00507 q = temp/(T1.second - T2.second); 00508 // std::cout << "Difference between logs " << temp 00509 // << " temporary bound value " << B << std::endl; 00510 if(!boundSet || B < q + 2){// Choose the maximum 00511 boundSet = true; 00512 B = q+2; 00513 } 00514 } 00515 }else{//Else split the coefficient f[posCounter] to compensate for 00516 // the paucity of "positive" terms and then do the matching. 00517 // std::cout <<" Pos length "<< l2 << " smaller than Neg length " 00518 // << l1 << std::endl; 00519 00520 //T2=Pos.front(); Pos.pop(); 00521 T2= Pos.top();Pos.pop(); 00522 for(int i=0; i <= l1-l2; i++){ 00523 T1= Neg.front(); Neg.pop(); 00524 temp = bit_size( T1.first ) - bit_size( T2.first ) + bit_size(RT(l1-l2+1)) - 1; 00525 q = temp/(T1.second-T2.second); 00526 if(!boundSet || B < q + 2){// Choose the maximum 00527 boundSet = true; 00528 B = q+2; 00529 } 00530 } 00531 // std::cout <<" Splitting the leading coefficient done" << std::endl; 00532 l1 = Neg.size();// Now the size of Neg and Pos should be the same 00533 for(int i=0; i < l1; i++){ 00534 T1= Neg.front(); Neg.pop(); 00535 //T2= Pos.front(); Pos.pop(); 00536 Pos.pop(); 00537 temp = bit_size( T1.first ) - bit_size( T2.first ) - 1; 00538 q = temp/(T1.second - T2.second); 00539 if(!boundSet || B < q + 2){// Choose the maximum 00540 boundSet = true; 00541 B = q+2; 00542 } 00543 } 00544 }// end else 00545 // std::cout <<" Matching the coefficients done" << std::endl; 00546 posCounter = nPosCounter; Neg.empty(); Pos.empty(); 00547 }//end while 00548 // std::cout <<"Returning the lower bound " << B << std::endl; 00549 if ( B < 0 ) return pow2<RT>( abs(B) ); 00550 return 0; 00551 } 00552 00553 00554 template < typename Poly > static 00555 long lower_power_2( const Poly& f) 00556 { 00557 using univariate::degree; 00558 00559 // std::cout <<"Poly is " << f << std::endl; 00560 typedef std::pair<RT, int> Coeff_deg; 00561 Coeff_deg T1, T2; 00562 00563 unsigned deg=degree(f); 00564 int s=sign(f[0]);//, len; 00565 long B=0;// The logarithm of the bound to be returned 00566 bool boundSet=false;// The bound is not set initially 00567 long temp,q; 00568 int posCounter=0, negCounter=0, nPosCounter=0; 00569 // The coefficients from posCounter to negCounter-1 have the same sign 00570 // as f[0]; the coefficients from negCounter to nPosCounter-1 have the 00571 // opposite sign of f[0]. 00572 std::queue< Coeff_deg > Neg;// Queue that stores the negative (between 00573 // negCounter and nPosCounter) coefficients. 00574 std::stack< Coeff_deg > Pos; // Stack that stores the positive (between 00575 // posCounter and negCounter) coefficients. 00576 00577 int l1, l2;// size of the above two queues 00578 00579 while(posCounter != int(deg+1)){ 00580 // Find the first change in sign larger than posCounter and assign negCounter 00581 // to this value. If no such sign variation occurs then 00582 // set negCounter to -1. 00583 negCounter = -1;// By default there is no such coefficient 00584 //Pos.push(Coeff_deg(RT(f[posCounter]), posCounter));// Push the first "positive" coefficient 00585 Pos.push(Coeff_deg(RT(f[posCounter]), posCounter));// Push the first "positive" coefficient 00586 for(unsigned i=posCounter + 1;i <= deg; i++){ 00587 if(sign(f[i]) * s < 0){ 00588 negCounter=i; break; 00589 } 00590 if(sign(f[i]) *s > 0){// Store the list of "positive" coefficients 00591 //Pos.push(Coeff_deg(RT(f[i]), i));// Note the actual degree is deg-i, but 00592 // later we subtract degrees so we store only i 00593 Pos.push(Coeff_deg(RT(f[i]), i)); 00594 } 00595 } 00596 if(negCounter == -1){ 00597 // std::cout <<"Returning the lower bound " << B << std::endl; 00598 if ( B < 0 ) return abs( B); 00599 else return -1; 00600 } 00601 // Now find the next coefficient that has the same sign as f[0]. 00602 nPosCounter = deg+1;// By default this is deg+1 00603 Neg.push(Coeff_deg(RT(f[negCounter]), negCounter)); 00604 for(unsigned i=negCounter + 1;i <= deg; i++){ 00605 if(sign(f[i]) * s > 0){ 00606 nPosCounter=i; break; 00607 } 00608 if(sign(f[i]) *s < 0)// Store the list of "negative" coefficients 00609 Neg.push(Coeff_deg(RT(f[i]), i)); 00610 } 00611 00612 // std::cout <<" Assigning to the queues done" << std::endl; 00613 // Start computing the bound 00614 // If the number of "positive" terms from posCounter to negCounter -1 are 00615 // greater or equal to the number of "negative" terms from negCounter to 00616 // nPosCounter -1 then we have the straightforward matching of "negative" 00617 // coefficients with the "positive" ones. 00618 l1 = Neg.size(); l2 = Pos.size(); 00619 if(l2 >= l1){ 00620 // std::cout <<"Pos length " << l2 << " greater than Neg length " 00621 // << l1 << std::endl; 00622 // or equally negCounter - posCounter >= nPosCounter - negCounter 00623 for(int i=0; i < l1; i++){ 00624 T1= Neg.front(); Neg.pop(); 00625 //T2= Pos.front(); Pos.pop(); 00626 T2=Pos.top();Pos.pop(); 00627 // std::cout <<"Neg coeff " << T1.first << " Pos coeff " << T2.first 00628 // << " Deg difference " << T1.second - T2.second 00629 // << std::endl; 00630 temp = bit_size( T1.first ) - bit_size( T2.first ) - 1; 00631 q = temp/(T1.second - T2.second); 00632 // std::cout << "Difference between logs " << temp 00633 // << " temporary bound value " << B << std::endl; 00634 if(!boundSet || B < q + 2){// Choose the maximum 00635 boundSet = true; 00636 B = q+2; 00637 } 00638 } 00639 }else{//Else split the coefficient f[posCounter] to compensate for 00640 // the paucity of "positive" terms and then do the matching. 00641 // std::cout <<" Pos length "<< l2 << " smaller than Neg length " 00642 // << l1 << std::endl; 00643 00644 //T2=Pos.front(); Pos.pop(); 00645 T2= Pos.top();Pos.pop(); 00646 for(int i=0; i <= l1-l2; i++){ 00647 T1= Neg.front(); Neg.pop(); 00648 temp = bit_size( T1.first ) - bit_size( T2.first ) + bit_size(RT(l1-l2+1)) - 1; 00649 q = temp/(T1.second-T2.second); 00650 if(!boundSet || B < q + 2){// Choose the maximum 00651 boundSet = true; 00652 B = q+2; 00653 } 00654 } 00655 // std::cout <<" Splitting the leading coefficient done" << std::endl; 00656 l1 = Neg.size();// Now the size of Neg and Pos should be the same 00657 for(int i=0; i < l1; i++){ 00658 T1= Neg.front(); Neg.pop(); 00659 //T2= Pos.front(); Pos.pop(); 00660 Pos.pop(); 00661 temp = bit_size( T1.first ) - bit_size( T2.first ) - 1; 00662 q = temp/(T1.second - T2.second); 00663 if(!boundSet || B < q + 2){// Choose the maximum 00664 boundSet = true; 00665 B = q+2; 00666 } 00667 } 00668 }// end else 00669 // std::cout <<" Matching the coefficients done" << std::endl; 00670 posCounter = nPosCounter; Neg.empty(); Pos.empty(); 00671 }//end while 00672 // std::cout <<"Returning the lower bound " << B << std::endl; 00673 if ( B < 0 ) return abs( B); 00674 else return -1; 00675 00676 } 00677 }; 00678 //==================================================================== 00679 00680 } //namespace mmx 00681 //-------------------------------------------------------------------- 00682 #endif // realroot_UPOL_BOUND_H 00683