import scipy import scipy.linalg import math """ A code to simplify calculation of BKL billiard systems based on three-dimensional coset models. By Daniel H. Wesley D.H.Wesley at damtp.cam.ac.uk If this code is used in your research, please cite: "Coxeter group structure of cosmological billiards on compact spatial manifolds" Marc Henneaux, Daniel Persson, Daniel H. Wesley (to appear) """ class Billiard: def __init__(self, d, forms, dil=True ): """ d: spatial dimensions forms: a list of tuples (p, lamb, label) dil: True if dilaton, False if no dilaton Given this information, the class constructs the gravitational, symmetry, and p-form walls corresponding to this billiard. The walls themselves are stored as 1D SciPy arrays for easy manip- ulation. The p-forms must be labelled to make things easier: Labels are just strings that are carried along for the ride. Ordering of the labels is important. For p-forms, the letter "E" or "B" is prepended to the label given depending on whether the electric or magnetic components are being discussed. All of the couplings and so on are assumed to be in the Einstein frame. This allows the study of theories with and without dilatons in a single framework. Note that only one dilaton is currently supported. The caller has to manually set the dominant walls. This can be done by just setting which labelled walls one wants to have in the dominant wall set. """ self.d = d self.forms = forms self.dil = dil # This has to be done manually, since it isn't clear # algorithmically how one selects the dominant walls. self.domWallMatrix = None # This is a dictionary holding the map between the label for # and the wall itself. Newly created walls should register # themselves here. self.walls = { } self.domWallLabels = [] self.domWalls = [] self.coweightMatrix = None self.makeWalls() def makeWalls(self): """ This function makes all of the wall types. """ self.makeSWalls() self.makeEWalls() self.makeBWalls() self.makeGWalls() def makeSWalls(self): """ Make the symmetry walls, starting from beta^2-beta^1 up to beta^d-beta^(d-1) """ # These go from w2 = \beta^2 - \beta^1 all the way # to \beta^d - \beta^{d-1} sWalls = [] for j in range(2,self.d+1): new_wall = self.makeSWall(j) new_wall_label = self.makeSymName(j) sWalls.append( new_wall ) self.walls[ new_wall_label ] = new_wall self.sWalls = sWalls def makeSWall(self, j): """ Make the symmetry wall with \beta^j - (etc) """ if ( (j>self.d) or (j<2) ): return None if self.dil: wall = [0.] # first component is always for the scalar else: wall = [] niz = j-2 # digits in 1...(j-1) if (niz > 0): wall = wall + ( [0.] * niz ) wall = wall + ( [-1., 1.] ) nfz = self.d-j # digits in j ... d if (nfz > 0): wall = wall + ( [0.] * nfz ) return scipy.array(wall) def makeEWalls(self): """ Make the electric wall set """ eWalls = [] for f in self.forms: # We have to unpack the tuple, since makeEWall only # cares about "p" and "d" here, while we care about the # label as well. new_wall = self.makeEWall( f[:2] ) eWalls.append( new_wall ) new_wall_label = "E" + f[2] self.walls[ new_wall_label ] = new_wall self.eWalls = eWalls def makeEWall(self, ft): """ Make an individual electric wall. The second argument is ft=(p,lamb) """ (p,lamb) = ft if self.dil: wall = [ 0.5*lamb ] else: wall = [] if (p > 0): wall = wall + ( [1.] * p ) if (self.d-p > 0): wall = wall + ( [0.] * (self.d-p) ) return scipy.array(wall) def makeBWalls(self): bWalls = [] for f in self.forms: new_wall = self.makeBWall( f[:2] ) bWalls.append( new_wall ) new_wall_label = "B" + f[2] self.walls[ new_wall_label ] = new_wall self.bWalls = bWalls def makeBWall(self, ft): (p,lamb) = ft if self.dil: wall = [ -0.5*lamb ] else: wall = [] if (self.d - p - 1 > 0): wall = wall + [1.] * (self.d - p - 1) wall = wall + [0.] * (p+1) return scipy.array(wall) def makeGWalls(self): gwall = self.makeGWall() self.gWalls = [ gwall ] self.walls[ "G" ] = gwall def makeGWall(self): if self.dil: wall = [ 0. ] else: wall = [] wall = wall + [2.] if ( self.d-3 > 0): wall = wall + [1.]*(self.d-3) wall = wall + [0.]*2 return scipy.array(wall) def wallDot(self, w1, w2 ): """ Compute the inner product of two walls """ if self.dil: dil1 = w1[0] dil2 = w2[0] x1 = w1[1:] x2 = w2[1:] else: dil1 = 0. dil2 = 0. x1 = w1 x2 = w2 dot = x1.sum() * x2.sum() dot = dot * -1./float(self.d-1.) dot = dot + (x1*x2).sum() dot = dot + dil1*dil2 return dot def wallNorm(self, w): return self.wallDot(w,w) def getNonSymWalls(self): """ Return a list of labels for walls that do not correspond to symmetry walls. Right now this is just implemented by checking the first character of the wall label. Maybe in the future there will be a more sophisticated way of doing this. """ return filter( lambda s : s[0] != 'S', self.walls.keys() ) def setDomWalls(self, domWallLabels ): """ domWallLabels: a list of wall labels (strings) This sets which walls one wants in the dominant wall set. One simply chooses which (non-symmetry) walls are desired. The symmetry walls are automatically included. In the end this function also calculates the coweights and their norms. """ # Implementation note: the symmetry walls are found by just # looking at the list of self.sWalls # Now we have to copy over the desired walls without losing track # of the labels. The wrinkle is that to form the dominant wall array # we have to change the arrays to lists, which we can then mold into # an array. # Implementation note: these have to be lists, because we need to keep # ordering information about them! self.domWallLabels = [] self.domWalls = [] # First add the requested walls # This seems perverse, but the idea is that the caller has requested that # the walls in domWallLabels be properly added to self.domWallLables for wl in domWallLabels: self.domWallLabels.append(wl) self.domWalls.append( self.walls[ wl ] ) # Now add on the symmetry walls for j in range(len(self.sWalls)): # Can't reverse the lookup in a dict self.domWallLabels.append( self.makeSymName(j+2) ) self.domWalls.append( self.sWalls[j] ) # Now the dominant walls are all set. Make the wall matrix tmp = [] for w in self.domWalls: tmp.append( w.tolist() ) self.domWallMatrix = scipy.asarray(tmp) # Finally, to keep everything straight, we have to also calculate # the coweights so all is synchronized. self.calcCoweights() # And we have to compute the Cartan matrix. # Potentially, this is the transpose of the Cartan matrix A_mtrx = [] for dw1 in self.domWalls: A_row = [] for dw2 in self.domWalls: A_row = A_row + [ 2. * self.wallDot( dw1, dw2 )\ / self.wallNorm( dw1 ) ] A_mtrx.append( A_row ) self.cartanMatrix = scipy.asarray(A_mtrx) self.cartanMatrixEigenvalues = scipy.linalg.eigvals(self.cartanMatrix) self.cartanMatrixEigenvalues = self.cartanMatrixEigenvalues.real def calcCoweights(self): (size, size1) = self.domWallMatrix.shape if (size != size1): print "Billiard.calcCoweights: matrix not square" self.coweights = None self.coweightNorms = None return tmp = scipy.linalg.inv(self.domWallMatrix) self.coweightMatrix = tmp.transpose() # Now we have the coweights. At this point there is just the # task of unpacking the coweights and computing their norms. # By symmetry, let's create a dictionary called coweights that # holds these labels. # By construction, the domWallLabels are exactly those of the # coweights. So we can just re-use them. self.coweights = {} self.coweightNorms = {} for n in range(size): cw = self.coweightMatrix[n] self.coweights[ self.domWallLabels[n] ] = cw self.coweightNorms[ self.domWallLabels[n] ] = \ self.coweightDot(cw,cw) def coweightDot(self, cw1, cw2): """ Calculate the dot product of two coweights. """ if self.dil: dil1 = cw1[0] dil2 = cw2[0] x1 = cw1[1:] x2 = cw2[1:] else: dil1 = 0. dil2 = 0. x1 = cw1 x2 = cw2 dot = -1. * x1.sum() * x2.sum() dot = dot + (x1*x2).sum() dot = dot + dil1*dil2 return dot def isChaotic(self): """ Return whether the theory is chaotic or not. """ # in some cases coweights are not defined ct = self.countCoweightTypes() if not ct: return None (nT, nN, nS) = self.countCoweightTypes() if ( (nT>0) and (nS>0) ): return False return True def isNonChaotic(self): if self.isChaotic == None: return None return (not self.isChaotic() ) def countCoweightTypes(self): """ Return the number of timelike, null, spacelike coweights. This assumes you've already set the dominant walls, of course! """ # coweightNorms have failed (error checking) if not self.coweightNorms: return None numTimelike = 0 numNull = 0 numSpacelike = 0 tol = 1.e-6 for n in self.coweightNorms.values(): if n > tol: numSpacelike += 1 elif (n+tol) > 0.: numNull += 1 else: numTimelike += 1 return (numTimelike, numNull, numSpacelike) def __str__(self): s = "Original model " + self.__class__.__name__ + "\n" s = s + "Dominant walls " + str(self.domWallLabels) + "\n" s = s + "Coweights (T,N,S) " + str(self.countCoweightTypes()) + "\n" s = s + "Chaotic? " + str(self.isChaotic()) + "\n" s = s + "\n" s = s + self.dynkinString() return s def printDynkin(self): print print self.dynkinString() def dynkinString(self): """ Print a Dynkin-ish diagram. Basically, the cheat is that we always know that the symmetry walls form the backbone. So just print out a list of the symm walls, together with the walls that have a nonzero inner product, and the number of lines connecting them. Something like --- =>= etc. Option to only print the dominant ones, perhaps. """ s = "" nonSymsLabels = [e for e in self.domWallLabels if e[0] != 'S' ] # Keep track of the nodes that we've printed isPrinted = {} for nsl in nonSymsLabels: isPrinted[nsl] = False for j in range(2,self.d+1): symLabel = self.makeSymName(j) # If we're not the first, then we must have a symmetry node # already above us, which we should connect with the gravity line if (j != 2): s = s + "\n |" # Do something clever to only loop through the non-symmetry # walls. Then we must define a function that gives the number # of Dynkin links between two nodes according to the usual # rules of Dynkin diagrams. if ( j != 2): s = s + "\n" s = s + " %3s o" % symLabel # Now print all of the non-symmetry walls that have nonzero IP # with this wall. for nsLabel in nonSymsLabels: d = self.wallDot( self.walls[symLabel], self.walls[nsLabel] ) nsNorm = self.wallNorm( self.walls[nsLabel] ) if (round(d) != 0): s = s + self.makeDynkinConnect(2., nsNorm, d) + "o" s = s + " %s" % nsLabel # mark it printed isPrinted[nsLabel] = True # print s #s = s + "\n" # There should also be a check to report any additional linkages # that are not just symmetry wall connected with another wall for j in range(len(nonSymsLabels)): for k in range(j+1,len(nonSymsLabels)): w1 = self.walls[nonSymsLabels[j]] w2 = self.walls[nonSymsLabels[k]] d = self.wallDot( w1, w2 ) if (round(d) != 0): s = s + "\n\n%5s o%so %s" % (nonSymsLabels[j],\ self.makeDynkinConnect( self.wallNorm(w1), \ self.wallNorm(w2), d ),\ nonSymsLabels[k]) isPrinted[nonSymsLabels[j]]=True isPrinted[nonSymsLabels[k]]=True # Finally, there may be nodes that haven't beeen printed anywhere! # Also I want to avoid a terminating carriage return. for nsl in nonSymsLabels: if not isPrinted[nsl]: s = s + "\n\n o %s" % nsl return s def makeDynkinConnect(self, norm1, norm2, dot): # New line algorithm that avoids some rare issues iN1 = int(round(norm1)) iN2 = int(round(norm2)) norm = norm1 if norm2 < norm1: norm = norm2 iLines = int( round( -2. * dot / norm ) ) if iLines == 1: line = "-" elif iLines == 2: line = "=" elif iLines == 3: line = "3" elif iLines == 4: line = "4" else: line = "?" if (dot>1e-3): line = "+" if (iN1 > iN2): mid = ">" elif (iN1 < iN2): mid = "<" else: mid = line return line+mid+line def makeSymName(self, j): return "S" + str(j) hetBill = Billiard(9, [ (1,-1./math.sqrt(2.),"F2"), (2,-1.*math.sqrt(2.),"H3") ] ) class Compact: """ Defines a compactification of a wall system. This class does very little computation, and really just defines an interface for setting the zero betti numbers. """ def __init__(self, d): self.d=d self.betti=[1]*(self.d+1) def setZeroBetti(self, zeroB): """ Sets a given list of Betti numbers to zero. Enforces the duality. This should be called in any descendendant classes since it helps with error-checking. """ self.betti = [1] * (self.d+1) #print "Compact.setZeroBetti" for zb in zeroB: self.betti[zb] = 0 # Enforce the duality self.betti[self.d-zb] = 0 def getBettis(self): return self.betti def _prepCompactRules(self, billiard): """ Intented to be a helper function. In each class that implements the Compact interface, there is some kind of decision structure that decides which walls are dominant based on 1. the compactification deletions, and 2. some kind of dominance heirarchy. This function does the beginning bit of this process. It creates some dictionaries, keyed on the non-symmetry walls. dom keeps track of whether a wall is dominant. ext keeps track of whether it exists. This function then takes care of all of the compactification rules, and passes a tuple to the caller with (wks,ext,dom) where wks are the wall names. To do this, it needs to know about the Billiard object so that it can get the ps. This function is considered private because it assumes implementation details of the other stuff. """ dom = {} # whether the wall is dominant (untouched here except to init) ext = {} # whether the wall exists sbn = {} # to which betti is this wall sensitive? wks = billiard.getNonSymWalls() # to which betti number is a given form sensitive? for (p,lamb,nom) in billiard.forms: sbn[ "E"+nom ] = p sbn[ "B"+nom ] = p+1 # gravity walls are not symmetry walls sbn[ "G" ] = -1 for wk in wks: dom[wk] = True ext[wk] = True # Now remove walls that are excluded by compactification rules bs = self.betti for wk in wks: if not self.betti[sbn[wk]]: ext[wk] = False ext["G"] = True return (wks,ext,dom) def _postCompactRules(self, billiard, ext, dom): """ After the dominance heirarchy logic, set the dominant walls. """ dwl = [] for w in dom.keys(): if dom[w] and ext[w]: dwl.append(w) #print "Compact.__postCompactRules: setting to dom ",dwl billiard.setDomWalls(dwl) class cosetA(Billiard,Compact): """ The billiard based on the An groups. This yields a wall system defined by An^^ = AE_{n+2}. Compactification does not affect this at all. """ def __init__(self, n): self.n = n Billiard.__init__(self, n+2, (), False ) Compact.__init__(self, n+2) self.setDomWalls( [ "G" ] ) def setZeroBetti(self, zeroB): Compact.setZeroBetti(self, zeroB) print "bill.cosetAn.setZeroBetti has no effect" class cosetB(Billiard,Compact): """ The billiard for the Bn groups. The Bn coset in D=3 oxidizes to D=n+2, unless n=3 in which case it oxidizes to D=6. one obtains the following forms: p lamb name 1 a sqrt(2)/2 F 2 a sqrt(2) G where a^2 = 8/n. (So far as I know the sign does not matter here) When n=3 in one obtains 2 0 (no dilaton) G which is self-dual """ def __init__(self, n): self.n = n sqrt=scipy.sqrt lamb1 = sqrt(8./float(n)) * sqrt(2.) / 2. lamb2 = sqrt(8./float(n)) * sqrt(2.) if (n != 3): Billiard.__init__( self, n+1, [ (1, lamb1, "F2"), \ (2, lamb2, "G3") ] ) Compact.__init__(self, n+1) self.setDomWalls( [ "EF2", "BG3" ] ) else: # In this case, the maximal oxidation is to a higher dimension. Billiard.__init__( self, 5, [ (2, 0., "G3") ], False ) Compact.__init__( self, 5) self.setDomWalls( [ "BG3" ] ) def setZeroBetti(self, zeroB): Compact.setZeroBetti(self,zeroB) #print "bill.cosetB.setZeroBetti ", zeroB if (self.n==3): return self.setZeroBettiSpecial() (wkl,ext,dom) = self._prepCompactRules(self) # Construction rules # Example: if EF2 and BG3 exist, then BF2 is not dominant. if ext['EF2'] and ext['BG3']: dom['BF2']=False if ext['EF2']: dom['EG3']=False if ext['BG3'] and ext['EF2']: dom['G']=False if ext['G'] and ext['BG3']: dom['BF2']=False if ext['EG3'] and ext['BG3']: dom['G']=False if ext['EF2'] and ext['BF2']: dom['G']=False self._postCompactRules(self,ext,dom) def setZeroBettiSpecial(self): """ In this case, the oxidation can proceed further, to D=6 where there is no dilaton. Oddly, here the electric and magnetic walls are the same. The reason here is that G3 is self-dual. """ print "bill.cosetB.setZeroBettiSpecial" (wkl,ext,dom) = self._prepCompactRules(self) # The dominance heirarchy if ext['BG3']: dom['G'] = False # The convention we take is that BG3 is the wall. dom['EG3'] = False self._postCompactRules(self, ext, dom) class cosetC(Billiard,Compact): """ The billiard for the Cn groups. The Cn cosets do not oxidize beyond D=4. Also, there are many dilatons. Therefore they are kind of a special case that has to be handled carefully. Fortunately this will be easy because of the way in which Python handles inhertiance! """ def __init__(self, n): self.d = 3 self.n = n # Here I differ from usual practice self.dil = n-1 # This has to be done manually, since it isn't clear # algorithmically how one selects the dominant walls. self.domWallMatrix = None # This is a dictionary holding the map between the label for # and the wall itself. Newly created walls should register # themselves here. self.walls = { } self.domWallLabels = [] self.domWalls = [] self.coweightMatrix = None self.makeWalls() dw = [] for wk in self.walls.keys(): if wk != "G" and wk[0] != "S": dw.append(wk) self.setDomWalls( dw ) def _padWall(self, walla ): """ Pad the wall created by another function to include all the dilatons """ walll = walla.tolist() walll = [0.] * (self.dil-1) + walll return scipy.array(walll) def makeSWall(self,j): """ The regular version does all right, but only has one dilaton. """ return self._padWall( Billiard.makeSWall(self,j) ) def makeGWall(self): return self._padWall( Billiard.makeGWall(self) ) def setZeroBetti(self, zeroB): """ Again, a departure from normalcy """ Compact.setZeroBetti(self, zeroB) b1zero = False for b in zeroB: if b == 1 or b == 2: b1zero = True if b1zero: dw = [] for wk in self.walls.keys(): if wk[0] != "S" and wk[0] != "B": dw.append(wk) self.setDomWalls( dw ) def makeEWalls(self): """ Thuis function needs to make both the walls and their labels. I'm going to cheat here, because all of the relevant walls here are either dominant or don't exist. These are all axion electric walls. So: """ x = math.sqrt(2.)/2. self.eWalls = [] # A unique wall curr_wall = [0.] * (self.d + self.n - 1) curr_wall[0] = math.sqrt(2.) self.eWalls.append(curr_wall) self.walls[ "E%d0" % self.n ] = scipy.asarray(curr_wall) for j in range(2,self.n): curr_wall = [ 0. ] * (self.d + self.n - 1) curr_wall[self.n -j] = x curr_wall[self.n-1-j] = -1. * x self.eWalls.append( curr_wall ) label = "EX%d0" % j self.walls[ label ] = scipy.asarray(curr_wall) def makeBWalls(self): # A unique wall curr_wall = [0.] * (self.d + self.n - 1) curr_wall[self.n-2] = -1. * math.sqrt(2.)/2. curr_wall[self.n-1] = 1. self.bWalls = [ curr_wall ] self.walls[ "BA1" ] = scipy.asarray(curr_wall) def wallDot(self, w1, w2 ): # Just remove everything but the last dilaton entry. There are n-1 # dilatons, so this means n = self.n d = self.d ndils = self.dil dils1 = w1[:ndils] dils2 = w2[:ndils] bets1 = w1[ndils:] bets2 = w2[ndils:] dot = sum( dils1*dils2 ) dot += -1. * bets1.sum()*bets2.sum()/float(self.d-1) dot += (bets1*bets2).sum() return dot def coweightDot(self, cw1, cw2): """ Calculate the dot product of two coweights. """ # Just remove everything but the last dilaton entry. There are n-1 # dilatons, so this means n = self.n d = self.d ndils = self.dil dils1 = cw1[:ndils] dils2 = cw2[:ndils] bets1 = cw1[ndils:] bets2 = cw2[ndils:] dot = (dils1*dils2).sum() dot = dot -1. * bets1.sum() * bets2.sum() dot = dot + (bets1*bets2).sum() return dot class cosetD(Billiard,Compact): """ The billiard for the Dn groups. These oxidize to D=n+2 dimensions where one obtains the following form fields. p lamb name 2 a sqrt(2) H where a^2=8/n """ def __init__(self, n): self.n = n sqrt = scipy.sqrt lamb = sqrt(8./float(n)) * sqrt(2.) Billiard.__init__( self, n+1, [ (2, lamb, "H3") ], True ) Compact.__init__( self, n+1 ) self.setDomWalls( [ "EH3", "BH3" ] ) def setZeroBetti(self, zeroB): Compact.setZeroBetti(self, zeroB) #print "bill.cosetD.setZeroBetti: ",zeroB (wkl,ext,dom) = self._prepCompactRules(self) # Dominance heirarchy if ext["BH3"] and ext["EH3"]: dom["G"] = False self._postCompactRules(self,ext,dom) class cosetE6(Billiard,Compact): def __init__(self): root2 = scipy.sqrt(2.) Billiard.__init__(self, 7, [ (0, 2.*root2, "X1"), \ (3, -1.*root2, "G4" ) ], True ) Compact.__init__(self, 7 ) self.setDomWalls( [ "EX1", "EG4" ] ) def setZeroBetti( self, zeroB ): Compact.setZeroBetti( self, zeroB ) #print "bill.cosetE6.setZeroBetti: ", zeroB (wkl, ext, dom) = self._prepCompactRules(self) # all bs nonzero if ext["EX1"] and ext["EG4"]: dom["BX1"] = False dom["BG4"] = False dom["G"] = False self._postCompactRules(self, ext, dom) class cosetE7(Billiard, Compact): def __init__(self): lamb = 2. * math.sqrt(2./7.) Billiard.__init__( self, 8, \ [ (1, -2.*lamb, "F2"), (3, lamb, "G4") ], True ) Compact.__init__( self, 8 ) self.setDomWalls( [ "EF2", "EG4" ] ) def setZeroBetti( self, zeroB ): Compact.setZeroBetti( self, zeroB ) #print "bill.cosetE7.setZeroBetti: ", zeroB (wkl, ext, dom) = self._prepCompactRules(self) # all bs nonzero if ext["EF2"] and ext["EG4"]: dom["BF2"] = False dom["BG4"] = False dom["G"] = False if ext["EG4"] and ext["BG4"]: dom["BF2"] = False dom["G"] = False if ext["EF2"] and ext["BF2"]: dom["G"] = False self._postCompactRules(self, ext, dom) class cosetE8( Billiard, Compact ): def __init__(self): Billiard.__init__( self, 10, [ ( 3, 0., "G4" ) ], False ) Compact.__init__( self, 10 ) self.setDomWalls( [ "EG4" ] ) def setZeroBetti( self, zeroB ): Compact.setZeroBetti( self, zeroB ) ( wkl, ext, dom ) = self._prepCompactRules( self ) if ext[ "EG4" ]: dom[ "BG4" ] = False if ext["EG4"] and ext["BG4"]: dom["G"] = False self._postCompactRules( self, ext, dom ) class cosetF4( Billiard, Compact ): def __init__(self): Billiard.__init__( self, 5, [ (0, 2., "X1"), (1, 1., "F+2"), \ (1, -1., "F-2" ), (2, -2., "H3"), \ (2, 0., "G3" ) ], True ) Compact.__init__(self, 5) self.setDomWalls( [ "EX1", "EF-2" ] ) def setZeroBetti(self, zeroB): Compact.setZeroBetti(self,zeroB) #print "bill.cosetF4.setZeroBetti: ", zeroB (wkl,ext,dom) = self._prepCompactRules(self) if ext["EX1"] and ext["EH3"]: dom["EG3"] = False # alls bs nonzero if ext["EX1"] and ext["EF-2"]: dom["EF+2"] = False dom["EH3"] = False dom["BX1"] = False dom["BF+2"] = False dom["BF-2"] = False dom["BH3"] = False dom["BG3"] = False dom["G"] = False # b1=0, killing EF+2,EF-2,BX1 if ext["EX1"] and ext["EH3"]: dom["EG3"] = False dom["BX1"] = False dom["BF+2"] = False dom["BF-2"] = False dom["BH3"] = False dom["BG3"] = False dom["G"] = False self._postCompactRules(self, ext, dom) class cosetG2(Billiard,Compact): def __init__(self): Billiard.__init__(self, 4, [ (1, 0., "F2") ], False ) Compact.__init__(self, 4) self.setDomWalls( [ "EF2" ] ) def setZeroBetti(self): return def test_run(): b5=cosetE6() zblists = [ [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3] ] print "-" * 79 for lzb in zblists: b5.setZeroBetti( lzb ) print "Coweights (T,N,S): ", b5.countCoweightTypes() print "Chaotic: ", b5.isChaotic() b5.printDynkin() print "-" * 79 def all( cos ): zblists = [ [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3] ] print "-" * 79 for lzb in zblists: cos.setZeroBetti( lzb ) print "Zero Betti: ", lzb print "Coweights (T,N,S): ", cos.countCoweightTypes() print "Chaotic: ", cos.isChaotic() cos.printDynkin() print "-" * 79 def test_print(): e6 = cosetE6() print e6 def chaosTable( c, zb ): for n in range(2,12): b = c(n) b.setZeroBetti(zb) print "%2d %s" % ( n, str(b.isChaotic()) ) if __name__ == "__main__": cos = [ cosetB(8), cosetD(8), cosetF4(), cosetE6(), cosetE7() ] zblist_3 = [ [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3] ] zblist_4 = [] + zblist_3 for zb in zblist_3: zblist_4.append( zb + [4] ) #zblist_4.append( [] ) for c in cos: print "="*79 max_p = -1 for (p,l,s) in c.forms: if p > max_p: max_p = p zblists = zblist_3 if max_p > 2: zblists = zblist_4 for zb in zblists: print "-"*79 print "Zero Betti: ", str(zb) c.setZeroBetti(zb) print c