Re: [eigen] Eigen/FFT |

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]

*To*: eigen@xxxxxxxxxxxxxxxxxxx*Subject*: Re: [eigen] Eigen/FFT*From*: Benoit Jacob <jacob.benoit.1@xxxxxxxxx>*Date*: Tue, 23 Jun 2009 04:26:26 +0200*Dkim-signature*: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=NFWEmPPYNoDyEGX2XO4KfbW+/NVn1AF74tlTfFdbq+A=; b=Qe1//9qfRJZwxGCLvr7iRJzfnCm1rXmEzXS8xjYLyndSkDt/2LCnMy4R7l7EZyp+zc V5IvF5Uz1neqnXRyvcZL/E9apAgrdiUgfQjcJ9NU2L4uhTjD5PuGnsztBKq+8ICIRj0Y WRQJAcTZLC/G1CfcLbHgXOBy5VAwHMQg0JHSk=*Domainkey-signature*: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=sbjsU6TmB5hkPg3tRFy5oioe74QT1RG2Mjsw8OGl5PT2KBCIhGAaEkPY/ZNTeVkC03 78bihMMONs7FW9JnveHlT/mlQWeX0Xm3ohlC1hT82Qz9c90Bg2qzc+LHDGhyPSpVdO5q KUgi/EgroK4RxyshAbEOdwzLyeA539t5SXB+M=

(it seems that GMail now defaults to HTML mode. Is it worth that i click everytime on "text-only" or will it still send a text-only version alongside the HTML version if I leave HTML mode enabled ?) OK, finally here's a review of FFT! First of all thanks a lot for the good work and the wiki page, it's very useful. 2009/6/16 Mark Borgerding <mark@xxxxxxxxxxxxxx> > I would like to add fwd & inv functions for the Eigen Matrix types into the FFT interface, but I could use a little guidance on how to do it since I am still an Eigen novice. your function could have a prototype like this: template<typename SrcDerived, typename DstDerived> void foo(const MatrixBase<SrcDerived>& src, MatrixBase<DstDerived> *dst); now if each coefficient in src is going to be used many times, it is probably a good idea to evaluate the expression src into a matrix, if it wasn't already a plain matrix. To do so, use typename SrcDerived::PlainMatrixType The ultimate refinement is to make this foo() a thin wrapper around a function foo_impl() that is template only in the "plain matrix type" so that instantiating foo on many different Src types doesn't result in the whole code being instantiated everytime... template<typename SrcDerived, typename DstDerived> inline void foo(const MatrixBase<SrcDerived>& src, MatrixBase<DstDerived> *dst) { foo_impl(src, dst); } template<typename SrcMatrixType, typename DstDerived> void foo(const SrcMatrixType& src, MatrixBase<DstDerived> *dst) { foo_impl<typename SrcDerived::PlainMatrixType, DstDerived>(src, dst); } Of course that's not always needed, depends how your function is going to be used in practice, if it's big, etc. > > ### Design choices: > I should mention that in the FFT module, I've made a couple of design decisions that stray away from the behavior of most FFT libraries. The intent is to facilitate generic programming and ease migrating code from Matlab/octave. I've based these decisions on my experience both using FFTs and answering questions about KISSFFT. I think the default behavior of Eigen/FFT should favor correctness and generality over speed. Agree! > 1) Scaling: > Other libraries (FFTW,IMKL,KISSFFT) do not perform scaling, so there is a constant gain incurred after the forward&inverse transforms , so IFFT(FFT(x)) = Kx; this is done to avoid a vector-by-value multiply. The downside is that algorithms that worked correctly in Matlab/octave don't behave the same way once implemented in C++. I don't have the experience, but since you have, I believe that your solution can be more convenient in practice! This forces a retraversal of the array though so i wonder about the performance cost? First, O(N) is not that small compared to O(N log N) ; second, i'm concerned about the re-traversal of the array, which can be bad for caches on large data? By the way, you have room for improvement in the implementation of the scaling: by letting Eigen do it, you would have the vectorization. So this: Scalar s = 1./nfft; for (int k=0;k<nfft;++k) dst[k] *= s; becomes: Matrix<Scalar,Dynamic,1>::Map(dst, nfft) /= nfft; Likewise, in KissFFT, you can optimize scale(). > 2) Real FFT half-spectrum > Other libraries use only half the frequency spectrum (plus one extra sample for the Nyquist bin) for a real FFT, the other half is the conjugate-symmetric of the first half. This saves them a copy and some memory. The downside is the caller needs to have special logic for the number of bins in complex vs real. > > How Eigen/FFT differs: The full spectrum is returned from the forward transform. This facilitates generic template programming by obviating separate specializations for real vs complex. On the inverse transform, only half the spectrum is actually used if the output type is real. Again, i don't have the experience to express an opinion here. Now for more comments: * The size "nfft" is a runtime variable, which is great, but (honest naive question) isn't there also a use case for tiny sizes that are known at compile time? If yes, we can help making it work the Eigen way, the Eigen-ish approach is to add a NfftAtCompileTime parameter that can take the value Dynamic in which case the runtime variable nfft is used, otherwise it plays the role of the nfft variable. Of course that is a bit of work as there are template specializations to do to take advantage of the fixed size when possible. Also I understand that this probably would only affect the KissFFT backend. But it would then beat hands down all others, fixed size specializations mean 10x speed improvements. * The backend selection should IMO work like in the Sparse module: require the user to define a symbol to tell which backend to use, don't use whatever was included before Eigen. This way, there are no surprises, and it becomes possible to choose your backend for Eigen/FFT regardless of what you use in other parts of your program. (One thing though, Sparse uses #include"..." but that should be #include<....>, will fix this) * I'm uncomfortable about: typename _Traits=DEFAULT_FFT_IMPL<_Scalar> because 1) it's strange to have 'traits' as shorthand for an "impl", why not call it impl instead of traits, and 2) I don't think that there's a justification for using a macro here (a typedef would do) and 3) i'd rather have DEFAULT_FFT_IMPL be an integer (an enum) rather than a class name, and then the actual impl class could take that integer as template parameter and you would have partial template specializations for each possible value. It amounts to the same, but somehow feels cleaner to me. * We have a loose rule in Eigen that a "src" argument is a const reference, and a "dst" argument is a pointer. This helps the user catch a programming error where he mixes src and dst. Though at some places we have dst as a reference. What we don't have AFAIK is src as a pointer. Anyway you choose if it's a good rule in the context of your FFT module. That's all I can see for now ;) Feel free to push FFT to eigen/eigen2 when you want, since you put it in unsupported there's no reason not to import it. Do you want to get write access and push it, or should we pull it? As for when to move it to Eigen, I think that besides finishing the TODOs the main factors are if you think that you can commit to be the maintainer for this module, and if there are people starting to use it. Cheers, Benoit

**Follow-Ups**:**Re: [eigen] Eigen/FFT***From:*Benoit Jacob

**Re: [eigen] Eigen/FFT***From:*Rohit Garg

**Re: [eigen] Eigen/FFT***From:*Tim Hutt

**References**:**[eigen] Eigen/FFT***From:*Mark Borgerding

**Re: [eigen] Eigen/FFT***From:*Benoit Jacob

**Re: [eigen] Eigen/FFT***From:*Mark Borgerding

**Messages sorted by:**[ date | thread ]- Prev by Date:
**Re: [eigen] Eigen/FFT** - Next by Date:
**Re: [eigen] Eigen/FFT** - Previous by thread:
**Re: [eigen] Eigen/FFT** - Next by thread:
**Re: [eigen] Eigen/FFT**

Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |