CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download
Project: admcycles
Views: 745
Visibility: Unlisted (only visible to those who know the link)
Image: ubuntu2004
1
r"""
2
Double ramification cycle
3
"""
4
5
from __future__ import absolute_import, print_function
6
from six.moves import range
7
from admcycles.admcycles import psiclass, list_strata, fundclass, lambdaclass
8
from admcycles.stable_graph import StableGraph
9
10
import itertools
11
from copy import deepcopy, copy
12
13
from sage.combinat.integer_vector import IntegerVectors
14
from sage.arith.all import factorial
15
from sage.rings.all import QQ
16
from sage.rings.power_series_ring import PowerSeriesRing
17
18
# S.<x0,x1>=PowerSeriesRing(QQ,'x0,x1',default_prec=14)
19
def graph_sum(g,n,decgraphs=None,globalfact=None, vertterm=None,legterm=None,edgeterm=None,maxdeg=None,deg=None,termsout=False):
20
r"""Returns the (possibly mixed-degree) tautological class obtained by summing over graphs gamma,
21
inserting vertex-, leg- and edgeterms.
22
23
INPUT:
24
25
- ``decgraphs`` -- list or generator; entries of decgraphs are pairs (gamma,dec) of a StableGraph
26
gamma and some additional combinatorial structure dec associated to gamma
27
28
- ``globalfact`` -- function; globalfact(gamma,dec) gets handed the parameters gamma,dec as arguments and gives out a number that is multiplied with the corresponding term in the graph sum; default is 1
29
30
- ``vertterm`` -- function; vertterm(gv,nv,maxdeg **kwargs) takes arguments local genus gv and number of legs nv
31
and maxdeg gets handed the parameters gamma,dec,v as optional keyworded arguments and gives out a
32
tautological class on Mbar_{gv,nv}; the class is assumed to be of degree at most maxdeg,
33
if deg is given, the class is exactly of degree deg
34
35
- ``legterm`` -- function; legterm(gv,nv,i,maxdeg, **kwargs) similar to vertterm, except input is
36
gv,nv,i,maxdeg where i is number of marking on Mbar_{gv,nv} associated to leg
37
gamma, dec given as keyworded arguments
38
39
- ``edgeterm`` -- function; edgeterm(maxdeg,**kwargs) takes keyworded arguments gamma,dec,e,maxdeg
40
it gives a generating series s in x0,x1 such that the insertion at edge
41
e=(h0,h1) is given by s(psi_h0, psi_h1)
42
43
- ``termsout`` -- parameter; if termsout=False, return sum of all terms
44
if termsout = 'coarse', return tuple of terms, one for each pair (gamma,dec)
45
if termsout = 'fine', return tuple of terms, one for each pair (gamma,dec) and each distribution
46
of cohomological degrees to vertices and half-edges
47
"""
48
if maxdeg is None:
49
if deg is None:
50
maxdeg = 3*g-3+n
51
else:
52
maxdeg = deg
53
if decgraphs is None:
54
decgraphs = [(gr,None) for ednum in range(3*g-3+n+1) for gr in list_strata(g,n,ednum)]
55
if globalfact is None:
56
globalfact = lambda a,b : 1
57
if vertterm is None:
58
def vertterm(gv,nv,maxdeg, **kwargs):
59
return fundclass(gv,nv)
60
if legterm is None:
61
def legterm(gv,nv,i,maxdeg, **kwargs):
62
return fundclass(gv,nv)
63
if edgeterm is None:
64
def edgeterm(maxdeg,**kwargs):
65
S=PowerSeriesRing(QQ,'x0,x1',default_prec=maxdeg+1)
66
return S.one()
67
68
69
termlist = []
70
71
for (gamma,dec) in decgraphs:
72
restdeg = maxdeg - len(gamma.edges)
73
if restdeg < 0:
74
continue
75
76
gammadectermlist=[]
77
78
numvert = gamma.numvert()
79
gnvect=[(gamma.genera[i],len(gamma.legs[i])) for i in range(numvert)]
80
dimvect=[3*g-3+n for (g,n) in gnvect]
81
markings = gamma.list_markings()
82
vertdic = {l:v for v in range(numvert) for l in gamma.legs[v]}
83
indexdic = {l:j+1 for v in range(numvert) for j,l in enumerate(gamma.legs[v])}
84
# ex_dimvect=[dimvect[vertdic[l]] for l in halfedges] # list of dimensions of spaces adjacent to half-edges
85
86
# Pre-compute all vertex-, leg- and edgeterms
87
vterms = {v:vertterm(gnvect[v][0],gnvect[v][1],restdeg, gamma=gamma,dec=dec,v=v) for v in range(numvert)}
88
lterms = {i:legterm(gnvect[vertdic[i]][0],gnvect[vertdic[i]][1],indexdic[i], restdeg, gamma=gamma,dec=dec) for i in markings}
89
eterms = {e: edgeterm(restdeg,gamma=gamma,dec=dec,e=e) for e in gamma.edges}
90
varlist = {(h0,h1): eterms[h0,h1].parent().gens() for h0,h1 in gamma.edges}
91
eterms = {e:eterms[e].coefficients() for e in eterms}
92
varx = {h0 : varlist[h0,h1][0] for h0,h1 in gamma.edges}
93
varx.update({h1 : varlist[h0,h1][1] for h0,h1 in gamma.edges})
94
95
if deg is None:
96
rdlis = range(restdeg+1) # terms of all degrees up to restdeg must be computed
97
else:
98
rdlis = [deg - len(gamma.edges)]
99
for rdeg in rdlis:
100
# distribute the remaining degree rdeg to vertices
101
for degdist in IntegerVectors(rdeg,numvert,outer=dimvect):
102
# now for each vertex, split degree to vertex- and leg/half-edge terms
103
vertchoices = [IntegerVectors(degdist[v],len(gamma.legs[v])+1) for v in range(numvert)]
104
for choice in itertools.product(*vertchoices):
105
vdims = []
106
ldims = {}
107
for v in range(numvert):
108
vdims.append(choice[v][0])
109
ldims.update({l:choice[v][i+1] for i,l in enumerate(gamma.legs[v])})
110
111
effvterms = [vterms[v].degree_part(vdims[v]) for v in vterms]
112
efflterms = {i: lterms[i].degree_part(ldims[i]) for i in lterms}
113
for i in efflterms:
114
effvterms[vertdic[i]]*=efflterms[i] # multiply contributions from legs to vertexterms
115
for h0,h1 in gamma.edges:
116
# TODO: optimization potential here by multiplying kppolys directly
117
effvterms[vertdic[h0]]*= eterms[(h0,h1)].get(varx[h0]**ldims[h0] * varx[h1]**ldims[h1],0)* (psiclass(indexdic[h0],*gnvect[vertdic[h0]]))**ldims[h0]
118
effvterms[vertdic[h1]]*= (psiclass(indexdic[h1],*gnvect[vertdic[h1]]))**ldims[h1]
119
for t in effvterms:
120
t.simplify()
121
#print(gamma)
122
#print(rdeg)
123
#print(degdist)
124
#print(choice)
125
#print(effvterms)
126
#print(eterms)
127
#print(indexdic)
128
#print('\n')
129
tempres=gamma.boundary_pushforward(effvterms)
130
tempres.simplify()
131
if(len(tempres.terms))>0:
132
tempres*=globalfact(gamma,dec)
133
gammadectermlist.append(tempres)
134
#print(termlist)
135
if termsout=='coarse':
136
termlist.append(sum(gammadectermlist))
137
else:
138
termlist+=gammadectermlist
139
if termsout:
140
return termlist
141
else:
142
return sum(termlist)
143
144
############
145
#
146
# Useful functions and examples
147
#
148
############
149
150
###
151
# Example 1 : Conjectural graph sum for DR_g(1,-1)
152
###
153
154
# Generating functions for graphs
155
156
def DR11_tree_test(gr):
157
return gr.vertex(1) == gr.vertex(2)
158
159
160
def DR11_trees(g, maxdeg=None):
161
if maxdeg is None:
162
maxdeg = 3*g-3+n # n is not defined !
163
return [gr for n in range(1,g+1) for e in range(min(n,maxdeg-n+1))
164
for gr in list_strata(0,2+n,e) if DR11_tree_test(gr)]
165
166
167
def DR11_graphs(g, maxdeg=None):
168
if maxdeg is None:
169
maxdeg = 3*g-3+2
170
result=[]
171
for gr in DR11_trees(g,maxdeg):
172
n=len(gr.list_markings())-2
173
maxleg=max([max(j+[0]) for j in gr.legs])
174
grlist=[]
175
for gdist in IntegerVectors(g,n,min_part=1):
176
genera=copy(gr.genera)+list(gdist)
177
legs=copy(gr.legs)+[[j] for j in range(maxleg+1,maxleg+n+1)]
178
edges=copy(gr.edges)+[(j-maxleg+2,j) for j in range(maxleg+1,maxleg+n+1)]
179
grlist.append(StableGraph(genera,legs,edges))
180
result+=[(gam,None) for gam in grlist]
181
removedups(result,lambda a,b : a[0].is_isomorphic(b[0]))
182
return result
183
184
def removedups(li, comp=None, inplace=True):
185
if inplace:
186
l=li
187
else:
188
l=deepcopy(li) # could be done more efficiently
189
if comp is None:
190
comp = lambda a,b : a == b
191
n = len(l)
192
currn = len(l)
193
for i in range(n,-1,-1):
194
if any(comp(l[i],l[j]) for j in range(i+1,currn)):
195
l.pop(i)
196
currn-=1
197
return l
198
199
# Global factor = 1/|Aut(Gamma)|
200
201
def divbyaut(gamma,dec):
202
return QQ(1)/gamma.automorphism_number()
203
204
# Vertex- and edgeterms for DR11
205
def DR11_vterm(gv, nv, maxdeg,**kwargs):
206
if gv==0:
207
gamma = kwargs['gamma']
208
v = kwargs['v']
209
if not 1 in gamma.legs[v]:
210
# we are in genus zero vertex not equal to base
211
return -nv * fundclass(gv,nv)
212
else:
213
# we are at the base vertex
214
return fundclass(gv,nv)
215
else:
216
return sum([(-1)**j * lambdaclass(j,gv,nv) for j in range(maxdeg+1)])
217
def DR11_eterm(maxdeg,**kwargs): # smarter: edterm(maxdeg=None,gamma=None,dec=None,e=None, *args, *kwds)
218
S=PowerSeriesRing(QQ,'x0,x1',default_prec=maxdeg+1)
219
x0,x1 = S.gens()
220
return 1/(1-x0-x1+x0*x1)
221
222
# Final conjectural graph sum expressing DR_g(1,-1)
223
def DR11_sum(g,deg=None,**kwds):
224
if deg is None:
225
deg = g
226
return graph_sum(g,2,decgraphs=DR11_graphs(g,maxdeg=deg),globalfact=divbyaut,vertterm=DR11_vterm,edgeterm=DR11_eterm,deg=deg,**kwds)
227
228
# decorate the graphs of DR11_graphs(g) with a choice of half-edge at each non-root vertex
229
def DR11_decgraphs(g,maxdeg=None):
230
if maxdeg is None:
231
maxdeg=3*g-3+2
232
graphs = DR11_graphs(g,maxdeg)
233
result = []
234
for gr in graphs:
235
L = [v for v in gr[0].legs if not (1 in v)]
236
for choice in itertools.product(*L):
237
result.append((gr[0],choice))
238
return result
239
240
def divbyaut_new(gamma,dec):
241
zeroverts=gamma.genera.count(0)
242
return factorial(zeroverts-1)/gamma.automorphism_number()
243
244
# Vertex- and edgeterms for DR11
245
def DR11_vterm_new(gv, nv, maxdeg,**kwargs):
246
if gv==0:
247
gamma = kwargs['gamma']
248
v = kwargs['v']
249
if not 1 in gamma.legs[v]:
250
# we are in genus zero vertex not equal to base
251
return -1 * fundclass(gv,nv)
252
else:
253
# we are at the base vertex
254
return fundclass(gv,nv)
255
else:
256
return sum([(-1)**j * lambdaclass(j,gv,nv) for j in range(maxdeg+1)])
257
258
def DR11_eterm_new(maxdeg,**kwargs): # smarter: edterm(maxdeg=None,gamma=None,dec=None,e=None, *args, *kwds)
259
S=PowerSeriesRing(QQ,'x0,x1',default_prec=maxdeg+1)
260
x0,x1 = S.gens()
261
e = kwargs['e']
262
dec = kwargs['dec']
263
ex = 0
264
for i in e:
265
if i in dec:
266
ex += 1
267
return 1/((1-x0-x1)**ex)
268
269
# Final conjectural graph sum expressing DR_g(1,-1)
270
def DR11_sum_new(g,deg=None,**kwds):
271
if deg is None:
272
deg = g
273
return graph_sum(g,2,decgraphs=DR11_decgraphs(g,maxdeg=deg),globalfact=divbyaut_new,vertterm=DR11_vterm_new,edgeterm=DR11_eterm_new,deg=deg,**kwds)
274
275