<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Nov 18, 2013 at 3:35 PM, Oscar Benjamin <span dir="ltr"><<a href="mailto:oscar.j.benjamin@gmail.com" target="_blank">oscar.j.benjamin@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On 14 November 2013 17:19, David Cournapeau <<a href="mailto:cournape@gmail.com">cournape@gmail.com</a>> wrote:<br>

> On Thu, Nov 14, 2013 at 4:45 PM, Charles Waldman <<a href="mailto:charles@crunch.io">charles@crunch.io</a>> wrote:<br>
>><br>
>> Can you post the raw data?  It seems like there are just a couple of "bad"<br>
>> sizes, I'd like to know more precisely what these are.<br>
><br>
> Indeed. Several of the sizes generated by logspace(2, 7, 25) are prime<br>
> numbers, where numpy.fft is actually O(N^2) and not the usual O(NLogN).<br>
><br>
> There is unfortunately no freely (aka BSD-like licensed) available fft<br>
> implementation that works for prime (or 'close to prime') numbers, and<br>
> implementing one that is precise enough is not trivial (look at Bernstein<br>
> transform for more details).<br>
<br>
</div>I was interested by this comment as I wasn't aware of this aspect of<br>
numpy's fft function (or of fft algorithms in general). Having finally<br>
found a spare minute I've implemented the Bluestein algorithm based<br>
only on the Wikipedia page (feel free to use under any license<br>
including BSD).<br>
<br>
Is there anything wrong with the following? It's much faster for e.g.<br>
the prime size 215443 (~1s on this laptop; I didn't wait long enough<br>
to find out what numpy.fft.fft would take).<br>
<br>
from numpy import array, exp, pi, arange, concatenate<br>
from numpy.fft import fft, ifft<br>
<br>
def ceilpow2(N):<br>
    '''<br>
        >>> ceilpow2(15)<br>
        16<br>
        >>> ceilpow2(16)<br>
        16<br>
    '''<br>
    p = 1<br>
    while p < N:<br>
        p *= 2<br>
    return p<br>
<br>
def fftbs(x):<br>
    '''<br>
        >>> data = [1, 2, 5, 2, 5, 2, 3]<br>
        >>> from numpy.fft import fft<br>
        >>> from numpy import allclose<br>
        >>> from numpy.random import randn<br>
        >>> for n in range(1, 1000):<br>
        ...     data = randn(n)<br>
        ...     assert allclose(fft(data), fftbs(data))<br>
    '''<br>
    N = len(x)<br>
    x = array(x)<br>
<br>
    n = arange(N)<br>
    b = exp((1j*pi*n**2)/N)<br>
    a = x * b.conjugate()<br>
<br>
    M = ceilpow2(N) * 2<br>
    A = concatenate((a, [0] * (M - N)))<br>
    B = concatenate((b, [0] * (M - 2*N + 1), b[:0:-1]))<br>
    C = ifft(fft(A) * fft(B))<br>
    c = C[:N]<br>
    return b.conjugate() * c<br>
<br>
if __name__ == "__main__":<br>
    import doctest<br>
    doctest.testmod()<br>
<span class="HOEnZb"><font color="#888888"><br>
<br></font></span></blockquote><div><br></div><div>Where this starts to get tricky is when N is a product of primes not natively supported in fftpack. The fftpack supports primes 2, 3, 5, 7(?) at the moment, one would need to do initial transforms to break it down into a number of smaller transforms whose size would have prime factors supported by fftpack. Then use fftpack on each of those. Or the other way round, depending on taste.<br>
<br></div><div>Chuck   <br></div><br></div></div></div>