In [61]:
# This worksheet illustrates the use of Sage for the toric intersection calculations in the paper
# "Modular Amplitudes and Flux-Superpotentials on elliptic Calabi-Yau fourfolds", https://arxiv.org/abs/1709.02820
# As an example, we construct a 4-parameter elliptically fibered Calabi-Yau 4-fold with an E8 fiber and
# polytope 27 as the base.
# We choose polytope 27 because the corresponding variety is Fano and the intersection ring is relatively
# non-trivial.
# If you use this code or parts of it for a publication, please 
# cite the above paper.
ReflexivePolytope(3, 27).points()
Out[61]:
M( 1,  0,  0),
M(-1,  0,  0),
M( 0,  1,  0),
M( 0,  0,  1),
M( 1,  0, -1),
M( 1, -1,  0),
M( 0,  0,  0)
in 3-d lattice M
In [1]:
# Triangulate polytope and create toric variety
vertices = \
[[1, 0, 0, -2, -3], \
 [-1, 0, 0, -2, -3], \
 [0, 1, 0, -2, -3], \
 [0, 0, 1, -2, -3], \
 [1, 0, -1, -2, -3], \
 [1, -1, 0, -2, -3], \
 [0, 0, 0, -2, -3], \
 [0, 0, 0, 1, 0], \
 [0, 0, 0, 0, 1]]

poly = LatticePolytope(vertices)

irrelevantPoints = [b for a in map(lambda a: map(tuple, a.interior_points()), poly.faces_lp(codim=1)) for b in a]
relevantPoints = list(set(map(tuple, poly.points())) - set(irrelevantPoints))

pointTuples = relevantPoints

pointConfiguration = PointConfiguration(pointTuples, fine=True, star=pointTuples.index((0, 0, 0, 0, 0)))
triang = pointConfiguration.triangulate()
fan = Fan([Cone([pointTuples[i] for i in indices]) for indices in triang])

variety = ToricVariety(fan)

HH = variety.cohomology_ring()
D = [ HH(c) for c in variety.fan(dim=1) ]

# Print Mori cone
print variety.Mori_cone().rays()
(0, 0, 0, -1, -1, 1, 0, 1, 0,  0),
(0, 0, 0,  1,  0, 0, 3, 0, 2, -6),
(0, 1, 0, -2,  1, 0, 0, 0, 0,  0),
(1, 0, 1, -1, -1, 0, 0, 0, 0,  0)
in Ambient free module of rank 10 over the principal ideal domain Integer Ring
In [3]:
print variety.fan(dim = 1)[3].rays() # <-- this is (0,0,-2,-3)
s = D[3] # <-- the corresponding toric divisor is the section

# Using the Mori cone, we determine a basis for the Kähler cone
d1 = D[5]
d2 = D[1]
d3 = D[0]
d4 = D[3] + D[5] + 2*D[1] + D[0]

tc1 = d4 - s

kaehlerClasses = [d1,d2,d3,d4]

cy = sum(D)

cc=(reduce(operator.mul, [(1+d) for d in D], 1)/(1+sum(D)))
c1=cc.part_of_degree(1)
c2=cc.part_of_degree(2)
c3=cc.part_of_degree(3)
c4=cc.part_of_degree(4)
todd=1+(1/12)*c2+(1/240)*c2*c2-(1/720)*c4

intersections = {}

import itertools
import math

print ""

for comb in itertools.combinations_with_replacement(range(4), 4):
    
    intersection = variety.integrate(reduce(operator.mul, [[d1, d2,d3,d4][i] for i in comb], 1) * cy)
    intersections[tuple([a + 1 for a in comb])] = intersection
    print "C" + str([a + 1 for a in comb]) + ": " + str(intersection)
N(0, 0, 0, -2, -3)
in 5-d lattice N

C[1, 1, 1, 1]: 0
C[1, 1, 1, 2]: 0
C[1, 1, 1, 3]: 0
C[1, 1, 1, 4]: 0
C[1, 1, 2, 2]: 0
C[1, 1, 2, 3]: 0
C[1, 1, 2, 4]: 0
C[1, 1, 3, 3]: 0
C[1, 1, 3, 4]: 0
C[1, 1, 4, 4]: 0
C[1, 2, 2, 2]: 0
C[1, 2, 2, 3]: 0
C[1, 2, 2, 4]: 1
C[1, 2, 3, 3]: 0
C[1, 2, 3, 4]: 1
C[1, 2, 4, 4]: 3
C[1, 3, 3, 3]: 0
C[1, 3, 3, 4]: 0
C[1, 3, 4, 4]: 2
C[1, 4, 4, 4]: 8
C[2, 2, 2, 2]: 0
C[2, 2, 2, 3]: 0
C[2, 2, 2, 4]: 2
C[2, 2, 3, 3]: 0
C[2, 2, 3, 4]: 1
C[2, 2, 4, 4]: 6
C[2, 3, 3, 3]: 0
C[2, 3, 3, 4]: 0
C[2, 3, 4, 4]: 3
C[2, 4, 4, 4]: 18
C[3, 3, 3, 3]: 0
C[3, 3, 3, 4]: 0
C[3, 3, 4, 4]: 0
C[3, 4, 4, 4]: 8
C[4, 4, 4, 4]: 52
In [4]:
# Intersection ring of the base:
for comb in itertools.combinations_with_replacement(range(3), 3):
    
    intersection = variety.integrate(reduce(operator.mul, [[d1, d2, d3][i] for i in comb], 1) * s * cy)
    intersections[tuple([a + 1 for a in comb])] = intersection
    print "C" + str([a + 1 for a in comb]) + ": " + str(intersection)
C[1, 1, 1]: 0
C[1, 1, 2]: 0
C[1, 1, 3]: 0
C[1, 2, 2]: 1
C[1, 2, 3]: 1
C[1, 3, 3]: 0
C[2, 2, 2]: 2
C[2, 2, 3]: 1
C[2, 3, 3]: 0
C[3, 3, 3]: 0
In [5]:
# Determine dual basis of the base:
basecurves = [a * s for a in [d1*d1, d1*d2, d1*d3, d2*d2, d2*d3, d3*d3]]
for c in basecurves:
    print [variety.integrate(c*a*cy) for a in [d1,d2,d3]]
    print ""
basecurvebasis = [d2*d3 - d1*d3, d1*d3, d1*d2 - d1*d3]
print matrix([[variety.integrate(c*a*s*cy) for a in [d1,d2,d3]] for c in basecurvebasis])
[0, 0, 0]

[0, 1, 1]

[0, 1, 0]

[1, 2, 1]

[1, 1, 0]

[0, 0, 0]

[1 0 0]
[0 1 0]
[0 0 1]
In [6]:
# We choose the following basis of H22 cycles:
hilist=[s*d1,s*d2,s*d3] + basecurvebasis

# Print the intersections
print matrix([[variety.integrate(h*hp*cy) for hp in hilist] for h in hilist])
[ 0 -3 -2  1  0  0]
[-3 -6 -3  0  1  0]
[-2 -3  0  0  0  1]
[ 1  0  0  0  0  0]
[ 0  1  0  0  0  0]
[ 0  0  1  0  0  0]
In [7]:
# Determine the fundamental class
print variety.integrate(s*d1*d2*d3*cy)

fundamentalClass = s*d1*d2*d3
1
In [8]:
# Express the basis of the Mori cone as intersections of toric divisors
curves = [s * a for a in basecurvebasis] + [d1*d2*d3]
print matrix([[variety.integrate(c*d*cy) for d in [d1,d2,d3,d4]] for c in curves])
[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]
In [9]:
import itertools
    
def totalChern(te):

    totalChernClass = 0

    for h in te:
        
        if len(h[1]) == 0:
            
            chernClass = 1 + kaehlerClasses[0]
            chernClass = chernClass - kaehlerClasses[0] # Just a hack to lift the identity into the cohomology ring
    
        elif len(h[1]) == 1:
            
            d = h[1][0]
    
            chernClass = -d-(1/2)*d*d-(1/6)*d*d*d-(1/24)*d*d*d*d
        
        elif len(h[1]) == 2:
            
            da = h[1][0]
            db = h[1][1]
    
            chernClass = da*db+(1/2)*da*db*(da+db)+(1/12)*da*db*(2*da*da+3*da*db+2*db*db)
        
        elif len(h[1]) == 3:
            
            da = h[1][0]
            db = h[1][1]
            dc = h[1][2]
            
            chernClass = -da*db*dc-(1/2)*(da*da*db*dc+da*db*db*dc+da*db*dc*dc)
            
        elif len(h[1]) == 4:
            
            da = h[1][0]
            db = h[1][1]
            dc = h[1][2]
            dd = h[1][3]
            
            chernClass = da*db*dc*dd
        
        else:
            
            print "parameter error!"
            return
    
        totalChernClass = totalChernClass + h[0]*chernClass
        
    return totalChernClass

def asymptotics(te):

    cy=sum(D)
    cc=(reduce(operator.mul, [(1+d) for d in D], 1)/(1+sum(D)))
    c2=cc.part_of_degree(2)
    c3=cc.part_of_degree(3)
    c4=cc.part_of_degree(4)

    totalChernClass = totalChern(te)

    curveC0 = totalChernClass.part_of_degree(0)
    curveC1 = totalChernClass.part_of_degree(1)
    curveC2 = totalChernClass.part_of_degree(2)
    curveC3 = totalChernClass.part_of_degree(3)
    curveC4 = totalChernClass.part_of_degree(4)
    
    kaehlerVariableString = ['t'+str(i) for i in range(1,len(kaehlerClasses)+1)]
    _ = var(kaehlerVariableString)
    kaehlerVariables = eval(",".join(kaehlerVariableString))

    gammaClass = [(1,1),(1/24,c2),(I*zeta(3)/(8*pi^3),c3),((1/5760),7*c2*c2-4*c4)]
    
    fourTuples = list(itertools.product(range(1,len(kaehlerClasses)+1), repeat=4))
    threeTuples = list(itertools.product(range(1,len(kaehlerClasses)+1), repeat=3))
    twoTuples = list(itertools.product(range(1,len(kaehlerClasses)+1), repeat=2))
    oneTuples = list(itertools.product(range(1,len(kaehlerClasses)+1), repeat=1))
    
    asymptotics = sum([g[0]*variety.integrate(g[1]*cy*totalChernClass) for g in gammaClass]) \
     + sum([(1/factorial(len(tup)))*sum([g[0]*variety.integrate(g[1]*cy*totalChernClass*reduce(operator.mul, [kaehlerClasses[i - 1] for i in tup])) \
        for g in gammaClass]) * reduce(operator.mul, [kaehlerVariables[i - 1] for i in tup]) for tup in oneTuples]) \
     + sum([(1/factorial(len(tup)))*sum([g[0]*variety.integrate(g[1]*cy*totalChernClass*reduce(operator.mul, [kaehlerClasses[i - 1] for i in tup])) \
        for g in gammaClass]) * reduce(operator.mul, [kaehlerVariables[i - 1] for i in tup]) for tup in twoTuples]) \
     + sum([(1/factorial(len(tup)))*sum([g[0]*variety.integrate(g[1]*cy*totalChernClass*reduce(operator.mul, [kaehlerClasses[i - 1] for i in tup])) \
        for g in gammaClass]) * reduce(operator.mul, [kaehlerVariables[i - 1] for i in tup]) for tup in threeTuples]) \
     + sum([(1/factorial(len(tup)))*sum([g[0]*variety.integrate(g[1]*cy*totalChernClass*reduce(operator.mul, [kaehlerClasses[i - 1] for i in tup])) \
        for g in gammaClass]) * reduce(operator.mul, [kaehlerVariables[i - 1] for i in tup]) for tup in fourTuples]) \
    
    return str(asymptotics).replace("zeta(3)","Zeta[3]").replace("pi","Pi")

def dualClass(cl):
    
    return cl.part_of_degree(0) - cl.part_of_degree(1) + cl.part_of_degree(2) - cl.part_of_degree(3) + cl.part_of_degree(4)
In [59]:
# The syntax of asymptotics(...) (and totalChern) is such that you pass a list of tuples
# (a_i, [D_{i,1},...,D_{i,n}]) and get the asymptotic period (or the chern class)
# of a brane corresponding to \sum_i a_i D_{i,1}*...*D_{i,n}
print "d8asy="+asymptotics([(1,[])])+";"

print "d6asy1="+asymptotics([(1,[s])])+";"
print "d6asy2="+asymptotics([(1,[d1])])+";"
print "d6asy3="+asymptotics([(1,[d2])])+";"
print "d6asy4="+asymptotics([(1,[d3])])+";"

print "d4asy1="+asymptotics([(1,[s,d1])])+";"
print "d4asy2="+asymptotics([(1,[s,d2])])+";"
print "d4asy3="+asymptotics([(1,[s,d3])])+";"
print "d4asy4="+asymptotics([(1,[d2,d3]),(-1,[d1,d3])])+";"
print "d4asy5="+asymptotics([(1,[d1,d3])])+";"
print "d4asy6="+asymptotics([(1,[d1,d2]),(-1,[d1,d3])])+";"

print "d2asy1="+asymptotics([(1,[s,d2,d3]),(-1,[s,d1,d3])])+";"
print "d2asy2="+asymptotics([(1,[s,d1,d3]),(-1,[s,d1,d2,d3])])+";" # <-- choosen such that d2asy2 == -t2
print "d2asy3="+asymptotics([(1,[s,d1,d2]),(-1,[s,d1,d3])])+";"
print "d2asy4="+asymptotics([(1,[d1,d2,d3])])+";"

print "d0asy="+asymptotics([(1,[s,d1,d2,d3])])+";"
d8asy=1/2*t1*t2^2*t4 + 1/3*t2^3*t4 + t1*t2*t3*t4 + 1/2*t2^2*t3*t4 + 3/2*t1*t2*t4^2 + 3/2*t2^2*t4^2 + t1*t3*t4^2 + 3/2*t2*t3*t4^2 + 4/3*t1*t4^3 + 3*t2*t4^3 + 4/3*t3*t4^3 + 13/6*t4^4 + 3/2*t1*t2 + 3/2*t2^2 + t1*t3 + 3/2*t2*t3 + 23/6*t1*t4 + 103/12*t2*t4 + 23/6*t3*t4 + 149/12*t4^2 - 60*I*t1*Zeta[3]/Pi^3 - 135*I*t2*Zeta[3]/Pi^3 - 60*I*t3*Zeta[3]/Pi^3 - 392*I*t4*Zeta[3]/Pi^3 - 59/12;
d6asy1=-1/2*t1*t2^2 - 1/3*t2^3 - t1*t2*t3 - 1/2*t2^2*t3 + 3/2*t1*t2 + 3/2*t2^2 + t1*t3 + 3/2*t2*t3 - 7/6*t1 - 31/12*t2 - 7/6*t3 + 2*I*Zeta[3]/Pi^3 + 19/12;
d6asy2=-1/2*t2^2*t4 - t2*t3*t4 - 3/2*t2*t4^2 - t3*t4^2 - 4/3*t4^3 - 3/2*t2 - t3 - 23/6*t4 + 60*I*Zeta[3]/Pi^3;
d6asy3=-t1*t2*t4 - t2^2*t4 - t1*t3*t4 - t2*t3*t4 - 3/2*t1*t4^2 - 3*t2*t4^2 - 3/2*t3*t4^2 - 3*t4^3 - 1/2*t1*t4 - t2*t4 - 1/2*t3*t4 - 3/2*t4^2 - 3/2*t1 - 3*t2 - 3/2*t3 - 107/12*t4 + 135*I*Zeta[3]/Pi^3 - 3/2;
d6asy4=-t1*t2*t4 - 1/2*t2^2*t4 - t1*t4^2 - 3/2*t2*t4^2 - 4/3*t4^3 - t1 - 3/2*t2 - 23/6*t4 + 60*I*Zeta[3]/Pi^3;
d4asy1=1/2*t2^2 + t2*t3 - 3/2*t2 - t3 + 7/6;
d4asy2=t1*t2 + t2^2 + t1*t3 + t2*t3 - t1 - 2*t2 - t3 + 17/12;
d4asy3=t1*t2 + 1/2*t2^2 - t1 - 3/2*t2 + 7/6;
d4asy4=t1*t4 + 1/2*t4^2 + 1/2*t4 + 1/2;
d4asy5=t2*t4 + t4^2 + 1;
d4asy6=t3*t4 + 1/2*t4^2 + 1/2*t4 + 1/2;
d2asy1=-t1;
d2asy2=-t2;
d2asy3=-t3;
d2asy4=-t4;
d0asy=1;
In [10]:
charges = [[(1,[d2,d3]),(-1,[d1,d3])], \
          [(1,[d1,d3])], \
          [(1,[d1,d2]),(-1,[d1,d3])]]
hv = [variety.integrate(s*totalChern((c)).part_of_degree(3)*cy) for c in charges]
avo = [variety.integrate(s*c*tc1*cy) for c in [d2*d3-d1*d3,d1*d3,d1*d2-d1*d3]]

print "The vector h^i is"
print hv
The vector h^i is
[1/2, 0, 1/2]
In [11]:
def cal_cijk(i,j,k):
    di = [d1,d2,d3][i]
    dj = [d1,d2,d3][j]
    dk = [d1,d2,d3][k]
    return variety.integrate(di*dj*dk*s*cy)
def cal_aij(i,j):
    di = [d1,d2,d3][i]
    dj = [d1,d2,d3][j]
    return variety.integrate(di*dj*tc1*s*cy)
def cal_aiu(i):
    di = [d1,d2,d3][i]
    return variety.integrate(di*tc1*tc1*s*cy)
def cal_aio(i):
    c = basecurvebasis[i]
    return variety.integrate(tc1*c*s*cy)
def cal_a():
    return variety.integrate(tc1*tc1*tc1*s*cy)
In [16]:
d8cc=totalChern([(1,[])])

d6cc1=totalChern([(1,[s])])
d6cc2=totalChern([(1,[d1])])
d6cc3=totalChern([(1,[d2])])
d6cc4=totalChern([(1,[d3])])

d4cc1=totalChern([(1,[s,d1])])
d4cc2=totalChern([(1,[s,d2])])
d4cc3=totalChern([(1,[s,d3])])
d4cc4=totalChern([(1,[d2,d3]),(-1,[d1,d3])])
d4cc5=totalChern([(1,[d1,d3])])
d4cc6=totalChern([(1,[d1,d2]),(-1,[d1,d3])])

d2cc1=totalChern([(1,[s,d2,d3]),(-1,[s,d1,d3])])
d2cc2=totalChern([(1,[s,d1,d3])])
d2cc3=totalChern([(1,[s,d1,d2]),(-1,[s,d1,d3])])
d2cc4=totalChern([(1,[d1,d2,d3])])

d0cc=totalChern([(1,[s,d1,d2,d3])])

chargeList = [d8cc,d6cc1,d6cc2,d6cc3,d6cc4,d4cc1,d4cc2,d4cc3,d4cc4,d4cc5,d4cc6,d2cc1,d2cc2,d2cc3,d2cc4,d0cc]

intersection = matrix([[variety.integrate(dualClass(f1)*f2*todd*cy) for f1 in chargeList] for f2 in chargeList])
print "The mirror dual 4-cycles intersect as"
print intersection

print ""
print "int="+("["+(str(intersection).replace("\n",",").replace(" ",",").replace(" ","").replace(" ","").replace(" ","").replace(" ","").replace(",,",",").replace(",,",",").replace(",,",",").replace("[,","["))+"]").replace("[","{").replace("]","}")+";"
The mirror dual 4-cycles intersect as
[ 2  1  0 -3  0  1  1  1  1  2  1  0  1  0  0  1]
[ 1  2 -1 -4 -1  0 -3  0  1  1  1  1  2  1 -1  0]
[ 0 -1  0 -3 -2  0 -1 -1  0  0  0 -1  0  0  0  0]
[-3 -4 -3 -6 -3 -2 -3 -2  0  0  0  0 -1  0  0  0]
[ 0 -1 -2 -3  0 -1 -1  0  0  0  0  0  0 -1  0  0]
[ 1  0  0 -2 -1  0 -3 -2  1  0  0  0  0  0  0  0]
[ 1 -3 -1 -3 -1 -3 -6 -3  0  1  0  0  0  0  0  0]
[ 1  0 -1 -2  0 -2 -3  0  0  0  1  0  0  0  0  0]
[ 1  1  0  0  0  1  0  0  0  0  0  0  0  0  0  0]
[ 2  1  0  0  0  0  1  0  0  0  0  0  0  0  0  0]
[ 1  1  0  0  0  0  0  1  0  0  0  0  0  0  0  0]
[ 0  1 -1  0  0  0  0  0  0  0  0  0  0  0  0  0]
[ 1  2  0 -1  0  0  0  0  0  0  0  0  0  0  0  0]
[ 0  1  0  0 -1  0  0  0  0  0  0  0  0  0  0  0]
[ 0 -1  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
[ 1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]

int={{2,1,0,-3,0,1,1,1,1,2,1,0,1,0,0,1},{1,2,-1,-4,-1,0,-3,0,1,1,1,1,2,1,-1,0},{0,-1,0,-3,-2,0,-1,-1,0,0,0,-1,0,0,0,0},{-3,-4,-3,-6,-3,-2,-3,-2,0,0,0,0,-1,0,0,0},{0,-1,-2,-3,0,-1,-1,0,0,0,0,0,0,-1,0,0},{1,0,0,-2,-1,0,-3,-2,1,0,0,0,0,0,0,0},{1,-3,-1,-3,-1,-3,-6,-3,0,1,0,0,0,0,0,0},{1,0,-1,-2,0,-2,-3,0,0,0,1,0,0,0,0,0},{1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0},{2,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0},{1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0},{0,1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0},{1,2,0,-1,0,0,0,0,0,0,0,0,0,0,0,0},{0,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0},{0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
In [12]:
tp_a = variety.integrate(tc1*tc1*tc1*d4*cy)
tp_ai = [variety.integrate(tc1*tc1*i*d4*cy) for i in [d1,d2,d3]]
tp_aij = [[variety.integrate(tc1*i*j*d4*cy) for i in [d1,d2,d3]] for j in [d1,d2,d3]]
tp_cijk = [[[variety.integrate(i*j*k*d4*cy) for i in [d1,d2,d3]] for j in [d1,d2,d3]] for k in [d1,d2,d3]]
tp_aio = [cal_aio(i) for i in range(3)]
In [13]:
print "a: " + str(tp_a) + "\n"
print "a_i: " + str(tp_ai) + "\n"
print "a_ij:\n" + str(matrix(tp_aij)) + "\n"
print "c_ijk: " + str(tp_cijk) + "\n"
print "a^i: " + str(tp_aio) + "\n"
print "h^i: " + str(hv)
a: 52

a_i: [8, 18, 8]

a_ij:
[0 3 2]
[3 6 3]
[2 3 0]

c_ijk: [[[0, 0, 0], [0, 1, 1], [0, 1, 0]], [[0, 1, 1], [1, 2, 1], [1, 1, 0]], [[0, 1, 0], [1, 1, 0], [0, 0, 0]]]

a^i: [1, 2, 1]

h^i: [1/2, 0, 1/2]
In [ ]: