Пример #1
0
    def __classcall_private__(cls, cartan_type, r, s):
        """
        Normalize the input arguments to ensure unique representation.

        EXAMPLES::

            sage: KRT1 = KirillovReshetikhinTableaux(CartanType(['A',3,1]), 2, 3)
            sage: KRT2 = KirillovReshetikhinTableaux(['A',3,1], 2, 3)
            sage: KRT1 is KRT2
            True
        """
        ct = CartanType(cartan_type)
        assert ct.is_affine()

        if ct.is_untwisted_affine():
            if ct.letter == 'D':
                if r == ct.n or r == ct.n - 1:
                    return KRTableauxSpin(ct, r, s)
                return KRTableauxTypeVertical(ct, r, s)

            if ct.letter == 'B':
                if r == ct.n:
                    return KRTableauxBn(ct, r, s)
                return KRTypeVertical(ct, r, s)

            if ct.letter == 'A' or (ct.letter == 'C' and r == ct.n):
                return KRTableauxRectangle(ct, r, s)
        else:
            if ct.dual().letter == 'B':
                return KRTableauxTypeVertical(ct, r, s)

        raise NotImplementedError
Пример #2
0
    def __classcall_private__(cls, arg0, cartan_type=None, kac_moody=True):
        """
        Parse input to ensure a unique representation.

        INPUT:

        - ``arg0`` -- a simple Lie algebra or a base ring
        - ``cartan_type`` -- a Cartan type

        EXAMPLES::

            sage: L1 = lie_algebras.Affine(QQ, ['A',4,1])
            sage: cl = lie_algebras.sl(QQ, 5)
            sage: L2 = lie_algebras.Affine(cl)
            sage: L1 is L2
            True
            sage: cl.affine() is L1
            True
        """
        if isinstance(arg0, LieAlgebra):
            ct = arg0.cartan_type()
            if not ct.is_finite():
                raise ValueError("the base Lie algebra is not simple")
            cartan_type = ct.affine()
            g = arg0
        else:
            # arg0 is the base ring
            cartan_type = CartanType(cartan_type)
            if not cartan_type.is_affine():
                raise ValueError("the Cartan type must be affine")
            g = LieAlgebra(arg0, cartan_type=cartan_type.classical())

        if not cartan_type.is_untwisted_affine():
            raise NotImplementedError("only currently implemented for untwisted affine types")
        return super(AffineLieAlgebra, cls).__classcall__(cls, g, kac_moody)
Пример #3
0
    def __classcall_private__(cls, starting_weight, cartan_type = None, starting_weight_parent = None):
        """
        Classcall to mend the input.

        Internally, the
        :class:`~sage.combinat.crystals.littlemann_path.CrystalOfLSPaths` code
        works with a ``starting_weight`` that is in the weight space associated
        to the crystal. The user can, however, also input a ``cartan_type``
        and the coefficients of the fundamental weights as
        ``starting_weight``. This code transforms the input into the right
        format (also necessary for UniqueRepresentation).

        TESTS::

            sage: crystals.LSPaths(['A',2,1],[-1,0,1])
            The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2]

            sage: R = RootSystem(['B',2,1])
            sage: La = R.weight_space(extended=True).basis()
            sage: C = crystals.LSPaths(['B',2,1],[0,0,1])
            sage: B = crystals.LSPaths(La[2])
            sage: B is C
            True
        """
        if cartan_type is not None:
            cartan_type, starting_weight = CartanType(starting_weight), cartan_type
            if cartan_type.is_affine():
                extended = True
            else:
                extended = False

            R = RootSystem(cartan_type)
            P = R.weight_space(extended = extended)
            Lambda = P.basis()
            offset = R.index_set()[Integer(0)]
            starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set())
        if starting_weight_parent is None:
            starting_weight_parent = starting_weight.parent()
        else:
            # Both the weight and the parent of the weight are passed as arguments of init to be able
            # to distinguish between crystals with the extended and non-extended weight lattice!
            if starting_weight.parent() != starting_weight_parent:
                raise ValueError("The passed parent is not equal to parent of the inputted weight!")

        return super(CrystalOfLSPaths, cls).__classcall__(cls, starting_weight, starting_weight_parent = starting_weight_parent)
Пример #4
0
    def __classcall_private__(cls, cartan_type, La):
        r"""
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights()
            sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8])
            sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8])
            sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8])
            sage: M is M1 is M2
            True
        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.is_affine():
            La = RootSystem(cartan_type).weight_lattice(extended=True)(La)
        else:
            La = RootSystem(cartan_type).weight_lattice()(La)
        return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
Пример #5
0
    def __classcall_private__(cls, cartan_type, B):
        """
        Normalize the input arguments to ensure unique representation.

        EXAMPLES::

            sage: T1 = crystals.TensorProductOfKirillovReshetikhinTableaux(CartanType(['A',3,1]), [[2,2]])
            sage: T2 = crystals.TensorProductOfKirillovReshetikhinTableaux(['A',3,1], [(2,2)])
            sage: T3 = crystals.TensorProductOfKirillovReshetikhinTableaux(['A',3,1], ((2,2),))
            sage: T2 is T1, T3 is T1
            (True, True)
        """
        cartan_type = CartanType(cartan_type)
        if not cartan_type.is_affine():
            raise ValueError("The Cartan type must be affine")

        # Standardize B input into a tuple of tuples
        B = tuple(tuple(dim) for dim in B)
        return super(TensorProductOfKirillovReshetikhinTableaux, cls).__classcall__(cls, cartan_type, B)
Пример #6
0
    def __classcall_private__(cls, cartan_type, La):
        r"""
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights()
            sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8])
            sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8])
            sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8])
            sage: M is M1 is M2
            True
        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.is_affine():
            La = RootSystem(cartan_type).weight_lattice(extended=True)(La)
        else:
            La = RootSystem(cartan_type).weight_lattice()(La)
        return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
Пример #7
0
    def __classcall_private__(cls, starting_weight, cartan_type = None):
        """
        Classcall to mend the input.

        Internally, the CrystalOfLSPaths code works with a ``starting_weight`` that
        is in the ``weight_space`` associated to the crystal. The user can, however,
        also input a ``cartan_type`` and the coefficients of the fundamental weights
        as ``starting_weight``. This code transforms the input into the right
        format (also necessary for UniqueRepresentation).

        TESTS::

            sage: CrystalOfLSPaths(['A',2,1],[-1,0,1])
            The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2]

            sage: R = RootSystem(['B',2,1])
            sage: La = R.weight_space().basis()
            sage: C = CrystalOfLSPaths(['B',2,1],[0,0,1])
            sage: B = CrystalOfLSPaths(La[2])
            sage: B is C
            True
        """
        if cartan_type is not None:
            cartan_type, starting_weight = CartanType(starting_weight), cartan_type
            if cartan_type.is_affine():
                extended = True
            else:
                extended = False

            R = RootSystem(cartan_type)
            P = R.weight_space(extended = extended)
            Lambda = P.basis()
            offset = R.index_set()[Integer(0)]
            starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set())

        return super(CrystalOfLSPaths, cls).__classcall__(cls, starting_weight)
Пример #8
0
    def __classcall_private__(cls, cartan_type, La=None, c=None):
        r"""
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights()
            sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8])
            sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8])
            sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8])
            sage: M is M1 is M2
            True
        """
        if La is None:
            La = cartan_type
            cartan_type = La.parent().cartan_type()
        cartan_type = CartanType(cartan_type)
        if cartan_type.is_affine():
            La = RootSystem(cartan_type).weight_lattice(extended=True)(La)
        else:
            La = RootSystem(cartan_type).weight_lattice()(La)
        n = len(cartan_type.index_set())
        c = InfinityCrystalOfNakajimaMonomials._normalize_c(c, n)
        return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La, c)
Пример #9
0
    def __classcall__(cls, base_ring, cartan_type, level=None, twisted=False):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: Q1 = QSystem(QQ, ['A',4])
            sage: Q2 = QSystem(QQ, 'A4')
            sage: Q1 is Q2
            True

        Twisted Q-systems are different from untwisted Q-systems::

            sage: Q1 = QSystem(QQ, ['E',6,2], twisted=True)
            sage: Q2 = QSystem(QQ, ['E',6,2])
            sage: Q1 is Q2
            False
        """
        cartan_type = CartanType(cartan_type)
        if not is_tamely_laced(cartan_type):
            raise ValueError("the Cartan type is not tamely-laced")
        if twisted and not cartan_type.is_affine() and not cartan_type.is_untwisted_affine():
            raise ValueError("the Cartan type must be of twisted type")
        return super(QSystem, cls).__classcall__(cls, base_ring, cartan_type, level, twisted)
Пример #10
0
class CrystalOfLSPaths(UniqueRepresentation, Parent):
    r"""
    Crystal graph of LS paths generated from the straight-line path to a given weight.

    INPUT:

    - ``cartan_type`` -- the Cartan type of a finite or affine root system
    - ``starting_weight`` -- a weight given as a list of coefficients of the fundamental weights

    The crystal class of piecewise linear paths in the weight space,
    generated from a straight-line path from the origin to a given
    element of the weight lattice.

    OUTPUT: - a tuple of weights defining the directions of the piecewise linear segments

    EXAMPLES::

        sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]); C
        The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1)
        sage: c = C.module_generators[0]; c
        (-Lambda[0] + Lambda[2],)
        sage: [c.f(i) for i in C.index_set()]
        [None, None, (Lambda[1] - Lambda[2],)]

        sage: R = C.R; R
        Root system of type ['A', 2, 1]
        sage: Lambda = R.weight_space().basis(); Lambda
        Finite family {0: Lambda[0], 1: Lambda[1], 2: Lambda[2]}
        sage: b=C(tuple([-Lambda[0]+Lambda[2]]))
        sage: b==c
        True
        sage: b.f(2)
        (Lambda[1] - Lambda[2],)

    For classical highest weight crystals we can also compare the results with the tableaux implementation::

        sage: C = CrystalOfLSPaths(['A',2],[1,1])
        sage: list(set(C.list()))
        [(-Lambda[1] - Lambda[2],), (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2]), (-Lambda[1] + 2*Lambda[2],),
        (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]), (Lambda[1] - 2*Lambda[2],), (-2*Lambda[1] + Lambda[2],),
        (2*Lambda[1] - Lambda[2],), (Lambda[1] + Lambda[2],)]
        sage: C.cardinality()
        8
        sage: B = CrystalOfTableaux(['A',2],shape=[2,1])
        sage: B.cardinality()
        8
        sage: B.digraph().is_isomorphic(C.digraph())
        True

    TESTS::

        sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1])
        sage: TestSuite(C).run(skip=['_test_elements', '_test_elements_eq', '_test_enumerated_set_contains', '_test_some_elements'])
        sage: C = CrystalOfLSPaths(['E',6],[1,0,0,0,0,0])
        sage: TestSuite(C).run()

    REFERENCES::

        .. [L] P. Littelmann, Paths and root operators in representation theory. Ann. of Math. (2) 142 (1995), no. 3, 499-525.
    """

    @staticmethod
    def __classcall__(cls, cartan_type, starting_weight):
        """
        cartan_type and starting_weight are lists, which are mutable. The class
        UniqueRepresentation requires immutable inputs. The following code
        fixes this problem.

        TESTS::

            sage: CrystalOfLSPaths.__classcall__(CrystalOfLSPaths,['A',2,1],[-1,0,1])
            The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1)
        """
        cartan_type = CartanType(cartan_type)
        starting_weight = tuple(starting_weight)
        return super(CrystalOfLSPaths, cls).__classcall__(cls, cartan_type, starting_weight)

    def __init__(self, cartan_type, starting_weight):
        """
        EXAMPLES::

            sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]); C
            The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1)
            sage: C.R
            Root system of type ['A', 2, 1]
            sage: C.weight
            -Lambda[0] + Lambda[2]
            sage: C.weight.parent()
            Extended weight space over the Rational Field of the Root system of type ['A', 2, 1]
            sage: C.module_generators
            [(-Lambda[0] + Lambda[2],)]
        """
        self._cartan_type = CartanType(cartan_type)
        self.R = RootSystem(cartan_type)

        self._name = "The crystal of LS paths of type %s and weight %s"%(cartan_type,starting_weight)

        if self._cartan_type.is_affine():
            self.extended = True
            if all(i>=0 for i in starting_weight):
                Parent.__init__(self, category = HighestWeightCrystals())
            else:
                Parent.__init__(self, category = Crystals())
        else:
            self.extended = False
            Parent.__init__(self, category = FiniteCrystals())

        Lambda = self.R.weight_space(extended = self.extended).basis()
        offset = self.R.index_set()[Integer(0)]

        zero_weight = self.R.weight_space(extended = self.extended).zero()
        self.weight = sum([zero_weight]+[starting_weight[j-offset]*Lambda[j] for j in self.R.index_set()])

        if self.weight == zero_weight:
            initial_element = self(tuple([]))
        else:
            initial_element = self(tuple([self.weight]))
        self.module_generators = [initial_element]

    def _repr_(self):
        """
        EXAMPLES::

            sage: CrystalOfLSPaths(['B',3],[1,1,0]) # indirect doctest
            The crystal of LS paths of type ['B', 3] and weight (1, 1, 0)
        """
        return self._name

    class Element(ElementWrapper):
        """
        TESTS::

            sage: C = CrystalOfLSPaths(['E',6],[1,0,0,0,0,0])
            sage: c=C.an_element()
            sage: TestSuite(c).run()
        """

        def endpoint(self):
            r"""
            Computes the endpoint of the path.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: b = C.module_generators[0]
                sage: b.endpoint()
                Lambda[1] + Lambda[2]
                sage: b.f_string([1,2,2,1])
                (-Lambda[1] - Lambda[2],)
                sage: b.f_string([1,2,2,1]).endpoint()
                -Lambda[1] - Lambda[2]
                sage: b.f_string([1,2])
                (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2])
                sage: b.f_string([1,2]).endpoint()
                0
                sage: b = C([])
                sage: b.endpoint()
                0
            """
            if len(self.value) > 0:
                return sum(self.value)
            return self.parent().R.weight_space(extended = self.parent().extended).zero()

        def compress(self):
            r"""
            Merges consecutive positively parallel steps present in the path.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: Lambda = C.R.weight_space().fundamental_weights(); Lambda
                Finite family {1: Lambda[1], 2: Lambda[2]}
                sage: c = C(tuple([1/2*Lambda[1]+1/2*Lambda[2], 1/2*Lambda[1]+1/2*Lambda[2]]))
                sage: c.compress()
                (Lambda[1] + Lambda[2],)
            """
            def positively_parallel_weights(v, w):
                """
                Checks whether the vectors ``v`` and ``w`` are positive scalar multiples of each other.
                """
                supp = v.support()
                if len(supp) > 0:
                    i = supp[0]
                    if v[i]*w[i] > 0 and v[i]*w == w[i]*v:
                        return True
                return False

            if len(self.value) == 0:
                return self
            q = []
            curr = self.value[0]
            for i in range(1,len(self.value)):
                if positively_parallel_weights(curr,self.value[i]):
                    curr = curr + self.value[i]
                else:
                    q.append(curr)
                    curr = self.value[i]
            q.append(curr)
            return self.parent()(tuple(q))

        def split_step(self, which_step, r):
            r"""
            Splits indicated step into two parallel steps of relative lengths `r` and `1-r`.

            INPUT:
            - ``which_step`` -- a position in the tuple ``self``
            - ``r`` -- a rational number between 0 and 1

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: b = C.module_generators[0]
                sage: b.split_step(0,1/3)
                (1/3*Lambda[1] + 1/3*Lambda[2], 2/3*Lambda[1] + 2/3*Lambda[2])
            """
            assert which_step in range(len(self.value))
            v = self.value[which_step]
            return self.parent()(self.value[:which_step]+tuple([r*v,(1-r)*v])+self.value[which_step+1:])

        def reflect_step(self, which_step, i):
            r"""
            Apply the `i`-th simple reflection to the indicated step in ``self``.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: b = C.module_generators[0]
                sage: b.reflect_step(0,1)
                (-Lambda[1] + 2*Lambda[2],)
                sage: b.reflect_step(0,2)
                (2*Lambda[1] - Lambda[2],)
            """
            assert i in self.index_set()
            assert which_step in range(len(self.value))
            return self.parent()(self.value[:which_step]+tuple([self.value[which_step].simple_reflection(i)])+self.value[which_step+1:])

        def _string_data(self, i):
            r"""
            Computes the `i`-string data of ``self``.

            TESTS::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: b = C.module_generators[0]
                sage: b._string_data(1)
                ()
                sage: b._string_data(2)
                ()
                sage: b.f(1)._string_data(1)
                ((0, -1, -1),)
                sage: b.f(1).f(2)._string_data(2)
                ((0, -1, -1),)
            """
            if len(self.value) == 0:
                return ()
            # get the i-th simple coroot
            alv = self.value[0].parent().alphacheck()[i]
            # Compute the i-heights of the steps of vs
            steps = [v.scalar(alv) for v in self.value]
            # Get the wet step data
            minima_pos = []
            ps = 0
            psmin = 0
            for ix in range(len(steps)):
                ps = ps + steps[ix]
                if ps < psmin:
                    minima_pos.append((ix,ps,steps[ix]))
                    psmin = ps
            return tuple(minima_pos)

        def epsilon(self, i):
            r"""
            Returns the distance to the beginning of the `i`-string.

            This method overrides the generic implementation in the category of crystals
            since this computation is more efficient.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: [c.epsilon(1) for c in C]
                [0, 1, 0, 0, 1, 0, 1, 2]
                sage: [c.epsilon(2) for c in C]
                [0, 0, 1, 2, 1, 1, 0, 0]
            """
            return self.e(i,length_only=True)

        def phi(self, i):
            r"""
            Returns the distance to the end of the `i`-string.

            This method overrides the generic implementation in the category of crystals
            since this computation is more efficient.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: [c.phi(1) for c in C]
                [1, 0, 0, 1, 0, 2, 1, 0]
                sage: [c.phi(2) for c in C]
                [1, 2, 1, 0, 0, 0, 0, 1]
            """
            return self.f(i,length_only=True)

        def e(self, i, power=1, to_string_end=False, length_only=False):
            r"""
            Returns the `i`-th crystal raising operator on ``self``.

            INPUT:

            - ``i`` -- element of the index set of the underlying root system
            - ``power`` -- positive integer; specifies the power of the raising operator
               to be applied (default: 1)
            - ``to_string_end`` -- boolean; if set to True, returns the dominant end of the
              `i`-string of ``self``. (default: False)
            - ``length_only`` -- boolean; if set to True, returns the distance to the dominant
               end of the `i`-string of ``self``.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: c = C[2]; c
                (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2])
                sage: c.e(1)
                sage: c.e(2)
                (-Lambda[1] + 2*Lambda[2],)
                sage: c.e(2,to_string_end=True)
                (-Lambda[1] + 2*Lambda[2],)
                sage: c.e(1,to_string_end=True)
                (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2])
                sage: c.e(1,length_only=True)
                0
            """
            assert i in self.index_set()
            data = self._string_data(i)
            # compute the minimum i-height M on the path
            if len(data) == 0:
                M = 0
            else:
                M = data[-1][1]
            max_raisings = floor(-M)
            if length_only:
                return max_raisings
            # set the power of e_i to apply
            if to_string_end:
                p = max_raisings
            else:
                p = power
            if p > max_raisings:
                return None

            # copy the vector sequence into a working vector sequence ws
            #!!! ws only needs to be the actual vector sequence, not some
            #!!! fancy crystal graph element
            ws = self.parent()(self.value)

            ix = len(data)-1
            while ix >= 0 and data[ix][1] < M + p:
            # get the index of the current step to be processed
                j = data[ix][0]
                # find the i-height where the current step might need to be split
                if ix == 0:
                    prev_ht = M + p
                else:
                    prev_ht = min(data[ix-1][1],M+p)
                # if necessary split the step. Then reflect the wet part.
                if data[ix][1] - data[ix][2] > prev_ht:
                    ws = ws.split_step(j,1-(prev_ht-data[ix][1])/(-data[ix][2]))
                    ws = ws.reflect_step(j+1,i)
                else:
                    ws = ws.reflect_step(j,i)
                ix = ix - 1
            #!!! at this point we should return the fancy crystal graph element
            #!!! corresponding to the humble vector sequence ws
            return self.parent()(ws.compress())

        def dualize(self):
            r"""
            Returns dualized path.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: for c in C:
                ...     print c, c.dualize()
                ...    
                (Lambda[1] + Lambda[2],) (-Lambda[1] - Lambda[2],)
                (-Lambda[1] + 2*Lambda[2],) (Lambda[1] - 2*Lambda[2],)
                (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2])
                (Lambda[1] - 2*Lambda[2],) (-Lambda[1] + 2*Lambda[2],)
                (-Lambda[1] - Lambda[2],) (Lambda[1] + Lambda[2],)
                (2*Lambda[1] - Lambda[2],) (-2*Lambda[1] + Lambda[2],)
                (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2]) (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2])
                (-2*Lambda[1] + Lambda[2],) (2*Lambda[1] - Lambda[2],)
            """
            if len(self.value) == 0:
                return self
            dual_path = [-v for v in self.value]
            dual_path.reverse()
            return self.parent()(tuple(dual_path))

        def f(self, i, power=1, to_string_end=False, length_only=False):
            r"""
            Returns the `i`-th crystal lowering operator on ``self``.

            INPUT:

            - ``i`` -- element of the index set of the underlying root system
            - ``power`` -- positive integer; specifies the power of the lowering operator
               to be applied (default: 1)
            - ``to_string_end`` -- boolean; if set to True, returns the anti-dominant end of the
              `i`-string of ``self``. (default: False)
            - ``length_only`` -- boolean; if set to True, returns the distance to the anti-dominant
               end of the `i`-string of ``self``.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: c = C.module_generators[0]
                sage: c.f(1)
                (-Lambda[1] + 2*Lambda[2],)
                sage: c.f(1,power=2)
                sage: c.f(2)
                (2*Lambda[1] - Lambda[2],)
                sage: c.f(2,to_string_end=True)
                (2*Lambda[1] - Lambda[2],)
                sage: c.f(2,length_only=True)
                1

                sage: C = CrystalOfLSPaths(['A',2,1],[-1,-1,2])
                sage: c = C.module_generators[0]
                sage: c.f(2,power=2)
                (Lambda[0] + Lambda[1] - 2*Lambda[2],)
            """
            dual_path = self.dualize()
            dual_path = dual_path.e(i, power, to_string_end, length_only)
            if length_only:
                return dual_path
            if dual_path == None:
                return None
            return dual_path.dualize()

        def s(self, i):
            r"""
            Computes the reflection of ``self`` along the `i`-string.

            This method is more efficient than the generic implementation since it uses
            powers of `e` and `f` in the Littelmann model directly.

            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: c = C.module_generators[0]
                sage: c.s(1)
                (-Lambda[1] + 2*Lambda[2],)
                sage: c.s(2)
                (2*Lambda[1] - Lambda[2],)

                sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1])
                sage: c = C.module_generators[0]; c
                (-Lambda[0] + Lambda[2],)
                sage: c.s(2)
                (Lambda[1] - Lambda[2],)
                sage: c.s(1)
                (-Lambda[0] + Lambda[2],)
                sage: c.f(2).s(1)
                (Lambda[0] - Lambda[1],)
            """
            ph = self.phi(i)
            ep = self.epsilon(i)
            diff = ph - ep
            if diff >= 0:
                return self.f(i, power=diff)
            else:
                return self.e(i, power=-diff)

        def _latex_(self):
            r"""
            Latex method for ``self``.
           
            EXAMPLES::

                sage: C = CrystalOfLSPaths(['A',2],[1,1])
                sage: c = C.module_generators[0]
                sage: c._latex_()
                [\Lambda_{1} + \Lambda_{2}]
            """
            return [latex(p) for p in self.value]
Пример #11
0
    def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None,
                              index_set=None, abelian=False, **kwds):
        """
        Select the correct parent based upon input.

        TESTS::

            sage: LieAlgebra(QQ, abelian=True, names='x,y,z')
            Abelian Lie algebra on 3 generators (x, y, z) over Rational Field
            sage: LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2},
            ....:                 ('e','f'): {'h':1}}, names='e,f,h')
            Lie algebra on 3 generators (e, f, h) over Rational Field
        """
        # Parse associative algebra input
        # -----

        assoc = kwds.get("associative", None)
        if assoc is not None:
            return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set)

        # Parse input as a Cartan type
        # -----

        ct = kwds.get("cartan_type", None)
        if ct is not None:
            from sage.combinat.root_system.cartan_type import CartanType
            ct = CartanType(ct)
            if ct.is_affine():
                from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra
                return AffineLieAlgebra(R, cartan_type=ct,
                                        kac_moody=kwds.get("kac_moody", True))
            if not ct.is_finite():
                raise NotImplementedError("non-finite types are not implemented yet, see trac #14901 for details")
            rep = kwds.get("representation", "bracket")
            if rep == 'bracket':
                from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis
                return LieAlgebraChevalleyBasis(R, ct)
            if rep == 'matrix':
                from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra
                return ClassicalMatrixLieAlgebra(R, ct)
            raise ValueError("invalid representation")

        # Parse the remaining arguments
        # -----

        if R is None:
            raise ValueError("invalid arguments")

        check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace))
                                 or A in Rings()
                                 or A in Algebras(R).Associative())
        if arg0 in ZZ or check_assoc(arg1):
            # Check if we need to swap the arguments
            arg0, arg1 = arg1, arg0

        # Parse the first argument
        # -----

        if isinstance(arg0, dict):
            if not arg0:
                from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra
                return AbelianLieAlgebra(R, names, index_set)
            elif isinstance(next(iter(arg0.keys())), (list, tuple)):
                # We assume it is some structure coefficients
                arg1, arg0 = arg0, arg1

        if isinstance(arg0, (list, tuple)):
            if all(isinstance(x, str) for x in arg0):
                # If they are all strings, then it is a list of variables
                names = tuple(arg0)

        if isinstance(arg0, str):
            names = tuple(arg0.split(','))
        elif isinstance(names, str):
            names = tuple(names.split(','))

        # Parse the second argument

        if isinstance(arg1, dict):
            # Assume it is some structure coefficients
            from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients
            return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, **kwds)

        # Otherwise it must be either a free or abelian Lie algebra

        if arg1 in ZZ:
            if isinstance(arg0, str):
                names = arg0
            if names is None:
                index_set = list(range(arg1))
            else:
                if isinstance(names, str):
                    names = tuple(names.split(','))
                    if arg1 != 1 and len(names) == 1:
                        names = tuple('{}{}'.format(names[0], i)
                                      for i in range(arg1))
                if arg1 != len(names):
                    raise ValueError("the number of names must equal the"
                                     " number of generators")

        if abelian:
            from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra
            return AbelianLieAlgebra(R, names, index_set)

        # Otherwise it is the free Lie algebra
        rep = kwds.get("representation", "bracket")
        if rep == "polynomial":
            # Construct the free Lie algebra from polynomials in the
            #   free (associative unital) algebra
            # TODO: Change this to accept an index set once FreeAlgebra accepts one
            from sage.algebras.free_algebra import FreeAlgebra
            F = FreeAlgebra(R, names)
            if index_set is None:
                index_set = F.variable_names()
            # TODO: As part of #16823, this should instead construct a
            #   subclass with specialized methods for the free Lie algebra
            return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set)

        raise NotImplementedError("the free Lie algebra has only been"
                                  " implemented using polynomials in the"
                                  " free algebra, see trac ticket #16823")
Пример #12
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)
Пример #13
0
def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', general_linear=None):
    r"""
    Factory for the fundamental group of an extended affine Weyl group.

    INPUT:

    - ``cartan_type`` -- a Cartan type that is either affine or finite, with the latter being a
      shorthand for the untwisted affinization
    - ``prefix`` (default: 'pi') -- string that labels the elements of the group
    - ``general_linear`` -- (default: None, meaning False) In untwisted type A, if True, use the
      universal central extension

    .. RUBRIC:: Fundamental group

    Associated to each affine Cartan type `\tilde{X}` is an extended affine Weyl group `E`.
    Its subgroup of length-zero elements is called the fundamental group `F`.
    The group `F` can be identified with a subgroup of the group of automorphisms of the
    affine Dynkin diagram. As such, every element of `F` can be viewed as a permutation of the
    set `I` of affine Dynkin nodes.

    Let `0 \in I` be the distinguished affine node; it is the one whose removal produces the
    associated finite Cartan type (call it `X`). A node `i \in I` is called *special*
    if some automorphism of the affine Dynkin diagram, sends `0` to `i`.
    The node `0` is always special due to the identity automorphism.
    There is a bijection of the set of special nodes with the fundamental group. We denote the
    image of `i` by `\pi_i`. The structure of `F` is determined as follows.

    - `\tilde{X}` is untwisted -- `F` is isomorphic to `P^\vee/Q^\vee` where `P^\vee` and `Q^\vee` are the
      coweight and coroot lattices of type `X`. The group `P^\vee/Q^\vee` consists of the cosets `\omega_i^\vee + Q^\vee`
      for special nodes `i`, where `\omega_0^\vee = 0` by convention. In this case the special nodes `i`
      are the *cominuscule* nodes, the ones such that `\omega_i^\vee(\alpha_j)` is `0` or `1` for all `j\in I_0 = I \setminus \{0\}`.
      For `i` special, addition by `\omega_i^\vee+Q^\vee` permutes `P^\vee/Q^\vee` and therefore permutes the set of special nodes.
      This permutation extends uniquely to an automorphism of the affine Dynkin diagram.
    - `\tilde{X}` is dual untwisted -- (that is, the dual of `\tilde{X}` is untwisted) `F` is isomorphic to `P/Q`
      where `P` and `Q` are the weight and root lattices of type `X`. The group `P/Q` consists of the cosets
      `\omega_i + Q` for special nodes `i`, where `\omega_0 = 0` by convention. In this case the special nodes `i`
      are the *minuscule* nodes, the ones such that `\alpha_j^\vee(\omega_i)` is `0` or `1` for all `j \in I_0`.
      For `i` special, addition by `\omega_i+Q` permutes `P/Q` and therefore permutes the set of special nodes.
      This permutation extends uniquely to an automorphism of the affine Dynkin diagram.
    - `\tilde{X}` is mixed -- (that is, not of the above two types) `F` is the trivial group.

    EXAMPLES::

        sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]); F
        Fundamental group of type ['A', 3, 1]
        sage: F.cartan_type().dynkin_diagram()
        0
        O-------+
        |       |
        |       |
        O---O---O
        1   2   3
        A3~
        sage: F.special_nodes()
        (0, 1, 2, 3)
        sage: F(1)^2
        pi[2]
        sage: F(1)*F(2)
        pi[3]
        sage: F(3)^(-1)
        pi[1]

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("B3"); F
        Fundamental group of type ['B', 3, 1]
        sage: F.cartan_type().dynkin_diagram()
            O 0
            |
            |
        O---O=>=O
        1   2   3
        B3~
        sage: F.special_nodes()
        (0, 1)

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("C2"); F
        Fundamental group of type ['C', 2, 1]
        sage: F.cartan_type().dynkin_diagram()
        O=>=O=<=O
        0   1   2
        C2~
        sage: F.special_nodes()
        (0, 2)

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D4"); F
        Fundamental group of type ['D', 4, 1]
        sage: F.cartan_type().dynkin_diagram()
            O 4
            |
            |
        O---O---O
        1   |2  3
            |
            O 0
        D4~
        sage: F.special_nodes()
        (0, 1, 3, 4)
        sage: (F(4), F(4)^2)
        (pi[4], pi[0])

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D5"); F
        Fundamental group of type ['D', 5, 1]
        sage: F.cartan_type().dynkin_diagram()
          0 O   O 5
            |   |
            |   |
        O---O---O---O
        1   2   3   4
        D5~
        sage: F.special_nodes()
        (0, 1, 4, 5)
        sage: (F(5), F(5)^2, F(5)^3, F(5)^4)
        (pi[5], pi[1], pi[4], pi[0])
        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("E6"); F
        Fundamental group of type ['E', 6, 1]
        sage: F.cartan_type().dynkin_diagram()
                O 0
                |
                |
                O 2
                |
                |
        O---O---O---O---O
        1   3   4   5   6
        E6~
        sage: F.special_nodes()
        (0, 1, 6)
        sage: F(1)^2
        pi[6]

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['D',4,2]); F
        Fundamental group of type ['C', 3, 1]^*
        sage: F.cartan_type().dynkin_diagram()
        O=<=O---O=>=O
        0   1   2   3
        C3~*
        sage: F.special_nodes()
        (0, 3)

    We also implement a fundamental group for `GL_n`. It is defined to be the group of integers, which is the
    covering group of the fundamental group Z/nZ for affine `SL_n`::

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True); F
        Fundamental group of GL(3)
        sage: x = F.an_element(); x
        pi[5]
        sage: x*x
        pi[10]
        sage: x.inverse()
        pi[-5]
        sage: wt = F.cartan_type().classical().root_system().ambient_space().an_element(); wt
        (2, 2, 3)
        sage: x.act_on_classical_ambient(wt)
        (2, 3, 2)
        sage: w = WeylGroup(F.cartan_type(),prefix="s").an_element(); w
        s0*s1*s2
        sage: x.act_on_affine_weyl(w)
        s2*s0*s1
    """
    cartan_type = CartanType(cartan_type)
    if cartan_type.is_finite():
        cartan_type = cartan_type.affine()
    if not cartan_type.is_affine():
        raise NotImplementedError("Cartan type is not affine")
    if general_linear is True:
        if cartan_type.is_untwisted_affine() and cartan_type.type() == "A":
            return FundamentalGroupGL(cartan_type, prefix)
        else:
            raise ValueError("General Linear Fundamental group is untwisted type A")
    return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type,prefix,finite=True)
Пример #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)