Beispiel #1
0
def principal_volume(g_or_stratum, n=None):
    '''
    Return the Masur-Veech volume of the principal stratum. By convention an empty stratum has volume 0. Input can be either a single argument that is a list of orders of zeroes or two arguments g and n, where g is the genus and n is the number of simple poles. 
    '''
    if g_or_stratum in ZZ:
        assert n != None, "Input Error: the input must be either g,n or stratum"
        g = ZZ(g_or_stratum)
        stratum = [1] * (4 * g - 4 + n) + [-1] * n
    elif type(g_or_stratum) in {list, tuple}:
        assert n == None, "Input Error: the input must be either g,n or stratum"
        stratum = g_or_stratum
        n = stratum.count(-1)
        g = (sum(stratum) + 4) / ZZ(4)
    else:
        raise ValueError(
            "Input Error: the input must be either g,n or stratum")
    if sum(stratum) < -4 or sum(stratum) % 4 != 0 or n < 0 or (g, n) in {
        (0, 0), (0, 1), (0, 2), (0, 3), (1, 0)
    }:
        return 0
    memo = {}
    if g == 0: volume = 2 * pi**(2 * n - 6) / ZZ(2**(n - 4))
    else:
        volume = ZZ(2**(2 * g + 1)) * pi**(6 * g - 6 + 2 * n) * factorial(
            4 * g - 4 + n) / factorial(6 * g - 7 + 2 * n) * sum(
                dfactorial(5 * g - 7 + 2 * n - k) / dfactorial(5 * g - 3 - k) *
                CKazarian(g, k, memo) for k in range(g + 1))
    return volume
Beispiel #2
0
def sequence(el, n, list=False, x_required=True):
    R = el.parent()
    if (R is SR):
        variables = [str(v) for v in el.variables()]
        if ('x' in variables):
            variable = el.variables()[variables.index('x')]
        elif (not x_required):
            variable = el.variables()[0]
        else:
            if (n > 0):
                return 0
            else:
                return el
        if (list):
            return [
                el.derivative(variable, i)(**{
                    str(variable): 0
                }) / factorial(i) for i in range(n)
            ]
        else:
            return el.derivative(variable, n)(**{
                str(variable): 0
            }) / factorial(n)
    if (not isinstance(R, Ring_w_Sequence)):
        R = Wrap_w_Sequence_Ring(R)

    return R.sequence(el, n)
Beispiel #3
0
    def sequence(self, el, n, list=False):
        if (list):
            return [self.sequence(el, i) for i in range(n)]
        self_gen = 'x'
        try:
            self_gen = self.base().gens()[-1]
        except:
            pass

        if (self_gen == 1):
            if (n > 0):
                return 0
            elif (n == 0):
                return el
            else:
                raise ValueError(
                    "Impossible get negative element of the sequence")
        if (el in self):
            res = el
            for _ in range(n):
                try:
                    res = derivative(res, self_gen)
                except AttributeError:
                    ## Not derivative possible. Considering a constant
                    if (n == 0):
                        return res
                    return 0
            try:
                return res(**{repr(self_gen): 0}) / factorial(n)
            except TypeError:
                ## Not callable element. Returning the element without evaluation
                return res / factorial(n)
        else:
            raise TypeError("Element not in `self` to compute the sequence.")
Beispiel #4
0
def test_kontsevich_genus0_formula():
    from surface_dynamics.topological_recursion.kontsevich import psi_correlator

    # d1 + ... + dn = n-3
    # equivalently (d1+1) + ... + (dn+1) = 2n-3
    # <tau_{d1} ... tau_{dn}> = (n-3)! / prod d_i!
    for n in range(3, 10):
        for p in Partitions(2 * n - 3, length=n):
            p = tuple(i - 1 for i in p)
            val = QQ((factorial(n - 3), prod(factorial(d) for d in p)))
            assert psi_correlator(*p) == val, p
Beispiel #5
0
    def khovanskii_characteristic(self):
        """
        Given k polytopes P[0], ..., P[k-1] in n-space, compute the sum
        (-1)^(n+k) * n! * MV(P[0], ..., P[0], P[1], ..., P[1], ...)
        over all compositions of n.
        This number is an integer which is equal to the Euler characteristic
        of the subvariety of TT^n defined by sufficiently non-degenerate
        (Laurent) polynomials with Newton polytopes P[0], ..., P[k-1].
        """

        if not self.polynomials:
            return 1 if self.torus_dim == 0 else 0
        elif any(f.is_constant() and f != 0 for f in self.polynomials):
            return 0

        P = [f.newton_polytope() for f in self.polynomials]
        k = len(P)

        n = P[0].ambient_dim()
        if any(q.ambient_dim() != n for q in P):
            raise TypeError(
                'All polytopes must have the same ambient dimension')

        if k > n:
            return 0

        return ((-1)**(n + k) * factorial(n) * sum(
            mixed_volume(chain.from_iterable([q] * a for (q, a) in zip(P, c)))
            for c in MyCompositions(n, length=k)))
def smale_gamma(df, xip1, yij):
    """Smale gamma function.

    Parameters
    ----------
    df : MultivariatePolynomial
        A list of all of the y-derivatives of f, including f itself.
    xip1 : complex
        The x-point to analytically continue to.
    yij : complex
        A y-root at xi. The root that we'll analytically continue.

    Returns
    -------
    double
        The Smale gamma function.
    """
    df0 = df[0]
    df1 = df[1]
    deg = len(df) - 1
    df1y = df1(xip1, yij)
    gamma = numpy.double(0)

    for n in range(2, deg + 1):
        dfn = df[n]
        gamman = numpy.abs(dfn(xip1, yij) / (factorial(n) * df1y))
        gamman = gamman**(1.0 / (n - 1.0))
        if gamman > gamma:
            gamma = gamman
    return gamma
def main2():
    t, n = var('t, n')
    G = symbolic_expression(t**n * (t - Integer(1))**n /
                            factorial(n) * e**t).function(t)
    T = symbolic_expression(G.integral(t, Integer(0), Integer(1))).function(n)
    print([T(j) for j in range(Integer(10))])
    print([T(j).n() for j in range(Integer(10))])
def smale_gamma(df, xip1, yij):
    """Smale gamma function.

    Parameters
    ----------
    df : MultivariatePolynomial
        A list of all of the y-derivatives of f, including f itself.
    xip1 : complex
        The x-point to analytically continue to.
    yij : complex
        A y-root at xi. The root that we'll analytically continue.

    Returns
    -------
    double
        The Smale gamma function.
    """
    df0 = df[0]
    df1 = df[1]
    deg = len(df) - 1
    df1y = df1(xip1,yij)
    gamma = numpy.double(0)

    for n in range(2,deg+1):
        dfn = df[n]
        gamman = numpy.abs(dfn(xip1,yij) / (factorial(n)*df1y))
        gamman = gamman**(1.0/(n-1.0))
        if gamman > gamma:
            gamma = gamman
    return gamma
Beispiel #9
0
def ogf_egf(f):       
    '''
        Method that receives a sequence in the form of a black-box function
        and return a sequence h(n) such that egf(h) = ogf(f).
        
        Then h(n) = f(n)*factorial(n)
    '''
    return lambda n: f(n)*factorial(n)
Beispiel #10
0
def test_kontsevich_witten_formula():
    from surface_dynamics.topological_recursion.kontsevich import psi_correlator

    # <tau_{3g-2}>_{g,1} = 1 / (24^g g!)
    from surface_dynamics.topological_recursion import KontsevichTR
    K = KontsevichTR()
    for g in range(1, 10):
        assert 24**g * factorial(g) * psi_correlator(3 * g - 2) == 1, g
Beispiel #11
0
def c_f(dim_or_stratum):
    '''
    Return the renormalization coefficient for stratum: 2^(d+1)/(d-1)! where d is dimension. Input can be a dimension or a stratum itself.
    '''
    if type(dim_or_stratum) in {list, tuple}:
        d = c_d(dim_or_stratum)
    else:
        d = dim_or_stratum
    return ZZ(2**(d + 1)) / factorial(d - 1)
Beispiel #12
0
def lambda_helper(phi, NN, p=pp):
    """ Helper function for affine and projective factorization probabilities.
    """
    d = deg_fp(phi)
    return prod([
        prod([NN(j, p) - i for i in range(m1(phi, j))]) //
        prod([factorial(m2(phi, [j, i])) for i in range(1, d + 1)])
        for j in range(1, d + 1)
    ])
Beispiel #13
0
def cvolume_by_graphs(stratum, graphs):
    '''
    Return the contribution of given stable graphs to the completed volume of the stratum.
    
    INPUT:
    
    - ``stratum``    -- list or tuple, orders of zeros of the stratum
    - ``graphs``     -- iterable, e.g. a set, of Labeled Stable Graphs
    '''
    f = c_f(stratum)
    mu = prod(factorial(stratum.count(i)) for i in range(-1, max(stratum) + 1))
    return f * mu * sum(operator(graph_poly(stg) for stg in graphs))
Beispiel #14
0
def monom(par):
    '''
    Given a partition ``par`` = :math:`\\left[0^{i_0},1^{i_1},\\ldots,n^{i_n}\\right]` return a monomial (in Multivariate Polynomial Ring over Q) :math:`{t_0}^{i_0}\\cdot\\ldots\\cdot{t_n}^{i_n} \\big/ {i_0}!\\cdot\\ldots\\cdot{i_n}!`.
    
    EXAMPLE:
    
    Here we generate all monomials of weight 5::
    
        sage: from cvolume.series import monom
        sage: [monom(l) for l in Partitions(5)]
        [t4, t0*t3, t1*t2, 1/2*t0^2*t2, 1/2*t0*t1^2, 1/6*t0^3*t1, 1/120*t0^5]
    '''
    exp = par.to_exp()
    return prod(ZZ(1)/factorial(k) for k in exp)*prod([T_vars[i-1] for i in par])
def L_operator(k, m, _A, _D, r_ls, pol, us, d_up_down_mlt):
    '''
    Return (k)_m * Fourier coefficient of
    L_tilde^{k, m}(pol exp(2pi block_matrix([[A, R/2], [R^t/2, D]])Z))/
    exp(-2pi block_matrix([[A, R/2], [R^t/2, D]])Z).
    as an element of _Z_ring or _Z_U_ring.
    '''
    if m == 0:
        return pol
    zero = _Z_U_ring(0)
    res = zero
    u1, u2, u3, u4 = us
    for n in range(m // 2 + 1):
        pol_tmp = _Z_U_ring(pol)
        for _ in range(m - 2 * n):
            pol_tmp = _D_D_up_D_down(u1, u2, u3, u4, r_ls, pol_tmp)
        for _ in range(n):
            pol_tmp *= d_up_down_mlt

        pol_tmp *= QQ(factorial(n) * factorial(m - 2 * n) *
                      mul(2 - k - m + i for i in range(n))) ** (-1)

        res += pol_tmp
    return res
Beispiel #16
0
 def Aut(self):
     '''
     Return the order of the group of automorphisms of this Labeled Stable Graph.
     
     EXAMPLES:
     
     Here we compute the order of automorphism group of a single vertex graph with two loops::
     
         sage: from cvolume import LabeledStableGraph
         sage: edges, loops, kappa = [], [2], [[3, 3, 1, -1]]
         sage: stg = LabeledStableGraph(edges,loops,kappa)
         sage: stg.Aut()
         8
     
     Here we compute the order of automorphism group of a two vertex graph with no loops, but a symmetry due to isomorphic vertices::
     
         sage: edges, loops, kappa = [(0, 1, 1)], [0, 0], [[3, -1],[3, -1]]
         sage: stg = LabeledStableGraph(edges,loops,kappa)
         sage: stg.Aut()
         2
     
     Here we compute the order of automorphism group of a two vertex graph with no loops, but five edges between non-isomorphic vertices::
     
         sage: edges, loops, kappa = [(0, 1, 5)], [0, 0], [[5, 1],[7, -1]]
         sage: stg = LabeledStableGraph(edges,loops,kappa)
         sage: stg.Aut()
         120
     '''
     partition = k_to_p(self.edges, self.loops, self.kappa, self.graph)
     graph_aut = self.graph.automorphism_group(partition=partition,
                                               edge_labels=True,
                                               order=True,
                                               return_group=False)
     loops_aut = prod(2**i * factorial(i) for i in self.loops)
     weights_aut = prod(factorial(e[2]) for e in self.edges)
     return graph_aut * loops_aut * weights_aut
Beispiel #17
0
def test_kontsevich_genus1_formula():
    # from Andersen-Borot-Charbonnier-Delecroix-Giacchetto-Lewanski-Wheeler
    # appendix A

    from surface_dynamics.topological_recursion.kontsevich import psi_correlator

    # d1 + ... + dn = n
    # equivalently (d1+1) + ... + (dn+1) = 2n
    for n in range(1, 8):
        for p in Partitions(2 * n, length=n):
            p = tuple(i - 1 for i in p)
            s = sum(
                multinomial([i - j for i, j in zip(p, diff)]) *
                factorial(sum(diff) - 2)
                for diff in itertools.product([0, 1], repeat=n)
                if sum(diff) >= 2)
            assert 24 * psi_correlator(*p) == multinomial(p) - s, (p, s)
Beispiel #18
0
 def B0plus_old(self, m, n, k=2, N=10):
     if n == 0:
         summa = self._CF(0)
         for c in range(1, N):
             cn = c * self._N
             #term=self._CF(self.K(m,n,cn))/self._RF(cn)**2
             term = self.K(
                 m, n,
                 cn)  #    Ktriv(self._N,m,n,cn,self._prec)/self._RF(cn)**2
             #print "K,m,n(",cn,")=",term
             term = self._CF(term) / self._RF(cn)**k
             #print "term(",cn,")=",term
             summa = summa + term
     f = self._RF(2**k) * self._RF.pi()**k
     f = f * self._RF(m)**(k - 1)
     f = f * self._CF(0, 1)**(self._RF(k + 2))
     f = f / self._RF(factorial(k - 1))
     return f * summa
Beispiel #19
0
def _mixed_volume_naive(gen):
    """
    Naive computation of the normalised mixed volume using Cox et al.,
    'Using Algebraic Geometry', Thm 7.4.12.
    """
    P = list(gen)
    n = len(P)

    if any(q.ambient_dim() != n for q in P):
        raise TypeError(
            'Number of polytopes and ambient dimension do not match')
    res = 0
    for I in Subsets(range(n)):
        if not I:
            continue
        res += (-1)**len(I) * (sum(P[i] for i in I)).volume()

    return (-1)**n / Integer(factorial(n)) * res
Beispiel #20
0
def X_to_kappa(f,kappa):
    """
    f -- A polynomial in X. The constant term is ignored.
    kappa -- A function so that kappa(a) is kappa_a.
    
    Returns::
        A polynomial in kappas, converting ...
    """
    psi_list = []
    for expon,coef in f.dict().items():
        #print expon[0], coef
        if expon[0] !=0:
            psi_list += [expon[0]]*coef
        
    #print psi_list
    result = 0 
    for p in SetPartitions(range(len(psi_list))):   
        #print p  
        #print [ kappa( sum((psi_list[i] for i in s)) ) for s in p]
        result +=   prod((factorial(len(s) - 1) for s in p)) * prod(( kappa( sum((psi_list[i] for i in s)) ) for s in p ))
    return result
Beispiel #21
0
def X_to_kappa(f, kappa):
    """
    f -- A polynomial in X. The constant term is ignored.
    kappa -- A function so that kappa(a) is kappa_a.
    
    Returns::
        A polynomial in kappas, converting ...
    """
    psi_list = []
    for expon, coef in f.dict().items():
        #print expon[0], coef
        if expon[0] != 0:
            psi_list += [expon[0]] * coef

    #print psi_list
    result = 0
    for p in SetPartitions(list(range(len(psi_list)))):
        #print p
        #print [ kappa( sum((psi_list[i] for i in s)) ) for s in p]
        result += prod((factorial(len(s) - 1) for s in p)) * prod(
            (kappa(sum((psi_list[i] for i in s))) for s in p))
    return result
Beispiel #22
0
    def basis_integrals(self, s=None):
        """
        Return a list of numbers corresponding to the integrals of the basis elements in the top codimension.

        This is computed via the FZ relations, so it is probably not fast. However, it is a nice check.

        The value is cached, so you only have to compute it once per session.

        This is used by :meth:`~strataalgebra.StrataAlgebraElement.integrate` which is the more likely way you will want to use it.
        ::

            sage: from strataalgebra import *
            sage: s = StrataAlgebra(QQ,1,(1,))
            sage: s.print_strata(1)
            **** i: 0
            D_irr
            <BLANKLINE>
            **** i: 1
            ka1
            <BLANKLINE>
            **** i: 2
            ps1
            <BLANKLINE>
            sage: s.basis_integrals()
            [1, 1/24, 1/24]

        """
        int_kappa = Rational((1, 24**self.g * factorial(self.g)))
        G = StrataGraph(self.strataP.open_stratum().M)
        G.M[1, 0] += StrataGraph.Xvar**self.moduli_dim

        kappa_index = self.strataP.index_from_graph_codim(
            G, self.moduli_dim)  #._dstrata[self.moduli_dim][G]

        M = self.FZ_matrix(self.moduli_dim)
        ker = M.right_kernel()
        if ker.dimension() != 1:
            raise Exception("Something unexpected here!")
        return list(int_kappa / ker.gen(0)[kappa_index] * ker.gen(0))
Beispiel #23
0
def _mixed_volume_gfan(gen):
    """
    Use gfan to compute the mixed volume of a collection of polytopes.
    Just like Khovanskii, we use the normalised mixed volume which satisfies
    mixed_volume([P,...,P]) = volume(P).
    """

    P = list(gen)
    n = len(P)

    if any(Q.ambient_dim() != n for Q in P):
        raise TypeError(
            'Number of polytopes and ambient dimension do not match')

    if n == 0:
        return 0
    elif n == 1:
        return P[0].volume()

    R = PolynomialRing(QQ, 'x', n)
    I = R.ideal([sum(monomial_exp(R, e) for e in Q.vertices()) for Q in P])
    return ZZ.one() / Integer(factorial(n)) * I.groebner_fan().mixed_volume()
Beispiel #24
0
    def basis_integrals(self, s=None):
        """
        Return a list of numbers corresponding to the integrals of the basis elements in the top codimension.

        This is computed via the FZ relations, so it is probably not fast. However, it is a nice check.

        The value is cached, so you only have to compute it once per session.

        This is used by :meth:`~strataalgebra.StrataAlgebraElement.integrate` which is the more likely way you will want to use it.
        ::

            sage: from strataalgebra import *
            sage: s = StrataAlgebra(QQ,1,(1,))
            sage: s.print_strata(1)
            **** i: 0
            D_irr
            <BLANKLINE>
            **** i: 1
            ka1
            <BLANKLINE>
            **** i: 2
            ps1
            <BLANKLINE>
            sage: s.basis_integrals()
            [1, 1/24, 1/24]

        """
        int_kappa = Rational((1, 24**self.g * factorial(self.g)))
        G = StrataGraph(self.strataP.open_stratum().M)
        G.M[1, 0] += StrataGraph.Xvar ** self.moduli_dim

        kappa_index = self.strataP.index_from_graph_codim(G,self.moduli_dim) #._dstrata[self.moduli_dim][G]

        M = self.FZ_matrix(self.moduli_dim)
        ker = M.right_kernel()
        if ker.dimension() != 1:
            raise Exception("Something unexpected here!")
        return list( int_kappa / ker.gen(0)[kappa_index] * ker.gen(0))
Beispiel #25
0
def kappa_coeff(sigma,kappa_0,F):
  #maybe not optimal to compute the target_partition twice here...
  #global kappa_coeff_dict
  mmm = F.degree()
  target_partition = []
  for i in range(1,mmm+1):
    for j in range(F[i]):
      target_partition.append(i)
  #key = (tuple(sigma),kappa_0,tuple(target_partition))
  #if kappa_coeff_dict.has_key(key):
  #  return kappa_coeff_dict[key]
  total = 0
  num_ones = sum(1 for i in sigma if i == 1)
  for i in range(0,num_ones+1):
    for injection in Permutations(list(range(len(target_partition))),len(sigma)-i):
      term = binomial(num_ones,i)*binomial(kappa_0 + len(target_partition) + i-1, i)*factorial(i)
      for j in range(len(sigma)-i):
        term *= C_coeff(sigma[j+i],target_partition[injection[j]])
      for j in range(len(target_partition)):
        if j in injection:
          continue
        term *= C_coeff(0,target_partition[j])
      total += term
  return (-1)**(len(target_partition)+len(sigma))*total * Rational((1,aut(target_partition)))
Beispiel #26
0
def combination(n, m):
    return factorial(n) / (factorial(m) * factorial(n - m))
Beispiel #27
0
def completed_volume(stratum,
                     verbose=False,
                     one_vertex=False,
                     with_pi=True,
                     cache=None):
    '''
    Return the completed volume of the stratum.
    
    INPUT:
    
    - ``stratum``    -- list or tuple, orders of zeros of the stratum
    - ``verbose``    -- boolean (default `False`), when True prints progress of the computation: time to generate and the number       of stable graphs in each codimension and in total; progress of computing contribution of stable graphs
    - ``one_vertex`` -- boolean (default `False`), when True only computes contribution of one-vertex labeled stable graphs.
    - ``with_pi``    -- boolean (default `True`), when False returns completed volume as a rational number (volume divided by 
      an appropriate degree of pi
    - ``cache``      -- dict (default `None`), a cache to store computed local polynomials
    
    EXAMPLES:

    Here we compute completed volume of an empty stratum :math:`\\mathcal{Q}(3,1)`::
        
        sage: from cvolume import completed_volume 
        sage: completed_volume([3, 1])
        23/90*pi^4
        
    Here we demonstrate the verbose mode by computing completed volume of stratum :math:`\\mathcal{Q}(1,-1)`::
        
        sage: completed_volume([3, 1, 1, -1], verbose = True)
        Computing completed volume of stratum [3,1^2,-1]...
        Generated 2   codimension 1 graphs in ... s
        Generated 4   codimension 2 graphs in ... s
        Generated 3   codimension 3 graphs in ... s
        The total number of stable graphs for stratum [3,1^2,-1] is: 9. Generated in: ... s
        Computed contribution of 9/9 graphs. Time elapsed: ... s. ETA: ... s
        Completed volume of [3,1^2,-1] is: 7/60*pi^6. Computed in: ... s
        7/60*pi^6
        
    Here we compute one-vertex graphs contribution to the completed volume of :math:`\\mathcal{Q}(3,1,1,-1)`::
    
        sage: completed_volume([3, 1, 1, -1], one_vertex=True)
        1346/14175*pi^6
        
    Here are some examples for principal strata, where completed volume coincides with Masur-Veech volume::
    
        sage: assert completed_volume([1, -1, -1, -1, -1, -1]) == 1*pi^4 
        sage: assert completed_volume([1, 1, -1, -1]) == 1/3*pi^4
        sage: assert completed_volume([1, -1]) == 2/3*pi^2
        sage: assert completed_volume([-1, -1, -1, -1]) == 2*pi^2
    '''
    if cache is None: cache = {}
    stratum = tuple(sorted(stratum, reverse=True))
    if stratum in cvolumes_dict and one_vertex == False:
        cvolume = cvolumes_dict[stratum]
        if with_pi: return cvolume
        else: return cvolume.coefficient(pi**cvolume.degree(pi))

    def max_weight(stratum):
        return sum(stratum) / ZZ(2) + len(stratum) / ZZ(2) + stratum.count(
            -1) + 1

    higher_part = [i for i in stratum if i > 1]
    lower_part = [abs(i) for i in stratum if i not in higher_part]
    for new_higher_part in reversed(Combinations(higher_part).list()):
        rest_is_odd = (sum(higher_part) - sum(new_higher_part)) % 2
        w = max_weight(new_higher_part + lower_part) - rest_is_odd
        s_part = tuple(sorted((i + 1) / ZZ(2) for i in new_higher_part))
        _ = Fs(w, s_part)
    d = c_d(stratum)
    f = c_f(d)
    mu = prod(
        [factorial(stratum.count(i)) for i in range(-1,
                                                    max(stratum) + 1)])
    if verbose:
        tic_total = time.time()
        print(
            f"Computing completed volume of stratum {stratum2print(stratum)}..."
        )
        tic = time.time()
    stgs = stable_lab_graphs(stratum, one_vertex=one_vertex, verbose=verbose)
    total_num = len(stgs)
    vol, count, period = 0, 0, 10
    tic = time.time()
    for stg in stgs:
        vol += operator(graph_poly(stg, cache=cache))
        count += 1
        if verbose and (count % period == 0 or count == total_num):
            toc = time.time()
            print(
                f"\rComputed contribution of {count}/{total_num} graphs. Time elapsed: {float2time(toc-tic,3)}. ETA: {float2time((toc-tic)/count*(total_num-count),3)}          ",
                end="")
    if verbose:
        toc_total = time.time()
        print(
            f"\nCompleted volume of {stratum2print(stratum)} is: {f*mu*vol*pi**d}. Computed in: {float2time(toc_total-tic_total,3)}"
        )
    cvolume, cvolume_pi = f * mu * vol, f * mu * vol * pi**d
    if one_vertex == False: cvolumes_dict[stratum] = cvolume_pi
    if with_pi: return cvolume_pi
    else: return cvolume
Beispiel #28
0
def replmon(n):
    '''
    Return the result of application of :math:`\\mathcal{Z}`-operator to the monomial :math:`b_i^n`.
    '''
    if n == 0: return 1
    else: return factorial(n) * Rational(zeta(n + 1) / pi**(n + 1))
Beispiel #29
0
 def memo_Nlocal(g, n, stratum, labeled, mode):
     #print('Computing for (%s,%s,%s)...Cache size %s' % (g,n,stratum,len(cache_poly)))
     if not stratum or n != 2 - 2 * g + 1 / ZZ(2) * sum(
             stratum) or g < 0 or n < 1:
         return B.zero()
     if type(stratum) == list: stratum = tuple(stratum)
     if (g, n, stratum) in cache_poly:
         if labeled: return cache_poly[(g, n, stratum)]
         else:
             return cache_poly[(g, n, stratum)] / cache_labeling[(g, n,
                                                                  stratum)]
     if not labeled:
         memo_Nlocal(g, n, stratum, True, mode)
         return cache_poly[(g, n, stratum)] / cache_labeling[(g, n,
                                                              stratum)]
     #weight_check(g,n,stratum)
     m = [
         stratum.count(2 * i - 1)
         for i in range((max(stratum) + 1) / ZZ(2) + 1)
     ]
     if -1 in stratum:  # case with poles
         elderstratum = list(stratum)
         elderstratum.remove(-1)
         elderstratum.append(1)
         N_lab = memo_Nlocal(g, n + 1, elderstratum, True,
                             mode)(*vanish(b, [n + 1]))
         for i in range(len(elderstratum)):
             if elderstratum[i] > 1:
                 newstratum = list(elderstratum)
                 newstratum[i] = newstratum[i] - 2
                 N_lab -= elderstratum[i] * memo_Nlocal(
                     g, n, newstratum, True, mode)
         N_lab *= ZZ(1) / elderstratum.count(1)
         cache_poly[(g, n, stratum)] = N_lab
         cache_labeling[(g, n, stratum)] = ZZ(
             prod(
                 factorial(stratum.count(i))
                 for i in range(-1,
                                max(stratum) + 1)))
         return cache_poly[(g, n, stratum)]
     elif mode == 'derivative' or len(m) == 2:  # case without poles
         _Fs = stratum_to_F(g, n, stratum)
         deg = ZZ(3 * g - 3 + n - 1 / 2 * sum(d - 1 for d in stratum))
         M = sum(m[i] * (i - 1) for i in range(len(m)))
         mondeg = Partitions(deg + n, length=n)
         const = 2**(5 * g - 6 + 2 * n - 2 * M)
         labeling = prod(
             factorial(stratum.count(i))
             for i in range(1,
                            max(stratum) + 1))
         N_lab = ZZ(1)/const*labeling*sum(prod(ZZ(1)/factorial(d-1) for d in par)*\
                         prod(factorial(i) for i in par.to_exp())*\
                         _Fs.monomial_coefficient(prod(T.gen(d-1) for d in par))*\
                         sum(prod(B.gen(j)**(2*(sympar[j]-1)) for j in range(n)) for sympar in Permutations(par))\
                         for par in mondeg)
         cache_poly[(g, n, stratum)] = N_lab
         cache_labeling[(g, n, stratum)] = ZZ(
             prod(
                 factorial(stratum.count(i))
                 for i in range(-1,
                                max(stratum) + 1)))
         return cache_poly[(g, n, stratum)]
     elif mode == 'recursive':
         assert m[2] == 1 and len(
             m
         ) == 3, "'recursive' mode is only available for stratum = [3,1,1,...,-1,-1]"
         first_term = 2**4 * diff(
             memo_Nlocal(g, n + 1, [1] * (m[1] + 5), False, mode), b[n],
             4)(*vanish(b, [n + 1]))
         second_term = -ZZ(1) / 2 * 2 * memo_Nlocal(
             g - 1, n + 2, [1] *
             (m[1] + 3), False, mode)(*vanish(b, [n + 1, n + 2]))
         third_term = 0
         for par in OrderedSetPartitions(b[:n], 2):
             n_1, n_2 = len(par[0]), len(par[1])
             assert n_1 + n_2 == n
             third_term += -ZZ(1)/2*sum(memo_Nlocal(g_1,n_1+1,[1]*(4*g_1-4+2*(n_1+1)),False,mode)(*list(par[0])+[0]*(30-n_1))\
                     *memo_Nlocal(g-g_1,n_2+1,[1]*(4*(g-g_1)-4+2*(n_2+1)),False,mode)(*list(par[1])+[0]*(30-n_2))\
                               for g_1 in range(g+1))
         N_unlab = first_term + second_term + third_term
         cache_labeling[(g, n, stratum)] = ZZ(
             prod(
                 factorial(stratum.count(i))
                 for i in range(-1,
                                max(stratum) + 1)))
         cache_poly[(g, n,
                     stratum)] = N_unlab * cache_labeling[(g, n, stratum)]
         return cache_poly[(g, n, stratum)]
Beispiel #30
0
def genf_koszul_dual(P, Q, p):
    if p < 0:
        return ZZ_X_Y()
    f1 = genf_polygon(P, [1]*p) // factorial(p)
    f2 = genf_polygon_interior(Q)
    return f1 * f2
Beispiel #31
0
def genf_koszul_points(P, Q, p):
    if p < 0:
        return ZZ_X_Y()
    f1 = genf_points(P, [1]*p) // factorial(p)
    f2 = genf_points(Q)
    return f1 * f2
Beispiel #32
0
def multiset_perms(k_counts):
    "Simple multinomial coefficient using standard lib `math` functions"
    n_factorial = factorial(sum(k_counts))
    k_count_factorial_prod = prod([factorial(x) for x in k_counts])
    n_perms = n_factorial / k_count_factorial_prod
    return int(n_perms)
Beispiel #33
0
def proba(l, k):
    return exp(-l) * (l**k / factorial(k))
def test_kontsevich():
    from surface_dynamics.topological_recursion import KontsevichTR
    K = KontsevichTR()
    # dim 0
    assert K.F(0, 3, [0, 0, 0]) == 1

    # dim 1
    assert K.F(1, 1, [0]) == 0
    assert K.F(1, 1, [1]) == QQ((1, 8))
    assert K.F(0, 4, [1, 0, 0, 0]) == 3

    # dim 2
    assert K.F(0, 5, [2, 0, 0, 0, 0]) == 15
    assert K.F(0, 5, [1, 1, 0, 0, 0]) == 18
    assert K.F(1, 2, [2, 0]) == QQ((5, 8))
    assert K.F(1, 2, [1, 1]) == QQ((3, 8))

    # dim 3
    assert K.F(2, 1, [4]) == QQ((105, 128))

    # dim 4
    assert K.F(2, 2, [5, 0]) == QQ((1155, 128))
    assert K.F(2, 2, [4, 1]) == QQ((945, 128))
    assert K.F(2, 2, [3, 2]) == QQ((1015, 128))

    # genus zero
    assert K.F(0, 3, (0, 0, 0)) == QQ((1, 1))
    assert K.F(0, 4, (1, 0, 0, 0)) == QQ((3, 1))
    assert K.F(0, 5, (2, 0, 0, 0, 0)) == QQ((15, 1))
    assert K.F(0, 5, (1, 1, 0, 0, 0)) == QQ((18, 1))
    assert K.F(0, 6, (3, 0, 0, 0, 0, 0)) == QQ((105, 1))
    assert K.F(0, 6, (2, 1, 0, 0, 0, 0)) == QQ((135, 1))
    assert K.F(0, 6, (1, 1, 1, 0, 0, 0)) == QQ((162, 1))
    assert K.F(0, 7, (4, 0, 0, 0, 0, 0, 0)) == QQ((945, 1))
    assert K.F(0, 7, (3, 1, 0, 0, 0, 0, 0)) == QQ((1260, 1))
    assert K.F(0, 7, (2, 2, 0, 0, 0, 0, 0)) == QQ((1350, 1))
    assert K.F(0, 7, (2, 1, 1, 0, 0, 0, 0)) == QQ((1620, 1))
    assert K.F(0, 7, (1, 1, 1, 1, 0, 0, 0)) == QQ((1944, 1))

    # genus one
    assert K.F(1, 1, (1, )) == QQ((1, 8))
    assert K.F(1, 2, (2, 0)) == QQ((5, 8))
    assert K.F(1, 2, (1, 1)) == QQ((3, 8))
    assert K.F(1, 3, (3, 0, 0)) == QQ((35, 8))
    assert K.F(1, 3, (2, 1, 0)) == QQ((15, 4))
    assert K.F(1, 3, (1, 1, 1)) == QQ((9, 4))
    assert K.F(1, 4, (4, 0, 0, 0)) == QQ((315, 8))
    assert K.F(1, 4, (3, 1, 0, 0)) == QQ((315, 8))
    assert K.F(1, 4, (2, 2, 0, 0)) == QQ((75, 2))
    assert K.F(1, 4, (2, 1, 1, 0)) == QQ((135, 4))
    assert K.F(1, 4, (1, 1, 1, 1)) == QQ((81, 4))

    # genus two
    assert K.F(2, 1, [4]) == QQ((105, 128))
    assert K.F(2, 2, [5, 0]) == QQ((1155, 128))
    assert K.F(2, 2, [4, 1]) == QQ((945, 128))
    assert K.F(2, 2, [3, 2]) == QQ((1015, 128))
    assert K.F(2, 3, [6, 0, 0]) == QQ((15015, 128))
    assert K.F(2, 3, [5, 1, 0]) == QQ((3465, 32))
    assert K.F(2, 3, [4, 2, 0]) == QQ((3465, 32))
    assert K.F(2, 3, [3, 3, 0]) == QQ((7105, 64))
    assert K.F(2, 3, [4, 1, 1]) == QQ((2835, 32))
    assert K.F(2, 3, [3, 2, 1]) == QQ((3045, 32))
    assert K.F(2, 4, [7, 0, 0, 0]) == QQ((225225, 128))
    assert K.F(2, 4, [6, 1, 0, 0]) == QQ((225225, 128))
    assert K.F(2, 4, [5, 2, 0, 0]) == QQ((3465, 2))
    assert K.F(2, 4, [5, 1, 1, 0]) == QQ((51975, 32))
    assert K.F(2, 4, [4, 3, 0, 0]) == QQ((112455, 64))
    assert K.F(2, 4, [4, 2, 1, 0]) == QQ((51975, 32))
    assert K.F(2, 4, [4, 1, 1, 1]) == QQ((42525, 32))
    assert K.F(2, 4, [3, 3, 1, 0]) == QQ((106575, 64))
    assert K.F(2, 4, [3, 2, 2, 0]) == QQ((13125, 8))
    assert K.F(2, 4, [3, 2, 1, 1]) == QQ((45675, 32))
    assert K.F(2, 4, [2, 2, 2, 1]) == QQ((23625, 16))

    # genus three
    assert K.F(3, 1, [7]) == QQ((25025, 1024))
    assert K.F(3, 2, [8, 0]) == QQ((425425, 1024))
    assert K.F(3, 2, [7, 1]) == QQ((375375, 1024))
    assert K.F(3, 2, [6, 2]) == QQ((385385, 1024))
    assert K.F(3, 2, [5, 3]) == QQ((193655, 512))
    assert K.F(3, 2, [4, 4]) == QQ((191205, 512))
    assert K.F(3, 3, [9, 0, 0]) == QQ((8083075, 1024))
    assert K.F(3, 3, [8, 1, 0]) == QQ((3828825, 512))
    assert K.F(3, 3, [7, 2, 0]) == QQ((3828825, 512))
    assert K.F(3, 3, [7, 1, 1]) == QQ((3378375, 512))
    assert K.F(3, 3, [6, 3, 0]) == QQ((7732725, 1024))
    assert K.F(3, 3, [6, 2, 1]) == QQ((3468465, 512))
    assert K.F(3, 3, [5, 4, 0]) == QQ((1923075, 256))
    assert K.F(3, 3, [5, 3, 1]) == QQ((1742895, 256))
    assert K.F(3, 3, [5, 2, 2]) == QQ((883575, 128))
    assert K.F(3, 3, [4, 4, 1]) == QQ((1720845, 256))
    assert K.F(3, 3, [4, 3, 2]) == QQ((1765575, 256))
    assert K.F(3, 3, [3, 3, 3]) == QQ((3570875, 512))

    # Witten <tau_{3g-2}>_{g,1} = 1 / (24^g g!)
    assert all((24**g * factorial(g) *
                K.F(g, 1, [3 * g - 2]) == ZZ(6 * g - 3).multifactorial(2))
               for g in range(1, 10))