Source code for tryalgo.fft
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""\
Fast Fourier Transformation
christoph dürr - jill-jênn vie - 2022
"""
# http://www.cs.toronto.edu/~denisp/csc373/docs/tutorial3-adv-writeup.pdf
# https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
import math # for pi
import cmath # for exp
[docs]
def pad(x):
""" pad array x with zeros to make its length a power of two
:complexity: linear
"""
n = 1
while n < len(x):
n <<= 1
x += [0] * (n - len(x))
[docs]
def fft(x):
""" Fast Fourier Transformation
:input x: list of coefficients. Length n has to be a power of 2.
:returns: list of sample values.
:complexity: O(n log n).
"""
n2 = len(x) // 2
if n2 == 0:
return x
assert(2 * n2 == len(x)) # need to split evenly
even = fft(x[0::2])
odd = fft(x[1::2])
T = [cmath.exp(-1j * math.pi * k / n2) * odd[k] for k in range(n2)]
return [even[k] + T[k] for k in range(n2)] + \
[even[k] - T[k] for k in range(n2)]
[docs]
def inv_fft(y):
""" Inverse Fast Fourier Transformation
:input y: list of sample values. Length n has to be a power of 2.
:returns: list of coefficients.
:complexity: O(n log n).
"""
n = len(y)
p = fft([yi.conjugate() for yi in y])
return [pi.conjugate() / n for pi in p]
[docs]
def mul_poly_fft(p, q):
"""Multiply two polynomials in integer coefficient representation
:complexity: O(n log n)
"""
n = (len(p) + len(q)) # make them of same and enough large size
p += [0] * (n - len(p))
q += [0] * (n - len(q))
pad(p)
y = fft(p)
pad(q)
z = fft(q)
n = len(y) # the padding might have increased the size n
r = [y[i] * z[i] for i in range(n)]
R = inv_fft(r)
return [int(round(ri.real)) for ri in R]