https://github.com/uberparagon/mgn
Tip revision: 87eacb93177c9d41edb525bb71ae03ae45f18d14 authored by Drew Johnson on 20 March 2020, 16:48:33 UTC
added a ps and ps_ member to strataalgebra
added a ps and ps_ member to strataalgebra
Tip revision: 87eacb9
tau.py
"""
Computes the Witten tau function, i.e. the top intersections of psi classes.
Uses the genus recursion of Liu and Xu from [LX07].
"""
from __future__ import absolute_import
try:
from sage.all import *
from numpy import zeros, array, vectorize, hstack
#from checkin import *
from .remember import *
except ImportError:
pass
def ee(k,n):
"""
Returns the k-th n-dimensional "basis vector".
"""
v = zeros(n, dtype = Integer)
v[k] = 1
return v
#@breadth_first_tree
def tau_no_g(a):
"""
Like tau, but computes the genus that makes it non-zero, if possible.
"""
h = 3 + sum([(i-1)*ai for i,ai in enumerate(a)])
if h % 3 != 0:
return 0
else:
return tau(h/3, a)
#@breadth_first_tree
#@remember
#stored_values = dict()
master_table = dict()
@remember_convert_args(lambda g,a: (g, tuple(a)), master_table) #shares the master_table with intersect_monomial_with_data
def tau(g,a):
"""
INPUT:
- g -- The genus.
- a -- A vector. The first entry is the number of psi classes with exponent 0, the second in the number with exponent 1, etc.
Uses the recursion of Liu and Xu [LX07].
"""
n = sum(a)
deg = sum([ai*i for i, ai in enumerate(a)])
if deg != 3*g-3+n:
return 0
if g == 0:
return multinomial(get_exp_list(a))
if g == 1 and deg == 1:
return Rational((1,24))
if n > 0:
if a[1] !=0: #dialoton
return (2*g - 3 + n) * tau(g,a - ee(1,len(a)))
if a[0] !=0: #string
return sum( [(ai) * tau(g,a - ee(0, len(a)) + ee(i, len(a)) - ee(i+1,len(a))) for i, ai in enumerate(a[1:]) if ai != 0 ] )
d = Integer(a.nonzero()[0][0])
last_index = a.nonzero()[0][-1]
a1 = array(hstack( (a[0:(last_index+1)],array([0]))))
k = len(a1)
a1 -= ee(d, k)
ans = Rational((2*d + 3,12)) * tau(g-1, 4*ee(0, k) + ee(d + 1, k) + a1) \
- Rational((2*g + n -1,6)) * tau(g-1, 3*ee(0,len(a)) + a) \
+ sum(( (binomial_product(a1,b)) * \
(
(2*d + 3) *
tau_no_g(2*ee(0,k) + ee(d+1, k) + b) *
tau_no_g(2*ee(0,k) + a1 - b)
- (2*g + n - 1) *
tau_no_g(ee(0,k) + ee(d,k) + b) *
tau_no_g(2*ee(0,k) + a1 - b)
) for b in splittings(a1)))
return Rational((1,(2*g+n-1)*(2*g+n-2)))*ans
def binomial_product(v1,v2):
"""
See implementation.
"""
#return prod([binomial(a,b) for a,b in zip(v1, v2)])
#had to change after update broke it
return prod([binomial(int(a),int(b)) for a,b in zip(v1, v2)])
def splittings(a):
"""
Important for tau.
"""
#return [array(c) for c in CartesianProduct(*[range(i+1) for i in a])]
#sage update broke this
return [array(c) for c in cartesian_product([list(range(i+1)) for i in a])]
def get_exp_list(a):
"""
Turns a Witten tau list into my traditional list of the exponents of the psis.
"""
l = []
for i, ai in enumerate(a):
l +=[i]*ai
return l
def psi_intersect(g, n, a):
"""
Here ``a`` is a traditional (to me) list of the exponents of the psis. This will convert it into a Witten tau list and call the tau function, and return the answer.
"""
if 3*g - 3 + n != sum(a):
return 0
d = from_exp_list_to_tau(g,n,a)
return tau(g, array(d, dtype = Integer))
def from_exp_list_to_tau(g,n,a):
"""
Converts a list of psi exponents into a Witten tau list.
"""
d = [0] * (max(a) +1)
for ai in a:
d[ai] += 1
d[0] = n - len([ai for ai in a if ai != 0])
return d