numerix_doc 0.4
|
00001 00002 /****************************************************************************** 00003 * MODULE : modular.hpp 00004 * DESCRIPTION: modular arithmetic 00005 * COPYRIGHT : (C) 2008 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__MODULAR__HPP 00014 #define __MMX__MODULAR__HPP 00015 #include <basix/generic.hpp> 00016 #include <basix/wrap.hpp> 00017 #include <basix/operators.hpp> 00018 #include <basix/int.hpp> 00019 #include <numerix/integer.hpp> 00020 #include <numerix/modulus.hpp> 00021 00022 namespace mmx { 00023 #define Modular_variant(M) modular_variant_helper<M>::MV 00024 #define TMPL_DEF \ 00025 template<typename M, typename V= typename Modular_variant(M)> 00026 #define TMPL template<typename M, typename V> 00027 #define Modulus modulus<C,V> 00028 #define Modular modular<M,V> 00029 00030 template<typename M> 00031 struct modular_variant_helper; 00032 TMPL class modular; 00033 00034 /****************************************************************************** 00035 * Variant 00036 ******************************************************************************/ 00037 00038 // One modulus is attached to each modular 00039 struct modular_local { 00040 template<typename M> 00041 class modulus_storage { 00042 static inline M& dyn_modulus () { 00043 static M modulus = M (); 00044 return modulus; } 00045 public: 00046 static inline void set_modulus (const M& p) { 00047 if (! is_exact_zero (*p)) dyn_modulus () = p; } 00048 static inline M get_modulus () { return dyn_modulus (); } 00049 }; 00050 }; 00051 00052 // Global storage of the modulus 00053 struct modular_global { 00054 template<typename M> 00055 class modulus_storage { 00056 static inline M& dyn_modulus () { 00057 static M modulus = M (); 00058 return modulus; } 00059 public: 00060 static inline void set_modulus (const M& p) { dyn_modulus () = p; } 00061 static inline M get_modulus () { return dyn_modulus (); } 00062 }; 00063 }; 00064 00065 // Fixed modulus 00066 template<typename C, C p> 00067 struct modular_fixed { 00068 template<typename M> 00069 class modulus_storage { 00070 static inline M& dyn_modulus () { 00071 static fixed_value <C, p> _p; 00072 static M modulus = M (_p); 00073 return modulus; } 00074 public: 00075 static inline void set_modulus (const M& q) { 00076 ASSERT (q == dyn_modulus (), 00077 "modular_fixed: can not change the modulus"); 00078 } 00079 static inline M get_modulus () { return dyn_modulus (); } 00080 }; 00081 }; 00082 00083 /****************************************************************************** 00084 * Variant helper, default storage of the modulus is "global" 00085 ******************************************************************************/ 00086 00087 template<typename M> 00088 struct modular_variant_helper { 00089 typedef modular_global MV; }; 00090 00091 /****************************************************************************** 00092 * General modulars 00093 ******************************************************************************/ 00094 00095 TMPL_DEF 00096 class modular { 00097 MMX_ALLOCATORS 00098 public: 00099 typedef M modulus; 00100 typedef typename M::base C; 00101 typedef typename V::template modulus_storage<M> S; 00102 00103 C rep; 00104 static inline M get_modulus () { return S::get_modulus (); } 00105 static inline void set_modulus (const M& p) { S::set_modulus (p); } 00106 00107 inline C operator * () const { 00108 C dest; 00109 decode_mod (dest, rep, get_modulus ()); 00110 return dest; } 00111 00112 inline modular () { encode_mod (rep, C (), get_modulus ()); } 00113 00114 inline modular (const Modular& s) : rep (s.rep) {} 00115 00116 inline modular (const C& a, bool reduced) { 00117 if (reduced) rep = a; 00118 else encode_mod (rep, a, get_modulus ()); } 00119 00120 inline modular (const C& s, const M& p, bool reduced=false) { 00121 VERIFY (p == get_modulus (), "wrong modulus"); 00122 if (reduced) rep= s; 00123 else encode_mod (rep, s, p); } 00124 00125 template<typename O> 00126 inline modular (const O& a) { 00127 encode_mod (rep, as<C> (a), get_modulus ()); } 00128 00129 inline Modular& operator = (const Modular& a) { 00130 rep = a.rep; 00131 return *this; } 00132 00133 inline bool operator == (const Modular& a) const { 00134 return rep == a.rep; } 00135 00136 inline bool operator != (const Modular& a) const { 00137 return rep != a.rep; } 00138 }; 00139 00140 STYPE_TO_TYPE(TMPL,lift_type,Modular,typename Modular::C); 00141 00142 TMPL inline typename Modular::C 00143 lift (const Modular& x) { return *x; } 00144 00145 TMPL 00146 struct project_helper<Modular > { 00147 template<typename C> static inline Modular 00148 op (const C& x) { return Modular (x); } 00149 }; 00150 00151 TMPL inline M get_modulus (const Modular& x) { 00152 (void) x; return Modular::get_modulus (); } 00153 TMPL inline void set_modulus (Modular& x, const M& p) { 00154 (void) x; Modular::set_modulus (p); } 00155 00156 template<typename TM, typename TV, typename SM, typename SV> 00157 struct as_helper<modular<TM,TV>,modular<SM,SV> > { 00158 static inline modular<TM,TV> 00159 cv (const modular<SM,SV>& p) { return modular<TM,TV> (*p); } 00160 }; 00161 00162 template<typename C, typename V, typename W> 00163 struct as_helper<C,modular<modulus<C,V>,W> > { 00164 static inline C 00165 cv (const modular<modulus<C,V>,W>& p) { return *p; } 00166 }; 00167 00168 template<typename C, typename V, typename W> 00169 struct as_helper<generic, modular<modulus<C,V>,W> > { 00170 static inline generic cv (const modular<modulus<C,V>,W> & x) { 00171 return new generic_concrete_rep<modular<modulus<C,V>,W> > (x); } 00172 }; 00173 00174 WRAP_WRAPPED_IMPL(TMPL inline,Modular) 00175 00176 /****************************************************************************** 00177 * Arithmetic 00178 ******************************************************************************/ 00179 00180 TMPL inline Modular& 00181 operator += (Modular& dest, const Modular& s) { 00182 add_mod (dest.rep, s.rep, Modular::get_modulus ()); 00183 return dest; } 00184 00185 TMPL inline Modular& 00186 operator -= (Modular& dest, const Modular& s) { 00187 sub_mod (dest.rep, s.rep, Modular::get_modulus ()); 00188 return dest; } 00189 00190 TMPL inline Modular& 00191 operator *= (Modular& dest, const Modular& s) { 00192 mul_mod (dest.rep, s.rep, Modular::get_modulus ()); 00193 return dest; } 00194 00195 TMPL inline Modular& 00196 operator /= (Modular& dest, const Modular& s) { 00197 div_mod (dest.rep, s.rep, Modular::get_modulus ()); 00198 return dest; } 00199 00200 TMPL inline Modular 00201 operator + (const Modular& a, const Modular& b) { 00202 Modular c; 00203 add_mod (c.rep, a.rep, b.rep, Modular::get_modulus ()); 00204 return c; } 00205 00206 TMPL inline Modular 00207 operator + (const Modular& a, const typename M::base& b) { 00208 return a + Modular (b); } 00209 00210 TMPL inline Modular 00211 operator + (const typename M::base& a, const Modular& b) { 00212 return Modular (a) + b; } 00213 00214 TMPL inline Modular 00215 operator - (const Modular& a) { 00216 Modular c; 00217 neg_mod (c.rep, a.rep, Modular::get_modulus ()); 00218 return c; } 00219 00220 TMPL inline Modular 00221 operator - (const Modular& a, const Modular& b) { 00222 Modular c; 00223 sub_mod (c.rep, a.rep, b.rep, Modular::get_modulus ()); 00224 return c; } 00225 00226 TMPL inline Modular 00227 operator - (const Modular& a, const typename M::base& b) { 00228 return a - Modular (b); } 00229 00230 TMPL inline Modular 00231 operator - (const typename M::base& a, const Modular& b) { 00232 return Modular (a) - b; } 00233 00234 TMPL inline Modular 00235 operator * (const Modular& a, const Modular& b) { 00236 Modular c; 00237 mul_mod (c.rep, a.rep, b.rep, Modular::get_modulus ()); 00238 return c; } 00239 00240 TMPL inline Modular 00241 operator * (const Modular& a, const typename M::base& b) { 00242 return a * Modular (b); } 00243 00244 TMPL inline Modular 00245 operator * (const typename M::base& a, const Modular& b) { 00246 return Modular (a) * b; } 00247 00248 TMPL inline Modular 00249 operator / (const Modular& a, const Modular& b) { 00250 Modular c; 00251 div_mod (c.rep, a.rep, b.rep, Modular::get_modulus ()); 00252 return c; } 00253 00254 TMPL inline Modular 00255 operator / (const Modular& a, const typename M::base& b) { 00256 return a / Modular (b); } 00257 00258 TMPL inline Modular 00259 operator / (const typename M::base& a, const Modular& b) { 00260 return Modular (a) / b; } 00261 00262 TMPL inline Modular 00263 invert (const Modular& a) { 00264 Modular c; 00265 inv_mod (c.rep, a.rep, Modular::get_modulus ()); 00266 return c; } 00267 00268 /****************************************************************************** 00269 * Gcd & lcm routine 00270 ******************************************************************************/ 00271 00272 TMPL inline Modular 00273 gcd (const Modular& a, const Modular& b) { 00274 if (a == 0) return b; 00275 return a; } 00276 00277 TMPL inline Modular 00278 lcm (const Modular& a, const Modular& b) { 00279 return a * b; } 00280 00281 /****************************************************************************** 00282 * Output routine 00283 ******************************************************************************/ 00284 00285 WRAP_PRINT_IMPL(TMPL inline,Modular) 00286 00287 /****************************************************************************** 00288 * Syntactic sugar 00289 ******************************************************************************/ 00290 00291 ARITH_INT_SUGAR(TMPL,Modular) 00292 POOR_MAN_SQRT_SUGAR(TMPL,Modular) 00293 POOR_MAN_ELEMENTARY_SUGAR(TMPL,Modular) 00294 00295 #undef TMPL_DEF 00296 #undef TMPL 00297 #undef Modulus 00298 #undef Modular 00299 00300 /****************************************************************************** 00301 * Modulars with local moduli 00302 ******************************************************************************/ 00303 00304 #define TMPL template<typename M> 00305 #define Modulus modulus<C,V> 00306 #define Modular modular<M,modular_local> 00307 00308 TMPL 00309 class modular<M, modular_local> { 00310 MMX_ALLOCATORS 00311 public: 00312 typedef M modulus; 00313 typedef modular_local V; 00314 typedef typename M::base C; 00315 typedef typename V::template modulus_storage<M> S; 00316 00317 C rep; 00318 M mod; 00319 static inline M get_modulus () { return S::get_modulus (); } 00320 static inline void set_modulus (const M& p) { S::set_modulus (p); } 00321 00322 inline M get_local_modulus () const { return mod; } 00323 inline void set_local_modulus (const M& p) { mod= p; S::set_modulus (p); } 00324 00325 inline C operator * () const { 00326 C dest; 00327 decode_mod (dest, rep, mod); 00328 return dest; } 00329 00330 inline modular () { 00331 mod= get_modulus (); 00332 encode_mod (rep, C (), mod); } 00333 00334 inline modular (const Modular& s) : rep (s.rep), mod (s.mod) {} 00335 00336 inline modular (const C& s, bool reduced) { 00337 mod= get_modulus (); 00338 if (reduced) rep= s; 00339 else encode_mod (rep, s, mod); } 00340 00341 inline modular (const C& s, const M& p, bool reduced=false) { 00342 mod= p; 00343 set_modulus (p); 00344 if (reduced) rep= s; 00345 else encode_mod (rep, s, mod); } 00346 00347 template<typename O> 00348 inline modular (const O& a) { 00349 mod= get_modulus (); 00350 encode_mod (rep, as<C> (a), mod); } 00351 00352 inline Modular& operator = (const Modular& a) { 00353 rep = a.rep; 00354 mod = a.mod; 00355 return *this; } 00356 00357 inline bool operator == (const Modular& a) const { 00358 if (mod == a.mod) return rep == a.rep; 00359 if (mod == C(0)) return Modular (* (*this), a.mod) == a; 00360 if (a.mod == C(0)) return Modular (* a, mod) == *this; 00361 return false; } 00362 00363 inline bool operator != (const Modular& a) const { 00364 if (mod == a.mod) return rep != a.rep; 00365 if (mod == C(0)) return Modular (* (*this), a.mod) != a; 00366 if (a.mod == C(0)) return Modular (* a, mod) != *this; 00367 return true; } 00368 }; 00369 00370 template<typename M> inline M 00371 get_modulus (const modular<M, modular_local>& x) { 00372 return x.get_local_modulus (); } 00373 00374 template<typename M> inline void 00375 set_modulus (Modular& x, const M& p) { 00376 x.set_local_modulus (p); } 00377 00378 template<typename TM, typename SM, typename SV> 00379 struct as_helper<modular<TM,modular_local>,modular<SM,SV> > { 00380 static inline modular<TM,modular_local> 00381 cv (const modular<SM,SV>& p) { 00382 return modular<TM,modular_local> (* p, get_modulus (p)); } 00383 }; 00384 00385 TMPL nat 00386 hash (const Modular& c) { 00387 nat h= hash (*c); 00388 return (h<<1) ^ (h<<5) ^ (h>>29) ^ hash (get_modulus (c)); } 00389 00390 TMPL nat 00391 exact_hash (const Modular& c) { 00392 nat h= exact_hash (*c); 00393 return (h<<1) ^ (h<<5) ^ (h>>29) ^ exact_hash (get_modulus (c)); } 00394 00395 TMPL nat hard_hash (const Modular& c) { 00396 nat h= hard_hash (*c); 00397 return (h<<1) ^ (h<<5) ^ (h>>29) ^ hard_hash (get_modulus (c)); } 00398 00399 TMPL bool exact_eq (const Modular& c1, const Modular& c2) { 00400 return exact_eq (*c1, *c2) && 00401 exact_eq (get_modulus (c1), get_modulus (c2)); } 00402 00403 TMPL bool exact_neq (const Modular& c1, const Modular& c2) { 00404 return ! exact_eq (c1, c2); } 00405 00406 TMPL bool hard_eq (const Modular& c1, const Modular& c2) { 00407 return hard_eq (*c1, *c2) && 00408 hard_eq (get_modulus (c1), get_modulus (c2)); } 00409 00410 TMPL bool hard_neq (const Modular& c1, const Modular& c2) { 00411 return ! hard_eq (c1, c2); } 00412 00413 TMPL inline Modular& 00414 operator += (Modular& dest, const Modular& s) { 00415 M md= get_modulus (dest), ms= get_modulus (s); 00416 M mod= md == 0 ? ms : md; 00417 VERIFY (md == 0 || ms == 0 || md == ms, "incompatible moduli"); 00418 add_mod (dest.rep, s.rep, mod); 00419 return dest; } 00420 00421 TMPL inline Modular& 00422 operator -= (Modular& dest, const Modular& s) { 00423 M md= get_modulus (dest), ms= get_modulus (s); 00424 M mod= md == 0 ? ms : md; 00425 VERIFY (md == 0 || ms == 0 || md == ms, "incompatible moduli"); 00426 sub_mod (dest.rep, s.rep, mod); 00427 return dest; } 00428 00429 TMPL inline Modular& 00430 operator *= (Modular& dest, const Modular& s) { 00431 M md= get_modulus (dest), ms= get_modulus (s); 00432 M mod= md == 0 ? ms : md; 00433 VERIFY (md == 0 || ms == 0 || md == ms, "incompatible moduli"); 00434 mul_mod (dest.rep, s.rep, mod); 00435 return dest; } 00436 00437 TMPL inline Modular& 00438 operator /= (Modular& dest, const Modular& s) { 00439 M md= get_modulus (dest), ms= get_modulus (s); 00440 M mod= md == 0 ? ms : md; 00441 VERIFY (md == 0 || ms == 0 || md == ms, "incompatible moduli"); 00442 div_mod (dest.rep, s.rep, mod); 00443 return dest; } 00444 00445 TMPL inline Modular 00446 operator + (const Modular& a, const Modular& b) { 00447 M ma= get_modulus (a), mb= get_modulus (b); 00448 M mod= ma == 0 ? mb : ma; 00449 VERIFY (ma == 0 || mb == 0 || ma == mb, "incompatible moduli"); 00450 Modular c; 00451 add_mod (c.rep, a.rep, b.rep, mod); 00452 c.mod= mod; 00453 return c; } 00454 00455 TMPL inline Modular 00456 operator - (const Modular& a) { 00457 M mod= get_modulus (a); 00458 Modular c; 00459 neg_mod (c.rep, a.rep, mod); 00460 c.mod= mod; 00461 return c; } 00462 00463 TMPL inline Modular 00464 operator - (const Modular& a, const Modular& b) { 00465 M ma= get_modulus (a), mb= get_modulus (b); 00466 M mod= ma == 0 ? mb : ma; 00467 VERIFY (ma == 0 || mb == 0 || ma == mb, "incompatible moduli"); 00468 Modular c; 00469 sub_mod (c.rep, a.rep, b.rep, mod); 00470 c.mod= mod; 00471 return c; } 00472 00473 TMPL inline Modular 00474 operator * (const Modular& a, const Modular& b) { 00475 M ma= get_modulus (a), mb= get_modulus (b); 00476 M mod= ma == 0 ? mb : ma; 00477 VERIFY (ma == 0 || mb == 0 || ma == mb, "incompatible moduli"); 00478 Modular c; 00479 mul_mod (c.rep, a.rep, b.rep, mod); 00480 c.mod= mod; 00481 return c; } 00482 00483 TMPL inline Modular 00484 operator / (const Modular& a, const Modular& b) { 00485 M ma= get_modulus (a), mb= get_modulus (b); 00486 M mod= ma == 0 ? mb : ma; 00487 VERIFY (ma == 0 || mb == 0 || ma == mb, "incompatible moduli"); 00488 Modular c; 00489 div_mod (c.rep, a.rep, b.rep, mod); 00490 c.mod= mod; 00491 return c; } 00492 00493 TMPL inline Modular 00494 invert (const Modular& a) { 00495 M mod= get_modulus (a); 00496 Modular c; 00497 inv_mod (c.rep, a.rep, mod); 00498 c.mod= mod; 00499 return c; } 00500 00501 /****************************************************************************** 00502 * Extras for glue 00503 ******************************************************************************/ 00504 00505 #define mmx_modular(R) modular<modulus<R >,modular_local> 00506 00507 #undef TMPL 00508 #undef Modulus 00509 #undef Modular 00510 } // namespace mmx 00511 #endif //__MMX__MODULAR__HPP