00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 #ifndef __MMX__FFT_TRIADIC_NAIVE__HPP
00014 #define __MMX__FFT_TRIADIC_NAIVE__HPP
00015 #include <basix/vector_naive.hpp>
00016 #include <algebramix/fft_roots.hpp>
00017 
00018 namespace mmx {
00019 
00020 
00021 
00022 
00023 
00024 template<typename CC, typename UU=CC, typename SS=CC>
00025 struct roots_triadic_helper {
00026   typedef implementation<vector_linear,vector_naive> NVec;
00027   typedef CC C; 
00028   typedef UU U; 
00029   typedef SS S; 
00030 
00031   static U*
00032   create_roots (nat n, const format<C>& fm) {
00033     U* roots= mmx_new<U> (n);
00034     for (nat i=0; i<n; i++)
00035       roots[i] = primitive_root<C> (n, digit_mirror_triadic (i, n), fm);
00036     return roots; }
00037 
00038   static U*
00039   create_stoor (nat n, const format<C>& fm) {
00040     U* stoor= mmx_new<U> (n);
00041     for (nat i=0; i<n; i++)
00042       stoor[i]= primitive_root<C> (n, i==0 ? 0 : n - digit_mirror_triadic (i, n), fm);
00043     return stoor; }
00044 
00045   static void
00046   destroy_roots (U* u, nat n) {
00047     mmx_delete<U> (u, n); }
00048 
00049   static inline void
00050   dfft_cross (C* c1, C* c2, C* c3, const U* u1, const U* u2, const U* u3) {
00051     C temp1= *c1, temp2= *c2;
00052     *c1 = temp1 + (*u1) * (temp2 + (*u1) * (*c3));
00053     *c2 = temp1 + (*u2) * (temp2 + (*u2) * (*c3));
00054     *c3 = temp1 + (*u3) * (temp2 + (*u3) * (*c3));
00055   }
00056 
00057   static inline void
00058   ifft_cross (C* c1, C* c2, C* c3, const U* u1, const U* u2, const U* u3) {
00059     C temp1= *c1, temp2= *c2;
00060     *c1 = temp1 + temp2 + (*c3);
00061     *c2 = (*u1) * temp1 + (*u2) * temp2 + (*u3) * (*c3);
00062     *c3 = (*u1) * ((*u1) * temp1 + (*u3) * temp2 + (*u2) * (*c3));
00063   }
00064 
00065   static inline void
00066   fft_shift (C* dest, S v, nat t) {
00067     NVec::mul (dest, C(v), t); }
00068 };
00069 
00070 struct std_roots_triadic {
00071   template<typename C>
00072   struct helper {
00073     typedef cached_roots_helper<roots_triadic_helper<C> > roots_type;
00074   };
00075 };
00076 
00077 
00078 
00079 
00080 
00081 template<typename C, typename VV= std_roots_triadic>
00082 class fft_triadic_naive_transformer {
00083 public:
00084   typedef VV V;
00085   typedef typename V::template helper<C>::roots_type R;
00086   typedef typename R::U U;
00087   typedef typename R::S S;
00088 
00089   format<C> fm;
00090   nat depth;
00091   nat len;
00092   U*  roots; 
00093   U*  stoor; 
00094 
00095 public:
00096   inline fft_triadic_naive_transformer (nat n, const format<C>& fm2):
00097     fm (fm2),
00098     depth (log_3 (n)), len (n), roots (R::create_roots (n, fm)),
00099                                 stoor (R::create_stoor (n, fm)) {
00100     VERIFY (n == binpow ((nat) 3, depth), "power of three expected"); }
00101   inline ~fft_triadic_naive_transformer () {
00102     R::destroy_roots (roots, len);
00103     R::destroy_roots (stoor, len); }
00104 
00105   template<typename CC> inline void
00106   dfft_triadic (CC* c, nat stride, nat shift,
00107                 nat steps, nat step1, nat step2) {
00108     
00109     
00110     
00111     
00112     typedef typename V::template helper<CC>::roots_type RR;
00113     for (nat step= step1; step < step2; step++) {
00114       
00115       nat todo= binpow (3, steps - 1 - step);
00116       CC* cc  = c;
00117       U * uu  = roots + (shift / todo);
00118       for (nat j= 0; j < (nat) binpow (3, step); j++) {
00119         for (nat k= 0; k < todo; k++) {
00120           RR::dfft_cross (cc, cc + stride * todo,
00121                           cc + ((stride * todo) << 1), uu, uu+1, uu+2);
00122           cc += stride;
00123         }
00124         cc += (stride * todo) << 1;
00125         uu += 3;
00126       }
00127     }
00128   }
00129 
00130   template<typename CC> inline void
00131   ifft_triadic (CC* c, nat stride, nat shift,
00132                 nat steps, nat step1, nat step2) {
00133     
00134     
00135     
00136     
00137     typedef typename V::template helper<CC>::roots_type RR;
00138     for (int step= step2-1; step >= ((int) step1); step--) {
00139       
00140       nat todo= binpow (3, steps - 1 - step);
00141       CC* cc  = c;
00142       U * uu  = stoor + (shift / todo);
00143       for (nat j= 0; j < (nat) binpow (3, step); j++) {
00144         for (nat k= 0; k < todo; k++) {
00145           RR::ifft_cross (cc, cc + stride * todo,
00146                           cc + ((stride * todo) << 1), uu, uu+1, uu+2);
00147           cc += stride;
00148         }
00149         cc += (stride * todo) << 1;
00150         uu += 3;
00151       }
00152     }
00153   }
00154 
00155   template<typename CC> inline void
00156   dfft_triadic (CC* c, nat stride, nat shift, nat steps) {
00157     dfft_triadic (c, stride, shift, steps, 0, steps);
00158   }
00159 
00160   template<typename CC> inline void
00161   ifft_triadic (CC* c, nat stride, nat shift, nat steps) {
00162     ifft_triadic (c, stride, shift, steps, 0, steps);
00163   }
00164 
00165   inline void
00166   direct_transform_triadic (C* c) {
00167     dfft_triadic (c, 1, 0, depth);
00168   }
00169 
00170   inline void
00171   inverse_transform_triadic (C* c, bool shift=true) {
00172     ifft_triadic (c, 1, 0, depth);
00173     if (shift)
00174       R::fft_shift (c, invert (S (len)), len);
00175   }
00176 };
00177 
00178 
00179 
00180 
00181 
00182 template<typename C> inline void
00183 direct_fft_triadic (C* dest, nat n) {
00184   if (n == 0) return;
00185   fft_triadic_naive_transformer<C> ffter (n, get_format (dest[0]));
00186   ffter.direct_transform_triadic (dest);
00187 }
00188 
00189 template<typename C> inline void
00190 inverse_fft_triadic (C* dest, nat n) {
00191   if (n == 0) return;
00192   fft_triadic_naive_transformer<C> ffter (n, get_format (dest[0]));
00193   ffter.inverse_transform_triadic (dest);
00194 }
00195 
00196 } 
00197 #endif //__MMX__FFT_TRIADIC_NAIVE__HPP