| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- # See also https://cp-algorithms.com/algebra/fft.html
- q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
- K = GF(q)
- P.<X> = K[]
- def get_omega():
- generator = K(5)
- assert (q - 1) % 2^32 == 0
- # Root of unity
- t = (q - 1) / 2^32
- omega = generator**t
- assert omega != 1
- assert omega^(2^16) != 1
- assert omega^(2^31) != 1
- assert omega^(2^32) == 1
- return omega
- # Order of this element is 2^32
- omega = get_omega()
- k = 3
- n = 2^k
- omega = omega^(2^32 / n)
- assert omega^n == 1
- f = 6*X^7 + 7*X^5 + 3*X^2 + X
- def fft(F):
- print(f"fft({F})")
- # On the first invocation:
- #assert len(F) == n
- N = len(F)
- if N == 1:
- print(" returning 1")
- return F
- omega_prime = omega^(n/N)
- assert omega_prime^(n - 1) != 1
- assert omega_prime^N == 1
- # Split into even and odd powers of X
- F_e = [a for a in F[::2]]
- print(" Evens:", F_e)
- F_o = [a for a in F[1::2]]
- print(" Odds:", F_o)
- y_e, y_o = fft(F_e), fft(F_o)
- print(f"y_e = {y_e}, y_o = {y_o}")
- y = [0] * N
- for j in range(N / 2):
- y[j] = y_e[j] + omega_prime^j * y_o[j]
- y[j + N / 2] = y_e[j] - omega_prime^j * y_o[j]
- print(f" returning y = {y}")
- return y
- print("f =", f)
- evals = fft(list(f))
- print("evals =", evals)
- print("{omega^i : i in {0, 1, ..., n - 1}} =", [omega^i for i in range(n)])
- evals2 = [f(omega^i) for i in range(n)]
- print("{f(omega^i) for all omega^i} =", evals2)
- assert evals == evals2
|