algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : crt_integer.hpp 00004 * DESCRIPTION: Subroutines for efficient Chinese remaindering 00005 * COPYRIGHT : (C) 2008 Joris van der Hoeven 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_CRT_INTEGER_HPP 00014 #define __MMX_CRT_INTEGER_HPP 00015 #include <numerix/modular_integer.hpp> 00016 #include <algebramix/crt_naive.hpp> 00017 #include <algebramix/crt_dicho.hpp> 00018 #include <algebramix/crt_blocks.hpp> 00019 #include <algebramix/crt_int.hpp> 00020 00021 namespace mmx { 00022 00023 /****************************************************************************** 00024 * Naive variant 00025 ******************************************************************************/ 00026 00027 DEFINE_VARIANT(crt_naive_integer,crt_signed<crt_naive>) 00028 00029 #if defined(__GNU_MP__) 00030 template<typename V> 00031 struct implementation<crt_project,V,crt_naive_integer> : 00032 public implementation<crt_project,crt_signed<crt_naive> > 00033 { 00034 template<typename C, typename I, typename W> static inline I 00035 mod (const C& a, const modulus<I,W>& p) { 00036 static integer r; 00037 return (I) mpz_fdiv_r_ui (*r, *a, *p); } 00038 00039 template<typename C, typename W> static inline C 00040 mod (const C& a, const modulus<integer,W>& p) { 00041 return rem (a, *p); } 00042 }; 00043 #endif 00044 00045 STMPL 00046 struct crt_naive_variant_helper<integer> { 00047 typedef crt_naive_integer CV; }; 00048 00049 DEFINE_VARIANT(crt_dicho_integer,crt_dicho<crt_naive_integer>) 00050 00051 STMPL 00052 struct crt_dicho_variant_helper<integer> { 00053 typedef crt_dicho_integer CV; }; 00054 00055 /****************************************************************************** 00056 * Default parameters 00057 ******************************************************************************/ 00058 00059 STMPL 00060 struct std_crt_naive<integer> { 00061 typedef integer base; 00062 typedef int modulus_base; 00063 typedef modulus_int_preinverse<8*sizeof(int)-9> modulus_base_variant; 00064 typedef Modulus_variant(integer) modulus_variant; 00065 }; 00066 00067 STMPL 00068 struct std_crt_dicho<integer> { 00069 typedef integer base; 00070 typedef integer modulus_base; 00071 typedef Modulus_variant(integer) modulus_base_variant; 00072 typedef Modulus_variant(integer) modulus_variant; 00073 }; 00074 00075 /****************************************************************************** 00076 * Covering 00077 ******************************************************************************/ 00078 00079 template<typename M, typename W> 00080 struct moduli_helper<integer,M,W> : 00081 moduli_signed_integer_helper<integer,M,W> {}; 00082 00083 template <typename M, nat t> 00084 struct moduli_helper<integer, M, fft_prime_sequence_int<t> > { 00085 template<typename V> static bool 00086 covering (vector<M, V>& v, nat s) { 00087 static coprime_moduli_sequence<M, fft_prime_sequence_int<t> > seq; 00088 if (t < 2) { 00089 v= vector<M, V> (); 00090 return s == 0; 00091 } 00092 nat n= (s + t) / (t - 1); 00093 v= range (seq, 0, n); 00094 return N(v) == n; } 00095 }; 00096 00097 /****************************************************************************** 00098 * Special variant for GMP 00099 ******************************************************************************/ 00100 00101 #if defined(__GNU_MP__) 00102 #define C integer 00103 00104 vector<mp_limb_t> mpz_setup_crt (const vector<mp_limb_t>& mods); 00105 // Build auxiliary conversion information for the moduli p[i] 00106 00107 integer mpz_moduli_product (const vector<mp_limb_t>& mods, 00108 const vector<mp_limb_t>& cv); 00109 // Product of all the moduli 00110 00111 void mpz_encode_crt (mp_limb_t* dest, const integer& src, 00112 const vector<mp_limb_t>& mods, 00113 const vector<mp_limb_t>& cv); 00114 // Compute src mod p[i] for each of the moduli p[i] 00115 00116 integer mpz_decode_crt (const mp_limb_t* src, 00117 const vector<mp_limb_t>& mods, 00118 const vector<mp_limb_t>& cv); 00119 // Reconstruct the integer from its remainders w.r.t. p[i] for each i 00120 00121 template<typename I> 00122 struct crt_gmp_transformer { 00123 typedef C base; 00124 typedef int modulus_base; 00125 typedef modulus_int_preinverse<23> modulus_base_variant; 00126 typedef typename Modulus_variant(C) modulus_variant; 00127 private: 00128 typedef modulus<modulus_base,modulus_base_variant> M; 00129 00130 nat n; 00131 vector<mp_limb_t> mods; 00132 vector<mp_limb_t> cv; 00133 modulus<C> P; 00134 mp_limb_t* aux; 00135 00136 public: 00137 inline void setup_inverse () {} 00138 00139 inline crt_gmp_transformer (const vector<M>& p, bool lazy=true) { 00140 (void) lazy; 00141 ASSERT (sizeof (I) <= sizeof (mp_limb_t), "moduli too large"); 00142 n= N(p); mods= vector<mp_limb_t> ((mp_limb_t) 0, n); 00143 for (nat i= 0; i < n; i++) mods[i]= (mp_limb_t) * p[i]; 00144 cv= mpz_setup_crt (mods); 00145 P= mpz_moduli_product (mods, cv); 00146 if (sizeof (I) != sizeof (mp_limb_t)) 00147 aux= mmx_new<mp_limb_t> (n); } 00148 00149 inline ~crt_gmp_transformer () { 00150 if (sizeof (I) != sizeof (mp_limb_t)) 00151 mmx_delete<mp_limb_t> (aux, n); } 00152 00153 inline M operator[] (nat i) const { 00154 VERIFY (i < n, "index out of range"); 00155 return M (mods[i]); } 00156 00157 inline nat size () const { 00158 return n; } 00159 00160 inline modulus<C> product () const { 00161 return P; } 00162 00163 inline C comodulus (nat i) { 00164 VERIFY (i < n, "index out of range"); 00165 return (* P) / mods[i]; } 00166 00167 inline void direct_transform (I* c, const C& a) const { 00168 mp_limb_t* tmp= sizeof (I) == sizeof (mp_limb_t) ? 00169 (mp_limb_t*) (void*) c : aux; 00170 mpz_encode_crt (tmp, a, mods, cv); 00171 if (sizeof (I) != sizeof (mp_limb_t)) 00172 for (nat i= 0; i < n; i++) c[i]= (I) tmp[i]; } 00173 00174 inline void inverse_transform (C& a, const I* c) { 00175 mp_limb_t* tmp; 00176 if (sizeof (I) == sizeof (mp_limb_t)) 00177 tmp= (mp_limb_t*) (void*) c; 00178 else { 00179 for (nat i= 0; i < n; i++) aux[i]= (mp_limb_t) c[i]; 00180 tmp= aux; 00181 } 00182 a= mpz_decode_crt (tmp, mods, cv); } 00183 }; 00184 00185 template<typename I> inline nat 00186 N (const crt_gmp_transformer<I>& crter) { 00187 return crter.size (); 00188 } 00189 00190 #undef C 00191 #endif // __GNU_MP__ 00192 00193 } // namespace mmx 00194 #endif // __MMX_CRT_INTEGER_HPP