Exemple #1
0
def load_hashes():
    hashfile = opj("DATA", "hash", "thash.out")
    clusters = defaultdict(list)
    seen = defaultdict(set)
    with open(hashfile) as F:
        for line in F:
            n, t, N, hsh = map(ZZ, line.strip().split())
            seen[n].add(t)
            if N == 1024 or N > 2000 and not libgap.SmallGroupsAvailable(N):
                clusters[N, hsh].append(f"{n}T{t}")
    # We manually add some groups where we didn't succeed in computing the hash, but know that they are unique up to isomorphism (up to degree 47 at least)
    for n in range(39, 48):
        tmax = ZZ(libgap.NrTransitiveGroups(n))
        clusters[factorial(n), -1] = [f"{n}T{tmax}"]  # Sn
        clusters[factorial(n) // 2, -1] = [f"{n}T{tmax-1}"]  # An
        seen[n].update(set([tmax - 1, tmax]))
    for n in range(1, 47):
        if n not in seen:
            print("Missing degree", n)
        else:
            cnt = libgap.NrTransitiveGroups(n)
            if len(seen[n]) != cnt:
                print(f"Missing {cnt - len(seen[n])} in degree {n}")
                if cnt - len(seen[n]) < 10:
                    print([i for i in range(1, cnt + 1) if i not in seen[n]])
                else:
                    for i in range(1, cnt + 1):
                        if i not in seen[n]:
                            print("Smallest", i)
                            break
                    for i in range(cnt, 0, -1):
                        if i not in seen[n]:
                            print("Largest", i)
                            break
    return clusters
    def _bracket_(self, right):
        """
        The lambda bracket of these two elements.

        The result is a dictionary with non-negative integer keys.
        The value corresponding to the entry `j` is ``self_{(j)}right``.

        EXAMPLES::

            sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0
            sage: L.bracket(L)
            {0: TL, 1: 2*L, 3: 1/2*C}
            sage: L.T().bracket(L)
            {1: -TL, 2: -4*L, 4: -2*C}

            sage: R = lie_conformal_algebras.Affine(QQbar, 'A1', names=('e','h','f')); R
            The affine Lie conformal algebra of type ['A', 1] over Algebraic Field
            sage: R.inject_variables()
            Defining e, h, f, K
            sage: e.bracket(f)
            {0: h, 1: K}
            sage: h.bracket(h.T())
            {2: 4*K}
        """
        p = self.parent()
        if self.is_monomial() and right.is_monomial():
            if self.is_zero() or right.is_zero():
                return {}
            s_coeff = p._s_coeff
            a, k = self.index()
            coefa = self.monomial_coefficients()[(a, k)]
            b, m = right.index()
            coefb = right.monomial_coefficients()[(b, m)]
            try:
                mbr = dict(s_coeff[(a, b)])
            except KeyError:
                return {}
            pole = max(mbr.keys())
            ret =  {l: coefa*coefb*(-1)**k/factorial(k)*sum(factorial(l)\
                    /factorial(m+k+j-l)/factorial(l-k-j)/factorial(j)*\
                    mbr[j].T(m+k+j-l) for j in mbr if j >= l-m-k and\
                    j <= l-k) for l in range(m+k+pole+1)}
            return {k: v for k, v in ret.items() if v}

        diclist = [i._bracket_(j) for i in self.terms() for j in right.terms()]
        ret = {}
        pz = p.zero()
        for d in diclist:
            for k in d:
                ret[k] = ret.get(k, pz) + d[k]
        return {k: v for k, v in ret.items() if v}
Exemple #3
0
            def is_symmetric(self):
                r"""
                Determine if a `NCSym^*` function, expressed in the
                `\mathbf{w}` basis, is symmetric.

                A function `f` in the `\mathbf{w}` basis is a symmetric
                function if it is in the image of `\chi^*`. That is to say we
                have

                .. MATH::

                    f = \sum_{\lambda} c_{\lambda} \prod_i m_i(\lambda)!
                    \sum_{\lambda(A) = \lambda} \mathbf{w}_A

                where the second sum is over all set partitions `A` whose
                shape `\lambda(A)` is equal to `\lambda` and `m_i(\mu)` is
                the multiplicity of `i` in the partition `\mu`.

                OUTPUT:

                - ``True`` if `\lambda(A)=\lambda(B)` implies the coefficients of
                  `\mathbf{w}_A` and `\mathbf{w}_B` are equal, ``False`` otherwise

                EXAMPLES::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: elt -= 3*w.sum_of_partitions([1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: w = SymmetricFunctionsNonCommutingVariables(ZZ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1]) / 2
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + 2*w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                """
                d = {}
                R = self.base_ring()
                for A, coeff in self:
                    la = A.shape()
                    exp = prod([factorial(_) for _ in la.to_exp()])
                    if la not in d:
                        if coeff / exp not in R:
                            return False
                        d[la] = [coeff, 1]
                    else:
                        if d[la][0] != coeff:
                            return False
                        d[la][1] += 1
                # Make sure we've seen each set partition of the shape
                return all(
                    d[la][1] == SetPartitions(la.size(), la).cardinality()
                    for la in d)
Exemple #4
0
 def f(partition):
     n = 0
     for part in partition:
         if part != 1:
             return 0
         n += 1
     return t**n / factorial(n)
Exemple #5
0
 def f(partition):
     n = 0
     m = 1
     for part in partition:
         n += part
         m *= factorial(part)
     return t**n / m
Exemple #6
0
        def sum_of_partitions(self, la):
            r"""
            Return the sum over all sets partitions whose shape is ``la``,
            scaled by `\prod_i m_i!` where `m_i` is the multiplicity
            of `i` in ``la``.

            INPUT:

            - ``la`` -- an integer partition

            OUTPUT:

            - an element of ``self``

            EXAMPLES::

                sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                sage: w.sum_of_partitions([2,1,1])
                2*w{{1}, {2}, {3, 4}} + 2*w{{1}, {2, 3}, {4}} + 2*w{{1}, {2, 4}, {3}}
                 + 2*w{{1, 2}, {3}, {4}} + 2*w{{1, 3}, {2}, {4}} + 2*w{{1, 4}, {2}, {3}}
            """
            la = Partition(la)
            c = prod([factorial(_) for _ in la.to_exp()])
            P = SetPartitions()
            return self.sum_of_terms([(P(m), c) for m in SetPartitions(sum(la), la)], distinct=True)
Exemple #7
0
            def is_symmetric(self):
                r"""
                Determine if a `NCSym^*` function, expressed in the
                `\mathbf{w}` basis, is symmetric.

                A function `f` in the `\mathbf{w}` basis is a symmetric
                function if it is in the image of `\chi^*`. That is to say we
                have

                .. MATH::

                    f = \sum_{\lambda} c_{\lambda} \prod_i m_i(\lambda)!
                    \sum_{\lambda(A) = \lambda} \mathbf{w}_A

                where the second sum is over all set partitions `A` whose
                shape `\lambda(A)` is equal to `\lambda` and `m_i(\mu)` is
                the multiplicity of `i` in the partition `\mu`.

                OUTPUT:

                - ``True`` if `\lambda(A)=\lambda(B)` implies the coefficients of
                  `\mathbf{w}_A` and `\mathbf{w}_B` are equal, ``False`` otherwise

                EXAMPLES::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: elt -= 3*w.sum_of_partitions([1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: w = SymmetricFunctionsNonCommutingVariables(ZZ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1]) / 2
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + 2*w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                """
                d = {}
                R = self.base_ring()
                for A, coeff in self:
                    la = A.shape()
                    exp = prod([factorial(_) for _ in la.to_exp()])
                    if la not in d:
                        if coeff / exp not in R:
                            return False
                        d[la] = [coeff, 1]
                    else:
                        if d[la][0] != coeff:
                            return False
                        d[la][1] += 1
                # Make sure we've seen each set partition of the shape
                return all(d[la][1] == SetPartitions(la.size(), la).cardinality() for la in d)
Exemple #8
0
def logpp_binom(n, p, p_prec):
    """returns the (integral) power series p^n*(log_p(1+p*z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    L = logpp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans *= (p**n) / factorial(n)

    return ps_normalize(ans.truncate(p_prec), p, p_prec)
def logpp_binom(n, p, p_prec):
    """returns the (integral) power series p^n*(log_p(1+p*z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    L = logpp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans *= (p ** n) / factorial(n)
    
    return ps_normalize(ans.truncate(p_prec), p, p_prec)
Exemple #10
0
def polynomial_derivative_on_basis(e, f):
    """
    Return the differentiation of `f` by `e`.

    INPUT:

    - `e`, `f` -- exponent vectors representing two monomials `X^e` and `X^f`
                  (type: :class:`sage.rings.polynomial.polydict.ETuple`)

    OUTPUT:

    - a pair `(g,c)` where `g` is an exponent vector and `c` a
      coefficient, representing the term `c X^g`, or :obj:`None` if
      the result is zero.

    Let `R=K[X]` be a multivariate polynomial ring. Write `X^e` for
    the monomial with exponent vector `e`, and `p(\partial)` the
    differential operator obtained by substituting each variable `x`
    in `p` by `\frac{\partial}{\partial x}`.

    This returns `X^e(\partial)(X^f)`

    EXAMPLES::

        sage: from sage.rings.polynomial.polydict import ETuple
        sage: polynomial_derivative_on_basis(ETuple((4,0)), ETuple((4,0)))
        ((0, 0), 24)
        sage: polynomial_derivative_on_basis(ETuple((0,3)), ETuple((0,3)))
        ((0, 0), 6)
        sage: polynomial_derivative_on_basis(ETuple((0,1)), ETuple((0,3)))
        ((0, 2), 3)
        sage: polynomial_derivative_on_basis(ETuple((2,0)), ETuple((4,0)))
        ((2, 0), 12)
        sage: polynomial_derivative_on_basis(ETuple((2,1)), ETuple((4,3)))
        ((2, 2), 36)
        sage: polynomial_derivative_on_basis(ETuple((1,3)), ETuple((1,2)))
        sage: polynomial_derivative_on_basis(ETuple((2,0)), ETuple((1,2)))
    """
    g = f.esub(e)
    if any(i < 0 for i in g):
        return None
    return (g, prod(factorial(i) / factorial(j) for (i, j) in zip(f, g)))
Exemple #11
0
 def flip(self):  ##does not work correctly??
     k = self.weight()
     try:
         k = ZZ(k)
     except TypeError:
         return NotImplemented
     u = factorial(-k)
     return WeilRepMockModularForm(k,
                                   self.gram_matrix(),
                                   (u * self.shadow()).fourier_expansion(),
                                   self.bol() / u,
                                   weilrep=self.weilrep())
Exemple #12
0
 def coeff(p, q):
     ret = QQ.one()
     last = 0
     for val in p:
         count = 0
         s = 0
         while s != val:
             s += q[last+count]
             count += 1
         ret /= factorial(count)
         last += count
     return ret
Exemple #13
0
 def pochhammer_numerator(alpha, p, m, verbose=False):
     rational = fractional_part(alpha + m / (1 - p))
     R = GF(p)
     k = R(rational).lift()
     if k == 0:
         if verbose:
             print("issue alpha=%s m=%s" % (alpha, m))
         return R(1)
     else:
         fact = R(factorial(k - 1))
         res = (p - fact) if k % 2 else fact
         return res
def logp_binom(n, p, p_prec):
    """returns the (integral) power series (log_p(1+z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    if n == 0:
        return PolynomialRing(QQ, 'y')(1)
    L = logp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans = ans / factorial(n)
    
    return ps_normalize(ans.truncate(p_prec+1), p, p_prec) #Do we need the +1?
Exemple #15
0
 def coeff(p, q):
     ret = QQ.one()
     last = 0
     for val in p:
         count = 0
         s = 0
         while s != val:
             s += q[last + count]
             count += 1
         ret /= factorial(count)
         last += count
     return ret
Exemple #16
0
def logp_binom(n, p, p_prec):
    """returns the (integral) power series (log_p(1+z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    if n == 0:
        return PolynomialRing(QQ, 'y')(1)
    L = logp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans = ans / factorial(n)

    return ps_normalize(ans.truncate(p_prec + 1), p,
                        p_prec)  #Do we need the +1?
Exemple #17
0
    def eval_formula(self, n, x):
        """
        Evaluate ``chebyshev_T`` using an explicit formula.
        See [ASHandbook]_ 227 (p. 782) for details for the recurions.
        See also [EffCheby]_ for fast evaluation techniques.

        INPUT:

        - ``n`` -- an integer

        - ``x`` -- a value to evaluate the polynomial at (this can be
          any ring element)

        EXAMPLES::

            sage: chebyshev_T.eval_formula(-1,x)
            x
            sage: chebyshev_T.eval_formula(0,x)
            1
            sage: chebyshev_T.eval_formula(1,x)
            x
            sage: chebyshev_T.eval_formula(2,0.1) == chebyshev_T._evalf_(2,0.1)
            True
            sage: chebyshev_T.eval_formula(10,x)
            512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1
            sage: chebyshev_T.eval_algebraic(10,x).expand()
            512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1
        """
        if n < 0:
            return self.eval_formula(-n, x)
        elif n == 0:
            return parent(x).one()

        res = parent(x).zero()
        for j in xrange(0, n // 2 + 1):
            f = factorial(n - 1 - j) / factorial(j) / factorial(n - 2 * j)
            res += (-1) ** j * (2 * x) ** (n - 2 * j) * f
        res *= n / 2
        return res
    def eval_formula(self, n, x):
        """
        Evaluate ``chebyshev_T`` using an explicit formula.
        See [ASHandbook]_ 227 (p. 782) for details for the recurions.
        See also [EffCheby]_ for fast evaluation techniques.

        INPUT:

        - ``n`` -- an integer

        - ``x`` -- a value to evaluate the polynomial at (this can be
          any ring element)

        EXAMPLES::

            sage: chebyshev_T.eval_formula(-1,x)
            x
            sage: chebyshev_T.eval_formula(0,x)
            1
            sage: chebyshev_T.eval_formula(1,x)
            x
            sage: chebyshev_T.eval_formula(2,0.1) == chebyshev_T._evalf_(2,0.1)
            True
            sage: chebyshev_T.eval_formula(10,x)
            512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1
            sage: chebyshev_T.eval_algebraic(10,x).expand()
            512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1
        """
        if n < 0:
            return self.eval_formula(-n, x)
        elif n == 0:
            return parent(x).one()

        res = parent(x).zero()
        for j in xrange(0, n // 2 + 1):
            f = factorial(n - 1 - j) / factorial(j) / factorial(n - 2 * j)
            res += (-1)**j * (2 * x)**(n - 2 * j) * f
        res *= n / 2
        return res
Exemple #19
0
def abnormal_polynomials(L, r, m, s):
    r"""
    Return the highest degree coefficients for abnormal polynomials in step `s`
    of layer `m` in the Lie algebra `L`.

    INPUT:

    - ``L`` -- the Lie algebra to do the computations in
    - ``r`` -- the rank of the free Lie algebra
    - ``m`` -- the layer whose abnormal polynomials are computed
    - ``s`` -- the step of coefficients to compute

    OUTPUT:

    A dictionary {X: {mon: coeff}, where

    - ``X`` -- a Hall basis element of layer `m`
    - ``mon`` -- a tuple `(i_1,...,i_n)` describing the monomial
      `x_1^{i_1}...x_n^{i_n}`
    - ``coeff`` -- an element of a :class:`HallQuotient` Lie algebra whose dual
      element would be the coefficient of the monomial in the polynomial `P_X`
    """
    elems = sum((list(L.graded_basis(k)) for k in range(1, m)), [])
    weights = sum(([k] * len(L.graded_basis(k)) for k in range(1, m)), [])
    P = {}
    mons = list(reversed(list(WeightedIntegerVectors(s - m, weights))))
    verbose("computing abnormal polynomials:")
    for X in L.graded_basis(m):
        PX = {}
        pname = freebasis_element_to_short_word(X).replace("X", "P")
        verbose("  %s deg %d coefficients" % (pname, s - m))
        # compute coefficients for the abnormal polynomial P_X
        for mon in mons:
            # compute coefficient of the monomial mon
            adx = X
            mult = QQ(1)
            for i in mon:
                mult = mult / factorial(i)
            for rep, Xi in zip(mon, elems):
                for k in range(rep):
                    adx = Xi.bracket(adx)
            PX[tuple(mon)] = mult * adx
        P[X] = PX

    return P
Exemple #20
0
    def cardinality(self):
        r"""
        Count the number of linear extensions using a hook-length formula.

        EXAMPLES::

            sage: from sage.combinat.posets.poset_examples import Posets
            sage: P = Posets.YoungDiagramPoset(Partition([3,2]), dual=True)
            sage: P.linear_extensions().cardinality()
            5
        """
        num_elmts = self._poset.cardinality()

        if num_elmts == 0:
            return 1

        hook_product = self._poset.hook_product()
        return factorial(num_elmts) // hook_product
    def __getitem__(self, key):
        """
        EXAMPLES::

            sage: a, b, c, z = var('a b c z')
            sage: hs = HypergeometricSeries([a, b], [c], z)
            sage: for i in range(4): print hs[i]
            1
            a*b*z/c
            1/2*(b + 1)*(a + 1)*a*b*z^2/((c + 1)*c)
            1/6*(b + 1)*(b + 2)*(a + 1)*(a + 2)*a*b*z^3/((c + 1)*(c + 2)*c)

        """
        if key >= 0:
            nominator = PochhammerSymbol(self.list_a, key).evaluate()
            denominator = PochhammerSymbol(self.list_b, key).evaluate()*factorial(key)
            return nominator / denominator * self.z**key
        else:
            return 0
def kontsevich_star_product_terms(K, prime_weights, precision):
    """
    Kontsevich star product terms in KontsevichGraphSums ``K`` up to order ``precision``.

    INPUT:

    - ``K`` - KontsevichGraphSums module.
    - ``prime_weights`` - weights of prime graphs, modulo edge labeling and mirror images.

    EXAMPLES::

        sage: K = KontsevichGraphSums(QQ);
        sage: weights = {}
        sage: weights[KontsevichGraph({'F' : {},'G' : {}}, ground_vertices=('F','G'), immutable=True)] = 1
        sage: weights[KontsevichGraph([(1, 'F', 'L'), (1, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/2
        sage: weights[KontsevichGraph([(1, 2, 'R'), (1, 'F', 'L'), (2, 1, 'L'), (2, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/24
        sage: weights[KontsevichGraph([(1, 2, 'R'), (1, 'F', 'L'), (2, 'F', 'L'), (2, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/12
        sage: S.<h> = KontsevichGraphSeriesRng(K, star_product_terms = kontsevich_star_product_terms(K, weights, 2), default_prec = 2);
        sage: F = S(KontsevichGraph(('F',),immutable=True));
        sage: G = S(KontsevichGraph(('G',),immutable=True));
        sage: H = S(KontsevichGraph(('H',),immutable=True));
        sage: A = (F*G)*H - F*(G*H)
        sage: A.reduce()
        sage: len(A[2])  # three terms in the Jacobi identity
        3
    """
    series_terms = {
        0:
        K([(prime_weights[KontsevichGraph(('F', 'G'), immutable=True)],
            KontsevichGraph(('F', 'G'), immutable=True))])
    }
    for n in range(1, precision + 1):
        term = K(0)
        for graph in kontsevich_graphs(n,
                                       modulo_edge_labeling=True,
                                       positive_differential_order=True):
            coeff = kontsevich_weight(
                graph, prime_weights) * graph.multiplicity() / factorial(
                    len(graph.internal_vertices()))
            if coeff != 0:
                term += K([(coeff, graph)])
        series_terms[n] = term
    return series_terms
    def expansion_on_basis(self, w):
        r"""
        Return the expansion of `S_w` in words of the shuffle algebra.

        INPUT:

        - ``w`` -- a word

        EXAMPLES::

            sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis()
            sage: S.expansion_on_basis(Word())
            B[word: ]
            sage: S.expansion_on_basis(Word()).parent()
            Shuffle Algebra on 2 generators ['a', 'b'] over Rational Field
            sage: S.expansion_on_basis(Word('abba'))
            2*B[word: aabb] + B[word: abab] + B[word: abba]
            sage: S.expansion_on_basis(Word())
            B[word: ]
            sage: S.expansion_on_basis(Word('abab'))
            2*B[word: aabb] + B[word: abab]
        """
        from sage.functions.other import factorial
        if len(w) == 0:
            return self._alg.one()
        if len(w) == 1:
            return self._alg.monomial(w)

        if w.is_lyndon():
            W = self.basis().keys()
            letter = W(w[0])
            expansion = self.expansion_on_basis(W(w[1:]))
            return self._alg.sum_of_terms([(letter * i, c)
                                           for i, c in expansion])

        lf = w.lyndon_factorization()
        powers = {}
        for i in lf:
            powers[i] = powers.get(i, 0) + 1
        denom = prod(factorial(p) for p in powers.values())
        result = self._alg.prod(self.expansion_on_basis(i) for i in lf)
        return self._alg(result / denom)
Exemple #24
0
    def hodge_star(self, metric):
        r"""
        Compute the Hodge dual of the differential form.

        If ``self`` is a `p`-form `A`, its Hodge dual is the `(n-p)`-form
        `*A` defined by (`n` being the manifold's dimension)

        .. MATH::

            *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p}
                \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}}

        where `\epsilon` is the volume form associated with some
        pseudo-Riemannian metric `g` on the manifold, and the indices
        `k_1,\ldots, k_p` are raised with `g`.

        INPUT:

        - ``metric``: the pseudo-Riemannian metric `g` defining the Hodge dual,
          via the volume form `\epsilon`; must be an instance of
          :class:`~sage.geometry.manifolds.metric.Metric`

        OUTPUT:

        - the `(n-p)`-form `*A`

        EXAMPLES:

        """
        from sage.functions.other import factorial
        from sage.tensor.modules.format_utilities import format_unop_txt, \
                                                         format_unop_latex
        p = self._tensor_rank
        eps = metric.volume_form(p)
        args = range(p) + [eps] + range(p)
        resu = self.contract(*args)
        if p > 1:
            resu = resu / factorial(p)
        resu.set_name(name=format_unop_txt('*', self._name),
                      latex_name=format_unop_latex(r'\star ',
                                                   self._latex_name))
        return resu
Exemple #25
0
    def expansion_on_basis(self, w):
        r"""
        Return the expansion of `S_w` in words of the shuffle algebra.

        INPUT:

        - ``w`` -- a word

        EXAMPLES::

            sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis()
            sage: S.expansion_on_basis(Word())
            B[word: ]
            sage: S.expansion_on_basis(Word()).parent()
            Shuffle Algebra on 2 generators ['a', 'b'] over Rational Field
            sage: S.expansion_on_basis(Word('abba'))
            2*B[word: aabb] + B[word: abab] + B[word: abba]
            sage: S.expansion_on_basis(Word())
            B[word: ]
            sage: S.expansion_on_basis(Word('abab'))
            2*B[word: aabb] + B[word: abab]
        """
        from sage.functions.other import factorial
        if len(w) == 0:
            return self._alg.one()
        if len(w) == 1:
           return self._alg.monomial(w)

        if w.is_lyndon():
            W = self.basis().keys()
            letter = W(w[0])
            expansion = self.expansion_on_basis(W(w[1:]))
            return self._alg.sum_of_terms([(letter * i, c) for i,c in expansion])

        lf = w.lyndon_factorization()
        powers = {}
        for i in lf:
            powers[i] = powers.get(i, 0) + 1
        denom = prod(factorial(p) for p in powers.values())
        result = self._alg.prod(self.expansion_on_basis(i) for i in lf)
        return self._alg(result / denom)
Exemple #26
0
    def _eval_(self, s, x):
        r"""
        TESTS::

            sage: hurwitz_zeta(x, 1)
            zeta(x)
            sage: hurwitz_zeta(4, 3)
            1/90*pi^4 - 17/16
            sage: hurwitz_zeta(-4, x)
            -1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
            sage: hurwitz_zeta(3, 0.5)
            8.41439832211716
        """
        if x == 1:
            return zeta(s)
        if s in ZZ and s > 1:
            return ((-1)**s) * psi(s - 1, x) / factorial(s - 1)
        elif s in ZZ and s < 0:
            return -bernoulli_polynomial(x, -s + 1) / (-s + 1)
        else:
            return
Exemple #27
0
    def order(self):
        r"""
        Returns the number of elements of ``self``.

        EXAMPLES::

            sage: F.<a> = GF(4)
            sage: SemimonomialTransformationGroup(F, 5).order() == (4-1)**5 * factorial(5) * 2
            True
        """
        from sage.functions.other import factorial
        from sage.categories.homset import End
        n = self.degree()
        R = self.base_ring()
        if R.is_field():
            multgroup_size = len(R) - 1
            autgroup_size = R.degree()
        else:
            multgroup_size = R.unit_group_order()
            autgroup_size = len([x for x in End(R) if x.is_injective()])
        return multgroup_size**n * factorial(n) * autgroup_size
Exemple #28
0
    def _eval_(self, s, x):
        r"""
        TESTS::

            sage: hurwitz_zeta(x, 1)
            zeta(x)
            sage: hurwitz_zeta(4, 3)
            1/90*pi^4 - 17/16
            sage: hurwitz_zeta(-4, x)
            -1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
            sage: hurwitz_zeta(3, 0.5)
            8.41439832211716
        """
        if x == 1:
            return zeta(s)
        if s in ZZ and s > 1:
            return ((-1) ** s) * psi(s - 1, x) / factorial(s - 1)
        elif s in ZZ and s < 0:
            return -bernoulli_polynomial(x, -s + 1) / (-s + 1)
        else:
            return
    def order(self):
        r"""
        Returns the number of elements of ``self``.

        EXAMPLES::

            sage: F.<a> = GF(4)
            sage: SemimonomialTransformationGroup(F, 5).order() == (4-1)**5 * factorial(5) * 2
            True
        """
        from sage.functions.other import factorial
        from sage.categories.homset import End
        n = self.degree()
        R = self.base_ring()
        if R.is_field():
            multgroup_size = len(R)-1
            autgroup_size = R.degree()
        else:
            multgroup_size = R.unit_group_order()
            autgroup_size = len([x for x in End(R) if x.is_injective()])
        return multgroup_size**n * factorial(n) * autgroup_size
Exemple #30
0
            def to_symmetric_function(self):
                r"""
                Take a function in the `\mathbf{w}` basis, and return its
                symmetric realization, when possible, expressed in the
                homogeneous basis of symmetric functions.

                OUTPUT:

                - If ``self`` is a symmetric function, then the expansion
                  in the homogeneous basis of the symmetric functions is returned.
                  Otherwise an error is raised.

                EXAMPLES::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + w[[1,3],[2]]
                    sage: elt.to_symmetric_function()
                    h[2, 1]
                    sage: elt = w.sum_of_partitions([2,1,1]) / 2
                    sage: elt.to_symmetric_function()
                    1/2*h[2, 1, 1]

                TESTS::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: w(0).to_symmetric_function()
                    0
                    sage: w([]).to_symmetric_function()
                    h[]
                    sage: (2*w([])).to_symmetric_function()
                    2*h[]
                """
                if not self.is_symmetric():
                    raise ValueError("not a symmetric function")
                h = SymmetricFunctions(self.parent().base_ring()).homogeneous()
                d = {A.shape(): c for A, c in self}
                return h.sum_of_terms(
                    [(AA, cc / prod([factorial(_) for _ in AA.to_exp()]))
                     for AA, cc in d.items()],
                    distinct=True)
Exemple #31
0
        def idempotent(self, la):
            """
            Return the idemponent corresponding to the partition ``la``.

            EXAMPLES::

                sage: I = DescentAlgebra(QQ, 4).I()
                sage: E = I.idempotent([3,1]); E
                1/2*I[1, 3] + 1/2*I[3, 1]
                sage: E*E == E
                True
                sage: E2 = I.idempotent([2,1,1]); E2
                1/6*I[1, 1, 2] + 1/6*I[1, 2, 1] + 1/6*I[2, 1, 1]
                sage: E2*E2 == E2
                True
                sage: E*E2 == I.zero()
                True
            """
            from sage.combinat.permutation import Permutations
            k = len(la)
            C = Compositions(self.realization_of()._n)
            return self.sum_of_terms([(C(x), ~QQ(factorial(k))) for x in Permutations(la)])
Exemple #32
0
            def to_symmetric_function(self):
                r"""
                Take a function in the `\mathbf{w}` basis, and return its
                symmetric realization, when possible, expressed in the
                homogeneous basis of symmetric functions.

                OUTPUT:

                - If ``self`` is a symmetric function, then the expansion
                  in the homogeneous basis of the symmetric functions is returned.
                  Otherwise an error is raised.

                EXAMPLES::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + w[[1,3],[2]]
                    sage: elt.to_symmetric_function()
                    h[2, 1]
                    sage: elt = w.sum_of_partitions([2,1,1]) / 2
                    sage: elt.to_symmetric_function()
                    1/2*h[2, 1, 1]

                TESTS::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: w(0).to_symmetric_function()
                    0
                    sage: w([]).to_symmetric_function()
                    h[]
                    sage: (2*w([])).to_symmetric_function()
                    2*h[]
                """
                if not self.is_symmetric():
                    raise ValueError("not a symmetric function")
                h = SymmetricFunctions(self.parent().base_ring()).homogeneous()
                d = {A.shape(): c for A, c in self}
                return h.sum_of_terms(
                    [(AA, cc / prod([factorial(_) for _ in AA.to_exp()])) for AA, cc in d.items()], distinct=True
                )
Exemple #33
0
def coeff_sp(J, I):
    r"""
    Returns the coefficient `sp_{J,I}` as defined in [NCSF]_.

    INPUT:

    - ``J`` -- a composition
    - ``I`` -- a composition refining ``J``

    OUTPUT:

    - integer

    EXAMPLES::

        sage: from sage.combinat.ncsf_qsym.combinatorics import coeff_sp
        sage: coeff_sp(Composition([1,1,1]), Composition([2,1]))
        2
        sage: coeff_sp(Composition([2,1]), Composition([3]))
        4
    """
    return prod(factorial(len(K)) * prod(K) for K in J.refinement_splitting(I))
Exemple #34
0
def coeff_sp(J,I):
    r"""
    Returns the coefficient `sp_{J,I}` as defined in [NCSF]_.

    INPUT:

    - ``J`` -- a composition
    - ``I`` -- a composition refining ``J``

    OUTPUT:

    - integer

    EXAMPLES::

        sage: from sage.combinat.ncsf_qsym.combinatorics import coeff_sp
        sage: coeff_sp(Composition([1,1,1]), Composition([2,1]))
        2
        sage: coeff_sp(Composition([2,1]), Composition([3]))
        4
    """
    return prod(factorial(len(K))*prod(K) for K in J.refinement_splitting(I))
Exemple #35
0
        def idempotent(self, la):
            """
            Return the idemponent corresponding to the partition ``la``.

            EXAMPLES::

                sage: I = DescentAlgebra(QQ, 4).I()
                sage: E = I.idempotent([3,1]); E
                1/2*I[1, 3] + 1/2*I[3, 1]
                sage: E*E == E
                True
                sage: E2 = I.idempotent([2,1,1]); E2
                1/6*I[1, 1, 2] + 1/6*I[1, 2, 1] + 1/6*I[2, 1, 1]
                sage: E2*E2 == E2
                True
                sage: E*E2 == I.zero()
                True
            """
            from sage.combinat.permutation import Permutations
            k = len(la)
            C = Compositions(self.realization_of()._n)
            return self.sum_of_terms([(C(x), ~QQ(factorial(k)))
                                      for x in Permutations(la)])
Exemple #36
0
    def _eval_(self, s, x):
        r"""
        TESTS::

            sage: hurwitz_zeta(x, 1)
            zeta(x)
            sage: hurwitz_zeta(4, 3)
            1/90*pi^4 - 17/16
            sage: hurwitz_zeta(-4, x)
            -1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
            sage: hurwitz_zeta(3, 0.5)
            8.41439832211716
        """
        co = get_coercion_model().canonical_coercion(s, x)[0]
        if is_inexact(co) and not isinstance(co, Expression):
            return self._evalf_(s, x, parent=parent(co))
        if x == 1:
            return zeta(s)
        if s in ZZ and s > 1:
            return ((-1) ** s) * psi(s - 1, x) / factorial(s - 1)
        elif s in ZZ and s < 0:
            return -bernoulli_polynomial(x, -s + 1) / (-s + 1)
        else:
            return
    def _eval_(self, s, x):
        r"""
        TESTS::

            sage: hurwitz_zeta(x, 1)
            zeta(x)
            sage: hurwitz_zeta(4, 3)
            1/90*pi^4 - 17/16
            sage: hurwitz_zeta(-4, x)
            -1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
            sage: hurwitz_zeta(3, 0.5)
            8.41439832211716
        """
        co = get_coercion_model().canonical_coercion(s, x)[0]
        if is_inexact(co) and not isinstance(co, Expression):
            return self._evalf_(s, x, parent=parent(co))
        if x == 1:
            return zeta(s)
        if s in ZZ and s > 1:
            return ((-1)**s) * psi(s - 1, x) / factorial(s - 1)
        elif s in ZZ and s < 0:
            return -bernoulli_polynomial(x, -s + 1) / (-s + 1)
        else:
            return
def kontsevich_star_product_terms(K, prime_weights, precision):
    """
    Kontsevich star product terms in KontsevichGraphSums ``K`` up to order ``precision``.

    INPUT:

    - ``K`` - KontsevichGraphSums module.
    - ``prime_weights`` - weights of prime graphs, modulo edge labeling and mirror images.

    EXAMPLES::

        sage: K = KontsevichGraphSums(QQ);
        sage: weights = {}
        sage: weights[KontsevichGraph({'F' : {},'G' : {}}, ground_vertices=('F','G'), immutable=True)] = 1
        sage: weights[KontsevichGraph([(1, 'F', 'L'), (1, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/2
        sage: weights[KontsevichGraph([(1, 2, 'R'), (1, 'F', 'L'), (2, 1, 'L'), (2, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/24
        sage: weights[KontsevichGraph([(1, 2, 'R'), (1, 'F', 'L'), (2, 'F', 'L'), (2, 'G', 'R')], ground_vertices=('F','G'), immutable=True)] = 1/12
        sage: S.<h> = KontsevichGraphSeriesRng(K, star_product_terms = kontsevich_star_product_terms(K, weights, 2), default_prec = 2);
        sage: F = S(KontsevichGraph(('F',),immutable=True));
        sage: G = S(KontsevichGraph(('G',),immutable=True));
        sage: H = S(KontsevichGraph(('H',),immutable=True));
        sage: A = (F*G)*H - F*(G*H)
        sage: A.reduce()
        sage: len(A[2])  # three terms in the Jacobi identity
        3
    """
    series_terms = {0 : K([(prime_weights[KontsevichGraph(('F','G'), immutable=True)],
                            KontsevichGraph(('F','G'), immutable=True))])}
    for n in range(1, precision + 1):
        term = K(0)
        for graph in kontsevich_graphs(n, modulo_edge_labeling=True, positive_differential_order=True):
            coeff = kontsevich_weight(graph, prime_weights)*graph.multiplicity()/factorial(len(graph.internal_vertices()))
            if coeff != 0:
                term += K([(coeff, graph)])
        series_terms[n] = term
    return series_terms
    def __call__(self, x, type_3_pole_check=True):
        """
        Makes dynamical systems on Berkovich space over ``Cp`` callable.

        INPUT:

        - ``x`` -- a point of projective Berkovich space over ``Cp``.

        - type_3_pole_check -- (default ``True``) A bool. WARNING:
          changing the value of type_3_pole_check can lead to mathematically
          incorrect answers. Only set to ``False`` if there are NO
          poles of the dynamical system in the disk corresponding
          to the type III point ``x``. See Examples.

        OUTPUT: A point of projective Berkovich space over ``Cp``.

        EXAMPLES::

            sage: P.<x,y> = ProjectiveSpace(Qp(3), 1)
            sage: g = DynamicalSystem_projective([x^2 + y^2, x*y])
            sage: G = DynamicalSystem_Berkovich(g)
            sage: B = G.domain()
            sage: Q3 = B(0, 1)
            sage: G(Q3)
            Type II point centered at (0 : 1 + O(3^20)) of radius 3^0

        ::

            sage: P.<x,y> = ProjectiveSpace(Qp(3), 1)
            sage: H = DynamicalSystem_Berkovich([x*y^2, x^3 + 20*y^3])
            sage: B = H.domain()
            sage: Q4 = B(1/9, 1.5)
            sage: H(Q4, False)
            Type III point centered at (3^4 + 3^10 + 2*3^11 + 2*3^13 + 2*3^14 +
            2*3^15 + 3^17 + 2*3^18 + 2*3^19 + 3^20 + 3^21 + 3^22 + O(3^24) : 1 +
            O(3^20)) of radius 0.00205761316872428

        ALGORITHM:

        - For type II points, we use the approach outlined in Example
          7.37 of [Ben2019]_
        - For type III points, we use Proposition 7.6 of [Ben2019]_
        """
        if not isinstance(x.parent(), Berkovich_Cp_Projective):
            try:
                x = self.domain()(x)
            except:
                raise TypeError(
                    'action of dynamical system not defined on %s' %
                    x.parent())
        if x.parent().is_padic_base() != self.domain().is_padic_base():
            raise ValueError('x was not backed by the same type of field as f')
        if x.prime() != self.domain().prime():
            raise ValueError(
                'x and f are defined over Berkovich spaces over Cp for different p'
            )
        if x.type_of_point() == 1:
            return self.domain()(self._system(x.center()))
        if x.type_of_point() == 4:
            raise NotImplementedError(
                'action on Type IV points not implemented')
        f = self._system
        if x.type_of_point() == 2:
            if self.domain().is_number_field_base():
                ideal = self.domain().ideal()
                ring_of_integers = self.domain().base_ring().ring_of_integers()
            field = f.domain().base_ring()
            M = Matrix([[field(x.prime()**(-1 * x.power())),
                         x.center()[0]], [field(0), field(1)]])
            F = list(f * M)
            R = field['z']
            S = f.domain().coordinate_ring()
            z = R.gen(0)
            dehomogenize_hom = S.hom([z, 1])
            for i in range(len(F)):
                F[i] = dehomogenize_hom(F[i])
            lcm = field(1)
            for poly in F:
                for i in poly:
                    if i != 0:
                        lcm = i.denominator().lcm(lcm)
            for i in range(len(F)):
                F[i] *= lcm
            gcd = [i for i in F[0] if i != 0][0]
            for poly in F:
                for i in poly:
                    if i != 0:
                        gcd = gcd * i * gcd.lcm(i).inverse_of_unit()
            for i in range(len(F)):
                F[i] *= gcd.inverse_of_unit()
            gcd = F[0].gcd(F[1])
            F[0] = F[0].quo_rem(gcd)[0]
            F[1] = F[1].quo_rem(gcd)[0]
            fraction = []
            for poly in F:
                new_poly = []
                for i in poly:
                    if self.domain().is_padic_base():
                        new_poly.append(i.residue())
                    else:
                        new_poly.append(ring_of_integers(i).mod(ideal))
                new_poly = R(new_poly)
                fraction.append((new_poly))
            gcd = fraction[0].gcd(fraction[1])
            num = fraction[0].quo_rem(gcd)[0]
            dem = fraction[1].quo_rem(gcd)[0]
            if dem.is_zero():
                f = DynamicalSystem_affine(F[0] / F[1]).homogenize(1)
                f = f.conjugate(Matrix([[0, 1], [1, 0]]))
                g = DynamicalSystem_Berkovich(f)
                return g(self.domain()(QQ(0), QQ(1))).involution_map()
            # if the reduction is not constant, the image is the Gauss point
            if not (num.is_constant() and dem.is_constant()):
                return self.domain()(QQ(0), QQ(1))
            if self.domain().is_padic_base():
                reduced_value = field(num *
                                      dem.inverse_of_unit()).lift_to_precision(
                                          field.precision_cap())
            else:
                reduced_value = field(num * dem.inverse_of_unit())
            new_num = F[0] - reduced_value * F[1]
            if self.domain().is_padic_base():
                power_of_p = min([i.valuation() for i in new_num])
            else:
                power_of_p = min([i.valuation(ideal) for i in new_num])
            inverse_map = field(x.prime()**power_of_p) * z + reduced_value
            if self.domain().is_padic_base():
                return self.domain()(inverse_map(0),
                                     (inverse_map(1) - inverse_map(0)).abs())
            else:
                val = (inverse_map(1) - inverse_map(0)).valuation(ideal)
                if val == Infinity:
                    return self.domain()(inverse_map(0), 0)
                return self.domain()(inverse_map(0), x.prime()**(-1 * val))
        # point is now type III, so we compute using Proposition 7.6 [of Benedetto]
        affine_system = f.dehomogenize(1)
        dem = affine_system.defining_polynomials()[0].denominator(
        ).univariate_polynomial()
        if type_3_pole_check:
            if self.domain().is_padic_base():
                factorization = [i[0] for i in dem.factor()]
                for factor in factorization:
                    if factor.degree() >= 2:
                        try:
                            factor_root_field = factor.root_field('a')
                            factor = factor.change_ring(factor_root_field)
                        except:
                            raise NotImplementedError(
                                'cannot check if poles lie in type III disk')
                    else:
                        factor_root_field = factor.base_ring()
                    center = factor_root_field(x.center()[0])
                    for pole in [i[0] for i in factor.roots()]:
                        if (center - pole).abs() <= x.radius():
                            raise NotImplementedError(
                                'image of type III point not implemented when poles in disk'
                            )
            else:
                dem_splitting_field, embedding = dem.splitting_field('a', True)
                poles = [i[0] for i in dem.roots(dem_splitting_field)]
                primes_above = dem_splitting_field.primes_above(
                    self.domain().ideal())
                # check if all primes of the extension map the roots to outside
                # the disk corresponding to the type III point
                for prime in primes_above:
                    no_poles = True
                    for pole in poles:
                        valuation = (embedding(x.center()[0]) -
                                     pole).valuation(prime)
                        if valuation == Infinity:
                            no_poles = False
                            break
                        elif x.prime()**(-1 * valuation /
                                         prime.absolute_ramification_index()
                                         ) <= x.radius():
                            no_poles = False
                            break
                    if not no_poles:
                        break
                if not no_poles:
                    raise NotImplementedError(
                        'image of type III not implemented when poles in disk')
        nth_derivative = f.dehomogenize(1).defining_polynomials()[0]
        variable = nth_derivative.parent().gens()[0]
        a = x.center()[0]
        Taylor_expansion = []
        from sage.functions.other import factorial
        for i in range(f.degree() + 1):
            Taylor_expansion.append(nth_derivative(a) * 1 / factorial(i))
            nth_derivative = nth_derivative.derivative(variable)
        r = x.radius()
        new_center = f(a)
        if self.domain().is_padic_base():
            new_radius = max([
                Taylor_expansion[i].abs() * r**i
                for i in range(1, len(Taylor_expansion))
            ])
        else:
            if prime is None:
                prime = x.parent().ideal()
                dem_splitting_field = x.parent().base_ring()
            p = x.prime()
            new_radius = 0
            for i in range(1, len(Taylor_expansion)):
                valuation = dem_splitting_field(
                    Taylor_expansion[i]).valuation(prime)
                new_radius = max(
                    new_radius,
                    p**(-valuation / prime.absolute_ramification_index()) *
                    r**i)
        return self.domain()(new_center, new_radius)
Exemple #40
0
def number_of_partial_injection(n, algorithm='binomial'):
    r"""
    Return the number of partial injections on an set of `n` elements
    defined on a subset of `k` elements for each `k` in `0, 1, ..., n`.

    INPUT:

    - ``n`` -- integer
    - ``algorithm`` -- string (default: ``'binomial'``), ``'binomial'``
      or ``'recursive'``. When n>50, the binomial coefficient approach is
      faster (linear time vs quadratic time).

    OUTPUT:

        list

    .. NOTE::

        The recursive code of this function was originally written by
        Vincent Delecroix (Nov 30, 2017) the day after a discussion with
        Pascal Weil and me at LaBRI.

    EXAMPLES::

        sage: from slabbe import number_of_partial_injection
        sage: number_of_partial_injection(0)
        [1]
        sage: number_of_partial_injection(1)
        [1, 1]
        sage: number_of_partial_injection(2)
        [1, 4, 2]
        sage: number_of_partial_injection(3)
        [1, 9, 18, 6]
        sage: number_of_partial_injection(4)
        [1, 16, 72, 96, 24]
        sage: number_of_partial_injection(5)
        [1, 25, 200, 600, 600, 120]
        sage: number_of_partial_injection(6)
        [1, 36, 450, 2400, 5400, 4320, 720]
        sage: number_of_partial_injection(7)
        [1, 49, 882, 7350, 29400, 52920, 35280, 5040]
        sage: number_of_partial_injection(8)
        [1, 64, 1568, 18816, 117600, 376320, 564480, 322560, 40320]

    TESTS::

        sage: number_of_partial_injection(8, algorithm='recursive')
        [1, 64, 1568, 18816, 117600, 376320, 564480, 322560, 40320]

    REFERENCE:

        https://oeis.org/A144084
    """
    if algorithm == 'binomial':
        return [binomial(n,k)**2*factorial(k) for k in range(n+1)]
    elif algorithm == 'recursive':
        L = [ZZ(1)]
        for t in range(1, n+1):
            L.append(t * L[-1])
            for k in range(t-1, 0, -1):
                L[k] = (t * L[k]) // (t-k) + t * L[k-1]
        return L
Exemple #41
0
 def f(partition):
     n = partition.size()
     return (StandardTableaux(partition).cardinality() * t**n /
             factorial(n))
def _compute_sw_spherical_harm(s,
                               l,
                               m,
                               theta,
                               phi,
                               condon_shortley=True,
                               numerical=None):
    r"""
    Compute the spin-weighted spherical harmonic of spin weight ``s`` and
    indices ``(l,m)`` as a callable symbolic expression in (theta,phi)

    INPUT:

    - ``s`` -- integer; the spin weight
    - ``l`` -- non-negative integer; the harmonic degree
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number
    - ``theta`` -- colatitude angle
    - ``phi`` -- azimuthal angle
    - ``condon_shortley`` -- (default: ``True``) determines whether the
      Condon-Shortley phase of `(-1)^m` is taken into account (see below)
    - ``numerical`` -- (default: ``None``) determines whether a symbolic or
      a numerical computation of a given type is performed; allowed values are

      - ``None``: a symbolic computation is performed
      - ``RDF``: Sage's machine double precision floating-point numbers
        (``RealDoubleField``)
      - ``RealField(n)``, where ``n`` is a number of bits: Sage's
        floating-point numbers with an arbitrary precision; note that ``RR`` is
        a shortcut for ``RealField(53)``.
      - ``float``: Python's floating-point numbers


    OUTPUT:

    - `{}_s Y_l^m(\theta,\phi)` either

      - as a symbolic expression if ``numerical`` is ``None``
      - or a pair of floating-point numbers, each of them being of the type
        corresponding to ``numerical`` and representing respectively the
        real and imaginary parts of `{}_s Y_l^m(\theta,\phi)`

    ALGORITHM:

    The spin-weighted spherical harmonic is evaluated according to Eq. (3.1)
    of J. N. Golberg et al., J. Math. Phys. **8**, 2155 (1967)
    [:doi:`10.1063/1.1705135`], with an extra `(-1)^m` factor (the so-called
    *Condon-Shortley phase*) if ``condon_shortley`` is ``True``, the actual
    formula being then the one given in
    :wikipedia:`Spin-weighted_spherical_harmonics#Calculating`

    TESTS::

        sage: from kerrgeodesic_gw.spin_weighted_spherical_harm import _compute_sw_spherical_harm
        sage: theta, phi = var("theta phi")
        sage: _compute_sw_spherical_harm(-2, 2, 1, theta, phi)
        1/4*(sqrt(5)*cos(theta) + sqrt(5))*e^(I*phi)*sin(theta)/sqrt(pi)

    """
    if abs(s) > l:
        return ZZ(0)
    if abs(theta) < 1.e-6:  # TODO: fix the treatment of small theta values
        if theta < 0:  #       possibly with exact formula for theta=0
            theta = -1.e-6  #
        else:  #
            theta = 1.e-6  #
    cott2 = cos(theta / 2) / sin(theta / 2)
    res = 0
    for r in range(l - s + 1):
        res += (-1)**(l - r - s) * (binomial(l - s, r) * binomial(
            l + s, r + s - m) * cott2**(2 * r + s - m))
    res *= sin(theta / 2)**(2 * l)
    ff = factorial(l + m) * factorial(l - m) * (2 * l + 1) / (
        factorial(l + s) * factorial(l - s))
    if numerical:
        pre = sqrt(numerical(ff) / numerical(pi)) / 2
    else:
        pre = sqrt(ff) / (2 * sqrt(pi))
    res *= pre
    if condon_shortley:
        res *= (-1)**m
    if numerical:
        return (numerical(res * cos(m * phi)), numerical(res * sin(m * phi)))
    # Symbolic case:
    res = res.simplify_full()
    res = res.reduce_trig()  # get rid of cos(theta/2) and sin(theta/2)
    res = res.simplify_trig()  # further trigonometric simplifications
    res *= exp(I * m * phi)
    return res
Exemple #43
0
    def hodge_star(self, metric):
        r"""
        Compute the Hodge dual of the differential form. 
        
        If ``self`` is a `p`-form `A`, its Hodge dual is the `(n-p)`-form
        `*A` defined by (`n` being the manifold's dimension)
        
        .. MATH::
            
            *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p}
                \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}}
                
        where $\epsilon$ is the volume form associated with some 
        pseudo-Riemannian metric `g` on the manifold, and the indices 
        `k_1,\ldots, k_p` are raised with `g`. 
        
        INPUT:
        
        - ``metric``: the pseudo-Riemannian metric `g` defining the Hodge dual, 
          via the volume form `\epsilon`; must be an instance of :class:`Metric`
        
        OUTPUT:
        
        - the `(n-p)`-form `*A` 
        
        EXAMPLES:
        
        Hodge star of a 1-form in the Euclidean space `R^3`::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: X = Chart(m, 'x y z', 'xyz')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: a = OneForm(m, 'A')
            sage: var('Ax Ay Az')
            (Ax, Ay, Az)
            sage: a[:] = (Ax, Ay, Az)
            sage: sa = a.hodge_star(g) ; sa
            2-form '*A' on the 3-dimensional manifold 'M'
            sage: sa.show()
            *A = Az dx/\dy - Ay dx/\dz + Ax dy/\dz
            sage: ssa = sa.hodge_star(g) ; ssa
            1-form '**A' on the 3-dimensional manifold 'M'
            sage: ssa.show()
            **A = Ax dx + Ay dy + Az dz
            sage: ssa == a  # must hold for a Riemannian metric in dimension 3
            True
        
        Hodge star of a 0-form (scalar field) in `R^3`::
        
            sage: f = ScalarField(m, function('F',x,y,z), name='f')
            sage: sf = f.hodge_star(g) ; sf
            3-form '*f' on the 3-dimensional manifold 'M'
            sage: sf.show()
            *f = F(x, y, z) dx/\dy/\dz
            sage: ssf = sf.hodge_star(g) ; ssf
            scalar field '**f' on the 3-dimensional manifold 'M'
            sage: ssf.show()
            **f: (x, y, z) |--> F(x, y, z)
            sage: ssf == f # must hold for a Riemannian metric
            True
            
        Hodge star of a 0-form in Minkowksi spacetime::
        
            sage: m = Manifold(4, 'M')
            sage: X = Chart(m, 't x y z', 'txyz')
            sage: g = Metric(m, 'g', signature=2)
            sage: g[0,0], g[1,1], g[2,2], g[3,3] = -1, 1, 1, 1
            sage: g.show()  # Minkowski metric
            g = -dt*dt + dx*dx + dy*dy + dz*dz
            sage: var('f0')
            f0
            sage: f = ScalarField(m, f0, name='f')
            sage: sf = f.hodge_star(g) ; sf 
            4-form '*f' on the 4-dimensional manifold 'M'
            sage: sf.show()
            *f = f0 dt/\dx/\dy/\dz
            sage: ssf = sf.hodge_star(g) ; ssf
            scalar field '**f' on the 4-dimensional manifold 'M'
            sage: ssf.show()
            **f: (t, x, y, z) |--> -f0
            sage: ssf == -f  # must hold for a Lorentzian metric             
            True

        Hodge star of a 1-form in Minkowksi spacetime::
        
            sage: a = OneForm(m, 'A')
            sage: var('At Ax Ay Az')
            (At, Ax, Ay, Az)
            sage: a[:] = (At, Ax, Ay, Az)
            sage: a.show()
            A = At dt + Ax dx + Ay dy + Az dz
            sage: sa = a.hodge_star(g) ; sa
            3-form '*A' on the 4-dimensional manifold 'M'
            sage: sa.show()
            *A = -Az dt/\dx/\dy + Ay dt/\dx/\dz - Ax dt/\dy/\dz - At dx/\dy/\dz
            sage: ssa = sa.hodge_star(g) ; ssa
            1-form '**A' on the 4-dimensional manifold 'M'
            sage: ssa.show()
            **A = At dt + Ax dx + Ay dy + Az dz
            sage: ssa == a  # must hold for a Lorentzian metric in dimension 4
            True

        Hodge star of a 2-form in Minkowksi spacetime::
        
            sage: F = DiffForm(m, 2, 'F')    
            sage: var('Ex Ey Ez Bx By Bz')
            (Ex, Ey, Ez, Bx, By, Bz)
            sage: F[0,1], F[0,2], F[0,3] = -Ex, -Ey, -Ez
            sage: F[1,2], F[1,3], F[2,3] = Bz, -By, Bx
            sage: F[:]
            [  0 -Ex -Ey -Ez]
            [ Ex   0  Bz -By]
            [ Ey -Bz   0  Bx]
            [ Ez  By -Bx   0]
            sage: sF = F.hodge_star(g) ; sF
            2-form '*F' on the 4-dimensional manifold 'M'
            sage: sF[:]
            [  0  Bx  By  Bz]
            [-Bx   0  Ez -Ey]
            [-By -Ez   0  Ex]
            [-Bz  Ey -Ex   0]
            sage: ssF = sF.hodge_star(g) ; ssF
            2-form '**F' on the 4-dimensional manifold 'M'
            sage: ssF[:]   
            [  0  Ex  Ey  Ez]
            [-Ex   0 -Bz  By]
            [-Ey  Bz   0 -Bx]
            [-Ez -By  Bx   0]
            sage: ssF.show()
            **F = Ex dt/\dx + Ey dt/\dy + Ez dt/\dz - Bz dx/\dy + By dx/\dz - Bx dy/\dz
            sage: F.show()
            F = -Ex dt/\dx - Ey dt/\dy - Ez dt/\dz + Bz dx/\dy - By dx/\dz + Bx dy/\dz
            sage: ssF == -F  # must hold for a Lorentzian metric in dimension 4
            True

        Test of the standard identity
        
        .. MATH::
            
            *(A\wedge B) = \epsilon(A^\sharp, B^\sharp, ., .)
            
        where `A` and `B` are any 1-forms and `A^\sharp` and `B^\sharp` the 
        vectors associated to them by the metric `g` (index raising)::

            sage: b = OneForm(m, 'B')
            sage: var('Bt Bx By Bz')
            (Bt, Bx, By, Bz)
            sage: b[:] = (Bt, Bx, By, Bz) ; b.show()
            B = Bt dt + Bx dx + By dy + Bz dz
            sage: epsilon = g.volume_form()
            sage: (a.wedge(b)).hodge_star(g) == epsilon.contract(0, a.up(g), 0).contract(0, b.up(g), 0)
            True

        """
        from sage.functions.other import factorial
        from utilities import format_unop_txt, format_unop_latex
        p = self.rank
        eps = metric.volume_form(p)
        if p == 0:
            resu = self * eps
        else:
            resu = self.contract(0, eps, 0)
            for j in range(1, p):
                resu = resu.self_contract(0, p - j)
            if p > 1:
                resu = resu / factorial(p)
        # Name and LaTeX name of the result:
        resu.name = format_unop_txt('*', self.name)
        resu.latex_name = format_unop_latex(r'\star ', self.latex_name)
        return resu
Exemple #44
0
def bch_iterator(X=None, Y=None):
    r"""
    A generator function which returns successive terms of the
    Baker-Campbell-Hausdorff formula.

    INPUT:

    - ``X`` -- (optional) an element of a Lie algebra
    - ``Y`` -- (optional) an element of a Lie algebra

    The BCH formula is an expression for `\log(\exp(X)\exp(Y))` as a sum of Lie
    brackets of ``X`` and ``Y`` with rational coefficients. In arbitrary Lie
    algebras, the infinite sum is only guaranteed to converge for ``X`` and
    ``Y`` close to zero.

    If the elements ``X`` and ``Y`` are not given, then the iterator will
    return successive terms of the abstract BCH formula, i.e., the BCH formula
    for the generators of the free Lie algebra on 2 generators.

    If the Lie algebra containing ``X`` and ``Y`` is not nilpotent, the
    iterator will output infinitely many elements. If the Lie algebra is
    nilpotent, the number of elements outputted is equal to the nilpotency step.

    EXAMPLES:

    The terms of the abstract BCH formula up to fifth order brackets::

        sage: from sage.algebras.lie_algebras.bch import bch_iterator
        sage: bch = bch_iterator()
        sage: next(bch)
        X + Y
        sage: next(bch)
        1/2*[X, Y]
        sage: next(bch)
        1/12*[X, [X, Y]] + 1/12*[[X, Y], Y]
        sage: next(bch)
        1/24*[X, [[X, Y], Y]]
        sage: next(bch)
        -1/720*[X, [X, [X, [X, Y]]]] + 1/180*[X, [X, [[X, Y], Y]]]
        + 1/360*[[X, [X, Y]], [X, Y]] + 1/180*[X, [[[X, Y], Y], Y]]
        + 1/120*[[X, Y], [[X, Y], Y]] - 1/720*[[[[X, Y], Y], Y], Y]

    For nilpotent Lie algebras the BCH formula only has finitely many terms::

        sage: L = LieAlgebra(QQ, 2, step=3)
        sage: L.inject_variables()
        Defining X_1, X_2, X_12, X_112, X_122
        sage: [Z for Z in bch_iterator(X_1, X_2)]
        [X_1 + X_2, 1/2*X_12, 1/12*X_112 + 1/12*X_122]
        sage: [Z for Z in bch_iterator(X_1 + X_2, X_12)]
        [X_1 + X_2 + X_12, 1/2*X_112 - 1/2*X_122, 0]

    The elements ``X`` and ``Y`` don't need to be elements of the same Lie
    algebra if there is a coercion from one to the other::

        sage: L = LieAlgebra(QQ, 3, step=2)
        sage: L.inject_variables()
        Defining X_1, X_2, X_3, X_12, X_13, X_23
        sage: S = L.subalgebra(X_1, X_2)
        sage: bch1 = [Z for Z in bch_iterator(S(X_1), S(X_2))]; bch1
        [X_1 + X_2, 1/2*X_12]
        sage: bch1[0].parent() == S
        True
        sage: bch2 = [Z for Z in bch_iterator(S(X_1), X_3)]; bch2
        [X_1 + X_3, 1/2*X_13]
        sage: bch2[0].parent() == L
        True

    The BCH formula requires a coercion from the rationals::

        sage: L.<X,Y,Z> = LieAlgebra(ZZ, 2, step=2)
        sage: bch = bch_iterator(X, Y); next(bch)
        Traceback (most recent call last):
        ...
        TypeError: the BCH formula is not well defined since Integer Ring has no coercion from Rational Field

    TESTS:

    Compare to the BCH formula up to degree 5 given by wikipedia::

        sage: from sage.algebras.lie_algebras.bch import bch_iterator
        sage: bch = bch_iterator()
        sage: L.<X,Y> = LieAlgebra(QQ)
        sage: L = L.Lyndon()
        sage: computed_BCH = L.sum(next(bch) for k in range(5))
        sage: wikiBCH = X + Y + 1/2*L[X,Y] + 1/12*(L[X,[X,Y]] + L[Y,[Y,X]])
        sage: wikiBCH += -1/24*L[Y,[X,[X,Y]]]
        sage: wikiBCH += -1/720*(L[Y,[Y,[Y,[Y,X]]]] + L[X,[X,[X,[X,Y]]]])
        sage: wikiBCH += 1/360*(L[X,[Y,[Y,[Y,X]]]] + L[Y,[X,[X,[X,Y]]]])
        sage: wikiBCH += 1/120*(L[Y,[X,[Y,[X,Y]]]] + L[X,[Y,[X,[Y,X]]]])
        sage: computed_BCH == wikiBCH
        True

    ALGORITHM:

    The BCH formula `\log(\exp(X)\exp(Y)) = \sum_k Z_k` is computed starting
    from `Z_1 = X + Y`, by the recursion

    .. MATH::

        (m+1)Z_{m+1} =  \frac{1}{2}[X - Y, Z_m]
        + \sum_{2\leq 2p \leq m}\frac{B_{2p}}{(2p)!}\sum_{k_1+\cdots+k_{2p}=m}
        [Z_{k_1}, [\cdots [Z_{k_{2p}}, X + Y]\cdots],

    where `B_{2p}` are the Bernoulli numbers, see Lemma 2.15.3. in [Var1984]_.

    .. WARNING::

        The time needed to compute each successive term increases exponentially.
        For example on one machine iterating through `Z_{11},...,Z_{18}` for a
        free Lie algebra, computing each successive term took 4-5 times longer,
        going from 0.1s for `Z_{11}` to 21 minutes for `Z_{18}`.
    """
    if X is None or Y is None:
        L = LieAlgebra(QQ, ['X', 'Y']).Lyndon()
        X, Y = L.lie_algebra_generators()
    else:
        X, Y = canonical_coercion(X, Y)
        L = X.parent()

    R = L.base_ring()
    if not R.has_coerce_map_from(QQ):
        raise TypeError("the BCH formula is not well defined since %s "
                        "has no coercion from %s" % (R, QQ))

    xdif = X - Y
    Z = [0, X + Y]  # 1-based indexing for convenience
    m = 1
    yield Z[1]

    while True:
        m += 1
        if L in LieAlgebras.Nilpotent and m > L.step():
            return

        # apply the recursion formula of [Var1984]
        Zm = ~QQ(2 * m) * xdif.bracket(Z[-1])
        for p in range(1, (m - 1) // 2 + 1):
            partitions = IntegerListsLex(m - 1, length=2 * p, min_part=1)
            coeff = bernoulli(2 * p) / QQ(m * factorial(2 * p))
            for kvec in partitions:
                W = Z[1]
                for k in kvec:
                    W = Z[k].bracket(W)
                Zm += coeff * W

        Z.append(Zm)
        yield Zm
Exemple #45
0
def fiej(i, j, d):  # fiejcoeff_on_highest_weight
    """
    INPUT:

    - `i`, `j`, `d` -- nonnegative integers

    OUTPUT: a nonnegative integer

    Let $f = x\partial_y and e = y\partial_x$, and `p` be a highest
    weight polynomial of weight `d`.  Then `c=fiej(i,j,d)` is such
    that `f^i e^j p = c e^{j-i} p`. `c` is given by the formula::

    .. MATH:: \prod_{k = j-i+1}^j (kd - 2 \binom{k}{2})

    EXAMPLES::

        sage: R = QQ['x,y']
        sage: R.inject_variables()
        Defining x, y
        sage: def f(p): return x*diff(p,y)
        sage: def e(p): return y*diff(p,x)

        sage: fiej(0,0,3)
        1

        sage: fiej(0,1,3)
        1
        sage: f(e(x^3)) / x^3
        3
        sage: fiej(1,1,3)
        3
        sage: f(f(e(x^3)))
        0
        sage: fiej(2,1,3)
        0

        sage: fiej(0,2,3)
        1
        sage: f(e(e(x^3))) / e(x^3)
        4
        sage: fiej(1,2,3)
        4
        sage: f(f(e(e(x^3)))) / x^3
        12
        sage: fiej(2,2,3)
        12


        sage: fiej(0,3,3)
        1
        sage: f(e(e(e(x^3)))) / e(e(x^3))
        3
        sage: fiej(1,3,3)
        3
        sage: f(f(e(e(e(x^3))))) / e(x^3)
        12
        sage: f(f(f(e(e(e(x^3)))))) / x^3
        36
        sage: fiej(3,3,3)
        36
        sage: fiej(4,3,3)
        0

        sage: f(f(f(e(e(e(x^9)))))) / x^9
        3024
        sage: fiej(3,3,9)
        3024
    """
    return binomial(j, i) * binomial(d - j + i, i) * factorial(i)**2
Exemple #46
0
    def cardinality(self):
        r"""
        Return the number of linear extensions by using the determinant
        formula for counting linear extensions of mobiles.

        EXAMPLES::

            sage: from sage.combinat.posets.mobile import MobilePoset
            sage: M = MobilePoset(DiGraph([[0,1,2,3,4,5,6,7,8], [(1,0),(3,0),(2,1),(2,3),(4,
            ....: 3), (5,4),(5,6),(7,4),(7,8)]]))
            sage: M.linear_extensions().cardinality()
            1098

            sage: M1 = posets.RibbonPoset(6, [1,3])
            sage: M1.linear_extensions().cardinality()
            61

            sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), {1:
            ....: [posets.YoungDiagramPoset([3, 2], dual=True)], 3: [posets.DoubleTailedDiamond(6)]},
            ....: anchor=(4, 2, posets.ChainPoset(6)))
            sage: P.linear_extensions().cardinality()
            361628701868606400
        """
        import sage.combinat.posets.d_complete as dc
        # Find folds
        if self._poset._anchor:
            anchor_index = self._poset._ribbon.index(self._poset._anchor[0])
        else:
            anchor_index = len(self._poset._ribbon)

        folds_up = []
        folds_down = []

        for ind, r in enumerate(self._poset._ribbon[:-1]):
            if ind < anchor_index and self._poset.is_greater_than(
                    r, self._poset._ribbon[ind + 1]):
                folds_up.append((self._poset._ribbon[ind + 1], r))
            elif ind >= anchor_index and self._poset.is_less_than(
                    r, self._poset._ribbon[ind + 1]):
                folds_down.append((r, self._poset._ribbon[ind + 1]))

        if not folds_up and not folds_down:
            return dc.DCompletePoset(
                self._poset).linear_extensions().cardinality()

        # Get ordered connected components
        cr = self._poset.cover_relations()
        foldless_cr = [
            tuple(c) for c in cr
            if tuple(c) not in folds_up and tuple(c) not in folds_down
        ]

        elmts = list(self._poset._elements)
        poset_components = DiGraph([elmts, foldless_cr])
        ordered_poset_components = [
            poset_components.connected_component_containing_vertex(f[1],
                                                                   sort=False)
            for f in folds_up
        ]
        ordered_poset_components.extend(
            poset_components.connected_component_containing_vertex(f[0],
                                                                   sort=False)
            for f in folds_down)
        ordered_poset_components.append(
            poset_components.connected_component_containing_vertex(
                folds_down[-1][1] if folds_down else folds_up[-1][0],
                sort=False))

        # Return determinant

        # Consoludate the folds lists
        folds = folds_up
        folds.extend(folds_down)

        mat = []
        for i in range(len(folds) + 1):
            mat_poset = dc.DCompletePoset(
                self._poset.subposet(ordered_poset_components[i]))
            row = [0] * (i - 1 if i - 1 > 0 else 0) + [1
                                                       ] * (1 if i >= 1 else 0)
            row.append(1 / mat_poset.hook_product())
            for j, f in enumerate(folds[i:]):
                next_poset = self._poset.subposet(
                    ordered_poset_components[j + i + 1])
                mat_poset = dc.DCompletePoset(
                    next_poset.slant_sum(mat_poset, f[0], f[1]))
                row.append(1 / mat_poset.hook_product())

            mat.append(row)
        return matrix(QQ, mat).determinant() * factorial(
            self._poset.cardinality())
    def hodge_star(self, metric):
        r"""
        Compute the Hodge dual of the differential form. 
        
        If ``self`` is a `p`-form `A`, its Hodge dual is the `(n-p)`-form
        `*A` defined by (`n` being the manifold's dimension)
        
        .. MATH::
            
            *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p}
                \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}}
                
        where $\epsilon$ is the volume form associated with some 
        pseudo-Riemannian metric `g` on the manifold, and the indices 
        `k_1,\ldots, k_p` are raised with `g`. 
        
        INPUT:
        
        - ``metric``: the pseudo-Riemannian metric `g` defining the Hodge dual, 
          via the volume form `\epsilon`; must be an instance of :class:`Metric`
        
        OUTPUT:
        
        - the `(n-p)`-form `*A` 
        
        EXAMPLES:
        
        Hodge star of a 1-form in the Euclidean space `R^3`::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: X.<x,y,z> = m.chart('x y z', 'xyz')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: a = OneForm(m, 'A')
            sage: var('Ax Ay Az')
            (Ax, Ay, Az)
            sage: a[:] = (Ax, Ay, Az)
            sage: sa = a.hodge_star(g) ; sa
            2-form '*A' on the 3-dimensional manifold 'M'
            sage: sa.view()
            *A = Az dx/\dy - Ay dx/\dz + Ax dy/\dz
            sage: ssa = sa.hodge_star(g) ; ssa
            1-form '**A' on the 3-dimensional manifold 'M'
            sage: ssa.view()
            **A = Ax dx + Ay dy + Az dz
            sage: ssa == a  # must hold for a Riemannian metric in dimension 3
            True
        
        Hodge star of a 0-form (scalar field) in `R^3`::
        
            sage: f = ScalarField(m, function('F',x,y,z), name='f')
            sage: sf = f.hodge_star(g) ; sf
            3-form '*f' on the 3-dimensional manifold 'M'
            sage: sf.view()
            *f = F(x, y, z) dx/\dy/\dz
            sage: ssf = sf.hodge_star(g) ; ssf
            scalar field '**f' on the 3-dimensional manifold 'M'
            sage: ssf.view()
            **f: (x, y, z) |--> F(x, y, z)
            sage: ssf == f # must hold for a Riemannian metric
            True
            
        Hodge star of a 0-form in Minkowksi spacetime::
        
            sage: m = Manifold(4, 'M')
            sage: X = m.chart('t x y z', 'txyz')
            sage: g = Metric(m, 'g', signature=2)
            sage: g[0,0], g[1,1], g[2,2], g[3,3] = -1, 1, 1, 1
            sage: g.view()  # Minkowski metric
            g = -dt*dt + dx*dx + dy*dy + dz*dz
            sage: var('f0')
            f0
            sage: f = ScalarField(m, f0, name='f')
            sage: sf = f.hodge_star(g) ; sf 
            4-form '*f' on the 4-dimensional manifold 'M'
            sage: sf.view()
            *f = f0 dt/\dx/\dy/\dz
            sage: ssf = sf.hodge_star(g) ; ssf
            scalar field '**f' on the 4-dimensional manifold 'M'
            sage: ssf.view()
            **f: (t, x, y, z) |--> -f0
            sage: ssf == -f  # must hold for a Lorentzian metric             
            True

        Hodge star of a 1-form in Minkowksi spacetime::
        
            sage: a = OneForm(m, 'A')
            sage: var('At Ax Ay Az')
            (At, Ax, Ay, Az)
            sage: a[:] = (At, Ax, Ay, Az)
            sage: a.view()
            A = At dt + Ax dx + Ay dy + Az dz
            sage: sa = a.hodge_star(g) ; sa
            3-form '*A' on the 4-dimensional manifold 'M'
            sage: sa.view()
            *A = -Az dt/\dx/\dy + Ay dt/\dx/\dz - Ax dt/\dy/\dz - At dx/\dy/\dz
            sage: ssa = sa.hodge_star(g) ; ssa
            1-form '**A' on the 4-dimensional manifold 'M'
            sage: ssa.view()
            **A = At dt + Ax dx + Ay dy + Az dz
            sage: ssa == a  # must hold for a Lorentzian metric in dimension 4
            True

        Hodge star of a 2-form in Minkowksi spacetime::
        
            sage: F = DiffForm(m, 2, 'F')    
            sage: var('Ex Ey Ez Bx By Bz')
            (Ex, Ey, Ez, Bx, By, Bz)
            sage: F[0,1], F[0,2], F[0,3] = -Ex, -Ey, -Ez
            sage: F[1,2], F[1,3], F[2,3] = Bz, -By, Bx
            sage: F[:]
            [  0 -Ex -Ey -Ez]
            [ Ex   0  Bz -By]
            [ Ey -Bz   0  Bx]
            [ Ez  By -Bx   0]
            sage: sF = F.hodge_star(g) ; sF
            2-form '*F' on the 4-dimensional manifold 'M'
            sage: sF[:]
            [  0  Bx  By  Bz]
            [-Bx   0  Ez -Ey]
            [-By -Ez   0  Ex]
            [-Bz  Ey -Ex   0]
            sage: ssF = sF.hodge_star(g) ; ssF
            2-form '**F' on the 4-dimensional manifold 'M'
            sage: ssF[:]   
            [  0  Ex  Ey  Ez]
            [-Ex   0 -Bz  By]
            [-Ey  Bz   0 -Bx]
            [-Ez -By  Bx   0]
            sage: ssF.view()
            **F = Ex dt/\dx + Ey dt/\dy + Ez dt/\dz - Bz dx/\dy + By dx/\dz - Bx dy/\dz
            sage: F.view()
            F = -Ex dt/\dx - Ey dt/\dy - Ez dt/\dz + Bz dx/\dy - By dx/\dz + Bx dy/\dz
            sage: ssF == -F  # must hold for a Lorentzian metric in dimension 4
            True

        Test of the standard identity
        
        .. MATH::
            
            *(A\wedge B) = \epsilon(A^\sharp, B^\sharp, ., .)
            
        where `A` and `B` are any 1-forms and `A^\sharp` and `B^\sharp` the 
        vectors associated to them by the metric `g` (index raising)::

            sage: b = OneForm(m, 'B')
            sage: var('Bt Bx By Bz')
            (Bt, Bx, By, Bz)
            sage: b[:] = (Bt, Bx, By, Bz) ; b.view()
            B = Bt dt + Bx dx + By dy + Bz dz
            sage: epsilon = g.volume_form()
            sage: (a.wedge(b)).hodge_star(g) == epsilon.contract(0, a.up(g), 0).contract(0, b.up(g), 0)
            True

        """
        from sage.functions.other import factorial
        from utilities import format_unop_txt, format_unop_latex
        p = self.rank
        eps = metric.volume_form(p)
        if p == 0:
            resu = self * eps
        else:
            resu = self.contract(0, eps, 0)
            for j in range(1, p):
                resu = resu.self_contract(0, p-j)
            if p > 1:
                resu = resu / factorial(p)
        # Name and LaTeX name of the result:
        resu.name = format_unop_txt('*', self.name)
        resu.latex_name = format_unop_latex(r'\star ', self.latex_name)
        return resu