algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/series_carry_relaxed.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines