Пример #1
0
    def __classcall_private__(cls, cartan_type, P=None):
        r"""
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: C = crystals.elementary.Component("A2")
            sage: D = crystals.elementary.Component(CartanType(['A',2]))
            sage: C is D
            True
            sage: AS = RootSystem(['A',2]).ambient_space()
            sage: E = crystals.elementary.Component(AS)
            sage: F = crystals.elementary.Component(CartanType(['A',2]), AS)
            sage: C is E and C is F
            True
        """
        if cartan_type in RootLatticeRealizations:
            P = cartan_type
            cartan_type = P.cartan_type()
        elif P is None:
            cartan_type = CartanType(cartan_type)
            P = cartan_type.root_system().ambient_space()
            if P is None:
                P = cartan_type.root_system().weight_lattice()
        return super(ComponentCrystal, cls).__classcall__(cls, cartan_type, P)
    def _element_constructor_(self, cartan_type, **kwds):
        """
        The element constructor.

        This method is called internally when we try to convert
        something into an element. In this case, the only thing that
        can be converted into an associahedron is the Cartan type.

        EXAMPLES::

            sage: from sage.combinat.root_system.associahedron import Associahedra
            sage: parent = Associahedra(QQ,2)
            sage: parent(['A',2])
            Generalized associahedron of type ['A', 2] with 5 vertices
            sage: parent._element_constructor_(['A',2])
            Generalized associahedron of type ['A', 2] with 5 vertices
        """
        cartan_type = CartanType(cartan_type)
        assert cartan_type.is_finite()
        root_space = cartan_type.root_system().root_space()
        # TODO: generalize this as a method of root lattice realization
        rhocheck = sum(beta.associated_coroot()
                       for beta in root_space.positive_roots()) / 2
        I = root_space.index_set()
        inequalities = []
        for orbit in root_space.almost_positive_roots_decomposition():
            c = rhocheck.coefficient(orbit[0].leading_support())
            for beta in orbit:
                inequalities.append([c] + [beta.coefficient(i) for i in I])
        associahedron = super(Associahedra, self)._element_constructor_(
            None, [inequalities, []])
        associahedron._cartan_type = cartan_type
        return associahedron
Пример #3
0
    def __classcall_private__(cls, cartan_type, wt=None):
        r"""
        Normalize the input arguments to ensure unique representation.

        EXAMPLES::

            sage: La = RootSystem(['A', 2]).weight_lattice().fundamental_weights()
            sage: RC = crystals.RiggedConfigurations(La[1])
            sage: RC2 = crystals.RiggedConfigurations(['A', 2], La[1])
            sage: RC is RC2
            True
        """
        if wt is None:
            wt = cartan_type
            cartan_type = wt.parent().cartan_type()
        else:
            cartan_type = CartanType(cartan_type)
            wt_lattice = cartan_type.root_system().weight_lattice()
            wt = wt_lattice(wt)

        if not cartan_type.is_simply_laced():
            vct = cartan_type.as_folding()
            return CrystalOfNonSimplyLacedRC(vct, wt)

        return super(CrystalOfRiggedConfigurations, cls).__classcall__(cls, wt)
Пример #4
0
    def _element_constructor_(self, cartan_type, **kwds):
        """
        The element constructor.

        This method is called internally when we try to convert
        something into an element. In this case, the only thing that
        can be converted into an associahedron is the Cartan type.

        EXAMPLES::

            sage: from sage.combinat.root_system.associahedron import Associahedra
            sage: parent = Associahedra(QQ,2)
            sage: parent(['A',2])
            Generalized associahedron of type ['A', 2] with 5 vertices
            sage: parent._element_constructor_(['A',2])
            Generalized associahedron of type ['A', 2] with 5 vertices
        """
        cartan_type = CartanType(cartan_type)
        if not cartan_type.is_finite():
            raise ValueError("the Cartan type must be finite")
        root_space = cartan_type.root_system().root_space()
        # TODO: generalize this as a method of root lattice realization
        rhocheck = sum(beta.associated_coroot()
                       for beta in root_space.positive_roots()) / 2
        I = root_space.index_set()
        inequalities = []
        for orbit in root_space.almost_positive_roots_decomposition():
            c = rhocheck.coefficient(orbit[0].leading_support())
            for beta in orbit:
                inequalities.append([c] + [beta.coefficient(i) for i in I])
        associahedron = super(Associahedra, self)._element_constructor_(None, [inequalities, []])
        associahedron._cartan_type = cartan_type
        return associahedron
Пример #5
0
    def __classcall_private__(cls, cartan_type, P=None):
        r"""
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: C = crystals.elementary.Component("A2")
            sage: D = crystals.elementary.Component(CartanType(['A',2]))
            sage: C is D
            True
            sage: AS = RootSystem(['A',2]).ambient_space()
            sage: E = crystals.elementary.Component(AS)
            sage: F = crystals.elementary.Component(CartanType(['A',2]), AS)
            sage: C is E and C is F
            True
        """
        if cartan_type in RootLatticeRealizations:
            P = cartan_type
        elif P is None:
            cartan_type = CartanType(cartan_type)
            P = cartan_type.root_system().ambient_space()
            if P is None:
                P = cartan_type.root_system().weight_lattice()
        return super(ComponentCrystal, cls).__classcall__(cls, P)
Пример #6
0
class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation):
    r"""
    The type `A_n^{(1)}` crystal `B(\infty)` realized using
    Bernstein-Zelevinsky (BZ) multisegments.

    Using (a modified version of the) notation from [JL2009]_, for `\ell \in
    \ZZ_{>0}` and `i \in \ZZ / (n+1)\ZZ`, a segment of length `\ell` and head
    `i` is the sequence of consecutive residues `[i,i+1,\dots,i+\ell-1]`.  The
    notation  for a segment of length `\ell` and head `i` is simplified to
    `[i; \ell)`.  Similarly, a segment of length `\ell` and tail `i` is the
    sequence of consecutive residues `[i-\ell+1, \ldots, i-1, i]`.  The latter
    is denoted simply by `(\ell;i]`.  Finally, a multisegment is a formal
    linear combination of segments, usually written in the form

    .. MATH::

        \psi =
        \sum_{\substack{i \in \ZZ/(n+1)\ZZ \\ \ell \in \ZZ_{>0}}}
        m_{(\ell;i]} (\ell; i].

    Such a multisegment is called aperiodic if, for every `\ell > 0`, there
    exists some `i \in \ZZ / (n+1)\ZZ` such that `(\ell; i]` does not appear
    in `\psi`. Denote the set of all periodic multisegments, together with
    the empty multisegment `\varnothing`, by `\Psi`.  We define a crystal
    structure on multisegments as follows.  Set `S_{\ell,i} = \sum_{k \ge \ell}
    (m_{(k;i-1]} - m_{(k;i]})` and let `\ell_f` be the minimal `\ell` that
    attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have

    .. MATH::

        f_i \psi =
        \begin{cases}
         \psi + (1;i] & \text{ if } \ell_f = 1,\\
         \psi + (\ell_f;i] - (\ell_f-1;i-1] & \text{ if } \ell_f > 1.
        \end{cases}

    Similarly, let `\ell_e` be the maximal `\ell` that attains the value
    `\min_{\ell > 0} S_{\ell,i}`.  Then we have

    .. MATH::

        e_i \psi =
        \begin{cases}
         0 & \text{ if } \min_{\ell > 0} S_{\ell,i} = 0, \\
         \psi + (1; i] & \text{ if } \ell_e = 1,\\
         \psi - (\ell_e; i] + (\ell_e-1; i-1] & \text{ if } \ell_e > 1.
        \end{cases}

    Alternatively, the crystal operators may be defined using a signature
    rule, as detailed in Section 4 of [JL2009]_ (following [AJL2011]_).  For
    `\psi \in \Psi` and `i \in \ZZ/(n+1)\ZZ`, encode all segments in `\psi`
    with tail `i` by the symbol `R` and all segments in `\psi` with tail
    `i-1` by `A`.  For `\ell > 0`, set
    `w_{i,\ell} = R^{m_{(\ell;i]}} A^{m_{(\ell;i-1]}}` and
    `w_i = \prod_{\ell\ge 1} w_{i,\ell}`.  By successively canceling out
    as many `RA` factors as possible, set
    `\widetilde{w}_i = A^{a_i(\psi)} R^{r_i(\psi)}`.  If `a_i(\psi) > 0`,
    denote by `\ell_f > 0` the length of the rightmost segment `A` in
    `\widetilde{w}_i`.  If `a_i(\psi) = 0`, set `\ell_f = 0`.  Then

    .. MATH::

        f_i \psi =
        \begin{cases}
         \psi + (1; i] & \text{ if } a_i(\psi) = 0,\\
         \psi + (\ell_f; i] - (\ell_f-1; i-1] & \text{ if } a_i(\psi) > 0.
        \end{cases}

    The rule for computing `e_i \psi` is similar.

    INPUT:

    - ``n`` -- for type `A_n^{(1)}`

    EXAMPLES::

        sage: B = crystals.infinity.Multisegments(2)
        sage: x = B([(8,1),(6,0),(5,1),(5,0),(4,0),(4,1),(4,1),(3,0),(3,0),(3,1),(3,1),(1,0),(1,2),(1,2)]); x
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2]
        sage: x.f(1)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + 2 * (1; 2]
        sage: x.f(1).f(1)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + (1; 1] + 2 * (1; 2]
        sage: x.e(1)
        (7; 0] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2]
        sage: x.e(1).e(1)
        sage: x.f(0)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 0] + (1; 0] + (1; 2]

    We check an `\widehat{\mathfrak{sl}}_2` example against the generalized
    Young walls::

        sage: B = crystals.infinity.Multisegments(1)
        sage: G = B.subcrystal(max_depth=4).digraph()
        sage: C = crystals.infinity.GeneralizedYoungWalls(1)
        sage: GC = C.subcrystal(max_depth=4).digraph()
        sage: G.is_isomorphic(GC, edge_labels=True)
        True

    REFERENCES:

    - [AJL2011]_
    - [JL2009]_
    - [LTV1999]_
    """
    def __init__(self, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: TestSuite(B).run()
        """
        self._cartan_type = CartanType(['A', n, 1])
        self._Zn = IntegerModRing(n + 1)
        Parent.__init__(self,
                        category=(HighestWeightCrystals(),
                                  InfiniteEnumeratedSets()))
        self.module_generators = (self.highest_weight_vector(), )

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: crystals.infinity.Multisegments(2)
            Infinity crystal of multisegments of type ['A', 2, 1]
        """
        return "Infinity crystal of multisegments of type {}".format(
            self._cartan_type)

    @cached_method
    def highest_weight_vector(self):
        """
        Return the highest weight vector of ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: B.highest_weight_vector()
            0
        """
        return self.element_class(self, ())

    def weight_lattice_realization(self):
        """
        Return a realization of the weight lattice of ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: B.weight_lattice_realization()
            Extended weight lattice of the Root system of type ['A', 2, 1]
        """
        return self._cartan_type.root_system().weight_lattice(extended=True)

    class Element(ElementWrapper):
        """
        An element in a BZ multisegments crystal.
        """
        def __init__(self, parent, value):
            """
            Initialize ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: mg = B.highest_weight_vector()
                sage: TestSuite(mg).run()
            """
            def sort_key(x):
                return (-x[0], ZZ(x[1]))

            ZM = parent._Zn
            value = [(k, ZM(i)) for k, i in value]
            ElementWrapper.__init__(self, parent,
                                    tuple(sorted(value, key=sort_key)))

        def _repr_(self):
            r"""
            Return a string representation of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: B.highest_weight_vector()
                0
                sage: B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)])
                (4; 2] + (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1]
            """
            if not self.value:
                return '0'

            def sort_key(mc):
                x = mc[0]
                return (-x[0], ZZ(x[1]))

            def seg(x):
                m, c = x
                if c != 1:
                    return "{} * ({}; {}]".format(c, m[0], m[1])
                return "({}; {}]".format(m[0], m[1])

            d = {}
            for x in self.value:
                d[x] = d.get(x, 0) + 1
            return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key))

        def _latex_(self):
            r"""
            Return a LaTeX representation of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: latex(B.highest_weight_vector())
                0
                sage: latex(B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)]))
                (4; 2] + (3; 0] + 2 (3; 1] + (1; 0] + (1; 1]
            """
            if not self.value:
                return "0"

            def sort_key(mc):
                x = mc[0]
                return (-x[0], ZZ(x[1]))

            def seg(x):
                m, c = x
                if c != 1:
                    return "{} ({}; {}]".format(c, m[0], m[1])
                return "({}; {}]".format(m[0], m[1])

            d = {}
            for x in self.value:
                d[x] = d.get(x, 0) + 1
            return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key))

        def _sig(self, i):
            r"""
            Return an `i`-signature of ``self``.

            INPUT:

            - ``i`` -- an element of the indexing set

            OUTPUT:

            A pair ``(m, p, ep)`` where ``m`` and ``p`` correspond to the
            block length of the unmatched `-` and `+` respectively or ``None``
            if there is no such block and ``ep`` is the number of unmatched
            `-`.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b._sig(0)
                (1, None, 1)
                sage: b._sig(1)
                (None, None, 0)
            """
            if not self.value:
                return (None, None)
            pos = []
            block = self.value[0][0]
            cur = 0
            for k, j in self.value:
                if k != block:
                    if cur != 0:
                        pos.append((block, cur))
                    cur = 0
                    block = k
                if j + 1 == i:  # + or (
                    cur += 1
                elif j == i:  # - or )
                    cur -= 1
            if cur != 0:
                pos.append((block, cur))
            # Now cancel all +- pairs
            cur = 0
            m = None
            p = None
            ep = 0
            for k, c in pos:
                old = cur
                cur += c
                if cur < 0:
                    m = k
                    p = None
                    ep -= cur
                    cur = 0
                elif not cur:
                    p = None
                elif cur > 0 and old <= 0:
                    p = k
            return (m, p, ep)

        def e(self, i):
            r"""
            Return the action of `e_i` on ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.e(0)
                (4; 2] + (3; 0] + (3; 1] + (1; 1]
                sage: b.e(1)
                sage: b.e(2)
                (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1]
            """
            i = self.parent()._Zn(i)
            m = self._sig(i)[0]
            if m is None:
                return None

            M = self.value
            a = M.index((m, i))
            k = M[a][0]
            if k == 1:
                return self.__class__(self.parent(), M[:a] + M[a + 1:])
            return self.__class__(self.parent(),
                                  M[:a] + ((k - 1, i - 1), ) + M[a + 1:])

        def f(self, i):
            r"""
            Return the action of `f_i` on ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.f(0)
                (4; 2] + (3; 0] + (3; 1] + 2 * (1; 0] + (1; 1]
                sage: b.f(1)
                (4; 2] + (3; 0] + (3; 1] + (1; 0] + 2 * (1; 1]
                sage: b.f(2)
                2 * (4; 2] + (3; 0] + (1; 0] + (1; 1]
            """
            i = self.parent()._Zn(i)
            p = self._sig(i)[1]
            M = self.value
            if p is None:
                return self.__class__(self.parent(), ((1, i), ) + M)

            a = M.index((p, i - 1))
            return self.__class__(self.parent(),
                                  M[:a] + ((M[a][0] + 1, i), ) + M[a + 1:])

        def epsilon(self, i):
            r"""
            Return `\varepsilon_i` of ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.epsilon(0)
                1
                sage: b.epsilon(1)
                0
                sage: b.epsilon(2)
                1
            """
            i = self.parent()._Zn(i)
            return self._sig(i)[2]

        def phi(self, i):
            r"""
            Return `\varphi_i` of ``self``.

            Let `\psi \in \Psi`. Define `\varphi_i(\psi) :=
            \varepsilon_i(\psi) + \langle h_i, \mathrm{wt}(\psi) \rangle`,
            where `h_i` is the `i`-th simple coroot and `\mathrm{wt}(\psi)` is the
            :meth:`weight` of `\psi`.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.phi(0)
                1
                sage: b.phi(1)
                0
                sage: mg = B.highest_weight_vector()
                sage: mg.f(1).phi(0)
                1
            """
            h = self.parent().weight_lattice_realization().simple_coroots()
            return self.epsilon(i) + self.weight().scalar(h[i])

        def weight(self):
            """
            Return the weight of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.weight()
                -4*delta
            """
            WLR = self.parent().weight_lattice_realization()
            alpha = WLR.simple_roots()
            n = self.parent()._cartan_type.rank()
            return WLR.sum(-1 * alpha[j % n] for k, i in self.value
                           for j in range(ZZ(i),
                                          ZZ(i) + k))
Пример #7
0
class Associahedron(Polyhedron):
    r"""
    The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence
    with clusters in the cluster complex, and with edges between two vertices if and only if the associated two
    clusters intersect in codimension 1.

    The associahedron of type `A_n` is one way to realize the classical associahedron as defined in

    http://en.wikipedia.org/wiki/Associahedron.

    A polytopal realization of the associahedron can be found in [CFZ].
    The implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary 1.9.].

    EXAMPLES::

        sage: Asso = Associahedron(['A',2]); Asso
        Generalized associahedron of type ['A', 2] with 5 vertices
        sage: sorted(Asso.Hrepresentation(), key=repr)
        [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0]
        sage: Asso.Vrepresentation()
        [A vertex at (-1, 1), A vertex at (1, 1), A vertex at (1, -1), A vertex at (0, -1), A vertex at (-1, 0)]

        sage: Associahedron(['B',2])
        Generalized associahedron of type ['B', 2] with 6 vertices

   The two pictures of [CFZ] can be recovered with::

        sage: Asso = Associahedron(['A',3]); Asso
        Generalized associahedron of type ['A', 3] with 14 vertices
        sage: Asso.plot()

        sage: Asso = Associahedron(['B',3]); Asso
        Generalized associahedron of type ['B', 3] with 20 vertices
        sage: Asso.plot()

    TESTS::

        sage: sorted(Associahedron(['A',3]).vertices())
        [[-3/2, 0, -1/2], [-3/2, 0, 3/2], [-3/2, 1, -3/2], [-3/2, 2, -3/2], [-3/2, 2, 3/2], [-1/2, -1, -1/2], [-1/2, 0, -3/2], [1/2, -2, 1/2], [1/2, -2, 3/2], [3/2, -2, 1/2], [3/2, -2, 3/2], [3/2, 0, -3/2], [3/2, 2, -3/2], [3/2, 2, 3/2]]
        sage: sorted(Associahedron(['B',3]).vertices())
        [[-3, 0, 0], [-3, 0, 3], [-3, 2, -2], [-3, 4, -3], [-3, 5, -3], [-3, 5, 3], [-2, 1, -2], [-2, 3, -3], [-1, -2, 0], [-1, -1, -1], [1, -4, 1], [1, -3, 0], [2, -5, 2], [2, -5, 3], [3, -5, 2], [3, -5, 3], [3, -3, 0], [3, 3, -3], [3, 5, -3], [3, 5, 3]]

        sage: Associahedron(['A',4]).f_vector()
        (1, 42, 84, 56, 14, 1)
        sage: Associahedron(['B',4]).f_vector()
        (1, 70, 140, 90, 20, 1)

    REFERENCES:

    - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, arXiv:0202004.
    """
    def __init__(self, cartan_type):
        """
        TESTS::

            sage: Asso = Associahedron(['A',2]); Asso
            Generalized associahedron of type ['A', 2] with 5 vertices
            sage: TestSuite(Asso).run()

        """
        self._cartan_type = CartanType( cartan_type )
        assert self._cartan_type.is_finite()
        root_space = self._cartan_type.root_system().root_space()
        # TODO: generalize this as a method of root lattice realization
        rhocheck = sum( beta.associated_coroot() for beta in root_space.positive_roots() )/2
        I = root_space.index_set()
        inequalities = []
        for orbit in root_space.almost_positive_roots_decomposition():
            c = rhocheck.coefficient(orbit[0].leading_support())
            for beta in orbit:
                inequalities.append( [c] + [ beta.coefficient(i) for i in I ] )
        Polyhedron.__init__(self,ieqs=inequalities)
        # check that there are non non trivial facets
        assert self.n_facets() == len(inequalities)

    def _repr_(self):
        r"""
        Returns a string representation of self.

        EXAMPLES::

            sage: Associahedron(['A',3])._repr_()
            "Generalized associahedron of type ['A', 3] with 14 vertices"
        """
        return 'Generalized associahedron of type %s with %s vertices'%(self._cartan_type,self.n_vertices())

    def cartan_type(self):
        r"""
        Returns the Cartan type of self.

        EXAMPLES::

            sage: Associahedron(['A',3]).cartan_type()
            ['A', 3]
        """
        return self._cartan_type

    def vertices_in_root_space(self):
        r"""
        Returns the vertices of ``self`` as elements in the root space

        EXAMPLES::

            sage: Asso = Associahedron(['A',2])

            sage: Asso.vertices()
            [[-1, 1], [1, 1], [1, -1], [0, -1], [-1, 0]]

            sage: Asso.vertices_in_root_space()
            [-alpha[1] + alpha[2], alpha[1] + alpha[2], alpha[1] - alpha[2], -alpha[2], -alpha[1]]
        """
        root_space = self._cartan_type.root_system().root_space()
        return [ root_space.from_vector(vector(V)) for V in self.vertex_generator() ]
Пример #8
0
def WeylGroup(x, prefix=None):
    """
    Returns the Weyl group of type ct.

    INPUT:

    - ``ct`` - a Cartan Type.

    OPTIONAL:

    - ``prefix`` - changes the representation of elements from matrices
      to products of simple reflections

    EXAMPLES: The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::

        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()

    or alternatively and equivalently::

        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()

    Either produces a weight lattice, with access to its roots and
    weights.

    ::

        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3, 1])).run()

        sage: W=WeylGroup(['A',3,1])
        sage: s=W.simple_reflections()
        sage: w=s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w=s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
    """
    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    ct = CartanType(x)
    if ct.is_affine():
        return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
    else:
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
Пример #9
0
def WeylGroup(x, prefix=None, implementation='matrix'):
    """
    Returns the Weyl group of the root system defined by the Cartan
    type (or matrix) ``ct``.

    INPUT:

    - ``x`` - a root system or a Cartan type (or matrix)

    OPTIONAL:

    - ``prefix`` -- changes the representation of elements from matrices
      to products of simple reflections

    - ``implementation`` -- one of the following:
      * ``'matrix'`` - as matrices acting on a root system
      * ``"permutation"`` - as a permutation group acting on the roots

    EXAMPLES:

    The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::

        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()

    or alternatively and equivalently::

        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()
        sage: W = WeylGroup(L)

    Either produces a weight lattice, with access to its roots and
    weights.

    ::

        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    We can also do the same for arbitrary Cartan matrices::

        sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]])
        sage: W = WeylGroup(cm)
        sage: W.gens()
        (
        [-1  5  0]  [ 1  0  0]  [ 1  0  0]
        [ 0  1  0]  [ 2 -1  1]  [ 0  1  0]
        [ 0  0  1], [ 0  0  1], [ 0  1 -1]
        )
        sage: s0,s1,s2 = W.gens()
        sage: s1*s2*s1
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s2*s1*s2
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s0*s1*s0*s2*s0
        [ 9  0 -5]
        [ 2  0 -1]
        [ 0  1 -1]

    Same Cartan matrix, but with a prefix to display using simple reflections::

        sage: W = WeylGroup(cm, prefix='s')
        sage: s0,s1,s2 = W.gens()
        sage: s0*s2*s1
        s2*s0*s1
        sage: (s1*s2)^3
        1
        sage: (s0*s1)^5
        s0*s1*s0*s1*s0*s1*s0*s1*s0*s1
        sage: s0*s1*s2*s1*s2
        s2*s0*s1
        sage: s0*s1*s2*s0*s2
        s0*s1*s0

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3,1])).run() # long time

        sage: W = WeylGroup(['A',3,1])
        sage: s = W.simple_reflections()
        sage: w = s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w = s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
        sage: W = groups.misc.WeylGroup(['A',3,1])
    """
    if implementation == "permutation":
        return WeylGroup_permutation(x, prefix)
    elif implementation != "matrix":
        raise ValueError("invalid implementation")

    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    try:
        ct = CartanType(x)
    except TypeError:
        ct = CartanMatrix(x)  # See if it is a Cartan matrix
    if ct.is_finite():
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
    return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
Пример #10
0
def WeylGroup(x, prefix=None, implementation='matrix'):
    """
    Returns the Weyl group of the root system defined by the Cartan
    type (or matrix) ``ct``.

    INPUT:

    - ``x`` - a root system or a Cartan type (or matrix)

    OPTIONAL:

    - ``prefix`` -- changes the representation of elements from matrices
      to products of simple reflections

    - ``implementation`` -- one of the following:
      * ``'matrix'`` - as matrices acting on a root system
      * ``"permutation"`` - as a permutation group acting on the roots

    EXAMPLES:

    The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::

        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()

    or alternatively and equivalently::

        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()
        sage: W = WeylGroup(L)

    Either produces a weight lattice, with access to its roots and
    weights.

    ::

        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    We can also do the same for arbitrary Cartan matrices::

        sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]])
        sage: W = WeylGroup(cm)
        sage: W.gens()
        (
        [-1  5  0]  [ 1  0  0]  [ 1  0  0]
        [ 0  1  0]  [ 2 -1  1]  [ 0  1  0]
        [ 0  0  1], [ 0  0  1], [ 0  1 -1]
        )
        sage: s0,s1,s2 = W.gens()
        sage: s1*s2*s1
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s2*s1*s2
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s0*s1*s0*s2*s0
        [ 9  0 -5]
        [ 2  0 -1]
        [ 0  1 -1]

    Same Cartan matrix, but with a prefix to display using simple reflections::

        sage: W = WeylGroup(cm, prefix='s')
        sage: s0,s1,s2 = W.gens()
        sage: s0*s2*s1
        s2*s0*s1
        sage: (s1*s2)^3
        1
        sage: (s0*s1)^5
        s0*s1*s0*s1*s0*s1*s0*s1*s0*s1
        sage: s0*s1*s2*s1*s2
        s2*s0*s1
        sage: s0*s1*s2*s0*s2
        s0*s1*s0

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3,1])).run() # long time

        sage: W = WeylGroup(['A',3,1])
        sage: s = W.simple_reflections()
        sage: w = s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w = s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
        sage: W = groups.misc.WeylGroup(['A',3,1])
    """
    if implementation == "permutation":
        return WeylGroup_permutation(x, prefix)
    elif implementation != "matrix":
        raise ValueError("invalid implementation")

    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    try:
        ct = CartanType(x)
    except TypeError:
        ct = CartanMatrix(x)  # See if it is a Cartan matrix
    if ct.is_finite():
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
    return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
 def __classcall_private__(cls, cartan_type, La):
     ct = CartanType(cartan_type)
     La = ct.root_system().weight_lattice()(La)
     return super(HighestWeightCrystalOfGYW, cls).__classcall__(cls, ct, La)
Пример #12
0
class Associahedron(Polyhedron_QQ_ppl):
    r"""
    The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence
    with clusters in the cluster complex, and with edges between two vertices if and only if the associated two
    clusters intersect in codimension 1.

    The associahedron of type `A_n` is one way to realize the classical associahedron as defined in

    http://en.wikipedia.org/wiki/Associahedron.

    A polytopal realization of the associahedron can be found in [CFZ].
    The implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary 1.9.].

    EXAMPLES::

        sage: Asso = Associahedron(['A',2]); Asso
        Generalized associahedron of type ['A', 2] with 5 vertices
        sage: sorted(Asso.Hrepresentation(), key=repr)
        [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0]
        sage: Asso.Vrepresentation()
        (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1))

        sage: Associahedron(['B',2])
        Generalized associahedron of type ['B', 2] with 6 vertices

   The two pictures of [CFZ] can be recovered with::

        sage: Asso = Associahedron(['A',3]); Asso
        Generalized associahedron of type ['A', 3] with 14 vertices
        sage: Asso.plot()

        sage: Asso = Associahedron(['B',3]); Asso
        Generalized associahedron of type ['B', 3] with 20 vertices
        sage: Asso.plot()

    TESTS::

        sage: sorted(Associahedron(['A',3]).vertices())
        [[-3/2, 0, -1/2], [-3/2, 0, 3/2], [-3/2, 1, -3/2], [-3/2, 2, -3/2], [-3/2, 2, 3/2], [-1/2, -1, -1/2], [-1/2, 0, -3/2], [1/2, -2, 1/2], [1/2, -2, 3/2], [3/2, -2, 1/2], [3/2, -2, 3/2], [3/2, 0, -3/2], [3/2, 2, -3/2], [3/2, 2, 3/2]]
        sage: sorted(Associahedron(['B',3]).vertices())
        [[-3, 0, 0], [-3, 0, 3], [-3, 2, -2], [-3, 4, -3], [-3, 5, -3], [-3, 5, 3], [-2, 1, -2], [-2, 3, -3], [-1, -2, 0], [-1, -1, -1], [1, -4, 1], [1, -3, 0], [2, -5, 2], [2, -5, 3], [3, -5, 2], [3, -5, 3], [3, -3, 0], [3, 3, -3], [3, 5, -3], [3, 5, 3]]

        sage: Associahedron(['A',4]).f_vector()
        (1, 42, 84, 56, 14, 1)
        sage: Associahedron(['B',4]).f_vector()
        (1, 70, 140, 90, 20, 1)

    REFERENCES:

    - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, arXiv:0202004.
    """
    def __init__(self, cartan_type):
        """
        TESTS::

            sage: Asso = Associahedron(['A',2]); Asso
            Generalized associahedron of type ['A', 2] with 5 vertices
            sage: TestSuite(Asso).run()

        """
        self._cartan_type = CartanType(cartan_type)
        assert self._cartan_type.is_finite()
        root_space = self._cartan_type.root_system().root_space()
        # TODO: generalize this as a method of root lattice realization
        rhocheck = sum(beta.associated_coroot()
                       for beta in root_space.positive_roots()) / 2
        I = root_space.index_set()
        inequalities = []
        for orbit in root_space.almost_positive_roots_decomposition():
            c = rhocheck.coefficient(orbit[0].leading_support())
            for beta in orbit:
                inequalities.append([c] + [beta.coefficient(i) for i in I])
        Polyhedron_QQ_ppl.__init__(self, len(I), None, [inequalities, []])
        # check that there are non non trivial facets
        assert self.n_facets() == len(inequalities)

    def _repr_(self):
        r"""
        Returns a string representation of self.

        EXAMPLES::

            sage: Associahedron(['A',3])._repr_()
            "Generalized associahedron of type ['A', 3] with 14 vertices"
        """
        return 'Generalized associahedron of type %s with %s vertices' % (
            self._cartan_type, self.n_vertices())

    def cartan_type(self):
        r"""
        Returns the Cartan type of self.

        EXAMPLES::

            sage: Associahedron(['A',3]).cartan_type()
            ['A', 3]
        """
        return self._cartan_type

    def vertices_in_root_space(self):
        r"""
        Returns the vertices of ``self`` as elements in the root space

        EXAMPLES::

            sage: Asso = Associahedron(['A',2])
            sage: Asso.vertices()
            [[1, -1], [1, 1], [-1, 1], [-1, 0], [0, -1]]

            sage: Asso.vertices_in_root_space()
            (alpha[1] - alpha[2], alpha[1] + alpha[2], -alpha[1] + alpha[2], -alpha[1], -alpha[2])
        """
        root_space = self._cartan_type.root_system().root_space()
        return tuple(
            root_space.from_vector(vector(V)) for V in self.vertex_generator())
Пример #13
0
class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation):
    r"""
    The type `A_n^{(1)}` crystal `B(\infty)` realized using
    Bernstein-Zelevinsky (BZ) multisegments.

    Using (a modified version of the) notation from [JL2009]_, for `\ell \in
    \ZZ_{>0}` and `i \in \ZZ / (n+1)\ZZ`, a segment of length `\ell` and head
    `i` is the sequence of consecutive residues `[i,i+1,\dots,i+\ell-1]`.  The
    notation  for a segment of length `\ell` and head `i` is simplified to
    `[i; \ell)`.  Similarly, a segment of length `\ell` and tail `i` is the
    sequence of consecutive residues `[i-\ell+1, \ldots, i-1, i]`.  The latter
    is denoted simply by `(\ell;i]`.  Finally, a multisegment is a formal
    linear combination of segments, usually written in the form

    .. MATH::

        \psi =
        \sum_{\substack{i \in \ZZ/(n+1)\ZZ \\ \ell \in \ZZ_{>0}}}
        m_{(\ell;i]} (\ell; i].

    Such a multisegment is called aperiodic if, for every `\ell > 0`, there
    exists some `i \in \ZZ / (n+1)\ZZ` such that `(\ell; i]` does not appear
    in `\psi`. Denote the set of all periodic multisegments, together with
    the empty multisegment `\varnothing`, by `\Psi`.  We define a crystal
    structure on multisegments as follows.  Set `S_{\ell,i} = \sum_{k \ge \ell}
    (m_{(k;i-1]} - m_{(k;i]})` and let `\ell_f` be the minimal `\ell` that
    attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have

    .. MATH::

        f_i \psi =
        \begin{cases}
         \psi + (1;i] & \text{ if } \ell_f = 1,\\
         \psi + (\ell_f;i] - (\ell_f-1;i-1] & \text{ if } \ell_f > 1.
        \end{cases}

    Similarly, let `\ell_e` be the maximal `\ell` that attains the value
    `\min_{\ell > 0} S_{\ell,i}`.  Then we have

    .. MATH::

        e_i \psi =
        \begin{cases}
         0 & \text{ if } \min_{\ell > 0} S_{\ell,i} = 0, \\
         \psi + (1; i] & \text{ if } \ell_e = 1,\\
         \psi - (\ell_e; i] + (\ell_e-1; i-1] & \text{ if } \ell_e > 1.
        \end{cases}

    Alternatively, the crystal operators may be defined using a signature
    rule, as detailed in Section 4 of [JL2009]_ (following [AJL2011]_).  For
    `\psi \in \Psi` and `i \in \ZZ/(n+1)\ZZ`, encode all segments in `\psi`
    with tail `i` by the symbol `R` and all segments in `\psi` with tail
    `i-1` by `A`.  For `\ell > 0`, set
    `w_{i,\ell} = R^{m_{(\ell;i]}} A^{m_{(\ell;i-1]}}` and
    `w_i = \prod_{\ell\ge 1} w_{i,\ell}`.  By successively canceling out
    as many `RA` factors as possible, set
    `\widetilde{w}_i = A^{a_i(\psi)} R^{r_i(\psi)}`.  If `a_i(\psi) > 0`,
    denote by `\ell_f > 0` the length of the rightmost segment `A` in
    `\widetilde{w}_i`.  If `a_i(\psi) = 0`, set `\ell_f = 0`.  Then

    .. MATH::

        f_i \psi =
        \begin{cases}
         \psi + (1; i] & \text{ if } a_i(\psi) = 0,\\
         \psi + (\ell_f; i] - (\ell_f-1; i-1] & \text{ if } a_i(\psi) > 0.
        \end{cases}

    The rule for computing `e_i \psi` is similar.

    INPUT:

    - ``n`` -- for type `A_n^{(1)}`

    EXAMPLES::

        sage: B = crystals.infinity.Multisegments(2)
        sage: x = B([(8,1),(6,0),(5,1),(5,0),(4,0),(4,1),(4,1),(3,0),(3,0),(3,1),(3,1),(1,0),(1,2),(1,2)]); x
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2]
        sage: x.f(1)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + 2 * (1; 2]
        sage: x.f(1).f(1)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + (1; 1] + 2 * (1; 2]
        sage: x.e(1)
        (7; 0] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2]
        sage: x.e(1).e(1)
        sage: x.f(0)
        (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1]
         + 2 * (3; 0] + 2 * (3; 1] + (2; 0] + (1; 0] + (1; 2]

    We check an `\widehat{\mathfrak{sl}}_2` example against the generalized
    Young walls::

        sage: B = crystals.infinity.Multisegments(1)
        sage: G = B.subcrystal(max_depth=4).digraph()
        sage: C = crystals.infinity.GeneralizedYoungWalls(1)
        sage: GC = C.subcrystal(max_depth=4).digraph()
        sage: G.is_isomorphic(GC, edge_labels=True)
        True

    REFERENCES:

    - [AJL2011]_
    - [JL2009]_
    - [LTV1999]_
    """
    def __init__(self, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: TestSuite(B).run()
        """
        self._cartan_type = CartanType(['A', n, 1])
        self._Zn = IntegerModRing(n+1)
        Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets()))
        self.module_generators = (self.highest_weight_vector(),)

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: crystals.infinity.Multisegments(2)
            Infinity crystal of multisegments of type ['A', 2, 1]
        """
        return "Infinity crystal of multisegments of type {}".format(self._cartan_type)

    @cached_method
    def highest_weight_vector(self):
        """
        Return the highest weight vector of ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: B.highest_weight_vector()
            0
        """
        return self.element_class(self, ())

    def weight_lattice_realization(self):
        """
        Return a realization of the weight lattice of ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: B.weight_lattice_realization()
            Extended weight lattice of the Root system of type ['A', 2, 1]
        """
        return self._cartan_type.root_system().weight_lattice(extended=True)

    class Element(ElementWrapper):
        """
        An element in a BZ multisegments crystal.
        """
        def __init__(self, parent, value):
            """
            Initialize ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: mg = B.highest_weight_vector()
                sage: TestSuite(mg).run()
            """
            def sort_key(x):
                return (-x[0], ZZ(x[1]))
            ZM = parent._Zn
            value = [(k, ZM(i)) for k,i in value]
            ElementWrapper.__init__(self, parent, tuple(sorted(value, key=sort_key)))

        def _repr_(self):
            r"""
            Return a string representation of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: B.highest_weight_vector()
                0
                sage: B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)])
                (4; 2] + (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1]
            """
            if not self.value:
                return '0'
            def sort_key(mc):
                x = mc[0]
                return (-x[0], ZZ(x[1]))
            def seg(x):
                m, c = x
                if c != 1:
                    return "{} * ({}; {}]".format(c, m[0], m[1])
                return "({}; {}]".format(m[0], m[1])
            d = {}
            for x in self.value:
                d[x] = d.get(x, 0) + 1
            return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key))

        def _latex_(self):
            r"""
            Return a LaTeX representation of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: latex(B.highest_weight_vector())
                0
                sage: latex(B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)]))
                (4; 2] + (3; 0] + 2 (3; 1] + (1; 0] + (1; 1]
            """
            if not self.value:
                return "0"
            def sort_key(mc):
                x = mc[0]
                return (-x[0], ZZ(x[1]))
            def seg(x):
                m, c = x
                if c != 1:
                    return "{} ({}; {}]".format(c, m[0], m[1])
                return "({}; {}]".format(m[0], m[1])
            d = {}
            for x in self.value:
                d[x] = d.get(x, 0) + 1
            return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key))

        def _sig(self, i):
            r"""
            Return an `i`-signature of ``self``.

            INPUT:

            - ``i`` -- an element of the indexing set

            OUTPUT:

            A pair ``(m, p, ep)`` where ``m`` and ``p`` correspond to the
            block length of the unmatched `-` and `+` respectively or ``None``
            if there is no such block and ``ep`` is the number of unmatched
            `-`.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b._sig(0)
                (1, None, 1)
                sage: b._sig(1)
                (None, None, 0)

            TESTS:

            Check that :trac:`23439` is fixed::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B.highest_weight_vector()
                sage: b._sig(1)
                (None, None, 0)
                sage: b.epsilon(1)
                0
            """
            if not self.value:
                return (None, None, 0)
            pos = []
            block = self.value[0][0]
            cur = 0
            for k,j in self.value:
                if k != block:
                    if cur != 0:
                        pos.append((block, cur))
                    cur = 0
                    block = k
                if j + 1 == i: # + or (
                    cur += 1
                elif j == i: # - or )
                    cur -= 1
            if cur != 0:
                pos.append((block, cur))
            # Now cancel all +- pairs
            cur = 0
            m = None
            p = None
            ep = 0
            for k,c in pos:
                old = cur
                cur += c
                if cur < 0:
                    m = k
                    p = None
                    ep -= cur
                    cur = 0
                elif not cur:
                    p = None
                elif cur > 0 and old <= 0:
                    p = k
            return (m, p, ep)

        def e(self, i):
            r"""
            Return the action of `e_i` on ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.e(0)
                (4; 2] + (3; 0] + (3; 1] + (1; 1]
                sage: b.e(1)
                sage: b.e(2)
                (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1]
            """
            i = self.parent()._Zn(i)
            m = self._sig(i)[0]
            if m is None:
                return None

            M = self.value
            a = M.index((m, i))
            k = M[a][0]
            if k == 1:
                return self.__class__(self.parent(), M[:a] + M[a+1:])
            return self.__class__(self.parent(), M[:a] + ((k-1,i-1),) + M[a+1:])

        def f(self, i):
            r"""
            Return the action of `f_i` on ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.f(0)
                (4; 2] + (3; 0] + (3; 1] + 2 * (1; 0] + (1; 1]
                sage: b.f(1)
                (4; 2] + (3; 0] + (3; 1] + (1; 0] + 2 * (1; 1]
                sage: b.f(2)
                2 * (4; 2] + (3; 0] + (1; 0] + (1; 1]
            """
            i = self.parent()._Zn(i)
            p = self._sig(i)[1]
            M = self.value
            if p is None:
                return self.__class__(self.parent(), ((1, i),) + M)

            a = M.index((p, i-1))
            return self.__class__(self.parent(), M[:a] + ((M[a][0]+1,i),) + M[a+1:])

        def epsilon(self, i):
            r"""
            Return `\varepsilon_i` of ``self``.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.epsilon(0)
                1
                sage: b.epsilon(1)
                0
                sage: b.epsilon(2)
                1
            """
            i = self.parent()._Zn(i)
            return self._sig(i)[2]

        def phi(self, i):
            r"""
            Return `\varphi_i` of ``self``.

            Let `\psi \in \Psi`. Define `\varphi_i(\psi) :=
            \varepsilon_i(\psi) + \langle h_i, \mathrm{wt}(\psi) \rangle`,
            where `h_i` is the `i`-th simple coroot and `\mathrm{wt}(\psi)` is the
            :meth:`weight` of `\psi`.

            INPUT:

            - ``i`` -- an element of the index set

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.phi(0)
                1
                sage: b.phi(1)
                0
                sage: mg = B.highest_weight_vector()
                sage: mg.f(1).phi(0)
                1
            """
            h = self.parent().weight_lattice_realization().simple_coroots()
            return self.epsilon(i) + self.weight().scalar(h[i])

        def weight(self):
            """
            Return the weight of ``self``.

            EXAMPLES::

                sage: B = crystals.infinity.Multisegments(2)
                sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)])
                sage: b.weight()
                -4*delta
            """
            WLR = self.parent().weight_lattice_realization()
            alpha = WLR.simple_roots()
            n = self.parent()._cartan_type.rank()
            return WLR.sum(-1*alpha[j % n] for k,i in self.value
                           for j in range(ZZ(i),ZZ(i)+k))
Пример #14
0
def WeylGroup(x, prefix=None):
    """
    Returns the Weyl group of type ct.
    
    INPUT:

    - ``ct`` - a Cartan Type.
    
    OPTIONAL:

    - ``prefix`` - changes the representation of elements from matrices
      to products of simple reflections
    
    EXAMPLES: The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::
    
        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()
    
    or alternatively and equivalently::
    
        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()
    
    Either produces a weight lattice, with access to its roots and
    weights.
    
    ::
    
        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3, 1])).run()

        sage: W=WeylGroup(['A',3,1])
        sage: s=W.simple_reflections()
        sage: w=s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w=s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
    """
    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    ct = CartanType(x)
    if ct.is_affine():
        return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
    else:
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)