00001
00002
00003
00004
00005
00006 #ifndef realroot_solver_bspline_hpp
00007 #define realroot_solver_bspline_hpp
00008
00009 #include <realroot/vector_monomials.hpp>
00010 #include <realroot/ring_bernstein_tensor.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
00050
00051
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
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
00092 if ( k >= m_n ) {
00093
00094
00095 x = NO_ROOT;
00096 break;
00097 }
00098
00099
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
00112 const Real e = std::max(x, m_t[k+m_d-1]) - std::min(x, m_t[k+1] );
00113
00114 if (e < eps)
00115 break;
00116
00117
00118 insert_knot(x,k);
00119 }
00120
00121
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 }
00218 #undef TMPL
00219 #undef NO_ROOT
00220 #endif //realroot_solver_bspline_hpp
00221