Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/crystals/tensor_product.py
8817 views
1
"""
2
Tensor Products of Crystals
3
4
Main entry points:
5
6
- :class:`TensorProductOfCrystals`
7
- :class:`CrystalOfTableaux`
8
9
AUTHORS:
10
11
- Anne Schilling, Nicolas Thiery (2007): Initial version
12
- Ben Salisbury, Travis Scrimshaw (2013): Refactored tensor products to handle
13
non-regular crystals and created new subclass to take advantage of
14
the regularity
15
"""
16
#*****************************************************************************
17
# Copyright (C) 2007 Anne Schilling <anne at math.ucdavis.edu>
18
# Nicolas Thiery <nthiery at users.sf.net>
19
#
20
# Distributed under the terms of the GNU General Public License (GPL)
21
#
22
# This code is distributed in the hope that it will be useful,
23
# but WITHOUT ANY WARRANTY; without even the implied warranty of
24
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25
# General Public License for more details.
26
#
27
# The full text of the GPL is available at:
28
#
29
# http://www.gnu.org/licenses/
30
#****************************************************************************
31
32
import operator
33
from sage.misc.latex import latex
34
from sage.misc.cachefunc import cached_method, cached_in_parent_method
35
from sage.structure.parent import Parent
36
from sage.structure.element import Element, parent
37
from sage.structure.global_options import GlobalOptions
38
from sage.categories.category import Category
39
from sage.categories.classical_crystals import ClassicalCrystals
40
from sage.categories.regular_crystals import RegularCrystals
41
from sage.combinat.root_system.cartan_type import CartanType
42
from sage.combinat.cartesian_product import CartesianProduct
43
from sage.combinat.combinat import CombinatorialObject
44
from sage.combinat.partition import Partition
45
from sage.combinat.tableau import Tableau
46
from letters import CrystalOfLetters
47
from spins import CrystalOfSpins, CrystalOfSpinsMinus, CrystalOfSpinsPlus
48
from sage.misc.flatten import flatten
49
from sage.rings.integer import Integer
50
51
##############################################################################
52
# Until trunc gets implemented in sage.function.other
53
54
from sage.functions.other import floor, ceil
55
def trunc(i):
56
"""
57
Truncates to the integer closer to zero
58
59
EXAMPLES::
60
61
sage: from sage.combinat.crystals.tensor_product import trunc
62
sage: trunc(-3/2), trunc(-1), trunc(-1/2), trunc(0), trunc(1/2), trunc(1), trunc(3/2)
63
(-1, -1, 0, 0, 0, 1, 1)
64
sage: isinstance(trunc(3/2), Integer)
65
True
66
"""
67
if i>= 0:
68
return floor(i)
69
else:
70
return ceil(i)
71
72
##############################################################################
73
# Support classes
74
##############################################################################
75
76
from sage.structure.unique_representation import UniqueRepresentation
77
78
class TestParent(UniqueRepresentation, Parent):
79
def _repr_(self):
80
return "A parent for tests"
81
82
class ImmutableListWithParent(CombinatorialObject, Element):
83
r"""
84
A class for lists having a parent
85
86
Specification: any subclass C should implement __init__ which
87
accepts the following form C(parent, list = list)
88
89
EXAMPLES: We create an immutable list whose parent is the class
90
list::
91
92
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
93
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
94
sage: l._list
95
[1, 2, 3]
96
sage: l.parent()
97
A parent for tests
98
sage: l.sibling([2,1]) == ImmutableListWithParent(TestParent(), [2,1])
99
True
100
sage: l.reversed()
101
[3, 2, 1]
102
sage: l.set_index(1,4)
103
[1, 4, 3]
104
"""
105
106
def __init__(self, parent, list):
107
"""
108
EXAMPLES::
109
110
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
111
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
112
sage: l.parent()
113
A parent for tests
114
sage: parent(l)
115
A parent for tests
116
sage: TestSuite(l).run(skip = "_test_category")
117
"""
118
Element.__init__(self, parent)
119
CombinatorialObject.__init__(self, list)
120
121
def _repr_(self):
122
"""
123
EXAMPLES::
124
125
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
126
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
127
sage: l._repr_()
128
'[1, 2, 3]'
129
"""
130
return "%s"%self._list
131
132
def __eq__(self, other):
133
"""
134
EXAMPLES::
135
136
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
137
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
138
sage: m = ImmutableListWithParent(ZZ, [1,2,3])
139
sage: n = ImmutableListWithParent(ZZ, [2,3,4])
140
sage: l == l
141
True
142
sage: l == m
143
False
144
sage: m == n
145
False
146
"""
147
return self.__class__ is other.__class__ and \
148
self.parent() == other.parent() and \
149
self._list == other._list
150
151
def __ne__(self, other):
152
return not self.__eq__(other)
153
154
# Should go in Element? Sets.ElementMethods?
155
# How to define them conditionally, only of __lt__ is defined?
156
def __le__(self, other):
157
if self == other:
158
return True
159
else:
160
return self.__le__(other)
161
162
def __gt__(self, other):
163
if parent(self) is not parent(other):
164
return NotImplemented
165
return other.__lt__(self)
166
167
def __ge__(self, other):
168
if self == other:
169
return True
170
else:
171
return self.__le__(other)
172
173
def sibling(self, l):
174
"""
175
Returns an ImmutableListWithParent object whose list is l and whose
176
parent is the same as self's parent.
177
178
Note that the implementation of this function makes an assumption
179
about the constructor for subclasses.
180
181
EXAMPLES::
182
183
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
184
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
185
sage: m = l.sibling([2,3,4]); m
186
[2, 3, 4]
187
sage: m.parent()
188
A parent for tests
189
"""
190
return self.__class__(self.parent(), list=l)
191
192
def reversed(self):
193
"""
194
Returns the sibling of self which is obtained by reversing the
195
elements of self.
196
197
EXAMPLES::
198
199
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
200
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
201
sage: l.reversed()
202
[3, 2, 1]
203
"""
204
return self.sibling([ i for i in reversed(self._list)])
205
206
def set_index(self, k, value):
207
"""
208
Returns the sibling of self obtained by setting the
209
`k^{th}` entry of self to value.
210
211
EXAMPLES::
212
213
sage: from sage.combinat.crystals.tensor_product import ImmutableListWithParent, TestParent
214
sage: l = ImmutableListWithParent(TestParent(), [1,2,3])
215
sage: l.set_index(0,2)
216
[2, 2, 3]
217
sage: l.set_index(1,4)
218
[1, 4, 3]
219
sage: _.parent()
220
A parent for tests
221
"""
222
l = [i for i in self._list]
223
l[k] = value
224
return self.sibling(l)
225
226
class CrystalOfWords(UniqueRepresentation, Parent):
227
"""
228
Auxiliary class to provide a call method to create tensor product elements.
229
This class is shared with several tensor product classes and is also used in CrystalOfTableaux to allow
230
tableaux of different tensor product structures in column-reading (and hence different shapes)
231
to be considered elements in the same crystal.
232
"""
233
def _element_constructor_(self, *crystalElements):
234
"""
235
EXAMPLES::
236
237
sage: C = CrystalOfLetters(['A',2])
238
sage: T = TensorProductOfCrystals(C,C)
239
sage: T(1,1)
240
[1, 1]
241
sage: _.parent()
242
Full tensor product of the crystals [The crystal of letters for type ['A', 2], The crystal of letters for type ['A', 2]]
243
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)]])
244
sage: T(C(2), C(1), C(1))
245
[2, 1, 1]
246
"""
247
return self.element_class(self, list(crystalElements))
248
249
def one_dimensional_configuration_sum(self, q = None, group_components = True):
250
r"""
251
Computes the one-dimensional configuration sum.
252
253
INPUT:
254
255
- ``q`` -- (default: ``None``) a variable or ``None``; if ``None``,
256
a variable `q` is set in the code
257
- ``group_components`` -- (default: ``True``) boolean; if ``True``,
258
then the terms are grouped by classical component
259
260
The one-dimensional configuration sum is the sum of the weights of all elements in the crystal
261
weighted by the energy function.
262
263
EXAMPLES::
264
265
sage: K = KirillovReshetikhinCrystal(['A',2,1],1,1)
266
sage: T = TensorProductOfCrystals(K,K)
267
sage: T.one_dimensional_configuration_sum()
268
B[-2*Lambda[1] + 2*Lambda[2]] + (q+1)*B[-Lambda[1]] + (q+1)*B[Lambda[1] - Lambda[2]]
269
+ B[2*Lambda[1]] + B[-2*Lambda[2]] + (q+1)*B[Lambda[2]]
270
sage: R.<t> = ZZ[]
271
sage: T.one_dimensional_configuration_sum(t, False)
272
B[-2*Lambda[1] + 2*Lambda[2]] + (t+1)*B[-Lambda[1]] + (t+1)*B[Lambda[1] - Lambda[2]]
273
+ B[2*Lambda[1]] + B[-2*Lambda[2]] + (t+1)*B[Lambda[2]]
274
275
sage: R = RootSystem(['A',2,1])
276
sage: La = R.weight_space().basis()
277
sage: LS = CrystalOfProjectedLevelZeroLSPaths(2*La[1])
278
sage: LS.one_dimensional_configuration_sum() == T.one_dimensional_configuration_sum()
279
True
280
281
TESTS::
282
283
sage: K1 = KirillovReshetikhinCrystal(['A',2,1],1,1)
284
sage: K2 = KirillovReshetikhinCrystal(['A',2,1],2,1)
285
sage: T = TensorProductOfCrystals(K1,K2)
286
sage: T.one_dimensional_configuration_sum() == T.one_dimensional_configuration_sum(group_components=False)
287
True
288
"""
289
if q is None:
290
from sage.rings.all import QQ
291
q = QQ['q'].gens()[0]
292
P0 = self.weight_lattice_realization().classical()
293
B = P0.algebra(q.parent())
294
if group_components:
295
G = self.digraph(index_set = self.cartan_type().classical().index_set())
296
C = G.connected_components()
297
return sum(q**(c[0].energy_function())*B.sum(B(P0(b.weight())) for b in c) for c in C)
298
return B.sum(q**(b.energy_function())*B(P0(b.weight())) for b in self)
299
300
TensorProductOfCrystalsOptions=GlobalOptions(name='tensor_product_of_crystals',
301
doc=r"""
302
Sets the global options for tensor products of crystals. The default is to
303
use the anti-Kashiwara convention.
304
305
There are two conventions for how `e_i` and `f_i` act on tensor products,
306
and the difference between the two is the order of the tensor factors
307
are reversed. This affects both the input and output. See the example
308
below.
309
""",
310
end_doc=r"""
311
312
.. NOTE::
313
314
Changing the ``convention`` also changes how the input is handled.
315
316
.. WARNING::
317
318
Internally, the crystals are always stored using the anti-Kashiwara
319
convention.
320
321
If no parameters are set, then the function returns a copy of the
322
options dictionary.
323
324
EXAMPLES::
325
326
sage: C = CrystalOfLetters(['A',2])
327
sage: T = TensorProductOfCrystals(C,C)
328
sage: elt = T(C(1), C(2)); elt
329
[1, 2]
330
sage: TensorProductOfCrystals.global_options['convention'] = "Kashiwara"
331
sage: elt
332
[2, 1]
333
sage: T(C(1), C(2)) == elt
334
False
335
sage: T(C(2), C(1)) == elt
336
True
337
sage: TensorProductOfCrystals.global_options.reset()
338
""",
339
convention=dict(default="antiKashiwara",
340
description='Sets the convention used for displaying/inputting tensor product of crystals',
341
values=dict(antiKashiwara='use the anti-Kashiwara convention',
342
Kashiwara='use the Kashiwara convention'),
343
alias=dict(anti="antiKashiwara", opposite="antiKashiwara"),
344
case_sensitive=False)
345
)
346
347
class TensorProductOfCrystals(CrystalOfWords):
348
r"""
349
Tensor product of crystals.
350
351
Given two crystals `B` and `B'` of the same Cartan type,
352
one can form the tensor product `B \otimes B^{\prime}`. As a set
353
`B \otimes B^{\prime}` is the Cartesian product
354
`B \times B^{\prime}`. The crystal operators `f_i` and
355
`e_i` act on `b \otimes b^{\prime} \in B \otimes B^{\prime}` as
356
follows:
357
358
.. MATH::
359
360
f_i(b \otimes b^{\prime}) = \begin{cases}
361
f_i(b) \otimes b^{\prime} & \text{if } \varepsilon_i(b) \geq
362
\varphi_i(b^{\prime}) \\
363
b \otimes f_i(b^{\prime}) & \text{otherwise}
364
\end{cases}
365
366
and
367
368
.. MATH::
369
370
e_i(b \otimes b^{\prime}) = \begin{cases}
371
e_i(b) \otimes b^{\prime} & \text{if } \varepsilon_i(b) >
372
\varphi_i(b^{\prime}) \\
373
b \otimes e_i(b^{\prime}) & \text{otherwise.}
374
\end{cases}
375
376
We also define:
377
378
.. MATH::
379
380
\begin{aligned}
381
\varphi_i(b \otimes b^{\prime}) & = \max\left( \varphi_i(b),
382
\varphi_i(b) + \varphi_i(b^{\prime}) - \varepsilon_i(b) \right)
383
\\ \varepsilon_i(b \otimes b^{\prime}) & = \max\left(
384
\varepsilon_i(b^{\prime}), \varepsilon_i(b^{\prime}) +
385
\varepsilon_i(b) - \varphi_i(b^{\prime}) \right).
386
\end{aligned}
387
388
.. NOTE::
389
390
This is the opposite of Kashiwara's convention for tensor
391
products of crystals.
392
393
Since tensor products are associative `(\mathcal{B} \otimes \mathcal{C})
394
\otimes \mathcal{D} \cong \mathcal{B} \otimes (\mathcal{C} \otimes
395
\mathcal{D})` via the natural isomorphism `(b \otimes c) \otimes d \mapsto
396
b \otimes (c \otimes d)`, we can generalizing this to arbitrary tensor
397
products. Thus consider `B_N \otimes \cdots \otimes B_1`, where each
398
`B_k` is an abstract crystal. The underlying set of the tensor product is
399
`B_N \times \cdots \times B_1`, while the crystal structure is given
400
as follows. Let `I` be the index set, and fix some `i \in I` and `b_N
401
\otimes \cdots \otimes b_1 \in B_N \otimes \cdots \otimes B_1`. Define
402
403
.. MATH::
404
405
a_i(k) := \varepsilon_i(b_k) - \sum_{j=1}^{k-1} \langle
406
\alpha_i^{\vee}, \mathrm{wt}(b_j) \rangle.
407
408
Then
409
410
.. MATH::
411
412
\begin{aligned}
413
\mathrm{wt}(b_N \otimes \cdots \otimes b_1) &=
414
\mathrm{wt}(b_N) + \cdots + \mathrm{wt}(b_1),
415
\\ \varepsilon_i(b_N \otimes \cdots \otimes b_1) &= \max_{1 \leq k
416
\leq n}\left( \sum_{j=1}^k \varepsilon_i(b_j) - \sum_{j=1}^{k-1}
417
\varphi_i(b_j) \right)
418
\\ & = \max_{1 \leq k \leq N}\bigl( a_i(k) \bigr),
419
\\ \varphi_i(b_N \otimes \cdots \otimes b_1) &= \max_{1 \leq k \leq N}
420
\left( \varphi_i(b_N) + \sum_{j=k}^{N-1} \big( \varphi_i(b_j) -
421
\varepsilon_i(b_{j+1}) \big) \right)
422
\\ & = \max_{1 \leq k \leq N}\bigl( \lambda_i + a_i(k) \bigr)
423
\end{aligned}
424
425
where `\lambda_i = \langle \alpha_i^{\vee}, \mathrm{wt}(b_N \otimes \cdots
426
\otimes b_1) \rangle`. Then for `k = 1, \ldots, N` the action of the
427
Kashiwara operators is determined as follows.
428
429
- If `a_i(k) > a_i(j)` for `1 \leq j < k` and `a_i(k) \geq a_i(j)`
430
for `k < j \leq N`:
431
432
.. MATH::
433
434
e_i(b_N \otimes \cdots \otimes b_1) = b_N \otimes \cdots \otimes
435
e_i b_k \otimes \cdots \otimes b_1.
436
437
- If `a_i(k) \geq a_i(j)` for `1 \leq j < k` and `a_i(k) > a_i(j)`
438
for `k < j \leq N`:
439
440
.. MATH::
441
442
f_i(b_N \otimes \cdots \otimes b_1) = b_N \otimes \cdots \otimes
443
f_i b_k \otimes \cdots \otimes b_1.
444
445
Note that this is just recursively applying the definition of the tensor
446
product on two crystals. Recall that `\langle \alpha_i^{\vee},
447
\mathrm{wt}(b_j) \rangle = \varphi_i(b_j) - \varepsilon_i(b_j)` by the
448
definition of a crystal.
449
450
.. RUBRIC:: Regular crystals
451
452
Now if all crystals `B_k` are regular crystals, all `\varepsilon_i` and
453
`\varphi_i` are non-negative and we can
454
define tensor product by the *signature rule*. We start by writing a word
455
in `+` and `-` as follows:
456
457
.. MATH::
458
459
\underbrace{- \cdots -}_{\varphi_i(b_N) \text{ times}} \quad
460
\underbrace{+ \cdots +}_{\varepsilon_i(b_N) \text{ times}}
461
\quad \cdots \quad
462
\underbrace{- \cdots -}_{\varphi_i(b_1) \text{ times}} \quad
463
\underbrace{+ \cdots +}_{\varepsilon_i(b_1) \text{ times}},
464
465
and then canceling ordered pairs of `+-` until the word is in the reduced
466
form:
467
468
.. MATH::
469
470
\underbrace{- \cdots -}_{\varphi_i \text{ times}} \quad
471
\underbrace{+ \cdots +}_{\varepsilon_i \text{ times}}.
472
473
Here `e_i` acts on the factor corresponding to the leftmost `+` and `f_i`
474
on the factor corresponding to the rightmost `-`. If there is no `+` or
475
`-` respectively, then the result is `0` (``None``).
476
477
EXAMPLES:
478
479
We construct the type `A_2`-crystal generated by `2 \otimes 1 \otimes 1`::
480
481
sage: C = CrystalOfLetters(['A',2])
482
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)]])
483
484
It has `8` elements::
485
486
sage: T.list()
487
[[2, 1, 1], [2, 1, 2], [2, 1, 3], [3, 1, 3], [3, 2, 3], [3, 1, 1], [3, 1, 2], [3, 2, 2]]
488
489
One can also check the Cartan type of the crystal::
490
491
sage: T.cartan_type()
492
['A', 2]
493
494
Other examples include crystals of tableaux (which internally are
495
represented as tensor products obtained by reading the tableaux
496
columnwise)::
497
498
sage: C = CrystalOfTableaux(['A',3], shape=[1,1,0])
499
sage: D = CrystalOfTableaux(['A',3], shape=[1,0,0])
500
sage: T = TensorProductOfCrystals(C,D, generators=[[C(rows=[[1], [2]]), D(rows=[[1]])], [C(rows=[[2], [3]]), D(rows=[[1]])]])
501
sage: T.cardinality()
502
24
503
sage: TestSuite(T).run()
504
sage: T.module_generators
505
[[[[1], [2]], [[1]]], [[[2], [3]], [[1]]]]
506
sage: [x.weight() for x in T.module_generators]
507
[(2, 1, 0, 0), (1, 1, 1, 0)]
508
509
If no module generators are specified, we obtain the full tensor
510
product::
511
512
sage: C = CrystalOfLetters(['A',2])
513
sage: T = TensorProductOfCrystals(C,C)
514
sage: T.list()
515
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
516
sage: T.cardinality()
517
9
518
519
For a tensor product of crystals without module generators, the
520
default implementation of ``module_generators`` contains all elements
521
in the tensor product of the crystals. If there is a subset of
522
elements in the tensor product that still generates the crystal,
523
this needs to be implemented for the specific crystal separately::
524
525
sage: T.module_generators.list()
526
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
527
528
For classical highest weight crystals, it is also possible to list
529
all highest weight elements::
530
531
sage: C = CrystalOfLetters(['A',2])
532
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)],[C(1),C(2),C(1)]])
533
sage: T.highest_weight_vectors()
534
[[2, 1, 1], [1, 2, 1]]
535
536
Examples with non-regular and infinite crystals (these did not work
537
before :trac:`14402`)::
538
539
sage: B = InfinityCrystalOfTableaux(['D',10])
540
sage: T = TensorProductOfCrystals(B,B)
541
sage: T
542
Full tensor product of the crystals
543
[The infinity crystal of tableaux of type ['D', 10],
544
The infinity crystal of tableaux of type ['D', 10]]
545
546
sage: B = InfinityCrystalOfGeneralizedYoungWalls(15)
547
sage: T = TensorProductOfCrystals(B,B,B)
548
sage: T
549
Full tensor product of the crystals
550
[Crystal of generalized Young walls of type ['A', 15, 1],
551
Crystal of generalized Young walls of type ['A', 15, 1],
552
Crystal of generalized Young walls of type ['A', 15, 1]]
553
554
sage: La = RootSystem(['A',2,1]).weight_lattice().fundamental_weights()
555
sage: B = CrystalOfGeneralizedYoungWalls(2,La[0]+La[1])
556
sage: C = CrystalOfGeneralizedYoungWalls(2,2*La[2])
557
sage: D = CrystalOfGeneralizedYoungWalls(2,3*La[0]+La[2])
558
sage: T = TensorProductOfCrystals(B,C,D)
559
sage: T
560
Full tensor product of the crystals
561
[Highest weight crystal of generalized Young walls of Cartan type ['A', 2, 1] and highest weight Lambda[0] + Lambda[1].,
562
Highest weight crystal of generalized Young walls of Cartan type ['A', 2, 1] and highest weight 2*Lambda[2].,
563
Highest weight crystal of generalized Young walls of Cartan type ['A', 2, 1] and highest weight 3*Lambda[0] + Lambda[2].]
564
565
There is also a global option for setting the convention (by default Sage
566
uses anti-Kashiwara)::
567
568
sage: C = CrystalOfLetters(['A',2])
569
sage: T = TensorProductOfCrystals(C,C)
570
sage: elt = T(C(1), C(2)); elt
571
[1, 2]
572
sage: TensorProductOfCrystals.global_options['convention'] = "Kashiwara"
573
sage: elt
574
[2, 1]
575
sage: TensorProductOfCrystals.global_options.reset()
576
"""
577
@staticmethod
578
def __classcall_private__(cls, *crystals, **options):
579
"""
580
Create the correct parent object.
581
582
EXAMPLES::
583
584
sage: C = CrystalOfLetters(['A',2])
585
sage: T = TensorProductOfCrystals(C, C)
586
sage: T2 = TensorProductOfCrystals(C, C)
587
sage: T is T2
588
True
589
sage: B = InfinityCrystalOfTableaux(['A',2])
590
sage: T = TensorProductOfCrystals(B, B)
591
"""
592
crystals = tuple(crystals)
593
if "cartan_type" in options:
594
cartan_type = CartanType(options["cartan_type"])
595
else:
596
if len(crystals) == 0:
597
raise ValueError("you need to specify the Cartan type if the tensor product list is empty")
598
else:
599
cartan_type = crystals[0].cartan_type()
600
601
if "generators" in options:
602
generators = tuple(tuple(x) if isinstance(x, list) else x for x in options["generators"])
603
604
if all(c in RegularCrystals() for c in crystals):
605
return TensorProductOfRegularCrystalsWithGenerators(crystals, generators, cartan_type)
606
return TensorProductOfCrystalsWithGenerators(crystals, generators, cartan_type)
607
608
if all(c in RegularCrystals() for c in crystals):
609
return FullTensorProductOfRegularCrystals(crystals, cartan_type=cartan_type)
610
return FullTensorProductOfCrystals(crystals, cartan_type=cartan_type)
611
612
global_options = TensorProductOfCrystalsOptions
613
614
def _element_constructor_(self, *crystalElements):
615
"""
616
EXAMPLES::
617
618
sage: C = CrystalOfLetters(['A',2])
619
sage: T = TensorProductOfCrystals(C,C)
620
sage: T(1,1)
621
[1, 1]
622
sage: _.parent()
623
Full tensor product of the crystals [The crystal of letters for type ['A', 2], The crystal of letters for type ['A', 2]]
624
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)]])
625
sage: T(C(2), C(1), C(1))
626
[2, 1, 1]
627
"""
628
if self.global_options['convention'] == "Kashiwara":
629
crystalElements = reversed(crystalElements)
630
return self.element_class(self, list(crystalElements))
631
632
class TensorProductOfCrystalsWithGenerators(TensorProductOfCrystals):
633
"""
634
Tensor product of crystals with a generating set.
635
"""
636
def __init__(self, crystals, generators, cartan_type):
637
"""
638
EXAMPLES::
639
640
sage: C = CrystalOfLetters(['A',2])
641
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)]])
642
sage: TestSuite(T).run()
643
"""
644
assert isinstance(crystals, tuple)
645
assert isinstance(generators, tuple)
646
category = Category.meet([crystal.category() for crystal in crystals])
647
Parent.__init__(self, category = category)
648
self.crystals = crystals
649
self._cartan_type = cartan_type
650
self.module_generators = [ self(*x) for x in generators ]
651
652
def _repr_(self):
653
"""
654
Return a string representation of ``self``.
655
656
EXAMPLES::
657
658
sage: C = CrystalOfLetters(['A',2])
659
sage: TensorProductOfCrystals(C,C,generators=[[C(2),C(1)]])
660
The tensor product of the crystals [The crystal of letters for type ['A', 2], The crystal of letters for type ['A', 2]]
661
"""
662
if self.global_options['convention'] == "Kashiwara":
663
st = repr(list(reversed(self.crystals)))
664
else:
665
st = repr(list(self.crystals))
666
return "The tensor product of the crystals %s"%st
667
668
class FullTensorProductOfCrystals(TensorProductOfCrystals):
669
"""
670
Full tensor product of crystals.
671
"""
672
def __init__(self, crystals, **options):
673
"""
674
TESTS::
675
676
sage: from sage.combinat.crystals.tensor_product import FullTensorProductOfCrystals
677
sage: C = CrystalOfLetters(['A',2])
678
sage: T = TensorProductOfCrystals(C,C)
679
sage: isinstance(T, FullTensorProductOfCrystals)
680
True
681
sage: TestSuite(T).run()
682
"""
683
crystals = list(crystals)
684
category = Category.meet([crystal.category() for crystal in crystals])
685
Parent.__init__(self, category = category)
686
self.crystals = crystals
687
if options.has_key('cartan_type'):
688
self._cartan_type = CartanType(options['cartan_type'])
689
else:
690
if len(crystals) == 0:
691
raise ValueError, "you need to specify the Cartan type if the tensor product list is empty"
692
else:
693
self._cartan_type = crystals[0].cartan_type()
694
self.cartesian_product = CartesianProduct(*self.crystals)
695
self.module_generators = self
696
697
def _repr_(self):
698
"""
699
Return a string representation of ``self``.
700
701
EXAMPLES::
702
703
sage: C = CrystalOfLetters(['A',2])
704
sage: TensorProductOfCrystals(C,C)
705
Full tensor product of the crystals [The crystal of letters for type ['A', 2], The crystal of letters for type ['A', 2]]
706
"""
707
if self.global_options['convention'] == "Kashiwara":
708
st = repr(reversed(self.crystals))
709
else:
710
st = repr(self.crystals)
711
return "Full tensor product of the crystals %s"%st
712
713
# TODO: __iter__ and cardinality should be inherited from EnumeratedSets().CartesianProducts()
714
def __iter__(self):
715
"""
716
EXAMPLES::
717
718
sage: C = CrystalOfLetters(['A',2])
719
sage: T = TensorProductOfCrystals(C,C)
720
sage: list(T)
721
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
722
sage: _[0].parent()
723
Full tensor product of the crystals [The crystal of letters for type ['A', 2], The crystal of letters for type ['A', 2]]
724
"""
725
for x in self.cartesian_product:
726
yield self(*x)
727
728
# list = CombinatorialClass._CombinatorialClass__list_from_iterator
729
730
def cardinality(self):
731
"""
732
Return the cardinality of ``self``.
733
734
EXAMPLES::
735
736
sage: C = CrystalOfLetters(['A',2])
737
sage: T = TensorProductOfCrystals(C,C)
738
sage: T.cardinality()
739
9
740
"""
741
return self.cartesian_product.cardinality()
742
743
class TensorProductOfCrystalsElement(ImmutableListWithParent):
744
r"""
745
A class for elements of tensor products of crystals.
746
"""
747
def _repr_(self):
748
"""
749
Return a string representation of ``self``.
750
751
EXAMPLES::
752
753
sage: C = CrystalOfLetters(['A',3])
754
sage: T = TensorProductOfCrystals(C,C)
755
sage: T(C(1),C(2))
756
[1, 2]
757
"""
758
if self.parent().global_options['convention'] == "Kashiwara":
759
return repr(list(reversed(self._list)))
760
return repr(self._list)
761
762
def _latex_(self):
763
r"""
764
Return latex code for ``self``.
765
766
EXAMPLES::
767
768
sage: C = CrystalOfLetters(["A",2])
769
sage: D = CrystalOfTableaux(["A",2], shape=[2])
770
sage: E = TensorProductOfCrystals(C,D)
771
sage: latex(E.module_generators[0])
772
1 \otimes {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
773
\raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
774
\lr{1}&\lr{1}\\\cline{1-2}
775
\end{array}$}
776
}
777
"""
778
return ' \otimes '.join(latex(c) for c in self)
779
780
def _ascii_art_(self):
781
"""
782
Return an ASCII art representation of ``self``.
783
784
EXAMPLES::
785
786
sage: KT = TensorProductOfKirillovReshetikhinTableaux(['D',4,1],[[3,3],[2,1],[1,2]])
787
sage: ascii_art(KT.module_generators[0])
788
1 1 1
789
2 2 2 # 1 # 1 1
790
3 3 3 2
791
-4 -4 -4
792
"""
793
from sage.misc.ascii_art import ascii_art, AsciiArt
794
s = ascii_art(self[0])
795
s._baseline = s._h // 2
796
ret = s
797
for tableau in self[1:]:
798
s = ascii_art(tableau)
799
s._baseline = s._h // 2
800
ret += AsciiArt([" # "]) + s
801
return ret
802
803
def __lt__(self, other):
804
"""
805
Non elements of the crystal are incomparable with elements of the crystal
806
(or should it return NotImplemented?).
807
808
Comparison of two elements of this crystal:
809
810
- different length: incomparable
811
- otherwise lexicographicaly, considering ``self[i]`` and ``other[i]``
812
as incomparable if ``self[i] < other[i]`` returns NotImplemented
813
"""
814
if parent(self) is not parent(other):
815
return False
816
if len(self) != len(other):
817
return False
818
for i in range(len(self)):
819
if (self[i] < other[i]) == True:
820
return True
821
if (other[i] < self[i]) == True:
822
return False
823
return False
824
825
def weight(self):
826
r"""
827
Return the weight of ``self``.
828
829
EXAMPLES::
830
831
sage: B = InfinityCrystalOfTableaux("A3")
832
sage: T = TensorProductOfCrystals(B,B)
833
sage: b1 = B.highest_weight_vector().f_string([2,1,3])
834
sage: b2 = B.highest_weight_vector().f(1)
835
sage: t = T(b2, b1)
836
sage: t
837
[[[1, 1, 1, 2], [2, 2], [3]], [[1, 1, 1, 1, 2], [2, 2, 4], [3]]]
838
sage: t.weight()
839
(-2, 1, 0, 1)
840
"""
841
return sum(self[i].weight() for i in range(len(self)))
842
843
def epsilon(self, i):
844
r"""
845
Return `\varepsilon_i` of ``self``.
846
847
INPUT:
848
849
- ``i`` -- An element of the index set
850
851
EXAMPLES::
852
853
sage: B = InfinityCrystalOfTableaux("G2")
854
sage: T = TensorProductOfCrystals(B,B)
855
sage: b1 = B.highest_weight_vector().f(2)
856
sage: b2 = B.highest_weight_vector().f_string([2,2,1])
857
sage: t = T(b2, b1)
858
sage: [t.epsilon(i) for i in B.index_set()]
859
[0, 3]
860
"""
861
return max(self._sig(i, k) for k in range(1, len(self)+1))
862
863
def phi(self, i):
864
r"""
865
Return `\varphi_i` of ``self``.
866
867
INPUT:
868
869
- ``i`` -- An element of the index set
870
871
EXAMPLES::
872
873
sage: La = RootSystem(['A',2,1]).weight_lattice().fundamental_weights()
874
sage: B = CrystalOfGeneralizedYoungWalls(2,La[0]+La[1])
875
sage: T = TensorProductOfCrystals(B,B)
876
sage: b1 = B.highest_weight_vector().f_string([1,0])
877
sage: b2 = B.highest_weight_vector().f_string([0,1])
878
sage: t = T(b2, b1)
879
sage: [t.phi(i) for i in B.index_set()]
880
[1, 1, 4]
881
882
TESTS:
883
884
Check that :trac:`15462` is fixed::
885
886
sage: B = CrystalOfTableaux(['A',2], shape=[2,1])
887
sage: La = RootSystem(['A',2]).ambient_space().fundamental_weights()
888
sage: T = TensorProductOfCrystals(TCrystal(['A',2], La[1]+La[2]), B)
889
sage: t = T.an_element()
890
sage: t.phi(1)
891
2
892
sage: t.phi(2)
893
2
894
"""
895
P = self[-1].parent().weight_lattice_realization()
896
h = P.simple_coroots()
897
omega = P(self.weight()).scalar(h[i])
898
return max([omega + self._sig(i, k) for k in range(1, len(self)+1)])
899
900
@cached_in_parent_method
901
def _sig(self,i,k):
902
r"""
903
Return `a_i(k)` of ``self``.
904
905
The value `a_i(k)` of a crystal `b = b_N \otimes \cdots \otimes b_1`
906
is defined as:
907
908
.. MATH::
909
910
a_i(k) = \varepsilon_i(b_k) - \sum_{j=1}^{k-1} \langle h_i,
911
\mathrm{wt}(b_j) \rangle
912
913
where `\mathrm{wt}` is the :meth:`weight` of `b_j`.
914
915
INPUT:
916
917
- ``i`` -- An element of the index set
918
919
- ``k`` -- The (1-based) index of the tensor factor of ``self``
920
921
EXAMPLES::
922
923
sage: B = InfinityCrystalOfGeneralizedYoungWalls(3)
924
sage: T = TensorProductOfCrystals(B,B)
925
sage: b1 = B.highest_weight_vector().f_string([0,3,1])
926
sage: b2 = B.highest_weight_vector().f_string([3,2,1,0,2,3])
927
sage: t = T(b1, b2)
928
sage: [[t._sig(i,k) for k in range(1,len(t)+1)] for i in B.index_set()]
929
[[0, -1], [0, 0], [0, 1], [1, 2]]
930
"""
931
if k == 1:
932
return self[-1].epsilon(i)
933
return self._sig(i, k-1) + self[-k].epsilon(i) - self[-k+1].phi(i)
934
935
def e(self,i):
936
r"""
937
Return the action of `e_i` on ``self``.
938
939
INPUT:
940
941
- ``i`` -- An element of the index set
942
943
EXAMPLES::
944
945
sage: B = InfinityCrystalOfTableaux("D4")
946
sage: T = TensorProductOfCrystals(B,B)
947
sage: b1 = B.highest_weight_vector().f_string([1,4,3])
948
sage: b2 = B.highest_weight_vector().f_string([2,2,3,1,4])
949
sage: t = T(b2, b1)
950
sage: t.e(1)
951
[[[1, 1, 1, 1, 1], [2, 2, 3, -3], [3]], [[1, 1, 1, 1, 2], [2, 2, 2], [3, -3]]]
952
sage: t.e(2)
953
sage: t.e(3)
954
[[[1, 1, 1, 1, 1, 2], [2, 2, 3, -4], [3]], [[1, 1, 1, 1, 2], [2, 2, 2], [3, -3]]]
955
sage: t.e(4)
956
[[[1, 1, 1, 1, 1, 2], [2, 2, 3, 4], [3]], [[1, 1, 1, 1, 2], [2, 2, 2], [3, -3]]]
957
"""
958
N = len(self) + 1
959
for k in range(1, N):
960
if all(self._sig(i,k) > self._sig(i,j) for j in range(1, k)) and \
961
all(self._sig(i,k) >= self._sig(i,j) for j in range(k+1, N)):
962
crystal = self[-k].e(i)
963
if crystal is None:
964
return None
965
return self.set_index(-k, crystal)
966
return None
967
968
def f(self,i):
969
r"""
970
Return the action of `f_i` on ``self``.
971
972
INPUT:
973
974
- ``i`` -- An element of the index set
975
976
EXAMPLES::
977
978
sage: La = RootSystem(['A',3,1]).weight_lattice().fundamental_weights()
979
sage: B = CrystalOfGeneralizedYoungWalls(3,La[0])
980
sage: T = TensorProductOfCrystals(B,B,B)
981
sage: b1 = B.highest_weight_vector().f_string([0,3])
982
sage: b2 = B.highest_weight_vector().f_string([0])
983
sage: b3 = B.highest_weight_vector()
984
sage: t = T(b3, b2, b1)
985
sage: t.f(0)
986
[[[0]], [[0]], [[0, 3]]]
987
sage: t.f(1)
988
[[], [[0]], [[0, 3], [1]]]
989
sage: t.f(2)
990
[[], [[0]], [[0, 3, 2]]]
991
sage: t.f(3)
992
[[], [[0, 3]], [[0, 3]]]
993
"""
994
N = len(self) + 1
995
for k in range(1, N):
996
if all(self._sig(i,k) >= self._sig(i,j) for j in range(1, k)) and \
997
all(self._sig(i,k) > self._sig(i,j) for j in range(k+1, N)):
998
crystal = self[-k].f(i)
999
if crystal is None:
1000
return None
1001
return self.set_index(-k, crystal)
1002
return None
1003
1004
class TensorProductOfRegularCrystalsElement(TensorProductOfCrystalsElement):
1005
"""
1006
Element class for a tensor product of regular crystals.
1007
1008
TESTS::
1009
1010
sage: C = CrystalOfLetters(['A',2])
1011
sage: T = TensorProductOfCrystals(C, C)
1012
sage: elt = T(C(1), C(2))
1013
sage: from sage.combinat.crystals.tensor_product import TensorProductOfRegularCrystalsElement
1014
sage: isinstance(elt, TensorProductOfRegularCrystalsElement)
1015
True
1016
"""
1017
def e(self, i):
1018
"""
1019
Return the action of `e_i` on ``self``.
1020
1021
EXAMPLES::
1022
1023
sage: C = CrystalOfLetters(['A',5])
1024
sage: T = TensorProductOfCrystals(C,C)
1025
sage: T(C(1),C(2)).e(1) == T(C(1),C(1))
1026
True
1027
sage: T(C(2),C(1)).e(1) == None
1028
True
1029
sage: T(C(2),C(2)).e(1) == T(C(1),C(2))
1030
True
1031
"""
1032
if i not in self.index_set():
1033
raise ValueError("i must be in the index set")
1034
position = self.positions_of_unmatched_plus(i)
1035
if position == []:
1036
return None
1037
k = position[0]
1038
return self.set_index(k, self[k].e(i))
1039
1040
def weight(self):
1041
"""
1042
Return the weight of ``self``.
1043
1044
EXAMPLES::
1045
1046
sage: C = CrystalOfLetters(['A',3])
1047
sage: T = TensorProductOfCrystals(C,C)
1048
sage: T(C(1),C(2)).weight()
1049
(1, 1, 0, 0)
1050
sage: T=CrystalOfTableaux(['D',4],shape=[])
1051
sage: T.list()[0].weight()
1052
(0, 0, 0, 0)
1053
"""
1054
return sum((self[j].weight() for j in range(len(self))), self.parent().weight_lattice_realization().zero())
1055
1056
def f(self, i):
1057
"""
1058
Return the action of `f_i` on ``self``.
1059
1060
EXAMPLES::
1061
1062
sage: C = CrystalOfLetters(['A',5])
1063
sage: T = TensorProductOfCrystals(C,C)
1064
sage: T(C(1),C(1)).f(1)
1065
[1, 2]
1066
sage: T(C(1),C(2)).f(1)
1067
[2, 2]
1068
sage: T(C(2),C(1)).f(1) is None
1069
True
1070
"""
1071
if i not in self.index_set():
1072
raise ValueError("i must be in the index set")
1073
position = self.positions_of_unmatched_minus(i)
1074
if position == []:
1075
return None
1076
k = position[len(position)-1]
1077
return self.set_index(k, self[k].f(i))
1078
1079
def phi(self, i):
1080
r"""
1081
Return `\varphi_i` of ``self``.
1082
1083
EXAMPLES::
1084
1085
sage: C = CrystalOfLetters(['A',5])
1086
sage: T = TensorProductOfCrystals(C,C)
1087
sage: T(C(1),C(1)).phi(1)
1088
2
1089
sage: T(C(1),C(2)).phi(1)
1090
1
1091
sage: T(C(2),C(1)).phi(1)
1092
0
1093
"""
1094
self = self.reversed()
1095
height = 0
1096
for j in range(len(self)):
1097
plus = self[j].epsilon(i)
1098
minus = self[j].phi(i)
1099
if height-plus < 0:
1100
height = minus
1101
else:
1102
height = height - plus + minus
1103
return height
1104
1105
def epsilon(self, i):
1106
r"""
1107
Return `\varepsilon_i` of ``self``.
1108
1109
EXAMPLES::
1110
1111
sage: C = CrystalOfLetters(['A',5])
1112
sage: T = TensorProductOfCrystals(C,C)
1113
sage: T(C(1),C(1)).epsilon(1)
1114
0
1115
sage: T(C(1),C(2)).epsilon(1)
1116
1
1117
sage: T(C(2),C(1)).epsilon(1)
1118
0
1119
"""
1120
height = 0
1121
for j in range(len(self)):
1122
minus = self[j].phi(i)
1123
plus = self[j].epsilon(i)
1124
if height-minus < 0:
1125
height = plus
1126
else:
1127
height = height - minus + plus
1128
return height
1129
1130
def positions_of_unmatched_minus(self, i, dual=False, reverse=False):
1131
"""
1132
EXAMPLES::
1133
1134
sage: C = CrystalOfLetters(['A',5])
1135
sage: T = TensorProductOfCrystals(C,C)
1136
sage: T(C(2),C(1)).positions_of_unmatched_minus(1)
1137
[]
1138
sage: T(C(1),C(2)).positions_of_unmatched_minus(1)
1139
[0]
1140
"""
1141
unmatched_plus = []
1142
height = 0
1143
if reverse == True:
1144
self = self.reversed()
1145
if dual == False:
1146
for j in range(len(self)):
1147
minus = self[j].phi(i)
1148
plus = self[j].epsilon(i)
1149
if height-minus < 0:
1150
unmatched_plus.append(j)
1151
height = plus
1152
else:
1153
height = height - minus + plus
1154
else:
1155
for j in range(len(self)):
1156
plus = self[j].epsilon(i)
1157
minus = self[j].phi(i)
1158
if height-plus < 0:
1159
unmatched_plus.append(j)
1160
height = minus
1161
else:
1162
height = height - plus + minus
1163
return unmatched_plus
1164
1165
def positions_of_unmatched_plus(self, i):
1166
"""
1167
EXAMPLES::
1168
1169
sage: C = CrystalOfLetters(['A',5])
1170
sage: T = TensorProductOfCrystals(C,C)
1171
sage: T(C(2),C(1)).positions_of_unmatched_plus(1)
1172
[]
1173
sage: T(C(1),C(2)).positions_of_unmatched_plus(1)
1174
[1]
1175
"""
1176
l = self.positions_of_unmatched_minus(i, dual=True, reverse=True)
1177
l.reverse()
1178
return [len(self)-1-l[j] for j in range(len(l))]
1179
1180
def energy_function(self):
1181
r"""
1182
Return the energy function of ``self``.
1183
1184
INPUT:
1185
1186
- ``self`` -- an element of a tensor product of perfect Kirillov-Reshetkhin crystals of the same level.
1187
1188
OUTPUT: an integer
1189
1190
The energy is only defined when ``self`` is an element of a tensor product of affine Kirillov-Reshetikhin crystals.
1191
In this implementation, it is assumed that ``self`` is an element of a tensor product of perfect crystals of the
1192
same level, see Theorem 7.5 in [SchillingTingley2011]_.
1193
1194
REFERENCES:
1195
1196
.. [SchillingTingley2011] A. Schilling, P. Tingley.
1197
Demazure crystals, Kirillov-Reshetikhin crystals, and the energy
1198
function. Electronic Journal of Combinatorics. **19(2)**. 2012.
1199
:arXiv:`1104.2359`
1200
1201
EXAMPLES::
1202
1203
sage: K = KirillovReshetikhinCrystal(['A',2,1],1,1)
1204
sage: T = TensorProductOfCrystals(K,K,K)
1205
sage: hw = [b for b in T if all(b.epsilon(i)==0 for i in [1,2])]
1206
sage: for b in hw:
1207
... print b, b.energy_function()
1208
...
1209
[[[1]], [[1]], [[1]]] 0
1210
[[[1]], [[2]], [[1]]] 2
1211
[[[2]], [[1]], [[1]]] 1
1212
[[[3]], [[2]], [[1]]] 3
1213
1214
sage: K = KirillovReshetikhinCrystal(['C',2,1],1,2)
1215
sage: T = TensorProductOfCrystals(K,K)
1216
sage: hw = [b for b in T if all(b.epsilon(i)==0 for i in [1,2])]
1217
sage: for b in hw: # long time (5s on sage.math, 2011)
1218
... print b, b.energy_function()
1219
...
1220
[[], []] 4
1221
[[], [[1, 1]]] 1
1222
[[[1, 1]], []] 3
1223
[[[1, 1]], [[1, 1]]] 0
1224
[[[1, 2]], [[1, 1]]] 1
1225
[[[2, 2]], [[1, 1]]] 2
1226
[[[-1, -1]], [[1, 1]]] 2
1227
[[[1, -1]], [[1, 1]]] 2
1228
[[[2, -1]], [[1, 1]]] 2
1229
1230
sage: K = KirillovReshetikhinCrystal(['C',2,1],1,1)
1231
sage: T = TensorProductOfCrystals(K)
1232
sage: t = T.module_generators[0]
1233
sage: t.energy_function()
1234
Traceback (most recent call last):
1235
...
1236
ValueError: All crystals in the tensor product need to be perfect of the same level
1237
"""
1238
C = self.parent().crystals[0]
1239
ell = ceil(C.s()/C.cartan_type().c()[C.r()])
1240
if any(ell != K.s()/K.cartan_type().c()[K.r()] for K in self.parent().crystals):
1241
raise ValueError("All crystals in the tensor product need to be perfect of the same level")
1242
t = self.parent()(*[K.module_generator() for K in self.parent().crystals])
1243
d = t.affine_grading()
1244
return d - self.affine_grading()
1245
1246
def affine_grading(self):
1247
r"""
1248
Returns the affine grading of `self`.
1249
1250
INPUT:
1251
1252
- ``self`` -- an element of a tensor product of Kirillov-Reshetikhin crystals.
1253
1254
OUTPUT: an integer
1255
1256
The affine grading is only defined when ``self`` is an element of a tensor product of affine Kirillov-Reshetikhin crystals.
1257
It is calculated by finding a path from ``self`` to a ground state path using the helper method
1258
:meth:`e_string_to_ground_state` and counting the number of affine Kashiwara operators `e_0` applied on the way.
1259
1260
EXAMPLES::
1261
1262
sage: K = KirillovReshetikhinCrystal(['A',2,1],1,1)
1263
sage: T = TensorProductOfCrystals(K,K)
1264
sage: t = T.module_generators[0]
1265
sage: t.affine_grading()
1266
1
1267
1268
sage: K = KirillovReshetikhinCrystal(['A',2,1],1,1)
1269
sage: T = TensorProductOfCrystals(K,K,K)
1270
sage: hw = [b for b in T if all(b.epsilon(i)==0 for i in [1,2])]
1271
sage: for b in hw:
1272
... print b, b.affine_grading()
1273
...
1274
[[[1]], [[1]], [[1]]] 3
1275
[[[1]], [[2]], [[1]]] 1
1276
[[[2]], [[1]], [[1]]] 2
1277
[[[3]], [[2]], [[1]]] 0
1278
1279
sage: K = KirillovReshetikhinCrystal(['C',2,1],1,1)
1280
sage: T = TensorProductOfCrystals(K,K,K)
1281
sage: hw = [b for b in T if all(b.epsilon(i)==0 for i in [1,2])]
1282
sage: for b in hw:
1283
... print b, b.affine_grading()
1284
...
1285
[[[1]], [[1]], [[1]]] 2
1286
[[[1]], [[2]], [[1]]] 1
1287
[[[1]], [[-1]], [[1]]] 0
1288
[[[2]], [[1]], [[1]]] 1
1289
[[[-2]], [[2]], [[1]]] 0
1290
[[[-1]], [[1]], [[1]]] 1
1291
"""
1292
return self.e_string_to_ground_state().count(0)
1293
1294
@cached_method
1295
def e_string_to_ground_state(self):
1296
r"""
1297
Returns a string of integers in the index set `(i_1,\ldots,i_k)` such that `e_{i_k} \cdots e_{i_1} self` is
1298
the ground state.
1299
1300
INPUT:
1301
1302
- ``self`` -- an element of a tensor product of Kirillov-Reshetikhin crystals.
1303
1304
OUTPUT: a tuple of integers `(i_1,\ldots,i_k)`
1305
1306
This method is only defined when ``self`` is an element of a tensor product of affine Kirillov-Reshetikhin crystals.
1307
It calculates a path from ``self`` to a ground state path using Demazure arrows as defined in
1308
Lemma 7.3 in [SchillingTingley2011]_.
1309
1310
EXAMPLES::
1311
1312
sage: K = KirillovReshetikhinCrystal(['A',2,1],1,1)
1313
sage: T = TensorProductOfCrystals(K,K)
1314
sage: t = T.module_generators[0]
1315
sage: t.e_string_to_ground_state()
1316
(0, 2)
1317
1318
sage: K = KirillovReshetikhinCrystal(['C',2,1],1,1)
1319
sage: T = TensorProductOfCrystals(K,K)
1320
sage: t = T.module_generators[0]; t
1321
[[[1]], [[1]]]
1322
sage: t.e_string_to_ground_state()
1323
(0,)
1324
sage: x=t.e(0)
1325
sage: x.e_string_to_ground_state()
1326
()
1327
sage: y=t.f_string([1,2,1,1,0]); y
1328
[[[2]], [[1]]]
1329
sage: y.e_string_to_ground_state()
1330
()
1331
"""
1332
from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux
1333
if self.parent().crystals[0].__module__ != 'sage.combinat.crystals.kirillov_reshetikhin' and \
1334
not isinstance(self.parent().crystals[0], KirillovReshetikhinTableaux):
1335
raise ValueError("All crystals in the tensor product need to be Kirillov-Reshetikhin crystals")
1336
I = self.cartan_type().classical().index_set()
1337
ell = max(ceil(K.s()/K.cartan_type().c()[K.r()]) for K in self.parent().crystals)
1338
for i in I:
1339
if self.epsilon(i) > 0:
1340
return (i,) + (self.e(i)).e_string_to_ground_state()
1341
if self.epsilon(0) > ell:
1342
return (0,) + (self.e(0)).e_string_to_ground_state()
1343
return ()
1344
1345
CrystalOfWords.Element = TensorProductOfCrystalsElement
1346
1347
class FullTensorProductOfRegularCrystals(FullTensorProductOfCrystals):
1348
"""
1349
Full tensor product of regular crystals.
1350
"""
1351
Element = TensorProductOfRegularCrystalsElement
1352
1353
class TensorProductOfRegularCrystalsWithGenerators(TensorProductOfCrystalsWithGenerators):
1354
"""
1355
Tensor product of regular crystals with a generating set.
1356
"""
1357
Element = TensorProductOfRegularCrystalsElement
1358
1359
#########################################################
1360
## Crystal of tableaux
1361
1362
class CrystalOfTableaux(CrystalOfWords):
1363
r"""
1364
A class for crystals of tableaux with integer valued shapes
1365
1366
INPUT:
1367
1368
- ``cartan_type`` -- a Cartan type
1369
- ``shape`` -- a partition of length at most ``cartan_type.rank()``
1370
- ``shapes`` -- a list of such partitions
1371
1372
This constructs a classical crystal with the given Cartan type and
1373
highest weight(s) corresponding to the given shape(s).
1374
1375
If the type is `D_r`, the shape is permitted to have a negative
1376
value in the `r`-th position. Thus if the shape equals `[s_1,\ldots,s_r]`,
1377
then `s_r` may be negative but in any case `s_1 \geq \cdots \geq s_{r-1}
1378
\geq |s_r|`. This crystal is related to that of shape
1379
`[s_1,\ldots,|s_r|]` by the outer automorphism of `SO(2r)`.
1380
1381
If the type is `D_r` or `B_r`, the shape is permitted to be of
1382
length `r` with all parts of half integer value. This corresponds
1383
to having one spin column at the beginning of the tableau. If
1384
several shapes are provided, they currently should all or none
1385
have this property.
1386
1387
Crystals of tableaux are constructed using an embedding into
1388
tensor products following Kashiwara and Nakashima [KN94]_. Sage's tensor
1389
product rule for crystals differs from that of Kashiwara and Nakashima
1390
by reversing the order of the tensor factors. Sage produces the same
1391
crystals of tableaux as Kashiwara and Nakashima. With Sage's convention,
1392
the tensor product of crystals is the same as the monoid operation on
1393
tableaux and hence the plactic monoid.
1394
1395
.. SEEALSO::
1396
1397
:mod:`sage.combinat.crystals.crystals` for general help on
1398
crystals, and in particular plotting and `\LaTeX` output.
1399
1400
EXAMPLES:
1401
1402
We create the crystal of tableaux for type `A_2`, with
1403
highest weight given by the partition `[2,1,1]`::
1404
1405
sage: T = CrystalOfTableaux(['A',3], shape = [2,1,1])
1406
1407
Here is the list of its elements::
1408
1409
sage: T.list()
1410
[[[1, 1], [2], [3]], [[1, 2], [2], [3]], [[1, 3], [2], [3]],
1411
[[1, 4], [2], [3]], [[1, 4], [2], [4]], [[1, 4], [3], [4]],
1412
[[2, 4], [3], [4]], [[1, 1], [2], [4]], [[1, 2], [2], [4]],
1413
[[1, 3], [2], [4]], [[1, 3], [3], [4]], [[2, 3], [3], [4]],
1414
[[1, 1], [3], [4]], [[1, 2], [3], [4]], [[2, 2], [3], [4]]]
1415
1416
Internally, a tableau of a given Cartan type is represented as a
1417
tensor product of letters of the same type. The order in which the
1418
tensor factors appear is by reading the columns of the tableaux
1419
left to right, top to bottom (in French notation). As an example::
1420
1421
sage: T = CrystalOfTableaux(['A',2], shape = [3,2])
1422
sage: T.module_generators[0]
1423
[[1, 1, 1], [2, 2]]
1424
sage: T.module_generators[0]._list
1425
[2, 1, 2, 1, 1]
1426
1427
To create a tableau, one can use::
1428
1429
sage: Tab = CrystalOfTableaux(['A',3], shape = [2,2])
1430
sage: Tab(rows=[[1,2],[3,4]])
1431
[[1, 2], [3, 4]]
1432
sage: Tab(columns=[[3,1],[4,2]])
1433
[[1, 2], [3, 4]]
1434
1435
.. TODO::
1436
1437
FIXME:
1438
1439
- Do we want to specify the columns increasingly or
1440
decreasingly? That is, should this be
1441
``Tab(columns = [[1,3],[2,4]])``?
1442
- Make this fully consistent with
1443
:func:`~sage.combinat.tableau.Tableau`!
1444
1445
We illustrate the use of a shape with a negative last entry in
1446
type `D`::
1447
1448
sage: T = CrystalOfTableaux(['D',4],shape=[1,1,1,-1])
1449
sage: T.cardinality()
1450
35
1451
sage: TestSuite(T).run()
1452
1453
We illustrate the construction of crystals of spin tableaux when
1454
the partitions have half integer values in type `B` and `D`::
1455
1456
sage: T = CrystalOfTableaux(['B',3],shape=[3/2,1/2,1/2]); T
1457
The crystal of tableaux of type ['B', 3] and shape(s) [[3/2, 1/2, 1/2]]
1458
sage: T.cardinality()
1459
48
1460
sage: T.module_generators
1461
[[+++, [[1]]]]
1462
sage: TestSuite(T).run()
1463
1464
sage: T = CrystalOfTableaux(['D',3],shape=[3/2,1/2,-1/2]); T
1465
The crystal of tableaux of type ['D', 3] and shape(s) [[3/2, 1/2, -1/2]]
1466
sage: T.cardinality()
1467
20
1468
sage: T.module_generators
1469
[[++-, [[1]]]]
1470
sage: TestSuite(T).run()
1471
1472
TESTS:
1473
1474
Base cases::
1475
1476
sage: T = CrystalOfTableaux(['A',2], shape = [])
1477
sage: T.list()
1478
[[]]
1479
sage: TestSuite(T).run()
1480
1481
sage: T = CrystalOfTableaux(['C',2], shape = [1])
1482
sage: T.list()
1483
[[[1]], [[2]], [[-2]], [[-1]]]
1484
sage: TestSuite(T).run()
1485
1486
sage: T = CrystalOfTableaux(['A',2], shapes = [[],[1],[2]])
1487
sage: T.list()
1488
[[], [[1]], [[2]], [[3]], [[1, 1]], [[1, 2]], [[2, 2]], [[1, 3]], [[2, 3]], [[3, 3]]]
1489
sage: T.module_generators
1490
([], [[1]], [[1, 1]])
1491
1492
sage: T = CrystalOfTableaux(['B',2], shape=[3])
1493
sage: T(rows=[[1,1,0]])
1494
[[1, 1, 0]]
1495
1496
Input tests::
1497
1498
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1499
sage: C = T.letters
1500
sage: Tab(rows = [[1,2],[3,4]])._list == [C(3),C(1),C(4),C(2)]
1501
True
1502
sage: Tab(columns = [[3,1],[4,2]])._list == [C(3),C(1),C(4),C(2)]
1503
True
1504
1505
For compatibility with :func:`TensorProductOfCrystals` we need to
1506
accept as input the internal list or sequence of elements::
1507
1508
sage: Tab(list = [3,1,4,2])._list == [C(3),C(1),C(4),C(2)]
1509
True
1510
sage: Tab(3,1,4,2)._list == [C(3),C(1),C(4),C(2)]
1511
True
1512
1513
The next example checks whether a given tableau is in fact a valid
1514
type `C` tableau or not::
1515
1516
sage: T = CrystalOfTableaux(['C',3], shape = [2,2,2])
1517
sage: Tab = T(rows=[[1,3],[2,-3],[3,-1]])
1518
sage: Tab in T.list()
1519
True
1520
sage: Tab = T(rows=[[2,3],[3,-3],[-3,-2]])
1521
sage: Tab in T.list()
1522
False
1523
"""
1524
1525
@staticmethod
1526
def __classcall_private__(cls, cartan_type, shapes = None, shape = None):
1527
"""
1528
Normalizes the input arguments to ensure unique representation,
1529
and to delegate the construction of spin tableaux.
1530
1531
EXAMPLES::
1532
1533
sage: T1 = CrystalOfTableaux(CartanType(['A',3]), shape = [2,2])
1534
sage: T2 = CrystalOfTableaux(['A',3], shape = (2,2))
1535
sage: T3 = CrystalOfTableaux(['A',3], shapes = ([2,2],))
1536
sage: T2 is T1, T3 is T1
1537
(True, True)
1538
"""
1539
cartan_type = CartanType(cartan_type)
1540
n = cartan_type.rank()
1541
# standardize shape/shapes input into a tuple of tuples
1542
assert operator.xor(shape is not None, shapes is not None)
1543
if shape is not None:
1544
shapes = (shape,)
1545
spin_shapes = tuple( tuple(shape) for shape in shapes )
1546
try:
1547
shapes = tuple( tuple(trunc(i) for i in shape) for shape in spin_shapes )
1548
except Exception:
1549
raise ValueError("shapes should all be partitions or half-integer partitions")
1550
if spin_shapes == shapes:
1551
return super(CrystalOfTableaux, cls).__classcall__(cls, cartan_type, shapes)
1552
1553
# Handle the construction of a crystals of spin tableaux
1554
# Caveat: this currently only supports all shapes being half
1555
# integer partitions of length the rank for type B and D. In
1556
# particular, for type D, the spins all have to be plus or all
1557
# minus spins
1558
if any(len(sh) != n for sh in shapes):
1559
raise ValueError("the length of all half-integer partition shapes should be the rank")
1560
if any(2*i % 2 != 1 for shape in spin_shapes for i in shape):
1561
raise ValueError("shapes should be either all partitions or all half-integer partitions")
1562
if cartan_type.type() == 'D':
1563
if all( i >= 0 for shape in spin_shapes for i in shape):
1564
S = CrystalOfSpinsPlus(cartan_type)
1565
elif all(shape[-1]<0 for shape in spin_shapes):
1566
S = CrystalOfSpinsMinus(cartan_type)
1567
else:
1568
raise ValueError("In type D spins should all be positive or negative")
1569
else:
1570
if any( i < 0 for shape in spin_shapes for i in shape):
1571
raise ValueError("shapes should all be partitions")
1572
S = CrystalOfSpins(cartan_type)
1573
B = CrystalOfTableaux(cartan_type, shapes = shapes)
1574
T = TensorProductOfCrystals(S,B, generators=[[S.module_generators[0],x] for x in B.module_generators])
1575
T.rename("The crystal of tableaux of type %s and shape(s) %s"%(cartan_type, list(list(shape) for shape in spin_shapes)))
1576
T.shapes = spin_shapes
1577
return T
1578
1579
1580
def __init__(self, cartan_type, shapes):
1581
"""
1582
Construct the crystal of all tableaux of the given shapes
1583
1584
INPUT:
1585
1586
- ``cartan_type`` - (data coercible into) a cartan type
1587
- ``shapes`` - a list (or iterable) of shapes
1588
- ``shape` ` - a shape
1589
1590
shapes themselves are lists (or iterable) of integers
1591
1592
EXAMPLES::
1593
1594
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1595
sage: TestSuite(T).run()
1596
"""
1597
# super(CrystalOfTableaux, self).__init__(category = FiniteEnumeratedSets())
1598
Parent.__init__(self, category = ClassicalCrystals())
1599
self.letters = CrystalOfLetters(cartan_type)
1600
self.shapes = shapes
1601
self.module_generators = tuple(self.module_generator(la) for la in shapes)
1602
self.rename("The crystal of tableaux of type %s and shape(s) %s"%(cartan_type, list(list(shape) for shape in shapes)))
1603
1604
def cartan_type(self):
1605
"""
1606
Returns the Cartan type of the associated crystal
1607
1608
EXAMPLES::
1609
1610
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1611
sage: T.cartan_type()
1612
['A', 3]
1613
"""
1614
return self.letters.cartan_type()
1615
1616
def module_generator(self, shape):
1617
"""
1618
This yields the module generator (or highest weight element) of a classical
1619
crystal of given shape. The module generator is the unique tableau with equal
1620
shape and content.
1621
1622
EXAMPLE::
1623
1624
sage: T = CrystalOfTableaux(['D',3], shape = [1,1])
1625
sage: T.module_generator([1,1])
1626
[[1], [2]]
1627
1628
sage: T = CrystalOfTableaux(['D',4],shape=[2,2,2,-2])
1629
sage: T.module_generator(tuple([2,2,2,-2]))
1630
[[1, 1], [2, 2], [3, 3], [-4, -4]]
1631
sage: T.cardinality()
1632
294
1633
sage: T = CrystalOfTableaux(['D',4],shape=[2,2,2,2])
1634
sage: T.module_generator(tuple([2,2,2,2]))
1635
[[1, 1], [2, 2], [3, 3], [4, 4]]
1636
sage: T.cardinality()
1637
294
1638
"""
1639
type = self.cartan_type()
1640
if type[0] == 'D' and len(shape) == type[1] and shape[type[1]-1] < 0:
1641
invert = True
1642
shape = shape[:-1]+(-shape[type[1]-1],)
1643
else:
1644
invert = False
1645
p = Partition(shape).conjugate()
1646
# The column canonical tableau, read by columns
1647
module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(len(p))])
1648
if invert:
1649
f = lambda x : -x if x == type[1] else x
1650
module_generator = map(f, module_generator)
1651
return self(list=[self.letters(x) for x in module_generator])
1652
1653
def _element_constructor_(self, *args, **options):
1654
"""
1655
Returns a CrystalOfTableauxElement
1656
1657
EXAMPLES::
1658
1659
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1660
sage: T(rows=[[1,2],[3,4]])
1661
[[1, 2], [3, 4]]
1662
sage: T(columns=[[3,1],[4,2]])
1663
[[1, 2], [3, 4]]
1664
"""
1665
return self.element_class(self, *args, **options)
1666
1667
1668
1669
class CrystalOfTableauxElement(TensorProductOfRegularCrystalsElement):
1670
"""
1671
Element in a crystal of tableaux.
1672
"""
1673
def __init__(self, parent, *args, **options):
1674
"""
1675
There are several ways to input tableaux, by rows,
1676
by columns, as the list of column elements, or as a sequence of numbers
1677
in column reading.
1678
1679
EXAMPLES::
1680
1681
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1682
sage: t = T(rows=[[1,2],[3,4]])
1683
sage: t
1684
[[1, 2], [3, 4]]
1685
sage: TestSuite(t).run()
1686
1687
sage: t = T(columns=[[3,1],[4,2]])
1688
sage: t
1689
[[1, 2], [3, 4]]
1690
sage: TestSuite(t).run()
1691
1692
sage: t = T(list=[3,1,4,2])
1693
sage: t
1694
[[1, 2], [3, 4]]
1695
1696
sage: t = T(3,1,4,2)
1697
sage: t
1698
[[1, 2], [3, 4]]
1699
1700
Currently inputting the empty tableau as an empty sequence is broken due to a bug in
1701
the generic __call__ method (see trac ticket #8648)
1702
1703
EXAMPLES::
1704
1705
sage: T = CrystalOfTableaux(['A',3], shape=[])
1706
sage: t = T()
1707
sage: t._list
1708
[0]
1709
1710
TESTS:
1711
1712
Integer types that are not a Sage ``Integer`` (such as a Python ``int``
1713
and typically arise from compiled code) were not converted into a
1714
letter. This caused certain functions to fail. This is fixed in
1715
:trac:`13204`::
1716
1717
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1718
sage: t = T(list=[int(3),1,4,2])
1719
sage: type(t[0])
1720
<type 'sage.combinat.crystals.letters.Crystal_of_letters_type_A_element'>
1721
sage: t = T(list=[3,int(1),4,2])
1722
sage: type(t[1])
1723
<type 'sage.combinat.crystals.letters.Crystal_of_letters_type_A_element'>
1724
sage: C = KirillovReshetikhinCrystal(['A',int(3),1], 1,1)
1725
sage: C[0].e(0)
1726
[[4]]
1727
"""
1728
if len(args) == 1:
1729
if isinstance(args[0], Tableau):
1730
options['rows'] = args[0]
1731
if options.has_key('list'):
1732
list = options['list']
1733
elif options.has_key('rows'):
1734
rows=options['rows']
1735
# list=Tableau(rows).to_word_by_column()
1736
rows=Tableau(rows).conjugate()
1737
list=[]
1738
for col in rows:
1739
col.reverse()
1740
list+=col
1741
elif options.has_key('columns'):
1742
columns=options['columns']
1743
list=[]
1744
for col in columns:
1745
list+=col
1746
else:
1747
list = [i for i in args]
1748
TensorProductOfRegularCrystalsElement.__init__(self, parent, map(parent.letters, list))
1749
1750
def _repr_(self):
1751
"""
1752
EXAMPLES::
1753
1754
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1755
sage: t = T(rows=[[1,2],[3,4]])
1756
sage: t._repr_()
1757
'[[1, 2], [3, 4]]'
1758
"""
1759
return repr(self.to_tableau())
1760
1761
def pp(self):
1762
"""
1763
EXAMPLES::
1764
1765
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1766
sage: t = T(rows=[[1,2],[3,4]])
1767
sage: t.pp()
1768
1 2
1769
3 4
1770
"""
1771
return self.to_tableau().pp()
1772
1773
def _latex_(self):
1774
r"""
1775
EXAMPLES::
1776
1777
sage: T = CrystalOfTableaux(['A',3], shape = [4,2])
1778
sage: t = T(rows=[[1,1,2,3],[2,3]])
1779
sage: latex(t) # indirect doctest
1780
{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
1781
\raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{1-4}
1782
\lr{1}&\lr{1}&\lr{2}&\lr{3}\\\cline{1-4}
1783
\lr{2}&\lr{3}\\\cline{1-2}
1784
\end{array}$}
1785
}
1786
"""
1787
from sage.combinat.output import tex_from_array
1788
# Modified version of to_tableau() to have the entrys be letters
1789
# rather than their values
1790
if self._list == []:
1791
return "{\\emptyset}"
1792
1793
tab = [ [self[0]] ]
1794
for i in range(1,len(self)):
1795
if self[i-1] < self[i] or (self[i-1].value != 0 and self[i-1] == self[i]):
1796
tab.append([self[i]])
1797
else:
1798
l = len(tab)-1
1799
tab[l].append(self[i])
1800
for x in tab:
1801
x.reverse()
1802
T = Tableau(tab).conjugate()
1803
return tex_from_array([[letter._latex_() for letter in row] for row in T])
1804
1805
@cached_method
1806
def to_tableau(self):
1807
"""
1808
Returns the Tableau object corresponding to self.
1809
1810
EXAMPLES::
1811
1812
sage: T = CrystalOfTableaux(['A',3], shape = [2,2])
1813
sage: t = T(rows=[[1,2],[3,4]]).to_tableau(); t
1814
[[1, 2], [3, 4]]
1815
sage: type(t)
1816
<class 'sage.combinat.tableau.Tableaux_all_with_category.element_class'>
1817
sage: type(t[0][0])
1818
<type 'int'>
1819
sage: T = CrystalOfTableaux(['D',3], shape = [1,1])
1820
sage: t=T(rows=[[-3],[3]]).to_tableau(); t
1821
[[-3], [3]]
1822
sage: t=T(rows=[[3],[-3]]).to_tableau(); t
1823
[[3], [-3]]
1824
sage: T = CrystalOfTableaux(['B',2], shape = [1,1])
1825
sage: t = T(rows=[[0],[0]]).to_tableau(); t
1826
[[0], [0]]
1827
"""
1828
if self._list == []:
1829
return Tableau([])
1830
tab = [ [self[0].value] ]
1831
for i in range(1,len(self)):
1832
if self[i-1] < self[i] or (self[i-1].value != 0 and self[i-1] == self[i]):
1833
tab.append([self[i].value])
1834
else:
1835
l = len(tab)-1
1836
tab[l].append(self[i].value)
1837
for x in tab:
1838
x.reverse()
1839
return Tableau(tab).conjugate()
1840
1841
def promotion(self):
1842
"""
1843
Promotion for type A crystals of tableaux of rectangular shape
1844
1845
Returns the result of applying promotion on this tableau.
1846
1847
This method only makes sense in type A with rectangular shapes.
1848
1849
EXAMPLES::
1850
1851
sage: C = CrystalOfTableaux(["A",3], shape = [3,3,3])
1852
sage: t = C(Tableau([[1,1,1],[2,2,3],[3,4,4]]))
1853
sage: t
1854
[[1, 1, 1], [2, 2, 3], [3, 4, 4]]
1855
sage: t.promotion()
1856
[[1, 1, 2], [2, 2, 3], [3, 4, 4]]
1857
sage: t.promotion().parent()
1858
The crystal of tableaux of type ['A', 3] and shape(s) [[3, 3, 3]]
1859
"""
1860
crystal = self.parent()
1861
cartan_type = crystal.cartan_type()
1862
assert cartan_type.type() == 'A'
1863
return crystal(self.to_tableau().promotion(cartan_type.rank()))
1864
1865
def promotion_inverse(self):
1866
"""
1867
Inverse promotion for type A crystals of tableaux of rectangular shape
1868
1869
Returns the result of applying inverse promotion on this tableau.
1870
1871
This method only makes sense in type A with rectangular shapes.
1872
1873
EXAMPLES::
1874
1875
sage: C = CrystalOfTableaux(["A",3], shape = [3,3,3])
1876
sage: t = C(Tableau([[1,1,1],[2,2,3],[3,4,4]]))
1877
sage: t
1878
[[1, 1, 1], [2, 2, 3], [3, 4, 4]]
1879
sage: t.promotion_inverse()
1880
[[1, 1, 2], [2, 3, 3], [4, 4, 4]]
1881
sage: t.promotion_inverse().parent()
1882
The crystal of tableaux of type ['A', 3] and shape(s) [[3, 3, 3]]
1883
"""
1884
crystal = self.parent()
1885
cartan_type = crystal.cartan_type()
1886
assert cartan_type.type() == 'A'
1887
return crystal(self.to_tableau().promotion_inverse(cartan_type.rank()))
1888
1889
CrystalOfTableaux.Element = CrystalOfTableauxElement
1890
1891