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