Ejemplo n.º 1
0
    def __classcall_private__(cls, cartan_type, la, mu):
        """
        Normalize input to ensure a unique representation.

        TESTS::

            sage: K1 = crystals.KacModule(['A', [2,1]], [2,1], [1])
            sage: K2 = crystals.KacModule(CartanType(['A', [2,1]]), (2,1), (1,))
            sage: K1 is K2
            True
        """
        cartan_type = CartanType(cartan_type)
        la = _Partitions(la)
        mu = _Partitions(mu)
        return super(CrystalOfKacModule, cls).__classcall__(cls, cartan_type, la, mu)
Ejemplo n.º 2
0
    def __classcall_private__(cls, cartan_type, la, mu):
        """
        Normalize input to ensure a unique representation.

        TESTS::

            sage: K1 = crystals.KacModule(['A', [2,1]], [2,1], [1])
            sage: K2 = crystals.KacModule(CartanType(['A', [2,1]]), (2,1), (1,))
            sage: K1 is K2
            True
        """
        cartan_type = CartanType(cartan_type)
        la = _Partitions(la)
        mu = _Partitions(mu)
        return super(CrystalOfKacModule, cls).__classcall__(cls, cartan_type, la, mu)
Ejemplo n.º 3
0
    def some_elements(self):
        r"""
        Return some elements of ``self``.

        EXAMPLES::

            sage: L = lie_algebras.SymplecticDerivation(QQ, 5)
            sage: L.some_elements()
            [a1*a2, b1*b3, a1*a1*a2, b3*b4, a1*a4*b3,
             a1*a2 - 1/2*a1*a2*a2*a5 + a1*a1*a2*b1*b4]
        """
        d = self.monomial
        g = self._g
        return [d( _Partitions([2,1]) ), d( _Partitions([g+3,g+1]) ), d( _Partitions([2,1,1])),
                d( _Partitions([2*g-1,2*g-2]) ), d( _Partitions([2*g-2,g-1,1]) ),
                self.an_element()]
Ejemplo n.º 4
0
    def _an_element_(self):
        r"""
        Return an element of ``self``.

        EXAMPLES::

            sage: L = lie_algebras.SymplecticDerivation(QQ, 5)
            sage: L.an_element()
            a1*a2 - 1/2*a1*a2*a2*a5 + a1*a1*a2*b1*b4
        """
        d = self.monomial
        return (
                 d( _Partitions([2,1]) )
                 - self.base_ring().an_element() * d( _Partitions([5,2,2,1]) )
                 + d( _Partitions([2*self._g-1, self._g+1, 2, 1, 1]) )
                )
Ejemplo n.º 5
0
def spin_polynomial_square(part, weight, length):
    r"""
    Returns the spin polynomial associated with ``part``, ``weight``, and
    ``length``, with the substitution `t \to t^2` made.

    EXAMPLES::

        sage: from sage.combinat.ribbon_tableau import spin_polynomial_square
        sage: spin_polynomial_square([6,6,6],[4,2],3)
        t^12 + t^10 + 2*t^8 + t^6 + t^4
        sage: spin_polynomial_square([6,6,6],[4,1,1],3)
        t^12 + 2*t^10 + 3*t^8 + 2*t^6 + t^4
        sage: spin_polynomial_square([3,3,3,2,1], [2,2], 3)
        t^7 + t^5
        sage: spin_polynomial_square([3,3,3,2,1], [2,1,1], 3)
        2*t^7 + 2*t^5 + t^3
        sage: spin_polynomial_square([3,3,3,2,1], [1,1,1,1], 3)
        3*t^7 + 5*t^5 + 3*t^3 + t
        sage: spin_polynomial_square([5,4,3,2,1,1,1], [2,2,1], 3)
        2*t^9 + 6*t^7 + 2*t^5
        sage: spin_polynomial_square([[6]*6, [3,3]], [4,4,2], 3)
        3*t^18 + 5*t^16 + 9*t^14 + 6*t^12 + 3*t^10
    """
    R = ZZ['t']

    if part in _Partitions:
        part = SkewPartition([part,_Partitions([])])
    elif part in SkewPartitions():
        part = SkewPartition(part)

    if part == [[],[]] and weight == []:
        return R.one()

    t = R.gen()
    return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec,t))[0])
Ejemplo n.º 6
0
def spin_polynomial_square(part, weight, length):
    r"""
    Returns the spin polynomial associated with ``part``, ``weight``, and
    ``length``, with the substitution `t \to t^2` made.

    EXAMPLES::

        sage: from sage.combinat.ribbon_tableau import spin_polynomial_square
        sage: spin_polynomial_square([6,6,6],[4,2],3)
        t^12 + t^10 + 2*t^8 + t^6 + t^4
        sage: spin_polynomial_square([6,6,6],[4,1,1],3)
        t^12 + 2*t^10 + 3*t^8 + 2*t^6 + t^4
        sage: spin_polynomial_square([3,3,3,2,1], [2,2], 3)
        t^7 + t^5
        sage: spin_polynomial_square([3,3,3,2,1], [2,1,1], 3)
        2*t^7 + 2*t^5 + t^3
        sage: spin_polynomial_square([3,3,3,2,1], [1,1,1,1], 3)
        3*t^7 + 5*t^5 + 3*t^3 + t
        sage: spin_polynomial_square([5,4,3,2,1,1,1], [2,2,1], 3)
        2*t^9 + 6*t^7 + 2*t^5
        sage: spin_polynomial_square([[6]*6, [3,3]], [4,4,2], 3)
        3*t^18 + 5*t^16 + 9*t^14 + 6*t^12 + 3*t^10
    """
    R = ZZ['t']
    t = R.gen()

    if part in _Partitions:
        part = SkewPartition([part,_Partitions([])])
    elif part in SkewPartitions():
        part = SkewPartition(part)

    if part == [[],[]] and weight == []:
        return t.parent()(1)

    return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec,t))[0])
Ejemplo n.º 7
0
    def bottom_schur_function(self, partition, degree=None):
        r"""
        Return the least-degree component of ``s[partition]``,
        where ``s`` denotes the Schur basis of the symmetric
        functions, and the grading is not the usual grading on the
        symmetric functions but rather the grading which gives
        every `p_i` degree `1`.

        This least-degree component has its degree equal to the
        Frobenius rank of ``partition``, while the degree with respect
        to the usual grading is still the size of ``partition``.

        This method requires the base ring to be a (commutative)
        `\QQ`-algebra. This restriction is unavoidable, since
        the least-degree component (in general) has noninteger
        coefficients in all classical bases of the symmetric
        functions.

        The optional keyword ``degree`` allows taking any
        homogeneous component rather than merely the least-degree
        one. Specifically, if ``degree`` is set, then the
        ``degree``-th component will be returned.

        REFERENCES:

        .. [ClSt03] Peter Clifford, Richard P. Stanley,
           *Bottom Schur functions*.
           :arxiv:`math/0311382v2`.

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ)
            sage: p = Sym.p()
            sage: p.bottom_schur_function([2,2,1])
            -1/6*p[3, 2] + 1/4*p[4, 1]
            sage: p.bottom_schur_function([2,1])
            -1/3*p[3]
            sage: p.bottom_schur_function([3])
            1/3*p[3]
            sage: p.bottom_schur_function([1,1,1])
            1/3*p[3]
            sage: p.bottom_schur_function(Partition([1,1,1]))
            1/3*p[3]
            sage: p.bottom_schur_function([2,1], degree=1)
            -1/3*p[3]
            sage: p.bottom_schur_function([2,1], degree=2)
            0
            sage: p.bottom_schur_function([2,1], degree=3)
            1/3*p[1, 1, 1]
            sage: p.bottom_schur_function([2,2,1], degree=3)
            1/8*p[2, 2, 1] - 1/6*p[3, 1, 1]
        """
        from sage.combinat.partition import _Partitions

        s = self.realization_of().schur()
        partition = _Partitions(partition)
        if degree is None:
            degree = partition.frobenius_rank()
        s_partition = self(s[partition])
        return self.sum_of_terms([(p, coeff) for p, coeff in s_partition if len(p) == degree], distinct=True)
Ejemplo n.º 8
0
    def bracket_on_basis(self, x, y):
        r"""
        Return the bracket of basis elements indexed by ``x`` and ``y``,
        where ``i < j``.

        EXAMPLES::

            sage: L = lie_algebras.SymplecticDerivation(QQ, 5)
            sage: L.bracket_on_basis([5,2,1], [5,1,1])
            0
            sage: L.bracket_on_basis([6,1], [3,1,1])
            -2*a1*a1*a3
            sage: L.bracket_on_basis([9,2,1], [4,1,1])
            -a1*a1*a1*a2
            sage: L.bracket_on_basis([5,5,2], [6,1,1])
            0
            sage: L.bracket_on_basis([5,5,5], [10,3])
            3*a3*a5*a5
            sage: L.bracket_on_basis([10,10,10], [5,3])
            -3*a3*b5*b5
        """
        g = self._g
        ret = {}
        one = self.base_ring().one()
        for i,xi in enumerate(x):
            for j,yj in enumerate(y):
                # The symplectic form will be 0
                if (xi <= g and yj <= g) or (xi > g and yj > g):
                    continue
                if xi <= g and yj > g:
                    if xi != yj - g:
                        continue
                    m = _Partitions(sorted(x[:i] + x[i+1:] + y[:j] + y[j+1:], reverse=True))
                    if m in ret:
                        ret[m] += one
                    else:
                        ret[m] = one
                else: # if ci > g and yj <= g:
                    if xi - g != yj:
                        continue
                    m = _Partitions(sorted(x[:i] + x[i+1:] + y[:j] + y[j+1:], reverse=True))
                    if m in ret:
                        ret[m] -= one
                    else:
                        ret[m] = -one
        return self._from_dict(ret, remove_zeros=True)
Ejemplo n.º 9
0
def compat(n, mu, nu):
    r"""
    Generate all possible partitions of `n` that can precede `\mu, \nu`
    in a rigging sequence.

    INPUT:

    - ``n`` -- a positive integer
    - ``mu``, ``nu`` -- partitions

    OUTPUT:

    - a list of partitions

    EXAMPLES::

        sage: from sage.combinat.sf.kfpoly import *
        sage: compat(4, [1], [2,1])
        [[1, 1, 1, 1], [2, 1, 1], [2, 2], [3, 1], [4]]
        sage: compat(3, [1], [2,1])
        [[1, 1, 1], [2, 1], [3]]
        sage: compat(2, [1], [])
        [[2]]
        sage: compat(3, [1], [])
        [[2, 1], [3]]
        sage: compat(3, [2], [1])
        [[3]]
        sage: compat(4, [1,1], [])
        [[2, 2], [3, 1], [4]]
        sage: compat(4, [2], [])
        [[4]]
    """
    l = max(len(mu), len(nu))
    mmu = list(mu) + [0] * (l - len(mu))
    nnu = list(nu) + [0] * (l - len(nu))

    bd = []
    sa = 0
    for i in range(l):
        sa += 2 * mmu[i] - nnu[i]
        bd.append(sa)

    for la in ZS1_iterator(n):
        if dom(la, bd):
            return [
                x.conjugate() for x in _Partitions(la).dominated_partitions()
            ]

    return []  # _Partitions([])
Ejemplo n.º 10
0
def compat(n, mu, nu):
    r"""
    Generate all possible partitions of `n` that can precede `\mu, \nu`
    in a rigging sequence.

    INPUT:

    - ``n`` -- a positive integer
    - ``mu``, ``nu`` -- partitions

    OUTPUT:

    - a list of partitions

    EXAMPLES::

        sage: from sage.combinat.sf.kfpoly import *
        sage: compat(4, [1], [2,1])
        [[1, 1, 1, 1], [2, 1, 1], [2, 2], [3, 1], [4]]
        sage: compat(3, [1], [2,1])
        [[1, 1, 1], [2, 1], [3]]
        sage: compat(2, [1], [])
        [[2]]
        sage: compat(3, [1], [])
        [[2, 1], [3]]
        sage: compat(3, [2], [1])
        [[3]]
        sage: compat(4, [1,1], [])
        [[2, 2], [3, 1], [4]]
        sage: compat(4, [2], [])
        [[4]]
    """
    l = max(len(mu), len(nu))
    mmu = list(mu) + [0]*(l-len(mu))
    nnu = list(nu) + [0]*(l-len(nu))

    bd = []
    sa = 0
    for i in range(l):
        sa += 2*mmu[i] - nnu[i]
        bd.append(sa)

    for la in ZS1_iterator(n):
        if dom(la, bd):
            return [x.conjugate() for x in _Partitions(la).dominated_partitions()]

    return [] # _Partitions([])
Ejemplo n.º 11
0
def kfpoly(mu, nu, t=None):
    r"""
    Return the Kostka-Foulkes polynomial `K_{\mu, \nu}(t)`
    by generating all rigging sequences for the shape `\mu`, and then
    selecting those of content `\nu`.

    INPUT:

    - ``mu``, ``nu`` -- partitions
    - ``t`` -- an optional parameter (default: ``None``)

    OUTPUT:

    - the Koskta-Foulkes polynomial indexed by partitions ``mu`` and ``nu`` and
      evaluated at the parameter ``t``.  If ``t`` is ``None`` the resulting polynomial
      is in the polynomial ring `\ZZ['t']`.

    EXAMPLES::

        sage: from sage.combinat.sf.kfpoly import kfpoly
        sage: kfpoly([2,2], [2,1,1])
        t
        sage: kfpoly([4], [2,1,1])
        t^3
        sage: kfpoly([4], [2,2])
        t^2
        sage: kfpoly([1,1,1,1], [2,2])
        0

    TESTS::

        sage: kfpoly([], [])
        1
    """
    if mu == nu:
        return 1

    if t is None:
        t = polygen(ZZ, 't')

    nuc = _Partitions(nu).conjugate()

    f = lambda x: weight(x, t) if x[0] == nuc else 0

    return sum(f(rg) for rg in riggings(mu))
Ejemplo n.º 12
0
    def __classcall_private__(cls, ct, shape):
        """
        Normalize input to ensure a unique representation.

        TESTS::

            sage: crystals.Tableaux(['A', [1, 2]], shape=[2,1])
            Crystal of BKK tableaux of shape [2, 1] of gl(2|3)
            sage: crystals.Tableaux(['A', [1, 1]], shape=[3,3,3])
            Traceback (most recent call last):
            ...
            ValueError: invalid hook shape
        """
        ct = CartanType(ct)
        shape = _Partitions(shape)
        if len(shape) > ct.m + 1 and shape[ct.m+1] > ct.n + 1:
            raise ValueError("invalid hook shape")
        return super(CrystalOfBKKTableaux, cls).__classcall__(cls, ct, shape)
Ejemplo n.º 13
0
    def __classcall_private__(cls, ct, shape):
        """
        Normalize input to ensure a unique representation.

        TESTS::

            sage: crystals.Tableaux(['A', [1, 2]], shape=[2,1])
            Crystal of BKK tableaux of shape [2, 1] of gl(2|3)
            sage: crystals.Tableaux(['A', [1, 1]], shape=[3,3,3])
            Traceback (most recent call last):
            ...
            ValueError: invalid hook shape
        """
        ct = CartanType(ct)
        shape = _Partitions(shape)
        if len(shape) > ct.m + 1 and shape[ct.m + 1] > ct.n + 1:
            raise ValueError("invalid hook shape")
        return super(CrystalOfBKKTableaux, cls).__classcall__(cls, ct, shape)
Ejemplo n.º 14
0
def kfpoly(mu, nu, t=None):
    r"""
    Returns the Kostka-Foulkes polynomial `K_{\mu, \nu}(t)`
    by generating all rigging sequences for the shape `\mu`, and then
    selecting those of content `\nu`.

    INPUT:

    - ``mu``, ``nu`` -- partitions
    - ``t`` -- an optional parameter (default: ``None``)

    OUTPUT:

    - the Koskta-Foulkes polynomial indexed by partitions ``mu`` and ``nu`` and
      evaluated at the parameter ``t``.  If ``t`` is ``None`` the resulting polynomial
      is in the polynomial ring `\mathbb{Z}['t']`.

    EXAMPLES::

        sage: from sage.combinat.sf.kfpoly import kfpoly
        sage: kfpoly([2,2], [2,1,1])
        t
        sage: kfpoly([4], [2,1,1])
        t^3
        sage: kfpoly([4], [2,2])
        t^2
        sage: kfpoly([1,1,1,1], [2,2])
        0
    """
    if mu == nu:
        return 1
    elif mu == []:
        return 0

    if t is None:
        t = polygen(ZZ, 't')

    nuc = _Partitions(nu).conjugate()

    f = lambda x: weight(x, t) if x[0] == nuc else 0

    res = sum(f(rg) for rg in riggings(mu))
    return res
Ejemplo n.º 15
0
    def __classcall_private__(cls, n=None):
        r"""
        This class returns the appropriate parent based on arguments.
        See the documentation for :class:`StandardTableaux` for more
        information.

        TESTS::

            sage: SST = StandardSuperTableaux(); SST
            Standard super tableaux
            sage: StandardSuperTableaux(3)
            Standard super tableaux of size 3
            sage: StandardSuperTableaux([2,2])
            Standard super tableaux of shape [2, 2]
            sage: StandardSuperTableaux(-1)
            Traceback (most recent call last):
            ...
            ValueError: the argument must be a non-negative integer or a
            partition
            sage: StandardSuperTableaux([[1]])
            Traceback (most recent call last):
            ...
            ValueError: the argument must be a non-negative integer or a
            partition
        """
        from sage.combinat.partition import _Partitions
        from sage.combinat.skew_partition import SkewPartitions

        if n is None:
            return StandardSuperTableaux_all()

        elif n in _Partitions:
            return StandardSuperTableaux_shape(_Partitions(n))

        elif n in SkewPartitions():
            raise NotImplementedError("standard super tableau for skew "
                                      "partitions is not implemented yet")

        if not isinstance(n, (int, Integer)) or n < 0:
            raise ValueError("the argument must be a non-negative integer"
                             " or a partition")

        return StandardSuperTableaux_size(n)
Ejemplo n.º 16
0
    def __classcall_private__(cls, shape, weight, length):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: R = RibbonTableaux([[2,1],[]],[1,1,1],1)
            sage: R2 = RibbonTableaux(SkewPartition([[2,1],[]]),(1,1,1),1)
            sage: R is R2
            True
        """
        if shape in _Partitions:
            shape = _Partitions(shape)
            shape = SkewPartition([shape, shape.core(length)])
        else:
            shape = SkewPartition(shape)

        if shape.size() != length*sum(weight):
            raise ValueError("Incompatible shape and weight")

        return super(RibbonTableaux, cls).__classcall__(cls, shape, tuple(weight), length)
Ejemplo n.º 17
0
    def __classcall_private__(cls, shape, weight, length):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: R = RibbonTableaux([[2,1],[]],[1,1,1],1)
            sage: R2 = RibbonTableaux(SkewPartition([[2,1],[]]),(1,1,1),1)
            sage: R is R2
            True
        """
        if shape in _Partitions:
            shape = _Partitions(shape)
            shape = SkewPartition([shape, shape.core(length)])
        else:
            shape = SkewPartition(shape)

        if shape.size() != length*sum(weight):
            raise ValueError("Incompatible shape and weight")

        return super(RibbonTableaux, cls).__classcall__(cls, shape, tuple(weight), length)
Ejemplo n.º 18
0
    def module_generator(self, shape):
        """
        This yields the module generator (or highest weight element) of a classical
        crystal of given shape. The module generator is the unique tableau with equal
        shape and content.

        EXAMPLES::

            sage: T = crystals.Tableaux(['D',3], shape = [1,1])
            sage: T.module_generator([1,1])
            [[1], [2]]

            sage: T = crystals.Tableaux(['D',4],shape=[2,2,2,-2])
            sage: T.module_generator(tuple([2,2,2,-2]))
            [[1, 1], [2, 2], [3, 3], [-4, -4]]
            sage: T.cardinality()
            294
            sage: T = crystals.Tableaux(['D',4],shape=[2,2,2,2])
            sage: T.module_generator(tuple([2,2,2,2]))
            [[1, 1], [2, 2], [3, 3], [4, 4]]
            sage: T.cardinality()
            294
        """
        type = self.cartan_type()
        if type[0] == 'D' and len(shape) == type[1] and shape[type[1] - 1] < 0:
            invert = True
            shape = shape[:-1] + (-shape[type[1] - 1], )
        else:
            invert = False
        p = _Partitions(shape).conjugate()
        # The column canonical tableau, read by columns
        module_generator = flatten([[val - i for i in range(val)]
                                    for val in p])
        if invert:
            module_generator = [(-x if x == type[1] else x)
                                for x in module_generator]
        return self(list=[self.letters(x) for x in module_generator])
    def _supp_to_s(self, gamma):
        r"""
        This is a helper function that is not meant to be called directly.

        Given the support of an element `x_1^{\gamma_1} x_2^{\gamma_2} \cdots
        x_\ell^{\gamma_\ell}` in the ``ShiftingOperatorAlgebra``, return
        the appropriate `s_\gamma` in the Schur basis using
        "Schur function straightening" in [BMPS2018]_ Proposition 4.1.

        EXAMPLES::

            sage: S = ShiftingOperatorAlgebra(QQ)
            sage: s = SymmetricFunctions(QQ).s()
            sage: S._supp_to_s(S([3,2,1]).support_of_term())
            s[3, 2, 1]
            sage: S._supp_to_s(S([2,3,1]).support_of_term())
            0
            sage: S._supp_to_s(S([2,4,-1,1]).support_of_term())
            s[3, 3]
            sage: S._supp_to_s(S([3,2,0]).support_of_term())
            s[3, 2]
        """
        def number_of_noninversions(lis):
            return sum(1 for i, val in enumerate(lis)
                       for j in range(i + 1, len(lis))
                       if val < lis[j])  # i < j is already enforced

        rho = list(range(len(gamma) - 1, -1, -1))
        combined = [g + r for g, r in zip(gamma, rho)]
        if len(set(combined)) == len(combined) and all(e >= 0
                                                       for e in combined):
            sign = (-1)**number_of_noninversions(combined)
            sort_combined = sorted(combined, reverse=True)
            new_gamma = [sc - r for sc, r in zip(sort_combined, rho)]
            return sign * self._sym_s(_Partitions(new_gamma))
        else:
            return self._sym_s.zero()
Ejemplo n.º 20
0
    def _element_constructor_(self, x):
        """
        Convert ``x`` into ``self``, if coercion failed.

        INPUT:

        - ``x`` -- an element of the symmetric functions

        EXAMPLES::

            sage: s = SymmetricFunctions(QQ).s()
            sage: s(2)
            2*s[]
            sage: s([2,1]) # indirect doctest
            s[2, 1]

            sage: McdJ = SymmetricFunctions(QQ['q','t'].fraction_field()).macdonald().J()
            sage: s = SymmetricFunctions(McdJ.base_ring()).s()
            sage: s._element_constructor_(McdJ(s[2,1]))
            s[2, 1]

        TESTS:

        Check that non-Schur bases raise an error when given skew partitions
        (:trac:`19218`)::

            sage: e = SymmetricFunctions(QQ).e()
            sage: e([[2,1],[1]])
            Traceback (most recent call last):
            ...
            TypeError: do not know how to make x (= [[2, 1], [1]]) an element of self
        """
        R = self.base_ring()

        eclass = self.element_class
        if isinstance(x, int):
            x = Integer(x)


        ##############
        # Partitions #
        ##############
        if x in _Partitions:
            return eclass(self, {_Partitions(x): R.one()})

        # Todo: discard all of this which is taken care by Sage's coercion
        # (up to changes of base ring)

        ##############
        # Dual bases #
        ##############
        elif sfa.is_SymmetricFunction(x) and hasattr(x, 'dual'):
            #Check to see if it is the dual of some other basis
            #If it is, try to coerce its corresponding element
            #in the other basis
            return self(x.dual())

        ##################################################################
        # Symmetric Functions, same basis, possibly different coeff ring #
        ##################################################################

        # self.Element is used below to test if another symmetric
        # function is expressed in the same basis but in another
        # ground ring.  This idiom is fragile and depends on the
        # internal (unstable) specifications of parents and categories
        #
        # TODO: find the right idiom
        #
        # One cannot use anymore self.element_class: it is build by
        # the category mechanism, and depends on the coeff ring.

        elif isinstance(x, self.Element):
            P = x.parent()
            #same base ring
            if P is self:
                return x
            #different base ring
            else:
                return eclass(self, dict([ (e1,R(e2)) for e1,e2 in x._monomial_coefficients.items()]))

        ##################################################
        # Classical Symmetric Functions, different basis #
        ##################################################
        elif isinstance(x, SymmetricFunctionAlgebra_classical.Element):


            R = self.base_ring()
            xP = x.parent()
            xm = x.monomial_coefficients()

            #determine the conversion function.
            try:
                t = conversion_functions[(xP.basis_name(),self.basis_name())]
            except AttributeError:
                raise TypeError("do not know how to convert from %s to %s"%(xP.basis_name(), self.basis_name()))

            if R == QQ and xP.base_ring() == QQ:
                if xm:
                    return self._from_dict(t(xm)._monomial_coefficients, coerce=True)
                else:
                    return self.zero()
            else:
                f = lambda part: self._from_dict(t( {part: ZZ.one()} )._monomial_coefficients)
                return self._apply_module_endomorphism(x, f)


        ###############################
        # Hall-Littlewood Polynomials #
        ###############################
        elif isinstance(x, hall_littlewood.HallLittlewood_generic.Element):
            #
            #Qp: Convert to Schur basis and then convert to self
            #
            if isinstance(x, hall_littlewood.HallLittlewood_qp.Element):
                Qp = x.parent()
                sx = Qp._s._from_cache(x, Qp._s_cache, Qp._self_to_s_cache, t=Qp.t)
                return self(sx)
            #
            #P: Convert to Schur basis and then convert to self
            #
            elif isinstance(x, hall_littlewood.HallLittlewood_p.Element):
                P = x.parent()
                sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, t=P.t)
                return self(sx)
            #
            #Q: Convert to P basis and then convert to self
            #
            elif isinstance(x, hall_littlewood.HallLittlewood_q.Element):
                return self( x.parent()._P( x ) )

        #######
        # LLT #
        #######
        #Convert to m and then to self.
        elif isinstance(x, llt.LLT_generic.Element):
            P = x.parent()
            BR = self.base_ring()
            zero = BR.zero()
            PBR = P.base_ring()
            if not BR.has_coerce_map_from(PBR):
                raise TypeError("no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)"%(PBR, self.base_ring()))

            z_elt = {}
            for m, c in x._monomial_coefficients.iteritems():
                n = sum(m)
                P._m_cache(n)
                for part in P._self_to_m_cache[n][m]:
                    z_elt[part] = z_elt.get(part, zero) + BR(c*P._self_to_m_cache[n][m][part].subs(t=P.t))

            m = P._sym.monomial()
            return self( m._from_dict(z_elt) )

        #########################
        # Macdonald Polynomials #
        #########################
        elif isinstance(x, macdonald.MacdonaldPolynomials_generic.Element):
            if isinstance(x, macdonald.MacdonaldPolynomials_j.Element):
                J = x.parent()
                sx = J._s._from_cache(x, J._s_cache, J._self_to_s_cache, q=J.q, t=J.t)
                return self(sx)
            elif isinstance(x, (macdonald.MacdonaldPolynomials_q.Element, macdonald.MacdonaldPolynomials_p.Element)):
                J = x.parent()._J
                jx = J(x)
                sx = J._s._from_cache(jx, J._s_cache, J._self_to_s_cache, q=J.q, t=J.t)
                return self(sx)
            elif isinstance(x, (macdonald.MacdonaldPolynomials_h.Element,macdonald.MacdonaldPolynomials_ht.Element)):
                H = x.parent()
                sx = H._self_to_s(x)
                return self(sx)
            elif isinstance(x, macdonald.MacdonaldPolynomials_s.Element):
                S = x.parent()
                sx = S._s._from_cache(x, S._s_cache, S._self_to_s_cache, q=S.q, t=S.t)
                return self(sx)
            else:
                raise TypeError

        ####################
        # Jack Polynomials #
        ####################
        elif isinstance(x, jack.JackPolynomials_generic.Element):
            if isinstance(x, jack.JackPolynomials_p.Element):
                P = x.parent()
                mx = P._m._from_cache(x, P._m_cache, P._self_to_m_cache, t=P.t)
                return self(mx)
            if isinstance(x, (jack.JackPolynomials_j.Element, jack.JackPolynomials_q.Element)):
                return self( x.parent()._P(x) )
            else:
                raise TypeError

        ####################################################
        # Bases defined by orthogonality and triangularity #
        ####################################################
        elif isinstance(x, orthotriang.SymmetricFunctionAlgebra_orthotriang.Element):
            #Convert to its base and then to self
            xp = x.parent()
            if self is xp._sf_base:
                return xp._sf_base._from_cache(x, xp._base_cache, xp._self_to_base_cache)
            else:
                return self( xp._sf_base(x) )

        #################################
        # Last shot -- try calling R(x) #
        #################################
        else:
            try:
                return eclass(self, {_Partitions([]): R(x)})
            except Exception:
                raise TypeError("do not know how to make x (= {}) an element of self".format(x))
Ejemplo n.º 21
0
    def __classcall_private__(cls, cartan_type, shapes=None, shape=None):
        """
        Normalizes the input arguments to ensure unique representation,
        and to delegate the construction of spin tableaux.

        EXAMPLES::

            sage: T1 = crystals.Tableaux(CartanType(['A',3]), shape  = [2,2])
            sage: T2 = crystals.Tableaux(['A',3],             shape  = (2,2))
            sage: T3 = crystals.Tableaux(['A',3],             shapes = ([2,2],))
            sage: T2 is T1, T3 is T1
            (True, True)

            sage: T1 = crystals.Tableaux(['A', [1,1]], shape=[3,1,1,1])
            sage: T1
            Crystal of BKK tableaux of shape [3, 1, 1, 1] of gl(2|2)
            sage: T2 = crystals.Tableaux(['A', [1,1]], [3,1,1,1])
            sage: T1 is T2
            True

        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.letter == 'A' and isinstance(cartan_type,
                                                    SuperCartanType_standard):
            if shape is None:
                shape = shapes
            shape = _Partitions(shape)
            from sage.combinat.crystals.bkk_crystals import CrystalOfBKKTableaux
            return CrystalOfBKKTableaux(cartan_type, shape=shape)
        if cartan_type.letter == 'Q':
            if any(shape[i] == shape[i + 1] for i in range(len(shape) - 1)):
                raise ValueError("not a strict partition")
            shape = _Partitions(shape)
            return CrystalOfQueerTableaux(cartan_type, shape=shape)
        n = cartan_type.rank()
        # standardize shape/shapes input into a tuple of tuples
        # of length n, or n+1 in type A
        assert operator.xor(shape is not None, shapes is not None)
        if shape is not None:
            shapes = (shape, )
        if cartan_type.type() == "A":
            n1 = n + 1
        else:
            n1 = n
        if not all(all(i == 0 for i in shape[n1:]) for shape in shapes):
            raise ValueError(
                "shapes should all have length at most equal to the rank or the rank + 1 in type A"
            )
        spin_shapes = tuple((tuple(shape) + (0, ) * (n1 - len(shape)))[:n1]
                            for shape in shapes)
        try:
            shapes = tuple(
                tuple(trunc(i) for i in shape) for shape in spin_shapes)
        except Exception:
            raise ValueError(
                "shapes should all be partitions or half-integer partitions")
        if spin_shapes == shapes:
            shapes = tuple(
                _Partitions(shape) if shape[n1 - 1] in NN else shape
                for shape in shapes)
            return super(CrystalOfTableaux,
                         cls).__classcall__(cls, cartan_type, shapes)

        # Handle the construction of a crystals of spin tableaux
        # Caveat: this currently only supports all shapes being half
        # integer partitions of length the rank for type B and D. In
        # particular, for type D, the spins all have to be plus or all
        # minus spins
        if any(len(sh) != n for sh in shapes):
            raise ValueError(
                "the length of all half-integer partition shapes should be the rank"
            )
        if any(2 * i % 2 != 1 for shape in spin_shapes for i in shape):
            raise ValueError(
                "shapes should be either all partitions or all half-integer partitions"
            )
        if any(
                any(i < j
                    for i, j in zip(shape, shape[1:-1] + (abs(shape[-1]), )))
                for shape in spin_shapes):
            raise ValueError("entries of each shape must be weakly decreasing")
        if cartan_type.type() == 'D':
            if all(i >= 0 for shape in spin_shapes for i in shape):
                S = CrystalOfSpinsPlus(cartan_type)
            elif all(shape[-1] < 0 for shape in spin_shapes):
                S = CrystalOfSpinsMinus(cartan_type)
            else:
                raise ValueError(
                    "in type D spins should all be positive or negative")
        else:
            if any(i < 0 for shape in spin_shapes for i in shape):
                raise ValueError("shapes should all be partitions")
            S = CrystalOfSpins(cartan_type)
        B = CrystalOfTableaux(cartan_type, shapes=shapes)
        T = TensorProductOfCrystals(S,
                                    B,
                                    generators=[[S.module_generators[0], x]
                                                for x in B.module_generators])
        T.rename("The crystal of tableaux of type %s and shape(s) %s" %
                 (cartan_type, list(list(shape) for shape in spin_shapes)))
        T.shapes = spin_shapes
        return T
Ejemplo n.º 22
0
    def bottom_schur_function(self, partition, degree=None):
        r"""
        Return the least-degree component of ``s[partition]``,
        where ``s`` denotes the Schur basis of the symmetric
        functions, and the grading is not the usual grading on the
        symmetric functions but rather the grading which gives
        every `p_i` degree `1`.

        This least-degree component has its degree equal to the
        Frobenius rank of ``partition``, while the degree with respect
        to the usual grading is still the size of ``partition``.

        This method requires the base ring to be a (commutative)
        `\QQ`-algebra. This restriction is unavoidable, since
        the least-degree component (in general) has noninteger
        coefficients in all classical bases of the symmetric
        functions.

        The optional keyword ``degree`` allows taking any
        homogeneous component rather than merely the least-degree
        one. Specifically, if ``degree`` is set, then the
        ``degree``-th component will be returned.

        REFERENCES:

        .. [ClSt03] Peter Clifford, Richard P. Stanley,
           *Bottom Schur functions*.
           :arxiv:`math/0311382v2`.

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ)
            sage: p = Sym.p()
            sage: p.bottom_schur_function([2,2,1])
            -1/6*p[3, 2] + 1/4*p[4, 1]
            sage: p.bottom_schur_function([2,1])
            -1/3*p[3]
            sage: p.bottom_schur_function([3])
            1/3*p[3]
            sage: p.bottom_schur_function([1,1,1])
            1/3*p[3]
            sage: p.bottom_schur_function(Partition([1,1,1]))
            1/3*p[3]
            sage: p.bottom_schur_function([2,1], degree=1)
            -1/3*p[3]
            sage: p.bottom_schur_function([2,1], degree=2)
            0
            sage: p.bottom_schur_function([2,1], degree=3)
            1/3*p[1, 1, 1]
            sage: p.bottom_schur_function([2,2,1], degree=3)
            1/8*p[2, 2, 1] - 1/6*p[3, 1, 1]
        """
        from sage.combinat.partition import _Partitions
        s = self.realization_of().schur()
        partition = _Partitions(partition)
        if degree is None:
            degree = partition.frobenius_rank()
        s_partition = self(s[partition])
        return self.sum_of_terms(
            [(p, coeff) for p, coeff in s_partition if len(p) == degree],
            distinct=True)
Ejemplo n.º 23
0
 def P(i):
     return _Partitions([i]) if i else _Partitions([])
Ejemplo n.º 24
0
    def _element_constructor_(self, x):
        """
        Convert ``x`` into ``self``, if coercion failed.

        INPUT:

        - ``x`` -- an element of the symmetric functions

        EXAMPLES::

            sage: s = SymmetricFunctions(QQ).s()
            sage: s(2)
            2*s[]
            sage: s([2,1]) # indirect doctest
            s[2, 1]

            sage: McdJ = SymmetricFunctions(QQ['q','t'].fraction_field()).macdonald().J()
            sage: s = SymmetricFunctions(McdJ.base_ring()).s()
            sage: s._element_constructor_(McdJ(s[2,1]))
            s[2, 1]

        TESTS:

        Check that non-Schur bases raise an error when given skew partitions
        (:trac:`19218`)::

            sage: e = SymmetricFunctions(QQ).e()
            sage: e([[2,1],[1]])
            Traceback (most recent call last):
            ...
            TypeError: do not know how to make x (= [[2, 1], [1]]) an element of self
        """
        R = self.base_ring()

        eclass = self.element_class
        if isinstance(x, int):
            x = Integer(x)

        ##############
        # Partitions #
        ##############
        if x in _Partitions:
            return eclass(self, {_Partitions(x): R.one()})

        # Todo: discard all of this which is taken care by Sage's coercion
        # (up to changes of base ring)

        ##############
        # Dual bases #
        ##############
        elif sfa.is_SymmetricFunction(x) and hasattr(x, 'dual'):
            #Check to see if it is the dual of some other basis
            #If it is, try to coerce its corresponding element
            #in the other basis
            return self(x.dual())

        ##################################################################
        # Symmetric Functions, same basis, possibly different coeff ring #
        ##################################################################

        # self.Element is used below to test if another symmetric
        # function is expressed in the same basis but in another
        # ground ring.  This idiom is fragile and depends on the
        # internal (unstable) specifications of parents and categories
        #
        # TODO: find the right idiom
        #
        # One cannot use anymore self.element_class: it is build by
        # the category mechanism, and depends on the coeff ring.

        elif isinstance(x, self.Element):
            P = x.parent()
            #same base ring
            if P is self:
                return x
            #different base ring
            else:
                return eclass(
                    self,
                    dict([(e1, R(e2))
                          for e1, e2 in x._monomial_coefficients.items()]))

        ##################################################
        # Classical Symmetric Functions, different basis #
        ##################################################
        elif isinstance(x, SymmetricFunctionAlgebra_classical.Element):

            R = self.base_ring()
            xP = x.parent()
            xm = x.monomial_coefficients()

            #determine the conversion function.
            try:
                t = conversion_functions[(xP.basis_name(), self.basis_name())]
            except AttributeError:
                raise TypeError("do not know how to convert from %s to %s" %
                                (xP.basis_name(), self.basis_name()))

            if R == QQ and xP.base_ring() == QQ:
                if xm:
                    return self._from_dict(t(xm)._monomial_coefficients,
                                           coerce=True)
                else:
                    return self.zero()
            else:
                f = lambda part: self._from_dict(
                    t({
                        part: ZZ.one()
                    })._monomial_coefficients)
                return self._apply_module_endomorphism(x, f)

        ###############################
        # Hall-Littlewood Polynomials #
        ###############################
        elif isinstance(x, hall_littlewood.HallLittlewood_generic.Element):
            #
            #Qp: Convert to Schur basis and then convert to self
            #
            if isinstance(x, hall_littlewood.HallLittlewood_qp.Element):
                Qp = x.parent()
                sx = Qp._s._from_cache(x,
                                       Qp._s_cache,
                                       Qp._self_to_s_cache,
                                       t=Qp.t)
                return self(sx)
            #
            #P: Convert to Schur basis and then convert to self
            #
            elif isinstance(x, hall_littlewood.HallLittlewood_p.Element):
                P = x.parent()
                sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, t=P.t)
                return self(sx)
            #
            #Q: Convert to P basis and then convert to self
            #
            elif isinstance(x, hall_littlewood.HallLittlewood_q.Element):
                return self(x.parent()._P(x))

        #######
        # LLT #
        #######
        #Convert to m and then to self.
        elif isinstance(x, llt.LLT_generic.Element):
            P = x.parent()
            BR = self.base_ring()
            zero = BR.zero()
            PBR = P.base_ring()
            if not BR.has_coerce_map_from(PBR):
                raise TypeError(
                    "no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)"
                    % (PBR, self.base_ring()))

            z_elt = {}
            for m, c in x._monomial_coefficients.iteritems():
                n = sum(m)
                P._m_cache(n)
                for part in P._self_to_m_cache[n][m]:
                    z_elt[part] = z_elt.get(part, zero) + BR(
                        c * P._self_to_m_cache[n][m][part].subs(t=P.t))

            m = P._sym.monomial()
            return self(m._from_dict(z_elt))

        #########################
        # Macdonald Polynomials #
        #########################
        elif isinstance(x, macdonald.MacdonaldPolynomials_generic.Element):
            if isinstance(x, macdonald.MacdonaldPolynomials_j.Element):
                J = x.parent()
                sx = J._s._from_cache(x,
                                      J._s_cache,
                                      J._self_to_s_cache,
                                      q=J.q,
                                      t=J.t)
                return self(sx)
            elif isinstance(x, (macdonald.MacdonaldPolynomials_q.Element,
                                macdonald.MacdonaldPolynomials_p.Element)):
                J = x.parent()._J
                jx = J(x)
                sx = J._s._from_cache(jx,
                                      J._s_cache,
                                      J._self_to_s_cache,
                                      q=J.q,
                                      t=J.t)
                return self(sx)
            elif isinstance(x, (macdonald.MacdonaldPolynomials_h.Element,
                                macdonald.MacdonaldPolynomials_ht.Element)):
                H = x.parent()
                sx = H._self_to_s(x)
                return self(sx)
            elif isinstance(x, macdonald.MacdonaldPolynomials_s.Element):
                S = x.parent()
                sx = S._s._from_cache(x,
                                      S._s_cache,
                                      S._self_to_s_cache,
                                      q=S.q,
                                      t=S.t)
                return self(sx)
            else:
                raise TypeError

        ####################
        # Jack Polynomials #
        ####################
        elif isinstance(x, jack.JackPolynomials_generic.Element):
            if isinstance(x, jack.JackPolynomials_p.Element):
                P = x.parent()
                mx = P._m._from_cache(x, P._m_cache, P._self_to_m_cache, t=P.t)
                return self(mx)
            if isinstance(x, (jack.JackPolynomials_j.Element,
                              jack.JackPolynomials_q.Element)):
                return self(x.parent()._P(x))
            else:
                raise TypeError

        ####################################################
        # Bases defined by orthogonality and triangularity #
        ####################################################
        elif isinstance(
                x, orthotriang.SymmetricFunctionAlgebra_orthotriang.Element):
            #Convert to its base and then to self
            xp = x.parent()
            if self is xp._sf_base:
                return xp._sf_base._from_cache(x, xp._base_cache,
                                               xp._self_to_base_cache)
            else:
                return self(xp._sf_base(x))

        #################################
        # Last shot -- try calling R(x) #
        #################################
        else:
            try:
                return eclass(self, {_Partitions([]): R(x)})
            except Exception:
                raise TypeError(
                    "do not know how to make x (= {}) an element of self".
                    format(x))
Ejemplo n.º 25
0
def q_subgroups_of_abelian_group(la, mu, q=None, algorithm='birkhoff'):
    r"""
    Return the `q`-number of subgroups of type ``mu`` in a finite abelian
    group of type ``la``.

    INPUT:

    - ``la`` -- type of the ambient group as a :class:`Partition`
    - ``mu`` -- type of the subgroup as a :class:`Partition`
    - ``q`` -- (default: ``None``) an indeterminate or a prime number; if
      ``None``, this defaults to `q \in \ZZ[q]`
    - ``algorithm`` -- (default: ``'birkhoff'``) the algorithm to use can be
      one of the following:

      - ``'birkhoff`` -- use the Birkhoff formula from [Bu87]_
      - ``'delsarte'`` -- use the formula from [Delsarte48]_

    OUTPUT:

    The number of subgroups of type ``mu`` in a group of type ``la`` as a
    polynomial in ``q``.

    ALGORITHM:

    Let `q` be a prime number and `\lambda = (\lambda_1, \ldots, \lambda_l)`
    be a partition. A finite abelian `q`-group is of type `\lambda` if it
    is isomorphic to

    .. MATH::

        \ZZ / q^{\lambda_1} \ZZ \times \cdots \times \ZZ / q^{\lambda_l} \ZZ.

    The formula from [Bu87]_ works as follows:
    Let `\lambda` and `\mu` be partitions. Let `\lambda^{\prime}` and
    `\mu^{\prime}` denote the conjugate partitions to `\lambda` and `\mu`,
    respectively. The number of subgroups of type `\mu` in a group of type
    `\lambda` is given by

    .. MATH::

        \prod_{i=1}^{\mu_1} q^{\mu^{\prime}_{i+1}
        (\lambda^{\prime}_i - \mu^{\prime}_i)}
        \binom{\lambda^{\prime}_i - \mu^{\prime}_{i+1}}
        {\mu^{\prime}_i - \mu^{\prime}_{i+1}}_q

    The formula from [Delsarte48]_ works as follows:
    Let `\lambda` and `\mu` be partitions. Let `(s_1, s_2, \ldots, s_l)`
    and `(r_1, r_2, \ldots, r_k)` denote the parts of the partitions
    conjugate to `\lambda` and `\mu` respectively. Let


    .. MATH::

        \mathfrak{F}(\xi_1, \ldots, \xi_k) = \xi_1^{r_2} \xi_2^{r_3} \cdots
        \xi_{k-1}^{r_k} \prod_{i_1=r_2}^{r_1-1} (\xi_1-q^{i_1})
        \prod_{i_2=r_3}^{r_2-1} (\xi_2-q^{i_2}) \cdots
        \prod_{i_k=0}^{r_k-1} (\xi_k-q^{-i_k}).

    Then the number of subgroups of type `\mu` in a group of type `\lambda`
    is given by

    .. MATH::

        \frac{\mathfrak{F}(q^{s_1}, q^{s_2}, \ldots, q^{s_k})}{\mathfrak{F}
        (q^{r_1}, q^{r_2}, \ldots, q^{r_k})}.

    EXAMPLES::

        sage: from sage.combinat.q_analogues import q_subgroups_of_abelian_group
        sage: q_subgroups_of_abelian_group([1,1], [1])
        q + 1
        sage: q_subgroups_of_abelian_group([3,3,2,1], [2,1])
        q^6 + 2*q^5 + 3*q^4 + 2*q^3 + q^2
        sage: R.<t> = QQ[]
        sage: q_subgroups_of_abelian_group([5,3,1], [3,1], t)
        t^4 + 2*t^3 + t^2
        sage: q_subgroups_of_abelian_group([5,3,1], [3,1], 3)
        144
        sage: q_subgroups_of_abelian_group([1,1,1], [1]) == q_subgroups_of_abelian_group([1,1,1], [1,1])
        True
        sage: q_subgroups_of_abelian_group([5], [3])
        1
        sage: q_subgroups_of_abelian_group([1], [2])
        0
        sage: q_subgroups_of_abelian_group([2], [1,1])
        0

    TESTS:

    Check the same examples with ``algorithm='delsarte'``::

        sage: q_subgroups_of_abelian_group([1,1], [1], algorithm='delsarte')
        q + 1
        sage: q_subgroups_of_abelian_group([3,3,2,1], [2,1], algorithm='delsarte')
        q^6 + 2*q^5 + 3*q^4 + 2*q^3 + q^2
        sage: q_subgroups_of_abelian_group([5,3,1], [3,1], t, algorithm='delsarte')
        t^4 + 2*t^3 + t^2
        sage: q_subgroups_of_abelian_group([5,3,1], [3,1], 3, algorithm='delsarte')
        144
        sage: q_subgroups_of_abelian_group([1,1,1], [1], algorithm='delsarte') == q_subgroups_of_abelian_group([1,1,1], [1,1])
        True
        sage: q_subgroups_of_abelian_group([5], [3], algorithm='delsarte')
        1
        sage: q_subgroups_of_abelian_group([1], [2], algorithm='delsarte')
        0
        sage: q_subgroups_of_abelian_group([2], [1,1], algorithm='delsarte')
        0

    Check that :trac:`25715` is fixed::

        sage: parent(q_subgroups_of_abelian_group([2], [1], algorithm='delsarte'))
        Univariate Polynomial Ring in q over Integer Ring
        sage: q_subgroups_of_abelian_group([7,7,1], [])
        1
        sage: q_subgroups_of_abelian_group([7,7,1], [0,0])
        1

    REFERENCES:

    .. [Bu87] Butler, Lynne M. *A unimodality result in the enumeration
       of subgroups of a finite abelian group.* Proceedings of the American
       Mathematical Society 101, no. 4 (1987): 771-775.
       :doi:`10.1090/S0002-9939-1987-0911049-8`

    .. [Delsarte48] \S. Delsarte, *Fonctions de Möbius Sur Les Groupes Abeliens
       Finis*, Annals of Mathematics, second series, Vol. 45, No. 3, (Jul 1948),
       pp. 600-609. http://www.jstor.org/stable/1969047

    AUTHORS:

    - Amritanshu Prasad (2013-06-07): Implemented the Delsarte algorithm
    - Tomer Bauer (2013, 2018): Implemented the Birkhoff algorithm and refactoring
    """
    if q is None:
        q = ZZ['q'].gen()
    la_c = _Partitions(la).conjugate()
    mu_c = _Partitions(mu).conjugate()
    k = mu_c.length()
    if not mu_c:
        # There is only one trivial subgroup
        return parent(q)(1)
    if not la_c.contains(mu_c):
        return parent(q)(0)

    if algorithm == 'delsarte':

        def F(args):
            prd = lambda j: prod(args[j] - q**i
                                 for i in range(mu_c[j + 1], mu_c[j]))
            F1 = prod(args[i]**mu_c[i + 1] * prd(i) for i in range(k - 1))
            return F1 * prod(args[k - 1] - q**i for i in range(mu_c[k - 1]))

        return F([q**ss for ss in la_c[:k]]) // F([q**rr for rr in mu_c])

    if algorithm == 'birkhoff':
        fac1 = q**(sum(mu_c[i + 1] * (la_c[i] - mu_c[i])
                       for i in range(k - 1)))
        fac2 = prod(
            q_binomial(la_c[i] - mu_c[i + 1], mu_c[i] - mu_c[i + 1], q=q)
            for i in range(k - 1))
        fac3 = q_binomial(la_c[k - 1], mu_c[k - 1], q=q)

        return prod([fac1, fac2, fac3])

    raise ValueError("invalid algorithm choice")
Ejemplo n.º 26
0
    REFERENCES:

    - :wikipedia:`Q-Pochhammer_symbol`
    """
    if q is None:
        q = ZZ['q'].gen()
    if n not in ZZ:
        raise ValueError("{} must be an integer".format(n))
    R = parent(q)
    one = R(1)
    if n < 0:
        return R.prod(one / (one - a / q**-k) for k in range(1, -n + 1))
    return R.prod((one - a * q**k) for k in range(n))


@cached_function(key=lambda t, q: (_Partitions(t), q))
def q_jordan(t, q=None):
    r"""
    Return the `q`-Jordan number of `t`.

    If `q` is the power of a prime number, the output is the number of
    complete flags in `\GF{q}^N` (where `N` is the size of `t`) stable
    under a linear nilpotent endomorphism `f_t` whose Jordan type is
    given by `t`, i.e. such that for all `i`:

    .. MATH::

        \dim (\ker f_t^i) = t[0] + \cdots + t[i-1]

    If `q` is unspecified, then it defaults to using the generator `q` for
    a univariate polynomial ring over the integers.
Ejemplo n.º 27
0
 def P(i): return _Partitions([i]) if i else _Partitions([])
 T = self.tensor_square()
Ejemplo n.º 28
0
    def rectify(self, inner=None, verbose=False):
        """
        Rectify ``self``.

        This gives the usual rectification of a skew standard tableau and gives a
        generalisation to skew semistandard tableaux. The usual construction uses
        jeu-de-taquin but here we use the Bender-Knuth involutions.

        EXAMPLES::

            sage: st = SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]])
            sage: path_tableaux.SemistandardPathTableau(st).rectify()
            [(), (1,), (1, 1), (2, 1, 0), (3, 1, 0, 0), (3, 2, 0, 0, 0), (4, 2, 0, 0, 0, 0)]
            sage: path_tableaux.SemistandardPathTableau(st).rectify(verbose=True)
            [[(3, 2, 2), (3, 3, 2, 0), (3, 3, 2, 1, 0), (3, 3, 2, 2, 0, 0), (4, 3, 2, 2, 0, 0, 0), (4, 3, 3, 2, 0, 0, 0, 0), (4, 4, 3, 2, 0, 0, 0, 0, 0)],
            [(3, 2), (3, 3, 0), (3, 3, 1, 0), (3, 3, 2, 0, 0), (4, 3, 2, 0, 0, 0), (4, 3, 3, 0, 0, 0, 0), (4, 4, 3, 0, 0, 0, 0, 0)],
            [(3,), (3, 1), (3, 1, 1), (3, 2, 1, 0), (4, 2, 1, 0, 0), (4, 3, 1, 0, 0, 0), (4, 4, 1, 0, 0, 0, 0)],
            [(), (1,), (1, 1), (2, 1, 0), (3, 1, 0, 0), (3, 2, 0, 0, 0), (4, 2, 0, 0, 0, 0)]]

        TESTS::

            sage: S = SemistandardSkewTableaux([[5,3,3],[3,1]],[3,2,2])
            sage: LHS = [path_tableaux.SemistandardPathTableau(st.rectify()) for st in S]
            sage: RHS = [path_tableaux.SemistandardPathTableau(st).rectify() for st in S]
            sage: LHS == RHS
            True

            sage: st = SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]])
            sage: pt = path_tableaux.SemistandardPathTableau(st)
            sage: SP = [path_tableaux.SemistandardPathTableau(it) for it in StandardTableaux([3,2,2])]
            sage: len(set(pt.rectify(inner=ip) for ip in SP))
            1
        """
        if not self.is_skew():
            return self

        n = len(self)
        pp = self[0]
        P = self.parent()

        if inner is None:
            initial = [pp[:r] for r in range(len(pp))]
        elif _Partitions(inner[-1]) == _Partitions(pp):
            initial = list(inner)[:-1]
        else:
            raise ValueError(
                f"the final shape{inner[-1]} must agree with the initial shape {pp}"
            )

        r = len(initial)
        path = P.element_class(P, initial + list(self))
        if verbose:
            rect = [self]

        for i in range(r):
            for j in range(n - 1):
                path = path.local_rule(r + j - i)
            if verbose:
                rect.append(
                    P.element_class(P,
                                    list(path)[r - i - 1:r + n - i - 1]))

        if verbose:
            return rect
        else:
            return P.element_class(P, list(path)[:n])
Ejemplo n.º 29
0
 def P(i): return _Partitions([i]) if i else _Partitions([])
 T = self.tensor_square()