algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/fft_triadic_naive.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : fft_triadic_naive.hpp
00004 * DESCRIPTION: generic low-level triadic FFT
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__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 * Naive root arithmetic
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; // type of entries
00028   typedef UU U; // type of roots
00029   typedef SS S; // type of scalars
00030 
00031   static U*
00032   create_roots (nat n) {
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));
00036     return roots; }
00037 
00038   static U*
00039   create_stoor (nat n) {
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 :
00043                                    n - digit_mirror_triadic (i, n));
00044     return stoor; }
00045 
00046   static void
00047   destroy_roots (U* u, nat n) {
00048     mmx_delete<U> (u, n); }
00049 
00050   static inline void
00051   dfft_cross (C* c1, C* c2, C* c3, const U* u1, const U* u2, const U* u3) {
00052     C temp1= *c1, temp2= *c2;
00053     *c1 = temp1 + (*u1) * (temp2 + (*u1) * (*c3));
00054     *c2 = temp1 + (*u2) * (temp2 + (*u2) * (*c3));
00055     *c3 = temp1 + (*u3) * (temp2 + (*u3) * (*c3));
00056   }
00057 
00058   static inline void
00059   ifft_cross (C* c1, C* c2, C* c3, const U* u1, const U* u2, const U* u3) {
00060     C temp1= *c1, temp2= *c2;
00061     *c1 = temp1 + temp2 + (*c3);
00062     *c2 = (*u1) * temp1 + (*u2) * temp2 + (*u3) * (*c3);
00063     *c3 = (*u1) * ((*u1) * temp1 + (*u3) * temp2 + (*u2) * (*c3));
00064   }
00065 
00066   static inline void
00067   fft_shift (C* dest, S v, nat t) {
00068     NVec::mul (dest, C(v), t); }
00069 };
00070 
00071 struct std_roots_triadic {
00072   template<typename C>
00073   struct helper {
00074     typedef cached_roots_helper<roots_triadic_helper<C> > roots_type;
00075   };
00076 };
00077 
00078 /******************************************************************************
00079 * The FFT transformer class
00080 ******************************************************************************/
00081 
00082 template<typename C, typename VV= std_roots_triadic>
00083 class fft_triadic_naive_transformer {
00084 public:
00085   typedef VV V;
00086   typedef typename V::template helper<C>::roots_type R;
00087   typedef typename R::U U;
00088   typedef typename R::S S;
00089 
00090   nat depth;
00091   nat len;
00092   U*  roots; // roots in triadic digit reverse order
00093   U*  stoor; // inverses of the roots
00094 
00095 public:
00096   inline fft_triadic_naive_transformer (nat n):
00097     depth (log_3 (n)), len (n), roots (R::create_roots (n)),
00098                                 stoor (R::create_stoor (n)) {
00099     VERIFY (n == binpow ((nat) 3, depth), "power of three expected"); }
00100   inline ~fft_triadic_naive_transformer () {
00101     R::destroy_roots (roots, len);
00102     R::destroy_roots (stoor, len); }
00103 
00104   template<typename CC> inline void
00105   dfft_triadic (CC* c, nat stride, nat shift,
00106                 nat steps, nat step1, nat step2) {
00107     // In place direct triadic fft of
00108     // c[0], c[stride], ..., c[(3^steps-1) stride]
00109     // Only performs steps from step1 until step2-1
00110     // Roots start at roots + shift
00111     typedef typename V::template helper<CC>::roots_type RR;
00112     for (nat step= step1; step < step2; step++) {
00113       //mmout << "step " << step << ": " << flush_now;
00114       nat todo= binpow (3, steps - 1 - step);
00115       CC* cc  = c;
00116       U * uu  = roots + (shift / todo);
00117       for (nat j= 0; j < (nat) binpow (3, step); j++) {
00118         for (nat k= 0; k < todo; k++) {
00119           RR::dfft_cross (cc, cc + stride * todo,
00120                           cc + ((stride * todo) << 1), uu, uu+1, uu+2);
00121           cc += stride;
00122         }
00123         cc += (stride * todo) << 1;
00124         uu += 3;
00125       }
00126     }
00127   }
00128 
00129   template<typename CC> inline void
00130   ifft_triadic (CC* c, nat stride, nat shift,
00131                 nat steps, nat step1, nat step2) {
00132     // In place inverse triadic fft of
00133     // c[0], c[stride], ..., c[(3^steps-1) stride]
00134     // Only performs steps from step2-1 until step1
00135     // Roots start at roots + shift
00136     typedef typename V::template helper<CC>::roots_type RR;
00137     for (int step= step2-1; step >= ((int) step1); step--) {
00138       //mmout << "step " << step << ": " << flush_now;
00139       nat todo= binpow (3, steps - 1 - step);
00140       CC* cc  = c;
00141       U * uu  = stoor + (shift / todo);
00142       for (nat j= 0; j < (nat) binpow (3, step); j++) {
00143         for (nat k= 0; k < todo; k++) {
00144           RR::ifft_cross (cc, cc + stride * todo,
00145                           cc + ((stride * todo) << 1), uu, uu+1, uu+2);
00146           cc += stride;
00147         }
00148         cc += (stride * todo) << 1;
00149         uu += 3;
00150       }
00151     }
00152   }
00153 
00154   template<typename CC> inline void
00155   dfft_triadic (CC* c, nat stride, nat shift, nat steps) {
00156     dfft_triadic (c, stride, shift, steps, 0, steps);
00157   }
00158 
00159   template<typename CC> inline void
00160   ifft_triadic (CC* c, nat stride, nat shift, nat steps) {
00161     ifft_triadic (c, stride, shift, steps, 0, steps);
00162   }
00163 
00164   inline void
00165   direct_transform_triadic (C* c) {
00166     dfft_triadic (c, 1, 0, depth);
00167   }
00168 
00169   inline void
00170   inverse_transform_triadic (C* c, bool shift=true) {
00171     ifft_triadic (c, 1, 0, depth);
00172     if (shift)
00173       R::fft_shift (c, invert (S (len)), len);
00174   }
00175 };
00176 
00177 /******************************************************************************
00178 * The FFT transformer class
00179 ******************************************************************************/
00180 
00181 template<typename C> inline void
00182 direct_fft_triadic (C* dest, nat n) {
00183   fft_triadic_naive_transformer<C> ffter (n);
00184   ffter.direct_transform_triadic (dest);
00185 }
00186 
00187 template<typename C> inline void
00188 inverse_fft_triadic (C* dest, nat n) {
00189   fft_triadic_naive_transformer<C> ffter (n);
00190   ffter.inverse_transform_triadic (dest);
00191 }
00192 } // namespace mmx
00193 #endif //__MMX__FFT_TRIADIC_NAIVE__HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines