00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __MMX__FFT_ROOTS__HPP
00014 #define __MMX__FFT_ROOTS__HPP
00015 #include <basix/int.hpp>
00016 #include <basix/vector_naive.hpp>
00017 #include <numerix/modular.hpp>
00018 #include <numerix/modular_int.hpp>
00019 #include <numerix/complex_double.hpp>
00020
00021 namespace mmx {
00022
00023
00024
00025
00026
00027
00028 static nat
00029 bit_mirror (nat i, nat n) {
00030 if (n == 1) return i;
00031 else return (bit_mirror (i & ((n>>1) -1), n>>1) << 1) + i / (n>>1);
00032 }
00033
00034
00035 static nat
00036 digit_mirror_triadic (nat i, nat n) {
00037 if (n == 1) return i;
00038 else return digit_mirror_triadic (i % (n / 3), n / 3) * 3 + i / (n / 3);
00039 }
00040
00041
00042
00043
00044
00045 template<typename C>
00046 struct primitive_root_helper {
00047
00048
00049 static inline nat
00050 max_order (nat b) { return 0; }
00051
00052 static inline C
00053 op (nat n, nat i, const format<C>& fm) {
00054 if (n == 1 || i == 0) return promote (1, fm);
00055 else if (n == 2) return promote (-1, fm);
00056 else {
00057 C z= promote (1, fm);
00058 set_pi (z);
00059 z= times_i (z);
00060 z= (promote ((int) (i+i), z) / promote ((int) n, z)) * z;
00061 return exp (z);
00062
00063
00064 }
00065 }
00066 };
00067
00068 template<typename C> C
00069 primitive_root (nat n, nat i, const format<C>& fm) {
00070 return primitive_root_helper<C>::op (n, i, fm);
00071 }
00072
00073 template<typename C> nat
00074 primitive_root_max_order (nat b) {
00075 return primitive_root_helper<C>::max_order (b);
00076 }
00077
00078
00079 #ifdef ACCURATE_ROOTS
00080 template<>
00081 struct primitive_root_helper<complex<double> > {
00082 static inline nat
00083 max_order (nat b) { return 0; }
00084
00085 static complex<double> op (nat n, nat i, const format<complex<double> >&);
00086 };
00087 #endif // ACCURATE_ROOTS
00088
00089
00090 template<typename I> nat
00091 primitive_root_max_order_int (nat b, I p, I& m) {
00092
00093 nat k= 0;
00094 m= (nat) (p-1);
00095 while (m % b == 0) { k++; m /= b; }
00096 return ((nat) (p-1)) / m;
00097 }
00098
00099 template<typename I> I
00100 primitive_root_max_int (nat b, I p, nat& k, I& m) {
00101
00102 typedef modulus<I, modulus_int_preinverse<8*sizeof(I)> > Modulus;
00103 typedef modular<Modulus> Modular;
00104 k= primitive_root_max_order_int (b, p, m);
00105 if (k == 1) return I (1);
00106 Modulus tmp= Modular::get_modulus ();
00107 Modular::set_modulus (p);
00108 Modular v;
00109 for (I x = 1; x < p; x++) {
00110 v = binpow (Modular (x), (nat) m);
00111 if (v == 1) continue;
00112 if (binpow (v, k / b) != 1) break;
00113 }
00114 Modular::set_modulus (tmp);
00115 return * v;
00116 }
00117
00118 template<typename I, typename V, typename W>
00119 struct primitive_root_helper_modular_int {
00120 typedef modular<modulus<I,V>,W> C;
00121
00122 static inline nat
00123 max_order (nat b) {
00124 I m, p= * C::get_modulus ();
00125 return primitive_root_max_order_int (b, p, m);
00126 }
00127
00128 static inline C
00129 op (nat n, nat i, const format<C>& fm) {
00130 (void) fm;
00131 nat b, k;
00132 if (n == next_power_of_two (n)) b = 2;
00133 else if (n == next_power_of_three (n)) b = 3;
00134 else ERROR ("only radices 2 and 3 are implemented");
00135 I m, p= * C::get_modulus ();
00136 C v= primitive_root_max_int (b, p, k, m);
00137 VERIFY (n <= k, "maximal order exceeded");
00138
00139 return binpow (v, i * (k / n));
00140 }
00141 };
00142
00143 template<typename V, typename W>
00144 struct primitive_root_helper<modular<modulus<unsigned char,V>,W> > :
00145 primitive_root_helper_modular_int<unsigned char, V, W> {};
00146
00147 template<typename V, typename W>
00148 struct primitive_root_helper<modular<modulus<signed char,V>,W> > :
00149 primitive_root_helper_modular_int<signed char, V, W> {};
00150
00151 template<typename V, typename W>
00152 struct primitive_root_helper<modular<modulus<short unsigned int,V>,W> > :
00153 primitive_root_helper_modular_int<short unsigned int, V, W> {};
00154
00155 template<typename V, typename W>
00156 struct primitive_root_helper<modular<modulus<short signed int,V>,W> > :
00157 primitive_root_helper_modular_int<short signed int, V, W> {};
00158
00159 template<typename V, typename W>
00160 struct primitive_root_helper<modular<modulus<unsigned int,V>,W> > :
00161 primitive_root_helper_modular_int<unsigned int, V, W> {};
00162
00163 template<typename V, typename W>
00164 struct primitive_root_helper<modular<modulus<int,V>,W> > :
00165 primitive_root_helper_modular_int<int, V, W> {};
00166
00167 template<typename V, typename W>
00168 struct primitive_root_helper<modular<modulus<long unsigned int,V>,W> > :
00169 primitive_root_helper_modular_int<long unsigned int, V, W> {};
00170
00171 template<typename V, typename W>
00172 struct primitive_root_helper<modular<modulus<long int,V>,W> > :
00173 primitive_root_helper_modular_int<long int, V, W> {};
00174
00175 #ifdef BASIX_HAVE_LONG_LONG_INT
00176 template<typename V, typename W>
00177 struct primitive_root_helper<modular<modulus<long long unsigned int,V>,W> > :
00178 primitive_root_helper_modular_int<long long unsigned int, V, W> {};
00179
00180 template<typename V, typename W>
00181 struct primitive_root_helper<modular<modulus<long long int,V>,W> > :
00182 primitive_root_helper_modular_int<long long int, V, W> {};
00183 #endif
00184
00185
00186 #define FFTP modular_fixed<nat,0x0c0000001>
00187
00188 template<typename V>
00189 struct primitive_root_helper<modular<modulus<nat,V>,FFTP> > {
00190 typedef modulus<nat, V> Modulus;
00191 typedef modular<Modulus,FFTP> Modular;
00192
00193 static inline nat
00194 max_order (nat b) {
00195 if (b == 2) return 1<<30;
00196 if (b == 3) return 3;
00197 return 0;
00198 }
00199
00200 static inline Modular
00201 op (nat n, nat i, const format<Modular >&) {
00202 nat k;
00203 Modular v;
00204 if (n == next_power_of_two (n)) {
00205 k = max_order (2);
00206 v = 125;
00207 }
00208 else if (n == next_power_of_three (n)) {
00209 k = max_order (3);
00210 v = 1610563584;
00211 }
00212 else ERROR ("only radices 2 and 3 are implemented");
00213 ASSERT (n <= k, "maximal order exceeded");
00214 return binpow (v, i * (k / n));
00215 }
00216 };
00217
00218
00219 #define FFTP29 modular_fixed<nat,469762049>
00220
00221 template<typename V>
00222 struct primitive_root_helper<modular<modulus<nat,V>,FFTP29> > {
00223 typedef modulus<nat, V> Modulus;
00224 typedef modular<Modulus,FFTP29> Modular;
00225
00226 static inline nat
00227 max_order (nat b) {
00228 if (b == 2) return 1<<26;
00229 return 0;
00230 }
00231
00232 static inline Modular
00233 op (nat n, nat i, const format<Modular >&) {
00234 nat k;
00235 Modular v;
00236 if (n == next_power_of_two (n)) {
00237 k = max_order (2);
00238 v = 2187;
00239 }
00240 else { ERROR ("only radix 2 is implemented"); }
00241 ASSERT (n <= k, "maximal order exceeded");
00242 return binpow (v, i * (k / n));
00243 }
00244 };
00245
00246
00247 #define FFTP14 modular_fixed<unsigned short, 3*(1<<12)+1>
00248
00249 template<typename V>
00250 struct primitive_root_helper<modular<modulus<nat,V>,FFTP14> > {
00251 typedef modulus<nat, V> Modulus;
00252 typedef modular<Modulus,FFTP14> Modular;
00253
00254 static inline nat
00255 max_order (nat b) {
00256 if (b == 2) return 1<<12;
00257 return 0;
00258 }
00259
00260 static inline Modular
00261 op (nat n, nat i, const format<Modular >&) {
00262 nat k;
00263 Modular v;
00264 if (n == next_power_of_two (n)) {
00265 k = max_order (2);
00266 v = 1331;
00267 }
00268 else { ERROR ("only radix 2 is implemented"); }
00269 ASSERT (n <= k, "maximal order exceeded");
00270 return binpow (v, i * (k / n));
00271 }
00272 };
00273
00274
00275 template<typename C, typename V> struct polynomial;
00276
00277 template<typename C, typename V>
00278 struct primitive_root_helper<polynomial<C,V> > :
00279 primitive_root_helper<C> {};
00280
00281
00282 template<typename C, typename U, typename V, typename W>
00283 struct primitive_root_helper<modular<modulus<polynomial<C,U>,V>,W> > :
00284 primitive_root_helper<C> {};
00285
00286
00287
00288
00289
00290 template<typename V>
00291 struct cached_roots_helper: public V {
00292 typedef typename V::C C;
00293 typedef typename V::U U;
00294 static nat capacity;
00295 static U* roots;
00296
00297 static U*
00298 create_roots (nat n, const format<C>& fm) {
00299 if (n > capacity) {
00300 if (capacity != 0) V::destroy_roots (roots, capacity);
00301 roots= V::create_roots (n, fm);
00302 capacity= n;
00303 }
00304 return roots;
00305 }
00306
00307 static void
00308 destroy_roots (U* u, nat n) {
00309 (void) u; (void) n;
00310 }
00311 };
00312
00313 template<typename V> nat cached_roots_helper<V>::capacity= 0;
00314 template<typename V> typename V::U* cached_roots_helper<V>::roots= NULL;
00315
00316
00317 template<typename CC, typename UU=CC, typename SS=CC>
00318 struct roots_helper;
00319
00320 template<typename C>
00321 struct std_roots {
00322 typedef roots_helper<C> roots_type;
00323 };
00324
00325 template<typename C, typename V>
00326 struct std_roots<vector<C, V> > {
00327 typedef roots_helper<vector<C, V>, C, C> roots_type;
00328 };
00329
00330 template<typename C, typename V>
00331 struct std_roots<polynomial<C, V> > {
00332 typedef roots_helper<polynomial<C, V>, C, C> roots_type;
00333 };
00334
00335 STMPL
00336 struct std_roots<complex<double> > {
00337 typedef complex<double> C;
00338 typedef cached_roots_helper<roots_helper<C> > roots_type;
00339 };
00340
00341 template<typename M, typename D, D d>
00342 struct std_roots<modular<M, modular_fixed<D, d> > >{
00343 typedef modular<M, modular_fixed<D, d> > C;
00344 typedef cached_roots_helper<roots_helper<C> > roots_type;
00345 };
00346
00347 }
00348 #endif //__MMX__FFT_ROOTS__HPP