This is the code used to find the global dimensions of endomorphism rings of modules over E6.
Using the notation of Yoshino (1990) for the indecomposable modules, the correspondence between vertices of the quiver used here and indecomposable modules is as follows:
0 - R
1 - M1
2 - B
3 - X
4 - M2
5 - A
6 - N1
7 - (Zero module)
-------------
import sys
#These routines switch between representing a module as a vector with a summand's multiplicity in the corresponding position (i.e. (1,0,2,0)) or as a list of indecomposable summands (i.e. [0,2,2])
def veckter(a,n):
 
 
 
 
zippy = zero_vector(ZZ,n)
 
 
 
 
if type(a) == Integer or type(a) == int:
 
 
 
 
 
 
 
 
zippy[a] = 1
 
 
 
 
elif type(a) == list:
 
 
 
 
 
 
 
 
for i in a:
 
 
 
 
 
 
 
 
 
 
 
 
zippy = zippy + veckter(i,n)
 
 
 
 
return zippy
def vertecks(v):
 
 
 
 
listy = []
 
 
 
 
for i in [0..len(v)-1]:
 
 
 
 
 
 
 
 
if v[i] >= 1:
 
 
 
 
 
 
 
 
 
 
 
 
for n in [1..v[i]]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
listy.append(i)
 
 
 
 
if len(listy) == 1:
 
 
 
 
 
 
 
 
return listy[0]
 
 
 
 
else:
 
 
 
 
 
 
 
 
return listy
#Changes all positive entries of a vector to one, to represent a module up to multiplicities of its summands.
def haircut(v):
 
 
 
 
h = zero_vector(len(v))
 
 
 
 
for i in [0..len(h)-1]:
 
 
 
 
 
 
 
 
if v[i] > 0:
 
 
 
 
 
 
 
 
 
 
 
 
h[i] = 1
 
 
 
 
return h
 
 
 
 
#This is the AR quiver of E6
E6 = DiGraph(matrix([[0,1,0,0,0,0,0,0],[0,0,0,0,0,1,0,1],[0,1,0,1,0,0,0,0],[0,0,1,0,1,1,0,0],[0,0,0,1,0,0,0,0],[0,0,0,1,0,0,1,0],[1,0,1,0,0,0,0,0],[0,0,0,0,0,0,1,0]]))
#Here we construct a matrix to represent the AR translate
tau = matrix([[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,1,0],[0,0,0,0,0,1,0,0],[0,0,0,1,0,0,0,0],[0,0,0,0,1,0,0,0],[0,0,1,0,0,0,0,0],[0,1,0,0,0,0,0,0],[1,0,0,0,0,0,0,0]])
#A routine to approximate one indecomposable module.
#Parameters:
#v: The number of the vertex in the AR quiver corresponding to the module to be approximated
#G: The AR quiver
#tau: The AR translate matrix
#S: The set of modulesto be used in the approximation
def approxOne(v,G,tau,S):
 
 
 
 
 
 
 
 
#Defining variables:
 
 
 
 
q = len(G)
 
 
 
 
n = q - 1
 
 
 
 
 
 
 
 
#The current number of vertices of the graph ("the graph" being the finite portion of the universal cover of the AR quiver which we are working with)
 
 
 
 
vertNum = 1
 
 
 
 
 
 
 
#The level of the graph which is currently being numbered
 
 
 
 
curlev = 1
 
 
 
 
#A list used to match a vertex with its level - if vertex a is at level b, then levels[a] == b
 
 
 
 
levels = [1]
 
 
 
 
#A list showing which modules of the AR quiver each vertex is identified with
 
 
 
 
ids = [v]
 
 
 
 
#A finite portion of the graph
 
 
 
 
UC = DiGraph(1)
 
 
 
 
#Adjacency matrix of the AR quiver
 
 
 
 
arqMat = G.adjacency_matrix()
 
 
 
 
#A list recording the numbers of the vertices - mults[i] is the number of vertex i
 
 
 
 
mults = [1]
 
 
 
 
#The kernel and middle term of the approximation, represented as vectors
 
 
 
 
ker = zero_vector(ZZ,n)
 
 
 
 
midterm = zero_vector(ZZ,n)
 
 
 
 
 
 
 
 
#A list of all vertices at level l of the graph
 
 
 
 
def levlist(l):
 
 
 
 
 
 
 
 
laval = []
 
 
 
 
 
 
 
 
for i in [0..len(levels)-1]:
 
 
 
 
 
 
 
 
 
 
 
 
if levels[i] == l:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
laval.append(i)
 
 
 
 
 
 
 
 
return laval
 
 
 
 
 
 
 
 
#Finds the inverse AR translate of a vertex
 
 
 
 
def tauf(w):
 
 
 
 
 
 
 
 
lev = levels[w]
 
 
 
 
 
 
 
 
#If the vertex's inverse AR translate is outside the portion of the graph we've constructed, the value None is returned (vertices outside the constructed portion are all numbered zero)
 
 
 
 
 
 
 
 
if lev - 2 <= 0:
 
 
 
 
 
 
 
 
 
 
 
 
return None
 
 
 
 
 
 
 
 
for i in levlist(lev-2):
 
 
 
 
 
 
 
 
 
 
 
 
if ids[i] == vertecks(veckter(ids[w],q)*tau):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return i
 
 
 
 
 
 
 
 
return None
 
 
 
 
 
 
 
 
#Determines whether a vertex is numbered zero or otherwise treated as zero
 
 
 
 
def isZip(w):
 
 
 
 
 
 
 
 
return (mults[w] <= 0 or ids[w] == n or (ids[w] in S and w != 0))
 
 
 
 
 
 
 
 
#Determines whether the current and previous levels are both full of zeros (in which case we can stop the algorithm)
 
 
 
 
def stop():
 
 
 
 
 
 
 
 
redlight = true
 
 
 
 
 
 
 
 
for w in levlist(curlev):
 
 
 
 
 
 
 
 
 
 
 
 
if isZip(w) == false:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
redlight = false
 
 
 
 
 
 
 
 
for w in levlist(curlev-1):
 
 
 
 
 
 
 
 
 
 
 
 
if isZip(w) == false:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
redlight = false
 
 
 
 
 
 
 
 
return redlight
 
 
 
 
 
 
 
 
 
 
 
 
#This loop adds a new level to the graph
 
 
 
 
while stop() == false:
 
 
 
 
 
 
 
 
for u in levlist(curlev):
 
 
 
 
 
 
 
 
 
 
 
 
#Identifying predecessors of vertex u
 
 
 
 
 
 
 
 
 
 
 
 
old = ids[u]
 
 
 
 
 
 
 
 
 
 
 
 
nextsteps = arqMat*veckter(old,q)
 
 
 
 
 
 
 
 
 
 
 
 
#Checking whether a vertex corresponding to a particular predecessor i has already been added
 
 
 
 
 
 
 
 
 
 
 
 
for i in [0..q-1]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if nextsteps[i] == 1:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
make = true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
for t in levlist(curlev + 1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if ids[t] == i:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#If a vertex corresponding to i has already been added to the next level, we don't create another, but simply connect that vertex to u
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
UC.add_edge(t,u)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
make = false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if make:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#Adding another vertex to the next level, corresponding to the predecessor i, and connecting it to u
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
UC.add_vertex(vertNum)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
UC.add_edge(vertNum,u)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#Updating relevant lists to record the new vertex
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ids.append(i)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
levels.append(curlev + 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mults.append(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vertNum = vertNum + 1
 
 
 
 
 
 
 
 
#Updating the current level
 
 
 
 
 
 
 
 
curlev = curlev + 1
 
 
 
 
 
 
 
 
#Now we number each vertex on the current level
 
 
 
 
 
 
 
 
ucMat = UC.adjacency_matrix()
 
 
 
 
 
 
 
 
for w in levlist(curlev):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#The terms to be added and subtracted to obtain the number of v
               
 
 
 
 
middle = 0
 
 
 
 
 
 
 
 
 
 
 
 
back = 0
               
 
 
 
 
#A list of successors of vertex w, represented as a vector (e.g. [0,1,0,1] if the successors are 1 and 3)
 
 
 
 
 
 
 
 
 
 
 
 
right = veckter(w,len(UC))*ucMat
 
 
 
 
 
 
 
 
 
 
 
 
for x in [0..len(right)-1]:
               
               
#If vertex x is a successor of w and its number is not treated as zero, its number is added
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if right[x] == 1 and isZip(x) == false:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
middle = middle + mults[x]
 
 
 
 
 
 
 
 
 
 
 
 
#The number of the inverse AR translate of w is subtracted
               
 
 
 
 
t = tauf(w)
 
 
 
 
 
 
 
 
 
 
 
 
if t != None and isZip(t) == false:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
back = mults[t]
               
 
 
 
 
#The number of w is calculated
 
 
 
 
 
 
 
 
 
 
 
 
mults[w] = middle - back
               
 
 
 
 
#If w has a negative number and is not associated with the zero module, the multiplicity of its corresponding module in the kernel is increased by the negative of its number
 
 
 
 
 
 
 
 
 
 
 
 
if ids[w] != n and mults[w] < 0:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ker[ids[w]] = ker[ids[w]] - mults[w]
 
 
 
 
 
 
 
 
 
 
 
 
#If w has a positive number and is associated with a module in S, the multiplicity of its corresponding module in the kernel is increased by its number
 
 
 
 
 
 
 
 
 
 
 
 
elif ids[w] in S:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
midterm[ids[w]] = midterm[ids[w]] + mults[w]
 
 
 
 
 
 
 
 
#The first two terms of the approximation, represented as vectors, are returned
 
 
 
 
return [ker,midterm]
#Approximates a sum of indecomposable modules, represented as a list of summands
def approx(v,G,tau,S):
 
 
 
 
if type(v) != list:
 
 
 
 
 
 
 
 
return approx([v],G,tau,S)
 
 
 
 
seq = zero_matrix(2,len(G)-1)
 
 
 
 
for i in v:
 
 
 
 
 
 
 
 
seq = seq + Matrix(approxOne(i,G,tau,S))
 
 
 
 
return list(seq)
#Checks whether a sum of indecomposable modules, represented as a vector, contains only summands in the set S
def okay(v,S):
 
 
 
 
o = true
 
 
 
 
for i in [0..len(v)-1]:
 
 
 
 
 
 
 
 
if (i in S or v[i] == 0)==false:
 
 
 
 
 
 
 
 
 
 
 
 
o = false
 
 
 
 
return o
#Computes approximations recursively and splices them together until we obtain an approximation of v in terms of modules in S only, or detect an infinite repeating patern.
def recur(v,G,tau,S):
 
 
 
 
#A list of modules not in S that have appeared in kernels of approximations
 
 
 
 
archive = []
 
 
 
 
#The first approximation of v, represented as a list of its terms in the form of vectors
 
 
 
 
T = list(approx(v,G,tau,S))
 
 
 
 
n = len(T[0])
 
 
 
 
#If the kernel contains terms not in S, we must approximate those terms
 
 
 
 
while okay(T[0],S)==false:
 
 
 
 
 
 
 
 
#A list of summands of the kernel, not in S
 
 
 
 
 
 
 
 
bads = list(zero_vector(ZZ,n))
 
 
 
 
 
 
 
 
for i in [0..n-1]:
 
 
 
 
 
 
 
 
 
 
 
 
#If a module i has a nonzero multiplicity in the kernel and is not in S, it must be approximated.
 
 
 
 
 
 
 
 
 
 
 
 
if (T[0][i] > 0) and ((i in S) == false):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bads[i] = bads[i] + T[0][i]
 
 
 
 
 
 
 
 
#If the set of modules to be approximated is identical to one which has occurred at a previous step of the approximation (up to multiplicities), then the approximation is infinite, so the value None is returned.
 
 
 
 
 
 
 
 
bads = haircut(bads)
 
 
 
 
 
 
 
 
if bads in archive:
 
 
 
 
 
 
 
 
 
 
 
 
return
 
 
 
 
 
 
 
 
else:
 
 
 
 
 
 
 
 
 
 
 
 
#If the set of modules to be approximated has not appeared previously, it is added to the archive so that the pattern can be detected if it appears again in a subsequent step.
 
 
 
 
 
 
 
 
 
 
 
 
archive.append(bads)
 
 
 
 
 
 
 
 
#The summands of the kernel not in S are approximated, and this sequence is spliced together with the previous approximation
 
 
 
 
 
 
 
 
goods = T[0] - vector(bads)
 
 
 
 
 
 
 
 
newprox = list(approx(vertecks(bads),G,tau,S))
 
 
 
 
 
 
 
 
newprox[1] = newprox[1] + goods
 
 
 
 
 
 
 
 
for w in [1..len(T)-1]:
 
 
 
 
 
 
 
 
 
 
 
 
newprox.append(T[w])
 
 
 
 
 
 
 
 
T = newprox
 
 
 
 
return T
#Approximates all modules of a set S, using the modules of S
def allMods(G,tau,S):
 
 
 
 
proxList = []
 
 
 
 
for m in list(S):
 
 
 
 
 
 
 
 
proxList.append(recur(m,G,tau,S))
 
 
 
 
return proxList
#Computes the global dimensions of the endomorphism rings of all modules over the ring with AR quiver G and AR translate tau
def allSubsets(G,tau):
 
 
 
 
#A list of finite global dimensions that have ocurred
 
 
 
 
ll = []
 
 
 
 
#The modules over the ring correspond to subsets of the nonzero modules in the AR quiver
 
 
 
 
for l in powerset(set([0..len(G)-2])):
 
 
 
 
 
 
 
 
S = set(l)
               
#The maximum length of approximations of indecomposable summands of the module l computed so far
 
 
 
 
 
 
 
 
ML = 0
 
 
 
 
 
 
 
 
if S == set([]):
 
 
 
 
 
 
 
 
 
 
 
 
allClear = false
 
 
 
 
 
 
 
 
else:
 
 
 
 
 
 
 
 
 
 
 
 
allClear = true
 
 
 
 
 
 
 
 
for m in l:
               
 
 
 
 
#The approximation of indecomposable module m is computed
 
 
 
 
 
 
 
 
 
 
 
 
r = recur(m,G,tau,S)
 
 
 
 
 
 
 
 
 
 
 
 
if r == None:
               
               
#If the approximation was infinte, the global dimension of the endomorphism ring will be infinite as well
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
allClear = false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
break
 
 
 
 
 
 
 
 
 
 
 
 
else:
               
               
#Finding the length of the approximation and updating the maximum length, if necessary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ml = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
for a in r:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if a != 0:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ml = ml + 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if ml > ML:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ML = ml
               
#If all approximations are found to be finite and the global dimension has not occurred previously, it is added to the list (actually I made a mistake in writing this part, and the length of the longest finite chain is added even if the global dimension is infinite; however, we later did a more detailed breakdown of the finite global dimensions which made this part of the code superfluous anyway. One could correct this error by putting this section of the code inside the next one, after "if allClear:"
 
 
 
 
 
 
 
 
if (ML in ll) == false:
 
 
 
 
 
 
 
 
 
 
 
 
ll.append(ML)
               
#If all approximations are found to be finite, the module, represented as a set of its indecomposable summands, is printed, along with its global dimension (the maximum length of approximations)
 
 
 
 
 
 
 
 
if allClear:
 
 
 
 
 
 
 
 
 
 
 
 
print S
 
 
 
 
 
 
 
 
 
 
 
 
print 'max length: ', ML
 
 
 
 
 
 
 
 
 
 
 
 
sys.stdout.flush()
 
 
 
 
#The list of all global dimensions that occurred is printed
 
 
 
 
print 'Global Dimensions: ', ll
#A method to compute the minimal length of projective resolutions for a particular indecomposable summand of a particular module.
def projdim(v,G,tau,S):
 
 
 
 
seq = recur(v,G,tau,S)
 
 
 
 
if seq == None:
 
 
 
 
 
 
 
 
return infinity
 
 
 
 
elif seq[0] == zero_vector(len(seq[0])):
 
 
 
 
 
 
 
 
return len(seq) -1
 
 
 
 
else:
 
 
 
 
 
 
 
 
return len(recur(v,G,tau,S))
#A method to compute the global dimension of the endomorphism ring of one module.
def gldim(G,tau,S):
 
 
 
 
dims = []
 
 
 
 
for v in S:
 
 
 
 
 
 
 
 
dims.append(projdim(v,G,tau,S))
 
 
 
 
return max(dims)