예제 #1
0
    def __init__(self, partition, ring=None, cache_matrices=True):
        r"""
        An irreducible representation of the symmetric group corresponding
        to ``partition``.

        For more information, see the documentation for
        :func:`SymmetricGroupRepresentation`.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([3])
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True

            sage: spc = SymmetricGroupRepresentation([3], cache_matrices=False)
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True
        """
        self._partition = Partition(partition)
        self._ring = ring if not ring is None else self._default_ring
        if cache_matrices is False:
            self.representation_matrix = self._representation_matrix_uncached
예제 #2
0
    def coproduct_on_basis(self, a):
        """
        Return the coproduct of the basis element indexed by ``a``.

        EXAMPLES::

            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
            sage: q = R.gen()
            sage: I = HallAlgebra(R, q).monomial_basis()
            sage: I.coproduct_on_basis(Partition([1]))
            I[] # I[1] + I[1] # I[]
            sage: I.coproduct_on_basis(Partition([2]))
            I[] # I[2] + 1/q*I[1] # I[1] + I[2] # I[]
            sage: I.coproduct_on_basis(Partition([2,1]))
            I[] # I[2, 1] + 1/q*I[1] # I[1, 1] + I[1] # I[2]
             + 1/q*I[1, 1] # I[1] + I[2] # I[1] + I[2, 1] # I[]

            sage: R.<q> = LaurentPolynomialRing(ZZ)
            sage: I = HallAlgebra(R, q).monomial_basis()
            sage: I.coproduct_on_basis(Partition([2,1]))
            I[] # I[2, 1] + (q^-1)*I[1] # I[1, 1] + I[1] # I[2]
             + (q^-1)*I[1, 1] # I[1] + I[2] # I[1] + I[2, 1] # I[]
        """
        S = self.tensor_square()
        return S.prod(S.sum_of_terms([( (Partition([r]), Partition([n-r]) ), self._q**(-r*(n-r)) )
                                      for r in range(n+1)], distinct=True) for n in a)
예제 #3
0
파일: core.py 프로젝트: biasse/sage
    def __classcall_private__(cls, part, k):
        r"""
        Implements the shortcut ``Core(part, k)`` to ``Cores(k,l)(part)``
        where `l` is the length of the core.

        TESTS::

            sage: c = Core([2,1],4); c
            [2, 1]
            sage: c.parent()
            4-Cores of length 3
            sage: type(c)
            <class 'sage.combinat.core.Cores_length_with_category.element_class'>

            sage: Core([2,1],3)
            Traceback (most recent call last):
            ...
            ValueError: [2, 1] is not a 3-core
        """
        if isinstance(part, cls):
            return part
        part = Partition(part)
        if not part.is_core(k):
            raise ValueError, "%s is not a %s-core"%(part, k)
        l = sum(part.k_boundary(k).row_lengths())
        return Cores(k, l)(part)
예제 #4
0
파일: dual.py 프로젝트: sagemath/sage
        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)
예제 #5
0
    def coproduct_on_generators(self, i):
        r"""
        Return coproduct on generators for power sums `p_i`
        (for `i > 0`).

        The elements `p_i` are primitive elements.

        INPUT:

        - ``self`` -- the power sum basis of the symmetric functions
        - ``i`` -- a positive integer

        OUTPUT:

        - the result of the coproduct on the generator `p(i)`

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ)
            sage: p = Sym.powersum()
            sage: p.coproduct_on_generators(2)
            p[] # p[2] + p[2] # p[]
        """
        Pi = Partition([i])
        P0 = Partition([])
        T = self.tensor_square()
        return T.sum_of_monomials([(Pi, P0), (P0, Pi)])
예제 #6
0
파일: dual.py 프로젝트: EnterStudios/sage-1
        def sum_of_partitions(self, la):
            """
            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)
예제 #7
0
파일: core.py 프로젝트: biasse/sage
    def __classcall_private__(cls, part, k):
        r"""
        Implements the shortcut ``Core(part, k)`` to ``Cores(k,l)(part)``
        where `l` is the length of the core.

        TESTS::

            sage: c = Core([2,1],4); c
            [2, 1]
            sage: c.parent()
            4-Cores of length 3
            sage: type(c)
            <class 'sage.combinat.core.Cores_length_with_category.element_class'>

            sage: Core([2,1],3)
            Traceback (most recent call last):
            ...
            ValueError: [2, 1] is not a 3-core
        """
        if isinstance(part, cls):
            return part
        part = Partition(part)
        if not part.is_core(k):
            raise ValueError, "%s is not a %s-core" % (part, k)
        l = sum(part.k_boundary(k).row_lengths())
        return Cores(k, l)(part)
예제 #8
0
    def __classcall_private__(cls, w, n, x=None, k=None):
        r"""
        Classcall to mend the input.

        TESTS::

            sage: A = crystals.AffineFactorization([[3,1],[1]], 4, k=3); A
            Crystal on affine factorizations of type A3 associated to s3*s2*s1
            sage: AC = crystals.AffineFactorization([Core([4,1],4),Core([1],4)], 4, k=3)
            sage: AC is A
            True
        """
        if k is not None:
            from sage.combinat.core import Core
            from sage.combinat.partition import Partition
            W = WeylGroup(['A', k, 1], prefix='s')
            if isinstance(w[0], Core):
                w = [w[0].to_bounded_partition(), w[1].to_bounded_partition()]
            else:
                w = [Partition(w[0]), Partition(w[1])]
            w0 = W.from_reduced_word(w[0].from_kbounded_to_reduced_word(k))
            w1 = W.from_reduced_word(w[1].from_kbounded_to_reduced_word(k))
            w = w0 * (w1.inverse())
        return super(AffineFactorizationCrystal,
                     cls).__classcall__(cls, w, n, x)
예제 #9
0
파일: core.py 프로젝트: biasse/sage
    def __init__(self, core, parent):
        """
        TESTS::

            sage: C = Cores(4,3)
            sage: c = C([2,1]); c
            [2, 1]
            sage: type(c)
            <class 'sage.combinat.core.Cores_length_with_category.element_class'>
            sage: c.parent()
            4-Cores of length 3
            sage: TestSuite(c).run()

            sage: C = Cores(3,3)
            sage: C([2,1])
            Traceback (most recent call last):
            ...
            ValueError: [2, 1] is not a 3-core
        """
        k = parent.k
        part = Partition(core)
        if not part.is_core(k):
            raise ValueError, "%s is not a %s-core" % (part, k)
        CombinatorialObject.__init__(self, core)
        Element.__init__(self, parent)
예제 #10
0
def bidecompositions(p):
    r"""
    Iterator through the pair of partitions ``(q1,q2)`` such that the union of
    the parts of ``q1`` and ``q2`` equal ``p``.

    EXAMPLES::

        sage: import surface_dynamics.interval_exchanges.rauzy_class_cardinality as rcc
        sage: list(rcc.bidecompositions(Partition([3,1])))
        [([], [3, 1]), ([3], [1]), ([1], [3]), ([3, 1], [])]
        sage: list(rcc.bidecompositions(Partition([2,1,1])))
        [([], [2, 1, 1]),
         ([2], [1, 1]),
         ([1], [2, 1]),
         ([2, 1], [1]),
         ([1, 1], [2]),
         ([2, 1, 1], [])]
    """
    from itertools import product

    exp = p.to_exp()
    for i in product(*tuple(xrange(i + 1) for i in exp)):
        p1 = Partition(exp=i)
        p2 = Partition(exp=[exp[j] - i[j] for j in xrange(len(exp))])
        yield p1, p2
예제 #11
0
파일: core.py 프로젝트: biasse/sage
    def __init__(self, core, parent):
        """
        TESTS::

            sage: C = Cores(4,3)
            sage: c = C([2,1]); c
            [2, 1]
            sage: type(c)
            <class 'sage.combinat.core.Cores_length_with_category.element_class'>
            sage: c.parent()
            4-Cores of length 3
            sage: TestSuite(c).run()

            sage: C = Cores(3,3)
            sage: C([2,1])
            Traceback (most recent call last):
            ...
            ValueError: [2, 1] is not a 3-core
        """
        k = parent.k
        part = Partition(core)
        if not part.is_core(k):
            raise ValueError, "%s is not a %s-core"%(part, k)
        CombinatorialObject.__init__(self, core)
        Element.__init__(self, parent)
예제 #12
0
    def coproduct_on_basis(self, la):
        """
        Return the coproduct of the basis element indexed by ``la``.

        EXAMPLES::

            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
            sage: q = R.gen()
            sage: H = HallAlgebra(R, q)
            sage: H.coproduct_on_basis(Partition([1,1]))
            H[] # H[1, 1] + 1/q*H[1] # H[1] + H[1, 1] # H[]
            sage: H.coproduct_on_basis(Partition([2]))
            H[] # H[2] + ((q-1)/q)*H[1] # H[1] + H[2] # H[]
            sage: H.coproduct_on_basis(Partition([2,1]))
            H[] # H[2, 1] + ((q^2-1)/q^2)*H[1] # H[1, 1] + 1/q*H[1] # H[2]
             + ((q^2-1)/q^2)*H[1, 1] # H[1] + 1/q*H[2] # H[1] + H[2, 1] # H[]
        """
        S = self.tensor_square()
        if all(x == 1 for x in la):
            n = len(la)
            return S.sum_of_terms([((Partition(
                [1] * r), Partition([1] * (n - r))), self._q**(-r * (n - r)))
                                   for r in range(n + 1)],
                                  distinct=True)

        I = HallAlgebraMonomials(self.base_ring(), self._q)
        la = self.monomial(la)
        return S(I(la).coproduct())
예제 #13
0
    def _llt_generic(self, skp, stat):
        r"""
        Takes in partition, list of partitions, or a list of skew
        partitions as well as a function which takes in two partitions and
        a level and returns a coefficient.

        INPUT:

        - ``self`` -- a family of LLT symmetric functions bases
        - ``skp`` -- a partition or a list of partitions or a list of skew partitions
        - ``stat`` -- a function which accepts two partitions and a value
          for the level and returns a coefficient which is a polynomial
          in a parameter `t`.  The first partition is the index of the
          LLT function, the second partition is the index of the monomial
          basis element.

        OUTPUT:

        - returns the monomial expansion of the LLT symmetric function
          indexed by ``skp``

        EXAMPLES::

            sage: L3 = SymmetricFunctions(FractionField(QQ['t'])).llt(3)
            sage: f = lambda skp,mu,level: QQ(1)
            sage: L3._llt_generic([3,2,1],f)
            m[1, 1] + m[2]
            sage: L3._llt_generic([[2,1],[1],[2]],f)
            m[1, 1, 1, 1, 1, 1] + m[2, 1, 1, 1, 1] + m[2, 2, 1, 1] + m[2, 2, 2] + m[3, 1, 1, 1] + m[3, 2, 1] + m[3, 3] + m[4, 1, 1] + m[4, 2] + m[5, 1] + m[6]
            sage: L3._llt_generic([[[2,2],[1]],[[2,1],[]]],f)
            m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1] + m[4]
        """
        if skp in _Partitions:
            m = (sum(skp) / self.level()).floor()
            if m == 0:
                raise ValueError("level (%s=) must divide %s " % (sum(skp),
                                                                  self.level()))
            mu = Partitions( ZZ(sum(skp) / self.level()) )

        elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions():
            #skp is a list of skew partitions
            skp2 =  [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])]
            skp2 += [Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])]
            mu = Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level()))
            skp = skp2
        elif isinstance(skp, list) and skp[0] in _Partitions:
            #skp is a list of partitions
            skp = Partition(core=[], quotient=skp)
            mu = Partitions( ZZ(sum(skp) / self.level()) )
        else:
            raise ValueError("LLT polynomials not defined for %s"%skp)

        BR = self.base_ring()
        return sum([ BR(stat(skp,nu,self.level()).subs(t=self.t))*self._m(nu) for nu in mu])
    def __init__(self, *args, **kwds):
        r"""
        TESTS::

            sage: from surface_dynamics.interval_exchanges.marked_partition import MarkedPartition
            sage: p = MarkedPartition([3,2,1], 1,(2,0))
            sage: loads(dumps(p)) == p
            True
        """
        from sage.combinat.partition import Partition

        if len(args) == 1 and isinstance(args[0], MarkedPartition):
            from copy import copy
            self.p = copy(args[0].p)
            self.m = copy(args[0].m)
        elif len(args) == 1 and isinstance(args[0], str):
            import re
            x = re.compile("(?P<mark>[^[]*)[^[]*\[(?P<parts>[^]]*)]")
            m = x.match(args[0])
            self.m = Marking(m.groupdict()["mark"])
            self.p = Partition(
                sorted(map(Integer,
                           m.groupdict()["parts"].split(',')),
                       reverse=True))
        elif len(args) == 1 and isinstance(args[0], (list, tuple)) and len(
                args[0]) == 3:
            self.p = Partition(sorted(args[0][0], reverse=True))
            self.m = Marking(args[0][1], args[0][2])
        elif len(args) == 3:
            self.p = Partition(sorted(args[0], reverse=True))
            self.m = Marking(args[1], args[2])
        else:
            raise ValueError("can not build marked partition from given data")

        if kwds.get("check", True):
            if self.p == Partition([]):
                if self.m.t != 2 or self.m.data[0] != 0 or self.m.data[1] != 0:
                    raise ValueError(
                        "empty partition has only type 2 with data (0,0)")

            elif self.m.t == 1:
                if self.m.data[0] not in self.p:
                    raise ValueError("%d is not an element of parts" % data[0])
            else:
                if ((self.m.data[0] not in self.p
                     or self.m.data[1] not in self.p)
                        or (self.m.data[0] == self.m.data[1]
                            and list(self.p).count(self.m.data[0]) < 2)):
                    raise ValueError(
                        "parts do not contains (m_l,m_r) = (%d,%d)" %
                        (self.m.data[0], self.m.data[1]))
예제 #15
0
        def affine_grassmannian_to_core(self):
            r"""
            Bijection between affine Grassmannian elements of type `A_k^{(1)}` and `(k+1)`-cores.

            INPUT:

            - ``self`` -- an affine Grassmannian element of some affine Weyl group of type `A_k^{(1)}`

            Recall that an element `w` of an affine Weyl group is
            affine Grassmannian if all its all reduced words end in 0, see :meth:`is_affine_grassmannian`.

            OUTPUT:

            - a `(k+1)`-core

            See also :meth:`affine_grassmannian_to_partition`.

            EXAMPLES::

                sage: W = WeylGroup(['A',2,1])
                sage: w = W.from_reduced_word([0,2,1,0])
                sage: la = w.affine_grassmannian_to_core(); la
                [4, 2]
                sage: type(la)
                <class 'sage.combinat.core.Cores_length_with_category.element_class'>
                sage: la.to_grassmannian() == w
                True

                sage: w = W.from_reduced_word([0,2,1])
                sage: w.affine_grassmannian_to_core()
                Traceback (most recent call last):
                ...
                ValueError: Error! this only works on type 'A' affine Grassmannian elements
            """
            from sage.combinat.partition import Partition
            from sage.combinat.core import Core
            if not self.is_affine_grassmannian() or not self.parent(
            ).cartan_type().letter == 'A':
                raise ValueError(
                    "Error! this only works on type 'A' affine Grassmannian elements"
                )
            out = Partition([])
            rword = self.reduced_word()
            kp1 = self.parent().n
            for i in range(len(rword)):
                for c in (x for x in out.outside_corners()
                          if (x[1] - x[0]) % kp1 == rword[-i - 1]):
                    out = out.add_cell(c[0], c[1])
            return Core(out._list, kp1)
예제 #16
0
    def _g_to_kh_on_basis(self,la):
        r"""
        Returns the expansion of the K-`k`-Schur function in the homogeneous basis. See
        method _DualGrothendieck for the code.

        INPUT:

        - ``la`` -- A `k`-bounded partition.

        OUTPUT:

        - A symmetric function in the homogeneous basis.

        EXAMPLES::

            sage: g = SymmetricFunctions(QQ).kBoundedSubspace(3,1).K_kschur()
            sage: g._g_to_kh_on_basis([2,1])
            h[2] + h[2, 1] - h[3]
            sage: g._g_to_kh_on_basis([])
            h[]
            sage: g._g_to_kh_on_basis([4,1])
            Traceback (most recent call last):
            ValueError: Partition should be 3-bounded
        """
        if la != [] and (la[0] > self.k):
            raise  ValueError, "Partition should be %d-bounded"%self.k
        return self._DualGrothendieck(Partition(la))
예제 #17
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 = Partition(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])
예제 #18
0
        def _comp_to_par(self, comp):
            """
            Return the partition if the composition is actually a partition. Otherwise
            returns nothing.

            INPUT:

            - ``comp`` -- a composition

            OUTPUT:

            - ``comp`` as a partition, if it is sorted; otherwise returns
              ``None`` (nothing).

            EXAMPLES::

                sage: NCSF=NonCommutativeSymmetricFunctions(QQ)
                sage: L = NCSF.elementary()
                sage: L._comp_to_par(Composition([1,1,3,1,2]))
                sage: L.sum_of_partition_rearrangements(Composition([]))
                L[]
                sage: L._comp_to_par(Composition([3,2,1,1]))
                [3, 2, 1, 1]
            """
            try:
                return Partition(comp)
            except ValueError:
                return None
예제 #19
0
    def _element_constructor_(self, list, **options):
        """
        Construct a :class:`KirillovReshetikhinTableauxElement`.

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['A', 4, 1], 2, 1)
            sage: KRT([3, 4]) # indirect doctest
            [[4], [3]]
            sage: KRT([4, 3])
            [[3], [4]]
        """
        if "shape" in options:
            return self._fill(Partition(options["shape"]).conjugate())

        if isinstance(list, KirillovReshetikhinGenericCrystalElement):
            # Check to make sure it can be converted
            if list.cartan_type() != self.cartan_type().affine() \
              or list.parent().r() != self._r or list.parent().s() != self._s:
                raise ValueError(
                    "The Kirillov-Reshetikhin crystal must have the same Cartan type and shape"
                )

            # To build a KR tableau from a KR crystal:
            # 1 - start with a highest weight KR tableau generated from the
            #  shape of the KR crystal
            # 2 - determine a path from the KR crystal to its highest weight
            # 3 - apply the inverse path to the highest weight KR tableau
            lifted = list.lift()
            shape = lifted.to_tableau().shape().conjugate()
            f_str = reversed(lifted.to_highest_weight()[1])
            return self._fill(shape).f_string(f_str)

        return KirillovReshetikhinTableaux._element_constructor_(
            self, list, **options)
예제 #20
0
def graph_implementation_rec(skp, weight, length, function):
    """
    TESTS::

        sage: from sage.combinat.ribbon_tableau import graph_implementation_rec, list_rec
        sage: graph_implementation_rec(SkewPartition([[1], []]), [1], 1, list_rec)
        [[[], [[1]]]]
        sage: graph_implementation_rec(SkewPartition([[2, 1], []]), [1, 2], 1, list_rec)
        [[[], [[2], [1, 2]]]]
        sage: graph_implementation_rec(SkewPartition([[], []]), [0], 1, list_rec)
        [[[], []]]
    """
    if sum(weight) == 0:
        weight = []

    partp = skp[0].conjugate()
    ell = len(partp)
    outer = skp[1]
    outer_len = len(outer)

    # Some tests in order to know if the shape and the weight are compatible.
    if weight and weight[-1] <= len(partp):
        perms = permutation.Permutations([0] * (len(partp) - weight[-1]) +
                                         [length] * (weight[-1])).list()
    else:
        return function([], [], skp, weight, length)

    selection = []

    for j in range(len(perms)):
        retire = [(val + ell - (i + 1) - perms[j][i])
                  for i, val in enumerate(partp)]
        retire.sort(reverse=True)
        retire = [val - ell + (i + 1) for i, val in enumerate(retire)]

        if retire[-1] >= 0 and retire == sorted(retire, reverse=True):
            retire = Partition(retire).conjugate()

            # Cutting branches if the retired partition has a line strictly included into the inner one
            if len(retire) >= outer_len:
                append = True
                for k in range(outer_len):
                    if retire[k] - outer[k] < 0:
                        append = False
                        break
                if append:
                    selection.append([retire, perms[j]])

    #selection contains the list of current nodes

    if len(weight) == 1:
        return function([], selection, skp, weight, length)
    else:
        #The recursive calls permit us to construct the list of the sons
        #of all current nodes in selection
        a = [
            graph_implementation_rec([p[0], outer], weight[:-1], length,
                                     function) for p in selection
        ]
        return function(a, selection, skp, weight, length)
예제 #21
0
    def __classcall_private__(cls, s, part=None):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: S = SetPartitions(4)
            sage: T = SetPartitions([1,2,3,4])
            sage: S is T
            True
        """
        if isinstance(s, (int, Integer)):
            s = frozenset(range(1, s + 1))
        else:
            try:
                if s.cardinality() == infinity:
                    raise ValueError("The set must be finite")
            except AttributeError:
                pass
            s = frozenset(s)

        if part is not None:
            if isinstance(part, (int, Integer)):
                if len(s) < part:
                    raise ValueError("part must be <= len(set)")
                else:
                    return SetPartitions_setn(s, part)
            else:
                if part not in Partitions(len(s)):
                    raise ValueError("part must be a partition of %s" % len(s))
                else:
                    return SetPartitions_setparts(s, Partition(part))
        else:
            return SetPartitions_set(s)
def syt_promotion(lam):
    r"""
    Return the invertible finite discrete dynamical system
    consisting of all standard tableaux of shape ``lam`` (a
    given partition) and evolving according to promotion.

    EXAMPLES::

        sage: F = finite_dynamical_systems.syt_promotion([4, 4, 4])
        sage: sorted(F.orbit_lengths())
        [3, 3, 4, 4, 4, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12,
         12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
         12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
         12, 12, 12, 12, 12]
        sage: G = finite_dynamical_systems.syt_promotion([4, 3, 1])
        sage: sorted(G.orbit_lengths())
        [16, 22, 32]
        sage: G.verify_inverse_evolution()
        True
    """
    from sage.combinat.partition import Partition
    lam = Partition(lam)
    from sage.combinat.tableau import StandardTableaux
    X = StandardTableaux(lam)
    return InvertibleFiniteDynamicalSystem(
        X, lambda T: T.promotion(), inverse=lambda T: T.promotion_inverse())
예제 #23
0
    def _stretch_gen(self, k, ao):
        """
        EXAMPLES::
        
            sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
            sage: p = SFAPower(QQ)
            sage: CIS = CycleIndexSeriesRing(p)
            sage: f = CIS([p([1])])
            sage: g = f._stretch_gen(2,0)
            sage: [g.next() for i in range(10)]
            [p[2], 0, p[2], 0, p[2], 0, p[2], 0, p[2], 0]
        """
        from sage.combinat.partition import Partition
        BR = self.base_ring()
        zero = BR(0)

        stretch_k = lambda p: Partition([k * i for i in p])

        yield self.coefficient(0).map_support(stretch_k)

        n = 1
        while True:
            for i in range(k - 1):
                yield BR(0)
            yield self.coefficient(n).map_support(stretch_k)
            n += 1
예제 #24
0
    def __init__(self, partition, ring=None, cache_matrices=True):
        r"""
        An irreducible representation of the symmetric group corresponding
        to ``partition``.

        For more information, see the documentation for
        :func:`SymmetricGroupRepresentation`.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([3])
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True

            sage: spc = SymmetricGroupRepresentation([3], cache_matrices=False)
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True
        """
        self._partition = Partition(partition)
        self._ring = ring if not ring is None else self._default_ring
        if cache_matrices is False:
            self.representation_matrix = self._representation_matrix_uncached
예제 #25
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.

        EXAMPLE::

            sage: T = CrystalOfTableaux(['D',3], shape = [1,1])
            sage: T.module_generator([1,1])
            [[1], [2]]
        """
        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 = Partition(shape).conjugate()
        # The column canonical tableau, read by columns
        module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(len(p))])
        if invert:
            for i in range(type[1]):
                if module_generator[i] == type[1]:
                    module_generator[i] = -type[1]
        return self(list=[self.letters(x) for x in module_generator])
예제 #26
0
def split(p, k, i=0):
    r"""
    Splits the i-th term of p into two parts of size k and n-k-1

    There is a symmetry split(p, k, i) = split(p, p[i]-k-1, i)

    INPUT:

    - ``p`` - a partition

    - ``k`` - an integer between 2 and p[i]

    - ``i`` - integer - the index of the element to split

    OUTPUT: a partition

    EXAMPLES::

        sage: import surface_dynamics.interval_exchanges.rauzy_class_cardinality as rcc
        sage: p = Partition([5,1])
        sage: rcc.split(p,1,0)
        [3, 1, 1]
        sage: rcc.split(p,2,0)
        [2, 2, 1]
        sage: rcc.split(p,3,0)
        [3, 1, 1]
    """
    l = list(p)
    n = l.pop(i)
    l.append(n - k - 1)
    l.append(k)
    l.sort(reverse=True)
    return Partition(l)
예제 #27
0
    def _cycle_type(self, s):
        """
        EXAMPLES::

            sage: cis = species.PartitionSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
            sage: cis = species.PermutationSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1, 1], [2, 2, 1, 1], [1, 1, 1, 1, 1, 1]]
            sage: cis = species.SetSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[1], [1], [1]]
        """
        if s == []:
            return self._card(0)
        res = []
        for k in range(1, self._upper_bound_for_longest_cycle(s) + 1):
            e = 0
            for d in divisors(k):
                m = moebius(d)
                if m == 0:
                    continue
                u = s.power(k / d)
                e += m * self.count(u)
            res.extend([k] * int(e / k))
        res.reverse()
        return Partition(res)
예제 #28
0
    def loop_type(self, other=None):
        r"""
        Return the loop type of ``self``.

        INPUT:

        - ``other`` -- a perfect matching of the same set of ``self``.
          (if the second argument is empty, the method :meth:`an_element` is
          called on the parent of the first)

        OUTPUT:

        If we draw the two perfect matchings simultaneously as edges of a
        graph, the graph obtained is a union of cycles of even
        lengths. The function returns the ordered list of the semi-length
        of these cycles (considered as a partition)

        EXAMPLES::

            sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
            sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')])
            sage: m.loop_type(n)
            [2, 1]

        TESTS::

            sage: m = PerfectMatching([]); m.loop_type()
            []
        """
        return Partition(
            sorted((len(l) // 2 for l in self.loops_iterator(other)),
                   reverse=True))
예제 #29
0
    def _stretch_gen(self, k, ao):
        """
        EXAMPLES::

            sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
            sage: p = SymmetricFunctions(QQ).power()
            sage: CIS = CycleIndexSeriesRing(QQ)
            sage: f = CIS([p([1])]) # This is the power series whose all coefficients
            ....:                   # are p[1]. Not combinatorially meaningful!
            sage: g = f._stretch_gen(2,0)
            sage: [next(g) for i in range(10)]
            [p[2], 0, p[2], 0, p[2], 0, p[2], 0, p[2], 0]
        """
        from sage.combinat.partition import Partition
        BR = self.base_ring()
        zero = BR.zero()

        stretch_k = lambda p: Partition([k * i for i in p])

        yield self.coefficient(0).map_support(stretch_k)

        n = 1
        while True:
            for i in range(k - 1):
                yield zero
            yield self.coefficient(n).map_support(stretch_k)
            n += 1
예제 #30
0
    def G_quotient(self, r, b=-1, label_swap_xy=False):
        r"""
        Calculates the G-quotient of `self` with respect to the $(r,b)$-action, 

        First, the G-abacus of `self` is computed. Second, the path sequence of each abacus wire is converted back to a partition.
        Note that the abacus uses the convention {1:N, 0:E} in English notation for partition border paths

        Due to differences in conventions effectively swapping xy-coordinates for cell colouring (vs. content), the order of partitions 
        in the $(r,r-1)$-quotient ($b=-1$ special case) differs from the classical $r$-quotient by a reflection of indices. 
        This can be accounted for by setting the optional `label_swap_xy` keyword argument to `True`. A cell $(i,j)$ is mapped as
        `Partition.content` -> $j - i$, whilst $(r,-1)$-colour -> $i - j (mod r)$ (as case of $(r,b)$-colour -> $i + bj (mod r)$).

        Returns: an $r$-tuple of partitions
        """
        # Sagemath uses the convention {1:E, 0:N} when reading partition from a path sequence, so we have to swap '0's and '1's
        p_list = [
            Partition(zero_one=invert_zero_one(wire))
            for wire in self.G_abacus(r, b)
        ]
        # Reflect the order of partitions in the $b=-1$ case `G_quotient` to account for differences in conventions for cell colouring
        # for compatibility with `Partition.quotient`.
        if label_swap_xy:
            p_list = [p_list[0]] + p_list[:0:-1]
        # Cast the list of partitions in the quotient as a `PartitionTuple` for compatibility with the `Partition.quotient` method
        return PartitionTuple(p_list)
예제 #31
0
def graph_implementation_rec(skp, weight, length, function):
    """
    TESTS::

        sage: from sage.combinat.ribbon_tableau import graph_implementation_rec, list_rec
        sage: graph_implementation_rec(SkewPartition([[1], []]), [1], 1, list_rec)
        [[[], [[1]]]]
        sage: graph_implementation_rec(SkewPartition([[2, 1], []]), [1, 2], 1, list_rec)
        [[[], [[2], [1, 2]]]]
        sage: graph_implementation_rec(SkewPartition([[], []]), [0], 1, list_rec)
        [[[], []]]
    """
    if sum(weight) == 0:
        weight = []

    partp = skp[0].conjugate()

    ## Some tests in order to know if the shape and the weight are compatible.
    if weight != [] and weight[-1] <= len(partp):
        perms = permutation.Permutations([0] * (len(partp) - weight[-1]) +
                                         [length] * (weight[-1])).list()
    else:
        return function([], [], skp, weight, length)

    selection = []

    for j in range(len(perms)):
        retire = [(partp[i] + len(partp) - (i + 1) - perms[j][i])
                  for i in range(len(partp))]
        retire.sort(reverse=True)
        retire = [retire[i] - len(partp) + (i + 1) for i in range(len(retire))]

        if retire[-1] >= 0 and retire == [i for i in reversed(sorted(retire))]:
            retire = Partition([x for x in retire if x != 0]).conjugate()

            # Cutting branches if the retired partition has a line strictly included into the inner one
            append = True
            padded_retire = retire + [0] * (len(skp[1]) - len(retire))
            for k in range(len(skp[1])):
                if padded_retire[k] - skp[1][k] < 0:
                    append = False
                    break
            if append:
                selection.append([retire, perms[j]])

    #selection contains the list of current nodes
    #print "selection", selection

    if len(weight) == 1:
        return function([], selection, skp, weight, length)
    else:
        #The recursive calls permit us to construct the list of the sons
        #of all current nodes in selection
        a = [
            graph_implementation_rec([p[0], skp[1]], weight[:-1], length,
                                     function) for p in selection
        ]
        #print "a", a
        return function(a, selection, skp, weight, length)
예제 #32
0
        def affine_grassmannian_to_core(self):
            r"""
            Bijection between affine Grassmannian elements of type `A_k^{(1)}` and `(k+1)`-cores.

            INPUT:

            - ``self`` -- an affine Grassmannian element of some affine Weyl group of type `A_k^{(1)}`

            Recall that an element `w` of an affine Weyl group is
            affine Grassmannian if all its all reduced words end in 0, see :meth:`is_affine_grassmannian`.

            OUTPUT:

            - a `(k+1)`-core

            See also :meth:`affine_grassmannian_to_partition`.

            EXAMPLES::

                sage: W = WeylGroup(['A',2,1])
                sage: w = W.from_reduced_word([0,2,1,0])
                sage: la = w.affine_grassmannian_to_core(); la
                [4, 2]
                sage: type(la)
                <class 'sage.combinat.core.Cores_length_with_category.element_class'>
                sage: la.to_grassmannian() == w
                True

                sage: w = W.from_reduced_word([0,2,1])
                sage: w.affine_grassmannian_to_core()
                Traceback (most recent call last):
                ...
                ValueError: Error! this only works on type 'A' affine Grassmannian elements
            """
            from sage.combinat.partition import Partition
            from sage.combinat.core import Core

            if not self.is_affine_grassmannian() or not self.parent().cartan_type().letter == "A":
                raise ValueError("Error! this only works on type 'A' affine Grassmannian elements")
            out = Partition([])
            rword = self.reduced_word()
            kp1 = self.parent().n
            for i in range(len(rword)):
                for c in (x for x in out.outside_corners() if (x[1] - x[0]) % kp1 == rword[-i - 1]):
                    out = out.add_cell(c[0], c[1])
            return Core(out._list, kp1)
예제 #33
0
    def Podium(data):
        r"""
        If ``data`` is an integer than the standard podium with ``data`` steps is
        returned. Otherwise, ``data`` should be a weakly decreasing list of integers
        (i.e. a integer partition).

        EXAMPLES::

            sage: from surface_dynamics.all import *

            sage: o = origamis.Podium([3,3,2,1])
            sage: o
            Podium origami with partition [3, 3, 2, 1]
            sage: print o
            (1,2,3)(4,5,6)(7,8)(9)
            (1,4,7,9)(2,5,8)(3,6)
        """
        from sage.combinat.partition import Partition

        if isinstance(data, (int,Integer)):
            p = Partition([i for i in xrange(data,0,-1)])
        else:
            p = Partition(data)

        p = Partition(data)
        q = p.conjugate()

        r=[]
        positions = []
        i = 0
        for j,jj in enumerate(p):
            r.extend(xrange(i+1,i+jj))
            r.append(i)
            i += jj
            positions.extend((k,j) for k in xrange(jj))

        u = [None]*sum(p)
        for j in xrange(len(q)):
            k = j
            for jj in xrange(q[j]-1):
                u[k] = k+p[jj]
                k += p[jj]
            u[k] = j

        return Origami(r,u,positions=positions,name="Podium origami with partition %s" %str(p),as_tuple=True)
예제 #34
0
 def contained_partitions(l):
     """
     Nested function returning those partitions contained in
     the partition `l`
     """
     if l == Partition([]):
         return l
     return flatten(
         [l, [contained_partitions(m) for m in lower_covers(l)]])
예제 #35
0
 def arith_prod_of_partitions(l1, l2):
     # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by
     # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes
     # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2`
     # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a
     # partition of `nm`.
     term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair))
                                         for pair in product(l1, l2))
     return Partition(sorted(term_iterable, reverse=True))
예제 #36
0
    def __classcall_private__(cls, shape, weight):
        r"""
        Straighten arguments before unique representation.

        TESTS::

            sage: LR = LittlewoodRichardsonTableaux([3,2,1],[[2,1],[2,1]])
            sage: TestSuite(LR).run()
            sage: LittlewoodRichardsonTableaux([3,2,1],[[2,1]])
            Traceback (most recent call last):
            ...
            ValueError: the sizes of shapes and sequence of weights do not match
        """
        shape = Partition(shape)
        weight = tuple(Partition(a) for a in weight)
        if shape.size() != sum(a.size() for a in weight):
            raise ValueError("the sizes of shapes and sequence of weights do not match")
        return super(LittlewoodRichardsonTableaux, cls).__classcall__(cls, shape, weight)
예제 #37
0
파일: lr_tableau.py 프로젝트: sagemath/sage
    def __classcall_private__(cls, shape, weight):
        r"""
        Straighten arguments before unique representation.

        TESTS::

            sage: LR = LittlewoodRichardsonTableaux([3,2,1],[[2,1],[2,1]])
            sage: TestSuite(LR).run()
            sage: LittlewoodRichardsonTableaux([3,2,1],[[2,1]])
            Traceback (most recent call last):
            ...
            ValueError: the sizes of shapes and sequence of weights do not match
        """
        shape = Partition(shape)
        weight = tuple(Partition(a) for a in weight)
        if shape.size() != sum(a.size() for a in weight):
            raise ValueError("the sizes of shapes and sequence of weights do not match")
        return super(LittlewoodRichardsonTableaux, cls).__classcall__(cls, shape, weight)
예제 #38
0
    def __classcall_private__(cls, deg, par):
        r"""
        Create a primary similarity class type.

        EXAMPLES::

            sage: PrimarySimilarityClassType(2, [3, 2, 1])
            [2, [3, 2, 1]]

        The parent class is the class of primary similarity class types of order
        `d|\lambda\`::

            sage: PT = PrimarySimilarityClassType(2, [3, 2, 1])
            sage: PT.parent().size()
            12
        """
        par = Partition(par)
        P = PrimarySimilarityClassTypes(par.size() * deg)
        return P(deg, par)
예제 #39
0
    def count(self, t):
        """
        Return the number of structures corresponding to a certain cycle
        type ``t``.

        EXAMPLES::

            sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
            sage: p = SymmetricFunctions(QQ).power()
            sage: CIS = CycleIndexSeriesRing(QQ)
            sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])])
            sage: f.count([1])
            1
            sage: f.count([1,1])
            4
            sage: f.count([2,1])
            6
        """
        t = Partition(t)
        return t.aut() * self.coefficient_cycle_type(t)
예제 #40
0
    def coefficient_cycle_type(self, t):
        """
        Returns the coefficient of a cycle type ``t`` in ``self``.

        EXAMPLES::

            sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing
            sage: p = SymmetricFunctions(QQ).power()
            sage: CIS = CycleIndexSeriesRing(QQ)
            sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])])
            sage: f.coefficient_cycle_type([1])
            1
            sage: f.coefficient_cycle_type([1,1])
            2
            sage: f.coefficient_cycle_type([2,1])
            3
        """
        t = Partition(t)
        p = self.coefficient(t.size())
        return p.coefficient(t)
def marking_iterator(profile,left=None,standard=False):
    r"""
    Returns the marked profile associated to a partition

    EXAMPLES::

        sage: import surface_dynamics.interval_exchanges.rauzy_class_cardinality as rcc
        sage: p = Partition([3,2,2])
        sage: list(rcc.marking_iterator(p))
        [(1, 2, 0),
         (1, 2, 1),
         (1, 3, 0),
         (1, 3, 1),
         (1, 3, 2),
         (2, 2, 2),
         (2, 2, 3),
         (2, 3, 2)]
    """
    e = Partition(sorted(profile,reverse=True)).to_exp_dict()

    if left is not None:
        assert(left in e)

    if left is not None: keys = [left]
    else: keys = e.keys()

    for m in keys:
        if standard: angles = range(1,m-1)
        else: angles = range(0,m)
        for a in angles:
            yield (1,m,a)

    for m_l in keys:
        for m_r in e:
            if m_l != m_r or e[m_l] > 1:
                yield (2,m_l,m_r)
예제 #42
0
def hall_polynomial(nu, mu, la, q=None):
    r"""
    Return the (classical) Hall polynomial `P^{\nu}_{\mu,\lambda}`
    (where `\nu`, `\mu` and `\lambda` are the inputs ``nu``, ``mu``
    and ``la``).

    Let `\nu,\mu,\lambda` be partitions. The Hall polynomial
    `P^{\nu}_{\mu,\lambda}(q)` (in the indeterminate `q`) is defined
    as follows: Specialize `q` to a prime power, and consider the
    category of `\GF{q}`-vector spaces with a distinguished
    nilpotent endomorphism. The morphisms in this category shall be
    the linear maps commuting with the distinguished endomorphisms.
    The *type* of an object in the category will be the Jordan type
    of the distinguished endomorphism; this is a partition. Now, if
    `N` is any fixed object of type `\nu` in this category, then
    the polynomial `P^{\nu}_{\mu,\lambda}(q)` specialized at the
    prime power `q` counts the number of subobjects `L` of `N` having
    type `\lambda` such that the quotient object `N / L` has type
    `\mu`. This determines the values of the polynomial
    `P^{\nu}_{\mu,\lambda}` at infinitely many points (namely, at all
    prime powers), and hence `P^{\nu}_{\mu,\lambda}` is uniquely
    determined. The degree of this polynomial is at most
    `n(\nu) - n(\lambda) - n(\mu)`, where
    `n(\kappa) = \sum_i (i-1) \kappa_i` for every partition `\kappa`.
    (If this is negative, then the polynomial is zero.)

    These are the structure coefficients of the
    :class:`(classical) Hall algebra <HallAlgebra>`.

    If `\lvert \nu \rvert \neq \lvert \mu \rvert + \lvert \lambda \rvert`,
    then we have `P^{\nu}_{\mu,\lambda} = 0`. More generally, if the
    Littlewood-Richardson coefficient `c^{\nu}_{\mu,\lambda}`
    vanishes, then `P^{\nu}_{\mu,\lambda} = 0`.

    The Hall polynomials satisfy the symmetry property
    `P^{\nu}_{\mu,\lambda} = P^{\nu}_{\lambda,\mu}`.

    ALGORITHM:

    If `\lambda = (1^r)` and
    `\lvert \nu \rvert = \lvert \mu \rvert + \lvert \lambda \rvert`,
    then we compute `P^{\nu}_{\mu,\lambda}` as follows (cf. Example 2.4
    in [Schiffmann]_):

    First, write `\nu = (1^{l_1}, 2^{l_2}, \ldots, n^{l_n})`, and
    define a sequence `r = r_0 \geq r_1 \geq \cdots \geq r_n` such that

    .. MATH::

        \mu = \left( 1^{l_1 - r_0 + 2r_1 - r_2}, 2^{l_2 - r_1 + 2r_2 - r_3},
        \ldots , (n-1)^{l_{n-1} - r_{n-2} + 2r_{n-1} - r_n},
        n^{l_n - r_{n-1} + r_n} \right).

    Thus if `\mu = (1^{m_1}, \ldots, n^{m_n})`, we have the following system
    of equations:

    .. MATH::

        \begin{aligned}
        m_1 & = l_1 - r + 2r_1 - r_2,
        \\ m_2 & = l_2 - r_1 + 2r_2 - r_3,
        \\ & \vdots ,
        \\ m_{n-1} & = l_{n-1} - r_{n-2} + 2r_{n-1} - r_n,
        \\ m_n & = l_n - r_{n-1} + r_n
        \end{aligned}

    and solving for `r_i` and back substituting we obtain the equations:

    .. MATH::

        \begin{aligned}
        r_n & = r_{n-1} + m_n - l_n,
        \\ r_{n-1} & = r_{n-2} + m_{n-1} - l_{n-1} + m_n - l_n,
        \\ & \vdots ,
        \\ r_1 & = r + \sum_{k=1}^n (m_k - l_k),
        \end{aligned}

    or in general we have the recursive equation:

    .. MATH::

        r_i = r_{i-1} + \sum_{k=i}^n (m_k - l_k).

    This, combined with the condition that `r_0 = r`, determines the
    `r_i` uniquely (recursively). Next we define

    .. MATH::

        t = (r_{n-2} - r_{n-1})(l_n - r_{n-1})
        + (r_{n-3} - r_{n-2})(l_{n-1} + l_n - r_{n-2}) + \cdots
        + (r_0 - r_1)(l_2 + \cdots + l_n - r_1),

    and with these notations we have

    .. MATH::

        P^{\nu}_{\mu,(1^r)} = q^t \binom{l_n}{r_{n-1}}_q
        \binom{l_{n-1}}{r_{n-2} - r_{n-1}}_q \cdots \binom{l_1}{r_0 - r_1}_q.

    To compute `P^{\nu}_{\mu,\lambda}` in general, we compute the product
    `I_{\mu} I_{\lambda}` in the Hall algebra and return the coefficient of
    `I_{\nu}`.

    EXAMPLES::

        sage: from sage.combinat.hall_polynomial import hall_polynomial
        sage: hall_polynomial([1,1],[1],[1])
        q + 1
        sage: hall_polynomial([2],[1],[1])
        1
        sage: hall_polynomial([2,1],[2],[1])
        q
        sage: hall_polynomial([2,2,1],[2,1],[1,1])
        q^2 + q
        sage: hall_polynomial([2,2,2,1],[2,2,1],[1,1])
        q^4 + q^3 + q^2
        sage: hall_polynomial([3,2,2,1], [3,2], [2,1])
        q^6 + q^5
        sage: hall_polynomial([4,2,1,1], [3,1,1], [2,1])
        2*q^3 + q^2 - q - 1
        sage: hall_polynomial([4,2], [2,1], [2,1], 0)
        1
    """
    if q is None:
        q = ZZ['q'].gen()
    R = q.parent()

    # Make sure they are partitions
    nu = Partition(nu)
    mu = Partition(mu)
    la = Partition(la)

    if sum(nu) != sum(mu) + sum(la):
        return R.zero()

    if all(x == 1 for x in la):
        r = [len(la)]   # r will be [r_0, r_1, ..., r_n].
        exp_nu = nu.to_exp()  # exp_nu == [l_1, l_2, ..., l_n].
        exp_mu = mu.to_exp()  # exp_mu == [m_1, m_2, ..., m_n].
        n = max(len(exp_nu), len(exp_mu))
        for k in range(n):
            r.append(r[-1] + sum(exp_mu[k:]) - sum(exp_nu[k:]))
        # Now, r is [r_0, r_1, ..., r_n].
        exp_nu += [0]*(n - len(exp_nu)) # Pad with 0's until it has length n
        # Note that all -1 for exp_nu is due to indexing
        t = sum((r[k-2] - r[k-1])*(sum(exp_nu[k-1:]) - r[k-1]) for k in range(2,n+1))
        if t < 0:
            # This case needs short-circuiting, since otherwise q**-t
            # might throw an exception if q is non-invertible.
            return R.zero()
        return q**t * q_binomial(exp_nu[n-1], r[n-1], q) \
               * prod([q_binomial(exp_nu[k-1], r[k-1] - r[k], q)
                       for k in range(1, n)], R.one())

    from sage.algebras.hall_algebra import HallAlgebra
    H = HallAlgebra(R, q)
    return (H[mu]*H[la]).coefficient(nu)
예제 #43
0
파일: q_analogues.py 프로젝트: drupel/sage
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 indeterminat 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

    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-09-26): Implemented the Birkhoff algorithm
    """
    if q is None:
        q = ZZ['q'].gens()[0]
    la_c = Partition(la).conjugate()
    mu_c = Partition(mu).conjugate()
    k = mu_c.length()
    if not la_c.contains(mu_c):
        return q.parent().zero()

    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")
예제 #44
0
class SymmetricGroupRepresentation_generic_class(SageObject):
    r"""
    Generic methods for a representation of the symmetric group.
    """
    _default_ring = None

    def __init__(self, partition, ring=None, cache_matrices=True):
        r"""
        An irreducible representation of the symmetric group corresponding
        to ``partition``.

        For more information, see the documentation for
        :func:`SymmetricGroupRepresentation`.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([3])
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True

            sage: spc = SymmetricGroupRepresentation([3], cache_matrices=False)
            sage: spc([3,2,1])
            [1]
            sage: spc == loads(dumps(spc))
            True
        """
        self._partition = Partition(partition)
        self._ring = ring if not ring is None else self._default_ring
        if cache_matrices is False:
            self.representation_matrix = self._representation_matrix_uncached

    def __eq__(self, other):
        r"""
        Test for equality.

        EXAMPLES::

            sage: spc1 = SymmetricGroupRepresentation([3], cache_matrices=True)
            sage: spc1([3,1,2])
            [1]
            sage: spc2 = loads(dumps(spc1))
            sage: spc1 == spc2
            True

        ::

            sage: spc3 = SymmetricGroupRepresentation([3], cache_matrices=False)
            sage: spc3([3,1,2])
            [1]
            sage: spc4 = loads(dumps(spc3))
            sage: spc3 == spc4
            True

        TESTS:

        The following tests against some bug that was fixed in :trac:`8611`::

            sage: spc = SymmetricGroupRepresentation([3])
            sage: spc.important_info = 'Sage rules'
            sage: spc == SymmetricGroupRepresentation([3])
            True

        """
        if not isinstance(other, type(other)):
            return False
        return (self._ring,self._partition)==(other._ring,other._partition)
#        # both self and other must have caching enabled
#        if 'representation_matrix' in self.__dict__:
#            if 'representation_matrix' not in other.__dict__:
#                return False
#            else:
#                for key in self.__dict__:
#                    if key != 'representation_matrix':
#                        if self.__dict__[key] != other.__dict__[key]:
#                            return False
#                else:
#                    return True
#        else:
#            if 'representation_matrix' in other.__dict__:
#                return False
#            else:
#                return self.__dict__.__eq__(other.__dict__)

    def __call__(self, permutation):
        r"""
        Return the image of ``permutation`` in the representation.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([2,1])
            sage: spc([1,3,2])
            [ 1  0]
            [ 1 -1]
        """
        return self.representation_matrix(Permutation(permutation))

    def __iter__(self):
        r"""
        Iterate over the matrices representing the elements of the
        symmetric group.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([1,1,1])
            sage: list(spc)
            [[1], [-1], [-1], [1], [1], [-1]]
        """
        for permutation in Permutations(self._partition.size()):
            yield self.representation_matrix(permutation)

    def verify_representation(self):
        r"""
        Verify the representation: tests that the images of the simple
        transpositions are involutions and tests that the braid relations
        hold.

        EXAMPLES::

            sage: spc = SymmetricGroupRepresentation([1,1,1])
            sage: spc.verify_representation()
            True
            sage: spc = SymmetricGroupRepresentation([4,2,1])
            sage: spc.verify_representation()
            True
        """
        n = self._partition.size()
        transpositions = []
        for i in range(1,n):
            si = Permutation(range(1,i) + [i+1,i] + range(i+2,n+1))
            transpositions.append(si)
        repn_matrices = map(self.representation_matrix, transpositions)
        for (i,si) in enumerate(repn_matrices):
            for (j,sj) in enumerate(repn_matrices):
                if i == j:
                    if si*sj != si.parent().identity_matrix():
                        return False, "si si != 1 for i = %s" % (i,)
                elif abs(i-j) > 1:
                    if si*sj != sj*si:
                        return False, "si sj != sj si for (i,j) =(%s,%s)" % (i,j)
                else:
                    if si*sj*si != sj*si*sj:
                        return False, "si sj si != sj si sj for (i,j) = (%s,%s)" % (i,j)
        return True

    def to_character(self):
        r"""
        Return the character of the representation.

        EXAMPLES:

        The trivial character::

            sage: rho = SymmetricGroupRepresentation([3])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, 1, 1]
            sage: all(chi(g) == 1 for g in SymmetricGroup(3))
            True

        The sign character::

            sage: rho = SymmetricGroupRepresentation([1,1,1])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, -1, 1]
            sage: all(chi(g) == g.sign() for g in SymmetricGroup(3))
            True

        The defining representation::

            sage: triv = SymmetricGroupRepresentation([4])
            sage: hook = SymmetricGroupRepresentation([3,1])
            sage: def_rep = lambda p : triv(p).block_sum(hook(p)).trace()
            sage: map(def_rep, Permutations(4))
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]
            sage: [p.to_matrix().trace() for p in Permutations(4)]
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]

        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        Sym = SymmetricGroup(sum(self._partition))
        values = [self(g).trace() for g in Sym.conjugacy_classes_representatives()]
        return Sym.character(values)
예제 #45
0
def HighestWeightCrystal(dominant_weight, model=None):
    r"""
    Return the highest weight crystal of highest weight ``dominant_weight``
    of the given ``model``.

    INPUT:

    - ``dominant_weight`` -- a dominant weight
    - ``model`` -- (optional) if not specified, then we have the following
      default models:

      * types `A_n, B_n, C_n, D_n, G_2` - :class:`tableaux
        <sage.combinat.crystals.tensor_product.CrystalOfTableaux>`
      * types `E_{6,7}` - :class:`type E finite dimensional crystal
        <FiniteDimensionalHighestWeightCrystal_TypeE>`
      * all other types - :class:`LS paths
        <sage.combinat.crystals.littelmann_path.CrystalOfLSPaths>`

      otherwise can be one of the following:

      * ``'Tableaux'`` - :class:`KN tableaux
        <sage.combinat.crystals.tensor_product.CrystalOfTableaux>`
      * ``'TypeE'`` - :class:`type E finite dimensional crystal
        <FiniteDimensionalHighestWeightCrystal_TypeE>`
      * ``'NakajimaMonomials'`` - :class:`Nakajima monomials
        <sage.combinat.crystals.monomial_crystals.CrystalOfNakajimaMonomials>`
      * ``'LSPaths'`` - :class:`LS paths
        <sage.combinat.crystals.littelmann_path.CrystalOfLSPaths>`
      * ``'AlcovePaths'`` - :class:`alcove paths
        <sage.combinat.crystals.alcove_path.CrystalOfAlcovePaths>`
      * ``'GeneralizedYoungWalls'`` - :class:`generalized Young walls
        <sage.combinat.crystals.generalized_young_walls.CrystalOfGeneralizedYoungWalls>`
      * ``'RiggedConfigurations'`` - :class:`rigged configurations
        <sage.combinat.rigged_configurations.rc_crystal.CrystalOfRiggedConfigurations>`

    EXAMPLES::

        sage: La = RootSystem(['A',2]).weight_lattice().fundamental_weights()
        sage: wt = La[1] + La[2]
        sage: crystals.HighestWeight(wt)
        The crystal of tableaux of type ['A', 2] and shape(s) [[2, 1]]

        sage: La = RootSystem(['C',2]).weight_lattice().fundamental_weights()
        sage: wt = 5*La[1] + La[2]
        sage: crystals.HighestWeight(wt)
        The crystal of tableaux of type ['C', 2] and shape(s) [[6, 1]]

    Some type `E` examples::

        sage: C = CartanType(['E',6])
        sage: La = C.root_system().weight_lattice().fundamental_weights()
        sage: T = crystals.HighestWeight(La[1])
        sage: T.cardinality()
        27
        sage: T = crystals.HighestWeight(La[6])
        sage: T.cardinality()
        27
        sage: T = crystals.HighestWeight(La[2])
        sage: T.cardinality()
        78
        sage: T = crystals.HighestWeight(La[4])
        sage: T.cardinality()
        2925
        sage: T = crystals.HighestWeight(La[3])
        sage: T.cardinality()
        351
        sage: T = crystals.HighestWeight(La[5])
        sage: T.cardinality()
        351

        sage: C = CartanType(['E',7])
        sage: La = C.root_system().weight_lattice().fundamental_weights()
        sage: T = crystals.HighestWeight(La[1])
        sage: T.cardinality()
        133
        sage: T = crystals.HighestWeight(La[2])
        sage: T.cardinality()
        912
        sage: T = crystals.HighestWeight(La[3])
        sage: T.cardinality()
        8645
        sage: T = crystals.HighestWeight(La[4])
        sage: T.cardinality()
        365750
        sage: T = crystals.HighestWeight(La[5])
        sage: T.cardinality()
        27664
        sage: T = crystals.HighestWeight(La[6])
        sage: T.cardinality()
        1539
        sage: T = crystals.HighestWeight(La[7])
        sage: T.cardinality()
        56

    An example with an affine type::

        sage: C = CartanType(['C',2,1])
        sage: La = C.root_system().weight_lattice().fundamental_weights()
        sage: T = crystals.HighestWeight(La[1])
        sage: sorted(T.subcrystal(max_depth=3), key=str)
        [(-Lambda[0] + 3*Lambda[1] - Lambda[2] - delta,),
         (-Lambda[0] + Lambda[1] + Lambda[2] - delta,),
         (-Lambda[1] + 2*Lambda[2] - delta,),
         (2*Lambda[0] - Lambda[1],),
         (Lambda[0] + Lambda[1] - Lambda[2],),
         (Lambda[0] - Lambda[1] + Lambda[2],),
         (Lambda[1],)]

    Using the various models::

        sage: La = RootSystem(['F',4]).weight_lattice().fundamental_weights()
        sage: wt = La[1] + La[4]
        sage: crystals.HighestWeight(wt)
        The crystal of LS paths of type ['F', 4] and weight Lambda[1] + Lambda[4]
        sage: crystals.HighestWeight(wt, model='NakajimaMonomials')
        Highest weight crystal of modified Nakajima monomials of
         Cartan type ['F', 4] and highest weight Lambda[1] + Lambda[4]
        sage: crystals.HighestWeight(wt, model='AlcovePaths')
        Highest weight crystal of alcove paths of type ['F', 4] and weight Lambda[1] + Lambda[4]
        sage: crystals.HighestWeight(wt, model='RiggedConfigurations')
        Crystal of rigged configurations of type ['F', 4] and weight Lambda[1] + Lambda[4]
    """
    cartan_type = dominant_weight.parent().cartan_type()
    if model is None:
        if cartan_type.is_finite():
            if cartan_type.type() == 'E':
                model = 'TypeE'
            elif cartan_type.type() in ['A','B','C','D','G']:
                model = 'Tableaux'
            else:
                model = 'LSPaths'
        else:
            model = 'LSPaths'

    if model == 'Tableaux':
        sh = sum([[i]*c for i,c in dominant_weight], [])
        sh = Partition(reversed(sh))
        return CrystalOfTableaux(cartan_type, shape=sh.conjugate())

    if model == 'TypeE':
        if not cartan_type.is_finite() or cartan_type.type() != 'E':
            raise ValueError("only for finite type E")
        if cartan_type.rank() == 6:
            return FiniteDimensionalHighestWeightCrystal_TypeE6(dominant_weight)
        elif cartan_type.rank() == 7:
            return FiniteDimensionalHighestWeightCrystal_TypeE7(dominant_weight)
        raise NotImplementedError

    if model == 'NakajimaMonomials':
        # Make sure it's in the weight lattice
        P = dominant_weight.parent().root_system.weight_lattice()
        wt = P.sum_of_terms((i, c) for i,c in dominant_weight)
        return CrystalOfNakajimaMonomials(cartan_type, wt)

    if model == 'LSPaths':
        # Make sure it's in the (extended) weight space
        if cartan_type.is_affine():
            P = dominant_weight.parent().root_system.weight_space(extended=True)
        else:
            P = dominant_weight.parent().root_system.weight_space()
        wt = P.sum_of_terms((i, c) for i,c in dominant_weight)
        return CrystalOfLSPaths(wt)

    if model == 'AlcovePaths':
        # Make sure it's in the weight space
        P = dominant_weight.parent().root_system.weight_space()
        wt = P.sum_of_terms((i, c) for i,c in dominant_weight)
        return CrystalOfAlcovePaths(wt, highest_weight_crystal=True)

    if model == 'GeneralizedYoungWalls':
        if not cartan_type.is_affine():
            raise ValueError("only for affine types")
        if cartan_type.type() != 'A':
            raise NotImplementedError("only for affine type A")
        # Make sure it's in the weight lattice
        P = dominant_weight.parent().root_system.weight_space()
        wt = P.sum_of_terms((i, c) for i,c in dominant_weight)
        return CrystalOfGeneralizedYoungWalls(cartan_type.rank(), wt)

    if model == 'RiggedConfigurations':
        # Make sure it's in the weight lattice
        P = dominant_weight.parent().root_system.weight_lattice()
        wt = P.sum_of_terms((i, c) for i,c in dominant_weight)
        return CrystalOfRiggedConfigurations(cartan_type, wt)

    raise ValueError("invalid model")
예제 #46
0
def insertion_tableau(skp, perm, evaluation, tableau, length):
    """
    INPUT:

    -  ``skp`` -- skew partitions

    -  ``perm, evaluation`` -- non-negative integers

    -  ``tableau`` -- skew tableau

    -  ``length`` -- integer

    TESTS::

        sage: from sage.combinat.ribbon_tableau import insertion_tableau
        sage: insertion_tableau([[1], []], [1], 1, [[], []], 1)
        [[], [[1]]]
        sage: insertion_tableau([[2, 1], []], [1, 1], 2, [[], [[1]]], 1)
        [[], [[2], [1, 2]]]
        sage: insertion_tableau([[2, 1], []], [0, 0], 3, [[], [[2], [1, 2]]], 1)
        [[], [[2], [1, 2]]]
        sage: insertion_tableau([[1, 1], []], [1], 2, [[], [[1]]], 1)
        [[], [[2], [1]]]
        sage: insertion_tableau([[2], []], [0, 1], 2, [[], [[1]]], 1)
        [[], [[1, 2]]]
        sage: insertion_tableau([[2, 1], []], [0, 1], 3, [[], [[2], [1]]], 1)
        [[], [[2], [1, 3]]]
        sage: insertion_tableau([[1, 1], []], [2], 1, [[], []], 2)
        [[], [[1], [0]]]
        sage: insertion_tableau([[2], []], [2, 0], 1, [[], []], 2)
        [[], [[1, 0]]]
        sage: insertion_tableau([[2, 2], []], [0, 2], 2, [[], [[1], [0]]], 2)
        [[], [[1, 2], [0, 0]]]
        sage: insertion_tableau([[2, 2], []], [2, 0], 2, [[], [[1, 0]]], 2)
        [[], [[2, 0], [1, 0]]]
        sage: insertion_tableau([[2, 2], [1]], [3, 0], 1, [[], []], 3)
        [[1], [[1, 0], [0]]]
    """
    psave = Partition(skp[1])
    partc = skp[1] + [0]*(len(skp[0])-len(skp[1]))

    tableau = SkewTableau(expr=tableau).to_expr()[1]

    for k in range(len(tableau)):
        tableau[-(k+1)] += [0]* ( skp[0][k] - partc[k] - len(tableau[-(k+1)]))

    ## We construct a tableau from the southwest corner to the northeast one
    tableau = [[0] * (skp[0][k] - partc[k])
               for k in reversed(range(len(tableau), len(skp[0])))] + tableau

    tableau = SkewTableaux().from_expr([skp[1], tableau]).conjugate()
    tableau = tableau.to_expr()[1]

    skp = SkewPartition(skp).conjugate().to_list()
    skp[1].extend( [0]*(len(skp[0])-len(skp[1])) )

    if len(perm) > len(skp[0]):
        return None

    for k in range(len(perm)):
        if perm[ -(k+1) ] !=0:
            tableau[len(tableau)-len(perm)+k][ skp[0][len(perm)-(k+1)] - skp[1][ len(perm)-(k+1) ] - 1 ] = evaluation

    return SkewTableau(expr=[psave.conjugate(),tableau]).conjugate().to_expr()
def _delta_irr_rec(p, marking):
    r"""
    Internal recursive function called by :func:`delta_irr`.
    """
    if len(p) == 0:
        return 0

    if marking[0] == 1:
        m = marking[1]
        a = marking[2]
        i = p.index(m)
        pp = Partition(p._list[:i]+p._list[i+1:]) # the partition p'

        N = (-1)**a* delta_std(
                pp._list + [m+2],
                (1,m+2,m-a))

        for m1 in xrange(1,m-1,2):
            m2 = m-m1-1
            for a1 in xrange(max(0,a-m2),min(a,m1)):
                a2 = a - a1 - 1
                for p1,p2 in bidecompositions(pp):
                    l1 = sorted([m1]+p1._list,reverse=True)
                    l2 = sorted([m2+2]+p2._list,reverse=True)
                    N += (-1)**a2*(_delta_irr_rec(Partition(l1),(1,m1,a1)) *
                        spin_difference_for_standard_permutations(Partition(l2),(1,m2+2,m2-a2)))
        return N

    elif marking[0] == 2:
        m1 = marking[1]
        m2 = marking[2]
        i1 = p.index(m1)
        i2 = p.index(m2)
        if m1 == m2: i2 += 1
        if i2 < i1: i1,i2 = i2,i1
        pp = Partition(p._list[:i1] + p._list[i1+1:i2] + p._list[i2+1:])

        N = d(Partition(sorted(pp._list+[m1+m2+1],reverse=True))) /  pp.centralizer_size()
        # nb of standard permutations that corrresponds to extension of good
        # guys

        for p1,p2 in bidecompositions(Partition(pp)):
            for k1 in xrange(1,m1,2): # remove (k1|.) (k2 o m_2)
                k2 = m1-k1-1
                q1 = Partition(sorted(p1._list+[k1],reverse=True))
                q2 = Partition(sorted(p2._list+[k2+m2+1],reverse=True))
                for a in xrange(k1): # a is a angle
                    N += _delta_irr_rec(q1, (1,k1,a)) * d(q2) / p2.centralizer_size()

            for k1 in xrange(1,m2,2): # remove (m_1 o k1) (k2|.)
                k2 = m2-k1-1
                l1 = sorted(p1._list+[m1,k1],reverse=True)
                l2 = sorted(p2._list+[k2+2],reverse=True)
                for a in xrange(1,k2+1): # a is an angle for standard perm
                    N += (_delta_irr_rec(Partition(l1), (2,m1,k1)) *
                        spin_difference_for_standard_permutations(Partition(l2), (1,k2+2,a)))

        for m in pp.to_exp_dict(): # remove (m_1 o k_1) (k_2 o m_2) for k1+k2+1 an other zero
            q = pp._list[:]
            del q[q.index(m)]
            for p1,p2 in bidecompositions(Partition(q)):
                for k1 in xrange(1,m,2):
                    k2 = m-k1-1
                    q1 = Partition(sorted(p1._list+[m1,k1],reverse=True))
                    q2 = Partition(sorted(p2._list+[k2+m2+1],reverse=True))
                    N += _delta_irr_rec(q1, (2,m1,k1)) * d(q2) / p2.centralizer_size()

        return N
def _gamma_irr_rec(p, marking):
    r"""
    Internal recursive function called by :func:`gamma_irr`
    """
    if len(p) == 0:
        return 1

    if marking[0] == 1:
        m = marking[1]
        a = marking[2]
        i = p.index(m)
        pp = Partition(p._list[:i]+p._list[i+1:]) # the partition p'

        N = gamma_std(pp._list + [m+2],(1,m+2,m-a))

        for m1 in xrange(1,m-1):
            m2 = m-m1-1
            for a1 in xrange(max(0,a-m2),min(a,m1)):
                a2 = a - a1 - 1
                for p1,p2 in bidecompositions(pp):
                    l1 = sorted([m1]+p1._list,reverse=True)
                    l2 = sorted([m2+2]+p2._list,reverse=True)
                    if (sum(l1)+len(l1)) % 2 == 0 and (sum(l2)+len(l2)) % 2 == 0:
                        N -= (_gamma_irr_rec(Partition(l1), (1,m1,a1)) *
                              gamma_std(Partition(l2),(1,m2+2,m2-a2)))
        return N


    elif marking[0] == 2:
        m1 = marking[1]
        m2 = marking[2]
        i1 = p.index(m1)
        i2 = p.index(m2)
        if m1 == m2: i2 += 1
        if i2 < i1: i1,i2 = i2,i1
        pp = Partition(p._list[:i1] + p._list[i1+1:i2] + p._list[i2+1:])

        N = gamma_std(pp._list + [m1+1,m2+1],(2,m1+1,m2+1))

        for p1,p2 in bidecompositions(pp):
            for k1 in xrange(1,m1): # remove (m'_1|.) (m''_1 o m_2)
                k2 = m1-k1-1
                l1 = sorted(p1._list+[k1],reverse=True)
                l2 = sorted(p2._list+[k2+1,m2+1],reverse=True)
                if (sum(l1)+len(l1)) %2 == 0 and (sum(l2)+len(l2)) %2 == 0:
                    for a in xrange(k1): # a is an angle
                        N -= (_gamma_irr_rec(Partition(l1), (1,k1,a))*
                              gamma_std(Partition(l2),(2,k2+1,m2+1)))

            for k1 in xrange(1,m2): # remove (m_1 o m'_2) (m''_2|.)
                k2 = m2-k1-1
                l1 = sorted(p1._list+[m1,k1],reverse=True)
                l2 = sorted(p2._list+[k2+2],reverse=True)
                if (sum(l1)+len(l1)) %2 == 0 and (sum(l2)+len(l2)) %2 == 0:
                    for a in xrange(1,k2+1): # a is an angle for standard perm
                        N -= (_gamma_irr_rec(Partition(l1), (2,m1,k1)) *
                              gamma_std(Partition(l2),(1,k2+2,a)))

        for m in pp.to_exp_dict(): # remove (m_1, k_1) (k_2, m_2) for k1+k2+1 an other zero
            q = pp._list[:]
            del q[q.index(m)]
            for p1,p2 in bidecompositions(Partition(q)):
                for k1 in xrange(1,m):
                    k2 = m-k1-1
                    l1 = sorted(p1._list+[m1,k1],reverse=True)
                    l2 = sorted(p2._list+[k2+1,m2+1],reverse=True)
                    if (sum(l1)+len(l1))%2 == 0 and (sum(l2)+len(l2))%2 == 0:
                        N -= (_gamma_irr_rec(Partition(l1), (2,m1,k1)) *
                              gamma_std(Partition(l2),(2,k2+1,m2+1)))

        return N

    else:
        raise ValueError, "marking must be a 3-tuple of the form (1,m,a) or (2,m1,m2)"
예제 #49
0
def is_gale_ryser(r,s):
    r"""
    Tests whether the given sequences satisfy the condition
    of the Gale-Ryser theorem.

    Given a binary matrix `B` of dimension `n\times m`, the
    vector of row sums is defined as the vector whose
    `i^{\mbox{th}}` component is equal to the sum of the `i^{\mbox{th}}`
    row in `A`. The vector of column sums is defined similarly.

    If, given a binary matrix, these two vectors are easy to compute,
    the Gale-Ryser theorem lets us decide whether, given two
    non-negative vectors `r,s`, there exists a binary matrix
    whose row/colum sums vectors are `r` and `s`.

    This functions answers accordingly.

    INPUT:

    - ``r``, ``s`` -- lists of non-negative integers.

    ALGORITHM:

    Without loss of generality, we can assume that:

    - The two given sequences do not contain any `0` ( which would
      correspond to an empty column/row )

    - The two given sequences are ordered in decreasing order
      (reordering the sequence of row (resp. column) sums amounts to
      reordering the rows (resp. columns) themselves in the matrix,
      which does not alter the columns (resp. rows) sums.

    We can then assume that `r` and `s` are partitions
    (see the corresponding class ``Partition``)

    If `r^*` denote the conjugate of `r`, the Gale-Ryser theorem
    asserts that a binary Matrix satisfying the constraints exists
    if and only if `s\preceq r^*`, where `\preceq` denotes
    the domination order on partitions.

    EXAMPLES::

        sage: from sage.combinat.integer_vector import is_gale_ryser
        sage: is_gale_ryser([4,2,2],[3,3,1,1])
        True
        sage: is_gale_ryser([4,2,1,1],[3,3,1,1])
        True
        sage: is_gale_ryser([3,2,1,1],[3,3,1,1])
        False

    REMARK: In the literature, what we are calling a
    Gale-Ryser sequence sometimes goes by the (rather
    generic-sounding) term ''realizable sequence''.
    """

    # The sequences only contan non-negative integers
    if [x for x in r if x<0] or [x for x in s if x<0]:
        return False

    # builds the corresponding partitions, i.e.
    # removes the 0 and sorts the sequences
    from sage.combinat.partition import Partition
    r2 = Partition(sorted([x for x in r if x>0], reverse=True))
    s2 = Partition(sorted([x for x in s if x>0], reverse=True))

    # If the two sequences only contained zeroes
    if len(r2) == 0 and len(s2) == 0:
        return True

    rstar = Partition(r2).conjugate()

    #                                same number of 1s           domination
    return len(rstar) <= len(s2) and  sum(r2) == sum(s2) and rstar.dominates(s)