algebramix_doc 0.3
|
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