realroot_doc 0.1.1
/Users/mourrain/Devel/mmx/realroot/include/realroot/solver_uv_bspline.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): J. Seland SINTEF
00004  *              B. Mourrain GALAAD, INRIA
00005  ********************************************************************/
00006 #ifndef realroot_solver_bspline_hpp
00007 #define realroot_solver_bspline_hpp
00008 /********************************************************************/
00009 #include <realroot/univariate.hpp>
00010 #include <realroot/polynomial_bernstein.hpp>
00011 #include <realroot/solver.hpp>
00012 //--------------------------------------------------------------------
00013 #define NO_ROOT -1.0
00014 #define TMPL template<class Real>
00015 namespace mmx {
00016   
00017 struct Bspline{};
00018 
00019 //-----------------------------------------------------------------------------
00020 TMPL
00021 Real knotSum(Real* t, int k, int d)
00022 {
00023   Real ret = t[k+1];
00024   for ( int i=2; i<=d; ++i) ret+=t[k+i];
00025   return ret;
00026 }
00027 
00028 //-----------------------------------------------------------------------------
00029 TMPL
00030 struct solver_bspline {
00031   Real *m_t, *m_c;
00032   unsigned m_n, maxn, m_k ;
00033   int m_d;
00034   Real eps;
00035 
00036   solver_bspline(unsigned n, unsigned d, unsigned N=100): m_n(n), maxn(N+n), m_d(d), eps(1e-7) { 
00037     m_t= new Real[2*n+N]; 
00038     for(unsigned i=0; i< 2*n+N; i++) m_t[i]=Real(1);
00039     m_c = new Real[n+N];
00040     for(unsigned i=0; i< n+N; i++) m_c[i]=Real(0);
00041   }
00042   
00043   int  insert_knot ( const Real& x, int mu) ;
00044   Real first_root  ();
00045 
00046 };
00047 
00048 //-----------------------------------------------------------------------------
00049 // insert knot x in interval mu by Boehms algorithm
00050 // Note: t,c must have capacity at least n+1, n+d+2 respectively
00051 // require that x>=t[mu]
00052 TMPL
00053 int solver_bspline<Real>::insert_knot( const Real& x, int mu) 
00054 {
00055   mu = std::max(mu,m_d);
00056   while ( x>=m_t[mu+1]) mu++;
00057   
00058   for ( int i=m_n; i>mu; i--) {
00059     m_c[i] = m_c[i-1];
00060   }
00061   
00062   for ( int i=mu; i>=mu-m_d+1; i--) {
00063     const Real alpha = (x-m_t[i])/(m_t[i+m_d]-m_t[i]);
00064     m_c[i] = (1.0-alpha) * m_c[i-1] + alpha * m_c[i];
00065   }
00066 
00067   m_t[m_n+m_d] = 1.0;
00068   
00069   for ( int i=m_n; i>mu+1; --i)
00070     m_t[i] = m_t[i-1];
00071   m_t[mu+1] = x;
00072   
00073   //    n++;
00074   return mu;
00075 }
00076   
00077 // --------------------------------------------------------------------------
00078 TMPL
00079 Real solver_bspline<Real>::first_root(void)
00080 {
00081 
00082   unsigned k = 1;
00083   Real x = NO_ROOT;
00084     
00085   for ( ;  m_n < maxn; ++m_n ) {
00086     
00087     while( k<m_n && (m_c[k-1]*m_c[k] > 0.0) )
00088       ++k;
00089     
00090     
00091     // Off end?
00092     if ( k >= m_n ) {
00093       //if (x!= NO_ROOT)
00094       //x = -x; // NO_ROOT;
00095       x = NO_ROOT;
00096       break;
00097     }
00098     
00099     // Interval converged?
00100     const Real diff = m_t[k+m_d]-m_t[k];
00101 
00102     if (diff<eps) {
00103       x = m_t[k];
00104       break;
00105     }
00106     
00107     const Real av = knotSum(m_t,k-1, m_d);
00108     const Real lambda = m_c[k-1]/(m_c[k-1]-m_c[k]);
00109     x = (av + lambda*diff)/Real(m_d);
00110 
00111     // Stopping criterion
00112     const Real e = std::max(x, m_t[k+m_d-1]) - std::min(x, m_t[k+1] );
00113     // const Real e = max(fabs(x-t[k+1]),fabs(x-t[k+m_d-1]));
00114     if (e < eps)
00115       break;
00116     
00117     // Refine spline
00118     insert_knot(x,k);
00119   }
00120   
00121   //  dx = d*(m_c[k]-m_c[k-1])/(t[k+m_d]-t[k]);
00122   m_k  = k;
00123   return x;
00124 }
00125 //--------------------------------------------------------------------
00126 template<class Ring>
00127 struct solver<Ring, Bspline> {
00128   typedef double                                    solution_t;
00129   typedef solver_bspline<typename Ring::Scalar>     base_t;
00130 
00131   template<class POL,class T> static solution_t
00132   first_root(const POL& p, const T& u, const T& v);
00133 
00134   template<class POL> static solution_t
00135   first_root(const POL& p);
00136 
00137 };
00138 //--------------------------------------------------------------------
00142 template<class Ring> 
00143 template<class POL, class T> 
00144 typename solver<Ring,Bspline>::solution_t
00145 solver<Ring,Bspline>::first_root(const POL& p,
00146                                  const T& u, const T& v) {
00147 
00148   typedef typename Ring::scalar_t                     Real;
00149   typedef typename POL::Ring                          ring_t;
00150   typedef typename solver<Ring, Bspline>::base_t      base_t;
00151   typedef GMP::rational                               rational;
00152   
00153   rational U,V;
00154   let::assign(U,u);
00155   let::assign(V,v);
00156   int sz= degree(p)+1;
00157 
00158   std::vector<rational> bp(sz);
00159   univariate::convertm2b(bp,p,sz,U,V);
00160 
00161   solver_bspline<Real> slv(sz,sz-1);
00162 
00163   for ( int i = 0; i < sz; i ++ ) {
00164     slv.m_c[i]=as<Real>(bp[i]);
00165     slv.m_t[i]=Real(0);
00166   }
00167 
00168   return u +(v-u)*slv.first_root();
00169 
00170 }
00171 
00174 template<class Ring> 
00175 template<class POL> 
00176 typename solver<Ring,Bspline>::solution_t
00177 solver<Ring,Bspline>::first_root(const POL& p) {
00178 
00179   typedef typename Ring::Scalar                       Real;
00180   typedef typename POL::Ring                          ring_t;
00181   typedef typename solver<Ring, Bspline>::base_t      base_t;
00182   typedef GMP::integer                                integer;
00183   typedef GMP::rational                               rational;
00184 
00185 
00186   int d= degree(p), sz=d+1;
00187   solver_bspline<Real> slv(sz,sz-1);
00188 
00189   std::vector<rational> bp(sz);
00190   binomials<integer> bn;
00191   rational c;
00192   if(p[0]==0) 
00193     return 0;
00194   else if(p[0]<0) {
00195     numerics::rounding<Real> rnd( numerics::rnd_up() );
00196     for(int i=0;i<sz;i++) {
00197       c= as<rational>(p[i])/bn(d,i);
00198       slv.m_c[i]=as<Real>(c);
00199     }
00200   } else {
00201     numerics::rounding<Real> rnd( numerics::rnd_dw() );
00202     for(int i=0;i<sz;i++) {
00203       c= as<rational>(p[i])/bn(d,i);
00204       slv.m_c[i]=as<Real>(c);
00205     }
00206   }
00207   for ( int i = 0; i < sz; i ++ ) {
00208     slv.m_t[i]=Real(0);
00209   }
00210 
00211   Real x= slv.first_root();
00212  
00213   return x/(1-x);
00214 
00215 }
00216 //====================================================================
00217 } //namespace mmx
00218 #undef TMPL
00219 #undef NO_ROOT
00220 #endif  //realroot_solver_bspline_hpp
00221