Ticket #3663: affine-crystal-3663-as.2.patch

File affine-crystal-3663-as.2.patch, 43.5 KB (added by aschilling, 8 years ago)
  • new file sage/combinat/crystals/affine.py

    # HG changeset patch
    # User Anne Schilling <anne@math.ucdavis.edu>
    # Date 1243461252 25200
    # Node ID 5651ac1a05fba76f0f54523754f25f0a1e2495da
    # Parent  b583a3e2ef588c153185810c50fc2382bb155e09
    Implementation of affine crystals from classical crystals:
    - input is a classical crystal together with an automorphism
    - result is an affine crystal
    
    Implementation of Kirillov Reshetikhin crystals:
    
    - Type A_n^{(1)} KR crystals are implemented.
    - Type D_n^{(1)}, B_n^{(1)}, A_{2n}^{(2)} KR crystals are implemented using plus-minus diagrams
    
    diff -r b583a3e2ef58 -r 5651ac1a05fb sage/combinat/crystals/affine.py
    - +  
     1r"""
     2Affine crystals
     3"""
     4
     5#*****************************************************************************
     6#       Copyright (C) 2008 Brant Jones <brant at math.ucdavis.edu>
     7#                          Anne Schilling <anne at math.ucdavis.edu>
     8#
     9#  Distributed under the terms of the GNU General Public License (GPL)
     10#
     11#    This code is distributed in the hope that it will be useful,
     12#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14#    General Public License for more details.
     15#
     16#  The full text of the GPL is available at:
     17#
     18#                  http://www.gnu.org/licenses/
     19#****************************************************************************
     20# Acknowledgment: most of the design and implementation of this
     21# library is heavily inspired from MuPAD-Combinat.
     22#****************************************************************************
     23
     24from sage.combinat.crystals.crystals import Crystal, ClassicalCrystal, CrystalElement
     25from sage.structure.unique_representation import UniqueRepresentation
     26from sage.structure.element_wrapper import ElementWrapper
     27from sage.combinat.root_system.cartan_type import CartanType
     28from sage.combinat.crystals.tensor_product import CrystalOfTableaux
     29from sage.combinat.tableau import Tableau_class
     30
     31class AffineCrystal(Crystal):
     32    r"""
     33    The abstract class of affine crystals
     34    """
     35    pass
     36
     37class AffineCrystalFromClassical(Crystal, UniqueRepresentation):
     38    r"""
     39    Crystals that are constructed from a classical crystal and a
     40    Dynkin diagram automorphism `\sigma`.  In type `A_n`, the Dynkin
     41    diagram automorphism is `i \to i+1 \pmod n+1` and the
     42    corresponding map on the crystal is the promotion operation
     43    `\mathrm{pr}` on tableaux. The affine crystal operators are given
     44    by `f_0= \mathrm{pr}^{-1} f_{\sigma(0)} \mathrm{pr}`.
     45
     46    INPUT:
     47
     48    - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     49
     50    - ``classical_crystal`` - instance of a classical crystal.
     51
     52    - ``automorphism, inverse_automorphism`` - A function on the
     53      elements of the classical_crystal
     54   
     55    - ``dynkin_node`` - Integer specifying the classical node in the
     56      image of the zero node under the automorphism sigma.
     57
     58    EXAMPLES::
     59
     60        sage: n=2
     61        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     62        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     63        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     64        sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     65        sage: A.list()
     66        [[[1]], [[2]], [[3]]]
     67        sage: A.cartan_type()
     68        ['A', 2, 1]
     69        sage: A.index_set()
     70        [0, 1, 2]
     71        sage: b=A(rows=[[1]])
     72        sage: b.weight()
     73        -Lambda[0] + Lambda[1]
     74        sage: b.classical_weight()
     75        (1, 0, 0)
     76        sage: [x.s(0) for x in A.list()]
     77        [[[3]], [[2]], [[1]]]
     78        sage: [x.s(1) for x in A.list()]
     79        [[[2]], [[1]], [[3]]]
     80    """
     81
     82    @staticmethod
     83    def __classcall__(cls, cartan_type, *args):
     84        ct = CartanType(cartan_type)
     85        return super(AffineCrystalFromClassical, cls).__classcall__(cls, ct, *args)
     86
     87    def __init__(self, cartan_type, classical_crystal, p_automorphism, p_inverse_automorphism, dynkin_node):
     88        """
     89        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     90        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     91
     92        EXAMPLES::
     93
     94            sage: n=1
     95            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     96            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     97            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     98            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     99            sage: A.list()
     100            [[[1]], [[2]]]
     101            sage: A.cartan_type()
     102            ['A', 1, 1]
     103            sage: A.index_set()
     104            [0, 1]
     105        """
     106        self._cartan_type = cartan_type
     107        self.p_automorphism = p_automorphism
     108        self.p_inverse_automorphism = p_inverse_automorphism
     109        self._name = "An affine crystal for type %s"%self.cartan_type
     110        self.dynkin_node = dynkin_node
     111        self.element_class = AffineCrystalFromClassicalElement
     112        self.classical_crystal = classical_crystal;
     113        self.module_generators = map( self.retract, self.classical_crystal.module_generators )
     114
     115    def __iter__(self):
     116        for x in self.classical_crystal:
     117            yield self.retract(x)
     118
     119    # should be removed once crystal defines __iter__ instead of list
     120    def list(self):
     121        """
     122        Returns the list of all crystal elements using the underlying classical crystal
     123
     124        EXAMPLES::
     125
     126            sage: n=2
     127            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     128            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     129            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     130            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     131            sage: A.list()
     132            [[[1]], [[2]], [[3]]]
     133        """
     134        return map( self.retract, self.classical_crystal.list() )
     135       
     136    def automorphism(self, x):
     137        """
     138        Gives the analogue of the affine Dynkin diagram automorphism on the level of crystals
     139
     140        EXAMPLES::
     141
     142            sage: n=2
     143            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     144            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     145            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     146            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     147            sage: b=A.list()[0]
     148            sage: A.automorphism(b)
     149            [[2]]
     150        """
     151        return self.retract( self.p_automorphism( x.lift() ) )
     152
     153    def inverse_automorphism(self, x):
     154        """
     155        Gives the analogue of the inverse of the affine Dynkin diagram automorphism on the level of crystals
     156
     157        EXAMPLES::
     158
     159            sage: n=2
     160            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     161            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     162            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     163            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     164            sage: b=A.list()[0]
     165            sage: A.inverse_automorphism(b)
     166            [[3]]
     167        """
     168        return self.retract( self.p_inverse_automorphism( x.lift() ) )
     169
     170    def lift(self, affine_elt):
     171        """
     172        Lifts an affine crystal element to the corresponding classical crystal element
     173
     174        EXAMPLES::
     175
     176            sage: n=2
     177            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     178            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     179            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     180            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     181            sage: b=A.list()[0]
     182            sage: type(A.lift(b))
     183            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     184        """
     185        return affine_elt.lift()
     186
     187    def retract(self, classical_elt):
     188        """
     189        Transforms a classical crystal element to the corresponding affine crystal element
     190
     191        EXAMPLES::
     192
     193            sage: n=2
     194            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     195            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     196            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     197            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     198            sage: t=C(rows=[[1]])
     199            sage: type(t)
     200            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     201            sage: A.retract(t)
     202            [[1]]
     203            sage: type(A.retract(t))
     204            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalElement'>
     205        """
     206        return self.element_class(classical_elt, parent = self)
     207   
     208    def __call__(self, *value, **options):
     209        r"""
     210        Coerces value into self.
     211
     212        EXAMPLES:
     213
     214            sage: n=2
     215            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     216            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     217            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     218            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     219            sage: b=A(rows=[[1]])
     220            sage: b
     221            [[1]]
     222            sage: type(b)
     223            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalElement'>
     224            sage: A(b)
     225            [[1]]
     226            sage: type(A(b))
     227            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalElement'>
     228        """
     229        if len(value) == 1 and isinstance(value[0], self.element_class) and value[0].parent() == self:
     230            return value[0]
     231        else: # Should do sanity checks!  (Including check for inconsistent parent.)
     232            return self.retract(self.classical_crystal(*value, **options))
     233
     234    def __contains__(self, x):
     235        r"""
     236        Checks whether x is an element of self.
     237
     238        EXAMPLES:
     239
     240            sage: n=2
     241            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     242            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     243            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     244            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     245            sage: b=A(rows=[[1]])
     246            sage: A.__contains__(b)
     247            True
     248        """
     249        return x.parent() is self
     250
     251
     252class AffineCrystalFromClassicalElement(ElementWrapper, CrystalElement):
     253    r"""
     254    Elements of crystals that are constructed from a classical crystal
     255    and a Dynkin diagram automorphism.  In type A, the automorphism is
     256    the promotion operation on tableaux.  It inherits a constructor
     257    from Letter.
     258
     259    This class is not instantiated directly but rather __call__ed from
     260    AffineCrystalFromClassical.  The syntax of this is governed by the
     261    (classical) CrystalOfTableaux.
     262
     263    EXAMPLES::
     264
     265        sage: n=2
     266        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     267        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     268        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     269        sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     270        sage: b=A(rows=[[1]])
     271        sage: b.__repr__()
     272        '[[1]]'
     273    """
     274
     275    def classical_weight(self):
     276        """
     277        Returns the classical weight corresponding to self.
     278
     279        EXAMPLES::
     280
     281            sage: n=2
     282            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     283            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     284            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     285            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     286            sage: b=A(rows=[[1]])
     287            sage: b.classical_weight()
     288            (1, 0, 0)
     289        """
     290        return self.lift().weight()
     291
     292    def lift(self):
     293        """
     294        Lifts an affine crystal element to the corresponding classical crystal element
     295
     296        EXAMPLES::
     297
     298            sage: n=2
     299            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     300            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     301            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     302            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     303            sage: b=A.list()[0]
     304            sage: type(b.lift())
     305            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     306        """
     307        return self.value
     308
     309    def e(self, i):
     310        r"""
     311        Returns the action of `e_i` on self.
     312
     313        EXAMPLES::
     314
     315            sage: n=2
     316            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     317            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     318            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     319            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     320            sage: b=A(rows=[[1]])
     321            sage: b.e(0)
     322            [[3]]
     323            sage: b.e(1)
     324        """
     325        if (i != 0):
     326            x = self.lift().e(i)
     327            if (x == None):
     328                return None
     329            else:
     330                return self.parent().retract(x)
     331        else:
     332            x = self.parent().automorphism(self).e(self.parent().dynkin_node)
     333            if (x == None):
     334                return None
     335            else:
     336                return self.parent().inverse_automorphism(x)
     337
     338    def f(self, i):
     339        r"""
     340        Returns the action of `f_i` on self.
     341
     342        EXAMPLES::
     343
     344            sage: n=2
     345            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     346            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     347            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     348            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     349            sage: b=A(rows=[[3]])
     350            sage: b.f(0)
     351            [[1]]
     352            sage: b.f(2)
     353        """
     354        if (i != 0):
     355            x = self.lift().f(i)
     356            if (x == None):
     357                return None
     358            else:
     359                return self.parent().retract(x)
     360        else:
     361            x = self.parent().automorphism(self).f(self.parent().dynkin_node)
     362            if (x == None):
     363                return None
     364            else:
     365                return self.parent().inverse_automorphism(x)
     366
     367    def epsilon(self, i):
     368        """
     369        Returns the maximal time the crystal operator `e_i` can be applied to self.
     370
     371        EXAMPLES::
     372
     373            sage: n=2
     374            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     375            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     376            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     377            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     378            sage: [x.epsilon(0) for x in A.list()]
     379            [1, 0, 0]
     380            sage: [x.epsilon(1) for x in A.list()]
     381            [0, 1, 0]
     382        """
     383        if (i == 0):
     384            x = self.parent().automorphism(self)
     385            return x.lift().epsilon(self.parent().dynkin_node)
     386        else:
     387            return self.lift().epsilon(i)
     388
     389    def phi(self, i):
     390        """
     391        Returns the maximal time the crystal operator `f_i` can be applied to self.
     392
     393        EXAMPLES::
     394
     395            sage: n=2
     396            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     397            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     398            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     399            sage: A=AffineCrystalFromClassical(['A',n,1],C,pr,pr_inverse,1)
     400            sage: [x.phi(0) for x in A.list()]
     401            [0, 0, 1]
     402            sage: [x.phi(1) for x in A.list()]
     403            [1, 0, 0]
     404        """
     405        if (i == 0):
     406            x = self.parent().automorphism(self)
     407            return x.lift().phi(self.parent().dynkin_node)
     408        else:
     409            return self.lift().phi(i)
  • sage/combinat/crystals/all.py

    diff -r b583a3e2ef58 -r 5651ac1a05fb sage/combinat/crystals/all.py
    a b  
    66from tensor_product import TensorProductOfCrystals
    77from tensor_product import CrystalOfTableaux
    88from fast_crystals import FastCrystal
     9from affine import AffineCrystalFromClassical
     10from kirillov_reshetikhin import KirillovReshetikhinCrystal
  • sage/combinat/crystals/crystals.py

    diff -r b583a3e2ef58 -r 5651ac1a05fb sage/combinat/crystals/crystals.py
    a b  
    143143#****************************************************************************
    144144
    145145from sage.misc.latex import latex
     146from sage.misc.cachefunc import CachedFunction
    146147from sage.structure.parent import Parent
    147148from sage.structure.element import Element
    148149from sage.combinat.combinat import CombinatorialClass
     
    178179            sage: C = CrystalOfLetters(['A', 5])
    179180            sage: C.weight_lattice_realization()
    180181            Ambient space of the Root system of type ['A', 5]
     182            sage: K = KirillovReshetikhinCrystal(['A',2,1], 1, 1)
     183            sage: K.weight_lattice_realization()
     184            Weight lattice of the Root system of type ['A', 2, 1]
    181185        """
    182         return self.cartan_type().root_system().ambient_space()
     186        F = self.cartan_type().root_system()
     187        if F.ambient_space() is None:
     188            return F.weight_lattice()
     189        else:
     190            return F.ambient_space()
    183191
    184192    def cartan_type(self):
    185193        """
     
    262270            sage: l.sort(); l
    263271            [1, 2, 3, 4, 5, 6]
    264272        """
    265         # To be generalized to some transitiveIdeal
     273        # Should use transitiveIdeal
     274        # should be transformed to __iter__ instead of list
    266275        # To be moved in a super category CombinatorialModule
    267276        result = set(self.module_generators)
    268277        todo = result.copy()
     
    276285                result.add(y)
    277286        return list(result)
    278287
     288    def crystal_morphism(self, g, index_set = None, automorphism = lambda i : i, direction = 'down', direction_image = 'down',
     289                         cached = False):
     290        """
     291        Constructs a morphism from the crystal self to another crystal.
     292        The input g can either be a function of a (sub)set of elements of self to
     293        element in another crystal or a dictionary between certain elements.
     294        Usually one would map highest weight elements or crystal generators to each
     295        other using g.
     296        Specifying index_set gives the opportunity to define the morphism as `I`-crystals
     297        where I = index_set. If index_set is not specified, the index set of self is used.
     298        It is also possible to define twisted-morphisms by specifying an automorphism on the
     299        nodes in te Dynkin diagram (or the index_set).
     300        The option direction and direction_image indicate whether to use `f_i` or `e_i` in
     301        self or the image crystal to construct the morphism, depending on whether the direction
     302        is set to 'down' or 'up'.
     303       
     304        EXAMPLES::
     305
     306            sage: C2 = CrystalOfLetters(['A',2])
     307            sage: C3 = CrystalOfLetters(['A',3])
     308            sage: g = {C2.module_generators[0] : C3.module_generators[0]}
     309            sage: g_full = C2.crystal_morphism(g)
     310            sage: g_full(C2(1))
     311            1
     312            sage: g_full(C2(2))
     313            2
     314            sage: g = {C2(1) : C2(3)}
     315            sage: g_full = C2.crystal_morphism(g, automorphism = lambda i : 3-i, direction_image = 'up')
     316            sage: [g_full(b) for b in C2.list()]
     317            [3, 2, 1]
     318        """
     319        if index_set is None:
     320            index_set = self.index_set()
     321        if direction == 'down':
     322            e = 'e'
     323        else:
     324            e = 'f'
     325        if direction_image == 'down':
     326            f = 'f'
     327        else:
     328            f = 'e'
     329        if type(g) == dict:
     330            g = g.__getitem__
     331
     332        def morphism(b):
     333            for i in index_set:
     334                c = getattr(b, e)(i)
     335                if c is not None:
     336                    d = getattr(morphism(c),f)(automorphism(i))
     337                    if d is not None:
     338                        return d
     339                    else:
     340                        raise ValueError, "there is not morphism!"
     341            #now we know that b is hw
     342            return g(b)
     343
     344        if cached:
     345            return morphism
     346        else:
     347            return CachedFunction(morphism)
     348
     349
    279350    def digraph(self):
    280351        """
    281352        Returns the DiGraph associated to self.
     
    737808            phi = phi+1
    738809        return phi
    739810
     811    def phi_minus_epsilon(self, i):
     812        """
     813        Returns `\phi_i - \epsilon_i` of self. There are sometimes
     814        better implementations using the weight for this. It is used
     815        for reflections along a string.
     816
     817        EXAMPLES::
     818
     819            sage: C = CrystalOfLetters(['A',5])
     820            sage: C(1).phi_minus_epsilon(1)
     821            1
     822        """
     823        return self.phi(i) - self.epsilon(i)
     824
    740825    def Epsilon(self):
    741826        """
    742827        EXAMPLES::
     
    785870            sage: t.s(1)
    786871            [[1, 1, 1, 2]]
    787872        """
    788         d = self.phi(i)-self.epsilon(i)
     873        d = self.phi_minus_epsilon(i)
    789874        b = self
    790875        if d > 0:
    791876            for j in range(d):
  • new file sage/combinat/crystals/kirillov_reshetikhin.py

    diff -r b583a3e2ef58 -r 5651ac1a05fb sage/combinat/crystals/kirillov_reshetikhin.py
    - +  
     1r"""
     2Affine crystals
     3"""
     4
     5#*****************************************************************************
     6#       Copyright (C) 2009   Anne Schilling <anne at math.ucdavis.edu>
     7#
     8#  Distributed under the terms of the GNU General Public License (GPL)
     9#
     10#    This code is distributed in the hope that it will be useful,
     11#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13#    General Public License for more details.
     14#
     15#  The full text of the GPL is available at:
     16#
     17#                  http://www.gnu.org/licenses/
     18#****************************************************************************
     19# Acknowledgment: most of the design and implementation of this
     20# library is heavily inspired from MuPAD-Combinat.
     21#****************************************************************************
     22
     23from sage.combinat.combinat import CombinatorialObject
     24from sage.rings.integer import Integer
     25from sage.misc.functional import is_even, is_odd
     26from sage.combinat.crystals.crystals import Crystal, ClassicalCrystal, CrystalElement
     27from sage.combinat.crystals.affine import AffineCrystal, AffineCrystalFromClassical, AffineCrystalFromClassicalElement
     28from sage.combinat.crystals.letters import Letter
     29from sage.combinat.root_system.cartan_type import CartanType
     30from sage.combinat.crystals.tensor_product import CrystalOfTableaux
     31from sage.combinat.tableau import Tableau_class, Tableau
     32from sage.combinat.partition import Partition, Partitions
     33
     34
     35def KirillovReshetikhinCrystal(cartan_type, r, s):
     36    r"""
     37    Returns the Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     38
     39    For most cases the Kirillov-Reshetikhin crystals are constructed from a
     40    classical crystal together with an automorphism `p` on the level of crystals which
     41    corresponds to a Dynkin diagram automorphism mapping node 0 to some other node i.
     42    The action of `f_0` and `e_0` is then constructed using
     43    `f_0 = p^{-1} \circ f_i \circ p`.
     44
     45    For example, for type `A_n^{(1)}` the Kirillov-Reshetikhin crystal `B^{r,s}`
     46    is obtained from the classical crystal `B(s\omega_r)` using the
     47    promotion operator. For other types, see
     48
     49    M. Shimozono
     50    "Affine type A crystal structure on tensor products of rectangles,
     51    Demazure characters, and nilpotent varieties",
     52    J. Algebraic Combin.  15  (2002),  no. 2, 151-187
     53    (arXiv:math.QA/9804039)
     54
     55    A. Schilling, "Combinatorial structure of Kirillov-Reshetikhin crystals of
     56    type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     57    (arXiv:0704.2046 [math.QA])
     58
     59    G. Fourier, M. Okado, A. Schilling,
     60    "Kirillov-Reshetikhin crystals for nonexceptional types"
     61    Advances in Math., to appear (arXiv:0810.5067 [math.RT])
     62
     63    INPUT:
     64
     65        - ``cartan_type`` Affine type and rank
     66
     67        - ``r`` label of finite Dynkin diagram
     68
     69        - ``s`` positive integer
     70
     71    EXAMPLES::
     72   
     73        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2, 1)
     74        sage: K.index_set()
     75        [0, 1, 2, 3]
     76        sage: K.list()
     77        [[[1], [2]], [[1], [3]], [[2], [3]], [[1], [4]], [[2], [4]], [[3], [4]]]
     78        sage: b=K(rows=[[1],[2]])
     79        sage: b.weight()
     80        -Lambda[0] + Lambda[2]
     81        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     82        sage: K.automorphism(K.module_generators[0])
     83        [[2, 2], [3, 3]]
     84        sage: K.module_generators[0].e(0)
     85        [[1, 2], [2, 4]]
     86        sage: K.module_generators[0].f(2)
     87        [[1, 1], [2, 3]]
     88        sage: K.module_generators[0].f(1)
     89        sage: K.module_generators[0].phi(0)
     90        0
     91        sage: K.module_generators[0].phi(1)
     92        0
     93        sage: K.module_generators[0].phi(2)
     94        2
     95        sage: K.module_generators[0].epsilon(0)
     96        2
     97        sage: K.module_generators[0].epsilon(1)
     98        0
     99        sage: K.module_generators[0].epsilon(2)
     100        0
     101        sage: b = K(rows=[[1,2],[2,3]])
     102        sage: b
     103        [[1, 2], [2, 3]]
     104        sage: b.f(2)
     105        [[1, 2], [3, 3]]
     106    """
     107    ct = CartanType(cartan_type)
     108    if ct.letter == 'A' and ct[2] == 1:
     109        return KR_type_A(ct, r, s)
     110    elif ct.letter == 'D' and ct[2] == 1 and r<ct[1]-1:
     111        return KR_type_vertical(ct, r, s)
     112    elif ct.letter == 'B' and ct[2] ==1 and r<ct[1]:
     113        return KR_type_vertical(ct, r, s)
     114    elif ct.letter == 'A' and ct[2] ==2 and is_even(ct[1]):
     115        return KR_type_vertical(ct, r, s)
     116    else:
     117        raise NotImplementedError
     118
     119
     120class KirillovReshetikhinGenericCrystal(AffineCrystalFromClassical):
     121    r"""
     122    Generic class for Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     123
     124    This generic class assumes that the Kirillov-Reshetikhin crystal is constructed
     125    from a classical crystal 'classical_decomposition' and an automorphism 'promotion' and its inverse
     126    which corresponds to a Dynkin diagram automorphism 'dynkin_diagram_automorphism'.
     127
     128    Each instance using this class needs to implement the methods:
     129    - classical_decomposition
     130    - promotion
     131    - promotion_inverse
     132    - dynkin_diagram_automorphism
     133    """
     134    def __init__(self, cartan_type, r, s):
     135        self._cartan_type = CartanType(cartan_type)
     136        self._r = r
     137        self._s = s
     138        self._name = "Kirillov-Reshetikhin crystal of type %s with (r,s)=(%d,%d)" % (cartan_type, r, s)
     139        AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition(),
     140                                            self.promotion(), self.promotion_inverse(), self.dynkin_diagram_automorphism(0))
     141
     142    def cartan_type(self):
     143        """
     144        Returns the Cartan type of the underlying Kirillov-Reshetikhin crystal
     145
     146        EXAMPLE::
     147
     148            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     149            sage: K.cartan_type()
     150            ['D', 4, 1]
     151        """
     152        return self._cartan_type
     153
     154    def r(self):
     155        """
     156        Returns r of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     157
     158        EXAMPLE::
     159
     160            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     161            sage: K.r()
     162            2
     163        """
     164        return self._r
     165   
     166    def s(self):
     167        """
     168        Returns s of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     169
     170        EXAMPLE::
     171
     172            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     173            sage: K.s()
     174            1
     175        """
     176        return self._s
     177
     178class KR_type_A(KirillovReshetikhinGenericCrystal):
     179    r"""
     180    Class of Kirillov-Reshetikhin crystals of type `A_n^{(1)}`.
     181
     182    EXAMPLES::
     183
     184        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     185        sage: b = K(rows=[[1,2],[2,4]])
     186        sage: b.f(0)
     187        [[1, 1], [2, 2]]
     188    """
     189
     190    def classical_decomposition(self):
     191        """
     192        Specifies the classical crystal underlying the KR crystal of type A.
     193
     194        EXAMPLES::
     195
     196            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     197            sage: K.classical_decomposition()
     198            The crystal of tableaux of type ['A', 3] and shape(s) ([2, 2],)
     199        """
     200        return CrystalOfTableaux(self._cartan_type.classical(), shape = [self.s() for i in range(1,self.r()+1)])
     201   
     202    def promotion(self):
     203        """
     204        Specifies the promotion operator used to construct the affine type A crystal.
     205        For type A this corresponds to the Dynkin diagram automorphism which maps i to i+1 mod n+1,
     206        where n is the rank.
     207
     208        EXAMPLES:
     209
     210            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     211            sage: b = K.classical_decomposition()(rows=[[1,2],[3,4]])
     212            sage: K.promotion()(b)
     213            [[1, 3], [2, 4]]
     214        """
     215        return lambda x : self.classical_crystal(x.to_tableau().promotion(self._cartan_type[1]))
     216   
     217    def promotion_inverse(self):
     218        """
     219        Specifies the inverse promotion operator used to construct the affine type A crystal.
     220
     221        EXAMPLES:
     222
     223            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     224            sage: b = K.classical_decomposition()(rows=[[1,3],[2,4]])
     225            sage: K.promotion()(b)
     226            [[1, 2], [3, 4]]
     227        """
     228        return lambda x : self.classical_crystal(x.to_tableau().promotion_inverse(self._cartan_type[1]))
     229
     230    def dynkin_diagram_automorphism(self, i):
     231        """
     232        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     233        elements. The automorphism needs to map node 0 to some other Dynkin node.
     234
     235        For type A we use the Dynkin diagram automorphism which maps i to i+1 mod n+1, where n is the rank.
     236
     237        EXAMPLES::
     238       
     239            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     240            sage: K.dynkin_diagram_automorphism(0)
     241            1
     242            sage: K.dynkin_diagram_automorphism(3)
     243            0
     244        """
     245        aut = range(1,self.cartan_type().rank())+[0]
     246        return aut[i]
     247
     248class KR_type_vertical(KirillovReshetikhinGenericCrystal):
     249    r"""
     250    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `D_n^{(1)}` for `r\le n-2`,
     251    `B_n^{(1)}` for `r<n`, and `A_{2n}^{(2)}` for `r\le n`.
     252
     253    EXAMPLES::
     254
     255        sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     256        sage: b = K(rows=[])
     257        sage: b.f(0)
     258        [[1], [2]]
     259        sage: b.f(0).f(0)
     260        [[1, 1], [2, 2]]
     261        sage: b.e(0)
     262        [[-2], [-1]]
     263        sage: b.e(0).e(0)
     264        [[-2, -2], [-1, -1]]
     265
     266        sage: K = KirillovReshetikhinCrystal(['B',3,1], 1,1)
     267        sage: [[b,b.f(0)] for b in K]
     268        [[[[1]], None], [[[2]], None], [[[3]], None], [[[0]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     269        sage: K = KirillovReshetikhinCrystal(['A',6,2], 1,1)
     270        sage: [[b,b.f(0)] for b in K]
     271        [[[[1]], None], [[[2]], None], [[[3]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     272    """
     273 
     274    def classical_decomposition(self):
     275        """
     276        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `D_n^{(1)}`, `B_n^{(1)}`,
     277        and `A_{2n}^{(2)}`.
     278        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     279        a rectangle of width s and height r by removing verticle dominoes. Here we identify the fundamental
     280        weight `\Lambda_i` with a column of height `i`.
     281
     282        EXAMPLES::
     283
     284            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     285            sage: K.classical_decomposition()
     286            The crystal of tableaux of type ['D', 4] and shape(s) [[], [1, 1], [2, 2]]
     287        """
     288        return CrystalOfTableaux(self.cartan_type().classical(),
     289                                 shapes = self.vertical_dominoes_removed(self.r(),self.s()))
     290   
     291    def promotion(self):
     292        """
     293        Specifies the promotion operator used to construct the affine type 'D_n^{(1)}` crystal.
     294        For type D, this corresponds to the Dynkin diagram automorphism which interchanges nodes 0 and 1,
     295        and leaves all other nodes unchanged. On the level of crystals it is constructed using
     296        `\pm` diagrams.
     297
     298        EXAMPLES:
     299
     300            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     301            sage: promotion = K.promotion()
     302            sage: b = K.classical_decomposition()(rows=[])
     303            sage: promotion(b)
     304            [[1, 2], [-2, -1]]
     305            sage: b = K.classical_decomposition()(rows=[[1,3],[2,-1]])
     306            sage: promotion(b)
     307            [[1, 3], [2, -1]]
     308            sage: b = K.classical_decomposition()(rows=[[1],[-3]])
     309            sage: promotion(b)
     310            [[2, -3], [-2, -1]]
     311        """
     312        T = self.classical_decomposition()
     313        ind = T.index_set()
     314        ind.remove(1)
     315        return T.crystal_morphism( self.promotion_on_highest_weight_vectors(), index_set = ind)
     316   
     317    promotion_inverse = promotion
     318   
     319    def dynkin_diagram_automorphism(self, i):
     320        """
     321        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     322        elements. The automorphism needs to map node 0 to some other Dynkin node.
     323
     324        For type D we use the Dynkin diagram automorphism which interchanges nodes 0 and 1 and leaves
     325        all other nodes unchanged.
     326
     327        EXAMPLES::
     328       
     329            sage: K = KirillovReshetikhinCrystal(['D',4,1],1,1)
     330            sage: K.dynkin_diagram_automorphism(0)
     331            1
     332            sage: K.dynkin_diagram_automorphism(1)
     333            0
     334            sage: K.dynkin_diagram_automorphism(4)
     335            4
     336        """
     337        aut = [1,0]+range(2,self.cartan_type().rank())
     338        return aut[i]
     339
     340    def partitions_in_box(self, r, s):
     341        """
     342        Returns all partitions in a box of width s and height r.
     343
     344        EXAMPLES::
     345
     346            sage: K = KirillovReshetikhinCrystal(['D',4,1], 1,2)
     347            sage: K.partitions_in_box(3,2)
     348            [[], [1], [2], [1, 1], [2, 1], [1, 1, 1], [2, 2], [2, 1, 1],
     349            [2, 2, 1], [2, 2, 2]]
     350        """
     351        return [x for n in range(r*s+1) for x in Partitions(n,max_part=s,max_length=r)]
     352
     353    def vertical_dominoes_removed(self, r, s):
     354        """
     355        Returns all partitions obtained from a rectangle of width s and height r by removing
     356        vertical dominoes.
     357
     358        EXAMPLES::
     359
     360            sage: K = KirillovReshetikhinCrystal(['D',4,1], 1,2)
     361            sage: K.vertical_dominoes_removed(2,2)
     362            [[], [1, 1], [2, 2]]
     363            sage: K.vertical_dominoes_removed(3,2)
     364            [[2], [2, 1, 1], [2, 2, 2]]
     365        """
     366        list = [ [y for y in x] + [0 for i in range(s-x.length())] for x in self.partitions_in_box(s, int(r/2)) ]
     367        two = lambda x : 2*(x-int(r/2)) + r
     368        return [Partition([two(y) for y in x]).conjugate() for x in list]
     369
     370    def promotion_on_highest_weight_vectors(self):
     371        """
     372        Calculates promotion on `{2,3,...,n}` highest weight vectors.
     373
     374        EXAMPLES::
     375
     376            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     377            sage: T = K.classical_decomposition()
     378            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     379            sage: [K.promotion_on_highest_weight_vectors()(b) for b in hw]
     380            [[[1, 2], [-2, -1]], [[2, 2], [-2, -1]], [[1, 2], [3, -1]], [[2], [-2]],
     381            [[1, 2], [2, -2]], [[2, 2], [-1, -1]], [[2, 2], [3, -1]], [[2, 2], [3, 3]],
     382            [], [[1], [2]], [[1, 1], [2, 2]], [[2], [-1]], [[1, 2], [2, -1]], [[2], [3]],
     383            [[1, 2], [2, 3]]]
     384        """
     385        return lambda b: self.from_pm_diagram_to_highest_weight_vector(self.from_highest_weight_vector_to_pm_diagram(b).sigma())
     386
     387    def from_highest_weight_vector_to_pm_diagram(self, b):
     388        """
     389        This gives the bijection between an element b in the classical decomposition
     390        of the KR crystal that is {2,3,..,n}-highest weight and `\pm` diagrams.
     391
     392        EXAMPLES::
     393
     394            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     395            sage: T = K.classical_decomposition()
     396            sage: b = T(rows=[[2],[-2]])
     397            sage: pm = K.from_highest_weight_vector_to_pm_diagram(b); pm
     398            [[1, 1], [0, 0], [0]]
     399            sage: pm.__repr__(pretty_printing=True)
     400            +
     401            -
     402            sage: b = T(rows=[])
     403            sage: pm=K.from_highest_weight_vector_to_pm_diagram(b); pm
     404            [[0, 2], [0, 0], [0]]
     405            sage: pm.__repr__(pretty_printing=True)
     406
     407            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     408            sage: all(K.from_pm_diagram_to_highest_weight_vector(K.from_highest_weight_vector_to_pm_diagram(b)) == b for b in hw)
     409            True
     410        """
     411        n = self.cartan_type().rank()-1
     412        inner = Partition([Integer(b.weight()[i]) for i in range(1,n+1)])
     413        inter = Partition([len([i for i in r if i>0]) for r in b.to_tableau()])
     414        outer = b.to_tableau().shape()
     415        return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True)
     416 
     417    def from_pm_diagram_to_highest_weight_vector(self, pm):
     418        """
     419        This gives the bijection between a `\pm` diagram and an element b in the classical
     420        decomposition of the KR crystal that is {2,3,..,n}-highest weight.
     421
     422        EXAMPLES::
     423
     424            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     425            sage: pm = sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1, 1], [0, 0], [0]])
     426            sage: K.from_pm_diagram_to_highest_weight_vector(pm)
     427            [[2], [-2]]
     428        """
     429        u = [b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()][0]
     430        ct = self.cartan_type()
     431        rank = ct.rank()-1
     432        list = []
     433        for h in pm.heights_of_addable_plus():
     434            list += range(1,h+1)
     435        for h in pm.heights_of_minus():
     436            if ct.letter == 'D':
     437                list += range(1,rank+1)+[rank-2-k for k in range(rank-1-h)]
     438            elif ct.letter == 'B':
     439                list += range(1,rank+1)+[rank-k for k in range(rank+1-h)]
     440            else:
     441                list += range(1,rank+1)+[rank-1-k for k in range(rank-h)]
     442        for i in reversed(list):
     443            u = u.f(i)
     444        return u
     445
     446
     447class PMDiagram(CombinatorialObject):
     448    """
     449    Class of `\pm` diagrams. These diagrams are in one-to-one bijection with `X_{n-1}` highest weight vectors
     450    in an `X_n` highest weight crystal `X=B,C,D`. See Section 4.1 of A. Schilling, "Combinatorial structure of
     451    Kirillov-Reshetikhin crystals of type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     452    (arXiv:0704.2046[math.QA]).
     453
     454    The input is a list `pm = [[a_0,b_0],[a_1,b_1],...,[a_{n-1},b_{n-1}],[b_n]]` of 2-tuples and a last 1-tuple.
     455    The tuple `[a_i,b_i]` specifies the number of `a_i` + and `b_i` - in the i-th row of the pm diagram
     456    if `n-i` is odd and the number of `a_i` +- pairs above row i and `b_i` columns of height i not containing
     457    any + or - if `n-i` is even.
     458
     459    Setting the option 'from_shapes = True' one can also input a `\pm` diagram in terms of its
     460    outer, intermediate and inner shape by specifying a tuple [n, s, outer, intermediate, inner]
     461    where `s` is the width of the `\pm` diagram, and 'outer' , 'intermediate',
     462    and 'inner' are the outer, intermediate and inner shape, respectively.
     463     
     464    EXAMPLES::
     465
     466        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     467        sage: pm.pm_diagram
     468        [[0, 1], [1, 2], [1]]
     469        sage: pm._list
     470        [1, 1, 2, 0, 1]
     471        sage: pm.n
     472        2
     473        sage: pm.width
     474        5
     475        sage: pm.__repr__(pretty_printing=True)
     476        .  .  .  .
     477        .  +  -  -
     478        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([2,5,[4,4],[4,2],[4,1]], from_shapes=True)
     479        [[0, 1], [1, 2], [1]]
     480
     481    TESTS::
     482       
     483        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     484        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     485        True
     486        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     487        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     488        True
     489    """
     490
     491    def __init__(self, pm_diagram, from_shapes = None):
     492        if from_shapes:
     493            n = pm_diagram[0]
     494            s = pm_diagram[1]
     495            outer = [s]+list(pm_diagram[2])+[0 for i in range(n)]
     496            intermediate = [s]+list(pm_diagram[3])+[0 for i in range(n)]
     497            inner = [s]+list(pm_diagram[4])+[0 for i in range(n)]
     498            pm = [[inner[n]]]
     499            for i in range(int((n+1)/2)):
     500                pm.append([intermediate[n-2*i]-inner[n-2*i], inner[n-2*i-1]-intermediate[n-2*i]])
     501                pm.append([outer[n-2*i]-inner[n-2*i-1], inner[n-2*i-2]-outer[n-2*i]])
     502            if is_odd(n):
     503                pm.pop(n+1)
     504            pm_diagram = list(reversed(pm))
     505        self.pm_diagram = pm_diagram
     506        self.n = len(pm_diagram)-1
     507        self._list = [i for a in reversed(pm_diagram) for i in a]
     508        self.width = sum(i for i in self._list)
     509
     510    def __repr__(self, pretty_printing = None):
     511        """
     512        Turning on pretty printing allows to display the pm diagram as a
     513        tableau with the + and - displayed
     514
     515        EXAMPLES::
     516
     517            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     518            sage: pm.__repr__(pretty_printing=True)
     519            .  .  .  +
     520            .  .  -  -
     521            +  +
     522            -  -
     523            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,2], [0,0], [0]])
     524            sage: pm.__repr__(pretty_printing=True)
     525
     526        """
     527        if pretty_printing is None:
     528            return repr(self.pm_diagram)
     529        t = []
     530        ish = self.inner_shape() + [0]*self.n
     531        msh = self.intermediate_shape() + [0]*self.n
     532        osh = self.outer_shape() + [0]*self.n
     533        for i in range(self.n):
     534            t.append(['.']*ish[i]+['+']*(msh[i]-ish[i])+['-']*(osh[i]-msh[i]))
     535        t=[i for i in t if i!= []]
     536        return Tableau(t).pp()
     537
     538    def inner_shape(self):
     539        """
     540        Returns the inner shape of the pm diagram
     541
     542        EXAMPLES::
     543            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     544            sage: pm.inner_shape()
     545            [4, 1]
     546            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     547            sage: pm.inner_shape()
     548            [7, 5, 3, 1]
     549            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     550            sage: pm.inner_shape()
     551            [10, 7, 5, 3, 1]
     552        """
     553        t = []
     554        ll = self._list
     555        for i in range(self.n):
     556            t.append(sum(ll[0:2*i+1]))
     557        return Partition(list(reversed(t)))
     558
     559    def outer_shape(self):
     560        """
     561        Returns the outer shape of the pm diagram
     562
     563        EXAMPLES::
     564
     565            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     566            sage: pm.outer_shape()
     567            [4, 4]
     568            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     569            sage: pm.outer_shape()
     570            [8, 8, 4, 4]
     571            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     572            sage: pm.outer_shape()
     573            [13, 8, 8, 4, 4]
     574        """
     575        t = []
     576        ll = self._list
     577        for i in range((self.n)/2):
     578            t.append(sum(ll[0:4*i+4]))
     579            t.append(sum(ll[0:4*i+4]))
     580        if is_even(self.n+1):
     581            t.append(sum(ll[0:2*self.n+2]))
     582        return Partition(list(reversed(t)))
     583
     584    def intermediate_shape(self):
     585        """
     586        Returns the intermediate shape of the pm diagram (innner shape plus positions of plusses)
     587
     588        EXAMPLES::
     589
     590            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     591            sage: pm.intermediate_shape()
     592            [4, 2]
     593            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     594            sage: pm.intermediate_shape()
     595            [8, 6, 4, 2]
     596            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     597            sage: pm.intermediate_shape()
     598            [11, 8, 6, 4, 2]
     599            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     600            sage: pm.intermediate_shape()
     601            [4, 2, 2]
     602        """
     603        p = self.inner_shape()
     604        p = p + [0,0]
     605        ll = list(reversed(self._list))
     606        p = [ p[i]+ll[2*i+1] for i in range(self.n) ]
     607        return Partition(p)
     608
     609    def heights_of_minus(self):
     610        """
     611        Returns a list with the heights of all minus in the `\pm` diagram.
     612
     613        EXAMPLES::
     614
     615            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     616            sage: pm.heights_of_minus()
     617            [5, 5, 3, 3, 1, 1]
     618            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     619            sage: pm.heights_of_minus()
     620            [4, 4, 2, 2]
     621        """
     622        n = self.n
     623        heights = []
     624        for i in range(int((n+1)/2)):
     625            heights += [n-2*i]*((self.outer_shape()+[0]*n)[n-2*i-1]-(self.intermediate_shape()+[0]*n)[n-2*i-1])
     626        return heights
     627
     628    def heights_of_addable_plus(self):
     629        """
     630        Returns a list with the heights of all addable plus in the `\pm` diagram.
     631
     632        EXAMPLES::
     633
     634            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     635            sage: pm.heights_of_addable_plus()
     636            [1, 1, 2, 3, 4, 5]
     637            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     638            sage: pm.heights_of_addable_plus()
     639            [1, 2, 3, 4]
     640        """
     641        heights = []
     642        for i in range(1,self.n+1):
     643            heights += [i]*self.sigma().pm_diagram[i][0]
     644        return heights
     645
     646    def sigma(self):
     647        """
     648        Returns sigma on pm diagrams as needed for the analogue of the Dynkin diagram automorphism
     649        that interchanges nodes `0` and `1` for type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)` for
     650        Kirillov-Reshetikhin crystals.
     651
     652        EXAMPLES::
     653
     654            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     655            sage: pm.sigma().pm_diagram
     656            [[1, 0], [2, 1], [1]]
     657        """
     658        pm = self.pm_diagram
     659        return PMDiagram([list(reversed(a)) for a in pm])
     660
  • sage/combinat/crystals/tensor_product.py

    diff -r b583a3e2ef58 -r 5651ac1a05fb sage/combinat/crystals/tensor_product.py
    a b  
    413413            sage: T = TensorProductOfCrystals(C,C)
    414414            sage: T(C(1),C(2)).weight()
    415415            (1, 1, 0, 0)
     416            sage: T=CrystalOfTableaux(['D',4],shape=[])
     417            sage: T.list()[0].weight()
     418            (0, 0, 0, 0)
    416419        """
    417         return sum(self[j].weight() for j in range(len(self)))
     420        return sum((self[j].weight() for j in range(len(self))), self.parent().weight_lattice_realization().zero())
    418421
    419422    def f(self, i):
    420423        """