-
Notifications
You must be signed in to change notification settings - Fork 1
/
wino.py
116 lines (94 loc) · 3.14 KB
/
wino.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
import numpy as np
import numpy.linalg as la
import toom
# Polynomial Object that stores the coefficients in a vector
class Polynomial:
def __init__(self, coefficients):
self.coeffs = coefficients
# may have zero leading terms
max_idx = -1
for i in range(len(coefficients)):
if(coefficients[i] != 0):
max_idx = i
assert(max_idx >= 0)
self.degree = i
def get_coeffs(self):
return self.coeffs
def get_degree(self):
return self.degree
def poly_prod(p1,p2):
prod_poly = np.convolve(p1.get_coeffs(), p2.get_coeffs())
return Polynomial(prod_poly)
def get_all_poly_prod(p_list):
poly = p_list[0]
for i in range(1,len(p_list)):
poly = poly_prod(poly, p_list[i])
return poly
def get_all_poly_prod_except_i(p_list,i):
p_list2 = np.asarray([])
for j in range(len(p_list)):
if(j != i):
p_list2 = np.append(p_list2, p_list[j])
return get_all_poly_prod(p_list2)
def T_conv(poly,input_size):
p_coeffs = poly.get_coeffs()
p_num_coeffs = len(p_coeffs)
H = np.zeros((p_num_coeffs + input_size-1, input_size), dtype=complex)
for col_idx in range(input_size):
H[col_idx:col_idx + p_num_coeffs, col_idx] = p_coeffs
return H
def X_eval(m,input_deg):
deg_m = m.get_degree()
# trivial modulo
if(deg_m > input_deg):
X = np.zeros((deg_m,input_deg+1))
X[:input_deg+1,:input_deg+1] = np.eye(input_deg+1)
return X
T = T_conv(m,input_deg-deg_m+1)
L = T[:deg_m,:]; U = T[-(input_deg-deg_m+1):,:]
I = np.eye(deg_m)
return np.hstack([I, np.dot(-L,la.inv(U)) ])
def Ni_coeffs(M,m):
T_M = T_conv(M, m.get_degree())
T_m = T_conv(m, M.get_degree())
A = np.hstack([T_M,T_m])
b = np.zeros(A.shape[0]); b[0] = 1
N_coeffs = la.solve(A,b)[:T_M.shape[1]]
return Polynomial(N_coeffs)
def winograd_conv_mats(polys,r,n):
M = get_all_poly_prod(polys)
deg_M = M.get_degree()
A = None
B = None
C = None
first = True
for i,mi in enumerate(polys):
deg_m = mi.get_degree()
[A_i,B_i,C_i] = toom.toom_cook_mats(deg_m,deg_m)
# create matrix A
X = X_eval(mi,r-1)
A_i = np.dot(X.T,A_i)
A = (A_i if first else np.hstack([A,A_i]))
# create matrix B
X = X_eval(mi,n-1)
B_i = np.dot(X.T,B_i)
B = (B_i if first else np.hstack([B,B_i]))
# compute e_i = M_iN_i (no mod)
Mi = get_all_poly_prod_except_i(polys,i)
Ni = Ni_coeffs(Mi, mi)
e_i = poly_prod(Mi,Ni)
# compute e_i = M_iN_i mod M
T_i = X_eval(M,e_i.get_degree())
e_i_coeffs = np.dot(T_i,e_i.get_coeffs())
e_i_filler = np.zeros(deg_M, dtype=complex)
e_i_filler[:len(e_i_coeffs)] = e_i_coeffs
e_i = Polynomial(e_i_coeffs)
# bring it all together
T_ei = T_conv(e_i, deg_m)
X_M = X_eval(M, deg_M + deg_m - 2)
# create matrix C
X_m = X_eval(mi,2*deg_m-2)
C_i = np.dot( np.dot(X_M, T_ei), np.dot(X_m,C_i) )
C = (C_i if first else np.hstack([C,C_i]))
first = False
return [A,B,C]