Exemple #1
0
class ClassicalCrystalOfAlcovePaths(UniqueRepresentation, Parent):
    r"""
    Implementation of crystal of alcove paths of the given classical type with
    given highest weight, based on the Lenart--Postnikov model [LP2008].

    These are highest weight crystals for classical types `A_n`, `B_n`, `C_n`,
    `D_n` and the exceptional types `F_4`, `G_2`, `E_6`, `E_7`, `E_8`.

    INPUT:

        - ``cartan_type`` is the Cartan type of a classical Dynkin diagram
        - ``highest_weight`` is a dominant weight as a list of coefficients of
          the fundamental weights `Lambda_i`

    In this model, a chain of roots is associated to the given highest_weight,
    and then the elements of the crystal are indexed by "admissible subsets"
    which indicate "folding positions" along the chain of roots.  See [LP2008]
    for details.

    TODO:

    - Resolve speed issues;  `E_6(\Lambda_1)` takes just under 4 minutes to list().
      To construct the highest-weight node takes 15 sec for `E_6(\Lambda_4)`.
      The initial chain has 42 roots.

    TESTS:

    The following example appears in Figure 2 of [LP2008]::

        sage: C = ClassicalCrystalOfAlcovePaths(['G',2],[0,1]);
        sage: G = C.digraph()
        sage: GG= DiGraph({
        ...       ()        : {(0)         : 2 },
        ...       (0)       : {(0,8)       : 1 },
        ...       (0,1)     : {(0,1,7)     : 2 },
        ...       (0,1,2)   : {(0,1,2,9)   : 1 },
        ...       (0,1,2,3) : {(0,1,2,3,4) : 2 },
        ...       (0,1,2,6) : {(0,1,2,3)   : 1 },
        ...       (0,1,2,9) : {(0,1,2,6)   : 1 },
        ...       (0,1,7)   : {(0,1,2)     : 2 },
        ...       (0,1,7,9) : {(0,1,2,9)   : 2 },
        ...       (0,5)     : {(0,1)       : 1, (0,5,7) : 2 },
        ...       (0,5,7)   : {(0,5,7,9)   : 1 },
        ...       (0,5,7,9) : {(0,1,7,9)   : 1 },
        ...       (0,8)     : {(0,5)       : 1 },
        ...       })
        sage: G.is_isomorphic(GG)
        True

        sage: for edge in sorted([(u.value, v.value, i) for (u,v,i) in G.edges()]):
        ...       print edge
        ([], [0], 2)
        ([0], [0, 8], 1)
        ([0, 1], [0, 1, 7], 2)
        ([0, 1, 2], [0, 1, 2, 9], 1)
        ([0, 1, 2, 3], [0, 1, 2, 3, 4], 2)
        ([0, 1, 2, 6], [0, 1, 2, 3], 1)
        ([0, 1, 2, 9], [0, 1, 2, 6], 1)
        ([0, 1, 7], [0, 1, 2], 2)
        ([0, 1, 7, 9], [0, 1, 2, 9], 2)
        ([0, 5], [0, 1], 1)
        ([0, 5], [0, 5, 7], 2)
        ([0, 5, 7], [0, 5, 7, 9], 1)
        ([0, 5, 7, 9], [0, 1, 7, 9], 1)
        ([0, 8], [0, 5], 1)

    REFERENCES:

        .. [LP2008]  C. Lenart and A. Postnikov. A combinatorial model for crystals of Kac-Moody algebras. Trans. Amer. Math. Soc.  360  (2008), 4349-4381. 
    """

    @staticmethod
    def __classcall__(cls, cartan_type, highest_weight):
        """
        cartan_type and heighest_weight are lists, which are mutable, this
        causes a problem for class UniqueRepresentation, the following code
        fixes this problem.

        EXAMPLES::
            sage: ClassicalCrystalOfAlcovePaths.__classcall__(ClassicalCrystalOfAlcovePaths,['A',3],[0,1,0])
            <class 'sage.combinat.crystals.alcove_path.ClassicalCrystalOfAlcovePaths_with_category'>
        """
        cartan_type = CartanType(cartan_type)
        highest_weight = tuple(highest_weight)
        return super(ClassicalCrystalOfAlcovePaths, cls).__classcall__(cls, cartan_type, highest_weight)

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

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[1,0,0])
            sage: C.list()
            [[], [0], [0, 1], [0, 1, 2]]
            sage: TestSuite(C).run()
        """
        Parent.__init__(self, category = ClassicalCrystals())
        self._cartan_type = CartanType(cartan_type)
        self._name = "The crystal of alcove paths for type %s"%cartan_type
        self.chain_cache = {}
        self.endweight_cache = {}

        self.R = RootSystem(cartan_type)
        alpha = self.R.root_space().simple_roots()
        Lambda = self.R.weight_space().basis()

        self.positive_roots = sorted(self.R.root_space().positive_roots());

        self.weight = Lambda[Integer(1)] - Lambda[Integer(1)]
        offset = self.R.index_set()[Integer(0)]
        for j in self.R.index_set():
            self.weight = self.weight + highest_weight[j-offset]*Lambda[j]

        self.initial_element = self([])

        self.initial_element.chain = self.get_initial_chain(self.weight)
        rho = (Integer(1)/Integer(2))*sum(self.positive_roots)
        self.initial_element.endweight = rho

        self.chain_cache[ str([]) ] = self.initial_element.chain
        self.endweight_cache[ str([]) ] = self.initial_element.endweight

        self.module_generators = [self.initial_element]

        self._list = super(ClassicalCrystalOfAlcovePaths, self).list()
        self._digraph = super(ClassicalCrystalOfAlcovePaths, self).digraph()
        self._digraph_closure = self.digraph().transitive_closure()

    def get_initial_chain(self, highest_weight):
        """
        Called internally by __init__() to construct the chain of roots
        associated to the highest weight element.

        EXAMPLES::
            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.get_initial_chain(RootSystem(['A',3]).weight_space().basis()[1])
            [[alpha[1], alpha[1]], [alpha[1] + alpha[2], alpha[1] + alpha[2]], [alpha[1] + alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]]
        """
        pos_roots = self.positive_roots
        tis = self.R.index_set()
        tis.reverse()
        cv_to_pos_root = {}
        to_sort = []
        for r in pos_roots:
            j = highest_weight.scalar( r.associated_coroot() )
            if (int(math.floor(j)) - j == Integer(0)):
                j = j - Integer(1)
            j = int(math.floor(j))
            for k in (ellipsis_range(Integer(0),Ellipsis,j)):
                cv = []
                cv.append((Integer(1)/highest_weight.scalar(r.associated_coroot()))*k)
                for i in tis:
                    cv.append((Integer(1)/highest_weight.scalar(r.associated_coroot()))*r.associated_coroot().coefficient(i))
                cv_to_pos_root[ str(cv) ] = r
                to_sort.append( cv )

        to_sort.sort() # Note:  Python sorts nested lists lexicographically by default.
        lambda_chain = []
        for t in to_sort:
            lambda_chain.append( [ cv_to_pos_root[str(t)], cv_to_pos_root[str(t)] ] )
        return lambda_chain

    def _element_constructor_(self, value):
        """
        Coerces value into self.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[1,0,0])
            sage: C.module_generators
            [[]]
            sage: C([]).e(1)
            sage: C([]).f(1)
            [0]
        """
        return self.element_class(self, value)

    def list(self):
        """
        Returns a list of the elements of self.

        .. warning::

           This can be slow!

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.list()
            [[], [0], [0, 1], [0, 2], [0, 1, 2], [0, 1, 2, 3]]
        """
        return self._list

    def digraph(self):
        """
        Returns the directed graph associated to self.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.digraph().vertices()
            [[], [0], [0, 1], [0, 2], [0, 1, 2], [0, 1, 2, 3]]
            sage: C.digraph().edges()
            [([], [0], 2), ([0], [0, 1], 1), ([0], [0, 2], 3), ([0, 1], [0, 1, 2], 3), ([0, 2], [0, 1, 2], 1), ([0, 1, 2], [0, 1, 2, 3], 2)]
        """
        return self._digraph

    def lt_elements(self, x, y):
        r"""
        Returns True if and only if there is a path
        from x to y in the crystal graph.

        Because the crystal graph is classical, it is a directed
        acyclic graph which can be interpreted as a poset. This
        function implements the comparison function of this poset.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: x = C([])
            sage: y = C([0,2])
            sage: C.lt_elements(x,y)
            True
            sage: C.lt_elements(y,x)
            False
            sage: C.lt_elements(x,x)
            False
        """
        assert x.parent() == self and y.parent() == self
        if self._digraph_closure.has_edge(x,y):
            return True
        return False
Exemple #2
0
class ClassicalCrystalOfAlcovePaths(UniqueRepresentation, Parent):
    r"""
    Implementation of crystal of alcove paths of the given classical type with
    given highest weight, based on the Lenart--Postnikov model [LP2008].

    These are highest weight crystals for classical types `A_n`, `B_n`, `C_n`,
    `D_n` and the exceptional types `F_4`, `G_2`, `E_6`, `E_7`, `E_8`.

    INPUT:

        - ``cartan_type`` is the Cartan type of a classical Dynkin diagram
        - ``highest_weight`` is a dominant weight as a list of coefficients of
          the fundamental weights `Lambda_i`

    In this model, a chain of roots is associated to the given highest_weight,
    and then the elements of the crystal are indexed by "admissible subsets"
    which indicate "folding positions" along the chain of roots.  See [LP2008]
    for details.

    TODO:

    - Resolve speed issues;  `E_6(\Lambda_1)` takes just under 4 minutes to list().
      To construct the highest-weight node takes 15 sec for `E_6(\Lambda_4)`.
      The initial chain has 42 roots.

    TESTS:

    The following example appears in Figure 2 of [LP2008]::

        sage: C = ClassicalCrystalOfAlcovePaths(['G',2],[0,1]);
        sage: G = C.digraph()
        sage: GG= DiGraph({
        ...       ()        : {(0)         : 2 },
        ...       (0)       : {(0,8)       : 1 },
        ...       (0,1)     : {(0,1,7)     : 2 },
        ...       (0,1,2)   : {(0,1,2,9)   : 1 },
        ...       (0,1,2,3) : {(0,1,2,3,4) : 2 },
        ...       (0,1,2,6) : {(0,1,2,3)   : 1 },
        ...       (0,1,2,9) : {(0,1,2,6)   : 1 },
        ...       (0,1,7)   : {(0,1,2)     : 2 },
        ...       (0,1,7,9) : {(0,1,2,9)   : 2 },
        ...       (0,5)     : {(0,1)       : 1, (0,5,7) : 2 },
        ...       (0,5,7)   : {(0,5,7,9)   : 1 },
        ...       (0,5,7,9) : {(0,1,7,9)   : 1 },
        ...       (0,8)     : {(0,5)       : 1 },
        ...       })
        sage: G.is_isomorphic(GG)
        True

        sage: for edge in sorted([(u.value, v.value, i) for (u,v,i) in G.edges()]):
        ...       print edge
        ([], [0], 2)
        ([0], [0, 8], 1)
        ([0, 1], [0, 1, 7], 2)
        ([0, 1, 2], [0, 1, 2, 9], 1)
        ([0, 1, 2, 3], [0, 1, 2, 3, 4], 2)
        ([0, 1, 2, 6], [0, 1, 2, 3], 1)
        ([0, 1, 2, 9], [0, 1, 2, 6], 1)
        ([0, 1, 7], [0, 1, 2], 2)
        ([0, 1, 7, 9], [0, 1, 2, 9], 2)
        ([0, 5], [0, 1], 1)
        ([0, 5], [0, 5, 7], 2)
        ([0, 5, 7], [0, 5, 7, 9], 1)
        ([0, 5, 7, 9], [0, 1, 7, 9], 1)
        ([0, 8], [0, 5], 1)

    REFERENCES:

        .. [LP2008]  C. Lenart and A. Postnikov. A combinatorial model for crystals of Kac-Moody algebras. Trans. Amer. Math. Soc.  360  (2008), 4349-4381. 
    """
    @staticmethod
    def __classcall__(cls, cartan_type, highest_weight):
        """
        cartan_type and heighest_weight are lists, which are mutable, this
        causes a problem for class UniqueRepresentation, the following code
        fixes this problem.

        EXAMPLES::
            sage: ClassicalCrystalOfAlcovePaths.__classcall__(ClassicalCrystalOfAlcovePaths,['A',3],[0,1,0])
            <class 'sage.combinat.crystals.alcove_path.ClassicalCrystalOfAlcovePaths_with_category'>
        """
        cartan_type = CartanType(cartan_type)
        highest_weight = tuple(highest_weight)
        return super(ClassicalCrystalOfAlcovePaths,
                     cls).__classcall__(cls, cartan_type, highest_weight)

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

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[1,0,0])
            sage: C.list()
            [[], [0], [0, 1], [0, 1, 2]]
            sage: TestSuite(C).run()
        """
        Parent.__init__(self, category=ClassicalCrystals())
        self._cartan_type = CartanType(cartan_type)
        self._name = "The crystal of alcove paths for type %s" % cartan_type
        self.chain_cache = {}
        self.endweight_cache = {}

        self.R = RootSystem(cartan_type)
        alpha = self.R.root_space().simple_roots()
        Lambda = self.R.weight_space().basis()

        self.positive_roots = sorted(self.R.root_space().positive_roots())

        self.weight = Lambda[Integer(1)] - Lambda[Integer(1)]
        offset = self.R.index_set()[Integer(0)]
        for j in self.R.index_set():
            self.weight = self.weight + highest_weight[j - offset] * Lambda[j]

        self.initial_element = self([])

        self.initial_element.chain = self.get_initial_chain(self.weight)
        rho = (Integer(1) / Integer(2)) * sum(self.positive_roots)
        self.initial_element.endweight = rho

        self.chain_cache[str([])] = self.initial_element.chain
        self.endweight_cache[str([])] = self.initial_element.endweight

        self.module_generators = [self.initial_element]

        self._list = super(ClassicalCrystalOfAlcovePaths, self).list()
        self._digraph = super(ClassicalCrystalOfAlcovePaths, self).digraph()
        self._digraph_closure = self.digraph().transitive_closure()

    def get_initial_chain(self, highest_weight):
        """
        Called internally by __init__() to construct the chain of roots
        associated to the highest weight element.

        EXAMPLES::
            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.get_initial_chain(RootSystem(['A',3]).weight_space().basis()[1])
            [[alpha[1], alpha[1]], [alpha[1] + alpha[2], alpha[1] + alpha[2]], [alpha[1] + alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]]
        """
        pos_roots = self.positive_roots
        tis = self.R.index_set()
        tis.reverse()
        cv_to_pos_root = {}
        to_sort = []
        for r in pos_roots:
            j = highest_weight.scalar(r.associated_coroot())
            if (int(math.floor(j)) - j == Integer(0)):
                j = j - Integer(1)
            j = int(math.floor(j))
            for k in (ellipsis_range(Integer(0), Ellipsis, j)):
                cv = []
                cv.append(
                    (Integer(1) / highest_weight.scalar(r.associated_coroot()))
                    * k)
                for i in tis:
                    cv.append((Integer(1) /
                               highest_weight.scalar(r.associated_coroot())) *
                              r.associated_coroot().coefficient(i))
                cv_to_pos_root[str(cv)] = r
                to_sort.append(cv)

        to_sort.sort(
        )  # Note:  Python sorts nested lists lexicographically by default.
        lambda_chain = []
        for t in to_sort:
            lambda_chain.append(
                [cv_to_pos_root[str(t)], cv_to_pos_root[str(t)]])
        return lambda_chain

    def _element_constructor_(self, value):
        """
        Coerces value into self.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[1,0,0])
            sage: C.module_generators
            [[]]
            sage: C([]).e(1)
            sage: C([]).f(1)
            [0]
        """
        return self.element_class(self, value)

    def list(self):
        """
        Returns a list of the elements of self.

        .. warning::

           This can be slow!

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.list()
            [[], [0], [0, 1], [0, 2], [0, 1, 2], [0, 1, 2, 3]]
        """
        return self._list

    def digraph(self):
        """
        Returns the directed graph associated to self.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: C.digraph().vertices()
            [[], [0], [0, 1], [0, 2], [0, 1, 2], [0, 1, 2, 3]]
            sage: C.digraph().edges()
            [([], [0], 2), ([0], [0, 1], 1), ([0], [0, 2], 3), ([0, 1], [0, 1, 2], 3), ([0, 2], [0, 1, 2], 1), ([0, 1, 2], [0, 1, 2, 3], 2)]
        """
        return self._digraph

    def lt_elements(self, x, y):
        r"""
        Returns True if and only if there is a path
        from x to y in the crystal graph.

        Because the crystal graph is classical, it is a directed
        acyclic graph which can be interpreted as a poset. This
        function implements the comparison function of this poset.

        EXAMPLES::

            sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[0,1,0])
            sage: x = C([])
            sage: y = C([0,2])
            sage: C.lt_elements(x,y)
            True
            sage: C.lt_elements(y,x)
            False
            sage: C.lt_elements(x,x)
            False
        """
        assert x.parent() == self and y.parent() == self
        if self._digraph_closure.has_edge(x, y):
            return True
        return False