diff --git a/unsupported/Eigen/FFT.h b/unsupported/Eigen/FFT.h new file mode 100644 index 000000000..03490d2c5 --- /dev/null +++ b/unsupported/Eigen/FFT.h @@ -0,0 +1,84 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2009 Mark Borgerding mark a borgerding net +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_FFT_H +#define EIGEN_FFT_H + +// simple_fft_traits: small, free, reasonably efficient default, derived from kissfft +#include "src/FFT/simple_fft_traits.h" +#define DEFAULT_FFT_TRAITS simple_fft_traits + +// FFTW: faster, GPL-not LGPL, bigger code size +#ifdef FFTW_PATIENT // definition of FFTW_PATIENT indicates the caller has included fftw3.h, we can use FFTW routines +// TODO +// #include "src/FFT/fftw_traits.h" +// #define DEFAULT_FFT_TRAITS fftw_traits +#endif + +// intel Math Kernel Library: fastest, commerical +#ifdef _MKL_DFTI_H_ // mkl_dfti.h has been included, we can use MKL FFT routines +// TODO +// #include "src/FFT/imkl_traits.h" +// #define DEFAULT_FFT_TRAITS imkl_traits +#endif + +namespace Eigen { + +template + > +class FFT +{ + public: + typedef _Traits traits_type; + typedef typename traits_type::Scalar Scalar; + typedef typename traits_type::Complex Complex; + + FFT(const traits_type & traits=traits_type() ) :m_traits(traits) { } + + void fwd( Complex * dst, const Complex * src, int nfft) + { + m_traits.prepare(nfft,false,dst,src); + m_traits.exec(dst,src); + m_traits.postprocess(dst); + } + + void inv( Complex * dst, const Complex * src, int nfft) + { + m_traits.prepare(nfft,true,dst,src); + m_traits.exec(dst,src); + m_traits.postprocess(dst); + } + + // TODO: fwd,inv for Scalar + // TODO: multi-dimensional FFTs + // TODO: handle Eigen MatrixBase + + traits_type & traits() {return m_traits;} + private: + traits_type m_traits; +}; +#undef DEFAULT_FFT_TRAITS +} +#endif diff --git a/unsupported/Eigen/src/FFT/simple_fft_traits.h b/unsupported/Eigen/src/FFT/simple_fft_traits.h new file mode 100644 index 000000000..fe9d24b84 --- /dev/null +++ b/unsupported/Eigen/src/FFT/simple_fft_traits.h @@ -0,0 +1,296 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2009 Mark Borgerding mark a borgerding net +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#include +#include + +namespace Eigen { + + template + struct simple_fft_traits + { + typedef _Scalar Scalar; + typedef std::complex Complex; + simple_fft_traits() : m_nfft(0) {} + + void prepare(int nfft,bool inverse,Complex * dst,const Complex *src) + { + if (m_nfft == nfft) { + // reuse the twiddles, conjugate if necessary + if (inverse != m_inverse) + for (int i=0;in) + p=n;// no more factors + } + n /= p; + m_stageRadix.push_back(p); + m_stageRemainder.push_back(n); + }while(n>1); + } + + void exec(Complex * dst, const Complex * src) + { + work(0, dst, src, 1,1); + } + + void postprocess(Complex *dst) + { + if (m_inverse) { + Scalar scale = 1./m_nfft; + for (int k=0;kreal() - .5*scratch[3].real() , Fout->imag() - .5*scratch[3].imag() ); + + scratch[0] *= epi3.imag(); + + *Fout += scratch[3]; + + Fout[m2] = Complex( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() ); + + Fout[m] += Complex( -scratch[0].imag(),scratch[0].real() ); + ++Fout; + }while(--k); + } + + void bfly5( Complex * Fout, const size_t fstride, const size_t m) + { + Complex *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + size_t u; + Complex scratch[13]; + Complex * twiddles = &m_twiddles[0]; + Complex *tw; + Complex ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=twiddles; + for ( u=0; u=Norig) twidx-=Norig; + t=scratchbuf[q] * twiddles[twidx]; + Fout[ k ] += t; + } + k += m; + } + } + } + + int m_nfft; + bool m_inverse; + std::vector m_twiddles; + std::vector m_stageRadix; + std::vector m_stageRemainder; + }; +} diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index abfbb0185..49de7dfb2 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -19,3 +19,4 @@ ei_add_test(autodiff) ei_add_test(BVH) ei_add_test(matrixExponential) ei_add_test(alignedvector3) +ei_add_test(FFT) diff --git a/unsupported/test/FFT.cpp b/unsupported/test/FFT.cpp new file mode 100644 index 000000000..b13a7810f --- /dev/null +++ b/unsupported/test/FFT.cpp @@ -0,0 +1,85 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2009 Mark Borgerding mark a borgerding net +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#include "main.h" +#include + +//#include +//#include +//#include + +using namespace std; + +template +void test_fft(int nfft) +{ + typedef typename Eigen::FFT::Complex Complex; + + //cout << "type:" << typeid(T).name() << " nfft:" << nfft; + + FFT fft; + + vector inbuf(nfft); + vector buf3(nfft); + vector outbuf(nfft); + for (int k=0;k acc = 0; + long double phinc = 2*k0* M_PIl / nfft; + for (int k1=0;k1 x(inbuf[k1].real(),inbuf[k1].imag()); + acc += x * exp( complex(0,-k1*phinc) ); + } + totalpower += norm(acc); + complex x(outbuf[k0].real(),outbuf[k0].imag()); + complex dif = acc - x; + difpower += norm(dif); + } + long double rmse = sqrt(difpower/totalpower); + VERIFY( rmse < 1e-5 );// gross check + + totalpower=0; + difpower=0; + for (int k=0;k(32) )); CALL_SUBTEST(( test_fft(32) )); CALL_SUBTEST(( test_fft(32) )); + CALL_SUBTEST(( test_fft(1024) )); CALL_SUBTEST(( test_fft(1024) )); CALL_SUBTEST(( test_fft(1024) )); + CALL_SUBTEST(( test_fft(2*3*4*5*7) )); CALL_SUBTEST(( test_fft(2*3*4*5*7) )); CALL_SUBTEST(( test_fft(2*3*4*5*7) )); +}