Ticket #14759: trac_14759-monomial_crystals-bs.patch

File trac_14759-monomial_crystals-bs.patch, 39.1 KB (added by bsalisbury1, 9 years ago)
  • doc/en/reference/combinat/crystals.rst

    # HG changeset patch
    # User Ben Salisbury <bsalisbury1@gmail.com>
    # Date 1371493542 -7200
    # Node ID 1d319e92cb9d298c6dec7ae034d0a727131b90a8
    # Parent b6aba97f69d8272ac4c7d5a0fb1c25fef21cca67
    Crystals of (modified) Nakajima monomials.
    
    diff --git a/doc/en/reference/combinat/crystals.rst b/doc/en/reference/combinat/crystals.rst
    a b  
    1818   ../sage/combinat/crystals/tensor_product
    1919   ../sage/combinat/crystals/generalized_young_walls
    2020   ../sage/combinat/crystals/infinity_crystals
     21   ../sage/combinat/crystals/monomial_crystals
    2122
  • sage/combinat/crystals/all.py

    diff --git a/sage/combinat/crystals/all.py b/sage/combinat/crystals/all.py
    a b  
    1616from generalized_young_walls import CrystalOfGeneralizedYoungWalls, HighestWeightCrystalOfGYW
    1717from infinity_crystals import InfinityCrystalOfTableaux
    1818from elementary_crystals import TCrystal, RCrystal, ElementaryCrystal, ComponentCrystal
     19from monomial_crystals import InfinityCrystalOfNakajimaMonomials, CrystalOfNakajimaMonomials
  • new file sage/combinat/crystals/monomial_crystals.py

    diff --git a/sage/combinat/crystals/monomial_crystals.py b/sage/combinat/crystals/monomial_crystals.py
    new file mode 100644
    - +  
     1r"""
     2Crystals of Modified Nakajima Monomials
     3
     4AUTHORS:
     5
     6- Arthur Lubovsky: Initial version
     7
     8- Ben Salisbury: Initial version
     9
     10Let `Y_{i,k}`, for `i \in I` and `k \in \ZZ`, be a commuting set of
     11variables, and let `\boldsymbol{1}` be a new variable which commutes with
     12each `Y_{i,k}`.  (Here, `I` represents the index set of a Cartan datum.)  One
     13may endow the structure of a crystal on the set `\widehat{\mathcal{M}}` of
     14monomials of the form
     15
     16.. MATH::
     17
     18    M = \prod_{(i,k) \in I\times \ZZ_{\ge0}} Y_{i,k}^{y_i(k)}\boldsymbol{1}.
     19
     20Elements of `\widehat{\mathcal{M}}` are called  *modified Nakajima monomials*.
     21We will omit the `\boldsymbol{1}` from the end of a monomial if there exists
     22at least one `y_i(k) \neq 0`.  The crystal structure on this set is defined by
     23
     24.. MATH::
     25
     26    \begin{aligned}
     27    \mathrm{wt}(M) &= \sum_{i\in I} \Bigl( \sum_{k\ge 0} y_i(k) \Bigr) \Lambda_i, \\
     28    \varphi_i(M) &= \max\Bigl\{ \sum_{0\le j \le k} y_i(j) : k\ge 0 \Bigr\}, \\
     29    \varepsilon_i(M) &= \varphi_i(M) - \langle h_i, \mathrm{wt}(M) \rangle, \\
     30    k_f = k_f(M) &= \min\Bigl\{ k\ge 0 : \varphi_i(M) = \sum_{0\le j\le k} y_i(j) \Bigr\}, \\
     31    k_e = k_e(M) &= \max\Bigl\{ k\ge 0 : \varphi_i(M) = \sum_{0\le j\le k} y_i(j) \Bigr\},
     32    \end{aligned}
     33
     34where `\{h_i : i \in I\}` and `\{\Lambda_i : i \in I \}` are the simple
     35coroots and fundamental weights, respectively.  With a chosen set of integers
     36`C = (c_{ij})_{i\neq j}` such that `c_{ij}+c{ji} =1`, one defines
     37
     38.. MATH::
     39
     40    A_{i,k} = Y_{i,k} Y_{i,k+1} \prod_{j\neq i} Y_{j,k+c_{ji}}^{a_{ji}},
     41
     42where `(a_{ij})` is a Cartan matrix.  Then
     43
     44.. MATH::
     45
     46    \begin{aligned}
     47    e_iM &= \begin{cases} 0 & \text{if } \varepsilon_i(M) = 0, \\
     48    A_{i,k_e}M & \text{if } \varepsilon_i(M) > 0, \end{cases} \\
     49    f_iM &= A_{i,k_f}^{-1} M.
     50    \end{aligned}
     51
     52It is shown in [KKS07]_ that the connected component of `\widehat{\mathcal{M}}`
     53containing the element `\boldsymbol{1}`, which we denote by
     54`\mathcal{M}(\infty)`, is crystal isomorphic to the crystal `B(\infty)`.
     55
     56Let `\widetilde{\mathcal{M}}` be `\widehat{\mathcal{M}}` as a set, and with
     57crystal structure defined as on `\widehat{\mathcal{M}}` with the exception
     58that
     59
     60.. MATH::
     61
     62    f_iM = \begin{cases} 0 & \text{if } \varphi_i(M) = 0, \\
     63    A_{i,k_f}^{-1}M & \text{if } \varphi_i(M) > 0. \end{cases}
     64
     65Then Kashiwara [Kash03]_ showed that the connected component in
     66`\widetilde{\mathcal{M}}` containing a monomial `M` such that `e_iM = 0`, for
     67all `i \in I`, is crystal isomorphic to the irreducible highest weight
     68crystal `B(\mathrm{wt}(M))`.
     69
     70WARNING:
     71
     72    Monomial crystals depend on the choice of positive integers
     73    `C = (c_{ij})_{i\neq j}` satisfying the condition `c_{ij}+c_{ji}=1`.
     74    We have chosen such integers uniformly such that `c_{ij} = 1` if
     75    `i < j` and `c_{ij} = 0` if `i>j`.
     76
     77REFERENCES:
     78
     79.. [KKS07] S.-J. Kang, J.-A. Kim, and D.-U. Shin.
     80   Modified Nakajima Monomials and the Crystal `B(\infty)`.
     81   J. Algebra **308**, pp. 524--535, 2007.
     82
     83.. [Kash03] M. Kashiwara.
     84   Realizations of Crystals.
     85   Combinatorial and geometric representation theory (Seoul, 2001),
     86   Contemp. Math. **325**, Amer. Math. Soc., pp. 133--139, 2003.
     87"""
     88
     89#******************************************************************************
     90#  Copyright (C) 2013
     91#
     92#  Arthur Lubovsky (alubovsky at albany dot edu)
     93#  Ben Salisbury (ben dot salisbury at cmich dot edu)
     94#
     95#  Distributed under the terms of the GNU General Public License (GPL)
     96#                  http://www.gnu.org/licenses/
     97#******************************************************************************
     98
     99from copy import copy
     100from sage.structure.element import Element
     101from sage.structure.parent import Parent
     102from sage.structure.unique_representation import UniqueRepresentation
     103from sage.combinat.combinat import CombinatorialObject
     104from sage.categories.highest_weight_crystals import HighestWeightCrystals
     105from sage.categories.regular_crystals import RegularCrystals
     106from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
     107from sage.combinat.root_system.cartan_type import CartanType
     108from sage.combinat.root_system.root_system import RootSystem
     109from sage.rings.infinity import Infinity
     110
     111class NakajimaYMonomial(Element):
     112    r"""
     113    Monomials of the form `Y_{i_1,k_1}^{a_1}\cdots Y_{i_t,k_t}^{y_t}`, where
     114    `i_1,\dots,i_t` are elements of the index set, `k_1,\dots,k_t` are
     115    nonnegative integers, and `y_1,\dots,y_t` are integers.
     116
     117    EXAMPLES::
     118
     119        sage: M = InfinityCrystalOfNakajimaMonomials(['B',3,1])
     120        sage: mg = M.module_generators[0]
     121        sage: mg
     122        1
     123        sage: mg.f_string([1,3,2,0,1,2,3,0,0,1])
     124        Y(0,0)^-1 Y(0,1)^-1 Y(0,2)^-1 Y(0,3)^-1 Y(1,0)^-3 Y(1,1)^-2 Y(1,2) Y(2,0)^3 Y(2,2) Y(3,0) Y(3,2)^-1
     125        """
     126
     127    def __init__(self,parent,dict):
     128        r"""
     129        INPUT:
     130
     131        - ``dict`` -- a dictionary of with pairs of the form ``{(i,k):y}``
     132
     133        EXAMPLES::
     134
     135            sage: M = InfinityCrystalOfNakajimaMonomials("C5")
     136            sage: mg = M.module_generators[0]
     137            sage: TestSuite(mg).run()
     138        """
     139        self._dict = dict
     140        Element.__init__(self, parent)
     141
     142    def _repr_(self):
     143        r"""
     144        Return a string representation of ``self``.
     145
     146        EXAMPLES::
     147
     148            sage: M = InfinityCrystalOfNakajimaMonomials(['A',5,2])
     149            sage: M({(1,0):1,(2,2):-2,(0,5):10})
     150            Y(0,5)^10 Y(1,0) Y(2,2)^-2
     151        """
     152        if self._dict == {}:
     153            return "1"
     154        else:
     155            L = sorted(self._dict.iteritems(), key=lambda x:(x[0][0],x[0][1]))
     156            return_str = ''
     157            for x in range(len(L)):
     158                if L[x][1] != 1:
     159                    return_str += "Y(%s,%s)"%(L[x][0][0],L[x][0][1]) + "^%s "%L[x][1]
     160                else:
     161                    return_str += "Y(%s,%s) "%(L[x][0][0],L[x][0][1])
     162            return return_str
     163
     164    def __eq__(self,other):
     165        r"""
     166        EXAMPLES::
     167
     168            sage: M = InfinityCrystalOfNakajimaMonomials(['C',5])
     169            sage: m1 = M.module_generators[0].f(1)
     170            sage: m2 = M.module_generators[0].f(2)
     171            sage: m1.__eq__(m2)
     172            False
     173            sage: m1.__eq__(m1)
     174            True
     175        """
     176        if isinstance(other, NakajimaYMonomial):
     177            return self._dict == other._dict
     178        return self._dict == other
     179
     180    def __ne__(self,other):
     181        r"""
     182        EXAMPLES::
     183
     184            sage: La = RootSystem(['A',2]).weight_lattice().fundamental_weights()
     185            sage: M = CrystalOfNakajimaMonomials(['A',2],La[1]+La[2])
     186            sage: m0 = M.module_generators[0]
     187            sage: m = M.module_generators[0].f(1).f(2).f(2).f(1)
     188            sage: m.__ne__(m0)
     189            True
     190            sage: m.__ne__(m)
     191            False
     192        """
     193        return not self.__eq__(other)
     194
     195    def __lt__(self,other):
     196        r"""
     197        EXAMPLES::
     198
     199            sage: M = InfinityCrystalOfNakajimaMonomials(['F',4])
     200            sage: mg = M.module_generators[0]
     201            sage: m = mg.f(4)
     202            sage: m.__lt__(mg)
     203            False
     204            sage: mg.__lt__(m)
     205            False
     206        """
     207        return False
     208
     209    def _latex_(self):
     210        r"""
     211        Return a `\LaTeX` representation of ``self``.
     212
     213        EXAMPLES::
     214
     215            sage: M = InfinityCrystalOfNakajimaMonomials(['G',2,1])
     216            sage: M.module_generators[0].f_string([1,0,2])._latex_()
     217            'Y_{0,0}^{-1} Y_{1,0}^{-1} Y_{1,1}^{2} Y_{2,0} Y_{2,1}^{-1} '
     218        """
     219        if self._dict == {}:
     220            return "\\boldsymbol{1}"
     221        else:
     222            L = sorted(self._dict.iteritems(), key=lambda x:(x[0][0],x[0][1]))
     223            return_str = ''
     224            for x in range(len(L)):
     225                if L[x][1] != 1:
     226                    return_str += "Y_{%s,%s}"%(L[x][0][0],L[x][0][1]) + "^{%s} "%L[x][1]
     227                else:
     228                    return_str += "Y_{%s,%s} "%(L[x][0][0],L[x][0][1])
     229            return return_str
     230
     231    def weight(self):
     232        r"""
     233        Return the weight of ``self`` as an element of
     234        ``self.parent().weight_lattice_realization``.
     235
     236        EXAMPLES::
     237
     238            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,2])
     239            sage: m = M.module_generators[0].f_string([0,3,2,0,1])
     240            sage: m.weight()
     241            -2*Lambda[0] + Lambda[1]
     242
     243            sage: M = InfinityCrystalOfNakajimaMonomials(['E',6])
     244            sage: m = M.module_generators[0].f_string([1,5,2,6,3])
     245            sage: m.weight()
     246            (-1/2, -3/2, 3/2, 1/2, -1/2, 1/2, 1/2, -1/2)
     247        """
     248        P = self.parent().weight_lattice_realization()
     249        La = P.fundamental_weights()
     250        return P(sum(v*La[k[0]] for k,v in self._dict.iteritems()))
     251
     252    def weight_in_root_lattice(self):
     253        r"""
     254        Return the weight of ``self`` as an element of the root lattice.
     255
     256        EXAMPLES::
     257
     258            sage: M = InfinityCrystalOfNakajimaMonomials(['F',4])
     259            sage: m = M.module_generators[0].f_string([3,3,1,2,4])
     260            sage: m.weight_in_root_lattice()
     261            -alpha[1] - alpha[2] - 2*alpha[3] - alpha[4]
     262
     263            sage: M = InfinityCrystalOfNakajimaMonomials(['B',3,1])
     264            sage: mg = M.module_generators[0]
     265            sage: m = mg.f_string([1,3,2,0,1,2,3,0,0,1])
     266            sage: m.weight_in_root_lattice()
     267            -3*alpha[0] - 3*alpha[1] - 2*alpha[2] - 2*alpha[3]
     268        """
     269        Q = RootSystem(self.parent().cartan_type()).root_lattice()
     270        alpha = Q.simple_roots()
     271        path = self.to_highest_weight()
     272        return Q(sum(-alpha[j] for j in path[1]))
     273
     274    def epsilon(self,i):
     275        r"""
     276        Return the value of `\varepsilon_i` on ``self``.
     277
     278        INPUT:
     279
     280        - ``i`` -- an element of the index set
     281
     282        EXAMPLES::
     283
     284            sage: M = InfinityCrystalOfNakajimaMonomials(['G',2,1])
     285            sage: m = M.module_generators[0].f(2)
     286            sage: [m.epsilon(i) for i in M.index_set()]
     287            [0, 0, 1]
     288        """
     289        if i not in self.parent().index_set():
     290            raise ValueError("i must be an element of the index set")
     291        h = self.parent().weight_lattice_realization().simple_coroots()
     292        return self.phi(i) - self.weight().scalar(h[i])
     293
     294    def phi(self,i):
     295        r"""
     296        Return the value of `\varphi_i` on ``self``.
     297
     298        INPUT:
     299
     300        - ``i`` -- an element of the index set
     301
     302        EXAMPLES::
     303
     304            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,3])
     305            sage: m = M.module_generators[0].f(1)
     306            sage: [m.phi(i) for i in M.index_set()]
     307            [1, -1, 1]
     308        """
     309        if i not in self.parent().index_set():
     310            raise ValueError("i must be an element of the index set")
     311        dict = self._dict
     312        if dict == {}:
     313            return 0
     314        else:
     315            L = [x[0] for x in dict.keys()]
     316            if i not in L:
     317                return 0
     318            else:
     319                d = copy(dict)
     320                K = max(x[1] for x in list(d) if x[0] ==i)
     321                for a in range(K):
     322                    if d.has_key((i,a)):
     323                        continue
     324                    else:
     325                        d[(i,a)] = 0
     326                S = sorted(filter(lambda x: x[0][0]==i, d.iteritems()), key=lambda x: x[0][1])
     327                return max(sum(S[k][1] for k in range(s)) for s in range(1,len(S)+1))
     328
     329    def _ke(self,i):
     330        r"""
     331        Return the value `k_e` with respect to ``i`` and ``self``.
     332
     333        INPUT:
     334
     335        - ``i`` -- an element of the index set
     336
     337        EXAMPLES::
     338
     339            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,3])
     340            sage: m = M.module_generators[0].f(1)
     341            sage: [m._ke(i) for i in M.index_set()]
     342            [+Infinity, 0, +Infinity]
     343        """
     344        dict = self._dict
     345        sum = 0
     346        L = []
     347        phi = self.phi(i)
     348        if self.epsilon(i) == 0:
     349            return Infinity
     350        else:
     351            d = copy(dict)
     352            K = max(x[1] for x in list(d) if x[0] ==i)
     353            for a in range(K):
     354                if d.has_key((i,a)):
     355                    continue
     356                else:
     357                    d[(i,a)] = 0
     358            S = sorted(filter(lambda x: x[0][0]==i, d.iteritems()), key=lambda x: x[0][1])
     359            for var,exp in S:
     360                sum += exp
     361                if sum == phi:
     362                    L.append(var[1])
     363            if L == []:
     364                return 0
     365            else:
     366                return max(L)
     367
     368    def _kf(self,i):
     369        r"""
     370        Return the value `k_f` with respect to ``i`` and ``self``.
     371
     372        INPUT:
     373
     374        - ``i`` -- an element of the index set
     375
     376        EXAMPLES::
     377
     378            sage: M = InfinityCrystalOfNakajimaMonomials(['F',4,1])
     379            sage: m = M.module_generators[0].f_string([0,1,4,3])
     380            sage: [m._kf(i) for i in M.index_set()]
     381            [0, 0, 2, 0, 0]
     382        """
     383        d = copy(self._dict)
     384        I = [x[0] for x in d]
     385        if i not in I:
     386            return 0
     387        else:
     388            K = max(x[1] for x in list(d) if x[0] ==i)
     389            for a in range(K):
     390                if d.has_key((i,a)):
     391                    continue
     392                else:
     393                    d[(i,a)] = 0
     394            S = sorted(filter(lambda x: x[0][0]==i, d.iteritems()), key=lambda x: x[0][1])
     395            sum = 0
     396            phi = self.phi(i)
     397            L = []
     398            for var,exp in S:
     399                sum += exp
     400                if sum == phi:
     401                    return var[1]
     402
     403    def e(self,i):
     404        r"""
     405        Return the action of `e_i` on ``self``.
     406
     407        INPUT:
     408
     409        - ``i`` -- an element of the index set
     410
     411        EXAMPLES::
     412
     413            sage: M = InfinityCrystalOfNakajimaMonomials(['E',7,1])
     414            sage: m = M.module_generators[0].f_string([0,1,4,3])
     415            sage: [m.e(i) for i in M.index_set()]
     416            [None,
     417             None,
     418             None,
     419             Y(0,0)^-1 Y(1,1)^-1 Y(2,1) Y(3,0) Y(3,1) Y(4,0)^-1 Y(4,1)^-1 Y(5,0) ,
     420             None,
     421             None,
     422             None,
     423             None]
     424
     425            sage: M = InfinityCrystalOfNakajimaMonomials("C5")
     426            sage: m = M.module_generators[0].f_string([1,3])
     427            sage: [m.e(i) for i in M.index_set()]
     428            [Y(2,1) Y(3,0)^-1 Y(3,1)^-1 Y(4,0) ,
     429             None,
     430             Y(1,0)^-1 Y(1,1)^-1 Y(2,0) ,
     431             None,
     432             None]
     433        """
     434        if i not in self.parent().index_set():
     435            raise ValueError("i must be an element of the index set")
     436        if self.epsilon(i) == 0:
     437            return None
     438
     439        newdict = copy(self._dict)
     440        ke = self._ke(i)
     441        Aik = {(i, ke):1, (i, ke+1):1}
     442        ct = self.parent().cartan_type()
     443        cm = ct.cartan_matrix()
     444        shift = 0
     445        if self.parent().cartan_type().is_finite():
     446            shift = 1
     447        for j in self.parent().index_set():
     448            if i == j:
     449                continue
     450            c = 0
     451            if i > j:
     452                c = 1
     453            if ct.is_affine() and ct.type() == 'A' and abs(i-j) == ct.rank() - 1:
     454                c = 1 - c
     455            if cm[j-shift][i-shift] != 0:
     456                Aik[(j, ke+c)] = cm[j-shift][i-shift]
     457        for key,value in Aik.iteritems():
     458            if newdict.has_key(key):
     459                newdict[key] +=value
     460            else:
     461                newdict[key] = value
     462        for k in list(newdict):
     463            if newdict[k] == 0:
     464                newdict.pop(k)
     465        return self.__class__(self.parent(),newdict)
     466
     467    def f(self,i):
     468        r"""
     469        Return the action of `f_i` on ``self``.
     470
     471        INPUT:
     472
     473        - ``i`` -- an element of the index set
     474
     475        EXAMPLES::
     476
     477            sage: M = InfinityCrystalOfNakajimaMonomials("B4")
     478            sage: m = M.module_generators[0].f_string([1,3,4])
     479            sage: [m.f(i) for i in M.index_set()]
     480            [Y(1,0)^-2 Y(1,1)^-2 Y(2,0)^2 Y(2,1) Y(3,0)^-1 Y(4,0) Y(4,1)^-1 ,
     481             Y(1,0)^-1 Y(1,1)^-1 Y(1,2) Y(2,0) Y(2,2)^-1 Y(3,0)^-1 Y(3,1) Y(4,0) Y(4,1)^-1 ,
     482             Y(1,0)^-1 Y(1,1)^-1 Y(2,0) Y(2,1)^2 Y(3,0)^-2 Y(3,1)^-1 Y(4,0)^3 Y(4,1)^-1 ,
     483             Y(1,0)^-1 Y(1,1)^-1 Y(2,0) Y(2,1) Y(3,0)^-1 Y(3,1) Y(4,1)^-2 ]
     484        """
     485        if i not in self.parent().index_set():
     486            raise ValueError("i must be an element of the index set")
     487        newdict = copy(self._dict)
     488        kf = self._kf(i)
     489        Aik = {(i, kf):-1, (i, kf+1):-1}
     490        ct = self.parent().cartan_type()
     491        cm = ct.cartan_matrix()
     492        shift = 0
     493        if ct.is_finite():
     494            shift = 1
     495        for j in self.parent().index_set():
     496            if i == j:
     497                continue
     498            c = 0
     499            if i > j:
     500                c = 1
     501            if ct.is_affine() and ct.type() == 'A' and abs(i-j) == ct.rank() - 1:
     502                c = 1 - c
     503            if cm[j-shift][i-shift] != 0:
     504                Aik[(j, kf+c)] = -cm[j-shift][i-shift]
     505        for key,value in Aik.iteritems():
     506            if newdict.has_key(key):
     507                newdict[key] +=value
     508            else:
     509                newdict[key] = value
     510        for k in list(newdict):
     511            if newdict[k] == 0:
     512                newdict.pop(k)
     513        return self.__class__(self.parent(),newdict)
     514
     515class NakajimaAMonomial(NakajimaYMonomial):
     516    r"""
     517    Monomials of the form `A_{i_1,k_1}^{a_1}\cdots A_{i_t,k_t}^{a_t}`, where
     518    `i_1,\dots,i_t` are elements of the index set, `k_1,\dots,k_t` are
     519    nonnegative integers, and `a_1,\dots,a_t` are integers.
     520
     521    EXAMPLES::
     522
     523        sage: M = InfinityCrystalOfNakajimaMonomials("A3",use_Y=False)
     524        sage: mg = M.module_generators[0]
     525        sage: mg.f_string([1,2,3,2,1])
     526        A(1,0)^-1 A(1,1)^-1 A(2,0)^-2 A(3,0)^-1
     527        sage: mg.f_string([3,2,1])
     528        A(1,2)^-1 A(2,1)^-1 A(3,0)^-1
     529    """
     530
     531    def _repr_(self):
     532        r"""
     533        Return a string representation of ``self``.
     534
     535        EXAMPLES::
     536
     537            sage: M = InfinityCrystalOfNakajimaMonomials(['B',4,1],use_Y=False)
     538            sage: m = M.module_generators[0].f_string([4,2,1])
     539            sage: m
     540            A(1,1)^-1 A(2,0)^-1 A(4,0)^-1
     541        """
     542        if self._dict == {}:
     543            return "1"
     544        else:
     545            L = sorted(self._dict.iteritems(), key=lambda x:(x[0][0],x[0][1]))
     546            return_str = ''
     547            for x in range(len(L)):
     548                if L[x][1] != 1:
     549                    return_str += "A(%s,%s)"%(L[x][0][0],L[x][0][1]) + "^%s "%L[x][1]
     550                else:
     551                    return_str += "A(%s,%s) "%(L[x][0][0],L[x][0][1])
     552            return return_str
     553
     554    def _latex_(self):
     555        r"""
     556        Return a `\LaTeX` representation of ``self``.
     557
     558        EXAMPLES::
     559
     560            sage: M = InfinityCrystalOfNakajimaMonomials(['C',4,1],use_Y=False)
     561            sage: m = M.module_generators[0].f_string([4,2,3])
     562            sage: m._latex_()
     563            'A_{2,0}^{-1} A_{3,1}^{-1} A_{4,0}^{-1} '
     564        """
     565        if self._dict == {}:
     566            return "\\boldsymbol{1}"
     567        else:
     568            L = sorted(self._dict.iteritems(), key=lambda x:(x[0][0],x[0][1]))
     569            return_str = ''
     570            for x in range(len(L)):
     571                if L[x][1] !=1:
     572                    return_str += "A_{%s,%s}"%(L[x][0][0],L[x][0][1]) + "^{%s} "%L[x][1]
     573                else:
     574                    return_str += "A_{%s,%s} "%(L[x][0][0],L[x][0][1])
     575            return return_str
     576
     577    def to_Y_monomial(self):
     578        r"""
     579        Represent `\prod_{(i,k)} A_{i,k}^{a_{i}(k)}` in the form
     580        `\prod_{(i,k)} Y_{i,k}^{y_i(k)}` using the formula
     581
     582        .. MATH::
     583
     584            A_{i,k} = Y_{i,k} Y_{i,k+1} \prod_{\substack{j \in I \\ j\neq i}}
     585            Y_{i,k+c_{ji}}^{a_{ji}}.
     586
     587        EXAMPLES::
     588
     589            sage: M = InfinityCrystalOfNakajimaMonomials(['A',2,1],use_Y=False)
     590            sage: m = M.module_generators[0].f_string([2,0,1,2,1])
     591            sage: m
     592            A(0,0)^-1 A(1,0)^-1 A(1,1)^-1 A(2,0)^-1 A(2,1)^-1
     593            sage: m.to_Y_monomial()
     594            Y(0,1) Y(0,2) Y(1,1)^-1 Y(2,2)^-1
     595        """
     596        Y = {}
     597        d = self._dict
     598        ct = self.parent().cartan_type()
     599        cm = ct.cartan_matrix()
     600        for k,v in d.iteritems():
     601            Y[k] = Y.get(k,0) + v
     602            Y[(k[0],k[1]+1)] = Y.get((k[0],k[1]+1), 0) + v
     603            shift = 0
     604            if ct.is_finite():
     605                shift = 1
     606            for j in self.parent().index_set():
     607                if k[0] == j:
     608                    continue
     609                c = 0
     610                if k[0] > j:
     611                    c = 1
     612                if ct.is_affine() and ct.type() == 'A' and abs(k[0]-j) == ct.rank() - 1:
     613                    c = 1 - c
     614                if cm[j-shift][k[0]-shift] != 0:
     615                    Y[(j, k[1]+c)] = Y.get((j,k[1]+c),0) + v*cm[j-shift][k[0]-shift]
     616        for k in Y.keys():
     617            if Y[k] == 0:
     618                Y.pop(k)
     619        return NakajimaYMonomial(self.parent(), Y)
     620
     621    def weight(self):
     622        r"""
     623        Return the weight of ``self`` as an element of
     624        ``self.parent().weight_lattice_realization()``.
     625
     626        EXAMPLES::
     627
     628            sage: M = InfinityCrystalOfNakajimaMonomials(['A',4,2],use_Y=False)
     629            sage: m = M.module_generators[0].f_string([1,2,0,1])
     630            sage: m.weight()
     631            2*Lambda[0] - Lambda[1]
     632        """
     633        return self.to_Y_monomial().weight()
     634
     635    def weight_in_root_lattice(self):
     636        r"""
     637        Return the weight of ``self`` as an element of the root lattice.
     638
     639        EXAMPLES::
     640
     641            sage: M = InfinityCrystalOfNakajimaMonomials(['C',3,1],use_Y=False)
     642            sage: m = M.module_generators[0].f_string([3,0,1,2,0])
     643            sage: m.weight_in_root_lattice()
     644            -2*alpha[0] - alpha[1] - alpha[2] - alpha[3]
     645        """
     646        return self.to_Y_monomial().weight_in_root_lattice()
     647
     648    def epsilon(self,i):
     649        r"""
     650        Return the action of `\varepsilon_i` on ``self``.
     651
     652        INPUT:
     653
     654        - ``i`` -- an element of the index set
     655
     656        EXAMPLES::
     657
     658            sage: M = InfinityCrystalOfNakajimaMonomials(['C',4,1],use_Y=False)
     659            sage: m = M.module_generators[0].f_string([4,2,3])
     660            sage: [m.epsilon(i) for i in M.index_set()]
     661            [0, 0, 0, 1, 0]
     662        """
     663        if i not in self.parent().index_set():
     664            raise ValueError("i must be an element of the index set")
     665        return self.to_Y_monomial().epsilon(i)
     666
     667    def phi(self,i):
     668        r"""
     669        Return the action of `\varphi_i` on ``self``.
     670
     671        INPUT:
     672
     673        - ``i`` -- an element of the index set
     674
     675        EXAMPLES::
     676
     677            sage: M = InfinityCrystalOfNakajimaMonomials(['C',4,1],use_Y=False)
     678            sage: m = M.module_generators[0].f_string([4,2,3])
     679            sage: [m.phi(i) for i in M.index_set()]
     680            [0, 1, -1, 2, -1]
     681        """
     682        if i not in self.parent().index_set():
     683            raise ValueError("i must be an element of the index set")
     684        return self.to_Y_monomial().phi(i)
     685
     686    def e(self,i):
     687        r"""
     688        Return the action of `e_i` on ``self``.
     689
     690        INPUT:
     691
     692        - ``i`` -- an element of the index set
     693
     694        EXAMPLES::
     695
     696            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,1],use_Y=False)
     697            sage: m = M.module_generators[0].f_string([4,2,3,0])
     698            sage: [m.e(i) for i in M.index_set()]
     699            [A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 ,
     700             None,
     701             None,
     702             A(0,2)^-1 A(2,1)^-1 A(4,0)^-1 ,
     703             None]
     704        """
     705        if i not in self.parent().index_set():
     706            raise ValueError("i must be an element of the index set")
     707        if self.epsilon(i) == 0:
     708            return None
     709        ke = self.to_Y_monomial()._ke(i)
     710        d = copy(self._dict)
     711        d[(i,ke)] = d.get((i,ke),0)+1
     712        for k in list(d):
     713            if d[k] == 0:
     714                d.pop(k)
     715        return self.__class__(self.parent(), d)
     716
     717    def f(self,i):
     718        r"""
     719        Return the action of `f_i` on ``self``.
     720
     721        INPUT:
     722
     723        - ``i`` -- an element of the index set
     724
     725        EXAMPLES::
     726
     727            sage: M = InfinityCrystalOfNakajimaMonomials("E8",use_Y=False)
     728            sage: m = M.module_generators[0].f_string([4,2,3,8])
     729            sage: m
     730            A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(8,0)^-1
     731            sage: [m.f(i) for i in M.index_set()]
     732            [A(1,2)^-1 A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(8,0)^-1 ,
     733             A(2,0)^-1 A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(8,0)^-1 ,
     734             A(2,1)^-1 A(3,0)^-1 A(3,1)^-1 A(4,0)^-1 A(8,0)^-1 ,
     735             A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(4,1)^-1 A(8,0)^-1 ,
     736             A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(5,0)^-1 A(8,0)^-1 ,
     737             A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(6,0)^-1 A(8,0)^-1 ,
     738             A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(7,1)^-1 A(8,0)^-1 ,
     739             A(2,1)^-1 A(3,1)^-1 A(4,0)^-1 A(8,0)^-2 ]
     740        """
     741        if i not in self.parent().index_set():
     742            raise ValueError("i must be an element of the index set")
     743        kf = self.to_Y_monomial()._kf(i)
     744        d = copy(self._dict)
     745        d[(i,kf)] = d.get((i,kf),0) - 1
     746        return self.__class__(self.parent(), d)
     747
     748class InfinityCrystalOfNakajimaMonomials(Parent,UniqueRepresentation):
     749    r"""
     750    Let `Y_{i,k}`, for `i \in I` and `k \in \ZZ`, be a commuting set of
     751    variables, and let `\boldsymbol{1}` be a new variable which commutes with
     752    each `Y_{i,k}`.  (Here, `I` represents the index set of a Cartan datum.)  One
     753    may endow the structure of a crystal on the set `\widehat{\mathcal{M}}` of
     754    monomials of the form
     755
     756    .. MATH::
     757
     758        M = \prod_{(i,k) \in I\times \ZZ_{\ge0}} Y_{i,k}^{y_i(k)}\boldsymbol{1}.
     759
     760    Elements of `\widehat{\mathcal{M}}` are called  *modified Nakajima monomials*.
     761    We will omit the `\boldsymbol{1}` from the end of a monomial if there exists
     762    at least one `y_i(k) \neq 0`.  The crystal structure on this set is defined by
     763
     764    .. MATH::
     765
     766        \begin{aligned}
     767        \mathrm{wt}(M) &= \sum_{i\in I} \Bigl( \sum_{k\ge 0} y_i(k) \Bigr) \Lambda_i, \\
     768        \varphi_i(M) &= \max\Bigl\{ \sum_{0\le j \le k} y_i(j) : k\ge 0 \Bigr\}, \\
     769        \varepsilon_i(M) &= \varphi_i(M) - \langle h_i, \mathrm{wt}(M) \rangle, \\
     770        k_f = k_f(M) &= \min\Bigl\{ k\ge 0 : \varphi_i(M) = \sum_{0\le j\le k} y_i(j) \Bigr\}, \\
     771        k_e = k_e(M) &= \max\Bigl\{ k\ge 0 : \varphi_i(M) = \sum_{0\le j\le k} y_i(j) \Bigr\},
     772        \end{aligned}
     773
     774    where `\{h_i : i \in I\}` and `\{\Lambda_i : i \in I \}` are the simple
     775    coroots and fundamental weights, respectively.  With a chosen set of integers
     776    `C = (c_{ij})_{i\neq j}` such that `c_{ij}+c{ji} =1`, one defines
     777
     778    .. MATH::
     779
     780        A_{i,k} = Y_{i,k} Y_{i,k+1} \prod_{j\neq i} Y_{j,k+c_{ji}}^{a_{ji}},
     781
     782    where `(a_{ij})` is a Cartan matrix.  Then
     783
     784    .. MATH::
     785
     786        \begin{aligned}
     787        e_iM &= \begin{cases} 0 & \text{if } \varepsilon_i(M) = 0, \\
     788        A_{i,k_e}M & \text{if } \varepsilon_i(M) > 0, \end{cases} \\
     789        f_iM &= A_{i,k_f}^{-1} M.
     790        \end{aligned}
     791
     792    It is shown in [KKS07]_ that the connected component of
     793    `\widehat{\mathcal{M}}` containing the element `\boldsymbol{1}`, which we
     794    denote by `\mathcal{M}(\infty)`, is crystal isomorphic to the crystal
     795    `B(\infty)`.
     796
     797    INPUT:
     798
     799    - ``cartan_type`` -- A Cartan type
     800
     801    - ``use_Y`` -- Choice of monomials in terms of `A` or `Y`
     802
     803    EXAMPLES::
     804
     805        sage: B = InfinityCrystalOfTableaux("C3")
     806        sage: S = B.subcrystal(max_depth=4)
     807        sage: G = B.digraph(subset=S) # long time
     808        sage: M = InfinityCrystalOfNakajimaMonomials("C3") # long time
     809        sage: T = M.subcrystal(max_depth=4) # long time
     810        sage: H = M.digraph(subset=T) # long time
     811        sage: G.is_isomorphic(H,edge_labels=True) # long time
     812        True
     813
     814        sage: M = InfinityCrystalOfNakajimaMonomials(['A',2,1])
     815        sage: T = M.subcrystal(max_depth=3)
     816        sage: H = M.digraph(subset=T) # long time
     817        sage: Y = CrystalOfGeneralizedYoungWalls(2) # long time
     818        sage: YS = Y.subcrystal(max_depth=3) # long time
     819        sage: YG = Y.digraph(subset=YS) # long time
     820        sage: YG.is_isomorphic(H,edge_labels=True) # long time
     821        True
     822
     823        sage: M = InfinityCrystalOfNakajimaMonomials("D4")
     824        sage: B = InfinityCrystalOfTableaux("D4")
     825        sage: MS = M.subcrystal(max_depth=3)
     826        sage: BS = B.subcrystal(max_depth=3)
     827        sage: MG = M.digraph(subset=MS) # long time
     828        sage: BG = B.digraph(subset=BS) # long time
     829        sage: BG.is_isomorphic(MG,edge_labels=True) # long time
     830        True
     831    """
     832
     833    @staticmethod
     834    def __classcall_private__(cls, ct, category=None, use_Y=True):
     835        r"""
     836        Normalize input to ensure a unique representation.
     837
     838        INPUT:
     839
     840        - ``ct`` -- Cartan type
     841
     842        EXAMPLES::
     843
     844            sage: M = InfinityCrystalOfNakajimaMonomials("E8")
     845            sage: M1 = InfinityCrystalOfNakajimaMonomials(['E',8])
     846            sage: M2 = InfinityCrystalOfNakajimaMonomials(CartanType(['E',8]))
     847            sage: M is M1 is M2
     848            True
     849        """
     850        if isinstance(use_Y, bool):
     851            if use_Y:
     852                elt_class = NakajimaYMonomial
     853            else:
     854                elt_class = NakajimaAMonomial
     855        else:
     856            elt_class = use_Y
     857        cartan_type = CartanType(ct)
     858        return super(InfinityCrystalOfNakajimaMonomials,cls).__classcall__(cls,cartan_type,category,elt_class)
     859
     860    def __init__(self, ct, category, elt_class):
     861        r"""
     862        EXAMPLES::
     863
     864            sage: Minf = InfinityCrystalOfNakajimaMonomials(['A',3])
     865            sage: TestSuite(Minf).run() # long time
     866        """
     867        self._cartan_type = ct
     868
     869        self.Element = elt_class
     870        if category is None:
     871            category = (HighestWeightCrystals(), InfiniteEnumeratedSets())
     872        Parent.__init__(self, category=category)
     873        self.module_generators = (self.element_class(self,{}),)
     874
     875    def _element_constructor_(self,dict):
     876        r"""
     877        Construct an element of ``self`` from ``dict``.
     878
     879        INPUT:
     880
     881        - ``dict`` -- a dictionary whose key is a pair and whose value is an integer
     882
     883        EXAMPLES::
     884
     885            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,1])
     886            sage: m = M({(1,0):-1,(1,1):-1,(2,0):1})
     887            sage: m
     888            Y(1,0)^-1 Y(1,1)^-1 Y(2,0)
     889        """
     890        return self.element_class(self,dict)
     891
     892    def _repr_(self):
     893        r"""
     894        EXAMPLES::
     895
     896            sage: M = InfinityCrystalOfNakajimaMonomials(['D',4,1])
     897            sage: m = M({(1,0):-1,(1,1):-1,(2,0):1})
     898            sage: m
     899            Y(1,0)^-1 Y(1,1)^-1 Y(2,0)
     900        """
     901        return "Infinity Crystal of modified Nakajima monomials of type %s" % self._cartan_type
     902
     903    def cardinality(self):
     904        r"""
     905        Return the cardinality of ``self``, which is always `\infty`.
     906
     907        EXAMPLES::
     908
     909            sage: M = InfinityCrystalOfNakajimaMonomials(['A',5,2])
     910            sage: M.cardinality()
     911            +Infinity
     912        """
     913        return Infinity
     914
     915class CrystalOfNakajimaMonomialsElement(NakajimaYMonomial):
     916    r"""
     917    Element class for :class:`CrystalOfNakajimaMonomials`.
     918
     919    The `f_i` operators need to be modified from the version in
     920    :class:`NakajimaYMonomial` in order to create irreducible highest weight
     921    realizations.  This modified `f_i` is defined as
     922
     923    .. MATH::
     924
     925        f_iM = \begin{cases} 0 & \text{if } \varphi_i(M) = 0, \\
     926        A_{i,k_f}^{-1}M & \text{if } \varphi_i(M) > 0. \end{cases}
     927
     928    EXAMPLES:
     929    """
     930
     931    def f(self,i):
     932        r"""
     933        Return the action of `f_i` on ``self``.
     934
     935        INPUT:
     936
     937        - ``i`` -- an element of the index set
     938
     939        EXAMPLES::
     940
     941            sage: La = RootSystem(['A',5,2]).weight_lattice().fundamental_weights()
     942            sage: M = CrystalOfNakajimaMonomials(['A',5,2],3*La[0])
     943            sage: m = M.module_generators[0]
     944            sage: [m.f(i) for i in M.index_set()]
     945            [Y(0,0)^2 Y(0,1)^-1 Y(2,0) , None, None, None]
     946        """
     947        if self.phi(i) == 0:
     948            return None
     949        else:
     950            return super(CrystalOfNakajimaMonomialsElement, self).f(i)
     951
     952class CrystalOfNakajimaMonomials(InfinityCrystalOfNakajimaMonomials):
     953    r"""
     954    Let `\widetilde{\mathcal{M}}` be `\widehat{\mathcal{M}}` as a set, and with
     955    crystal structure defined as on `\widehat{\mathcal{M}}` with the exception
     956    that
     957
     958    .. MATH::
     959
     960        f_iM = \begin{cases} 0 & \text{if } \varphi_i(M) = 0, \\
     961        A_{i,k_f}^{-1}M & \text{if } \varphi_i(M) > 0. \end{cases}
     962
     963    Then Kashiwara [Kash03]_ showed that the connected component in
     964    `\widetilde{\mathcal{M}}` containing a monomial `M` such that `e_iM = 0`, for
     965    all `i \in I`, is crystal isomorphic to the irreducible highest weight
     966    crystal `B(\mathrm{wt}(M))`.
     967
     968    EXAMPLES::
     969
     970        sage: La = RootSystem("A2").weight_lattice().fundamental_weights()
     971        sage: M = CrystalOfNakajimaMonomials("A2",La[1]+La[2])
     972        sage: B = CrystalOfTableaux("A2",shape=[2,1])
     973        sage: GM = M.digraph()
     974        sage: GB = B.digraph()
     975        sage: GM.is_isomorphic(GB,edge_labels=True)
     976        True
     977
     978        sage: La = RootSystem("G2").weight_lattice().fundamental_weights()
     979        sage: M = CrystalOfNakajimaMonomials("G2",La[1]+La[2])
     980        sage: B = CrystalOfTableaux("G2",shape=[2,1])
     981        sage: GM = M.digraph()
     982        sage: GB = B.digraph()
     983        sage: GM.is_isomorphic(GB,edge_labels=True)
     984        True
     985
     986        sage: La = RootSystem("B2").weight_lattice().fundamental_weights()
     987        sage: M = CrystalOfNakajimaMonomials(['B',2],La[1]+La[2])
     988        sage: B = CrystalOfTableaux("B2",shape=[3/2,1/2])
     989        sage: GM = M.digraph()
     990        sage: GB = B.digraph()
     991        sage: GM.is_isomorphic(GB,edge_labels=True)
     992        True
     993
     994        sage: La = RootSystem(['A',3,1]).weight_lattice().fundamental_weights()
     995        sage: M = CrystalOfNakajimaMonomials(['A',3,1],La[0]+La[2])
     996        sage: B = HighestWeightCrystalOfGYW(3,La[0]+La[2])
     997        sage: SM = M.subcrystal(max_depth=4)
     998        sage: SB = B.subcrystal(max_depth=4)
     999        sage: GM = M.digraph(subset=SM) # long time
     1000        sage: GB = B.digraph(subset=SB) # long time
     1001        sage: GM.is_isomorphic(GB,edge_labels=True) # long time
     1002        True
     1003
     1004        sage: La = RootSystem(['A',5,2]).weight_lattice().fundamental_weights()
     1005        sage: LA = RootSystem(['A',5,2]).weight_space().fundamental_weights()
     1006        sage: M = CrystalOfNakajimaMonomials(['A',5,2],3*La[0])
     1007        sage: B = CrystalOfLSPaths(3*LA[0])
     1008        sage: SM = M.subcrystal(max_depth=4)
     1009        sage: SB = B.subcrystal(max_depth=4)
     1010        sage: GM = M.digraph(subset=SM)
     1011        sage: GB = B.digraph(subset=SB)
     1012        sage: GM.is_isomorphic(GB,edge_labels=True)
     1013        True
     1014    """
     1015
     1016    @staticmethod
     1017    def __classcall_private__(cls, cartan_type, La):
     1018        r"""
     1019        Normalize input to ensure a unique representation.
     1020
     1021        INPUT:
     1022
     1023        - ``ct`` -- Cartan type
     1024
     1025        - ``La`` -- an element of ``weight_lattice``
     1026
     1027        EXAMPLES::
     1028
     1029            sage: La = RootSystem(['E',8,1]).weight_lattice().fundamental_weights()
     1030            sage: M = CrystalOfNakajimaMonomials(['E',8,1],La[0]+La[8])
     1031            sage: M1 = CrystalOfNakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8])
     1032            sage: M2 = CrystalOfNakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8])
     1033            sage: M is M1 is M2
     1034            True
     1035        """
     1036        cartan_type = CartanType(cartan_type)
     1037        La = RootSystem(cartan_type).weight_lattice()(La)
     1038        return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
     1039
     1040    def __init__(self, ct, La):
     1041        r"""
     1042        EXAMPLES::
     1043
     1044            sage: La = RootSystem(['A',2]).weight_lattice().fundamental_weights()
     1045            sage: M = CrystalOfNakajimaMonomials(['A',2],La[1]+La[2])
     1046            sage: TestSuite(M).run()
     1047        """
     1048        InfinityCrystalOfNakajimaMonomials.__init__( self, ct,
     1049                (RegularCrystals(), HighestWeightCrystals()), CrystalOfNakajimaMonomialsElement )
     1050        self._cartan_type = ct
     1051        self.hw = La
     1052        gen = {}
     1053        for j in range(len(La.support())):
     1054            gen[(La.support()[j],0)] = La.coefficients()[j]
     1055        self.module_generators = (self.element_class(self,gen),)
     1056
     1057    def _repr_(self):
     1058        r"""
     1059        Return a string representation of ``self``.
     1060
     1061        EXAMPLES::
     1062
     1063            sage: La = RootSystem(['C',3,1]).weight_lattice().fundamental_weights()
     1064            sage: M = CrystalOfNakajimaMonomials(['C',3,1],La[0]+5*La[3])
     1065            sage: M
     1066            Highest weight crystal of modified Nakajima monomials of Cartan type ['C', 3, 1] and highest weight Lambda[0] + 5*Lambda[3].
     1067        """
     1068        return "Highest weight crystal of modified Nakajima monomials of Cartan type {1!s} and highest weight {0!s}.".format(self.hw, self._cartan_type)
     1069
     1070    def cardinality(self):
     1071        r"""
     1072        Return the cardinality of ``self``.
     1073
     1074        EXAMPLES::
     1075
     1076            sage: La = RootSystem(['A',2]).weight_lattice().fundamental_weights()
     1077            sage: M = CrystalOfNakajimaMonomials(['A',2],La[1])
     1078            sage: M.cardinality()
     1079            3
     1080
     1081            sage: La = RootSystem(['D',4,2]).weight_lattice().fundamental_weights()
     1082            sage: M = CrystalOfNakajimaMonomials(['D',4,2],La[1])
     1083            sage: M.cardinality()
     1084            +Infinity
     1085        """
     1086        if self.cartan_type().is_affine():
     1087            return Infinity
     1088        else:
     1089            return len(list(self.subcrystal(generators=[self.module_generators[0]])))
     1090 No newline at end of file