-
Notifications
You must be signed in to change notification settings - Fork 0
/
cluster_seed.py
201 lines (175 loc) · 7.64 KB
/
cluster_seed.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
195
196
197
198
199
200
201
import time
from sage.matrix.matrix import Matrix
class ClusterSeed2(SageObject):
def __init__(self, data):
if isinstance(data, Matrix):
self._B0 = copy(data) #needed for cluster variables
self._m = self._B0.nrows() #needed for cluster variables
self._n = self._B0.ncols()
self._B = copy(self._B0[:self._n,:self._n])
if not self._B.is_skew_symmetrizable(positive=True):
raise ValueError('data must have skew-symmetrizable principal part.')
self._C = identity_matrix(self._n)
self._G = identity_matrix(self._n)
self._U = PolynomialRing(QQ,['u%s'%i for i in xrange(self._n)])
self._F = dict([ (i,self._U(1)) for i in xrange(self._n) ])
self._F_dict = dict([ (tuple(self._G.column(i)),self._U(1)) for i in xrange(self._n) ])
self._R = PolynomialRing(QQ,['x%s'%i for i in xrange(self._m)]) #needed for cluster variables
self._y = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._B0[i,j] for i in xrange(self._n,self._m)])) for j in xrange(self._n)]) #needed for cluster variables
self._yhat = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._B0[i,j] for i in xrange(self._m)])) for j in xrange(self._n)]) #needed for cluster variables
# at the moment we only deal with b_matrices
else:
raise NotImplementedError('At the moment we only deal with matrices.')
def __copy__(self):
other = type(self).__new__(type(self))
other._B0 = copy(self._B0)
other._n = self._n
other._m = self._m
other._B = copy(self._B)
other._C = copy(self._C)
other._G = copy(self._G)
other._U = copy(self._U)
other._F = copy(self._F)
other._F_dict = self._F_dict
other._R = copy(self._R)
other._y = copy(self._y)
other._yhat = copy(self._yhat)
return other
def mutate(self, sequence, inplace=True, mutating_F=True):
if not isinstance(inplace, bool):
raise ValueError('inplace must be boolean.')
if inplace:
seed = self
else:
seed = copy(self)
if sequence in xrange(seed._n):
seq = iter([sequence])
else:
seq = iter(sequence)
for k in seq:
if k not in xrange(seed._n):
raise ValueError('Cannot mutate in direction' + str(k) + '.')
# G-matrix
J = identity_matrix(seed._n)
if any(x > 0 for x in seed._C.column(k)):
eps = +1
else:
eps = -1
for j in xrange(seed._n):
J[j,k] += max(0, -eps*seed._B[j,k])
J[k,k] = -1
seed._G = seed._G*J
# F-polynomials
if mutating_F:
gvect = tuple(seed._G.column(k))
if not self._F_dict.has_key(gvect):
self._F_dict.setdefault(gvect,self._mutated_F(k))
seed._F[k] = self._F_dict[gvect]
# C-matrix
J = identity_matrix(seed._n)
if any(x > 0 for x in seed._C.column(k)):
eps = +1
else:
eps = -1
for j in xrange(seed._n):
J[k,j] += max(0, eps*seed._B[k,j])
J[k,k] = -1
seed._C = seed._C*J
# B-matrix
seed._B.mutate(k)
if not inplace:
return seed
def _mutated_F(self, k):
pos = self._U(1)
neg = self._U(1)
for j in xrange(self._n):
if self._C[j,k] > 0:
pos *= self._U.gen(j)**self._C[j,k]
else:
neg *= self._U.gen(j)**(-self._C[j,k])
if self._B[j,k] > 0:
pos *= self._F[j]**self._B[j,k]
else:
neg *= self._F[j]**(-self._B[j,k])
return (pos+neg)//self._F[k]
def find_cluster_variables(self, glist_tofind=[], num_mutations=infinity):
MCI = self.mutation_class_iter()
mutation_counter = 0
## the last check should be done more efficiently
while mutation_counter < num_mutations and (glist_tofind == [] or not Set(glist_tofind).issubset(Set(self._F_dict.keys()))):
try:
MCI.next()
except:
break
mutation_counter += 1
print "Found after "+str(mutation_counter)+" mutations."
def mutation_class_iter(self, depth=infinity, show_depth=False, return_paths=False, up_to_equivalence=True, only_sink_source=False):
depth_counter = 0
n = self._n
timer = time.time()
if return_paths:
yield (self,[])
else:
yield self
if up_to_equivalence:
cl = Set(self._G.columns())
else:
cl = tuple(self._G.columns())
clusters = {}
clusters[ cl ] = [ self, range(n), [] ]
gets_bigger = True
if show_depth:
timer2 = time.time()
dc = str(depth_counter)
dc += ' ' * (5-len(dc))
nr = str(len(clusters))
nr += ' ' * (10-len(nr))
print "Depth: %s found: %s Time: %.2f s"%(dc,nr,timer2-timer)
while gets_bigger and depth_counter < depth:
gets_bigger = False
keys = clusters.keys()
for key in keys:
sd = clusters[key]
while sd[1]:
i = sd[1].pop()
if not only_sink_source or all( entry >= 0 for entry in sd[0]._B.row( i ) ) or all( entry <= 0 for entry in sd[0]._B.row( i ) ):
sd2 = sd[0].mutate( i, inplace=False )
if up_to_equivalence:
cl2 = Set(sd2._G.columns())
else:
cl2 = tuple(sd2._G.columns())
if cl2 in clusters:
if not up_to_equivalence and i in clusters[cl2][1]:
clusters[cl2][1].remove(i)
else:
gets_bigger = True
if only_sink_source:
orbits = range(n)
else:
orbits = [ index for index in xrange(n) if index > i or sd2._B[index,i] != 0 ]
clusters[ cl2 ] = [ sd2, orbits, clusters[key][2]+[i] ]
if return_paths:
yield (sd2,clusters[cl2][2])
else:
yield sd2
depth_counter += 1
if show_depth and gets_bigger:
timer2 = time.time()
dc = str(depth_counter)
dc += ' ' * (5-len(dc))
nr = str(len(clusters))
nr += ' ' * (10-len(nr))
print "Depth: %s found: %s Time: %.2f s"%(dc,nr,timer2-timer)
def cluster_variable(self, k):
if k in range(self._n):
g_mon = prod([self._R.gen(i)**self._G[i,k] for i in xrange(self._n)])
F_std = self._F[k].subs(self._yhat)
F_trop = self._F[k].subs(self._y).denominator()
return g_mon*F_std*F_trop
if isinstance(k,tuple):
if not k in self._F_dict.keys():
self.find_cluster_variables([k])
g_mon = prod([self._R.gen(i)**k[i] for i in xrange(self._n)])
F_std = self._F_dict[k].subs(self._yhat)
F_trop = self._F_dict[k].subs(self._y).denominator()
return g_mon*F_std*F_trop