Finally I get around to posting some python code. First I will post some snippets from my “polytope calculator” for
. Part 2 will have some snippets from a program I’m writing to check my results.
I’m trying to figure out the best way to post the whole code. I was going to use Launchpad (since I used quickly to write the program) but I’ve been having some trouble with that. So I might end up just uploading the *.py to either my umich or math.northwestern accounts.
First I define an object called a “polytope half” that uses three lists of integers to represents a single path through the polytope. (In the two dimensional case each polytope only has two paths so one constitutes a polytope half). There are several methods implemented (or partially implemented) for this object including “__add__” which gives the convex hull of to paths. The “FIX ME” is because I haven’t yet implemented the merger of the side partitions. (It shouldn’t be too difficult, I simply haven’t gotten around to it.)
class Polytopehalf:
"""Only 'half' if the polytope is 2 dimensionsl. Really an i-lusztig datum
though we don't specify i. For sl3 this should be 3 non-negative integers.
for Lsl2 this should be 2 sequences (each of arbitrary finite length) of
non-negative integers and a multiset of positive integers.
This program only implements for Lsl2.
"""
def __init__(self,bottom=[],top=[],side=[]):
self.bottom = bottom
self.top = top
self.side = side
def weight(self):
"""returns the projecton of the weight to the sl2 component
assumes the polytope half is the right hand side"""
return sum(self.bottom)-sum(self.top)
def increment(self):
"""advancing in the crystal structure - relative to the chosen i-Lustig path"""
self.top=[0]+self.top
self.top[-1]+=1
def flip(self):
"""tells how this i-Lustig path effects other paths during iteration
this process may insert a negative number!"""
self.top=[0]+self.top
self.bottom.append(-2*self.weight()-self.top.pop())
def __add__(self,other):
"""takes the convex hull of the two halfs -- currently expects the paths align at top and bottom
this needs to be fixed because this is *not* typical """
Out=Polytopehalf()
#Pad to be the same length.
diff=len(self.top)-len(other.top)
if diff>0:
other.top=[0]*(diff+1)+other.top
self.top=[0]+self.top
else:
self.top=[0]*(1-diff)+self.top
other.top=[0]+other.top
#calculate displacements this is necessary as the tops of the polytopes do not align
d1=0
d2=0
for i in range(len(self.bottom)):
d1-=self.bottom[-i-1]*i
d2-=self.bottom[-i-1]
for i in range(len(self.top)):
d1-=self.top[-i-1]*(i+1)
d2+=self.top[-i-1]
for i in range(len(other.bottom)):
d1+=other.bottom[-i-1]*i
d2+=other.bottom[-i-1]
for i in range(len(other.top)):
d1+=other.top[-i-1]*(i+1)
d2-=other.top[-i-1]
for i in range(len(self.side)):
d1-=self.side[-i-1]*(i+1)
for i in range(len(other.side)):
d1+=other.side[-i-1]*(i+1)
Disp1=[0,0]
Disp2=[d1,d1+d2]
for i in range(len(self.top)):
Disp1.append(2*Disp1[-1]+self.top[-i-1]-Disp1[-2])
Disp2.append(2*Disp2[-1]+other.top[-i-1]-Disp2[-2])
D1=Disp1[-1]-Disp1[-2]
D2=Disp2[-1]-Disp2[-2]
while (Disp1[-1]-Disp2[-1])*(D1-D2)<=0 and (D1-D2)0:
Disp1.append(Disp1[-1]+D1)
Disp2.append(Disp2[-1]+D2)
Disp=map(max,Disp1,Disp2)
for i in range(1,len(Disp)-1):
Out.top=[Disp[i-1]+Disp[i+1]-2*Disp[i]]+Out.top
#Pad to the same length
diff=len(self.bottom)-len(other.bottom)
if diff>0:
other.bottom=[0]*(diff+1)+other.bottom
self.bottom=[0]+self.bottom
else:
self.bottom=[0]*(1-diff)+self.bottom
other.bottom=[0]+other.bottom
Disp1=[0,0]
Disp2=[0,0]
for i in range(len(self.bottom)):
Disp1.append(2*Disp1[-1]+self.bottom[-i-1]-Disp1[-2])
Disp2.append(2*Disp2[-1]+other.bottom[-i-1]-Disp2[-2])
D1=Disp1[-1]-Disp1[-2]
D2=Disp2[-1]-Disp2[-2]
while (Disp1[-1]-Disp2[-1])*(D1-D2)<=0 and (D1-D2)0:
Disp1.append(Disp1[-1]+D1)
Disp2.append(Disp2[-1]+D2)
Disp=map(max,Disp1,Disp2)
for i in range(1,len(Disp)-1):
Out.bottom=[Disp[i-1]+Disp[i+1]-2*Disp[i]]+Out.bottom
if sum(self.bottom)>sum(other.bottom):
Out.side=self.side
elif sum(self.bottom)<sum(other.bottom):
Out.side=other.side
elif sum(self.bottom)==sum(other.bottom):
b1=0
b2=0
p1=0
p2=0
for i in range(len(self.bottom)):
b1+=self.bottom[-i-1]*i
b2+=other.bottom[-i-1]*i
for i in range(len(self.side)):
p1+=self.side[-i-1]*(i+1)
for i in range(len(other.side)):
p2+=other.side[-i-1]*(i+1)
p=max(b1+p1,b2+p2)-min(b1,b2)
Out.side=[p] #FIXME
#Trim unnecessary zeros
Out.top.reverse()
while len(Out.top) and Out.top[-1]==0:
Out.top.pop()
Out.top.reverse()
Out.bottom.reverse()
while len(Out.bottom) and Out.bottom[-1]==0:
Out.bottom.pop()
Out.bottom.reverse()
return Out
I also create a full “polytope” class that contains two polytope halves (“Left” and “Right”) and a method for retrieving all the “points” of a polytope by going round the perimeter. An unfortunate side effect of doing things this way is that python stores lists as pointers so copying a polytope (and not merely creating another name that points to the same data) is a bit of a pain.
Inside my main instance I have two functions “itereate left” and “iterate right” linked to buttons on the GUI:
def iterate_right(self,button):
#increment
self.Polytope.Left.increment()
temp=copy.deepcopy(self.Polytope.Left)
#reflect
temp.flip()
#convex hull
self.Polytope.Right+=temp
self.builder.get_object("drawingarea1").queue_resize()
This method of incrementing, reflecting and taking convex hull is proven to work for
and conjectured to work for
. The current polytope being diplayed in window is “self.Polytope”. Since iterating changes the polytope I get the drawing area to refresh by sending it a “queue_resize” signal.