algebramix_doc 0.3
|
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