Skip to content

Commit 51f93c6

Browse files
authored
add FFT and tests (keon#847)
1 parent e24247f commit 51f93c6

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

algorithms/maths/fft.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Implementation of the Cooley-Tukey, which is the most common FFT algorithm.
3+
4+
Input: an array of complex values which has a size of N, where N is an integer power of 2
5+
Output: an array of complex values which is the discrete fourier transform of the input
6+
7+
Example 1
8+
Input: [2.0+2j, 1.0+3j, 3.0+1j, 2.0+2j]
9+
Output: [8+8j, 2j, 2-2j, -2+0j]
10+
11+
12+
Pseudocode: https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
13+
"""
14+
from cmath import exp, pi
15+
16+
def fft(x):
17+
""" Recursive implementation of the Cooley-Tukey"""
18+
N = len(x)
19+
if N == 1:
20+
return x
21+
22+
# get the elements at even/odd indices
23+
even = fft(x[0::2])
24+
odd = fft(x[1::2])
25+
26+
y = [0 for i in range(N)]
27+
for k in range(N//2):
28+
q = exp(-2j*pi*k/N)*odd[k]
29+
y[k] = even[k] + q
30+
y[k + N//2] = even[k] - q
31+
32+
return y

tests/test_maths.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
diffie_hellman_key_exchange, krishnamurthy_number,
2727
num_perfect_squares,
2828
chinese_remainder_theorem,
29+
fft
2930
)
3031

3132
import unittest
@@ -556,5 +557,41 @@ def test_empty_lists(self):
556557
chinese_remainder_theorem.solve_chinese_remainder(num, rem)
557558

558559

560+
class TestFFT(unittest.TestCase):
561+
"""[summary]
562+
Test for the file fft.py
563+
564+
Arguments:
565+
unittest {[type]} -- [description]
566+
"""
567+
def test_real_numbers(self):
568+
x = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0]
569+
y = [4.000, 2.613, 0.000, 1.082, 0.000, 1.082, 0.000, 2.613]
570+
# abs(complex) returns the magnitude
571+
result = [float("%.3f" % abs(f)) for f in fft.fft(x)]
572+
self.assertEqual(result, y)
573+
574+
def test_all_zero(self):
575+
x = [0.0, 0.0, 0.0, 0.0]
576+
y = [0.0, 0.0, 0.0, 0.0]
577+
result = [float("%.1f" % abs(f)) for f in fft.fft(x)]
578+
self.assertEqual(result, y)
579+
580+
def test_all_ones(self):
581+
x = [1.0, 1.0, 1.0, 1.0]
582+
y = [4.0, 0.0, 0.0, 0.0]
583+
result = [float("%.1f" % abs(f)) for f in fft.fft(x)]
584+
self.assertEqual(result, y)
585+
586+
def test_complex_numbers(self):
587+
x = [2.0+2j, 1.0+3j, 3.0+1j, 2.0+2j]
588+
real = [8.0, 0.0, 2.0, -2.0]
589+
imag = [8.0, 2.0, -2.0, 0.0]
590+
realResult = [float("%.1f" % f.real) for f in fft.fft(x)]
591+
imagResult = [float("%.1f" % f.imag) for f in fft.fft(x)]
592+
self.assertEqual(real, realResult)
593+
self.assertEqual(imag, imagResult)
594+
595+
559596
if __name__ == "__main__":
560597
unittest.main()

0 commit comments

Comments
 (0)