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

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

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