Exemplo n.º 1
0
Arquivo: braid.py Projeto: CETHop/sage
    def _LKB_matrix_(self, braid, variab):
        """
        Compute the Lawrence-Krammer-Bigelow representation matrix.

        The variables of the matrix must be given. This actual
        computation is done in this helper method for caching
        purposes.

        INPUT:

        - ``braid`` -- tuple of integers. The Tietze list of the
          braid.

        - ``variab`` -- string. the names of the variables that will
          appear in the matrix. They must be given as a string,
          separated by a comma

        OUTPUT:

        The LKB matrix of the braid, with respect to the variables.

        TESTS::

            sage: B=BraidGroup(3)
            sage: B._LKB_matrix_((2, 1, 2), 'x, y')
            [             0 -x^4*y + x^3*y         -x^4*y]
            [             0         -x^3*y              0]
            [        -x^2*y  x^3*y - x^2*y              0]
            sage: B._LKB_matrix_((1, 2, 1), 'x, y')
            [             0 -x^4*y + x^3*y         -x^4*y]
            [             0         -x^3*y              0]
            [        -x^2*y  x^3*y - x^2*y              0]
            sage: B._LKB_matrix_((-1, -2, -1, 2, 1, 2), 'x, y')
            [1 0 0]
            [0 1 0]
            [0 0 1]
        """
        n = self.strands()
        if len(braid)>1:
            A = self._LKB_matrix_(braid[:1], variab)
            for i in braid[1:]:
                A = A*self._LKB_matrix_((i,), variab)
            return A
        l = list(Set(range(n)).subsets(2))
        R = LaurentPolynomialRing(IntegerRing(), variab)
        q = R.gens()[0]
        t = R.gens()[1]
        if len(braid)==0:
            return identity_matrix(R, len(l), sparse=True)
        A = matrix(R, len(l), sparse=True)
        if braid[0]>0:
            i = braid[0]-1
            for m in range(len(l)):
                j = min(l[m])
                k = max(l[m])
                if i==j-1:
                    A[l.index(Set([i, k])), m] = q
                    A[l.index(Set([i, j])), m] = q*q-q
                    A[l.index(Set([j, k])), m] = 1-q
                elif i==j and not j==k-1:
                    A[l.index(Set([j, k])), m] = 0
                    A[l.index(Set([j+1, k])), m] = 1
                elif k-1==i and not k-1==j:
                    A[l.index(Set([j, i])), m] = q
                    A[l.index(Set([j, k])), m] = 1-q
                    A[l.index(Set([i, k])), m] = (1-q)*q*t
                elif i==k:
                    A[l.index(Set([j, k])), m] = 0
                    A[l.index(Set([j, k+1])), m] = 1
                elif i==j and j==k-1:
                    A[l.index(Set([j, k])), m] = -t*q*q
                else:
                    A[l.index(Set([j, k])), m] = 1
            return A
        else:
            i = -braid[0]-1
            for m in range(len(l)):
                j = min(l[m])
                k = max(l[m])
                if i==j-1:
                    A[l.index(Set([j-1, k])), m] = 1
                elif i==j and not j==k-1:
                    A[l.index(Set([j+1, k])), m] = q**(-1)
                    A[l.index(Set([j, k])), m] = 1-q**(-1)
                    A[l.index(Set([j, j+1])), m] = t**(-1)*q**(-1)-t**(-1)*q**(-2)
                elif k-1==i and not k-1==j:
                    A[l.index(Set([j, k-1])), m] = 1
                elif i==k:
                    A[l.index(Set([j, k+1])), m] = q**(-1)
                    A[l.index(Set([j, k])), m] = 1-q**(-1)
                    A[l.index(Set([k, k+1])), m] = -q**(-1)+q**(-2)
                elif i==j and j==k-1:
                    A[l.index(Set([j, k])), m] = -t**(-1)*q**(-2)
                else:
                    A[l.index(Set([j, k])), m] = 1
            return A
Exemplo n.º 2
0
def Omega_ge(a, exponents):
    r"""
    Return `\Omega_{\ge}` of the expression specified by the input.

    To be more precise, calculate

    .. MATH::

        \Omega_{\ge} \frac{\mu^a}{
        (1 - z_0 \mu^{e_0}) \dots (1 - z_{n-1} \mu^{e_{n-1}})}

    and return its numerator and a factorization of its denominator.
    Note that `z_0`, ..., `z_{n-1}` only appear in the output, but not in the
    input.

    INPUT:

    - ``a`` -- an integer

    - ``exponents`` -- a tuple of integers

    OUTPUT:

    A pair representing a quotient as follows: Its first component is the
    numerator as a Laurent polynomial, its second component a factorization
    of the denominator as a tuple of Laurent polynomials, where each
    Laurent polynomial `z` represents a factor `1 - z`.

    The parents of these Laurent polynomials is always a
    Laurent polynomial ring in `z_0`, ..., `z_{n-1}` over `\ZZ`, where
    `n` is the length of ``exponents``.

    EXAMPLES::

        sage: from sage.rings.polynomial.omega import Omega_ge
        sage: Omega_ge(0, (1, -2))
        (1, (z0, z0^2*z1))
        sage: Omega_ge(0, (1, -3))
        (1, (z0, z0^3*z1))
        sage: Omega_ge(0, (1, -4))
        (1, (z0, z0^4*z1))

        sage: Omega_ge(0, (2, -1))
        (z0*z1 + 1, (z0, z0*z1^2))
        sage: Omega_ge(0, (3, -1))
        (z0*z1^2 + z0*z1 + 1, (z0, z0*z1^3))
        sage: Omega_ge(0, (4, -1))
        (z0*z1^3 + z0*z1^2 + z0*z1 + 1, (z0, z0*z1^4))

        sage: Omega_ge(0, (1, 1, -2))
        (-z0^2*z1*z2 - z0*z1^2*z2 + z0*z1*z2 + 1, (z0, z1, z0^2*z2, z1^2*z2))
        sage: Omega_ge(0, (2, -1, -1))
        (z0*z1*z2 + z0*z1 + z0*z2 + 1, (z0, z0*z1^2, z0*z2^2))
        sage: Omega_ge(0, (2, 1, -1))
        (-z0*z1*z2^2 - z0*z1*z2 + z0*z2 + 1, (z0, z1, z0*z2^2, z1*z2))

    ::

        sage: Omega_ge(0, (2, -2))
        (-z0*z1 + 1, (z0, z0*z1, z0*z1))
        sage: Omega_ge(0, (2, -3))
        (z0^2*z1 + 1, (z0, z0^3*z1^2))
        sage: Omega_ge(0, (3, 1, -3))
        (-z0^3*z1^3*z2^3 + 2*z0^2*z1^3*z2^2 - z0*z1^3*z2
         + z0^2*z2^2 - 2*z0*z2 + 1,
         (z0, z1, z0*z2, z0*z2, z0*z2, z1^3*z2))

    ::

        sage: Omega_ge(0, (3, 6, -1))
        (-z0*z1*z2^8 - z0*z1*z2^7 - z0*z1*z2^6 - z0*z1*z2^5 - z0*z1*z2^4 +
         z1*z2^5 - z0*z1*z2^3 + z1*z2^4 - z0*z1*z2^2 + z1*z2^3 -
         z0*z1*z2 + z0*z2^2 + z1*z2^2 + z0*z2 + z1*z2 + 1,
         (z0, z1, z0*z2^3, z1*z2^6))

    TESTS::

        sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms()  # long time
        27837

    ::

        sage: Omega_ge(1, (2,))
        (1, (z0,))
    """
    import logging
    logger = logging.getLogger(__name__)
    logger.info('Omega_ge: a=%s, exponents=%s', a, exponents)

    from sage.arith.misc import lcm
    from sage.arith.srange import srange
    from sage.misc.misc_c import prod
    from sage.rings.integer_ring import ZZ
    from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
    from sage.rings.number_field.number_field import CyclotomicField

    if not exponents or any(e == 0 for e in exponents):
        raise NotImplementedError

    rou = sorted(set(abs(e) for e in exponents) - set([1]))
    ellcm = lcm(rou)
    B = CyclotomicField(ellcm, 'zeta')
    zeta = B.gen()
    z_names = tuple('z{}'.format(i) for i in range(len(exponents)))
    L = LaurentPolynomialRing(B, ('t', ) + z_names, len(z_names) + 1)
    t = L.gens()[0]
    Z = LaurentPolynomialRing(ZZ, z_names, len(z_names))
    powers = {i: L(zeta**(ellcm // i)) for i in rou}
    powers[2] = L(-1)
    powers[1] = L(1)
    exponents_and_values = tuple(
        (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e))))
        for z, e in zip(L.gens()[1:], exponents))
    x = tuple(v for e, v in exponents_and_values if e > 0)
    y = tuple(v for e, v in exponents_and_values if e < 0)

    def subs_power(expression, var, exponent):
        r"""
        Substitute ``var^exponent`` by ``var`` in ``expression``.

        It is assumed that ``var`` only occurs with exponents
        divisible by ``exponent``.
        """
        p = tuple(var.dict().popitem()[0]).index(
            1)  # var is the p-th generator

        def subs_e(e):
            e = list(e)
            assert e[p] % exponent == 0
            e[p] = e[p] // exponent
            return tuple(e)

        parent = expression.parent()
        result = parent(
            {subs_e(e): c
             for e, c in iteritems(expression.dict())})
        return result

    def de_power(expression):
        expression = Z(expression)
        for e, var in zip(exponents, Z.gens()):
            if abs(e) == 1:
                continue
            expression = subs_power(expression, var, abs(e))
        return expression

    logger.debug('Omega_ge: preparing denominator')
    factors_denominator = tuple(
        de_power(1 - factor) for factor in _Omega_factors_denominator_(x, y))

    logger.debug('Omega_ge: preparing numerator')
    numerator = de_power(_Omega_numerator_(a, x, y, t))

    logger.info('Omega_ge: completed')
    return numerator, factors_denominator
Exemplo n.º 3
0
def Omega_ge(a, exponents):
    r"""
    Return `\Omega_{\ge}` of the expression specified by the input.

    To be more precise, calculate

    .. MATH::

        \Omega_{\ge} \frac{\mu^a}{
        (1 - z_0 \mu^{e_0}) \dots (1 - z_{n-1} \mu^{e_{n-1}})}

    and return its numerator and a factorization of its denominator.
    Note that `z_0`, ..., `z_{n-1}` only appear in the output, but not in the
    input.

    INPUT:

    - ``a`` -- an integer

    - ``exponents`` -- a tuple of integers

    OUTPUT:

    A pair representing a quotient as follows: Its first component is the
    numerator as a Laurent polynomial, its second component a factorization
    of the denominator as a tuple of Laurent polynomials, where each
    Laurent polynomial `z` represents a factor `1 - z`.

    The parents of these Laurent polynomials is always a
    Laurent polynomial ring in `z_0`, ..., `z_{n-1}` over `\ZZ`, where
    `n` is the length of ``exponents``.

    EXAMPLES::

        sage: from sage.rings.polynomial.omega import Omega_ge
        sage: Omega_ge(0, (1, -2))
        (1, (z0, z0^2*z1))
        sage: Omega_ge(0, (1, -3))
        (1, (z0, z0^3*z1))
        sage: Omega_ge(0, (1, -4))
        (1, (z0, z0^4*z1))

        sage: Omega_ge(0, (2, -1))
        (z0*z1 + 1, (z0, z0*z1^2))
        sage: Omega_ge(0, (3, -1))
        (z0*z1^2 + z0*z1 + 1, (z0, z0*z1^3))
        sage: Omega_ge(0, (4, -1))
        (z0*z1^3 + z0*z1^2 + z0*z1 + 1, (z0, z0*z1^4))

        sage: Omega_ge(0, (1, 1, -2))
        (-z0^2*z1*z2 - z0*z1^2*z2 + z0*z1*z2 + 1, (z0, z1, z0^2*z2, z1^2*z2))
        sage: Omega_ge(0, (2, -1, -1))
        (z0*z1*z2 + z0*z1 + z0*z2 + 1, (z0, z0*z1^2, z0*z2^2))
        sage: Omega_ge(0, (2, 1, -1))
        (-z0*z1*z2^2 - z0*z1*z2 + z0*z2 + 1, (z0, z1, z0*z2^2, z1*z2))

    ::

        sage: Omega_ge(0, (2, -2))
        (-z0*z1 + 1, (z0, z0*z1, z0*z1))
        sage: Omega_ge(0, (2, -3))
        (z0^2*z1 + 1, (z0, z0^3*z1^2))
        sage: Omega_ge(0, (3, 1, -3))
        (-z0^3*z1^3*z2^3 + 2*z0^2*z1^3*z2^2 - z0*z1^3*z2
         + z0^2*z2^2 - 2*z0*z2 + 1,
         (z0, z1, z0*z2, z0*z2, z0*z2, z1^3*z2))

    ::

        sage: Omega_ge(0, (3, 6, -1))
        (-z0*z1*z2^8 - z0*z1*z2^7 - z0*z1*z2^6 - z0*z1*z2^5 - z0*z1*z2^4 +
         z1*z2^5 - z0*z1*z2^3 + z1*z2^4 - z0*z1*z2^2 + z1*z2^3 -
         z0*z1*z2 + z0*z2^2 + z1*z2^2 + z0*z2 + z1*z2 + 1,
         (z0, z1, z0*z2^3, z1*z2^6))

    TESTS::

        sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms()  # long time
        27837

    ::

        sage: Omega_ge(1, (2,))
        (1, (z0,))
    """
    import logging
    logger = logging.getLogger(__name__)
    logger.info('Omega_ge: a=%s, exponents=%s', a, exponents)

    from sage.arith.all import lcm, srange
    from sage.rings.integer_ring import ZZ
    from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
    from sage.rings.number_field.number_field import CyclotomicField

    if not exponents or any(e == 0 for e in exponents):
        raise NotImplementedError

    rou = sorted(set(abs(e) for e in exponents) - set([1]))
    ellcm = lcm(rou)
    B = CyclotomicField(ellcm, 'zeta')
    zeta = B.gen()
    z_names = tuple('z{}'.format(i) for i in range(len(exponents)))
    L = LaurentPolynomialRing(B, ('t',) + z_names, len(z_names) + 1)
    t = L.gens()[0]
    Z = LaurentPolynomialRing(ZZ, z_names, len(z_names))
    powers = {i: L(zeta**(ellcm//i)) for i in rou}
    powers[2] = L(-1)
    powers[1] = L(1)
    exponents_and_values = tuple(
        (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e))))
        for z, e in zip(L.gens()[1:], exponents))
    x = tuple(v for e, v in exponents_and_values if e > 0)
    y = tuple(v for e, v in exponents_and_values if e < 0)

    def subs_power(expression, var, exponent):
        r"""
        Substitute ``var^exponent`` by ``var`` in ``expression``.

        It is assumed that ``var`` only occurs with exponents
        divisible by ``exponent``.
        """
        p = tuple(var.dict().popitem()[0]).index(1)  # var is the p-th generator
        def subs_e(e):
            e = list(e)
            assert e[p] % exponent == 0
            e[p] = e[p] // exponent
            return tuple(e)
        parent = expression.parent()
        result = parent({subs_e(e): c for e, c in iteritems(expression.dict())})
        return result

    def de_power(expression):
        expression = Z(expression)
        for e, var in zip(exponents, Z.gens()):
            if abs(e) == 1:
                continue
            expression = subs_power(expression, var, abs(e))
        return expression

    logger.debug('Omega_ge: preparing denominator')
    factors_denominator = tuple(de_power(1 - factor)
                                for factor in _Omega_factors_denominator_(x, y))

    logger.debug('Omega_ge: preparing numerator')
    numerator = de_power(_Omega_numerator_(a, x, y, t))

    logger.info('Omega_ge: completed')
    return numerator, factors_denominator
Exemplo n.º 4
0
    def _LKB_matrix_(self, braid, variab):
        """
        Compute the Lawrence-Krammer-Bigelow representation matrix.

        The variables of the matrix must be given. This actual
        computation is done in this helper method for caching
        purposes.

        INPUT:

        - ``braid`` -- tuple of integers. The Tietze list of the
          braid.

        - ``variab`` -- string. the names of the variables that will
          appear in the matrix. They must be given as a string,
          separated by a comma

        OUTPUT:

        The LKB matrix of the braid, with respect to the variables.

        TESTS::

            sage: B=BraidGroup(3)
            sage: B._LKB_matrix_((2, 1, 2), 'x, y')
            [             0 -x^4*y + x^3*y         -x^4*y]
            [             0         -x^3*y              0]
            [        -x^2*y  x^3*y - x^2*y              0]
            sage: B._LKB_matrix_((1, 2, 1), 'x, y')
            [             0 -x^4*y + x^3*y         -x^4*y]
            [             0         -x^3*y              0]
            [        -x^2*y  x^3*y - x^2*y              0]
            sage: B._LKB_matrix_((-1, -2, -1, 2, 1, 2), 'x, y')
            [1 0 0]
            [0 1 0]
            [0 0 1]
        """
        n = self.strands()
        if len(braid) > 1:
            A = self._LKB_matrix_(braid[:1], variab)
            for i in braid[1:]:
                A = A * self._LKB_matrix_((i, ), variab)
            return A
        l = list(Set(range(n)).subsets(2))
        R = LaurentPolynomialRing(IntegerRing(), variab)
        q = R.gens()[0]
        t = R.gens()[1]
        if len(braid) == 0:
            return identity_matrix(R, len(l), sparse=True)
        A = matrix(R, len(l), sparse=True)
        if braid[0] > 0:
            i = braid[0] - 1
            for m in range(len(l)):
                j = min(l[m])
                k = max(l[m])
                if i == j - 1:
                    A[l.index(Set([i, k])), m] = q
                    A[l.index(Set([i, j])), m] = q * q - q
                    A[l.index(Set([j, k])), m] = 1 - q
                elif i == j and not j == k - 1:
                    A[l.index(Set([j, k])), m] = 0
                    A[l.index(Set([j + 1, k])), m] = 1
                elif k - 1 == i and not k - 1 == j:
                    A[l.index(Set([j, i])), m] = q
                    A[l.index(Set([j, k])), m] = 1 - q
                    A[l.index(Set([i, k])), m] = (1 - q) * q * t
                elif i == k:
                    A[l.index(Set([j, k])), m] = 0
                    A[l.index(Set([j, k + 1])), m] = 1
                elif i == j and j == k - 1:
                    A[l.index(Set([j, k])), m] = -t * q * q
                else:
                    A[l.index(Set([j, k])), m] = 1
            return A
        else:
            i = -braid[0] - 1
            for m in range(len(l)):
                j = min(l[m])
                k = max(l[m])
                if i == j - 1:
                    A[l.index(Set([j - 1, k])), m] = 1
                elif i == j and not j == k - 1:
                    A[l.index(Set([j + 1, k])), m] = q**(-1)
                    A[l.index(Set([j, k])), m] = 1 - q**(-1)
                    A[l.index(Set([j, j + 1])),
                      m] = t**(-1) * q**(-1) - t**(-1) * q**(-2)
                elif k - 1 == i and not k - 1 == j:
                    A[l.index(Set([j, k - 1])), m] = 1
                elif i == k:
                    A[l.index(Set([j, k + 1])), m] = q**(-1)
                    A[l.index(Set([j, k])), m] = 1 - q**(-1)
                    A[l.index(Set([k, k + 1])), m] = -q**(-1) + q**(-2)
                elif i == j and j == k - 1:
                    A[l.index(Set([j, k])), m] = -t**(-1) * q**(-2)
                else:
                    A[l.index(Set([j, k])), m] = 1
            return A
Exemplo n.º 5
0
    def alexander_polynomial(self,
                             multivar=True,
                             v='no',
                             method='default',
                             norm=True,
                             factored=False):
        """
        Calculates the Alexander polynomial of the link. For links with one component,
        can evaluate the alexander polynomial at v::

            sage: K = Link('4_1')
            sage: K.alexander_polynomial()
            t^2 - 3*t + 1
            sage: K.alexander_polynomial(v=[4])
            5
            
            sage: K = Link('L7n1')
            sage: K.alexander_polynomial(norm=False)
            t1^-1*t2^-1 + t1^-2*t2^-4

        The default algorithm for *knots* is Bar-Natan's super-fast
        tangle-based algorithm.  For links, we apply Fox calculus to a
        Wirtinger presentation for the link::

            sage: L = Link('K13n123')
            sage: L.alexander_polynomial() == L.alexander_polynomial(method='wirtinger')
            True
        """

        # sign normalization still missing, but when "norm=True" the
        # leading coefficient with respect to the first variable is made
        # positive.
        if method == 'snappy':
            try:
                return self.exterior().alexander_polynomial()
            except ImportError:
                raise RuntimeError('this method for alexander_polynomial ' +
                                   no_snappy_msg)
        else:
            comp = len(self.link_components)
            if comp < 2:
                multivar = False

            # If single variable, use the super-fast method of Bar-Natan.
            if comp == 1 and method == 'default' and norm:
                p = alexander.alexander(self)
            else:  # Use a simple method based on the Wirtinger presentation.
                if method not in ['default', 'wirtinger']:
                    raise ValueError(
                        "Available methods are 'default' and 'wirtinger'")

                if (multivar):
                    L = LaurentPolynomialRing(
                        QQ, ['t%d' % (i + 1) for i in range(comp)])
                    t = list(L.gens())
                else:
                    L = LaurentPolynomialRing(QQ, 't')
                    t = [L.gen()]

                M = self.alexander_matrix(mv=multivar)
                C = M[0]
                m = C.nrows()
                n = C.ncols()
                if n > m:
                    k = m - 1
                else:
                    k = n - 1

                subMatrix = C[0:k, 0:k]
                p = subMatrix.determinant()
                if p == 0: return 0
                if multivar:
                    t_i = M[1][-1]
                    p = (p.factor()) / (t_i - 1)
                    p = p.expand()

                if (norm):
                    p = normalize_alex_poly(p, t)

            if v != 'no':
                return p(*v)

            if multivar and factored:  # it's easier to view this way
                return p.factor()
            else:
                return p