algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/series_relaxed.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : series_relaxed.hpp
00004 * DESCRIPTION: Relaxed univariate power series
00005 * COPYRIGHT  : (C) 2006  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #ifndef __MMX__SERIES_RELAXED__HPP
00014 #define __MMX__SERIES_RELAXED__HPP
00015 #include <algebramix/series_naive.hpp>
00016 namespace mmx {
00017 #define TMPL template<typename C,typename V>
00018 #define Series series<C,V>
00019 #define Series_rep series_rep<C,V>
00020 
00021 /******************************************************************************
00022 * Variant
00023 ******************************************************************************/
00024 
00025 template<typename V>
00026 struct series_relaxed {};
00027 
00028 template<typename F, typename V, typename W>
00029 struct implementation<F,V,series_relaxed<W> >:
00030     public implementation<F,V,W> {};
00031 
00032 /******************************************************************************
00033 * Relaxed multiplication
00034 ******************************************************************************/
00035 
00036 template<typename U,typename W>
00037 struct implementation<series_multiply,U,series_relaxed<W> >:
00038   public implementation<series_abstractions,U>
00039 {
00040 
00041 TMPL
00042 class mul_series_rep: public Series_rep {
00043 public:
00044   typedef typename series_polynomial_helper<C,V >::PV PV;
00045   typedef implementation<polynomial_multiply,PV> Pol;
00046 
00047 protected:
00048   Series f, g;
00049 
00050   // NOTE: The following fields keep track of large segments of zeros
00051   // in the coefficients. This makes the multiplication algorithm linear
00052   // in the case when we multiply by a polynomial. This is for instance
00053   // interesting when computing coefficients of holonomic functions.
00054   int lnz_f;    // last non-zero coefficient in f
00055   int lnz_g;    // last non-zero coefficient in g
00056   nat zeros_f;  // bit 2^p set if f[2^p-1 ... 2^{p+1}-1] = 0
00057   nat zeros_g;  // bit 2^p set if g[2^p-1 ... 2^{p+1}-1] = 0
00058 
00059 public:
00060   mul_series_rep (const Series& f2, const Series& g2):
00061     Series_rep (CF(f2)), f (f2), g (g2), lnz_f (-1), lnz_g (-1),
00062     zeros_f (0), zeros_g (0) {}
00063   ~mul_series_rep () {}
00064 
00065   syntactic expression (const syntactic& z) const {
00066     return flatten (f, z) * flatten (g, z); }
00067 
00068   void Set_order (nat l2) {
00069     // NOTE: far from optimal, but let us not bother...
00070     if (l2 <= this->l) return;
00071     mmx_delete<C> (this->a, this->l);
00072     this->a= mmx_new<C> (l2);
00073     this->l= l2;
00074     Pol::clear (this->a, this->l);
00075     nat k= this->n;
00076     this->n= 0;
00077     lnz_f= -1;
00078     lnz_g= -1;
00079     /* not so nice in case of zero coefficients...
00080     if (k>0) {
00081       nat i= 1;
00082       while (((i<<1) + 1 < k) && ((i<<1) - 1 < this->l))
00083         i= (i<<1) + 1;
00084       Pol::mul (this->a, f->a, g->a, i, i);
00085       this->n= i;
00086     }
00087     */
00088     while (this->n < k) {
00089       (void) next ();
00090       this->n++;
00091     }
00092   }
00093 
00094   void Increase_order (nat l) {
00095     if (this->l < l) {
00096       nat k=1;
00097       while (k < (this->l << 1)) k= (k<<1) + 1;
00098       Set_order (max (k, l));
00099     }
00100     increase_order (f, l);
00101     increase_order (g, l);
00102   }
00103 
00104   C next () {
00105     nat k= this->n;
00106     if (exact_neq (f[k], C(0))) lnz_f= k;
00107     if (exact_neq (g[k], C(0))) lnz_g= k;
00108     if (k == 0) {
00109       if (lnz_f < 0) zeros_f |= 1;
00110       if (lnz_g < 0) zeros_g |= 1;
00111       if ((zeros_f&1) == 0 && (zeros_g&1) == 0) this->a[0]= f[0] * g[0];
00112     }
00113     else {
00114       if ((zeros_f&1) == 0) this->a[k] += f[0] * g[k];
00115       if ((zeros_g&1) == 0) this->a[k] += f[k] * g[0];
00116       if ((k&1) == 0) {
00117         nat p= 0;
00118         k += 2;
00119         while ((k&1) == 0 && k != 2) {
00120           p++;
00121           k= k >> 1;
00122           nat len= min (this->l, ((k+2)<<p) - 3) - ((k<<p) - 2);
00123           nat ord= min (((nat) 1)<<p, len);
00124           if (k == 2) {
00125             if (lnz_f < ((int) (1<<p)-1)) zeros_f |= (1<<p);
00126             if (lnz_g < ((int) (1<<p)-1)) zeros_g |= (1<<p);
00127           }
00128           C* aux= mmx_new<C> ((ord << 1) - 1);
00129           if ((zeros_f & (1<<p)) == 0 && lnz_g >= ((int) (((k-1)<<p)-1))) {
00130             //mmout << "  " << ((1<<p)-1) << " - " << (((1<<p)-1)+ord)
00131             //<< " x " << ((k-1)<<p)-1 << " - " << ((k-1)<<p)-1+ord << "\n";
00132             Pol::mul (aux, f->a + (1<<p)-1, g->a + ((k-1)<<p)-1, ord, ord);
00133             Pol::add (this->a + (k<<p)-2, aux, len);
00134           }
00135           if (k != 2)
00136             if ((zeros_g & (1<<p)) == 0 && lnz_f >= ((int) (((k-1)<<p)-1))) {
00137               //mmout << "  " << ((k-1)<<p)-1 << " - " << ((k-1)<<p)-1+ord
00138               //<< " x " << ((1<<p)-1) << " - " << (((1<<p)-1)+ord) << "\n";
00139               Pol::mul (aux, f->a + ((k-1)<<p)-1, g->a + (1<<p)-1, ord, ord);
00140               Pol::add (this->a + (k<<p)-2, aux, len);
00141             }
00142           mmx_delete<C> (aux, (ord << 1) - 1);
00143         }
00144       }
00145     }
00146     /*
00147     mmout << this->n << ", " << type_name<C> () << "\n\t";
00148     for (nat i= 0; i<=this->n; i++) mmout << f->a[i] << " ";
00149     Series::set_formula_output (true);
00150     mmout << "; " << zeros_f << "; " << flatten (f, "z") << "\n";
00151     Series::set_formula_output (false);
00152     mmout << "\t";
00153     for (nat i= 0; i<=this->n; i++) mmout << g->a[i] << " ";
00154     Series::set_formula_output (true);
00155     mmout << "; " << zeros_g << "; " << flatten (g, "z") << "\n";
00156     Series::set_formula_output (false);
00157     mmout << "\t";
00158     for (nat i= 0; i<=this->n; i++) mmout << this->a[i] << " ";
00159     mmout << "\n";
00160     */
00161     return this->a [this->n];
00162   }
00163 };
00164 
00165 TMPL static inline Series
00166 ser_mul (const Series& f, const Series& g) {
00167   typedef mul_series_rep<C,V> Mul_rep;
00168   if (is_exact_zero (f) || is_exact_zero (g))
00169     return Series (CF(f));
00170   return (Series_rep*) new Mul_rep (f, g); }
00171 
00172 TMPL static inline Series
00173 ser_truncate_mul (const Series& f, const Series& g, nat nf, nat ng) {
00174   typedef mul_series_rep<C,V> Mul_rep;
00175   if (is_exact_zero (f) || is_exact_zero (g) || nf == 0 || ng == 0)
00176     return Series (CF(f));
00177   return (Series_rep*)
00178     new Mul_rep (piecewise (f, Series (CF(f)), nf),
00179                  piecewise (g, Series (CF(g)), ng)); }
00180 
00181 }; // implementation<series_multiply,V,series_relaxed<W> >:
00182 
00183 #ifdef ALGEBRAMIX_ENABLE_UNSTABLE
00184 
00185 /******************************************************************************
00186 * Right composition with polynomials
00187 ******************************************************************************/
00188 
00189 TMPL Series compose (const Series& f, nat i, nat p, nat q, Series* H);
00190 
00191 TMPL
00192 struct partial_pol_compose_series_rep: public Series_rep {
00193   Series f, h;
00194   nat i, r;
00195   partial_pol_compose_series_rep<C>
00196     (const Series& f2, nat i2, nat p, nat q, Series* H);
00197   generic expression (const generic& z) const {
00198     return gen ("partial_polynomial_compose"); }
00199   void Increase_order (nat l) {
00200     Series_rep::Increase_order (min (l, r));
00201     increase_order (h, min (l, r));
00202   }
00203   C next ();
00204 };
00205 
00206 TMPL
00207 partial_pol_compose_series_rep<C>::partial_pol_compose_series_rep (
00208   const Series& f2, nat i2, nat p, nat q, Series* H):
00209     Series_rep (CF(f2)), f (f2), i (i2), r ((p-1) * (q-1) + 1)
00210 {
00211   assert (p > 1);
00212   Series h1= compose (f, i, p>>1, q, H);
00213   Series h2= compose (f, i+ (p>>1), p>>1, q, H);
00214   int d= p>>1;
00215   h= h1+ lshiftz (h2 * rshiftz (H[p>>1], d), d);
00216 }
00217 
00218 TMPL C
00219 partial_pol_compose_series_rep<C>::next () {
00220   nat n= this->n;
00221   if (n == r) h= 0;
00222   if (n >= r) return 0;
00223   return h[n];
00224 }
00225 
00226 TMPL Series
00227 compose (const Series& f, nat i, nat p, nat q, Series* H) {
00228   if (p == 1) return Series (f[i]);
00229   return (Series_rep*) new partial_pol_compose_series_rep<C> (f, i, p, q, H);
00230 }
00231 
00232 TMPL
00233 struct pol_compose_series_rep: public Series_rep {
00234   Series f, *H, h;
00235   nat q;
00236   pol_compose_series_rep<C> (const Series& f, const Series& g, nat q);
00237   ~pol_compose_series_rep<C> () { mmx_classical_delete<Series > (H); }
00238   syntactic expression (const syntactic& z) const {
00239     return apply (GEN_COMPOSE, flatten (f, z), flatten (H[1], z)); }
00240   void Increase_order (nat l) {
00241     Series_rep::Increase_order (l);
00242     increase_order (f, l);
00243     increase_order (h, l);
00244   }
00245   C next ();
00246 };
00247 
00248 TMPL
00249 pol_compose_series_rep<C>::pol_compose_series_rep
00250   (const Series& f2, const Series& g, nat q2):
00251     Series_rep (CF(f2)), f (f2), q (q2)
00252 {
00253   H= mmx_classical_new<Series > (2);
00254   H[1]= g;
00255   h= compose (f, 0, 1, q, H);
00256 }
00257 
00258 TMPL C
00259 pol_compose_series_rep<C>::next () {
00260   nat n= this->n;
00261   nat k= n;
00262   nat i;
00263   if (k > 0) while ((k&1) == 0) k= k>>1;
00264   if (k == 1) {
00265     if (n > 1) {
00266       Series* H2= mmx_classical_new<Series > (n+1);
00267       for (i=1; i<n; i=i<<1) H2[i]= H[i];
00268       H2[n]= H[n>>1] * H[n>>1];
00269       mmx_classical_delete<Series > (H);
00270       H= H2;
00271     }
00272     h= compose (f, 0, n<<1, q, H);
00273     increase_order (h, this->l);
00274   }
00275   return h[n];
00276 }
00277 
00278 TMPL Series
00279 compose (const Series& f, const Series& g, nat q) {
00280   if (is_exact_zero (f)) return Series (CF(f));
00281   ASSERT (g[0] == 0, "constant coefficient must be zero");  
00282   return (Series_rep*) new pol_compose_series_rep<C> (f, g, q);
00283 }
00284 
00285 /******************************************************************************
00286 * General relaxed composition
00287 ******************************************************************************/
00288 
00289 template<typename C> C
00290 multiply_range (nat first, nat end) {
00291   if (end == first) return C(1);
00292   else if (end == first+1) return C (first);
00293   nat half= (first + end) >> 1;
00294   return multiply_range<C> (first, half) * multiply_range<C> (half, end);
00295 }
00296 
00297 TMPL
00298 class relaxed_compose_series_rep: public Series_rep {
00299 protected:
00300   Series f, g, h;
00301 
00302 public:
00303   relaxed_compose_series_rep (const Series& f2, const Series& g2):
00304     Series_rep (CF(f2)), f (f2), g (g2),
00305     h ((Series_rep*) new compose_series_rep<C,V> (f2, g2)) {}
00306   ~relaxed_compose_series_rep () {}
00307 
00308   syntactic expression (const syntactic& z) const {
00309     return apply (GEN_COMPOSE, flatten (f, z), flatten (g, z)); }
00310 
00311   void Increase_order (nat l) {
00312     Series_rep::Increase_order (l);
00313     increase_order (f, l);
00314     increase_order (g, l);
00315   }
00316 
00317   C next () {
00318     nat n= this->n;
00319     if (n==0) return f[0];
00320     if (n==1) return f[1]*g[1];
00321     if (n==2) return f[2]*g[1]*g[1]+ f[1]*g[2];
00322     if (n==3) return (f[3]*g[1]*g[1]+ C(2)*f[2]*g[2])*g[1]+ f[1]*g[3];
00323 
00324     nat p=0;
00325     while (((p+1) * (1<<(2*p))) <= n) p++;
00326     if ((n != 4) && ((p * (1<<(2*p-2))) <= (n-1))) return h[n];
00327 
00328     nat nn= (p+1) * (1<<(2*p));
00329     nat i, q= 2<<p, r= (nn+q-1)/q;
00330     Series g1 = restrict (g, 0, q);
00331     Series dg1= derive (g1);
00332     Series g2 = rshiftz (g - g1, (int) q);
00333 
00334     Series D= f;
00335     for (i=1; i<r; i++) D= derive (D);
00336     D= compose (D, g1, q) / multiply_range<C> (1, r); // divides by (r-1)!
00337     h= D;
00338 
00339     for (i=r-1; i>0; i--) {
00340       D= (integrate (C(i) * D * dg1)) + f[i-1];
00341       h= D + lshiftz (h*g2, q);
00342     }
00343 
00344     increase_order (h, this->l);
00345     return h[n];
00346   }
00347 };
00348 
00349 TMPL Series
00350 bk_compose (const Series& f, const Series& g) {
00351   // NOTE: not yet default; needs further efficiency and accuracy twiddling
00352   if (is_exact_zero (f)) return Series (CF(f));
00353   ASSERT (g[0] == 0, "constant coefficient must be zero");  
00354   return (Series_rep*) new relaxed_compose_series_rep<C> (f, g);
00355 }
00356 #endif // UNSTABLE
00357 
00358 #undef TMPL
00359 #undef Series
00360 #undef Series_rep
00361 } // namespace mmx
00362 #endif // __MMX__SERIES_RELAXED__HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines