-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInverse_Transform.py
194 lines (173 loc) · 6.65 KB
/
Inverse_Transform.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# Fast-Fourier-Transform-(FFT)
import math
import cmath
import numpy as np
from cmath import exp, pi
#################################################################################
def nthRootsOfUnity(n): #Calculates nth root of unity
theta = math.pi * 2 / n
real = math.cos(theta)
img = math.sin(theta)
z=complex(real,img) # e^j(theta) =cos(theta)+ j sin(theta)
return z
################################################################################
def FFT(polynomial): # The forward transform
n=len(polynomial)
if n==1: # base case
return polynomial
w=nthRootsOfUnity(n)
pe=[] #stores the even powers of the polynomial
for j in range(0,int(n/2)):
{
pe.append(polynomial[2*j])
}
po=[] #stores the odd powers of the polynomial
for j in range(0,int(n/2)):
{
po.append(polynomial[2*j+1])
}
#recursively traverse till you get degree-0 polynomials
ye=FFT(pe)
yo=FFT(po)
y=[0]*n #initialising the resultant list
#the main thing in this algo that saves time:
#we have basically just used the property 'that roots of unity change asymmetrically with a period of pi'
for j in range(0,int(n/2)):
y[j]=ye[j]+yo[j]*(pow(w,j))
y[j+int(n/2)]=ye[j]-yo[j]*(pow(w,j))
return(y) #return the result
########################################################################################################
def IFFT(polynomial): #The function for inverse transform
n=len(polynomial)
if n==1: #base case
return polynomial
w=nthRootsOfUnity1(n) #the power of FFT. With only 2 changes in code you can transform from forward transform to its inverse
pe=[]
for j in range(0,int(n/2)):
{
pe.append(polynomial[2*j])
}
po=[]
for j in range(0,int(n/2)):
{
po.append(polynomial[2*j+1])
}
ye=IFFT(pe)
yo=IFFT(po)
y=[0]*n
for j in range(0,int(n/2)):
y[j]=(ye[j]+yo[j]*(pow(w,j)))
y[j+int(n/2)]=(ye[j]-yo[j]*(pow(w,j)))
return(y)
###############################################################################################################
def nthRootsOfUnity1(n): # just a minor change to that of the above function. Here we will be using -(theta)
theta = math.pi * 2 / n
theta=(-1*theta)
real = round(math.cos(theta),2)
real=real
img = round(math.sin(theta),2)
img=img
z=complex(real,img)
return z
##################################################################################################################
#########################################################################################################
if __name__=='__main__':
n=list(map(int,input("Enter the coeffecients of polynomial 1 in increasing order of degree: ").strip().split()))
m=list(map(int,input("Enter the coeffecients of polynomial 2 in increasing order of degree: ").strip().split()))
#Appending 0 so that polynomial is represnted in powers of 2.
a=len(n)
b=len(m)
c=(a-1)*(b-1)+1
while math.log2(c)%1!=0:
c=c+1
while a<c:
a=a+1
n.append(0)
while b<c:
b=b+1
m.append(0)
######################################################################################################
print("The coeffecients of the entered polynomial 1 with number of terms in power of 2: ",n)
print("The coeffecients of the entered polynomial 2 with number of terms in power of 2: ",m)
y=FFT(n) #calling the forward transform
z=FFT(m) #calling the forward transform
#######################################################################################################
j=0 # this is a precision function as roots of unity can be irrational also
for img in y:
e=img.real
f=img.imag
if e==0:
f=round(f)
if(f==0):
e=round(e)
if e!=0 and f!=0:
e=round(e,2)
f=round(f,2)
img=complex(e,f)
y[j]=img
j=j+1
j=0 # this is a precision function as roots of unity can be irrational also
for img in z:
e=img.real
f=img.imag
if e==0:
f=round(f)
if(f==0):
e=round(e)
if e!=0 and f!=0:
e=round(e,2)
f=round(f,2)
img=complex(e,f)
z[j]=img
j=j+1
########################################################################################################
print("The forward transform of the entered polynomial 1: ",y)
print("The forward transform of the entered polynomial 2: ",z)
########################################################################################################
res=[] #stores the poinwise multiplication
for j in range(len(z)):
res.append(y[j]*z[j])
#######################################################################################################
j=0 #this is a precision function as roots of unity can be irrational also
for img in res:
e=img.real
f=img.imag
if e==0:
f=round(f)
if(f==0):
e=round(e)
if e!=0 and f!=0:
e=round(e,3)
f=round(f,3)
img=complex(e,f)
res[j]=img
j=j+1
##################################################################################################
print("The pointwise multiplication of the 2 entered polynomials",res) #pointwise multiplcation of the y-coordinates,the x-coordinates are the roots of unity
###################################################################################################
res1=IFFT(res) # calling the inverse transform
##########################################################################################
j=0 #Another precision function. The problem of irrationals sadly
for img in res1:
e=img.real
f=img.imag
if e==0:
f=round(f)
if(f==0):
e=round(e)
if e!=0 and f!=0:
e=round(e,2)
f=round(f,2)
img=complex(e,f)
res1[j]=img
j=j+1
########################################################################################
j=0 #Completing the inverse transform
for img in res1:
e=img.real
e=e*1/c #This is the second change w.r.t Forward transform. We have to even divide by n(which in this case will be the determinant of the state matrix of roots of unity)
e=round(e)
res1[j]=e
j=j+1
######################################################################################
print("The final polynomial m*n= ",res1) #Ah...finally the result