algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/p_adic.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : p_adic.hpp
00004 * DESCRIPTION: p-adic integers
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_P_ADIC_HPP
00014 #define __MMX_P_ADIC_HPP
00015 #include <basix/pair.hpp>
00016 #include <algebramix/p_expansion_modular_int.hpp>
00017 #include <algebramix/p_expansion_modular_integer.hpp>
00018 #include <algebramix/series_int.hpp>
00019 #include <algebramix/series_integer.hpp>
00020 #include <algebramix/series_modular_int.hpp>
00021 #include <algebramix/series_integer.hpp>
00022 #include <algebramix/series_modular_integer.hpp>
00023 #include <algebramix/series_carry.hpp>
00024 #include <algebramix/series_carry_relaxed.hpp>
00025 #include <algebramix/series_carry_blocks.hpp>
00026 
00027 namespace mmx {
00028 
00029 #define P_adic_variant(M) Series_carry_variant (M)
00030 #define p_adic(M, V) series<M,V>
00031 #define default_p_adic(M) p_adic(M, typename P_adic_variant(M))
00032 
00033 #define Series series<M,V>
00034 #define Series_rep series_rep<M,V>
00035 #define C typename M::C
00036 #define TMPL template<typename M,typename V>
00037 
00038 /******************************************************************************
00039 * Specific variant for p-adic integer
00040 ******************************************************************************/
00041 
00042 template<typename V>
00043 struct series_carry_p_adic {};
00044 
00045 template<typename U,typename V,typename W>
00046 struct implementation<V,U,series_carry_p_adic<W> >:
00047   public implementation<V,U,W> {};
00048 
00049 /******************************************************************************
00050 * Naive product optimized for small hardware integer
00051 ******************************************************************************/
00052 
00053 template<typename V>
00054 struct series_carry_modular_int_naive {};
00055 
00056 template<typename U,typename V,typename W>
00057 struct implementation<V,W,series_carry_modular_int_naive<U> >:
00058   public implementation<V,W,U> {};
00059 
00060 template<typename U,typename W>
00061 struct implementation<series_multiply,U,series_carry_modular_int_naive<W> >:
00062   public implementation<series_abstractions,U>
00063 {
00064   typedef implementation<series_abstractions,U> Ser;
00065 
00066 template<typename M,typename V>
00067 class mul_series_rep: public Ser::template binary_series_rep<mul_op,M,V> {
00068   typedef typename M::modulus Modulus;
00069   typedef integer L;
00070   typedef unsigned long int N;
00071   nat nf, ng;
00072   L carry;
00073   xnat free_bits;
00074   
00075 public:
00076   inline mul_series_rep (const Series& f, const Series& g,
00077                          nat nf2= Maximal (nat),
00078                          nat ng2= Maximal (nat)):
00079     Ser::template binary_series_rep<mul_op,M,V> (f, g),
00080     nf (nf2), ng (ng2), carry (0) {
00081     Modulus p= M::get_modulus ();
00082     xnat p_size= bit_size (* p);
00083     xnat N_size= 8 * sizeof (N);
00084     free_bits= N_size <= 2 * p_size ? 0 : (N_size - 2 * p_size); }
00085   M next () {
00086     nat n= this->n;
00087     Modulus p= M::get_modulus ();
00088     if (n < 8 || free_bits <= 3) {
00089       C acc= as<C> (rem (carry, * p, carry)), tmp_a, tmp_c;
00090       for (nat i= n >= ng ? n - ng + 1 : 0; i < min (1 + n, nf); i++) {
00091         tmp_c= 0;
00092         mul_mod (tmp_a, (this->f[i]).rep, (this->g[n-i]).rep, p, tmp_c);
00093         carry += tmp_c; tmp_c= 0;
00094         add_mod (acc, tmp_a, p, tmp_c);
00095         carry += tmp_c;
00096       }
00097       return acc;
00098     }
00099     C acc= as<C> (rem (carry, * p, carry)), tmp_a, tmp_c;
00100     nat n_max= min (1 + n, nf);
00101     for (nat i= n >= ng ? n - ng + 1 : 0; i < n_max;) {
00102       N t0= 0, t1= 0;
00103       nat i_max= i + min (((nat) 1 << free_bits), (nat) (n_max - i));
00104       for (; i < i_max; i++)
00105         t0 += N((this->f[i]).rep) * N((this->g[n-i]).rep);
00106       tmp_a= rem (t0, * p, t1);
00107       tmp_c= 0; add_mod (acc, tmp_a, p, tmp_c);
00108       carry += tmp_c + t1;
00109     }
00110     return acc; }
00111 };
00112 
00113 template<typename M,typename V> static inline Series
00114 ser_mul (const Series& f, const Series& g) {
00115   typedef mul_series_rep<M,V> Mul_rep;
00116   if (is_exact_zero (f) || is_exact_zero (g))
00117     return Series (CF(f));
00118   return (Series_rep*) new Mul_rep (f, g); }
00119 
00120 template<typename M,typename V> static inline Series
00121 ser_truncate_mul (const Series& f, const Series& g, nat nf, nat ng) {
00122   typedef mul_series_rep<M,V> Mul_rep;
00123   if (is_exact_zero (f) || is_exact_zero (g) || nf == 0 || ng == 0)
00124     return Series (CF(f));
00125   return (Series_rep*) new Mul_rep (f, g, nf, ng); }
00126 
00127 }; // implementation<series_multiply,U,series_carry_modular_int_naive<U> >
00128 
00129 /******************************************************************************
00130 * p-th root
00131 ******************************************************************************/
00132 #define Pair pair<integer,integer>
00133 
00134 struct ser_carry_pth_root_reg_op {
00135   // For the only computation of the regularized part for p >= 3 only
00136 
00137   template<typename M, typename V> static Series
00138   binpow_no_tangent_normalized (const Series& x0, const Series& x1,
00139                                 const integer& r, const integer& p) {
00140     // ((x0 + p * x1)^r - r * p * x1 * x0^(r-1) - x0^r) / p^2
00141     // x1 has valuation at least 1
00142     ASSERT (p >= 3, "bug");
00143     if (r <= 1) return Series (0);
00144 
00145     Series x1_2= lshiftz (square (rshiftz (x1, 1)), 2);
00146     if (r == 2) return x1_2;
00147 
00148     Series s_p   (coefficients (as<default_p_expansion(M)> (p)));
00149 
00150     if ((r & 1) == 1) {
00151       integer h= r - 1;
00152       Series w= binpow_no_tangent_normalized (x0, x1, h, p);
00153       Series s_h (coefficients (as<default_p_expansion(M)> (h)));
00154       Series x0_h_1= binpow (x0, h - 1);
00155       return lshiftz ((x0 + s_p * x1) * rshiftz (w, 1), 1)
00156         + s_h * x0_h_1 * x1_2;
00157     }
00158 
00159     integer h= r >> 1; // r is now even
00160     Series s_h   (coefficients (as<default_p_expansion(M)> (h)));
00161     Series s_p_2 (coefficients (as<default_p_expansion(M)> (square (p))));
00162     Series x0_h_1= binpow (x0, h - 1);
00163     Series x0_h= x0 * x0_h_1;
00164 
00165     Series d= binpow_no_tangent_normalized (x0, x1, h, p);
00166     Series l= s_h * s_p * x0_h_1 * x1 + x0_h;
00167     return lshiftz (rshiftz (d, 1) * (s_p_2 * d + l + l), 1)
00168       + square (s_h * x0_h_1) * x1_2;
00169   }
00170 
00171   static generic name () { return "pth_root"; }
00172 
00173   template<typename M> static inline M
00174   op (const M& a, const Pair& p) {
00175     (void) p; return a; }
00176 
00177   template<typename M, typename V> static inline Series
00178   op (const Series& a, const Pair& p) {
00179     typedef implementation<series_pth_root_reg,V> Ser;
00180     return Ser::unsep_root_reg (a, p); }
00181 
00182   template<typename M, typename V> static inline Series
00183   op_init (const Series& a, const Pair& p, const M& init) {
00184     typedef implementation<series_pth_root_reg,V> Ser;
00185     return Ser::unsep_root_reg (a, p, init); }
00186 
00187   static inline syntactic
00188   op (const syntactic& a, const syntactic& p) {
00189     return apply ("pth_root_reg", a, p); }
00190 
00191   static inline nat nr_init () { return 1; }
00192 
00193   template<typename M, typename V> static inline Series
00194   def (const Series& me, const Series& a, const Pair& p_b0) {
00195     integer p= first (p_b0); integer b0= second (p_b0);
00196     integer q= as<integer> (* M::get_modulus ());
00197     Series ser_p (coefficients (as<default_p_expansion(M)> (p)));
00198     if (p == 2)
00199       return (a - me[0] - ser_p
00200               * (square (Series (me[0]))
00201                  + lshiftz (square (rshiftz (me, 1)), 2)))
00202         / (M(1) + square (ser_p) * me[0]);
00203 
00204     Series tmp= binpow (Series (M(b0) + ser_p * me[0]), p)
00205       - binpow (Series (M(b0)), p);
00206     tmp= q == p ? rshiftz (tmp, 2): rshiftz (M (q / square (p)) * tmp, 1);
00207     Series ap= a - tmp;
00208     Series c= M (b0) + ser_p * me[0];
00209     return (ap - binpow_no_tangent_normalized (c, me - me[0], p, p))
00210       / binpow (c, p - 1); }
00211 
00212 }; // struct ser_carry_pth_root_reg_op
00213 
00214 template<typename U, typename W>
00215 struct implementation<series_pth_root_reg,U,
00216                       series_carry_p_adic<W> > {
00217 
00218 TMPL static inline Series
00219 unsep_root_reg (const Series& a, const Pair& p) {
00220   return binary_scalar_recursive_series
00221     <ser_carry_pth_root_reg_op> (a, p); }
00222 
00223 TMPL static inline Series
00224 unsep_root_reg (const Series& a, const Pair& p, const M& init) {
00225   return binary_scalar_recursive_series
00226     <ser_carry_pth_root_reg_op> (a, p, init); }
00227 };
00228 
00229 template<typename U, typename W>
00230 struct implementation<series_pth_root,U,series_carry_p_adic<W> > {
00231 
00232 typedef implementation<series_pth_root_reg,U> Reg;
00233 
00234 TMPL static inline Series
00235 unsep_root (const Series& a) {
00236   if (is_exact_zero (a)) return Series (CF(a));
00237   C p= * M::get_modulus ();
00238   if (p == 2) {
00239     ASSERT (a[0] == 1, "positive valuation is not allowed");
00240     ASSERT (a[1] == 0 && a[2] == 0, "no root");
00241     return 1 + lshiftz (Reg::unsep_root_reg (rshiftz (a, 3), Pair (p, 1)), 2);
00242   }
00243   ASSERT (! is_exact_zero (a[0]), "positive valuation is not allowed");
00244   M b0= pth_root (a[0]);
00245   Series ap= a - binpow (Series (b0), p);
00246   ASSERT (ap[0] == 0 && ap[1] == 0, "no root");
00247   return b0 + lshiftz (Reg::unsep_root_reg
00248                        (rshiftz (ap, 2), Pair (p, * b0)), 1); }
00249 
00250 }; // implementation<series_pth_root,U,series_carry_p_adic<W> >
00251 
00252 // wrapper for block operations
00253  
00254 template<typename U,typename W,nat s,typename BV,nat t>
00255 struct implementation<series_pth_root_reg,U,
00256                       series_carry_monoblock<W,s,BV,t> > {
00257 
00258 TMPL static inline Series
00259 unsep_root_reg (const Series& a, const Pair& p) {
00260   return as<Series>
00261       (binary_scalar_recursive_monoblock_series
00262        <ser_carry_pth_root_reg_op,M,W,s,BV,t,Pair>
00263        (as<series<M,W> > (a), p)); }
00264 
00265 TMPL static inline Series
00266 unsep_root_reg (const Series& a, const Pair& p, const M& init) {
00267   return as<Series>
00268       (binary_scalar_recursive_monoblock_series
00269        <ser_carry_pth_root_reg_op,M,W,s,BV,t,Pair>
00270        (as<series<M,W> > (a), p, init)); }
00271 };
00272 #undef Pair
00273 
00274 #undef Series
00275 #undef Series_rep
00276 #undef C
00277 #undef TMPL
00278 
00279 /******************************************************************************
00280 * Default variants
00281 ******************************************************************************/
00282 
00283 #define IMPLEMENTATION_HELPER(C)                                        \
00284   template<typename V,typename W>                                       \
00285   struct series_carry_variant_helper<modular<modulus<C,V>,W> > {        \
00286     typedef series_carry_p_adic<                                        \
00287       series_carry_relaxed<series_carry_naive> > SV; };
00288 
00289 IMPLEMENTATION_HELPER(signed char)
00290 IMPLEMENTATION_HELPER(unsigned char)
00291 IMPLEMENTATION_HELPER(short int)
00292 IMPLEMENTATION_HELPER(unsigned short)
00293 IMPLEMENTATION_HELPER(int)
00294 IMPLEMENTATION_HELPER(unsigned int)
00295 IMPLEMENTATION_HELPER(long int)
00296 IMPLEMENTATION_HELPER(unsigned long int)
00297 IMPLEMENTATION_HELPER(long long int)
00298 IMPLEMENTATION_HELPER(unsigned long long int)
00299 #undef IMPLEMENTATION_HELPER
00300 
00301 template<typename V,typename W>
00302 struct series_carry_variant_helper<modular<modulus<integer,V>,W> > {
00303   typedef series_carry_p_adic<
00304     series_carry_relaxed<series_carry_naive> > SV;
00305 };
00306 
00307 } // namespace mmx
00308 #endif // __MMX_P_ADIC_HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines