algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : series_carry_relaxed.hpp 00004 * DESCRIPTION: relaxed p-adic numbers 00005 * COPYRIGHT : (C) 2009 Jeremy Berthomieu and Gregoire Lecerf 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_CARRY_RELAXED_HPP 00014 #define __MMX_SERIES_CARRY_RELAXED_HPP 00015 #include <algebramix/series_relaxed.hpp> 00016 #include <algebramix/series_carry_naive.hpp> 00017 00018 namespace mmx { 00019 #define Series series<M,V> 00020 #define Series_rep series_rep<M,V> 00021 #define C typename M::C 00022 #define Modulus typename M::modulus 00023 #define TMPL template<typename M, typename V> 00024 00025 /****************************************************************************** 00026 * Variant 00027 ******************************************************************************/ 00028 00029 template<typename V> 00030 struct series_carry_relaxed {}; 00031 00032 template<typename U,typename V,typename W> 00033 struct implementation<V,W,series_carry_relaxed<U> >: 00034 public implementation<V,W,U> {}; 00035 00036 /****************************************************************************** 00037 * Relaxed multiplication 00038 ******************************************************************************/ 00039 00040 template<typename U,typename W> 00041 struct implementation<series_multiply,U,series_carry_relaxed<W> >: 00042 public implementation<series_abstractions,U> 00043 { 00044 00045 public: 00046 TMPL 00047 class mul_series_rep: public Series_rep { 00048 public: 00049 typedef Lift_type(M) L; 00050 00051 protected: 00052 Series f, g; 00053 00054 // NOTE: The following fields keep track of large segments of zeros 00055 // in the coefficients. This makes the multiplication algorithm linear 00056 // in the case when we multiply by a polynomial. This is for instance 00057 // interesting when computing coefficients of holonomic functions. 00058 int lnz_f; // last non-zero coefficient in f 00059 int lnz_g; // last non-zero coefficient in g 00060 nat zeros_f; // bit 2^p set if f[2^p-1 ... 2^{p+1}-1] = 0 00061 nat zeros_g; // bit 2^p set if g[2^p-1 ... 2^{p+1}-1] = 0 00062 00063 vector<L> b_f, d_f, b_g, d_g; // binary representations for the segments 00064 // b_f[q] is the last segment of f of size 2^q 00065 // d_f[q] is the "diagonal segment" of size 2^q 00066 vector<L> powers_of_p; // p^(2^i) 00067 vector<L> carry; // carry[q] is the carry in size 2^q 00068 00069 L get_power_of_p (const Modulus& p, nat i) { 00070 // lazy access to p^(2^i), for i >= 0 00071 // with its own memory allocation 00072 static const L zero (0); 00073 while (i >= N (powers_of_p)) 00074 powers_of_p << vector<L> (zero, max ((nat) 1, N (powers_of_p))); 00075 if (powers_of_p [i] == zero) { 00076 if (i == 0) powers_of_p[0]= L(* p); 00077 else powers_of_p[i]= square (get_power_of_p (p, i - 1)); 00078 } 00079 return powers_of_p [i]; 00080 } 00081 00082 public: 00083 mul_series_rep (const Series& f2, const Series& g2): 00084 Series_rep (CF(f2)), f (f2), g (g2), lnz_f (-1), lnz_g (-1), 00085 zeros_f (0), zeros_g (0) {} 00086 ~mul_series_rep () {} 00087 00088 syntactic expression (const syntactic& z) const { 00089 return flatten (f, z) * flatten (g, z); } 00090 00091 void Set_order (nat l2) { 00092 Series_rep::Set_order (l2); 00093 nat m= log_2 (next_power_of_two (l2 + 1)); 00094 if (N(b_f) < m) { 00095 vector<L> tmp (L(0), m - N(b_f)); 00096 b_f << tmp; d_f << tmp; 00097 b_g << tmp; d_g << tmp; 00098 carry << tmp; } } 00099 00100 void Increase_order (nat l) { 00101 Set_order (l); 00102 increase_order (f, l); 00103 increase_order (g, l); } 00104 00105 M next () { 00106 //mmout << "--> next " << this->n << "\n"; 00107 Modulus p= M::get_modulus (); 00108 nat k= this->n; 00109 if (exact_neq (f[k], M(0))) lnz_f= k; 00110 if (exact_neq (g[k], M(0))) lnz_g= k; 00111 if (k == 0) { 00112 C r= 0; 00113 if (lnz_f < 0) zeros_f |= 1; 00114 if (lnz_g < 0) zeros_g |= 1; 00115 if ((zeros_f&1) == 0 && (zeros_g&1) == 0) { 00116 C q= 0; 00117 mul_mod (r, * f[0], * g[0], p, q); 00118 carry[0]= as<L> (q); 00119 } 00120 b_f[0]= d_f[0]= lift (f[0]); 00121 b_g[0]= d_g[0]= lift (g[0]); 00122 return M (r, true); 00123 } 00124 else { 00125 k = 2 * (this->n + 2); 00126 L t= 0, e_f= lift (f[this->n]), e_g= lift (g[this->n]); 00127 nat q= -1; 00128 while ((k&1) == 0 && k != 2) { 00129 q++; k= k >> 1; 00130 //mmout << "k= " << k << "\n"; 00131 if (q > 0) { 00132 e_f= b_f[q-1] + get_power_of_p (p, q-1) * e_f; 00133 e_g= b_g[q-1] + get_power_of_p (p, q-1) * e_g; 00134 } 00135 if (k == 2) { 00136 if (lnz_f < ((int) (1<<q)-1)) zeros_f |= (1<<q); 00137 if (lnz_g < ((int) (1<<q)-1)) zeros_g |= (1<<q); 00138 d_f[q]= e_f; d_g[q]= e_g; 00139 } 00140 t += carry[q]; 00141 if (q == 0 || 00142 ((zeros_f & (1<<q)) == 0 && lnz_g >= ((int) (((k-1)<<q)-1)))) 00143 t += d_f[q] * e_g; 00144 if (k == 2) break; 00145 if (q == 0 || 00146 ((zeros_g & (1<<q)) == 0 && lnz_f >= ((int) (((k-1)<<q)-1)))) { 00147 t += e_f * d_g[q]; 00148 } 00149 } 00150 b_f[q]= e_f; b_g[q]= e_g; 00151 while (q != (nat) -1) { 00152 t = rem (t, get_power_of_p (p, q), carry[q]); 00153 q--; 00154 } 00155 return M (as<C> (t), true); } } 00156 }; 00157 00158 TMPL static inline Series 00159 ser_mul (const Series& f, const Series& g) { 00160 //mmout << "f= " << f << "\n"; 00161 //mmout << "g= " << g << "\n"; 00162 typedef mul_series_rep<M,V> Mul_rep; 00163 if (is_exact_zero (f) || is_exact_zero (g)) 00164 return Series (CF(f)); 00165 return (Series_rep*) new Mul_rep (f, g); } 00166 00167 TMPL static inline Series 00168 ser_truncate_mul (const Series& f, const Series& g, nat nf, nat ng) { 00169 typedef mul_series_rep<M,V> Mul_rep; 00170 if (is_exact_zero (f) || is_exact_zero (g) || nf == 0 || ng == 0) 00171 return Series (CF(f)); 00172 return (Series_rep*) 00173 new Mul_rep (piecewise (f, Series (CF(f)), nf), 00174 piecewise (g, Series (CF(g)), ng)); } 00175 00176 }; // implementation<series_multiply,U,series_carry_relaxed>: 00177 00178 #undef Series 00179 #undef Series_rep 00180 #undef C 00181 #undef Modulus 00182 #undef TMPL 00183 00184 } // namespace mmx 00185 #endif // __MMX_SERIES_CARRY_RELAXED_HPP