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

File affine-crystal-3663-as.6.patch, 72.9 KB (added by aschilling, 8 years ago)

corrected problems with documentation in crystal_morphism

  • sage/combinat/crystals/__init__.py

    # HG changeset patch
    # User Anne Schilling <anne@math.ucdavis.edu>
    # Date 1247611240 25200
    # Node ID 5ccc4e99a3f5c17d4412c5d17f9e5b8d19b13eb1
    # Parent  a417ea244a939f2c2d286a06abbad014d46f0215
    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)}
    - Type A_{2n}^{(2)}, D_{n+1}^{(2)} KR crystals are implemented; the methods e0 and f0 are
      constructed using an embedding into the ambient crystal of type C_n^{(1)} via a similarity
      of crystals
    
    Some documentation links improvements.
    
    diff --git a/sage/combinat/crystals/__init__.py b/sage/combinat/crystals/__init__.py
    a b  
     1#This makes sure that sage.combinat.crystals? points to the correct
     2#documentation about crystals
     3from crystals import __doc__
  • new file sage/combinat/crystals/affine.py

    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    For general information about crystals see :mod:`sage.combinat.crystals`.
     44
     45    INPUT:
     46
     47    - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     48
     49    - ``classical_crystal`` - instance of a classical crystal.
     50
     51    EXAMPLES::
     52
     53        sage: n=2
     54        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     55        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     56        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     57        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     58        sage: A.list()
     59        [[[1]], [[2]], [[3]]]
     60        sage: A.cartan_type()
     61        ['A', 2, 1]
     62        sage: A.index_set()
     63        [0, 1, 2]
     64        sage: b=A(rows=[[1]])
     65        sage: b.weight()
     66        -Lambda[0] + Lambda[1]
     67        sage: b.classical_weight()
     68        (1, 0, 0)
     69        sage: [x.s(0) for x in A.list()]
     70        [[[3]], [[2]], [[1]]]
     71        sage: [x.s(1) for x in A.list()]
     72        [[[2]], [[1]], [[3]]]
     73    """
     74
     75    @staticmethod
     76    def __classcall__(cls, cartan_type, *args):
     77        ct = CartanType(cartan_type)
     78        return super(AffineCrystalFromClassical, cls).__classcall__(cls, ct, *args)
     79
     80    def __init__(self, cartan_type, classical_crystal):
     81        """
     82        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     83        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     84
     85        EXAMPLES::
     86
     87            sage: n=1
     88            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     89            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     90            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     91            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
     92            sage: A.list()
     93            [[[1]], [[2]]]
     94            sage: A.cartan_type()
     95            ['A', 1, 1]
     96            sage: A.index_set()
     97            [0, 1]
     98        """
     99        self._cartan_type = cartan_type
     100        if not hasattr(self, "_name"):
     101            self._name = "An affine crystal for type %s"%self.cartan_type()
     102        self.classical_crystal = classical_crystal;
     103        self.module_generators = map( self.retract, self.classical_crystal.module_generators )
     104
     105    def __iter__(self):
     106        r"""
     107        Construct the iterator from the underlying classical crystal.
     108
     109        TESTS::
     110
     111            sage: n=1
     112            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     113            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     114            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     115            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
     116            sage: A.list() # indirect doctest
     117            [[[1]], [[2]]]
     118        """
     119        for x in self.classical_crystal:
     120            yield self.retract(x)
     121
     122    # should be removed once crystal defines __iter__ instead of list
     123    def list(self):
     124        """
     125        Returns the list of all crystal elements using the underlying classical crystal
     126
     127        EXAMPLES::
     128
     129            sage: n=2
     130            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     131            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     132            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     133            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     134            sage: A.list()
     135            [[[1]], [[2]], [[3]]]
     136        """
     137        return map( self.retract, self.classical_crystal.list() )
     138       
     139    def lift(self, affine_elt):
     140        """
     141        Lifts an affine crystal element to the corresponding classical crystal element
     142
     143        EXAMPLES::
     144
     145            sage: n=2
     146            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     147            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     148            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     149            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     150            sage: b=A.list()[0]
     151            sage: type(A.lift(b))
     152            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     153        """
     154        return affine_elt.lift()
     155
     156    def retract(self, classical_elt):
     157        """
     158        Transforms a classical crystal element to the corresponding affine crystal element
     159
     160        EXAMPLES::
     161
     162            sage: n=2
     163            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     164            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     165            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     166            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     167            sage: t=C(rows=[[1]])
     168            sage: type(t)
     169            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     170            sage: A.retract(t)
     171            [[1]]
     172            sage: type(A.retract(t))
     173            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     174        """
     175        return self.element_class(classical_elt, parent = self)
     176   
     177    def __call__(self, *value, **options):
     178        r"""
     179        Coerces value into self.
     180
     181        EXAMPLES:
     182
     183            sage: n=2
     184            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     185            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     186            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     187            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     188            sage: b=A(rows=[[1]])
     189            sage: b
     190            [[1]]
     191            sage: type(b)
     192            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     193            sage: A(b)
     194            [[1]]
     195            sage: type(A(b))
     196            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     197        """
     198        if len(value) == 1 and isinstance(value[0], self.element_class) and value[0].parent() == self:
     199            return value[0]
     200        else: # Should do sanity checks!  (Including check for inconsistent parent.)
     201            return self.retract(self.classical_crystal(*value, **options))
     202
     203    def __contains__(self, x):
     204        r"""
     205        Checks whether x is an element of self.
     206
     207        EXAMPLES:
     208
     209            sage: n=2
     210            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     211            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     212            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     213            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     214            sage: b=A(rows=[[1]])
     215            sage: A.__contains__(b)
     216            True
     217        """
     218        return x.parent() is self
     219
     220
     221class AffineCrystalFromClassicalElement(ElementWrapper, CrystalElement):
     222    r"""
     223    Elements of crystals that are constructed from a classical crystal.
     224    The elements inherit many of their methods from the classical crystal
     225    using lift and retract.
     226
     227    This class is not instantiated directly but rather __call__ed from
     228    AffineCrystalFromClassical.  The syntax of this is governed by the
     229    (classical) CrystalOfTableaux.
     230
     231    EXAMPLES::
     232
     233        sage: n=2
     234        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     235        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     236        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     237        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     238        sage: b=A(rows=[[1]])
     239        sage: b.__repr__()
     240        '[[1]]'
     241    """
     242
     243    def classical_weight(self):
     244        """
     245        Returns the classical weight corresponding to self.
     246
     247        EXAMPLES::
     248
     249            sage: n=2
     250            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     251            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     252            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     253            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     254            sage: b=A(rows=[[1]])
     255            sage: b.classical_weight()
     256            (1, 0, 0)
     257        """
     258        return self.lift().weight()
     259
     260    def lift(self):
     261        """
     262        Lifts an affine crystal element to the corresponding classical crystal element
     263
     264        EXAMPLES::
     265
     266            sage: n=2
     267            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     268            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     269            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     270            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     271            sage: b=A.list()[0]
     272            sage: type(b.lift())
     273            <class 'sage.combinat.crystals.tensor_product.CrystalOfTableauxElement'>
     274        """
     275        return self.value
     276
     277    @abstract_method
     278    def e0(self):
     279        r"""
     280        Assumes that `e_0` is implemented separately.
     281        """
     282
     283    @abstract_method
     284    def f0(self):
     285        r"""
     286        Assumes that `f_0` is implemented separately.
     287        """
     288
     289    def e(self, i):
     290        r"""
     291        Returns the action of `e_i` on self.
     292
     293        EXAMPLES::
     294
     295            sage: n=2
     296            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     297            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     298            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     299            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     300            sage: b=A(rows=[[1]])
     301            sage: b.e(0)
     302            [[3]]
     303            sage: b.e(1)
     304        """
     305        if i == 0:
     306            return self.e0()
     307        else:
     308            x = self.lift().e(i)
     309            if (x == None):
     310                return None
     311            else:
     312                return self.parent().retract(x)
     313
     314    def f(self, i):
     315        r"""
     316        Returns the action of `f_i` on self.
     317
     318        EXAMPLES::
     319
     320            sage: n=2
     321            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     322            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     323            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     324            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     325            sage: b=A(rows=[[3]])
     326            sage: b.f(0)
     327            [[1]]
     328            sage: b.f(2)
     329        """
     330        if i == 0:
     331            return self.f0()
     332        else:
     333            x = self.lift().f(i)
     334            if (x == None):
     335                return None
     336            else:
     337                return self.parent().retract(x)
     338
     339    def epsilon0(self):
     340        r"""
     341        Uses `epsilon_0` from the super class, but should be implemented if a faster implementation exists.
     342        """
     343        return super(AffineCrystalFromClassicalElement, self).epsilon(0)
     344
     345    def epsilon(self, i):
     346        """
     347        Returns the maximal time the crystal operator `e_i` can be applied to self.
     348
     349        EXAMPLES::
     350
     351            sage: n=2
     352            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     353            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     354            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     355            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     356            sage: [x.epsilon(0) for x in A.list()]
     357            [1, 0, 0]
     358            sage: [x.epsilon(1) for x in A.list()]
     359            [0, 1, 0]
     360        """
     361        if i == 0:
     362            return self.epsilon0()
     363        else:
     364            return self.lift().epsilon(i)
     365
     366    def phi0(self):
     367        r"""
     368        Uses `phi_0` from the super class, but should be implemented if a faster implementation exists.
     369        """
     370        return super(AffineCrystalFromClassicalElement, self).phi(0)
     371
     372    def phi(self, i):
     373        r"""
     374        Returns the maximal time the crystal operator `f_i` can be applied to self.
     375
     376        EXAMPLES::
     377
     378            sage: n=2
     379            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     380            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     381            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     382            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     383            sage: [x.phi(0) for x in A.list()]
     384            [0, 0, 1]
     385            sage: [x.phi(1) for x in A.list()]
     386            [1, 0, 0]
     387        """
     388        if i == 0:
     389            return self.phi0()
     390        else:
     391            return self.lift().phi(i)
     392
     393AffineCrystalFromClassical.element_class = AffineCrystalFromClassicalElement
     394
     395
     396class AffineCrystalFromClassicalAndPromotion(AffineCrystalFromClassical):
     397    r"""
     398    Crystals that are constructed from a classical crystal and a
     399    Dynkin diagram automorphism `\sigma`.  In type `A_n`, the Dynkin
     400    diagram automorphism is `i \to i+1 \pmod n+1` and the
     401    corresponding map on the crystal is the promotion operation
     402    `\mathrm{pr}` on tableaux. The affine crystal operators are given
     403    by `f_0= \mathrm{pr}^{-1} f_{\sigma(0)} \mathrm{pr}`.
     404
     405    INPUT:
     406
     407    - ``cartan_type`` -  The Cartan type of the resulting affine crystal
     408
     409    - ``classical_crystal`` - instance of a classical crystal.
     410
     411    - ``automorphism, inverse_automorphism`` - A function on the
     412      elements of the classical_crystal
     413   
     414    - ``dynkin_node`` - Integer specifying the classical node in the
     415      image of the zero node under the automorphism sigma.
     416
     417    EXAMPLES::
     418
     419        sage: n=2
     420        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     421        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     422        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     423        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     424        sage: A.list()
     425        [[[1]], [[2]], [[3]]]
     426        sage: A.cartan_type()
     427        ['A', 2, 1]
     428        sage: A.index_set()
     429        [0, 1, 2]
     430        sage: b=A(rows=[[1]])
     431        sage: b.weight()
     432        -Lambda[0] + Lambda[1]
     433        sage: b.classical_weight()
     434        (1, 0, 0)
     435        sage: [x.s(0) for x in A.list()]
     436        [[[3]], [[2]], [[1]]]
     437        sage: [x.s(1) for x in A.list()]
     438        [[[2]], [[1]], [[3]]]
     439    """
     440
     441    def __init__(self, cartan_type, classical_crystal, p_automorphism, p_inverse_automorphism, dynkin_node):
     442        """
     443        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
     444        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'
     445
     446        EXAMPLES::
     447
     448            sage: n=1
     449            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     450            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     451            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     452            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     453            sage: A.list()
     454            [[[1]], [[2]]]
     455            sage: A.cartan_type()
     456            ['A', 1, 1]
     457            sage: A.index_set()
     458            [0, 1]
     459        """
     460        AffineCrystalFromClassical.__init__(self, cartan_type, classical_crystal)
     461        self.p_automorphism = p_automorphism
     462        self.p_inverse_automorphism = p_inverse_automorphism
     463        self.dynkin_node = dynkin_node
     464
     465    def automorphism(self, x):
     466        """
     467        Gives the analogue of the affine Dynkin diagram automorphism on the level of crystals
     468
     469        EXAMPLES::
     470
     471            sage: n=2
     472            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     473            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     474            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     475            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     476            sage: b=A.list()[0]
     477            sage: A.automorphism(b)
     478            [[2]]
     479        """
     480        return self.retract( self.p_automorphism( x.lift() ) )
     481
     482    def inverse_automorphism(self, x):
     483        """
     484        Gives the analogue of the inverse of the affine Dynkin diagram automorphism on the level of crystals
     485
     486        EXAMPLES::
     487
     488            sage: n=2
     489            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     490            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     491            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     492            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     493            sage: b=A.list()[0]
     494            sage: A.inverse_automorphism(b)
     495            [[3]]
     496        """
     497        return self.retract( self.p_inverse_automorphism( x.lift() ) )
     498
     499class AffineCrystalFromClassicalAndPromotionElement(AffineCrystalFromClassicalElement):
     500    r"""
     501    Elements of crystals that are constructed from a classical crystal
     502    and a Dynkin diagram automorphism.  In type A, the automorphism is
     503    the promotion operation on tableaux.
     504
     505    This class is not instantiated directly but rather __call__ed from
     506    AffineCrystalFromClassicalAndPromotion.  The syntax of this is governed by the
     507    (classical) CrystalOfTableaux.
     508
     509    Since this class inherits from AffineClassicalFromClassicalElement, the methods
     510    that need to be implemented are e0, f0 and possibly epsilon0 and phi0 if more efficient
     511    algorithms exist.
     512
     513    EXAMPLES::
     514
     515        sage: n=2
     516        sage: C=CrystalOfTableaux(['A',n],shape=[1])
     517        sage: pr=lambda x : C(x.to_tableau().promotion(n))
     518        sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     519        sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     520        sage: b=A(rows=[[1]])
     521        sage: b.__repr__()
     522        '[[1]]'
     523    """
     524
     525    def e0(self):
     526        r"""
     527        Implements `e_0` using the automorphism as
     528        `e_0 = \pr^{-1} e_{dynkin_node} \pr`
     529
     530        EXAMPLES::
     531
     532            sage: n=2
     533            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     534            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     535            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     536            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     537            sage: b=A(rows=[[1]])
     538            sage: b.e0()
     539            [[3]]
     540        """
     541        x = self.parent().automorphism(self).e(self.parent().dynkin_node)
     542        if (x == None):
     543            return None
     544        else:
     545            return self.parent().inverse_automorphism(x)
     546
     547    def f0(self):
     548        r"""
     549        Implements `f_0` using the automorphism as
     550        `f_0 = \pr^{-1} f_{dynkin_node} \pr`
     551
     552        EXAMPLES::
     553
     554            sage: n=2
     555            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     556            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     557            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     558            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     559            sage: b=A(rows=[[3]])
     560            sage: b.f0()
     561            [[1]]
     562        """
     563        x = self.parent().automorphism(self).f(self.parent().dynkin_node)
     564        if (x == None):
     565            return None
     566        else:
     567            return self.parent().inverse_automorphism(x)
     568
     569    def epsilon0(self):
     570        r"""
     571        Implements `epsilon_0` using the automorphism.
     572
     573        EXAMPLES::
     574
     575            sage: n=2
     576            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     577            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     578            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     579            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     580            sage: [x.epsilon0() for x in A.list()]
     581            [1, 0, 0]
     582        """
     583        x = self.parent().automorphism(self)
     584        return x.lift().epsilon(self.parent().dynkin_node)
     585
     586    def phi0(self):
     587        r"""
     588        Implements `phi_0` using the automorphism.
     589
     590        EXAMPLES::
     591
     592            sage: n=2
     593            sage: C=CrystalOfTableaux(['A',n],shape=[1])
     594            sage: pr=lambda x : C(x.to_tableau().promotion(n))
     595            sage: pr_inverse = lambda x : C(x.to_tableau().promotion_inverse(n))
     596            sage: A=AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1)
     597            sage: [x.phi0() for x in A.list()]
     598            [0, 0, 1]
     599        """
     600        x = self.parent().automorphism(self)
     601        return x.lift().phi(self.parent().dynkin_node)
     602
     603AffineCrystalFromClassicalAndPromotion.element_class = AffineCrystalFromClassicalAndPromotionElement
  • 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 of the type `T` weight lattice such that 
    2525   
    2626   -  `f_i(x)`.weight() = x.weight() - `\alpha_i`;
    2727
    28    -  `e_i(x)`.weight() = x.weight() +
    29       `\alpha_i`.
     28   -  `e_i(x)`.weight() = x.weight() + `\alpha_i`.
    3029
    3130
    3231
    documentations):: 
    7473    sage: Spin = CrystalOfSpins(['B', 3])
    7574    sage: Tab  = CrystalOfTableaux(['A', 3], shape = [2,1,1])
    7675    sage: Fast = FastCrystal(['B', 2], shape = [3/2, 1/2])
     76    sage: KR = KirillovReshetikhinCrystal(['A',2,1],1,1)
    7777
    7878One can get (currently) crude plotting via::
    7979
    TODO: 
    111111
    112112-  RestrictionOfCrystal / DirectSumOfCrystals
    113113
    114 -  Crystal.crystal_morphism
    115 
    116 -  Affine crystals
    117 
    118 -  Kirillov-Reshetikhin crystals
    119 
    120114
    121115Most of the above features (except Littelmann/alcove paths) are in
    122116MuPAD-Combinat (see lib/COMBINAT/crystals.mu), which could provide
    inspiration. 
    143137#****************************************************************************
    144138
    145139from sage.misc.latex import latex
     140from sage.misc.cachefunc import CachedFunction
    146141from sage.structure.parent import Parent
    147142from sage.structure.element import Element
    148143from sage.combinat.combinat import CombinatorialClass
    class Crystal(CombinatorialClass, Parent 
    178173            sage: C = CrystalOfLetters(['A', 5])
    179174            sage: C.weight_lattice_realization()
    180175            Ambient space of the Root system of type ['A', 5]
     176            sage: K = KirillovReshetikhinCrystal(['A',2,1], 1, 1)
     177            sage: K.weight_lattice_realization()
     178            Weight lattice of the Root system of type ['A', 2, 1]
    181179        """
    182         return self.cartan_type().root_system().ambient_space()
     180        F = self.cartan_type().root_system()
     181        if F.ambient_space() is None:
     182            return F.weight_lattice()
     183        else:
     184            return F.ambient_space()
    183185
    184186    def cartan_type(self):
    185187        """
    class Crystal(CombinatorialClass, Parent 
    262264            sage: l.sort(); l
    263265            [1, 2, 3, 4, 5, 6]
    264266        """
    265         # To be generalized to some transitiveIdeal
     267        # Should use transitiveIdeal
     268        # should be transformed to __iter__ instead of list
    266269        # To be moved in a super category CombinatorialModule
    267270        result = set(self.module_generators)
    268271        todo = result.copy()
    class Crystal(CombinatorialClass, Parent 
    276279                result.add(y)
    277280        return list(result)
    278281
     282    def crystal_morphism(self, g, index_set = None, automorphism = lambda i : i, direction = 'down', direction_image = 'down',
     283                         similarity_factor = None, similarity_factor_domain = None, cached = False):
     284        """
     285        Constructs a morphism from the crystal self to another crystal.
     286        The input g can either be a function of a (sub)set of elements of self to
     287        element in another crystal or a dictionary between certain elements.
     288        Usually one would map highest weight elements or crystal generators to each
     289        other using g.
     290        Specifying index_set gives the opportunity to define the morphism as `I`-crystals
     291        where `I =` index_set. If index_set is not specified, the index set of self is used.
     292        It is also possible to define twisted-morphisms by specifying an automorphism on the
     293        nodes in te Dynkin diagram (or the index_set).
     294        The option direction and direction_image indicate whether to use `f_i` or `e_i` in
     295        self or the image crystal to construct the morphism, depending on whether the direction
     296        is set to 'down' or 'up'.
     297        Finally, it is possible to set a similarity_factor. This should be a dictionary between
     298        the elements in the index set and positive integers. The crystal operator `f_i` then gets
     299        mapped to `f_i^{m_i}` where `m_i =` similarity_factor[i].
     300        Setting similarity_factor_domain to a dictionary between the index set and positive integers
     301        has the effect that `f_i^{m_i}` gets mapped to `f_i` where `m_i =` similarity_factor_domain[i].
     302
     303        EXAMPLES::
     304
     305            sage: C2 = CrystalOfLetters(['A',2])
     306            sage: C3 = CrystalOfLetters(['A',3])
     307            sage: g = {C2.module_generators[0] : C3.module_generators[0]}
     308            sage: g_full = C2.crystal_morphism(g)
     309            sage: g_full(C2(1))
     310            1
     311            sage: g_full(C2(2))
     312            2
     313            sage: g = {C2(1) : C2(3)}
     314            sage: g_full = C2.crystal_morphism(g, automorphism = lambda i : 3-i, direction_image = 'up')
     315            sage: [g_full(b) for b in C2]
     316            [3, 2, 1]
     317            sage: T = CrystalOfTableaux(['A',2], shape = [2])
     318            sage: g = {C2(1) : T(rows=[[1,1]])}
     319            sage: g_full = C2.crystal_morphism(g, similarity_factor = {1:2, 2:2})
     320            sage: [g_full(b) for b in C2]
     321            [[[1, 1]], [[2, 2]], [[3, 3]]]
     322            sage: g = {T(rows=[[1,1]]) : C2(1)}
     323            sage: g_full = T.crystal_morphism(g, similarity_factor_domain = {1:2, 2:2})
     324            sage: g_full(T(rows=[[2,2]]))
     325            2
     326        """
     327        if index_set is None:
     328            index_set = self.index_set()
     329        if similarity_factor is None:
     330            similarity_factor = dict( (i,1) for i in index_set )
     331        if similarity_factor_domain is None:
     332            similarity_factor_domain = dict( (i,1) for i in index_set )
     333        if direction == 'down':
     334            e_string = 'e_string'
     335        else:
     336            e_string = 'f_string'
     337        if direction_image == 'down':
     338            f_string = 'f_string'
     339        else:
     340            f_string = 'e_string'
     341        if type(g) == dict:
     342            g = g.__getitem__
     343
     344        def morphism(b):
     345            for i in index_set:
     346                c = getattr(b, e_string)([i for k in range(similarity_factor_domain[i])])
     347                if c is not None:
     348                    d = getattr(morphism(c),f_string)([automorphism(i) for k in range(similarity_factor[i])])
     349                    if d is not None:
     350                        return d
     351                    else:
     352                        raise ValueError, "This is not a morphism!"
     353            #now we know that b is hw
     354            return g(b)
     355
     356        if cached:
     357            return morphism
     358        else:
     359            return CachedFunction(morphism)
     360
     361
    279362    def digraph(self):
    280363        """
    281364        Returns the DiGraph associated to self.
    class CrystalElement(Element): 
    737820            phi = phi+1
    738821        return phi
    739822
     823    def phi_minus_epsilon(self, i):
     824        """
     825        Returns `\phi_i - \epsilon_i` of self. There are sometimes
     826        better implementations using the weight for this. It is used
     827        for reflections along a string.
     828
     829        EXAMPLES::
     830
     831            sage: C = CrystalOfLetters(['A',5])
     832            sage: C(1).phi_minus_epsilon(1)
     833            1
     834        """
     835        return self.phi(i) - self.epsilon(i)
     836
    740837    def Epsilon(self):
    741838        """
    742839        EXAMPLES::
    class CrystalElement(Element): 
    767864        Lambda = self.parent().Lambda()
    768865        return sum(self.phi(i) * Lambda[i] for i in self.index_set())
    769866
     867    def f_string(self, list):
     868        r"""
     869        Applies `f_{i_r} ... f_{i_1}` to self for `list = [i_1, ..., i_r]`
     870
     871        EXAMPLES::
     872
     873            sage: C = CrystalOfLetters(['A',3])
     874            sage: b = C(1)
     875            sage: b.f_string([1,2])
     876            3
     877            sage: b.f_string([2,1])
     878
     879        """
     880        b = self
     881        for i in list:
     882            b = b.f(i)
     883            if b is None:
     884                return None
     885        return b
     886
     887    def e_string(self, list):
     888        r"""
     889        Applies `e_{i_r} ... e_{i_1}` to self for `list = [i_1, ..., i_r]`
     890
     891        EXAMPLES::
     892
     893            sage: C = CrystalOfLetters(['A',3])
     894            sage: b = C(3)
     895            sage: b.e_string([2,1])
     896            1
     897            sage: b.e_string([1,2])
     898
     899        """
     900        b = self
     901        for i in list:
     902            b = b.e(i)
     903            if b is None:
     904                return None
     905        return b
     906
    770907    def s(self, i):
    771908        r"""
    772909        Returns the reflection of self along its `i`-string
    class CrystalElement(Element): 
    785922            sage: t.s(1)
    786923            [[1, 1, 1, 2]]
    787924        """
    788         d = self.phi(i)-self.epsilon(i)
     925        d = self.phi_minus_epsilon(i)
    789926        b = self
    790927        if d > 0:
    791928            for j in range(d):
    class CrystalElement(Element): 
    795932                b = b.e(i)
    796933        return b
    797934
    798     def is_highest_weight(self):
     935    def is_highest_weight(self, index_set = None):
    799936        r"""
    800937        Returns True if self is a highest weight.
     938        Specifying the option index_set to be a subset `I` of the index set
     939        of the underlying crystal, finds all highest weight vectors for arrows in `I`.
    801940       
    802941        EXAMPLES::
    803942       
    class CrystalElement(Element): 
    806945            True
    807946            sage: C(2).is_highest_weight()
    808947            False
     948            sage: C(2).is_highest_weight(index_set = [2,3,4,5])
     949            True
    809950        """
    810         return all(self.e(i) == None for i in self.index_set())
     951        if index_set is None:
     952            index_set = self.index_set()
     953        return all(self.e(i) == None for i in index_set)
    811954
    812955class CrystalBacktracker(GenericBacktracker):
    813956    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
     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
     33from sage.combinat.integer_vector import IntegerVectors
     34
     35
     36def KirillovReshetikhinCrystal(cartan_type, r, s):
     37    r"""
     38    Returns the Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     39
     40    For more information about general crystals see :mod:`sage.combinat.crystals`.
     41
     42    Many Kirillov-Reshetikhin crystals are constructed from a
     43    classical crystal together with an automorphism `p` on the level of crystals which
     44    corresponds to a Dynkin diagram automorphism mapping node 0 to some other node i.
     45    The action of `f_0` and `e_0` is then constructed using
     46    `f_0 = p^{-1} \circ f_i \circ p`.
     47
     48    For example, for type `A_n^{(1)}` the Kirillov-Reshetikhin crystal `B^{r,s}`
     49    is obtained from the classical crystal `B(s\omega_r)` using the
     50    promotion operator. For other types, see
     51
     52    M. Shimozono
     53    "Affine type A crystal structure on tensor products of rectangles,
     54    Demazure characters, and nilpotent varieties",
     55    J. Algebraic Combin.  15  (2002),  no. 2, 151-187
     56    (arXiv:math.QA/9804039)
     57
     58    A. Schilling, "Combinatorial structure of Kirillov-Reshetikhin crystals of
     59    type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     60    (arXiv:0704.2046 [math.QA])
     61
     62    Other Kirillov-Reshetikhin crystals are constructed using similarity methods.
     63    See Section 4 of
     64
     65    G. Fourier, M. Okado, A. Schilling,
     66    "Kirillov-Reshetikhin crystals for nonexceptional types"
     67    Advances in Math., to appear (arXiv:0810.5067 [math.RT])
     68
     69    INPUT:
     70
     71        - ``cartan_type`` Affine type and rank
     72
     73        - ``r`` Label of finite Dynkin diagram
     74
     75        - ``s`` Positive integer
     76
     77    EXAMPLES::
     78   
     79        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2, 1)
     80        sage: K.index_set()
     81        [0, 1, 2, 3]
     82        sage: K.list()
     83        [[[1], [2]], [[1], [3]], [[2], [3]], [[1], [4]], [[2], [4]], [[3], [4]]]
     84        sage: b=K(rows=[[1],[2]])
     85        sage: b.weight()
     86        -Lambda[0] + Lambda[2]
     87
     88        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     89        sage: K.automorphism(K.module_generators[0])
     90        [[2, 2], [3, 3]]
     91        sage: K.module_generators[0].e(0)
     92        [[1, 2], [2, 4]]
     93        sage: K.module_generators[0].f(2)
     94        [[1, 1], [2, 3]]
     95        sage: K.module_generators[0].f(1)
     96        sage: K.module_generators[0].phi(0)
     97        0
     98        sage: K.module_generators[0].phi(1)
     99        0
     100        sage: K.module_generators[0].phi(2)
     101        2
     102        sage: K.module_generators[0].epsilon(0)
     103        2
     104        sage: K.module_generators[0].epsilon(1)
     105        0
     106        sage: K.module_generators[0].epsilon(2)
     107        0
     108        sage: b = K(rows=[[1,2],[2,3]])
     109        sage: b
     110        [[1, 2], [2, 3]]
     111        sage: b.f(2)
     112        [[1, 2], [3, 3]]
     113
     114        sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     115        sage: K.cartan_type()
     116        ['D', 4, 1]
     117        sage: type(K.module_generators[0])
     118        <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     119    """
     120    ct = CartanType(cartan_type)
     121    assert ct.is_affine()
     122    if ct.is_untwisted_affine():
     123        if ct.type() == 'A':
     124            return KR_type_A(ct, r, s)
     125        elif ct.type() == 'D' and r<ct.rank()-2:
     126            return KR_type_vertical(ct, r, s)
     127        elif ct.type() == 'B' and r<ct.rank()-1:
     128            return KR_type_vertical(ct, r, s)
     129        elif ct.type() == 'C' and r<ct.rank()-1:
     130            return KR_type_C(ct, r, s)
     131        else:
     132            raise NotImplementedError
     133    else:
     134        if ct.dual().type() == 'B':
     135            return KR_type_vertical(ct, r, s)
     136        elif ct.type() == 'BC':
     137            return KR_type_box(ct, r, s)
     138        elif ct.dual().type() == 'C' and r<ct.rank()-1:
     139            return KR_type_box(ct, r, s)
     140        else:
     141            raise NotImplementedError
     142
     143
     144class KirillovReshetikhinGenericCrystal(AffineCrystal):
     145    r"""
     146    Generic class for Kirillov-Reshetikhin crystal `B^{r,s}` of the given type.
     147
     148    Input is a Dynkin node `r`, a positive integer `s`, and a Cartan type `cartan_type`.
     149    """
     150    def __init__(self, cartan_type, r, s):
     151        r"""
     152        Initializes a generic Kirillov-Reshetikhin crystal.
     153
     154        TESTS::
     155
     156            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KirillovReshetikhinGenericCrystal(['A',2,1], 1, 1)
     157            sage: K
     158            Kirillov-Reshetikhin crystal of type ['A', 2, 1] with (r,s)=(1,1)
     159            sage: K.r()
     160            1
     161            sage: K.s()
     162            1
     163        """
     164        self._cartan_type = CartanType(cartan_type)
     165        self._r = r
     166        self._s = s
     167        self._name = "Kirillov-Reshetikhin crystal of type %s with (r,s)=(%d,%d)" % (cartan_type, r, s)
     168
     169    def r(self):
     170        """
     171        Returns r of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     172
     173        EXAMPLE::
     174
     175            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     176            sage: K.r()
     177            2
     178        """
     179        return self._r
     180   
     181    def s(self):
     182        """
     183        Returns s of the underlying Kirillov-Reshetikhin crystal `B^{r,s}`
     184
     185        EXAMPLE::
     186
     187            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
     188            sage: K.s()
     189            1
     190        """
     191        return self._s
     192
     193
     194class KirillovReshetikhinCrystalFromPromotion(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassicalAndPromotion):
     195    r"""
     196    This generic class assumes that the Kirillov-Reshetikhin crystal is constructed
     197    from a classical crystal 'classical_decomposition' and an automorphism 'promotion' and its inverse
     198    which corresponds to a Dynkin diagram automorphism 'dynkin_diagram_automorphism'.
     199
     200    Each instance using this class needs to implement the methods:
     201    - classical_decomposition
     202    - promotion
     203    - promotion_inverse
     204    - dynkin_diagram_automorphism
     205    """
     206    def __init__(self, cartan_type, r, s):
     207        r"""
     208        TESTS::
     209
     210            sage: K = KirillovReshetikhinCrystal(['B',2,1], 1, 1)
     211            sage: K
     212            Kirillov-Reshetikhin crystal of type ['B', 2, 1] with (r,s)=(1,1)
     213        """
     214        KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     215        AffineCrystalFromClassicalAndPromotion.__init__(self, cartan_type, self.classical_decomposition(),
     216                                                        self.promotion(), self.promotion_inverse(),
     217                                                        self.dynkin_diagram_automorphism(0))
     218
     219
     220class KR_type_A(KirillovReshetikhinCrystalFromPromotion):
     221    r"""
     222    Class of Kirillov-Reshetikhin crystals of type `A_n^{(1)}`.
     223
     224    EXAMPLES::
     225
     226        sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     227        sage: b = K(rows=[[1,2],[2,4]])
     228        sage: b.f(0)
     229        [[1, 1], [2, 2]]
     230    """
     231
     232    def classical_decomposition(self):
     233        """
     234        Specifies the classical crystal underlying the KR crystal of type A.
     235
     236        EXAMPLES::
     237
     238            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     239            sage: K.classical_decomposition()
     240            The crystal of tableaux of type ['A', 3] and shape(s) ([2, 2],)
     241        """
     242        return CrystalOfTableaux(self.cartan_type().classical(), shape = [self.s() for i in range(1,self.r()+1)])
     243   
     244    def promotion(self):
     245        """
     246        Specifies the promotion operator used to construct the affine type A crystal.
     247        For type A this corresponds to the Dynkin diagram automorphism which maps i to i+1 mod n+1,
     248        where n is the rank.
     249
     250        EXAMPLES:
     251
     252            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     253            sage: b = K.classical_decomposition()(rows=[[1,2],[3,4]])
     254            sage: K.promotion()(b)
     255            [[1, 3], [2, 4]]
     256        """
     257        return lambda x : self.classical_crystal(x.to_tableau().promotion(self._cartan_type[1]))
     258   
     259    def promotion_inverse(self):
     260        """
     261        Specifies the inverse promotion operator used to construct the affine type A crystal.
     262        For type A this corresponds to the Dynkin diagram automorphism which maps i to i-1 mod n+1,
     263        where n is the rank.
     264
     265        EXAMPLES:
     266
     267            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     268            sage: b = K.classical_decomposition()(rows=[[1,3],[2,4]])
     269            sage: K.promotion_inverse()(b)
     270            [[1, 2], [3, 4]]
     271            sage: b = K.classical_decomposition()(rows=[[1,2],[3,3]])
     272            sage: K.promotion_inverse()(K.promotion()(b))
     273            [[1, 2], [3, 3]]
     274        """
     275        return lambda x : self.classical_crystal(x.to_tableau().promotion_inverse(self._cartan_type[1]))
     276
     277    def dynkin_diagram_automorphism(self, i):
     278        """
     279        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     280        elements. The automorphism needs to map node 0 to some other Dynkin node.
     281
     282        For type A we use the Dynkin diagram automorphism which maps i to i+1 mod n+1, where n is the rank.
     283
     284        EXAMPLES::
     285       
     286            sage: K = KirillovReshetikhinCrystal(['A',3,1], 2,2)
     287            sage: K.dynkin_diagram_automorphism(0)
     288            1
     289            sage: K.dynkin_diagram_automorphism(3)
     290            0
     291        """
     292        aut = range(1,self.cartan_type().rank())+[0]
     293        return aut[i]
     294
     295class KR_type_vertical(KirillovReshetikhinCrystalFromPromotion):
     296    r"""
     297    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `D_n^{(1)}` for `r\le n-2`,
     298    `B_n^{(1)}` for `r<n`, and `A_{2n-1}^{(2)}` for `r\le n`.
     299
     300    EXAMPLES::
     301
     302        sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     303        sage: b = K(rows=[])
     304        sage: b.f(0)
     305        [[1], [2]]
     306        sage: b.f(0).f(0)
     307        [[1, 1], [2, 2]]
     308        sage: b.e(0)
     309        [[-2], [-1]]
     310        sage: b.e(0).e(0)
     311        [[-2, -2], [-1, -1]]
     312
     313        sage: K = KirillovReshetikhinCrystal(['B',3,1], 1,1)
     314        sage: [[b,b.f(0)] for b in K]
     315        [[[[1]], None], [[[2]], None], [[[3]], None], [[[0]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     316
     317        sage: K = KirillovReshetikhinCrystal(['A',5,2], 1,1)
     318        sage: [[b,b.f(0)] for b in K]
     319        [[[[1]], None], [[[2]], None], [[[3]], None], [[[-3]], None], [[[-2]], [[1]]], [[[-1]], [[2]]]]
     320    """
     321 
     322    def classical_decomposition(self):
     323        r"""
     324        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `D_n^{(1)}`,
     325        `B_n^{(1)}`, and `A_{2n-1}^{(2)}`.
     326        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     327        a rectangle of width s and height r by removing verticle dominoes. Here we identify the fundamental
     328        weight `\Lambda_i` with a column of height `i`.
     329
     330        EXAMPLES::
     331
     332            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     333            sage: K.classical_decomposition()
     334            The crystal of tableaux of type ['D', 4] and shape(s) [[], [1, 1], [2, 2]]
     335        """
     336        return CrystalOfTableaux(self.cartan_type().classical(),
     337                                 shapes = vertical_dominoes_removed(self.r(),self.s()))
     338   
     339    def promotion(self):
     340        """
     341        Specifies the promotion operator used to construct the affine type `D_n^{(1)}` etc. crystal.
     342        This corresponds to the Dynkin diagram automorphism which interchanges nodes 0 and 1,
     343        and leaves all other nodes unchanged. On the level of crystals it is constructed using
     344        `\pm` diagrams.
     345
     346        EXAMPLES:
     347
     348            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     349            sage: promotion = K.promotion()
     350            sage: b = K.classical_decomposition()(rows=[])
     351            sage: promotion(b)
     352            [[1, 2], [-2, -1]]
     353            sage: b = K.classical_decomposition()(rows=[[1,3],[2,-1]])
     354            sage: promotion(b)
     355            [[1, 3], [2, -1]]
     356            sage: b = K.classical_decomposition()(rows=[[1],[-3]])
     357            sage: promotion(b)
     358            [[2, -3], [-2, -1]]
     359        """
     360        T = self.classical_decomposition()
     361        ind = T.index_set()
     362        ind.remove(1)
     363        return T.crystal_morphism( self.promotion_on_highest_weight_vectors(), index_set = ind)
     364   
     365    promotion_inverse = promotion
     366   
     367    def dynkin_diagram_automorphism(self, i):
     368        """
     369        Specifies the Dynkin diagram automorphism underlying the promotion action on the crystal
     370        elements. The automorphism needs to map node 0 to some other Dynkin node.
     371
     372        Here we use the Dynkin diagram automorphism which interchanges nodes 0 and 1 and leaves
     373        all other nodes unchanged.
     374
     375        EXAMPLES::
     376       
     377            sage: K = KirillovReshetikhinCrystal(['D',4,1],1,1)
     378            sage: K.dynkin_diagram_automorphism(0)
     379            1
     380            sage: K.dynkin_diagram_automorphism(1)
     381            0
     382            sage: K.dynkin_diagram_automorphism(4)
     383            4
     384        """
     385        aut = [1,0]+range(2,self.cartan_type().rank())
     386        return aut[i]
     387
     388    def promotion_on_highest_weight_vectors(self):
     389        """
     390        Calculates promotion on `{2,3,...,n}` highest weight vectors.
     391
     392        EXAMPLES::
     393
     394            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     395            sage: T = K.classical_decomposition()
     396            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     397            sage: [K.promotion_on_highest_weight_vectors()(b) for b in hw]
     398            [[[1, 2], [-2, -1]], [[2, 2], [-2, -1]], [[1, 2], [3, -1]], [[2], [-2]],
     399            [[1, 2], [2, -2]], [[2, 2], [-1, -1]], [[2, 2], [3, -1]], [[2, 2], [3, 3]],
     400            [], [[1], [2]], [[1, 1], [2, 2]], [[2], [-1]], [[1, 2], [2, -1]], [[2], [3]],
     401            [[1, 2], [2, 3]]]
     402        """
     403        return lambda b: self.from_pm_diagram_to_highest_weight_vector(self.from_highest_weight_vector_to_pm_diagram(b).sigma())
     404
     405    def from_highest_weight_vector_to_pm_diagram(self, b):
     406        """
     407        This gives the bijection between an element b in the classical decomposition
     408        of the KR crystal that is `{2,3,..,n}`-highest weight and `\pm` diagrams.
     409
     410        EXAMPLES::
     411
     412            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     413            sage: T = K.classical_decomposition()
     414            sage: b = T(rows=[[2],[-2]])
     415            sage: pm = K.from_highest_weight_vector_to_pm_diagram(b); pm
     416            [[1, 1], [0, 0], [0]]
     417            sage: pm.__repr__(pretty_printing=True)
     418            +
     419            -
     420            sage: b = T(rows=[])
     421            sage: pm=K.from_highest_weight_vector_to_pm_diagram(b); pm
     422            [[0, 2], [0, 0], [0]]
     423            sage: pm.__repr__(pretty_printing=True)
     424
     425            sage: hw = [ b for b in T if all(b.epsilon(i)==0 for i in [2,3,4]) ]
     426            sage: all(K.from_pm_diagram_to_highest_weight_vector(K.from_highest_weight_vector_to_pm_diagram(b)) == b for b in hw)
     427            True
     428        """
     429        n = self.cartan_type().rank()-1
     430        inner = Partition([Integer(b.weight()[i]) for i in range(1,n+1)])
     431        inter = Partition([len([i for i in r if i>0]) for r in b.to_tableau()])
     432        outer = b.to_tableau().shape()
     433        return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True)
     434 
     435    def from_pm_diagram_to_highest_weight_vector(self, pm):
     436        """
     437        This gives the bijection between a `\pm` diagram and an element b in the classical
     438        decomposition of the KR crystal that is {2,3,..,n}-highest weight.
     439
     440        EXAMPLES::
     441
     442            sage: K = KirillovReshetikhinCrystal(['D',4,1], 2,2)
     443            sage: pm = sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1, 1], [0, 0], [0]])
     444            sage: K.from_pm_diagram_to_highest_weight_vector(pm)
     445            [[2], [-2]]
     446        """
     447        u = [b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()][0]
     448        ct = self.cartan_type()
     449        rank = ct.rank()-1
     450        ct_type = ct.classical().type()
     451        assert ct_type in ['B', 'C', 'D']
     452        list = []
     453        for h in pm.heights_of_addable_plus():
     454            list += range(1,h+1)
     455        for h in pm.heights_of_minus():
     456            if ct_type == 'D':
     457                list += range(1,rank+1)+[rank-2-k for k in range(rank-1-h)]
     458            elif ct_type == 'B':
     459                list += range(1,rank+1)+[rank-k for k in range(rank+1-h)]
     460            else:
     461                list += range(1,rank+1)+[rank-1-k for k in range(rank-h)]
     462        for i in reversed(list):
     463            u = u.f(i)
     464        return u
     465
     466
     467class KR_type_C(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassical):
     468    r"""
     469    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `C_n^{(1)}` for `r<n`.
     470
     471    EXAMPLES::
     472
     473        sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     474        sage: K
     475        Kirillov-Reshetikhin crystal of type ['C', 2, 1] with (r,s)=(1,2)
     476        sage: b = K(rows=[])
     477        sage: b.f(0)
     478        [[1, 1]]
     479        sage: b.e(0)
     480        [[-1, -1]]
     481    """
     482    def __init__(self, cartan_type, r, s):
     483        r"""
     484        Initializes a Kirillov-Reshetikhin crystal of type `C_n^{(1)}`.
     485
     486        TESTS::
     487
     488            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KR_type_C(['C',2,1], 1, 1)
     489            sage: K
     490            Kirillov-Reshetikhin crystal of type ['C', 2, 1] with (r,s)=(1,1)
     491        """
     492        KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     493        AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition())
     494
     495    def classical_decomposition(self):
     496        """
     497        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `C_n^{(1)}`.
     498        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     499        a rectangle of width s and height r by removing horizontal dominoes. Here we identify the fundamental
     500        weight `\Lambda_i` with a column of height `i`.
     501
     502        EXAMPLES::
     503
     504            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     505            sage: K.classical_decomposition()
     506            The crystal of tableaux of type ['C', 3] and shape(s) [[], [2], [2, 2]]
     507        """
     508        return CrystalOfTableaux(self.cartan_type().classical(),
     509                                 shapes = horizontal_dominoes_removed(self.r(),self.s()))
     510
     511    def ambient_crystal(self):
     512        r"""
     513        Returns the ambient crystal `'B^{r,s}` of type `A_{2n+1}^{(2)}` associated to the Kirillov-Reshetikhin
     514        crystal of type `C_n^{(1)}`. This ambient crystal is used to construct the zero arrows.
     515
     516        EXAMPLES::
     517
     518            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,3)
     519            sage: K.ambient_crystal()
     520            Kirillov-Reshetikhin crystal of type ['B', 4, 1]^* with (r,s)=(2,3)
     521        """
     522        return KirillovReshetikhinCrystal(['A',2*self.cartan_type().classical().rank()+1,2], self.r(), self.s())
     523
     524    def ambient_dict_pm_diagrams(self):
     525        r"""
     526        Gives a dictionary of all self-dual `\pm` diagrams for the ambient crystal.
     527        Their key is their inner shape.
     528
     529        EXAMPLES::
     530
     531            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     532            sage: K.ambient_dict_pm_diagrams()
     533            {[]: [[1, 1], [0]], [2]: [[0, 0], [2]]}
     534            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     535            sage: K.ambient_dict_pm_diagrams()
     536            {[2, 2]: [[0, 0], [0, 0], [2]], []: [[1, 1], [0, 0], [0]], [2]: [[0, 0], [1, 1], [0]]}
     537            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,3)
     538            sage: K.ambient_dict_pm_diagrams()
     539            {[3, 3]: [[0, 0], [0, 0], [3]], [3, 1]: [[0, 0], [1, 1], [1]], [1, 1]: [[1, 1], [0, 0], [1]]}
     540        """
     541        list = []
     542        s = self.s()
     543        r = self.r()
     544        m = int(s/2)
     545        for i in range(m+1):
     546            for la in IntegerVectors(m-i, min_length=r, max_length=r):
     547                list.append(PMDiagram([[j,j] for j in la]+[[s-2*m+2*i]]))
     548        return dict( (x.inner_shape(), x) for x in list )
     549
     550    def ambient_highest_weight_dict(self):
     551        r"""
     552        Gives a dictionary of all `{2,...,n+1}`-highest weight vectors in the ambient crystal.
     553        Their key is the inner shape of their corresponding `\pm` diagram, or equivalently, their
     554        `{2,...,n+1}` weight.
     555
     556        EXAMPLES::
     557
     558            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     559            sage: K.ambient_highest_weight_dict()
     560            {[]: [[2], [-2]], [2, 2]: [[2, 2], [3, 3]], [2]: [[1, 2], [2, -1]]}
     561        """
     562        A = self.ambient_dict_pm_diagrams()
     563        ambient = self.ambient_crystal()
     564        return dict( (key, ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key]))) for key in A )
     565
     566    def highest_weight_dict(self):
     567        r"""
     568        Gives a dictionary of the classical highest weight vectors of self.
     569        Their key is their shape.
     570
     571        EXAMPLES::
     572
     573            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     574            sage: K.highest_weight_dict()
     575            {[2, 2]: [[1, 1], [2, 2]], []: [], [2]: [[1, 1]]}
     576        """
     577        return dict( (x.lift().to_tableau().shape(),x) for x in self.module_generators )
     578
     579    def to_ambient_crystal(self):
     580        r"""
     581        Provides a map from the Kirillov-Reshetikhin crystal of type `C_n^{(1)}` to the
     582        ambient crystal of type `A_{2n+1}^{(2)}`.
     583
     584        EXAMPLES::
     585
     586            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     587            sage: b=K(rows=[[1,1]])
     588            sage: K.to_ambient_crystal()(b)
     589            [[1, 2], [2, -1]]
     590            sage: b=K(rows=[])
     591            sage: K.to_ambient_crystal()(b)
     592            [[2], [-2]]
     593            sage: type(K.to_ambient_crystal()(b))
     594            <class 'sage.combinat.crystals.affine.AffineCrystalFromClassicalAndPromotionElement'>
     595        """
     596        keys = self.highest_weight_dict().keys()
     597        pdict = dict( (self.highest_weight_dict()[key], self.ambient_highest_weight_dict()[key]) for key in keys )
     598        return self.crystal_morphism( pdict, index_set = self.cartan_type().classical().index_set(),
     599                                      automorphism = lambda i : i+1 )
     600
     601    def from_ambient_crystal(self):
     602        r"""
     603        Provides a map from the ambient crystal of type `A_{2n+1}^{(2)}` to the Kirillov-Reshetikhin crystal of
     604        type `C_n^{(1)}`. Note that this map is only well-defined on elements that are in the image
     605        type `C_n^{(1)}` elements under `to_ambient_crystal`.
     606
     607        EXAMPLES::
     608
     609            sage: K = KirillovReshetikhinCrystal(['C',3,1], 2,2)
     610            sage: b=K.ambient_crystal()(rows=[[2,2],[3,3]])
     611            sage: K.from_ambient_crystal()(b)
     612            [[1, 1], [2, 2]]
     613        """
     614        keys = self.highest_weight_dict().keys()
     615        pdict_inv = dict( (self.ambient_highest_weight_dict()[key], self.highest_weight_dict()[key]) for key in keys )
     616        return self.crystal_morphism( pdict_inv, index_set = [j+1 for j in self.cartan_type().classical().index_set()],
     617                                      automorphism = lambda i : i-1 )
     618
     619class KR_type_CElement(AffineCrystalFromClassicalElement):
     620    r"""
     621    Class for the elements in the Kirillov-Reshetikhin crystals `B^{r,s}` of type `C_n^{(1)}` for `r<n`.
     622
     623    EXAMPLES::
     624
     625        sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     626        sage: type(K.module_generators[0])
     627        <class 'sage.combinat.crystals.kirillov_reshetikhin.KR_type_CElement'>
     628    """
     629
     630    def e0(self):
     631        r"""
     632        Gives `e_0` on self by mapping self to the ambient crystal, calculating `e_1 e_0` there and
     633        pulling the element back.
     634
     635        EXAMPLES::
     636
     637            sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     638            sage: b = K(rows=[])
     639            sage: b.e(0)
     640            [[-1, -1]]
     641        """
     642        b = self.parent().to_ambient_crystal()(self).e(1)
     643        if b is None:
     644            return None
     645        b = b.e(0)
     646        return self.parent().from_ambient_crystal()(b)
     647   
     648    def f0(self):
     649        r"""
     650        Gives `f_0` on self by mapping self to the ambient crystal, calculating `f_1 f_0` there and
     651        pulling the element back.
     652
     653        EXAMPLES::
     654
     655            sage: K=KirillovReshetikhinCrystal(['C',3,1],1,2)
     656            sage: b = K(rows=[])
     657            sage: b.f(0)
     658            [[1, 1]]
     659        """
     660        b = self.parent().to_ambient_crystal()(self).f(1)
     661        if b is None:
     662            return None
     663        b = b.f(0)
     664        return self.parent().from_ambient_crystal()(b)
     665
     666    def epsilon0(self):
     667        r"""
     668        Calculates `\epsilon_0` of self by mapping the element to the ambient crystal
     669        and calculating `\epsilon_1` there.
     670
     671        EXAMPLES::
     672
     673            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     674            sage: b=K(rows=[[1,1]])
     675            sage: b.epsilon(0)
     676            2
     677        """
     678        b = self.parent().to_ambient_crystal()(self)
     679        return b.epsilon(1)
     680
     681    def phi0(self):
     682        r"""
     683        Calculates `\phi_0` of self by mapping the element to the ambient crystal
     684        and calculating `\phi_1` there.
     685
     686        EXAMPLES::
     687
     688            sage: K = KirillovReshetikhinCrystal(['C',2,1], 1,2)
     689            sage: b=K(rows=[[-1,-1]])
     690            sage: b.phi(0)
     691            2
     692        """
     693        b = self.parent().to_ambient_crystal()(self)
     694        return b.phi(1)
     695
     696KR_type_C.element_class = KR_type_CElement
     697
     698
     699class KR_type_box(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassical):
     700    r"""
     701    Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `A_{2n}^{(2)}` for `r\le n`
     702    and type `D_{n+1}^{(2)}` for `r<n'.
     703
     704    EXAMPLES::
     705
     706        sage: K = KirillovReshetikhinCrystal(['A',4,2], 1,1)
     707        sage: K
     708        Kirillov-Reshetikhin crystal of type ['BC', 2, 2] with (r,s)=(1,1)
     709        sage: b = K(rows=[])
     710        sage: b.f(0)
     711        [[1]]
     712        sage: b.e(0)
     713        [[-1]]
     714    """
     715    def __init__(self, cartan_type, r, s):
     716        r"""
     717        Initializes a Kirillov-Reshetikhin crystal self.
     718
     719        TESTS::
     720
     721            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KR_type_box(['A',4,2], 1, 1)
     722            sage: K
     723            Kirillov-Reshetikhin crystal of type ['BC', 2, 2] with (r,s)=(1,1)
     724            sage: K = sage.combinat.crystals.kirillov_reshetikhin.KR_type_box(['D',4,2], 1, 1)
     725            sage: K
     726            Kirillov-Reshetikhin crystal of type ['C', 3, 1]^* with (r,s)=(1,1)
     727        """
     728        KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r ,s)
     729        AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition())
     730
     731    def classical_decomposition(self):
     732        r"""
     733        Specifies the classical crystal underlying the Kirillov-Reshetikhin crystal of type `A_{2n}^{(2)}`
     734        and `D_{n+1}^{(2)}`.
     735        It is given by `B^{r,s} \cong \oplus_\Lambda B(\Lambda)` where `\Lambda` are weights obtained from
     736        a rectangle of width s and height r by removing boxes. Here we identify the fundamental
     737        weight `\Lambda_i` with a column of height `i`.
     738
     739        EXAMPLES::
     740
     741            sage: K = KirillovReshetikhinCrystal(['A',4,2], 2,2)
     742            sage: K.classical_decomposition()
     743            The crystal of tableaux of type ['C', 2] and shape(s) [[], [1], [2], [1, 1], [2, 1], [2, 2]]
     744            sage: K = KirillovReshetikhinCrystal(['D',4,2], 2,3)
     745            sage: K.classical_decomposition()
     746            The crystal of tableaux of type ['B', 3] and shape(s) [[], [1], [2], [1, 1], [3], [2, 1], [3, 1], [2, 2], [3, 2], [3, 3]]
     747        """
     748        return CrystalOfTableaux(self.cartan_type().classical(),
     749                                 shapes = partitions_in_box(self.r(),self.s()))
     750
     751    def ambient_crystal(self):
     752        r"""
     753        Returns the ambient crystal `'B^{r,2s}` of type `C_n^{(1)}` associated to the Kirillov-Reshetikhin.
     754        This ambient crystal is used to construct the zero arrows.
     755
     756        EXAMPLES::
     757
     758            sage: K = KirillovReshetikhinCrystal(['A',4,2], 2,2)
     759            sage: K.ambient_crystal()
     760            Kirillov-Reshetikhin crystal of type ['C', 2, 1] with (r,s)=(2,4)
     761        """
     762        # calling KR_type_C instead of KirillovReshetikhin(['C',n,1],r,s) has the advantage that
     763        # that this also works for r=n for A_{2n}^{(2)}.
     764        return KR_type_C(['C', self.cartan_type().classical().rank(),1], self.r(), 2*self.s())
     765
     766    def highest_weight_dict(self):
     767        r"""
     768        Gives a dictionary of the classical highest weight vectors of self.
     769        Their key is 2 times their shape.
     770
     771        EXAMPLES::
     772
     773            sage: K = KirillovReshetikhinCrystal(['A',6,2], 2,2)
     774            sage: K.highest_weight_dict()
     775            {[4, 2]: [[1, 1], [2]], [2, 2]: [[1], [2]], []: [], [4]: [[1, 1]], [4, 4]: [[1, 1], [2, 2]], [2]: [[1]]}
     776        """
     777        return dict( (Partition([2*i for i in x.lift().to_tableau().shape()]),x) for x in self.module_generators )
     778
     779    def ambient_highest_weight_dict(self):
     780        r"""
     781        Gives a dictionary of the classical highest weight vectors of the ambient crystal of self.
     782        Their key is their shape.
     783
     784        EXAMPLES::
     785
     786            sage: K = KirillovReshetikhinCrystal(['A',6,2], 2,2)
     787            sage: K.ambient_highest_weight_dict()
     788            {[4, 2]: [[1, 1, 1, 1], [2, 2]], [2, 2]: [[1, 1], [2, 2]], []: [], [4]: [[1, 1, 1, 1]], [4, 4]: [[1, 1, 1, 1], [2, 2, 2, 2]],
     789            [2]: [[1, 1]]}
     790        """
     791        return dict( (x.lift().to_tableau().shape(),x) for x in self.ambient_crystal().module_generators )
     792
     793    def similarity_factor(self):
     794        r"""
     795        Sets the similarity factor used to map to the ambient crystal.
     796
     797        EXAMPLES::
     798
     799            sage: K = KirillovReshetikhinCrystal(['A',6,2], 2,2)
     800            sage: K.similarity_factor()
     801            {1: 2, 2: 2, 3: 2}
     802            sage: K = KirillovReshetikhinCrystal(['D',5,2], 1,1)
     803            sage: K.similarity_factor()
     804            {1: 2, 2: 2, 3: 2, 4: 1}
     805        """   
     806        C = self.cartan_type().classical()
     807        p = dict( (i,2) for i in C.index_set() )
     808        if C.type() == 'B':
     809            p[C.rank()] = 1
     810        return p
     811
     812    def to_ambient_crystal(self):
     813        r"""
     814        Provides a map from self to the ambient crystal of type `C_n^{(1)}`.
     815
     816        EXAMPLES::
     817
     818            sage: K = KirillovReshetikhinCrystal(['D',4,2], 1,1)
     819            sage: [K.to_ambient_crystal()(b) for b in K]
     820            [[], [[1, 1]], [[2, 2]], [[3, 3]], [[3, -3]], [[-3, -3]], [[-2, -2]], [[-1, -1]]]
     821            sage: K = KirillovReshetikhinCrystal(['A',4,2], 1,1)
     822            sage: [K.to_ambient_crystal()(b) for b in K]
     823            [[], [[1, 1]], [[2, 2]], [[-2, -2]], [[-1, -1]]]
     824        """
     825        keys = self.highest_weight_dict().keys()
     826        pdict = dict( (self.highest_weight_dict()[key], self.ambient_highest_weight_dict()[key]) for key in keys )
     827        return self.crystal_morphism( pdict, index_set = self.cartan_type().classical().index_set(),
     828                                      similarity_factor = self.similarity_factor() )
     829
     830    def from_ambient_crystal(self):
     831        r"""
     832        Provides a map from the ambient crystal of type `C_n^{(1)}` to the Kirillov-Reshetikhin crystal self.
     833        Note that this map is only well-defined on elements that are in the image under `to_ambient_crystal`.
     834
     835        EXAMPLES::
     836
     837            sage: K = KirillovReshetikhinCrystal(['D',4,2], 1,1)
     838            sage: b = K.ambient_crystal()(rows=[[3,-3]])
     839            sage: K.from_ambient_crystal()(b)
     840            [[0]]
     841            sage: K = KirillovReshetikhinCrystal(['A',4,2], 1,1)
     842            sage: b = K.ambient_crystal()(rows=[])
     843            sage: K.from_ambient_crystal()(b)
     844            []
     845        """
     846        keys = self.highest_weight_dict().keys()
     847        pdict_inv = dict( (self.ambient_highest_weight_dict()[key], self.highest_weight_dict()[key]) for key in keys )
     848        return self.crystal_morphism( pdict_inv, index_set = self.cartan_type().classical().index_set(),
     849                                      similarity_factor_domain = self.similarity_factor() )
     850
     851
     852class KR_type_boxElement(AffineCrystalFromClassicalElement):
     853    r"""
     854    Class for the elements in the Kirillov-Reshetikhin crystals `B^{r,s}` of type `A_{2n}^{(2)}` for `r\le n`
     855    and type `D_{n+1}^{(2)}` for `r<n`.
     856
     857    EXAMPLES::
     858
     859        sage: K=KirillovReshetikhinCrystal(['A',4,2],1,2)
     860        sage: type(K.module_generators[0])
     861        <class 'sage.combinat.crystals.kirillov_reshetikhin.KR_type_boxElement'>
     862    """
     863
     864    def e0(self):
     865        r"""
     866        Gives `e_0` on self by mapping self to the ambient crystal, calculating `e_0` there and
     867        pulling the element back.
     868
     869        EXAMPLES::
     870
     871            sage: K=KirillovReshetikhinCrystal(['A',4,2],1,1)
     872            sage: b = K(rows=[])
     873            sage: b.e(0)
     874            [[-1]]
     875        """
     876        b = self.parent().to_ambient_crystal()(self).e(0)
     877        if b is None:
     878            return None
     879        return self.parent().from_ambient_crystal()(b)
     880   
     881    def f0(self):
     882        r"""
     883        Gives `f_0` on self by mapping self to the ambient crystal, calculating `f_0` there and
     884        pulling the element back.
     885
     886        EXAMPLES::
     887
     888            sage: K=KirillovReshetikhinCrystal(['A',4,2],1,1)
     889            sage: b = K(rows=[])
     890            sage: b.f(0)
     891            [[1]]
     892        """
     893        b = self.parent().to_ambient_crystal()(self).f(0)
     894        if b is None:
     895            return None
     896        return self.parent().from_ambient_crystal()(b)
     897
     898    def epsilon0(self):
     899        r"""
     900        Calculates `\epsilon_0` of self by mapping the element to the ambient crystal
     901        and calculating `\epsilon_0` there.
     902
     903        EXAMPLES::
     904
     905            sage: K = KirillovReshetikhinCrystal(['A',4,2], 1,1)
     906            sage: b=K(rows=[[1]])
     907            sage: b.epsilon(0)
     908            2
     909        """
     910        b = self.parent().to_ambient_crystal()(self)
     911        return b.epsilon(0)
     912
     913    def phi0(self):
     914        r"""
     915        Calculates `\phi_0` of self by mapping the element to the ambient crystal
     916        and calculating `\phi_0` there.
     917
     918        EXAMPLES::
     919
     920            sage: K = KirillovReshetikhinCrystal(['D',3,2], 1,1)
     921            sage: b=K(rows=[[-1]])
     922            sage: b.phi(0)
     923            2
     924        """
     925        b = self.parent().to_ambient_crystal()(self)
     926        return b.phi(0)
     927
     928KR_type_box.element_class = KR_type_boxElement
     929
     930
     931class PMDiagram(CombinatorialObject):
     932    """
     933    Class of `\pm` diagrams. These diagrams are in one-to-one bijection with `X_{n-1}` highest weight vectors
     934    in an `X_n` highest weight crystal `X=B,C,D`. See Section 4.1 of A. Schilling, "Combinatorial structure of
     935    Kirillov-Reshetikhin crystals of type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)`", J. Algebra 319 (2008) 2938-2962
     936    (arXiv:0704.2046[math.QA]).
     937
     938    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.
     939    The tuple `[a_i,b_i]` specifies the number of `a_i` + and `b_i` - in the i-th row of the pm diagram
     940    if `n-i` is odd and the number of `a_i` +- pairs above row `i` and `b_i` columns of height `i` not containing
     941    any + or - if `n-i` is even.
     942
     943    Setting the option 'from_shapes = True' one can also input a `\pm` diagram in terms of its
     944    outer, intermediate and inner shape by specifying a tuple [n, s, outer, intermediate, inner]
     945    where `s` is the width of the `\pm` diagram, and 'outer' , 'intermediate',
     946    and 'inner' are the outer, intermediate and inner shape, respectively.
     947     
     948    EXAMPLES::
     949
     950        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     951        sage: pm.pm_diagram
     952        [[0, 1], [1, 2], [1]]
     953        sage: pm._list
     954        [1, 1, 2, 0, 1]
     955        sage: pm.n
     956        2
     957        sage: pm.width
     958        5
     959        sage: pm.__repr__(pretty_printing=True)
     960        .  .  .  .
     961        .  +  -  -
     962        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([2,5,[4,4],[4,2],[4,1]], from_shapes=True)
     963        [[0, 1], [1, 2], [1]]
     964
     965    TESTS::
     966       
     967        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     968        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     969        True
     970        sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     971        sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([pm.n, pm.width, pm.outer_shape(), pm.intermediate_shape(), pm.inner_shape()], from_shapes=True) == pm
     972        True
     973    """
     974
     975    def __init__(self, pm_diagram, from_shapes = None):
     976        r"""
     977        Initializes `\pm` diagrams.
     978
     979        TESTS::
     980
     981           sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     982           [[0, 1], [1, 2], [1]]
     983           sage: sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([2,5,[4,4],[4,2],[4,1]], from_shapes=True)
     984           [[0, 1], [1, 2], [1]]
     985        """
     986        if from_shapes:
     987            n = pm_diagram[0]
     988            s = pm_diagram[1]
     989            outer = [s]+list(pm_diagram[2])+[0 for i in range(n)]
     990            intermediate = [s]+list(pm_diagram[3])+[0 for i in range(n)]
     991            inner = [s]+list(pm_diagram[4])+[0 for i in range(n)]
     992            pm = [[inner[n]]]
     993            for i in range(int((n+1)/2)):
     994                pm.append([intermediate[n-2*i]-inner[n-2*i], inner[n-2*i-1]-intermediate[n-2*i]])
     995                pm.append([outer[n-2*i]-inner[n-2*i-1], inner[n-2*i-2]-outer[n-2*i]])
     996            if is_odd(n):
     997                pm.pop(n+1)
     998            pm_diagram = list(reversed(pm))
     999        self.pm_diagram = pm_diagram
     1000        self.n = len(pm_diagram)-1
     1001        self._list = [i for a in reversed(pm_diagram) for i in a]
     1002        self.width = sum(i for i in self._list)
     1003
     1004    def __repr__(self, pretty_printing = None):
     1005        """
     1006        Turning on pretty printing allows to display the pm diagram as a
     1007        tableau with the + and - displayed
     1008
     1009        EXAMPLES::
     1010
     1011            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     1012            sage: pm.__repr__(pretty_printing=True)
     1013            .  .  .  +
     1014            .  .  -  -
     1015            +  +
     1016            -  -
     1017            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,2], [0,0], [0]])
     1018            sage: pm.__repr__(pretty_printing=True)
     1019
     1020        """
     1021        if pretty_printing is None:
     1022            return repr(self.pm_diagram)
     1023        t = []
     1024        ish = self.inner_shape() + [0]*self.n
     1025        msh = self.intermediate_shape() + [0]*self.n
     1026        osh = self.outer_shape() + [0]*self.n
     1027        for i in range(self.n):
     1028            t.append(['.']*ish[i]+['+']*(msh[i]-ish[i])+['-']*(osh[i]-msh[i]))
     1029        t=[i for i in t if i!= []]
     1030        return Tableau(t).pp()
     1031
     1032    def inner_shape(self):
     1033        """
     1034        Returns the inner shape of the pm diagram
     1035
     1036        EXAMPLES::
     1037            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     1038            sage: pm.inner_shape()
     1039            [4, 1]
     1040            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     1041            sage: pm.inner_shape()
     1042            [7, 5, 3, 1]
     1043            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     1044            sage: pm.inner_shape()
     1045            [10, 7, 5, 3, 1]
     1046        """
     1047        t = []
     1048        ll = self._list
     1049        for i in range(self.n):
     1050            t.append(sum(ll[0:2*i+1]))
     1051        return Partition(list(reversed(t)))
     1052
     1053    def outer_shape(self):
     1054        """
     1055        Returns the outer shape of the pm diagram
     1056
     1057        EXAMPLES::
     1058
     1059            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     1060            sage: pm.outer_shape()
     1061            [4, 4]
     1062            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     1063            sage: pm.outer_shape()
     1064            [8, 8, 4, 4]
     1065            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     1066            sage: pm.outer_shape()
     1067            [13, 8, 8, 4, 4]
     1068        """
     1069        t = []
     1070        ll = self._list
     1071        for i in range((self.n)/2):
     1072            t.append(sum(ll[0:4*i+4]))
     1073            t.append(sum(ll[0:4*i+4]))
     1074        if is_even(self.n+1):
     1075            t.append(sum(ll[0:2*self.n+2]))
     1076        return Partition(list(reversed(t)))
     1077
     1078    def intermediate_shape(self):
     1079        """
     1080        Returns the intermediate shape of the pm diagram (innner shape plus positions of plusses)
     1081
     1082        EXAMPLES::
     1083
     1084            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     1085            sage: pm.intermediate_shape()
     1086            [4, 2]
     1087            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     1088            sage: pm.intermediate_shape()
     1089            [8, 6, 4, 2]
     1090            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     1091            sage: pm.intermediate_shape()
     1092            [11, 8, 6, 4, 2]
     1093            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,0],[0,1],[2,0],[0,0],[0]])
     1094            sage: pm.intermediate_shape()
     1095            [4, 2, 2]
     1096        """
     1097        p = self.inner_shape()
     1098        p = p + [0,0]
     1099        ll = list(reversed(self._list))
     1100        p = [ p[i]+ll[2*i+1] for i in range(self.n) ]
     1101        return Partition(p)
     1102
     1103    def heights_of_minus(self):
     1104        """
     1105        Returns a list with the heights of all minus in the `\pm` diagram.
     1106
     1107        EXAMPLES::
     1108
     1109            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     1110            sage: pm.heights_of_minus()
     1111            [5, 5, 3, 3, 1, 1]
     1112            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     1113            sage: pm.heights_of_minus()
     1114            [4, 4, 2, 2]
     1115        """
     1116        n = self.n
     1117        heights = []
     1118        for i in range(int((n+1)/2)):
     1119            heights += [n-2*i]*((self.outer_shape()+[0]*n)[n-2*i-1]-(self.intermediate_shape()+[0]*n)[n-2*i-1])
     1120        return heights
     1121
     1122    def heights_of_addable_plus(self):
     1123        """
     1124        Returns a list with the heights of all addable plus in the `\pm` diagram.
     1125
     1126        EXAMPLES::
     1127
     1128            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,2],[1,1],[1,1],[1,1],[1]])
     1129            sage: pm.heights_of_addable_plus()
     1130            [1, 1, 2, 3, 4, 5]
     1131            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[1,2],[1,1],[1,1],[1,1],[1]])
     1132            sage: pm.heights_of_addable_plus()
     1133            [1, 2, 3, 4]
     1134        """
     1135        heights = []
     1136        for i in range(1,self.n+1):
     1137            heights += [i]*self.sigma().pm_diagram[i][0]
     1138        return heights
     1139
     1140    def sigma(self):
     1141        """
     1142        Returns sigma on pm diagrams as needed for the analogue of the Dynkin diagram automorphism
     1143        that interchanges nodes `0` and `1` for type `D_n(1)`, `B_n(1)`, `A_{2n-1}(2)` for
     1144        Kirillov-Reshetikhin crystals.
     1145
     1146        EXAMPLES::
     1147
     1148            sage: pm=sage.combinat.crystals.kirillov_reshetikhin.PMDiagram([[0,1],[1,2],[1]])
     1149            sage: pm.sigma().pm_diagram
     1150            [[1, 0], [2, 1], [1]]
     1151        """
     1152        pm = self.pm_diagram
     1153        return PMDiagram([list(reversed(a)) for a in pm])
     1154
     1155
     1156def partitions_in_box(r, s):
     1157    """
     1158    Returns all partitions in a box of width s and height r.
     1159   
     1160    EXAMPLES::
     1161
     1162        sage: sage.combinat.crystals.kirillov_reshetikhin.partitions_in_box(3,2)
     1163        [[], [1], [2], [1, 1], [2, 1], [1, 1, 1], [2, 2], [2, 1, 1],
     1164        [2, 2, 1], [2, 2, 2]]
     1165    """
     1166    return [x for n in range(r*s+1) for x in Partitions(n,max_part=s,max_length=r)]
     1167
     1168def vertical_dominoes_removed(r, s):
     1169    """
     1170    Returns all partitions obtained from a rectangle of width s and height r by removing
     1171    vertical dominoes.
     1172
     1173    EXAMPLES::
     1174
     1175        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(2,2)
     1176        [[], [1, 1], [2, 2]]
     1177        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(3,2)
     1178        [[2], [2, 1, 1], [2, 2, 2]]
     1179        sage: sage.combinat.crystals.kirillov_reshetikhin.vertical_dominoes_removed(4,2)
     1180        [[], [1, 1], [1, 1, 1, 1], [2, 2], [2, 2, 1, 1], [2, 2, 2, 2]]
     1181    """
     1182    return [x.conjugate() for x in horizontal_dominoes_removed(s,r)]
     1183
     1184def horizontal_dominoes_removed(r, s):
     1185    """
     1186    Returns all partitions obtained from a rectangle of width s and height r by removing
     1187    horizontal dominoes.
     1188
     1189    EXAMPLES::
     1190
     1191        sage: sage.combinat.crystals.kirillov_reshetikhin.horizontal_dominoes_removed(2,2)
     1192        [[], [2], [2, 2]]
     1193        sage: sage.combinat.crystals.kirillov_reshetikhin.horizontal_dominoes_removed(3,2)
     1194        [[], [2], [2, 2], [2, 2, 2]]
     1195    """
     1196    list = [ [y for y in x] + [0 for i in range(r-x.length())] for x in partitions_in_box(r, int(s/2)) ]
     1197    two = lambda x : 2*(x-int(s/2)) + s
     1198    return [Partition([two(y) for y in x]) for x in list]
     1199
  • 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        """