realroot_doc 0.1.1
/Users/mourrain/Devel/mmx/realroot/include/realroot/univariate_bounds.hpp
Go to the documentation of this file.
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