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

File affine-crystal-3663-as.3.patch, 64.3 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 1244228440 25200
    # Node ID 8834f10af344437a638c5a886f6361932bd0f6d2
    # Parent  685d6480cdddef3260e5e23fc4a459a59a54a819
    Implementation of affine crystals from classical crystals:
    - input is a classical crystal
    - an affine crystal can be constructed by providing the methods e0 and f0
    
    Implementation of affine crystals from classical crystal and promotion:
    - input is a classical crystal and a promotion operators which corresponds
      to a Dynkin diagram automorphism
    - the methods e0 and f0 are computed using the promotion operator
    
    Implementation of Kirillov Reshetikhin crystals:
    
    - Type A_n^{(1)} KR crystals are implemented.
    - Type D_n^{(1)}, B_n^{(1)}, A_{2n-1}^{(2)} KR crystals are implemented using plus-minus diagrams
      to construct the promotion operator which corresponds to interchanging nodes 0 and 1
    - Type C_n^{(1)} KR crystals are implemented; the methods e0 and f0 are constructed
      using an embedding into the ambient crystal of type A_{2n+1}^{(2)}
    
    diff --git a/sage/combinat/crystals/affine.py b/sage/combinat/crystals/affine.py
    new file mode 100644
    - +  
     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.misc.abstract_method import abstract_method
     25from sage.combinat.crystals.crystals import Crystal, ClassicalCrystal, CrystalElement
     26from sage.structure.unique_representation import UniqueRepresentation
     27from sage.structure.element_wrapper import ElementWrapper
     28from sage.combinat.root_system.cartan_type import CartanType
     29from sage.combinat.crystals.tensor_product import CrystalOfTableaux
     30from sage.combinat.tableau import Tableau_class
     31
     32class AffineCrystal(Crystal):
     33    r"""
     34    The abstract class of affine crystals
     35    """
     36 
     37class AffineCrystalFromClassical(Crystal, UniqueRepresentation):
     38    r"""
     39    This abstract class can be used for affine crystals that are constructed from a classical crystal.
     40    The zero arrows can be implemented using different methods (for example using a Dynkin diagram
     41    automorphisms or virtual crystals).
     42
     43    INPUT:
     44
     45    - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     46
     47    - ``classical_crystal`` - instance of a classical crystal.
     48
     49    EXAMPLES::
     50
     51        sage: n=2
     52        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     53        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     54        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     55        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     56        sage: A.list()
     57        [[[1]], [[2]], [[3]]]
     58        sage: A.cartan_type()
     59        ['A', 2, 1]
     60        sage: A.index_set()
     61        [0, 1, 2]
     62        sage: b=A(rows=[[1]])
     63        sage: b.weight()
     64        -Lambda[0] + Lambda[1]
     65        sage: b.classical_weight()
     66        (1, 0, 0)
     67        sage: [x.s(0) for x in A.list()]
     68        [[[3]], [[2]], [[1]]]
     69        sage: [x.s(1) for x in A.list()]
     70        [[[2]], [[1]], [[3]]]
     71    """
     72
     73    @staticmethod
     74    def __classcall__(cls, cartan_type, *args):
     75        ct = CartanType(cartan_type)
     76        return super(AffineCrystalFromClassical, cls).__classcall__(cls, ct, *args)
     77
     78    def __init__(self, cartan_type, classical_crystal):
     79        """
     80        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     81        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     82
     83        EXAMPLES::
     84
     85            sage: n=1
     86            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     87            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     88            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     89            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
     90            sage: A.list()
     91            [[[1]], [[2]]]
     92            sage: A.cartan_type()
     93            ['A', 1, 1]
     94            sage: A.index_set()
     95            [0, 1]
     96        """
     97        self._cartan_type = cartan_type
     98        if not hasattr(self, "_name"):
     99            self._name = "An affine crystal for type %s"%self.cartan_type()
     100        self.classical_crystal = classical_crystal;
     101        self.module_generators = map( self.retract, self.classical_crystal.module_generators )
     102
     103    def __iter__(self):
     104        r"""
     105        Construct the iterator from the underlying classical crystal.
     106
     107        TESTS::
     108
     109            sage: n=1
     110            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     111            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     112            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     113            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
     114            sage: A.__iter__()
     115            <generator object at 0x1064fd28>
     116        """
     117        for x in self.classical_crystal:
     118            yield self.retract(x)
     119
     120    # should be removed once crystal defines __iter__ instead of list
     121    def list(self):
     122        """
     123        Returns the list of all crystal elements using the underlying classical crystal
     124
     125        EXAMPLES::
     126
     127            sage: n=2
     128            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     129            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     130            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     131            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     132            sage: A.list()
     133            [[[1]], [[2]], [[3]]]
     134        """
     135        return map( self.retract, self.classical_crystal.list() )
     136       
     137    def lift(self, affine_elt):
     138        """
     139        Lifts an affine crystal element to the corresponding classical crystal element
     140
     141        EXAMPLES::
     142
     143            sage: n=2
     144            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     145            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     146            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     147            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     148            sage: b=A.list()[0]
     149            sage: type(A.lift(b))
     150            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     151        """
     152        return affine_elt.lift()
     153
     154    def retract(self, classical_elt):
     155        """
     156        Transforms a classical crystal element to the corresponding affine crystal element
     157
     158        EXAMPLES::
     159
     160            sage: n=2
     161            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     162            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     163            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     164            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     165            sage: t=C(rows=[[1]])
     166            sage: type(t)
     167            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     168            sage: A.retract(t)
     169            [[1]]
     170            sage: type(A.retract(t))
     171            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     172        """
     173        return self.element_class(classical_elt, parent = self)
     174   
     175    def __call__(self, *value, **options):
     176        r"""
     177        Coerces value into self.
     178
     179        EXAMPLES:
     180
     181            sage: n=2
     182            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     183            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     184            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     185            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     186            sage: b=A(rows=[[1]])
     187            sage: b
     188            [[1]]
     189            sage: type(b)
     190            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     191            sage: A(b)
     192            [[1]]
     193            sage: type(A(b))
     194            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     195        """
     196        if len(value) == 1 and isinstance(value[0], self.element_class) and value[0].parent() == self:
     197            return value[0]
     198        else: # Should do sanity checks!  (Including check for inconsistent parent.)
     199            return self.retract(self.classical_crystal(*value, **options))
     200
     201    def __contains__(self, x):
     202        r"""
     203        Checks whether x is an element of self.
     204
     205        EXAMPLES:
     206
     207            sage: n=2
     208            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     209            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     210            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     211            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     212            sage: b=A(rows=[[1]])
     213            sage: A.__contains__(b)
     214            True
     215        """
     216        return x.parent() is self
     217
     218
     219class AffineCrystalFromClassicalElement(ElementWrapper, CrystalElement):
     220    r"""
     221    Elements of crystals that are constructed from a classical crystal.
     222    The elements inherit many of their methods from the classical crystal
     223    using lift and retract.
     224
     225    This class is not instantiated directly but rather __call__ed from
     226    AffineCrystalFromClassical.  The syntax of this is governed by the
     227    (classical) CrystalOfTableaux.
     228
     229    EXAMPLES::
     230
     231        sage: n=2
     232        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     233        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     234        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     235        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     236        sage: b=A(rows=[[1]])
     237        sage: b.__repr__()
     238        '[[1]]'
     239    """
     240
     241    def classical_weight(self):
     242        """
     243        Returns the classical weight corresponding to self.
     244
     245        EXAMPLES::
     246
     247            sage: n=2
     248            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     249            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     250            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     251            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     252            sage: b=A(rows=[[1]])
     253            sage: b.classical_weight()
     254            (1, 0, 0)
     255        """
     256        return self.lift().weight()
     257
     258    def lift(self):
     259        """
     260        Lifts an affine crystal element to the corresponding classical crystal element
     261
     262        EXAMPLES::
     263
     264            sage: n=2
     265            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     266            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     267            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     268            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     269            sage: b=A.list()[0]
     270            sage: type(b.lift())
     271            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     272        """
     273        return self.value
     274
     275    @abstract_method
     276    def e0(self):
     277        r"""
     278        Assumes that `e_0` is implemented separately.
     279        """
     280
     281    @abstract_method
     282    def f0(self):
     283        r"""
     284        Assumes that `f_0` is implemented separately.
     285        """
     286
     287    def e(self, i):
     288        r"""
     289        Returns the action of `e_i` on self.
     290
     291        EXAMPLES::
     292
     293            sage: n=2
     294            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     295            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     296            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     297            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     298            sage: b=A(rows=[[1]])
     299            sage: b.e(0)
     300            [[3]]
     301            sage: b.e(1)
     302        """
     303        if i == 0:
     304            return self.e0()
     305        else:
     306            x = self.lift().e(i)
     307            if (x == None):
     308                return None
     309            else:
     310                return self.parent().retract(x)
     311
     312    def f(self, i):
     313        r"""
     314        Returns the action of `f_i` on self.
     315
     316        EXAMPLES::
     317
     318            sage: n=2
     319            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     320            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     321            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     322            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     323            sage: b=A(rows=[[3]])
     324            sage: b.f(0)
     325            [[1]]
     326            sage: b.f(2)
     327        """
     328        if i == 0:
     329            return self.f0()
     330        else:
     331            x = self.lift().f(i)
     332            if (x == None):
     333                return None
     334            else:
     335                return self.parent().retract(x)
     336
     337    def epsilon0(self):
     338        r"""
     339        Uses `epsilon_0` from the super class, but should be implemented if a faster implementation exists.
     340        """
     341        return super(AffineCrystalFromClassicalElement, self).epsilon(0)
     342
     343    def epsilon(self, i):
     344        """
     345        Returns the maximal time the crystal operator `e_i` can be applied to self.
     346
     347        EXAMPLES::
     348
     349            sage: n=2
     350            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     351            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     352            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     353            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     354            sage: [x.epsilon(0) for x in A.list()]
     355            [1, 0, 0]
     356            sage: [x.epsilon(1) for x in A.list()]
     357            [0, 1, 0]
     358        """
     359        if i == 0:
     360            return self.epsilon0()
     361        else:
     362            return self.lift().epsilon(i)
     363
     364    def phi0(self):
     365        r"""
     366        Uses `phi_0` from the super class, but should be implemented if a faster implementation exists.
     367        """
     368        return super(AffineCrystalFromClassicalElement, self).phi(0)
     369
     370    def phi(self, i):
     371        r"""
     372        Returns the maximal time the crystal operator `f_i` can be applied to self.
     373
     374        EXAMPLES::
     375
     376            sage: n=2
     377            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     378            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     379            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     380            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     381            sage: [x.phi(0) for x in A.list()]
     382            [0, 0, 1]
     383            sage: [x.phi(1) for x in A.list()]
     384            [1, 0, 0]
     385        """
     386        if i == 0:
     387            return self.phi0()
     388        else:
     389            return self.lift().phi(i)
     390
     391AffineCrystalFromClassical.element_class = AffineCrystalFromClassicalElement
     392
     393
     394class AffineCrystalFromClassicalAndPromotion(AffineCrystalFromClassical):
     395    r"""
     396    Crystals that are constructed from a classical crystal and a
     397    Dynkin diagram automorphism `\sigma`.  In type `A_n`, the Dynkin
     398    diagram automorphism is `i \to i+1 \pmod n+1` and the
     399    corresponding map on the crystal is the promotion operation
     400    `\mathrm{pr}` on tableaux. The affine crystal operators are given
     401    by `f_0= \mathrm{pr}^{-1} f_{\sigma(0)} \mathrm{pr}`.
     402
     403    INPUT:
     404
     405    - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     406
     407    - ``classical_crystal`` - instance of a classical crystal.
     408
     409    - ``automorphism, inverse_automorphism`` - A function on the
     410      elements of the classical_crystal
     411   
     412    - ``dynkin_node`` - Integer specifying the classical node in the
     413      image of the zero node under the automorphism sigma.
     414
     415    EXAMPLES::
     416
     417        sage: n=2
     418        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     419        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     420        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     421        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     422        sage: A.list()
     423        [[[1]], [[2]], [[3]]]
     424        sage: A.cartan_type()
     425        ['A', 2, 1]
     426        sage: A.index_set()
     427        [0, 1, 2]
     428        sage: b=A(rows=[[1]])
     429        sage: b.weight()
     430        -Lambda[0] + Lambda[1]
     431        sage: b.classical_weight()
     432        (1, 0, 0)
     433        sage: [x.s(0) for x in A.list()]
     434        [[[3]], [[2]], [[1]]]
     435        sage: [x.s(1) for x in A.list()]
     436        [[[2]], [[1]], [[3]]]
     437    """
     438
     439    def __init__(self, cartan_type, classical_crystal, p_automorphism, p_inverse_automorphism, dynkin_node):
     440        """
     441        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     442        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     443
     444        EXAMPLES::
     445
     446            sage: n=1
     447            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     448            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     449            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     450            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     451            sage: A.list()
     452            [[[1]], [[2]]]
     453            sage: A.cartan_type()
     454            ['A', 1, 1]
     455            sage: A.index_set()
     456            [0, 1]
     457        """
     458        AffineCrystalFromClassical.__init__(self, cartan_type, classical_crystal)
     459        self.p_automorphism = p_automorphism
     460        self.p_inverse_automorphism = p_inverse_automorphism
     461        self.dynkin_node = dynkin_node
     462
     463    def automorphism(self, x):
     464        """
     465        Gives the analogue of the affine Dynkin diagram automorphism on the level of crystals
     466
     467        EXAMPLES::
     468
     469            sage: n=2
     470            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     471            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     472            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     473            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     474            sage: b=A.list()[0]
     475            sage: A.automorphism(b)
     476            [[2]]
     477        """
     478        return self.retract( self.p_automorphism( x.lift() ) )
     479
     480    def inverse_automorphism(self, x):
     481        """
     482        Gives the analogue of the inverse of the affine Dynkin diagram automorphism on the level of crystals
     483
     484        EXAMPLES::
     485
     486            sage: n=2
     487            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     488            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     489            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     490            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     491            sage: b=A.list()[0]
     492            sage: A.inverse_automorphism(b)
     493            [[3]]
     494        """
     495        return self.retract( self.p_inverse_automorphism( x.lift() ) )
     496
     497class AffineCrystalFromClassicalAndPromotionElement(AffineCrystalFromClassicalElement):
     498    r"""
     499    Elements of crystals that are constructed from a classical crystal
     500    and a Dynkin diagram automorphism.  In type A, the automorphism is
     501    the promotion operation on tableaux.
     502
     503    This class is not instantiated directly but rather __call__ed from
     504    AffineCrystalFromClassicalAndPromotion.  The syntax of this is governed by the
     505    (classical) CrystalOfTableaux.
     506
     507    Since this class inherits from AffineClassicalFromClassicalElement, the methods
     508    that need to be implemented are e0, f0 and possibly epsilon0 and phi0 if more efficient
     509    algorithms exist.
     510
     511    EXAMPLES::
     512
     513        sage: n=2
     514        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     515        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     516        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     517        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     518        sage: b=A(rows=[[1]])
     519        sage: b.__repr__()
     520        '[[1]]'
     521    """
     522
     523    def e0(self):
     524        r"""
     525        Implements `e_0` using the automorphism as
     526        `e_0 = \pr^{-1} e_{dynkin_node} \pr`
     527
     528        EXAMPLES::
     529
     530            sage: n=2
     531            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     532            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     533            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     534            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     535            sage: b=A(rows=[[1]])
     536            sage: b.e0()
     537            [[3]]
     538        """
     539        x = self.parent().automorphism(self).e(self.parent().dynkin_node)
     540        if (x == None):
     541            return None
     542        else:
     543            return self.parent().inverse_automorphism(x)
     544
     545    def f0(self):
     546        r"""
     547        Implements `f_0` using the automorphism as
     548        `f_0 = \pr^{-1} f_{dynkin_node} \pr`
     549
     550        EXAMPLES::
     551
     552            sage: n=2
     553            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     554            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     555            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     556            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     557            sage: b=A(rows=[[3]])
     558            sage: b.f0()
     559            [[1]]
     560        """
     561        x = self.parent().automorphism(self).f(self.parent().dynkin_node)
     562        if (x == None):
     563            return None
     564        else:
     565            return self.parent().inverse_automorphism(x)
     566
     567    def epsilon0(self):
     568        r"""
     569        Implements `epsilon_0` using the automorphism.
     570
     571        EXAMPLES::
     572
     573            sage: n=2
     574            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     575            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     576            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     577            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     578            sage: [x.epsilon0() for x in A.list()]
     579            [1, 0, 0]
     580        """
     581        x = self.parent().automorphism(self)
     582        return x.lift().epsilon(self.parent().dynkin_node)
     583
     584    def phi0(self):
     585        r"""
     586        Implements `phi_0` using the automorphism.
     587
     588        EXAMPLES::
     589
     590            sage: n=2
     591            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     592            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     593            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     594            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     595            sage: [x.phi0() for x in A.list()]
     596            [0, 0, 1]
     597        """
     598        x = self.parent().automorphism(self)
     599        return x.lift().phi(self.parent().dynkin_node)
     600
     601AffineCrystalFromClassicalAndPromotion.element_class = AffineCrystalFromClassicalAndPromotionElement
     602
     603
     604# class AffineCrystalFromClassicalAndVirtual(AffineCrystalFromClassical):
     605#     r"""
     606#     Crystals that are constructed from a classical crystal and an
     607#     embedding into an ambient crystal.
     608
     609#     See for example:
     610
     611#     M. Okado, A. Schilling, M. Shimozono, "Virtual crystals and Kleber's algorithm",
     612#     Commun. Math. Phys. 238 (2003) 187-209 ( math.QA/0209082 )
     613
     614#     As an example, the affine crystal `B^{r,s}` of type `C_n^{(1)}`
     615#     can be obtained from the ambient crystal `B^{r,s}` of type
     616#     `A_{2n+1}^{(2)}` identifying the crystal operator `f_0` (respectively
     617#     `f_i`) of type `C_n^{(1)}` with `f_0 f_1` (respectively `f_{i+1}`) in
     618#     the ambient crystal. See Section 4.3 of G. Fourier, M. Okado, A. Schilling,
     619#     "Kirillov-Reshetikhin crystals for nonexceptional types"
     620#     Advances in Math., to appear (arXiv:0810.5067 [math.RT]).
     621
     622#     INPUT:
     623
     624#     - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     625
     626#     - ``classical_crystal`` - instance of a classical crystal.
     627
     628#     - ``ambient_crystal`` - the ambient crystal which defines the zero arrows
     629
     630#     - ``similarity_matrix`` - gives the relation between `f_i` in the virtual crystal
     631#                               and the `f_j` in the ambient crystal
     632
     633#     EXAMPLES::
     634
     635#         XXXXX
     636#     """
     637
     638#     def __init__(self, cartan_type, classical_crystal, p_automorphism, p_inverse_automorphism, dynkin_node):
     639#       """
     640#       Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     641#       inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     642
     643#       EXAMPLES::
     644
     645#             sage: n=1
     646#           sage: C=CrystalOfTableaux(['A',n],shape=[1])
     647#           sage: pr=lambda x : C(x.to_tableau().promotion(n))
     648#           sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     649#           sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     650#           sage: A.list()
     651#           [[[1]], [[2]]]
     652#           sage: A.cartan_type()
     653#           ['A', 1, 1]
     654#           sage: A.index_set()
     655#           [0, 1]
     656#       """
     657#       AffineCrystalFromClassical.__init__(self, cartan_type, classical_crystal)
     658#         self.p_automorphism = p_automorphism
     659#         self.p_inverse_automorphism = p_inverse_automorphism
     660#       self.dynkin_node = dynkin_node
  • sage/combinat/crystals/all.py

    diff --git a/sage/combinat/crystals/all.py b/sage/combinat/crystals/all.py
    a b from spins import CrystalOfSpinsMinus 
    66from tensor_product import TensorProductOfCrystals
    77from tensor_product import CrystalOfTableaux
    88from fast_crystals import FastCrystal
     9from affine import AffineCrystalFromClassical
     10from affine import AffineCrystalFromClassicalAndPromotion
     11from kirillov_reshetikhin import KirillovReshetikhinCrystal
  • sage/combinat/crystals/crystals.py

    diff --git a/sage/combinat/crystals/crystals.py b/sage/combinat/crystals/crystals.py
    a b inspiration. 
    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
    class Crystal(CombinatorialClass, Parent 
    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        """
    class Crystal(CombinatorialClass, Parent 
    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()
    class Crystal(CombinatorialClass, Parent 
    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.
    class CrystalElement(Element): 
    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::
    class CrystalElement(Element): 
    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):
    class CrystalElement(Element): 
    795880                b = b.e(i)
    796881        return b
    797882
    798     def is_highest_weight(self):
     883    def is_highest_weight(self, index_set = None):
    799884        r"""
    800885        Returns True if self is a highest weight.
     886        Specifying the option index_set to be a subset `I` of the index set
     887        of the underlying crystal, finds all highest weight vectors for arrows in `I`.
    801888       
    802889        EXAMPLES::
    803890       
    class CrystalElement(Element): 
    806893            True
    807894            sage: C(2).is_highest_weight()
    808895            False
     896            sage: C(2).is_highest_weight(index_set = [2,3,4,5])
     897            True
    809898        """
    810         return all(self.e(i) == None for i in self.index_set())
     899        if index_set is None:
     900            index_set = self.index_set()
     901        return all(self.e(i) == None for i in index_set)
    811902
    812903class CrystalBacktracker(GenericBacktracker):
    813904    def __init__(self, crystal):
  • new file sage/combinat/crystals/kirillov_reshetikhin.py

    diff --git a/sage/combinat/crystals/kirillov_reshetikhin.py b/sage/combinat/crystals/kirillov_reshetikhin.py
    new file mode 100644
    - +  
     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.affine import AffineCrystalFromClassicalAndPromotion, AffineCrystalFromClassicalAndPromotionElement
     29#from sage.combinat.crystals.affine import AffineCrystalFromClassicalAndVirtual, AffineCrystalFromClassicalAndVirtualElement
     30from sage.combinat.root_system.cartan_type import CartanType
     31from sage.combinat.crystals.tensor_product import CrystalOfTableaux
     32from sage.combinat.tableau import Tableau_class, Tableau
     33from sage.combinat.partition import Partition, Partitions
     34from sage.combinat.integer_vector import IntegerVectors
     35
     36
     37def KirillovReshetikhinCrystal(cartan_type, r, s):
     38    r"""
     39    Returns the Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     40
     41    Many Kirillov-Reshetikhin crystals are constructed from a
     42    classical crystal together with an automorphism `p` on the level of crystals which
     43    corresponds to a Dynkin diagram automorphism mapping node 0 to some other node i.
     44    The action of `f_0` and `e_0` is then constructed using
     45    `f_0 = p^{-1} \circ f_i \circ p`.
     46
     47    For example, for type `A_n^{(1)}` the Kirillov-Reshetikhin crystal `B^{r,s}`
     48    is obtained from the classical crystal `B(s\omega_r)` using the
     49    promotion operator. For other types, see
     50
     51    M. Shimozono
     52    "Affine type A crystal structure on tensor products of rectangles,
     53    Demazure characters, and nilpotent varieties",
     54    J. Algebraic Combin.  15  (2002),  no. 2, 151-187
     55    (arXiv:math.QA/9804039)
     56
     57    A. Schilling, "Combinatorial structure of Kirillov-Reshetikhin crystals of
     58    type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     59    (arXiv:0704.2046 [math.QA])
     60
     61    G. Fourier, M. Okado, A. Schilling,
     62    "Kirillov-Reshetikhin crystals for nonexceptional types"
     63    Advances in Math., to appear (arXiv:0810.5067 [math.RT])
     64
     65    INPUT:
     66
     67        - ``cartan_type`` Affine type and rank
     68
     69        - ``r`` Label of finite Dynkin diagram
     70
     71        - ``s`` Positive integer
     72
     73    EXAMPLES::
     74   
     75        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2, 1)
     76        sage: K.index_set()
     77        [0, 1, 2, 3]
     78        sage: K.list()
     79        [[[1], [2]], [[1], [3]], [[2], [3]], [[1], [4]], [[2], [4]], [[3], [4]]]
     80        sage: b=K(rows=[[1],[2]])
     81        sage: b.weight()
     82        -Lambda[0] + Lambda[2]
     83
     84        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     85        sage: K.automorphism(K.module_generators[0])
     86        [[2, 2], [3, 3]]
     87        sage: K.module_generators[0].e(0)
     88        [[1, 2], [2, 4]]
     89        sage: K.module_generators[0].f(2)
     90        [[1, 1], [2, 3]]
     91        sage: K.module_generators[0].f(1)
     92        sage: K.module_generators[0].phi(0)
     93        0
     94        sage: K.module_generators[0].phi(1)
     95        0
     96        sage: K.module_generators[0].phi(2)
     97        2
     98        sage: K.module_generators[0].epsilon(0)
     99        2
     100        sage: K.module_generators[0].epsilon(1)
     101        0
     102        sage: K.module_generators[0].epsilon(2)
     103        0
     104        sage: b = K(rows=[[1,2],[2,3]])
     105        sage: b
     106        [[1, 2], [2, 3]]
     107        sage: b.f(2)
     108        [[1, 2], [3, 3]]
     109
     110        sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     111        sage: K.cartan_type()
     112        ['D', 4, 1]
     113        sage: type(K.module_generators[0])
     114        <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     115    """
     116    ct = CartanType(cartan_type)
     117    assert ct.is_affine()
     118    if ct.is_untwisted_affine():
     119        if ct.type() == 'A':
     120            return KR_type_A(ct, r, s)
     121        elif ct.type() == 'D' and r<ct.rank()-2:
     122            return KR_type_vertical(ct, r, s)
     123        elif ct.type() == 'B' and r<ct.rank()-1:
     124            return KR_type_vertical(ct, r, s)
     125        elif ct.type() == 'C' and r<ct.rank()-1:
     126            return KR_type_C(ct, r, s)
     127        else:
     128            raise NotImplementedError
     129    else:
     130        if ct.dual().type() == 'B':
     131            return KR_type_vertical(ct, r, s)
     132        else:
     133            raise NotImplementedError
     134
     135
     136class KirillovReshetikhinGenericCrystal(AffineCrystal):
     137    r"""
     138    Generic class for Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     139
     140    Input is a Dynkin node `r`, a positive integer `s`, and a Cartan type `cartan_type`.
     141    """
     142    def __init__(self, cartan_type, r, s):
     143        r"""
     144        Initializes a generic Kirillov-Reshetikhin crystal.
     145
     146        TESTS::
     147
     148            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KirillovReshetikhinGenericCrystal(['A',2,1], 1, 1)
     149            sage: K
     150            Kirillov-Reshetikhin crystal of type ['A', 2, 1] with (r,s)=(1,1)
     151            sage: K.r()
     152            1
     153            sage: K.s()
     154            1
     155        """
     156        self._cartan_type = CartanType(cartan_type)
     157        self._r = r
     158        self._s = s
     159        self._name = "Kirillov-Reshetikhin crystal of type %s with (r,s)=(%d,%d)" % (cartan_type, r, s)
     160
     161    def r(self):
     162        """
     163        Returns r of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     164
     165        EXAMPLE::
     166
     167            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     168            sage: K.r()
     169            2
     170        """
     171        return self._r
     172   
     173    def s(self):
     174        """
     175        Returns s of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     176
     177        EXAMPLE::
     178
     179            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     180            sage: K.s()
     181            1
     182        """
     183        return self._s
     184
     185
     186class KirillovReshetikhinCrystalFromPromotion(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassicalAndPromotion):
     187    r"""
     188    This generic class assumes that the Kirillov-Reshetikhin crystal is constructed
     189    from a classical crystal 'classical_decomposition' and an automorphism 'promotion' and its inverse
     190    which corresponds to a Dynkin diagram automorphism 'dynkin_diagram_automorphism'.
     191
     192    Each instance using this class needs to implement the methods:
     193    - classical_decomposition
     194    - promotion
     195    - promotion_inverse
     196    - dynkin_diagram_automorphism
     197    """
     198    def __init__(self, cartan_type, r, s):
     199        r"""
     200        TESTS::
     201
     202            sage: K = KirillovReshetikhinCrystal(['B',2,1], 1, 1)
     203            sage: K
     204            Kirillov-Reshetikhin crystal of type ['B', 2, 1] with (r,s)=(1,1)
     205        """
     206        KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     207        AffineCrystalFromClassicalAndPromotion.__init__(self, cartan_type, self.classical_decomposition(),
     208                                                        self.promotion(), self.promotion_inverse(),
     209                                                        self.dynkin_diagram_automorphism(0))
     210
     211
     212class KR_type_A(KirillovReshetikhinCrystalFromPromotion):
     213    r"""
     214    Class of Kirillov-Reshetikhin crystals of type `A_n^{(1)}`.
     215
     216    EXAMPLES::
     217
     218        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     219        sage: b = K(rows=[[1,2],[2,4]])
     220        sage: b.f(0)
     221        [[1, 1], [2, 2]]
     222    """
     223
     224    def classical_decomposition(self):
     225        """
     226        Specifies the classical crystal underlying the KR crystal of type A.
     227
     228        EXAMPLES::
     229
     230            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     231            sage: K.classical_decomposition()
     232            The crystal of tableaux of type ['A', 3] and shape(s) ([2, 2],)
     233        """
     234        return CrystalOfTableaux(self.cartan_type().classical(), shape = [self.s() for i in range(1,self.r()+1)])
     235   
     236    def promotion(self):
     237        """
     238        Specifies the promotion operator used to construct the affine type A crystal.
     239        For type A this corresponds to the Dynkin diagram automorphism which maps i to i+1 mod n+1,
     240        where n is the rank.
     241
     242        EXAMPLES:
     243
     244            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     245            sage: b = K.classical_decomposition()(rows=[[1,2],[3,4]])
     246            sage: K.promotion()(b)
     247            [[1, 3], [2, 4]]
     248        """
     249        return lambda x : self.classical_crystal(x.to_tableau().promotion(self._cartan_type[1]))
     250   
     251    def promotion_inverse(self):
     252        """
     253        Specifies the inverse promotion operator used to construct the affine type A crystal.
     254        For type A this corresponds to the Dynkin diagram automorphism which maps i to i-1 mod n+1,
     255        where n is the rank.
     256
     257        EXAMPLES:
     258
     259            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     260            sage: b = K.classical_decomposition()(rows=[[1,3],[2,4]])
     261            sage: K.promotion_inverse()(b)
     262            [[1, 2], [3, 4]]
     263            sage: b = K.classical_decomposition()(rows=[[1,2],[3,3]])
     264            sage: K.promotion_inverse()(K.promotion()(b))
     265            [[1, 2], [3, 3]]
     266        """
     267        return lambda x : self.classical_crystal(x.to_tableau().promotion_inverse(self._cartan_type[1]))
     268
     269    def dynkin_diagram_automorphism(self, i):
     270        """
     271        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     272        elements. The automorphism needs to map node 0 to some other Dynkin node.
     273
     274        For type A we use the Dynkin diagram automorphism which maps i to i+1 mod n+1, where n is the rank.
     275
     276        EXAMPLES::
     277       
     278            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     279            sage: K.dynkin_diagram_automorphism(0)
     280            1
     281            sage: K.dynkin_diagram_automorphism(3)
     282            0
     283        """
     284        aut = range(1,self.cartan_type().rank())+[0]
     285        return aut[i]
     286
     287class KR_type_vertical(KirillovReshetikhinCrystalFromPromotion):
     288    r"""
     289    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `D_n^{(1)}` for `r\le n-2`,
     290    `B_n^{(1)}` for `r<n`, and `A_{2n-1}^{(2)}` for `r\le n`.
     291
     292    EXAMPLES::
     293
     294        sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     295        sage: b = K(rows=[])
     296        sage: b.f(0)
     297        [[1], [2]]
     298        sage: b.f(0).f(0)
     299        [[1, 1], [2, 2]]
     300        sage: b.e(0)
     301        [[-2], [-1]]
     302        sage: b.e(0).e(0)
     303        [[-2, -2], [-1, -1]]
     304
     305        sage: K = KirillovReshetikhinCrystal(['B',3,1], 1,1)
     306        sage: [[b,b.f(0)] for b in K]
     307        [[[[1]], None], [[[2]], None], [[[3]], None], [[[0]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     308
     309        sage: K = KirillovReshetikhinCrystal(['A',5,2], 1,1)
     310        sage: [[b,b.f(0)] for b in K]
     311        [[[[1]], None], [[[2]], None], [[[3]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     312    """
     313 
     314    def classical_decomposition(self):
     315        r"""
     316        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `D_n^{(1)}`,
     317        `B_n^{(1)}`, and `A_{2n}^{(2)}`.
     318        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     319        a rectangle of width s and height r by removing verticle dominoes. Here we identify the fundamental
     320        weight `\Lambda_i` with a column of height `i`.
     321
     322        EXAMPLES::
     323
     324            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     325            sage: K.classical_decomposition()
     326            The crystal of tableaux of type ['D', 4] and shape(s) [[], [1, 1], [2, 2]]
     327        """
     328        return CrystalOfTableaux(self.cartan_type().classical(),
     329                                 shapes = vertical_dominoes_removed(self.r(),self.s()))
     330   
     331    def promotion(self):
     332        """
     333        Specifies the promotion operator used to construct the affine type 'D_n^{(1)}` crystal.
     334        For type D, this corresponds to the Dynkin diagram automorphism which interchanges nodes 0 and 1,
     335        and leaves all other nodes unchanged. On the level of crystals it is constructed using
     336        `\pm` diagrams.
     337
     338        EXAMPLES:
     339
     340            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     341            sage: promotion = K.promotion()
     342            sage: b = K.classical_decomposition()(rows=[])
     343            sage: promotion(b)
     344            [[1, 2], [-2, -1]]
     345            sage: b = K.classical_decomposition()(rows=[[1,3],[2,-1]])
     346            sage: promotion(b)
     347            [[1, 3], [2, -1]]
     348            sage: b = K.classical_decomposition()(rows=[[1],[-3]])
     349            sage: promotion(b)
     350            [[2, -3], [-2, -1]]
     351        """
     352        T = self.classical_decomposition()
     353        ind = T.index_set()
     354        ind.remove(1)
     355        return T.crystal_morphism( self.promotion_on_highest_weight_vectors(), index_set = ind)
     356   
     357    promotion_inverse = promotion
     358   
     359    def dynkin_diagram_automorphism(self, i):
     360        """
     361        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     362        elements. The automorphism needs to map node 0 to some other Dynkin node.
     363
     364        For type D we use the Dynkin diagram automorphism which interchanges nodes 0 and 1 and leaves
     365        all other nodes unchanged.
     366
     367        EXAMPLES::
     368       
     369            sage: K = KirillovReshetikhinCrystal(['D',4,1],1,1)
     370            sage: K.dynkin_diagram_automorphism(0)
     371            1
     372            sage: K.dynkin_diagram_automorphism(1)
     373            0
     374            sage: K.dynkin_diagram_automorphism(4)
     375            4
     376        """
     377        aut = [1,0]+range(2,self.cartan_type().rank())
     378        return aut[i]
     379
     380    def promotion_on_highest_weight_vectors(self):
     381        """
     382        Calculates promotion on `{2,3,...,n}` highest weight vectors.
     383
     384        EXAMPLES::
     385
     386            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     387            sage: T = K.classical_decomposition()
     388            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     389            sage: [K.promotion_on_highest_weight_vectors()(b) for b in hw]
     390            [[[1, 2], [-2, -1]], [[2, 2], [-2, -1]], [[1, 2], [3, -1]], [[2], [-2]],
     391            [[1, 2], [2, -2]], [[2, 2], [-1, -1]], [[2, 2], [3, -1]], [[2, 2], [3, 3]],
     392            [], [[1], [2]], [[1, 1], [2, 2]], [[2], [-1]], [[1, 2], [2, -1]], [[2], [3]],
     393            [[1, 2], [2, 3]]]
     394        """
     395        return lambda b: self.from_pm_diagram_to_highest_weight_vector(self.from_highest_weight_vector_to_pm_diagram(b).sigma())
     396
     397    def from_highest_weight_vector_to_pm_diagram(self, b):
     398        """
     399        This gives the bijection between an element b in the classical decomposition
     400        of the KR crystal that is `{2,3,..,n}`-highest weight and `\pm` diagrams.
     401
     402        EXAMPLES::
     403
     404            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     405            sage: T = K.classical_decomposition()
     406            sage: b = T(rows=[[2],[-2]])
     407            sage: pm = K.from_highest_weight_vector_to_pm_diagram(b); pm
     408            [[1, 1], [0, 0], [0]]
     409            sage: pm.__repr__(pretty_printing=True)
     410            +
     411            -
     412            sage: b = T(rows=[])
     413            sage: pm=K.from_highest_weight_vector_to_pm_diagram(b); pm
     414            [[0, 2], [0, 0], [0]]
     415            sage: pm.__repr__(pretty_printing=True)
     416
     417            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     418            sage: all(K.from_pm_diagram_to_highest_weight_vector(K.from_highest_weight_vector_to_pm_diagram(b)) == b for b in hw)
     419            True
     420        """
     421        n = self.cartan_type().rank()-1
     422        inner = Partition([Integer(b.weight()[i]) for i in range(1,n+1)])
     423        inter = Partition([len([i for i in r if i>0]) for r in b.to_tableau()])
     424        outer = b.to_tableau().shape()
     425        return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True)
     426 
     427    def from_pm_diagram_to_highest_weight_vector(self, pm):
     428        """
     429        This gives the bijection between a `\pm` diagram and an element b in the classical
     430        decomposition of the KR crystal that is {2,3,..,n}-highest weight.
     431
     432        EXAMPLES::
     433
     434            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     435            sage: pm = sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1, 1], [0, 0], [0]])
     436            sage: K.from_pm_diagram_to_highest_weight_vector(pm)
     437            [[2], [-2]]
     438        """
     439        u = [b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()][0]
     440        ct = self.cartan_type()
     441        rank = ct.rank()-1
     442        ct_type = ct.classical().type()
     443        assert ct_type in ['B', 'C', 'D']
     444        list = []
     445        for h in pm.heights_of_addable_plus():
     446            list += range(1,h+1)
     447        for h in pm.heights_of_minus():
     448            if ct_type == 'D':
     449                list += range(1,rank+1)+[rank-2-k for k in range(rank-1-h)]
     450            elif ct_type == 'B':
     451                list += range(1,rank+1)+[rank-k for k in range(rank+1-h)]
     452            else:
     453                list += range(1,rank+1)+[rank-1-k for k in range(rank-h)]
     454        for i in reversed(list):
     455            u = u.f(i)
     456        return u
     457
     458
     459# class KirillovReshetikhinCrystalFromVirtual(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassicalAndVirtual):
     460#     r"""
     461#     This generic class assumes that the Kirillov-Reshetikhin crystal is constructed
     462#     from a classical crystal 'classical_decomposition' and an embedding into a virtual crystal.
     463
     464#     Each instance using this class needs to implement the methods:
     465#     - classical_decomposition
     466#     - virtual_embedding
     467#     - XXXXXXXXXXXXX
     468#     """
     469#     def __init__(self, cartan_type, r, s):
     470#       KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     471#       AffineCrystalFromClassicalAndVirtual.__init__(self, cartan_type, self.classical_decomposition(),
     472#                                                     self.virtual_embedding())
     473
     474class KR_type_C(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassical):
     475    r"""
     476    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `C_n^{(1)}` for `r<n`.
     477
     478    EXAMPLES::
     479
     480        sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     481        sage: K
     482        Kirillov-Reshetikhin crystal of type ['C', 2, 1] with (r,s)=(1,2)
     483        sage: b = K(rows=[])
     484        sage: b.f(0)
     485        [[1, 1]]
     486        sage: b.e(0)
     487        [[-1, -1]]
     488    """
     489    def __init__(self, cartan_type, r, s):
     490        r"""
     491        Initializes a Kirillov-Reshetikhin crystal of type `C_n^{(1)}`.
     492
     493        TESTS::
     494
     495            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KR_type_C(['C',2,1], 1, 1)
     496            sage: K
     497            Kirillov-Reshetikhin crystal of type ['C', 2, 1] with (r,s)=(1,1)
     498        """
     499        KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     500        AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition())
     501
     502    def classical_decomposition(self):
     503        """
     504        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `C_n^{(1)}`.
     505        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     506        a rectangle of width s and height r by removing horizontal dominoes. Here we identify the fundamental
     507        weight `\Lambda_i` with a column of height `i`.
     508
     509        EXAMPLES::
     510
     511            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     512            sage: K.classical_decomposition()
     513            The crystal of tableaux of type ['C', 3] and shape(s) [[], [2], [2, 2]]
     514        """
     515        return CrystalOfTableaux(self.cartan_type().classical(),
     516                                 shapes = horizontal_dominoes_removed(self.r(),self.s()))
     517
     518    def ambient_crystal(self):
     519        r"""
     520        Returns the ambient crystal `'B^{r,s}` of type `A_{2n+1}^{(2)}` associated to the Kirillov-Reshetikhin
     521        crystal of type `C_n^{(1)}`. This ambient crystal is used to construct the zero arrows.
     522
     523        EXAMPLES::
     524
     525            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,3)
     526            sage: K.ambient_crystal()
     527            Kirillov-Reshetikhin crystal of type ['B', 4, 1]^* with (r,s)=(2,3)
     528        """
     529        return KirillovReshetikhinCrystal(['A',2*self.cartan_type().classical().rank()+1,2], self.r(), self.s())
     530
     531    def ambient_dict_pm_diagrams(self):
     532        r"""
     533        Gives a dictionary of all self-dual `\pm` diagrams for the ambient crystal.
     534        Their key is their inner shape.
     535
     536        EXAMPLES::
     537
     538            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     539            sage: K.ambient_dict_pm_diagrams()
     540            {[]: [[1, 1], [0]], [2]: [[0, 0], [2]]}
     541            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     542            sage: K.ambient_dict_pm_diagrams()
     543            {[2, 2]: [[0, 0], [0, 0], [2]], []: [[1, 1], [0, 0], [0]], [2]: [[0, 0], [1, 1], [0]]}
     544            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,3)
     545            sage: K.ambient_dict_pm_diagrams()
     546            {[3, 3]: [[0, 0], [0, 0], [3]], [3, 1]: [[0, 0], [1, 1], [1]], [1, 1]: [[1, 1], [0, 0], [1]]}
     547        """
     548        list = []
     549        s = self.s()
     550        r = self.r()
     551        m = int(s/2)
     552        for i in range(m+1):
     553            for la in IntegerVectors(m-i, min_length=r, max_length=r):
     554                list.append(PMDiagram([[j,j] for j in la]+[[s-2*m+2*i]]))
     555        return dict( (x.inner_shape(), x) for x in list )
     556
     557    def ambient_highest_weight_dict(self):
     558        r"""
     559        Gives a dictionary of all `{2,...,n+1}`-highest weight vectors in the ambient crystal.
     560        Their key is the inner shape of their corresponding `\pm` diagram, or equivalently, their
     561        `{2,...,n+1}` weight.
     562
     563        EXAMPLES::
     564
     565            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     566            sage: K.ambient_highest_weight_dict()
     567            {[]: [[2], [-2]], [2, 2]: [[2, 2], [3, 3]], [2]: [[1, 2], [2, -1]]}
     568        """
     569        A = self.ambient_dict_pm_diagrams()
     570        ambient = self.ambient_crystal()
     571        return dict( (key, ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key]))) for key in A )
     572
     573    def highest_weight_dict(self):
     574        r"""
     575        Gives a dictionary of the classical highest weight vectors of self.
     576        Their key is their shape.
     577
     578        EXAMPLES::
     579
     580            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     581            sage: K.highest_weight_dict()
     582            {[2, 2]: [[1, 1], [2, 2]], []: [], [2]: [[1, 1]]}
     583        """
     584        return dict( (x.lift().to_tableau().shape(),x) for x in self.module_generators )
     585
     586    def to_ambient_crystal(self):
     587        r"""
     588        Provides a map from the Kirillov-Reshetikhin crystal of type `C_n^{(1)}` to the
     589        ambient crystal of type `A_{2n+1}^{(2)}`.
     590
     591        EXAMPLES::
     592
     593            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     594            sage: b=K(rows=[[1,1]])
     595            sage: K.to_ambient_crystal()(b)
     596            [[1, 2], [2, -1]]
     597            sage: b=K(rows=[])
     598            sage: K.to_ambient_crystal()(b)
     599            [[2], [-2]]
     600            sage: type(K.to_ambient_crystal()(b))
     601            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     602        """
     603        keys = self.highest_weight_dict().keys()
     604        pdict = dict( (self.highest_weight_dict()[key], self.ambient_highest_weight_dict()[key]) for key in keys )
     605        return self.crystal_morphism( pdict, index_set = self.cartan_type().classical().index_set(),
     606                                      automorphism = lambda i : i+1 )
     607
     608    def from_ambient_crystal(self):
     609        r"""
     610        Provides a map from the ambient crystal of type `A_{2n+1}^{(2)}` to the Kirillov-Reshetikhin crystal of
     611        type `C_n^{(1)}`. Note that this map is only well-defined on elements that are in the image
     612        type `C_n^{(1)}` elements under `to_ambient_crystal'.
     613
     614        EXAMPLES::
     615
     616            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     617            sage: b=K.ambient_crystal()(rows=[[2,2],[3,3]])
     618            sage: K.from_ambient_crystal()(b)
     619            [[1, 1], [2, 2]]
     620        """
     621        keys = self.highest_weight_dict().keys()
     622        pdict_inv = dict( (self.ambient_highest_weight_dict()[key], self.highest_weight_dict()[key]) for key in keys )
     623        return self.crystal_morphism( pdict_inv, index_set = [j+1 for j in self.cartan_type().classical().index_set()],
     624                                      automorphism = lambda i : i-1 )
     625
     626class KR_type_CElement(AffineCrystalFromClassicalElement):
     627    r"""
     628    Class for the elements in the Kirillov-Reshetikhin crystals `B^{r,s}` of type `C_n^{(1)}` for `r<n`.
     629
     630    EXAMPLES::
     631
     632        sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     633        sage: type(K.module_generators[0])
     634        <class 'sage.combinat.crystals.kirillov_reshetikhin.KR_type_CElement'>
     635    """
     636
     637    def e0(self):
     638        r"""
     639        Gives `e_0` on self by mapping self to the ambient crystal, calculating `e_1 e_0` there and
     640        pulling the element back.
     641
     642        EXAMPLES::
     643
     644            sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     645            sage: b = K(rows=[])
     646            sage: b.e(0)
     647            [[-1, -1]]
     648        """
     649        b = self.parent().to_ambient_crystal()(self).e(1)
     650        if b is None:
     651            return None
     652        b = b.e(0)
     653        return self.parent().from_ambient_crystal()(b)
     654   
     655    def f0(self):
     656        r"""
     657        Gives `f_0` on self by mapping self to the ambient crystal, calculating `f_1 f_0` there and
     658        pulling the element back.
     659
     660        EXAMPLES::
     661
     662            sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     663            sage: b = K(rows=[])
     664            sage: b.f(0)
     665            [[1, 1]]
     666        """
     667        b = self.parent().to_ambient_crystal()(self).f(1)
     668        if b is None:
     669            return None
     670        b = b.f(0)
     671        return self.parent().from_ambient_crystal()(b)
     672
     673    def epsilon0(self):
     674        r"""
     675        Calculates `\epsilon_0` of self by mapping the element to the ambient crystal
     676        and calculating `\epsilon_1` there.
     677
     678        EXAMPLES::
     679
     680            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     681            sage: b=K(rows=[[1,1]])
     682            sage: b.epsilon(0)
     683            2
     684        """
     685        b = self.parent().to_ambient_crystal()(self)
     686        return b.epsilon(1)
     687
     688    def phi0(self):
     689        r"""
     690        Calculates `\phi_0` of self by mapping the element to the ambient crystal
     691        and calculating `\phi_1` there.
     692
     693        EXAMPLES::
     694
     695            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     696            sage: b=K(rows=[[-1,-1]])
     697            sage: b.phi(0)
     698            2
     699        """
     700        b = self.parent().to_ambient_crystal()(self)
     701        return b.phi(1)
     702
     703KR_type_C.element_class = KR_type_CElement
     704
     705class PMDiagram(CombinatorialObject):
     706    """
     707    Class of `\pm` diagrams. These diagrams are in one-to-one bijection with `X_{n-1}` highest weight vectors
     708    in an `X_n` highest weight crystal `X=B,C,D`. See Section 4.1 of A. Schilling, "Combinatorial structure of
     709    Kirillov-Reshetikhin crystals of type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     710    (arXiv:0704.2046[math.QA]).
     711
     712    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.
     713    The tuple `[a_i,b_i]` specifies the number of `a_i` + and `b_i` - in the i-th row of the pm diagram
     714    if `n-i` is odd and the number of `a_i` +- pairs above row i and `b_i` columns of height i not containing
     715    any + or - if `n-i` is even.
     716
     717    Setting the option 'from_shapes = True' one can also input a `\pm` diagram in terms of its
     718    outer, intermediate and inner shape by specifying a tuple [n, s, outer, intermediate, inner]
     719    where `s` is the width of the `\pm` diagram, and 'outer' , 'intermediate',
     720    and 'inner' are the outer, intermediate and inner shape, respectively.
     721     
     722    EXAMPLES::
     723
     724        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     725        sage: pm.pm_diagram
     726        [[0, 1], [1, 2], [1]]
     727        sage: pm._list
     728        [1, 1, 2, 0, 1]
     729        sage: pm.n
     730        2
     731        sage: pm.width
     732        5
     733        sage: pm.__repr__(pretty_printing=True)
     734        .  .  .  .
     735        .  +  -  -
     736        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([2,5,[4,4],[4,2],[4,1]], from_shapes=True)
     737        [[0, 1], [1, 2], [1]]
     738
     739    TESTS::
     740       
     741        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     742        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     743        True
     744        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     745        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     746        True
     747    """
     748
     749    def __init__(self, pm_diagram, from_shapes = None):
     750        r"""
     751        Initializes `\pm` diagrams.
     752
     753        TESTS::
     754
     755           sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     756           [[0, 1], [1, 2], [1]]
     757           sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([2,5,[4,4],[4,2],[4,1]], from_shapes=True)
     758           [[0, 1], [1, 2], [1]]
     759        """
     760        if from_shapes:
     761            n = pm_diagram[0]
     762            s = pm_diagram[1]
     763            outer = [s]+list(pm_diagram[2])+[0 for i in range(n)]
     764            intermediate = [s]+list(pm_diagram[3])+[0 for i in range(n)]
     765            inner = [s]+list(pm_diagram[4])+[0 for i in range(n)]
     766            pm = [[inner[n]]]
     767            for i in range(int((n+1)/2)):
     768                pm.append([intermediate[n-2*i]-inner[n-2*i], inner[n-2*i-1]-intermediate[n-2*i]])
     769                pm.append([outer[n-2*i]-inner[n-2*i-1], inner[n-2*i-2]-outer[n-2*i]])
     770            if is_odd(n):
     771                pm.pop(n+1)
     772            pm_diagram = list(reversed(pm))
     773        self.pm_diagram = pm_diagram
     774        self.n = len(pm_diagram)-1
     775        self._list = [i for a in reversed(pm_diagram) for i in a]
     776        self.width = sum(i for i in self._list)
     777
     778    def __repr__(self, pretty_printing = None):
     779        """
     780        Turning on pretty printing allows to display the pm diagram as a
     781        tableau with the + and - displayed
     782
     783        EXAMPLES::
     784
     785            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     786            sage: pm.__repr__(pretty_printing=True)
     787            .  .  .  +
     788            .  .  -  -
     789            +  +
     790            -  -
     791            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,2], [0,0], [0]])
     792            sage: pm.__repr__(pretty_printing=True)
     793
     794        """
     795        if pretty_printing is None:
     796            return repr(self.pm_diagram)
     797        t = []
     798        ish = self.inner_shape() + [0]*self.n
     799        msh = self.intermediate_shape() + [0]*self.n
     800        osh = self.outer_shape() + [0]*self.n
     801        for i in range(self.n):
     802            t.append(['.']*ish[i]+['+']*(msh[i]-ish[i])+['-']*(osh[i]-msh[i]))
     803        t=[i for i in t if i!= []]
     804        return Tableau(t).pp()
     805
     806    def inner_shape(self):
     807        """
     808        Returns the inner shape of the pm diagram
     809
     810        EXAMPLES::
     811            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     812            sage: pm.inner_shape()
     813            [4, 1]
     814            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     815            sage: pm.inner_shape()
     816            [7, 5, 3, 1]
     817            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     818            sage: pm.inner_shape()
     819            [10, 7, 5, 3, 1]
     820        """
     821        t = []
     822        ll = self._list
     823        for i in range(self.n):
     824            t.append(sum(ll[0:2*i+1]))
     825        return Partition(list(reversed(t)))
     826
     827    def outer_shape(self):
     828        """
     829        Returns the outer shape of the pm diagram
     830
     831        EXAMPLES::
     832
     833            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     834            sage: pm.outer_shape()
     835            [4, 4]
     836            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     837            sage: pm.outer_shape()
     838            [8, 8, 4, 4]
     839            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     840            sage: pm.outer_shape()
     841            [13, 8, 8, 4, 4]
     842        """
     843        t = []
     844        ll = self._list
     845        for i in range((self.n)/2):
     846            t.append(sum(ll[0:4*i+4]))
     847            t.append(sum(ll[0:4*i+4]))
     848        if is_even(self.n+1):
     849            t.append(sum(ll[0:2*self.n+2]))
     850        return Partition(list(reversed(t)))
     851
     852    def intermediate_shape(self):
     853        """
     854        Returns the intermediate shape of the pm diagram (innner shape plus positions of plusses)
     855
     856        EXAMPLES::
     857
     858            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     859            sage: pm.intermediate_shape()
     860            [4, 2]
     861            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     862            sage: pm.intermediate_shape()
     863            [8, 6, 4, 2]
     864            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     865            sage: pm.intermediate_shape()
     866            [11, 8, 6, 4, 2]
     867            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     868            sage: pm.intermediate_shape()
     869            [4, 2, 2]
     870        """
     871        p = self.inner_shape()
     872        p = p + [0,0]
     873        ll = list(reversed(self._list))
     874        p = [ p[i]+ll[2*i+1] for i in range(self.n) ]
     875        return Partition(p)
     876
     877    def heights_of_minus(self):
     878        """
     879        Returns a list with the heights of all minus in the `\pm` diagram.
     880
     881        EXAMPLES::
     882
     883            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     884            sage: pm.heights_of_minus()
     885            [5, 5, 3, 3, 1, 1]
     886            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     887            sage: pm.heights_of_minus()
     888            [4, 4, 2, 2]
     889        """
     890        n = self.n
     891        heights = []
     892        for i in range(int((n+1)/2)):
     893            heights += [n-2*i]*((self.outer_shape()+[0]*n)[n-2*i-1]-(self.intermediate_shape()+[0]*n)[n-2*i-1])
     894        return heights
     895
     896    def heights_of_addable_plus(self):
     897        """
     898        Returns a list with the heights of all addable plus in the `\pm` diagram.
     899
     900        EXAMPLES::
     901
     902            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     903            sage: pm.heights_of_addable_plus()
     904            [1, 1, 2, 3, 4, 5]
     905            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     906            sage: pm.heights_of_addable_plus()
     907            [1, 2, 3, 4]
     908        """
     909        heights = []
     910        for i in range(1,self.n+1):
     911            heights += [i]*self.sigma().pm_diagram[i][0]
     912        return heights
     913
     914    def sigma(self):
     915        """
     916        Returns sigma on pm diagrams as needed for the analogue of the Dynkin diagram automorphism
     917        that interchanges nodes `0` and `1` for type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)` for
     918        Kirillov-Reshetikhin crystals.
     919
     920        EXAMPLES::
     921
     922            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     923            sage: pm.sigma().pm_diagram
     924            [[1, 0], [2, 1], [1]]
     925        """
     926        pm = self.pm_diagram
     927        return PMDiagram([list(reversed(a)) for a in pm])
     928
     929
     930def partitions_in_box(r, s):
     931    """
     932    Returns all partitions in a box of width s and height r.
     933   
     934    EXAMPLES::
     935
     936        sage: sage.combinat.crystals.kirillov_reshetikhin.partitions_in_box(3,2)
     937        [[], [1], [2], [1, 1], [2, 1], [1, 1, 1], [2, 2], [2, 1, 1],
     938        [2, 2, 1], [2, 2, 2]]
     939    """
     940    return [x for n in range(r*s+1) for x in Partitions(n,max_part=s,max_length=r)]
     941
     942def vertical_dominoes_removed(r, s):
     943    """
     944    Returns all partitions obtained from a rectangle of width s and height r by removing
     945    vertical dominoes.
     946
     947    EXAMPLES::
     948
     949        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(2,2)
     950        [[], [1, 1], [2, 2]]
     951        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(3,2)
     952        [[2], [2, 1, 1], [2, 2, 2]]
     953        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(4,2)
     954        [[], [1, 1], [1, 1, 1, 1], [2, 2], [2, 2, 1, 1], [2, 2, 2, 2]]
     955    """
     956    return [x.conjugate() for x in horizontal_dominoes_removed(s,r)]
     957
     958def horizontal_dominoes_removed(r, s):
     959    """
     960    Returns all partitions obtained from a rectangle of width s and height r by removing
     961    horizontal dominoes.
     962
     963    EXAMPLES::
     964
     965        sage: sage.combinat.crystals.kirillov_reshetikhin.horizontal_dominoes_removed(2,2)
     966        [[], [2], [2, 2]]
     967        sage: sage.combinat.crystals.kirillov_reshetikhin.horizontal_dominoes_removed(3,2)
     968        [[], [2], [2, 2], [2, 2, 2]]
     969    """
     970    list = [ [y for y in x] + [0 for i in range(r-x.length())] for x in partitions_in_box(r, int(s/2)) ]
     971    two = lambda x : 2*(x-int(s/2)) + s
     972    return [Partition([two(y) for y in x]) for x in list]
     973
  • sage/combinat/crystals/tensor_product.py

    diff --git a/sage/combinat/crystals/tensor_product.py b/sage/combinat/crystals/tensor_product.py
    a b class TensorProductOfCrystalsElement(Imm 
    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        """