00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __MMX_MODULAR_POLYNOMIAL_HPP
00014 #define __MMX_MODULAR_POLYNOMIAL_HPP
00015 #include <numerix/modular.hpp>
00016 #include <algebramix/polynomial.hpp>
00017 #include <algebramix/quotient_polynomial.hpp>
00018
00019 namespace mmx {
00020
00021 #define TMPL template<typename C, typename M>
00022 #define Polynomial polynomial<C,V>
00023
00024
00025
00026
00027
00028 template<typename V>
00029 struct modulus_polynomial_inv_naive : public V {
00030
00031 TMPL static inline bool
00032 is_invertible_mod (const C& s, const M& m) {
00033 return abs (gcd (s, m.p)) == 1; }
00034
00035 TMPL static inline void
00036 inv_mod (C& a, const M& m) {
00037 if (m.p == 0) {
00038 if (deg (a) == 0)
00039 a= 1 / a [0];
00040 else
00041 ERROR ("inv_mod: argument is not invertible");
00042 }
00043 a = invert_modulo (a, m.p);
00044 if (a == 0)
00045 ERROR ("inv_mod: argument is not invertible"); }
00046
00047 TMPL static inline void
00048 inv_mod (C& dest, const C& s, const M& m) {
00049 dest = s;
00050 inv_mod (dest, m); }
00051 };
00052
00053 struct modulus_polynomial_naive:
00054 public modulus_encoding_naive<
00055 modulus_div_naive<
00056 modulus_polynomial_inv_naive<
00057 modulus_mul_naive<
00058 modulus_add_naive<
00059 modulus_reduction_naive<
00060 modulus_normalization_naive> > > > > > {};
00061
00062
00063
00064
00065
00066 template<typename C, typename V>
00067 struct modulus_variant_helper<polynomial<C,V> > {
00068 typedef modulus_polynomial_naive MV; };
00069
00070
00071
00072
00073
00074 template<typename C, typename PV, typename MV, typename MW> inline syntactic
00075 flatten (const modular<modulus<polynomial<C, PV>, MW>, MV>& c) {
00076 generic x= polynomial<C, PV>::get_variable_name ();
00077 generic a= gen (GEN_PRIME, x);
00078 if (x == "x") a= "a";
00079 if (x == "y") a= "b";
00080 if (x == "z") a= "c";
00081 return flatten (*c, as_syntactic (a));
00082 }
00083
00084 template<typename C, typename PV, typename MV> inline syntactic
00085 flatten (const modulus<polynomial<C, PV>, MV>& c) {
00086 generic x= polynomial<C, PV>::get_variable_name ();
00087 generic a= gen (GEN_PRIME, x);
00088 if (x == "x") a= "a";
00089 if (x == "y") a= "b";
00090 if (x == "z") a= "c";
00091 return flatten (*c, as_syntactic (a));
00092 }
00093
00094
00095
00096
00097
00098 template<typename X>
00099 struct modulus_polynomial_reduction_preinverse : public X {
00100 template<typename C,typename V, typename M> static inline void
00101 reduce_mod (Polynomial& dest, const M& m) {
00102 if (is_exact_zero (m.p)) return;
00103 int d= degree (m.p);
00104 if (deg (dest) < (d << 1)) {
00105 Polynomial carry;
00106 carry = rshiftz (rshiftz (dest, d) * m.q, d);
00107 dest = range (dest - carry * m.p, 0, d);
00108 }
00109 else dest= rem (dest, m.p); }
00110
00111 template<typename C,typename V, typename M> static inline void
00112 reduce_mod (Polynomial& dest, const M& m, Polynomial& carry) {
00113 int d= degree (m.p);
00114 if (is_exact_zero (m.p) != 0)
00115 carry= 0;
00116 else if (deg (dest) < (d << 1)) {
00117 carry = rshiftz (rshiftz (dest, d) * m.q, d);
00118 dest = range (dest - carry * m.p, 0, d);
00119 }
00120 else {
00121 carry= quo (dest, m.p);
00122 dest = rem (dest, m.p); } }
00123
00124 template<typename C,typename V, typename M> static inline void
00125 reduce_mod (Polynomial& dest, const Polynomial& s, const M& m) {
00126 dest= s; reduce_mod (dest, m); }
00127
00128 template<typename C,typename V, typename M> static inline void
00129 reduce_mod (Polynomial& dest, const Polynomial& s,
00130 const M& m, Polynomial& carry) {
00131 dest= s; reduce_mod (dest, m, carry); }
00132 };
00133
00134 template<typename X,typename W=modulus_mul_naive<X> >
00135 struct modulus_polynomial_mul_preinverse : public X {
00136
00137 template<typename C, typename V, typename M> static inline void
00138 mul_mod (Polynomial& dest, const Polynomial& s, const M& m) {
00139 if (is_exact_zero (*m)) dest *= s;
00140 else {
00141 int d= degree (*m);
00142 Polynomial a= dest * s;
00143 Polynomial b= rshiftz (rshiftz (a, d) * m.q, d);
00144 dest= a - b * (* m);
00145 }
00146 }
00147
00148 template<typename C, typename V, typename M> static inline void
00149 mul_mod (Polynomial& dest, const Polynomial& s, const M& m,
00150 Polynomial& carry) {
00151 if (is_exact_zero (*m)) {
00152 dest = dest * s + carry;
00153 carry = 0;
00154 }
00155 else {
00156 int d= degree (*m);
00157 Polynomial a= dest * s + carry;
00158 carry= rshiftz (rshiftz (a, d) * m.q, d);
00159 dest= a - carry * (* m);
00160 }
00161 }
00162
00163 template<typename C, typename V, typename M> static inline void
00164 mul_mod (Polynomial& dest, const Polynomial& s1, const Polynomial& s2,
00165 const M& m) {
00166 dest = s1;
00167 mul_mod (dest, s2, m); }
00168
00169 template<typename C, typename V, typename M> static inline void
00170 mul_mod (Polynomial& dest, const Polynomial& s1, const Polynomial& s2,
00171 const M& m, Polynomial& carry) {
00172 dest = s1;
00173 mul_mod (dest, s2, m, carry); }
00174
00175 };
00176
00177 template<typename V=modulus_polynomial_naive>
00178 struct modulus_polynomial_preinverse:
00179 public modulus_encoding_naive<
00180 modulus_div_naive<
00181 modulus_polynomial_inv_naive<
00182 modulus_polynomial_mul_preinverse<
00183 modulus_add_naive<
00184 modulus_polynomial_reduction_preinverse<
00185 modulus_normalization_naive> > > > > > {};
00186
00187 template<typename C, typename V, typename W>
00188 class modulus <Polynomial, modulus_polynomial_preinverse<W> > {
00189 MMX_ALLOCATORS
00190 public:
00191 Polynomial p;
00192 Polynomial q;
00193
00194 typedef Polynomial base;
00195 typedef modulus_polynomial_preinverse<W> variant;
00196 typedef modulus <Polynomial, modulus_polynomial_preinverse<W> > self_type;
00197
00198 inline Polynomial operator * () const { return p; }
00199
00200 inline modulus () : p (0), q (0) {}
00201
00202 inline modulus (const Polynomial& p2): p (p2) {
00203 q= is_exact_zero (p) ? p : invert_hi (p); }
00204
00205 inline modulus (const self_type& x) : p (x.p), q (x.q) {}
00206
00207 inline self_type&
00208 operator = (const self_type& x) {
00209 p = x.p;
00210 q = x.q;
00211 return *this; }
00212
00213 inline bool operator == (const self_type& a) const {
00214 return p == a.p; }
00215
00216 inline bool operator != (const self_type& a) const {
00217 return p != a.p; }
00218 };
00219
00220
00221
00222
00223
00224 template<typename X,typename W=modulus_mul_naive<X> >
00225 struct modulus_polynomial_mul_power_of_the_variable : public X {
00226
00227 template<typename C, typename V, typename M> static inline void
00228 mul_mod (Polynomial& dest, const Polynomial& s, const M& m) {
00229 if (is_exact_zero (*m)) dest *= s;
00230 else {
00231 int d= degree (*m);
00232 Polynomial a= dest * s;
00233 dest = range (a, 0, d);
00234 }
00235 }
00236
00237 template<typename C, typename V, typename M> static inline void
00238 mul_mod (Polynomial& dest, const Polynomial& s, const M& m,
00239 Polynomial& carry) {
00240 if (is_exact_zero (*m)) {
00241 dest = dest * s + carry;
00242 carry = 0;
00243 }
00244 else {
00245 int d= degree (*m);
00246 Polynomial a= dest * s + carry;
00247 carry= range (a, d, 2*d-1);
00248 dest= range (a, 0, d);
00249 }
00250 }
00251
00252 template<typename C, typename V, typename M> static inline void
00253 mul_mod (Polynomial& dest, const Polynomial& s1, const Polynomial& s2,
00254 const M& m) {
00255 dest = s1;
00256 mul_mod (dest, s2, m); }
00257
00258 template<typename C, typename V, typename M> static inline void
00259 mul_mod (Polynomial& dest, const Polynomial& s1, const Polynomial& s2,
00260 const M& m, Polynomial& carry) {
00261 dest = s1;
00262 mul_mod (dest, s2, m, carry); }
00263
00264 };
00265
00266 template<typename V=modulus_polynomial_naive>
00267 struct modulus_polynomial_power_of_the_variable:
00268 public modulus_encoding_naive<
00269 modulus_div_naive<
00270 modulus_polynomial_inv_naive<
00271 modulus_polynomial_mul_power_of_the_variable<
00272 modulus_add_naive<
00273 modulus_reduction_naive<
00274 modulus_normalization_naive> > > > > > {};
00275
00276 template<typename C, typename V, typename W>
00277 class modulus <Polynomial, modulus_polynomial_power_of_the_variable<W> > {
00278 MMX_ALLOCATORS
00279 public:
00280 Polynomial p;
00281
00282 typedef Polynomial base;
00283 typedef modulus_polynomial_power_of_the_variable<W> variant;
00284 typedef modulus <Polynomial, modulus_polynomial_power_of_the_variable<W> >
00285 self_type;
00286
00287 inline Polynomial operator * () const { return p; }
00288
00289 inline modulus () : p (0) {}
00290
00291 inline modulus (const Polynomial& p2): p (p2) {
00292 if (is_exact_zero (p)) return;
00293 ASSERT (is_exact_zero (range (p, 0, deg (p))),
00294 "Modulus must be a power of the variable");
00295 }
00296
00297 inline modulus (const self_type& x) : p (x.p) {}
00298
00299 inline self_type&
00300 operator = (const self_type& x) {
00301 p = x.p;
00302 return *this; }
00303
00304 inline bool operator == (const self_type& a) const {
00305 return p == a.p; }
00306
00307 inline bool operator != (const self_type& a) const {
00308 return p != a.p; }
00309 };
00310
00311
00312
00313
00314
00315 #undef TMPL
00316 #define TMPL template<typename C,typename V,typename MoV,typename MaV>
00317 #define Quotient quotient<polynomial<C,V>,polynomial<C,V> >
00318 #define Modular modular<modulus<polynomial<C,V>, MoV>,MaV>
00319
00320 TMPL
00321 struct as_helper<Modular,Quotient> {
00322 static Modular cv (const Quotient& x) {
00323 return as<Modular> (numerator (x)) / as<Modular> (denominator (x)); }
00324 };
00325
00326
00327
00328
00329
00330 UNARY_RETURN_TYPE(TMPL,reconstruct_op,Modular,Quotient);
00331
00332 TMPL Quotient
00333 reconstruct (const modular<modulus<polynomial<C,V>, MoV>,MaV>& x) {
00334 polynomial<C,V> num, den, q= *get_modulus (x);
00335 nat k= N(q) >> 1;
00336 bool b= reconstruct (*x, q, k, num, den);
00337 ASSERT (b, "rational reconstruction failed");
00338 return Quotient (num, den); }
00339
00340 TMPL bool
00341 is_reconstructible (const modular<modulus<polynomial<C,V>, MoV>,MaV>& x,
00342 Quotient& y) {
00343 polynomial<C,V> num, den, q= *get_modulus (x);
00344 nat k= N(q) >> 1;
00345 if (!reconstruct (*x, q, k, num, den)) return false;
00346 y= Quotient (num, den);
00347 return true; }
00348
00349 #undef Quotient
00350 #undef Modular
00351
00352 #undef TMPL
00353 #undef Polynomial
00354 }
00355 #endif // __MMX_MODULAR_POLYNOMIAL_HPP