algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : fft_roots.hpp 00004 * DESCRIPTION: primitive roots for diadic and triadic FFTs 00005 * COPYRIGHT : (C) 2005 Joris van der Hoeven 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__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 * Helper functions on bits 00025 ******************************************************************************/ 00026 00027 // diadic 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 // triadic 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 * Primitive roots of unity 00043 ******************************************************************************/ 00044 00045 template<typename C> 00046 struct primitive_root_helper { 00047 00048 // max order for b-adic fft 00049 static inline nat 00050 max_order (nat b) { return 0; } // means infinity 00051 00052 static inline C 00053 op (nat n, nat i) { 00054 if (n == 1 || i == 0) return C (1); 00055 else if (n == 2) return C(-1); 00056 else { 00057 Real_type(C) angle= (2 * i * Pi(Real_type(C))) / n; 00058 return gaussian (cos (angle), sin (angle)); 00059 } 00060 } 00061 }; 00062 00063 template<typename C> C 00064 primitive_root (nat n, nat i) { 00065 return primitive_root_helper<C>::op (n, i); 00066 } 00067 00068 template<typename C> nat 00069 primitive_root_max_order (nat b) { 00070 return primitive_root_helper<C>::max_order (b); 00071 } 00072 00073 // double 00074 #ifdef ACCURATE_ROOTS 00075 template<> 00076 struct primitive_root_helper<complex<double> > { 00077 static inline nat 00078 max_order (nat b) { return 0; } 00079 00080 static complex<double> op (nat n, nat i); 00081 }; 00082 #endif // ACCURATE_ROOTS 00083 00084 // modular native integers 00085 template<typename I> nat 00086 primitive_root_max_order_int (nat b, I p, I& m) { 00087 // p must be nonnegative 00088 nat k= 0; 00089 m= (nat) (p-1); 00090 while (m % b == 0) { k++; m /= b; } 00091 return ((nat) (p-1)) / m; 00092 } 00093 00094 template<typename I> I 00095 primitive_root_max_int (nat b, I p, nat& k, I& m) { 00096 // root of maximal order k for radix b modulo p 00097 typedef modulus<I, modulus_int_preinverse<8*sizeof(I)> > Modulus; 00098 typedef modular<Modulus> Modular; 00099 k= primitive_root_max_order_int (b, p, m); 00100 if (k == 1) return I (1); 00101 Modulus tmp= Modular::get_modulus (); 00102 Modular::set_modulus (p); 00103 Modular v; 00104 for (I x = 1; x < p; x++) { 00105 v = binpow (Modular (x), (nat) m); 00106 if (v == 1) continue; 00107 if (binpow (v, k / b) != 1) break; 00108 } 00109 Modular::set_modulus (tmp); 00110 return * v; 00111 } 00112 00113 template<typename I, typename V, typename W> 00114 struct primitive_root_helper_modular_int { 00115 typedef modular<modulus<I,V>,W> C; 00116 00117 static inline nat 00118 max_order (nat b) { 00119 I m, p= * C::get_modulus (); 00120 return primitive_root_max_order_int (b, p, m); 00121 } 00122 00123 static inline C 00124 op (nat n, nat i) { 00125 nat b, k; 00126 if (n == next_power_of_two (n)) b = 2; 00127 else if (n == next_power_of_three (n)) b = 3; 00128 else ERROR ("only radices 2 and 3 are implemented"); 00129 I m, p= * C::get_modulus (); 00130 C v= primitive_root_max_int (b, p, k, m); 00131 VERIFY (n <= k, "maximal order exceeded"); 00132 // v is now a primitive root of maximal order k 00133 return binpow (v, i * (k / n)); 00134 } 00135 }; 00136 00137 template<typename V, typename W> 00138 struct primitive_root_helper<modular<modulus<unsigned char,V>,W> > : 00139 primitive_root_helper_modular_int<unsigned char, V, W> {}; 00140 00141 template<typename V, typename W> 00142 struct primitive_root_helper<modular<modulus<signed char,V>,W> > : 00143 primitive_root_helper_modular_int<signed char, V, W> {}; 00144 00145 template<typename V, typename W> 00146 struct primitive_root_helper<modular<modulus<short unsigned int,V>,W> > : 00147 primitive_root_helper_modular_int<short unsigned int, V, W> {}; 00148 00149 template<typename V, typename W> 00150 struct primitive_root_helper<modular<modulus<short signed int,V>,W> > : 00151 primitive_root_helper_modular_int<short signed int, V, W> {}; 00152 00153 template<typename V, typename W> 00154 struct primitive_root_helper<modular<modulus<unsigned int,V>,W> > : 00155 primitive_root_helper_modular_int<unsigned int, V, W> {}; 00156 00157 template<typename V, typename W> 00158 struct primitive_root_helper<modular<modulus<int,V>,W> > : 00159 primitive_root_helper_modular_int<int, V, W> {}; 00160 00161 template<typename V, typename W> 00162 struct primitive_root_helper<modular<modulus<long unsigned int,V>,W> > : 00163 primitive_root_helper_modular_int<long unsigned int, V, W> {}; 00164 00165 template<typename V, typename W> 00166 struct primitive_root_helper<modular<modulus<long int,V>,W> > : 00167 primitive_root_helper_modular_int<long int, V, W> {}; 00168 00169 #ifdef BASIX_HAVE_LONG_LONG_INT 00170 template<typename V, typename W> 00171 struct primitive_root_helper<modular<modulus<long long unsigned int,V>,W> > : 00172 primitive_root_helper_modular_int<long long unsigned int, V, W> {}; 00173 00174 template<typename V, typename W> 00175 struct primitive_root_helper<modular<modulus<long long int,V>,W> > : 00176 primitive_root_helper_modular_int<long long int, V, W> {}; 00177 #endif 00178 00179 // special modulus 3 * 2^30 + 1 00180 #define FFTP modular_fixed<nat,0x0c0000001> 00181 00182 template<typename V> 00183 struct primitive_root_helper<modular<modulus<nat,V>,FFTP> > { 00184 typedef modulus<nat, V> Modulus; 00185 typedef modular<Modulus,FFTP> Modular; 00186 00187 static inline nat 00188 max_order (nat b) { 00189 if (b == 2) return 1<<30; 00190 if (b == 3) return 3; 00191 return 0; 00192 } 00193 00194 static inline Modular 00195 op (nat n, nat i) { 00196 nat k; 00197 Modular v; 00198 if (n == next_power_of_two (n)) { 00199 k = max_order (2); 00200 v = 125; 00201 } 00202 else if (n == next_power_of_three (n)) { 00203 k = max_order (3); 00204 v = 1610563584; 00205 } 00206 else ERROR ("only radices 2 and 3 are implemented"); 00207 ASSERT (n <= k, "maximal order exceeded"); 00208 return binpow (v, i * (k / n)); 00209 } 00210 }; 00211 00212 // Bivariate polynomials 00213 template<typename C, typename V> struct polynomial; 00214 00215 template<typename C, typename V> 00216 struct primitive_root_helper<polynomial<C,V> > : 00217 primitive_root_helper<C> {}; 00218 00219 // Polynomials over modulars of polynomials 00220 template<typename C, typename U, typename V, typename W> 00221 struct primitive_root_helper<modular<modulus<polynomial<C,U>,V>,W> > : 00222 primitive_root_helper<C> {}; 00223 00224 /****************************************************************************** 00225 * Cache for roots 00226 ******************************************************************************/ 00227 00228 template<typename V> 00229 struct cached_roots_helper: public V { 00230 typedef typename V::C C; 00231 typedef typename V::U U; 00232 static nat capacity; 00233 static U* roots; 00234 00235 static U* 00236 create_roots (nat n) { 00237 if (n > capacity) { 00238 if (capacity != 0) V::destroy_roots (roots, capacity); 00239 roots= V::create_roots (n); 00240 capacity= n; 00241 } 00242 return roots; 00243 } 00244 00245 static void 00246 destroy_roots (U* u, nat n) { 00247 (void) u; (void) n; 00248 } 00249 }; 00250 00251 template<typename V> nat cached_roots_helper<V>::capacity= 0; 00252 template<typename V> typename V::U* cached_roots_helper<V>::roots= NULL; 00253 00254 // Root caching is only used for when C can not be modified howsoever 00255 template<typename CC, typename UU=CC, typename SS=CC> 00256 struct roots_helper; 00257 00258 template<typename C> 00259 struct std_roots { 00260 typedef roots_helper<C> roots_type; 00261 }; 00262 00263 template<typename C, typename V> 00264 struct std_roots<polynomial<C, V> > { 00265 typedef roots_helper<polynomial<C, V>, C, C> roots_type; 00266 }; 00267 00268 STMPL 00269 struct std_roots<complex<double> > { 00270 typedef complex<double> C; 00271 typedef cached_roots_helper<roots_helper<C> > roots_type; 00272 }; 00273 00274 template<typename M, typename D, D d> 00275 struct std_roots<modular<M, modular_fixed<D, d> > >{ 00276 typedef modular<M, modular_fixed<D, d> > C; 00277 typedef cached_roots_helper<roots_helper<C> > roots_type; 00278 }; 00279 00280 } // namespace mmx 00281 #endif //__MMX__FFT_ROOTS__HPP