r"""
Kontsevich topological recursion that computes intersection of psi classes.
EXAMPLES::
sage: from surface_dynamics import KontsevichTR
sage: K = KontsevichTR()
sage: for p in [(4,),(5,0),(4,1),(3,2)]:
....: n = len(p)
....: assert sum(p) == n + 3
....: c = K.F(2, n, p) / prod((2*i + 1).multifactorial(2) for i in p)
....: print(p, c)
(4,) 1/1152
(5, 0) 1/1152
(4, 1) 1/384
(3, 2) 29/5760
"""
# ****************************************************************************
# Copyright (C) 2020 Vincent Delecroix <20100.delecroix@gmail.com>
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# https://www.gnu.org/licenses/
# ****************************************************************************
from sage.misc.misc_c import prod
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.all import ZZ, QQ
from .topological_recursion import TopologicalRecursion
ZZ_1 = ZZ.one()
[docs]
def psi_correlator(*args):
r"""
Return the integral of psi classes
EXAMPLES:
Examples in genus 0::
sage: from surface_dynamics.topological_recursion.kontsevich import psi_correlator
sage: psi_correlator(0,0,0)
1
sage: psi_correlator(1,0,0,0)
1
sage: psi_correlator(2,0,0,0,0)
1
sage: psi_correlator(1,1,0,0,0)
2
Examples in genus 1::
sage: psi_correlator(1)
1/24
sage: psi_correlator(2, 0)
1/24
sage: psi_correlator(1, 1)
1/24
sage: psi_correlator(3, 0, 0)
1/24
sage: psi_correlator(2, 1, 0)
1/12
sage: psi_correlator(1, 1, 1)
1/12
genus 2::
sage: psi_correlator(7)
1/82944
sage: psi_correlator(7, 1)
5/82944
sage: psi_correlator(6, 2)
77/414720
sage: psi_correlator(5, 3)
503/1451520
sage: psi_correlator(4, 4)
607/1451520
"""
assert all(x in ZZ and x >= 0 for x in args)
n = len(args)
s = sum(args)
if (s - n) % 3:
raise ValueError("the composition should sum up to 3*g - 3 + n")
g = (s - n) // 3 + 1
return KontsevichTR().F(g, n, args) / prod(ZZ(2 * i + 1).multifactorial(2) for i in args)
[docs]
class KontsevichTR(UniqueRepresentation, TopologicalRecursion):
r"""
Topological recursion for intersection of psi classes (Witten's conjecture)
`\int_{Mgn} exp(L_i^2/2 psi_i)`
EXAMPLES::
sage: from surface_dynamics import KontsevichTR
sage: K = KontsevichTR()
sage: [K.F(2, 1, (i,)) for i in range(5)]
[0, 0, 0, 0, 105/128]
sage: K.polynomial(0,3)
1
sage: K.polynomial(0,4)
3*b0 + 3*b1 + 3*b2 + 3*b3
sage: K.polynomial(0,5)
15*b0^2 + 18*b0*b1 + ...
sage: K.polynomial(1,1)
1/8*b0
sage: K.polynomial(1,2)
5/8*b0^2 + 3/8*b0*b1 + 5/8*b1^2
sage: K.write(0, 4)
[1, 0, 0, 0] 1/2
sage: K.write(0, 5)
[2, 0, 0, 0, 0] 1/8
[1, 1, 0, 0, 0] 1/2
sage: K.write(1, 2)
[2, 0] 1/192
[1, 1] 1/96
sage: K.write(2, 1)
[4] 1/442368
"""
def __init__(self):
TopologicalRecursion.__init__(self)
[docs]
def A(self, i, j, k):
r"""
A-data for Kontsevich recursion
"""
if i == 0 and j == 0 and k == 0:
return ZZ_1
else:
raise ValueError
[docs]
def B(self, g, n, i, j):
r"""
B-data for Kontsevich topological recursion
"""
# before we had s=I[0]+I[m]=i+j
# i + j = k + 1
k = i + j - 1
if k >= 0:
yield (k, ZZ(2 * j + 1))
[docs]
def C(self, i, jmax, kmax, smax):
r"""
C-data for Kontsevich topological recursion
"""
if i < 2 or jmax > i - 2 or kmax > i - 2:
# this is a waste of time...
return
# iterate through indices (j,k) with j + k = i-2
jmin = max(0, i - 2 - kmax)
jmax = min(i - 2, jmax)
for j in range(jmin, jmax + 1):
yield (j, i - j - 2, ZZ_1)
[docs]
def D(self, i):
r"""
D-data for Kontsevich topological recursion
"""
return QQ(((i == 1), 8))