algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/matrix_modular_int.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : matrix_modular_int.hpp
00004 * DESCRIPTION: modular matrices over hardware integers
00005 * COPYRIGHT  : (C) 2009  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__MATRIX_MODULAR_INT__HPP
00014 #define __MMX__MATRIX_MODULAR_INT__HPP
00015 #include <numerix/modular_int.hpp>
00016 #include <algebramix/matrix_int.hpp>
00017 #include <algebramix/matrix_double.hpp>
00018 #include <algebramix/matrix_modular.hpp>
00019 
00020 namespace mmx {
00021 #define TMPL template<typename C, typename V1, typename V2>
00022 #define Modulus modulus<C,V1>
00023 #define Modular modular<Modulus,V2>
00024 
00025 /******************************************************************************
00026 * Variant
00027 ******************************************************************************/
00028 
00029 typedef matrix_unrolled<4,matrix_unrolled<4,matrix_naive> >
00030         matrix_unrolled_4_4;
00031 
00032 DEFINE_VARIANT (matrix_modular_int,
00033                 matrix_strassen<
00034                   matrix_threads<
00035                     matrix_unrolled_4_4> >)
00036 
00037 #define DECLARE_HELPER(I,V1)                                            \
00038   template<typename V2, nat m>                                          \
00039   struct matrix_variant_helper<modular<modulus<I,V1>,V2> > {            \
00040     typedef matrix_naive Naive;                                         \
00041     typedef matrix_unrolled<4,matrix_unrolled<2,Naive> > Unrolled;      \
00042     typedef typename Matrix_simd_variant(I) Simd;                       \
00043     typedef matrix_modular_int MV;                                      \
00044   };
00045 
00046 DECLARE_HELPER(signed char, modulus_int_naive<m>)
00047 DECLARE_HELPER(signed char, modulus_int_preinverse<m>)
00048 DECLARE_HELPER(unsigned char, modulus_int_naive<m>)
00049 DECLARE_HELPER(unsigned char, modulus_int_preinverse<m>)
00050 DECLARE_HELPER(short int, modulus_int_naive<m>)
00051 DECLARE_HELPER(short int, modulus_int_preinverse<m>)
00052 DECLARE_HELPER(unsigned short int, modulus_int_naive<m>)
00053 DECLARE_HELPER(unsigned short int, modulus_int_preinverse<m>)
00054 DECLARE_HELPER(int, modulus_int_naive<m>)
00055 DECLARE_HELPER(int, modulus_int_preinverse<m>)
00056 DECLARE_HELPER(unsigned int, modulus_int_naive<m>)
00057 DECLARE_HELPER(unsigned int, modulus_int_preinverse<m>)
00058 DECLARE_HELPER(long int, modulus_int_naive<m>)
00059 DECLARE_HELPER(long int, modulus_int_preinverse<m>)
00060 DECLARE_HELPER(unsigned long int, modulus_int_naive<m>)
00061 DECLARE_HELPER(unsigned long int, modulus_int_preinverse<m>)
00062 DECLARE_HELPER(long long int, modulus_int_naive<m>)
00063 DECLARE_HELPER(long long int, modulus_int_preinverse<m>)
00064 DECLARE_HELPER(unsigned long long int, modulus_int_naive<m>)
00065 DECLARE_HELPER(unsigned long long int, modulus_int_preinverse<m>)
00066 #undef DECLARE_HELPER
00067 
00068 /******************************************************************************
00069 * Encoding and decoding from/to lifting type
00070 ******************************************************************************/
00071 
00072 template<typename D>
00073 struct free_bits_helper {
00074   static const nat value= 8 * sizeof (D);
00075 };
00076 
00077 template<typename V, typename D, typename C, typename V1, typename V2> void
00078 encode_modular_int (D* dest, const Modular* src,
00079                     nat r, nat rr, nat c, nat cc)
00080 {
00081   typedef implementation<matrix_linear,V> Mat;
00082   nat dest_rs= Mat::index (1, 0, r, c);
00083   nat dest_cs= Mat::index (0, 1, r, c);
00084   nat src_rs = Mat::index (1, 0, rr, cc);
00085   nat src_cs = Mat::index (0, 1, rr, cc);
00086   D* dest_row= dest;
00087   const Modular* src_row= src;
00088   for (nat i=0; i<r; i++, dest_row += dest_rs, src_row += src_rs) {
00089     D* dest_col= dest_row;
00090     const Modular* src_col= src_row;
00091     for (nat j=0; j<c; j++, dest_col += dest_cs, src_col += src_cs)
00092       *dest_col= (D) (*(*src_col));
00093   }
00094 }
00095 
00096 template<typename Op, typename V, typename C, typename D,
00097           typename V1, typename V2> void
00098 decode_modular_int (Modular* dest, const D* src,
00099                     nat r, nat rr, nat c, nat cc)
00100 {
00101   typedef implementation<matrix_linear,V> Mat;
00102   typedef typename Op::nomul_op Set;
00103   C p = *Modular::get_modulus ();
00104   nat dest_rs= Mat::index (1, 0, rr, cc);
00105   nat dest_cs= Mat::index (0, 1, rr, cc);
00106   nat src_rs = Mat::index (1, 0, r, c);
00107   nat src_cs = Mat::index (0, 1, r, c);
00108   Modular* dest_row= dest;
00109   const D* src_row= src;
00110   for (nat i=0; i<r; i++, dest_row += dest_rs, src_row += src_rs) {
00111     Modular* dest_col= dest_row;
00112     const D* src_col= src_row;
00113     for (nat j=0; j<c; j++, dest_col += dest_cs, src_col += src_cs)
00114       Set::set_op (*dest_col, Modular ((*src_col) % p, true));
00115   }
00116 }
00117 
00118 #if defined(NUMERIX_ENABLE_SIMD)\
00119  && defined(ALGEBRAMIX_ENABLE_SIMD)\
00120  && defined(__SSE2__)
00121 // double are faster than int's on usual platforms supporting SSE2
00122 template<typename Op, typename V,
00123          typename C, typename V1, typename V2> void
00124 decode_modular_int (Modular* dest, const double* src,
00125                     nat r, nat rr, nat c, nat cc)
00126 {
00127   typedef implementation<matrix_linear,V> Mat;
00128   typedef typename Op::nomul_op Set;
00129   uint32_t p = (uint32_t) *Modular::get_modulus ();
00130   nat dest_rs= Mat::index (1, 0, rr, cc);
00131   nat dest_cs= Mat::index (0, 1, rr, cc);
00132   nat src_rs = Mat::index (1, 0, r, c);
00133   nat src_cs = Mat::index (0, 1, r, c);
00134   Modular* dest_row= dest;
00135   const double* src_row= src;
00136   for (nat i=0; i<r; i++, dest_row += dest_rs, src_row += src_rs) {
00137     Modular* dest_col= dest_row;
00138     const double* src_col= src_row;
00139     for (nat j=0; j<c; j++, dest_col += dest_cs, src_col += src_cs)
00140       Set::set_op (*dest_col, Modular (((uint64_t) (*src_col)) % p, true));
00141   }
00142 }
00143 STMPL
00144 struct free_bits_helper<double> {
00145   static const nat value= 53;
00146 };
00147 #endif // __SSE2__
00148 
00149 
00150 template<typename V>
00151 struct implementation<matrix_multiply_base,V,matrix_modular_int>:
00152   public implementation<matrix_linear,V>
00153 {
00154   typedef matrix_strassen<matrix_threads<matrix_unrolled_4_4> > W;
00155   typedef implementation<matrix_multiply,W> Fallback;
00156   typedef implementation<matrix_linear,W> Mat;
00157 private:
00158 
00159 #if defined(NUMERIX_ENABLE_SIMD)\
00160  && defined(ALGEBRAMIX_ENABLE_SIMD)\
00161  && defined(__SSE2__)
00162 template<nat s>
00163 struct lifting_int_with_size_at_least_helper {
00164   template<bool b, typename T, typename E>
00165   struct if_helper { typedef T ret; };
00166   template<typename T, typename E>
00167   struct if_helper<false,T,E> { typedef E ret; };
00168   typedef
00169     typename if_helper<8*sizeof(short unsigned int) >= s, short unsigned int,
00170     typename if_helper<53 >= s, double,
00171       long long unsigned int>::ret >::ret type;
00172 };
00173 
00174 #else
00175 template<nat s>
00176 struct lifting_int_with_size_at_least_helper {
00177   template<bool b, typename T, typename E>
00178   struct if_helper { typedef T ret; };
00179   template<typename T, typename E>
00180   struct if_helper<false,T,E> { typedef E ret; };
00181   typedef
00182     typename if_helper<8*sizeof(unsigned char)>=s, unsigned char,
00183     typename if_helper<8*sizeof(short unsigned int)>=s, short unsigned int,
00184     typename if_helper<8*sizeof(unsigned int)>=s, unsigned int,
00185     typename if_helper<8*sizeof(long unsigned int)>=s, long unsigned int,
00186     long long unsigned int>::ret >::ret >::ret >::ret type ;
00187 };
00188 #endif
00189   
00190 template<typename Op, typename C, typename V1, typename V2>
00191 static inline void
00192 _mul_int (Modular* d, const Modular* s1, const Modular* s2,
00193          nat r, nat rr, nat l, nat ll, nat c, nat cc)
00194   {
00195     static const nat modulus_size= V1::template maximum_size_helper<C>::value;
00196     // 2 free bits are required
00197     static const nat required_size= (modulus_size << 1) + 2;
00198     typedef typename
00199       lifting_int_with_size_at_least_helper<required_size>::type D;
00200     // free bits in type D
00201     static const nat possible_free_bits=
00202       free_bits_helper<D>::value - (modulus_size << 1);
00203     static const nat free_bits= possible_free_bits >= 16
00204                                   ? 16 : possible_free_bits;
00205     const nat ul= MMX_SAFE_LEFT_SHIFT_INT(nat,1,free_bits);
00206     typedef typename Matrix_variant(D) W;
00207     typedef implementation<matrix_multiply,W> Mat_D;
00208 
00209     if (free_bits == 0) {
00210       Fallback::template mul<Op> (d, s1, s2, r, rr, l, ll, c, cc);
00211     }
00212     else if (l <= ul) {
00213       nat len_1= aligned_size<D,W> (r * l);
00214       nat len_2= aligned_size<D,W> (l * c);
00215       nat len_d= aligned_size<D,W> (r * c);
00216       nat spc = len_1 + len_2 + len_d;
00217       D* x1= mmx_new<D> (spc);
00218       D* x2= x1 + len_1;
00219       D* xd= x2 + len_2;
00220       encode_modular_int<W> (x1, s1, r, rr, l, ll);
00221       encode_modular_int<W> (x2, s2, l, ll, c, cc);
00222       Mat_D::template mul<Op> (xd, x1, x2, r, r, l, l, c, c);
00223       decode_modular_int<Op,W> (d, xd, r, rr, c, cc);
00224       mmx_delete<D> (x1, spc);
00225     }
00226     else {
00227       typedef typename Op::acc_op Acc;
00228       const nat ur= 32;
00229       const nat uc= 32;
00230 
00231       nat nr= (r + ur - 1) / ur;
00232       nat nl= (l + ul - 1) / ul;
00233       nat nc= (c + uc - 1) / uc;
00234       for (nat ir=0; ir<nr; ir++)
00235         for (nat ic=0; ic<nc; ic++) {
00236           nat il=0;
00237           for (; il<1; il++) {
00238             mul<Op > (d  + Mat::index (ir*ur, ic*uc, rr, cc),
00239                       s1 + Mat::index (ir*ur, il*ul, rr, ll),
00240                       s2 + Mat::index (il*ul, ic*uc, ll, cc),
00241                       min (ur, r - ir*ur), rr,
00242                       min (ul, l - il*ul), ll,
00243                       min (uc, c - ic*uc), cc);
00244           }
00245           for (; il<nl; il++) {
00246             mul<Acc> (d  + Mat::index (ir*ur, ic*uc, rr, cc),
00247                       s1 + Mat::index (ir*ur, il*ul, rr, ll),
00248                       s2 + Mat::index (il*ul, ic*uc, ll, cc),
00249                       min (ur, r - ir*ur), rr,
00250                       min (ul, l - il*ul), ll,
00251                       min (uc, c - ic*uc), cc);
00252           }
00253         }
00254     }
00255   }
00256 
00257 public:
00258 
00259 template<typename Op, typename C, typename V1, typename V2>
00260 static inline void
00261 mul (Modular* d, const Modular* s1, const Modular* s2,
00262      nat r, nat rr, nat l, nat ll, nat c, nat cc)
00263   {
00264     _mul_int<Op> (d, s1, s2, r, rr, l, ll, c, cc);
00265   }
00266 
00267 }; // implementation<matrix_multiply_base,V,matrix_modular_int<MV> >
00268 
00269 #undef TMPL
00270 #undef Modulus
00271 #undef Modular
00272 } // namespace mmx
00273 
00274 #endif //__MMX__MATRIX_MODULAR_INT__HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines