Reputation: 1186
A couple of months ago I found out that convolutions are computed in the fastest possible way using the FFT algorithm (even more with the FFTW library)
Using the following code I have controversial results.
Imports
from scipy import fftpack
from numba import jit
Convolution with FFT:
def conv_fft(X, R):
n = len(X)
a = fftpack.fft(X)
b = fftpack.fft(R)
c = a * b
e = fftpack.ifft(c)
result = e[n]
return result
Convolution using the formula:
@jit(cache=True)
def conv(X, R):
n = len(X)
result = complex_type(0)
for i in range(n+1):
result += X[n-i] * R[i]
return result
This are critical functions in a much complex process, the difference arises only by using one version or the other.
no FFT with FFT increment
Test1 0.028761 0.034139 0.0053780
Test2 0.098565 0.103180 0.0046150
** the test2 computes more convolutions per test.*
The test show that the code with FFT is slower and I cannot see why since the fftpack apparently call the FFTW library which is "the fastest in the west"...
Any guidance is appreciated.
A conclusion for my is that the numba JIT compilation is unbelievably fast.
Upvotes: 2
Views: 468
Reputation: 5717
You're only returning a single value (the n:th one) of the convolution, not the full array. With FFT you always calculate all values, whereas in your conv function you only calculate the one you're after. Complexity-wise, the FFT is O(N*log(N)), and your implementation of conv is O(N). If you would implement a naive conv function that would return the full convolution, it would be O(N^2). So, if you want the full convoluted array your best bet is the FFT way of doing it. If you only want the n:th value, your method is complexity wise the best.
Upvotes: 2
Reputation: 11860
You should be able to get away with creating fewer temporary arrays, using this type of syntax, which should make it faster.
def conv_fft(X, R):
fftpack.fft(X, overwrite_x=True)
b = fftpack.fft(R)
X *= b
fftpack.ifft(X, overwrite_x=True)
return X
Upvotes: 0