realroot_doc 0.1.1
/Users/mourrain/Devel/mmx/realroot/include/realroot/solver_ucf.hpp
Go to the documentation of this file.
00001 /********************************************************************
00002  *   Author(s): A. Mantzaflaris, GALAAD, INRIA
00003  ********************************************************************/
00004 #ifndef _realroot_SOLVER_FIRST_ROOT_CONFRAC_H
00005 #define _realroot_SOLVER_FIRST_ROOT_CONFRAC_H
00006 /********************************************************************/
00007 
00008 # include <realroot/Interval.hpp>
00009 
00010 # include <realroot/homography.hpp>
00011 # include <realroot/sign_variation.hpp>
00012 # include <realroot/univariate_bounds.hpp>
00013 # include <stack>
00014 # include <realroot/solver.hpp>
00015 
00016 # define NO_ROOT -1.0
00017 # define TMPL  template<class POL>
00018 # define TMPLR template<class Real, class POL>
00019 # define N_ITER 10000
00020 
00021 namespace mmx {
00022 
00023     struct CFfirstIsolate{};
00024     struct CFfirstApproximate{};
00025     struct CFfirstFloor{};
00026     struct CFallIsolate{};
00027     struct CFseparate{};
00028     struct CFdecide{};
00029 
00030     //bit_size support for QQ
00031 
00032     // inline long bit_size(QQ q) 
00033     // {
00034     //          long n,d;
00035     //          n= bit_size(  numerator(q) );
00036     //          d= bit_size(denominator(q) );
00037     //          return( n>d ? n : d ) ;
00038     // }
00039 
00040 
00041 /* ******************************************************** */
00042 /* Represents the polynomial on an interval [u,v].
00043    Keeps homography information to map [0,inf] back to [u,v].
00044    Main operations are shift, contraction and reciprocal.
00045  */
00046 TMPL
00047 class interval_rep
00048 {
00049     typedef typename POL::scalar_t C;
00050 
00051     POL   f;
00052     homography<C> hg;
00053 
00054 public:
00055 
00056     interval_rep(){ }
00057 
00058     interval_rep(const POL p) 
00059         {
00060             f  = p;
00061             hg = homography<C>() ;
00062         }
00063 
00064     interval_rep(const POL p, homography<C> h) 
00065         {
00066             f  = p;
00067             hg = h;
00068         }
00069 
00070 
00071     interval_rep(const POL p, C u,  C v ) 
00072         {
00073             f  = p;
00074             hg = homography<C>() ;
00075 
00076             shift_box           ( u );
00077             contract_box      ( v-u );
00078             reverse_and_shift_box (1);
00079             //print();
00080         }
00081 
00082     /* Access the equation */
00083     POL inline poly() {return f;};
00084     /* Access the homography */
00085     homography<C> hom() { return hg; }
00086 
00087     /* Access the domain */
00088     template<class Real>
00089     Interval<Real> domain() 
00090         { 
00091             Real l, r;
00092             Interval<Real>  s ;
00093             //lim to 0
00094             if ( hg.b!=0 && hg.d!=0 )
00095                 l= as<Real>(hg.b)/as<Real>(hg.d);
00096             else if ( hg.d==0 )
00097                 l= 10000000;
00098             else if ( hg.b==0 )
00099                 l= 0 ;
00100             else 
00101                 l= as<Real>(hg.a)/as<Real>(hg.c) ;
00102             //lim to inf
00103             if ( hg.a!=0 && hg.c!=0 )
00104                 r= as<Real>(hg.a)/as<Real>(hg.c);
00105             else if ( hg.c==0 )
00106                 r=10000000;
00107             else if ( hg.a==0 )
00108                 r= 0 ;
00109             else 
00110                 r= as<Real>(hg.b)/as<Real>(hg.d);
00111             
00112             if ( l<=r ) s= Interval<Real>(l,r);
00113             else        s= Interval<Real>(r,l);
00114     
00115             return s; 
00116         }
00117 
00118     /* Access the size of the domain */
00119     template<class Real>
00120     Real inline width() 
00121         { 
00122             return this->template domain<Real>().width(); 
00123         }
00124 
00125     /* Access the point where t\in\RR_+ corresponds */
00126     template<class Real>
00127     Real inline point(C & t)
00128         {
00129             return ( as<Real>(hg.a)*as<Real>(t) + as<Real>(hg.b) ) /
00130                    ( as<Real>(hg.c)*as<Real>(t) + as<Real>(hg.d) ) ;
00131         }
00132     
00133     C middle()
00134         {
00135             C t(hg.d / hg.c);
00136             
00137             if (t>0)
00138                 return ( t ) ;
00139             else
00140                 return C(1);
00141         }
00142 
00143     unsigned sign_var()
00144         {
00145             return sign_variation(f.begin(),f.end()) ;
00146         }
00147 
00148 
00149     // Shift the polynomial by t
00150     void shift_box(const C& t)
00151         {
00152             int s, k,j, sz= f.size();
00153             
00154             for ( s = sz, j = 0; j <= s-2; j++ )
00155                 for( k = s-2; k >= j; k-- ) 
00156                     f[k] += t*f[k+1];
00157             
00158             //update homography
00159             hg.shift_hom(t);
00160         };
00161     
00162     // x = t*x
00163     void contract_box(const C & t )
00164         {
00165             int s, sz= f.size();
00166             
00167             for ( s = 0 ; s < sz; ++s )
00168                 f[s] *= pow(t,s) ;
00169             
00170             //update homography
00171             hg.contract_hom(t);
00172         };
00173     
00174     // x = 1/x   -- parameter t=1 unused for now
00175     void reverse_box(const C & t=1 )
00176         {
00177             unsigned s, l= f.size()-1;
00178             
00179             for (s = 0 ; s <= l/2; s++ )
00180                 std::swap(f[s], f[l-s]);
00181             
00182             //update homography
00183             hg.reciprocal_hom(t);
00184         };
00185     
00186     // x = 1/(x+1)   -- parameter t=1 unused for now
00187     void inline reverse_and_shift_box(const C & t=1)
00188         {
00189             reverse_box(t);
00190             shift_box  (C(1));
00191         };
00192     
00193     void print() 
00194         {
00195             std::cout << "----------Interval---------------"    << "\n" ;
00196             std::cout << poly() << "\n" ;
00197             std::cout<< "("<<hg.a <<"x + " << hg.b<<")/("<<hg.c<<"x+ "<<hg.d << ")"<<", sv:"<<sign_var() <<std::endl;
00198             std::cout << domain() << "\n" ;
00199             std::cout << "-------------------------------"    << "\n" ;
00200         }
00201     
00202 }; /* Interval_rep */
00203     
00204 
00205 /* ******************************************************** */
00206     /* 
00207        Solver interface
00208     */
00209     TMPLR
00210     struct solver_cffirst {
00211         
00212         interval_rep<POL> ir;
00213         Real eps;
00214         
00215         solver_cffirst(interval_rep<POL> p){
00216             ir = p;
00217             eps= as<Real>(1e-7);
00218         } 
00219         
00220         interval_rep<POL>           first_root();
00221         Interval<Real>      first_root_isolate();
00222         Real            first_root_approximate();
00223         Real                  first_root_floor();
00224 
00225         Seq<interval_rep<POL> >      all_roots();
00226         Seq<Interval<Real> > all_roots_isolate();
00227         Seq<Real>           all_roots_separate();
00228     };
00229    
00230     /* 
00231        Main routine:
00232        Returns an "interval_rep" containing the minimum >0 root.
00233     */
00234     TMPLR
00235     interval_rep<POL> solver_cffirst<Real,POL>::first_root()
00236     {
00237         typedef interval_rep<POL> BOX;
00238         std::stack<BOX * > uboxes;
00239         typedef typename POL::scalar_t C;
00240         
00241         POL zero(0);
00242         Interval<Real> mid(0);
00243         BOX * b, * tmp;
00244         POL p;
00245         unsigned s, iters=0;
00246         
00247         Interval<Real> I;
00248         AkritasBound<C> lb;
00249         //HongBound<C> lb; 
00250         //Kioustelidis<C> lb; 
00251         //NISP<C> lb; 
00252         //Cauchy<C> lb; 
00253         
00254         C lower;
00255         b= new BOX(ir);
00256         uboxes.push (b);
00257         
00258         while ( !uboxes.empty() && iters++ < N_ITER )
00259             
00260         {
00261             b = uboxes.top() ;
00262             p = b->poly() ;
00263             uboxes.pop();
00264             
00265             if ( p==zero && (!uboxes.empty()) ) {
00266                 return *b;}
00267             
00268             s = b->sign_var() ;
00269             I = b->template domain<Real>();
00270             
00271             if ( s==1 && (!uboxes.empty()) ) {
00272                 return *b;}
00273             
00274             if ( s > 0 ) 
00275             {
00276                 if ( b->template width<Real>() < eps )
00277                 {std::cout<< "first_root: multiple root?"<<b->template domain<Real>() <<std::endl;}
00278                 else
00279                 {
00280                     lower= lb.lower_bound(p) ;
00281                     if ( lower!=0 )
00282                     {
00283                         if ( p( lower ) == 0 )
00284                             return *b;
00285                         
00286                         tmp= new BOX( *b ) ;
00287                         free(b);
00288                         tmp->shift_box( lower );
00289                         uboxes.push (tmp);
00290                     }
00291                     else
00292                     {
00293                         // right box
00294                         tmp = new BOX( *b ) ;
00295                         tmp->shift_box( 1 );
00296                         uboxes.push ( tmp );                    
00297                         //middle if needed
00298                         if ( p( Real(1) ) == Real(0) )
00299                         {   tmp = new BOX(zero, b->hom() ) ;
00300                             uboxes.push ( tmp ); }
00301                         //left
00302                         tmp = new BOX( *b ) ;
00303                         tmp->reverse_and_shift_box( 1 );
00304                         tmp->reverse_box( 1 );
00305                         uboxes.push ( tmp );
00306                         
00307                         free(b);
00308                     }
00309                 }
00310             }
00311         }
00312         /* -1 = No positive root */
00313         return BOX(-1);
00314     }
00315 
00316     /* 
00317        Returns a list of "interval_rep"s isolating the positive roots,
00318        in increasing order.
00319     */
00320   TMPLR
00321   Seq<interval_rep<POL> > solver_cffirst<Real,POL>::all_roots()
00322   {
00323     typedef interval_rep<POL> BOX;
00324     std::stack<BOX * > uboxes;
00325     typedef typename POL::scalar_t C;
00326 
00327     Real ev(0);
00328     Seq<interval_rep<POL> > sols;
00329     POL zero(0);
00330     Interval<Real> mid(0);
00331     BOX * b, * tmp;
00332     POL p;
00333     unsigned s, iters=0;
00334         
00335     Interval<Real> I;
00336     AkritasBound<C> lb;
00337     //HongBound<C> lb; 
00338     //Kioustelidis<C> lb; 
00339     //NISP<C> lb; 
00340     //Cauchy<C> lb; 
00341     
00342     C lower;
00343     b= new BOX(ir);
00344     uboxes.push (b);
00345     
00346     while ( !uboxes.empty() && iters++ < N_ITER )
00347     {
00348       b = uboxes.top() ;
00349       p = b->poly() ;
00350       uboxes.pop();
00351       
00352       if ( p==zero && (!uboxes.empty()) ) {
00353         sols<< *b;}
00354       
00355       I = b->template domain<Real>();
00356       // Interval<Real> ev= p( I ) ;
00357       // if ( ev.m * ev.M > 0  ) continue;
00358       s = b->sign_var() ;
00359       if ( s==1 && (!uboxes.empty()) ) {
00360         sols << *b; continue; }
00361       
00362       if ( s > 0 ) 
00363       {
00364         if ( (!uboxes.empty())  && b->template width<Real>() < eps*.1 )
00365         {std::cout<<
00366             "all_roots: multiple root?"<<b->template domain<Real>() <<std::endl; 
00367           std::cout<< b->poly()<<" , "<<b->template width<Real>()<<std::endl;
00368           std::cout<<"source: "<<ir.poly()<<std::endl;
00369 
00370         }
00371         else
00372         {
00373           lower= lb.lower_bound(p) ;
00374           if ( lower!=0 )
00375           {
00376             
00377             let::assign(ev,lower);
00378             if ( p(ev) == 0 )
00379               sols<< *b;
00380             
00381             tmp= new BOX( *b ) ;
00382             free(b);
00383             tmp->shift_box( lower );
00384             uboxes.push (tmp);
00385           }                     
00386           else
00387           {
00388             // right box
00389             tmp = new BOX( *b ) ;
00390             tmp->shift_box( 1 );
00391             uboxes.push ( tmp );                        
00392             //middle if needed
00393             ev=1;
00394             if ( p( ev ) == Real(0) )
00395             {   tmp = new BOX(zero, b->hom() ) ;
00396               uboxes.push ( tmp ); }
00397             //left
00398             tmp = new BOX( *b ) ;
00399             tmp->reverse_and_shift_box( 1 );
00400             tmp->reverse_box( 1 );
00401             uboxes.push ( tmp );
00402             
00403             free(b);
00404           }
00405         }
00406       }
00407     }
00408     return sols;
00409   }
00410 
00411     /*
00412        Return isolation box of the first positive root, [-1,-1] if none exists.
00413      */
00414     TMPLR
00415     Interval<Real> solver_cffirst<Real,POL>::first_root_isolate()
00416     {
00417         interval_rep<POL> a( first_root() );
00418         typename POL::scalar_t t(1);
00419         
00420         if ( a.poly()== POL(-1) ) 
00421             return (0);
00422         else 
00423             if (a.poly()==POL(0) ) 
00424                 return( a.template point<Real>(t) );
00425         else
00426             return ( a.template domain<Real>() );
00427     }
00428 
00429     TMPLR
00430     Real solver_cffirst<Real,POL>::first_root_approximate()
00431     {
00432         typedef interval_rep<POL> BOX;
00433         typedef typename POL::scalar_t C;
00434         BOX * l, * r= new BOX( first_root() ) ;
00435         C t(1);
00436         
00437         if ( r->poly()== POL(-1) ) 
00438             return (0);
00439         else 
00440             if (r->poly()==POL(0) ) 
00441                 return( r->template point<Real>(t) );
00442         else
00443         {
00444             /* Approximate */
00445             while ( r->template width<Real>() > eps )
00446             {
00447                 t= r->middle();
00448                 
00449                 if ( r->poly()( t ) == 0 ) return( r->template point<Real>(t) );
00450                 l= new BOX( *r) ;
00451                 l->shift_box( t );
00452                 
00453                 if ( l->sign_var() ) 
00454                 {   
00455                     free(r);
00456                     r=l; 
00457                     continue;
00458                 }
00459                 else 
00460                 {   
00461                     free(l);
00462                     r->contract_box(t);
00463                     r->reverse_and_shift_box(1);
00464                     r->reverse_box(1);
00465                 }  
00466             }
00467             
00468             return ( r->template domain<Real>() );
00469         }
00470     }
00471     
00472     TMPLR
00473     Real solver_cffirst<Real,POL>::first_root_floor()
00474     {
00475         typedef interval_rep<POL> BOX;
00476         typedef typename POL::scalar_t C;
00477 
00478         BOX * l, * r= new BOX( first_root() ) ;
00479         Interval<Real> I;
00480         C t(1);
00481         if ( r->poly()== POL(-1) ) 
00482             return (0);
00483         else 
00484             if (r->poly()==POL(0) ) 
00485                 return( r->template point<Real>(t) );
00486             else
00487             {
00488                 
00489                 I= r->template domain<Real>();
00490                 if ( r->poly() == POL(0) ) return as<Real> (floor(as<double>(r->template point<Real>(t))) );
00491                 while ( rfloor(I.m)!=rfloor(I.M) )
00492                 {
00493                     t= r->middle();
00494                     if ( r->poly()( t ) == 0 ) return as<Real>( floor(as<double>(r->template point<Real>(t))) ); 
00495                     
00496                     l= new BOX( *r) ;
00497                     l->shift_box( t );
00498                     
00499                     if ( l->sign_var() ) 
00500                     {   
00501                         free(r);
00502                         r=l; 
00503                         I= r->template domain<Real>(); 
00504                         continue;
00505                     }
00506                     else 
00507                     {   
00508                         free(l);
00509                         r->reverse_and_shift_box();
00510                         r->reverse_box();
00511                         I= r->template domain<Real>();
00512                     }  
00513                 }
00514             }
00515         return as<Real>( floor(as<double>(I.m)) );
00516     }/*first_root_floor*/
00517 
00518     TMPLR
00519     Seq<Interval<Real> > solver_cffirst<Real,POL>::all_roots_isolate()
00520     {
00521         Seq<interval_rep<POL> > a( all_roots() );
00522         Seq<Interval<Real> > s;
00523         typename POL::scalar_t t(1);
00524 
00525         for ( unsigned i=0; i<a.size(); ++i)
00526             if (a[i].poly()==POL(0) ) 
00527                 s<< Interval<Real>(a[i].template point<Real>(t) );
00528             else
00529                 s<< a[i].template domain<Real>();
00530 
00531         return s;
00532     }
00533 
00534     TMPLR
00535     Seq<Real> solver_cffirst<Real,POL>::all_roots_separate()
00536     {
00537         Seq< Interval<Real> > ints;
00538         Seq<Real> sep;
00539         
00540         ints= all_roots_isolate();
00541         for (unsigned i=1; i<ints.size(); ++i)
00542             sep << (ints[i-1].M + ints[i].m)*Real(0.5) ;
00543 
00544         return sep;
00545     }
00546 
00547 //--------------------------------------------------------------------
00548 template<class Ring>
00549 struct solver<Ring, CFfirstIsolate > {
00550 
00551     typedef typename Ring::scalar_t      base_t;
00552 
00553     template<class Real, class POL> static Interval<Real>
00554     solve(const POL& p,const base_t& u,const base_t& v);
00555 
00556     template<class Real, class POL> static Interval<Real>
00557     solve(const POL& p);
00558 };
00559 
00564 template<class Ring> 
00565 template<class Real, class POL> 
00566 Interval<Real>
00567 solver<Ring,CFfirstIsolate >::solve(const POL& p,
00568 const base_t & u,
00569 const base_t & v) {
00570 
00571   interval_rep<POL>  i(p,u,v);
00572   solver_cffirst<Real,POL> slv(i);
00573 
00574   return slv.first_root_isolate();
00575 }
00576 
00580 template<class Ring> 
00581 template<class Real, class POL> 
00582 Interval<Real>
00583 solver<Ring,CFfirstIsolate >::solve(const POL& p) {
00584 
00585   interval_rep<POL> i(p);
00586   solver_cffirst<Real,POL> slv(i);
00587 
00588   return slv.first_root_isolate();
00589 }
00590 
00591 
00592 //--------------------------------------------------------------------
00593     template<class Ring>
00594     struct solver<Ring, CFfirstApproximate > {
00595 
00596         typedef typename Ring::scalar_t   base_t;
00597 
00598         template<class Real, class POL> static Real
00599         solve(const POL& p, const base_t& u, const base_t& v);
00600         
00601         template<class Real, class POL> static Real
00602         solve(const POL& p);
00603 };
00604 
00609     template<class Ring> 
00610     template<class Real, class POL>
00611     Real
00612 
00613     solver<Ring,CFfirstApproximate >::solve(const POL& p,
00614                                  const base_t& u, const base_t& v) {
00615 
00616   
00617         interval_rep<POL>  i(p,u,v);
00618         solver_cffirst<Real,POL> slv(i);
00619 
00620         return slv.first_root_approximate();
00621 }
00622 
00626     template<class Ring> 
00627     template<class Real, class POL> 
00628     Real
00629     solver<Ring,CFfirstApproximate >::solve(const POL& p) {
00630 
00631 
00632         interval_rep<POL> i(p);
00633         solver_cffirst<Real,POL> slv(i);
00634 
00635   return slv.first_root_approximate();
00636 }
00637 
00638 
00639 //--------------------------------------------------------------------
00640     template<class Ring>
00641     struct solver<Ring, CFfirstFloor> {
00642         typedef typename Ring::Scalar  base_t;
00643 
00644         template<class Real, class POL> static Real
00645         solve(const POL& p, const base_t& u, const base_t& v);
00646 
00647         template<class Real,class POL> static Real
00648         solve(const POL& p);
00649 };
00650 
00655     template<class Ring> 
00656     template<class Real,class POL> 
00657     Real
00658     solver<Ring,CFfirstFloor >::solve(const POL& p,
00659                                  const base_t& u, const base_t& v) {
00660 
00661         interval_rep<POL>  i(p,u,v);
00662         solver_cffirst<Real,POL> slv(i);
00663         
00664         return slv.first_root_floor();
00665 }
00666 
00670     template<class Ring> 
00671     template<class Real, class POL> 
00672     Real
00673     solver<Ring,CFfirstFloor >::solve(const POL& p) {
00674         
00675         interval_rep<POL> i(p);
00676         solver_cffirst<Real,POL> slv(i);
00677         
00678         return slv.first_root_floor();
00679 }
00680 
00681 
00682 //--------------------------------------------------------------------
00683     template<class Ring>
00684     struct solver<Ring, CFallIsolate > {
00685 
00686         typedef typename Ring::Scalar   base_t;
00687 
00688         template<class Real, class POL> static Seq<Interval<Real> >
00689         solve(const POL& p,const base_t& u,const base_t& v);
00690 
00691         template<class Real,class POL> static Seq<Interval<Real> >
00692         solve(const POL& p);
00693 };
00694 
00698     template<class Ring> 
00699     template<class Real, class POL> 
00700     Seq<Interval<Real> >
00701     solver<Ring,CFallIsolate >::solve(const POL& p,
00702                                  const base_t& u, const base_t& v) {
00703 
00704         interval_rep<POL>  i(p,u,v);
00705         solver_cffirst<Real,POL> slv(i);
00706 
00707   return slv.all_roots_isolate();
00708 }
00709 
00713     template<class Ring> 
00714     template<class Real,class POL> 
00715     Seq<Interval<Real> >
00716     solver<Ring,CFallIsolate >::solve(const POL& p) {
00717 
00718         interval_rep<POL> i(p);
00719         solver_cffirst<Real,POL> slv(i);
00720 
00721         return slv.all_roots_isolate();
00722 }
00723 
00724 
00725 //--------------------------------------------------------------------
00726     template<class Ring>
00727     struct solver<Ring, CFseparate > {
00728 
00729         typedef typename Ring::Scalar  base_t;
00730 
00731         template<class Real,class POL> static Seq<Real>
00732         solve(const POL& p,const base_t& u,const base_t& v);
00733 
00734         template<class Real, class POL> static Seq<Real>
00735         solve(const POL& p);
00736 };
00737 
00741     template<class Ring> 
00742     template<class Real, class POL> 
00743     Seq<Real>
00744     solver<Ring,CFseparate >::solve(const POL& p,
00745                                  const base_t& u, const base_t& v) {
00746 
00747         interval_rep<POL>  i(p,u,v);
00748         solver_cffirst<Real,POL> slv(i);
00749         
00750         return slv.all_roots_separate();
00751 }
00752 
00756     template<class Ring> 
00757     template<class Real,class POL> 
00758     Seq<Real>
00759     solver<Ring,CFseparate >::solve(const POL& p) {
00760 
00761         interval_rep<POL> i(p);
00762         solver_cffirst<Real,POL> slv(i);
00763         
00764         return slv.all_roots_separate();
00765 }
00766 
00767 
00768 //--------------------------------------------------------------------
00769     template<class Ring> 
00770     struct solver<Ring,CFdecide> {
00771 
00772         template<class POL> static bool
00773         solve(const POL& p);
00774 };
00775 
00779     template<class Ring> 
00780     template<class POL> 
00781     bool
00782     solver<Ring,CFdecide>::solve(const POL& p) {
00783 
00784         interval_rep<POL> i(p);
00785         solver_cffirst<QQ,POL> slv(i);
00786         
00787         return ( slv.all_roots_isolate().size() );
00788 }
00789 
00790 
00791 } //namespace realroot
00792 
00793 #undef TMPL
00794 #undef TMPLR
00795 #undef NO_ROOT
00796 #undef N_ITER
00797 #endif // _realroot_SOLVER_FIRST_ROOT_CONFRAC_H