Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/gelfand_tsetlin_patterns.py
8817 views
1
r"""
2
Gelfand-Tsetlin Patterns
3
4
AUTHORS:
5
6
- Travis Scrimshaw (2013-15-03): Initial version
7
8
REFERENCES:
9
10
.. [BBF] B. Brubaker, D. Bump, and S. Friedberg.
11
Weyl Group Multiple Dirichlet Series: Type A Combinatorial Theory.
12
Ann. of Math. Stud., vol. 175, Princeton Univ. Press, New Jersey, 2011.
13
14
.. [GC50] I. M. Gelfand and M. L. Cetlin.
15
Finite-Dimensional Representations of the Group of Unimodular Matrices.
16
Dokl. Akad. Nauk SSSR **71**, pp. 825--828, 1950.
17
18
.. [Tok88] T. Tokuyama.
19
A Generating Function of Strict Gelfand Patterns and Some Formulas on
20
Characters of General Linear Groups.
21
J. Math. Soc. Japan **40** (4), pp. 671--685, 1988.
22
"""
23
#*****************************************************************************
24
# Copyright (C) 2013 Travis Scrimshaw <[email protected]>
25
#
26
# Distributed under the terms of the GNU General Public License (GPL)
27
#
28
# This code is distributed in the hope that it will be useful,
29
# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31
# General Public License for more details.
32
#
33
# The full text of the GPL is available at:
34
#
35
# http://www.gnu.org/licenses/
36
#*****************************************************************************
37
38
from sage.structure.parent import Parent
39
from sage.structure.list_clone import ClonableArray
40
from sage.structure.unique_representation import UniqueRepresentation
41
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
42
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
43
from sage.misc.classcall_metaclass import ClasscallMetaclass
44
from sage.misc.cachefunc import cached_method
45
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
46
from sage.rings.all import ZZ
47
from sage.combinat.partition import Partitions
48
from sage.combinat.tableau import Tableau, SemistandardTableaux
49
from sage.combinat.combinatorial_map import combinatorial_map
50
from sage.misc.misc import prod
51
52
class GelfandTsetlinPattern(ClonableArray):
53
r"""
54
A Gelfand-Tsetlin (sometimes written as Gelfand-Zetlin or Gelfand-Cetlin)
55
pattern. They were originally defined in [GC50]_.
56
57
A Gelfand-Tsetlin pattern is a triangular array:
58
59
.. MATH::
60
61
\begin{array}{ccccccccc}
62
a_{1,1} & & a_{1,2} & & a_{1,3} & & \cdots & & a_{1,n} \\
63
& a_{2,2} & & a_{2,3} & & \cdots & & a_{2,n} \\
64
& & a_{3,3} & & \cdots & & a_{3,n} \\
65
& & & \ddots \\
66
& & & & a_{n,n}
67
\end{array}
68
69
such that `a_{i,j} \geq a_{i+1,j+1} \geq a_{i,j+1}`.
70
71
Gelfand-Tsetlin patterns are in bijection with semistandard Young tableaux
72
by the following algorithm. Let `G` be a Gelfand-Tsetlin pattern with
73
`\lambda^{(k)}` being the `(n-k+1)`-st row (note that this is a partition).
74
The definition of `G` implies
75
76
.. MATH::
77
78
\lambda^{(0)} \subseteq \lambda^{(1)} \subseteq \cdots \subseteq
79
\lambda^{(n)},
80
81
where `\lambda^{(0)}` is the empty partition, and each skew shape
82
`\lambda^{(k)}/\lambda^{(k-1)}` is a horizontal strip. Thus define `T(G)`
83
by inserting `k` into the squares of the skew shape
84
`\lambda^{(k)}/ \lambda^{(k-1)}`, for `k=1,\dots,n`.
85
86
To each entry in a Gelfand-Tsetlin pattern, one may attach a decoration of
87
a circle or a box (or both or neither). These decorations appear in the
88
study of Weyl group multiple Dirichlet series, and are implemented here
89
following the exposition in [BBF]_.
90
91
.. NOTE::
92
93
We use the "right-hand" rule for determining circled and boxed entries.
94
95
.. WARNING::
96
97
The entries in Sage are 0-based and are thought of as flushed to the
98
left in a matrix. In other words, the coordinates of entries in the
99
Gelfand-Tsetlin patterns are thought of as the matrix:
100
101
.. MATH::
102
103
\begin{bmatrix}
104
g_{0,0} & g_{0,1} & g_{0,2} & \cdots & g_{0,n-2} & g_{n-1,n-1} \\
105
g_{1,0} & g_{1,1} & g_{1,2} & \cdots & g_{1,n-2} \\
106
g_{2,0} & g_{2,1} & g_{2,2} & \cdots \\
107
\vdots & \vdots & \vdots \\
108
g_{n-2,0} & g_{n-2,1} \\
109
g_{n-1,0}
110
\end{bmatrix}.
111
112
However, in the discussions, we will be using the **standard**
113
numbering system.
114
115
EXAMPLES::
116
117
sage: G = GelfandTsetlinPattern([[3, 2, 1], [2, 1], [1]]); G
118
[[3, 2, 1], [2, 1], [1]]
119
sage: G.pp()
120
3 2 1
121
2 1
122
1
123
sage: G = GelfandTsetlinPattern([[7, 7, 4, 0], [7, 7, 3], [7, 5], [5]]); G.pp()
124
7 7 4 0
125
7 7 3
126
7 5
127
5
128
sage: G.to_tableau().pp()
129
1 1 1 1 1 2 2
130
2 2 2 2 2 3 3
131
3 3 3 4
132
"""
133
# Note that the width == height, so len(gt) == len(gt[0]) except
134
# we don't have to check if it is the emtry GT pattern
135
__metaclass__ = ClasscallMetaclass
136
137
@staticmethod
138
def __classcall_private__(self, gt):
139
"""
140
Return ``gt`` as a proper element of :class:`GelfandTsetlinPatterns`.
141
142
EXAMPLES::
143
144
sage: G = GelfandTsetlinPattern([[3,2,1],[2,1],[1]])
145
sage: G.parent()
146
Gelfand-Tsetlin patterns
147
sage: TestSuite(G).run()
148
"""
149
return GelfandTsetlinPatterns()(gt)
150
151
def check(self):
152
"""
153
Check that this is a valid Gelfand-Tsetlin pattern.
154
155
EXAMPLES::
156
157
sage: G = GelfandTsetlinPatterns()
158
sage: G([[3,2,1],[2,1],[1]]).check()
159
"""
160
assert all( self[i-1][j] >= self[i][j] >= self[i-1][j+1]
161
for i in range(1, len(self)) for j in range(len(self[i])) )
162
163
def _hash_(self):
164
"""
165
Return the hash value of ``self``.
166
167
EXAMPLES::
168
169
sage: G = GelfandTsetlinPatterns()
170
sage: gt = G([[3,2,1],[2,1],[1]])
171
sage: hash(gt) == hash(gt)
172
True
173
174
Check that :trac:`14717` is fixed::
175
176
sage: GT = GelfandTsetlinPattern([[2, 1, 0], [2, 0], [1]])
177
sage: GT in {}
178
False
179
"""
180
return hash(tuple(map(tuple, self)))
181
182
def _repr_diagram(self):
183
"""
184
Return a string representation of ``self`` as a diagram.
185
186
EXAMPLES::
187
188
sage: G = GelfandTsetlinPatterns()
189
sage: print G([[3,2,1],[2,1],[1]])._repr_diagram()
190
3 2 1
191
2 1
192
1
193
"""
194
ret = ''
195
for i, row in enumerate(self):
196
if i != 0:
197
ret += '\n'
198
ret += ' '*i
199
ret += ' '.join('%3s'%val for val in row)
200
return ret
201
202
def pp(self):
203
"""
204
Pretty print ``self``.
205
206
EXAMPLES::
207
208
sage: G = GelfandTsetlinPatterns()
209
sage: G([[3,2,1],[2,1],[1]]).pp()
210
3 2 1
211
2 1
212
1
213
"""
214
print self._repr_diagram()
215
216
def _latex_(self):
217
r"""
218
Return a `\LaTeX` representation of ``self``.
219
220
EXAMPLES::
221
222
sage: G = GelfandTsetlinPatterns()
223
sage: latex(G([[3,2,1],[2,1],[1]]))
224
\begin{array}{ccccc}
225
3 & & 2 & & 1 \\
226
& 2 & & 1 & \\
227
& & 1 & &
228
\end{array}
229
sage: latex(G([]))
230
\emptyset
231
"""
232
n = len(self)
233
if n == 0:
234
return "\\emptyset"
235
ret = "\\begin{array}{" + 'c'*(n*2-1) + "}\n"
236
for i, row in enumerate(self):
237
if i > 0:
238
ret += " \\\\\n"
239
ret += "& "*i
240
ret += " & & ".join(repr(val) for val in row)
241
ret += " &"*i
242
return ret + "\n\\end{array}"
243
244
@combinatorial_map(name='to semistandard tableau')
245
def to_tableau(self):
246
"""
247
Return ``self`` as a semistandard Young tableau.
248
249
The conversion from a Gelfand-Tsetlin pattern to a semistandard Young
250
tableaux is as follows. Let `G` be a Gelfand-Tsetlin pattern with
251
`\lambda^{(k)}` being the `(n-k+1)`-st row (note that this is a
252
partition). The definition of `G` implies
253
254
.. MATH::
255
256
\lambda^{(0)} \subseteq \lambda^{(1)} \subseteq \cdots \subseteq
257
\lambda^{(n)},
258
259
where `\lambda^{(0)}` is the empty partition, and each skew shape
260
`\lambda^{(k)} / \lambda^{(k-1)}` is a horizontal strip. Thus define
261
`T(G)` by inserting `k` into the squares of the skew shape
262
`\lambda^{(k)} / \lambda^{(k-1)}`, for `k=1,\dots,n`.
263
264
EXAMPLES::
265
266
sage: G = GelfandTsetlinPatterns()
267
sage: elt = G([[3,2,1],[2,1],[1]])
268
sage: T = elt.to_tableau(); T
269
[[1, 2, 3], [2, 3], [3]]
270
sage: T.pp()
271
1 2 3
272
2 3
273
3
274
sage: G(T) == elt
275
True
276
"""
277
ret = []
278
for i, row in enumerate(reversed(self)):
279
for j, val in enumerate(row):
280
if j >= len(ret):
281
if val == 0:
282
break
283
ret.append([i+1]*val)
284
else:
285
ret[j].extend([i+1]*(val-len(ret[j])))
286
S = SemistandardTableaux()
287
return S(ret)
288
289
@cached_method
290
def boxed_entries(self):
291
"""
292
Return the position of the boxed entries of ``self``.
293
294
Using the *right-hand* rule, an entry `a_{i,j}` is boxed if
295
`a_{i,j} = a_{i-1,j-1}`; i.e., `a_{i,j}` has the same value as its
296
neighbor to the northwest.
297
298
EXAMPLES::
299
300
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[1]])
301
sage: G.boxed_entries()
302
((1, 0),)
303
"""
304
ret = []
305
for i in range(1, len(self)):
306
for j in range(len(self[i])):
307
if self[i][j] == self[i-1][j]:
308
ret.append((i, j))
309
return tuple(ret)
310
311
@cached_method
312
def circled_entries(self):
313
"""
314
Return the circled entries of ``self``.
315
316
Using the *right-hand* rule, an entry `a_{i,j}` is circled if
317
`a_{i,j} = a_{i-1,j}`; i.e., `a_{i,j}` has the same value as its
318
neighbor to the northeast.
319
320
EXAMPLES::
321
322
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[1]])
323
sage: G.circled_entries()
324
((1, 1), (2, 0))
325
"""
326
ret = []
327
for i in range(1, len(self)):
328
for j in range(len(self[i])):
329
if self[i][j] == self[i-1][j+1]:
330
ret.append((i, j))
331
return tuple(ret)
332
333
@cached_method
334
def special_entries(self):
335
"""
336
Return the special entries.
337
338
An entry `a_{i,j}` is special if `a_{i-1,j-1} > a_{i,j} > a_{i-1,j}`,
339
that is to say, the entry is neither boxed nor circled and is **not**
340
in the first row. The name was coined by [Tok88]_.
341
342
EXAMPLES::
343
344
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[1]])
345
sage: G.special_entries()
346
()
347
sage: G = GelfandTsetlinPattern([[4,2,1],[4,1],[2]])
348
sage: G.special_entries()
349
((2, 0),)
350
"""
351
ret = []
352
for i in range(1, len(self)):
353
for j in range(len(self[i])):
354
if self[i-1][j] > self[i][j] and self[i][j] > self[i-1][j+1]:
355
ret.append((i, j))
356
return tuple(ret)
357
358
def number_of_boxes(self):
359
"""
360
Return the number of boxed entries. See :meth:`boxed_entries()`.
361
362
EXAMPLES::
363
364
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[1]])
365
sage: G.number_of_boxes()
366
1
367
"""
368
return len(self.boxed_entries())
369
370
def number_of_circles(self):
371
"""
372
Return the number of boxed entries. See :meth:`circled_entries()`.
373
374
EXAMPLES::
375
376
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[1]])
377
sage: G.number_of_circles()
378
2
379
"""
380
return len(self.circled_entries())
381
382
def number_of_special_entries(self):
383
"""
384
Return the number of special entries. See :meth:`special_entries()`.
385
386
EXAMPLES::
387
388
sage: G = GelfandTsetlinPattern([[4,2,1],[4,1],[2]])
389
sage: G.number_of_special_entries()
390
1
391
"""
392
return len(self.special_entries())
393
394
def is_strict(self):
395
"""
396
Return ``True`` if ``self`` is a strict Gelfand-Tsetlin pattern.
397
398
A Gelfand-Tsetlin pattern is said to be *strict* if every row is
399
strictly decreasing.
400
401
EXAMPLES::
402
403
sage: GelfandTsetlinPattern([[7,3,1],[6,2],[4]]).is_strict()
404
True
405
sage: GelfandTsetlinPattern([[3,2,1],[3,1],[1]]).is_strict()
406
True
407
sage: GelfandTsetlinPattern([[6,0,0],[3,0],[2]]).is_strict()
408
False
409
"""
410
for row in self:
411
if any(row[i] == row[i+1] for i in range(len(row)-1)):
412
return False
413
return True
414
415
def row_sums(self):
416
r"""
417
Return the list of row sums.
418
419
For a Gelfand-Tsetlin pattern `G`, the `i`-th row sum `d_i` is
420
421
.. MATH::
422
423
d_i = d_i(G) = \sum_{j=i}^{n} a_{i,j}.
424
425
EXAMPLES::
426
427
sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]])
428
sage: G.row_sums()
429
[11, 9, 7, 5, 3]
430
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[2]])
431
sage: G.row_sums()
432
[6, 4, 2]
433
"""
434
return [sum(self[i][j] for j in range(len(self[i]))) \
435
for i in range(len(self))]
436
437
def weight(self):
438
r"""
439
Return the weight of ``self``.
440
441
Define the weight of `G` to be the content of the tableau to which `G`
442
corresponds under the bijection between Gelfand-Tsetlin patterns and
443
semistandard tableaux. More precisely,
444
445
.. MATH::
446
447
\mathrm{wt}(G) = (d_n, d_{n-1}-d_n, \dots, d_1-d_2),
448
449
where the `d_i` are the row sums.
450
451
EXAMPLES::
452
453
sage: G = GelfandTsetlinPattern([[2,1,0],[1,0],[1]])
454
sage: G.weight()
455
(1, 0, 2)
456
sage: G = GelfandTsetlinPattern([[4,2,1],[3,1],[2]])
457
sage: G.weight()
458
(2, 2, 3)
459
"""
460
wt = [self.row_sums()[-1]] + [self.row_sums()[i-1]-self.row_sums()[i] for i in reversed(range(1,len(self[0])))]
461
return tuple(wt)
462
463
def Tokuyama_coefficient(self, name='t'):
464
r"""
465
Return the Tokuyama coefficient attached to ``self``.
466
467
Following the exposition of [BBF]_, Tokuyama's formula asserts
468
469
.. MATH::
470
471
\sum_{G} (t+1)^{s(G)} t^{l(G)}
472
z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2}
473
=
474
s_{\lambda}(z_1,\dots,z_{n+1}) \prod_{i<j} (z_j+tz_i),
475
476
where the sum is over all strict Gelfand-Tsetlin patterns with fixed
477
top row `\lambda + \rho`, with `\lambda` a partition with at most
478
`n+1` parts and `\rho = (n, n-1, \ldots, 1, 0)`, and `s_\lambda` is a
479
Schur function.
480
481
INPUT:
482
483
- ``name`` -- (Default: ``'t'``) An alternative name for the
484
variable `t`.
485
486
EXAMPLES::
487
488
sage: P = GelfandTsetlinPattern([[3,2,1],[2,2],[2]])
489
sage: P.Tokuyama_coefficient()
490
0
491
sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[2]])
492
sage: G.Tokuyama_coefficient()
493
t^2 + t
494
sage: G = GelfandTsetlinPattern([[2,1,0],[1,1],[1]])
495
sage: G.Tokuyama_coefficient()
496
0
497
sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]])
498
sage: G.Tokuyama_coefficient()
499
t^8 + 3*t^7 + 3*t^6 + t^5
500
"""
501
R = PolynomialRing(ZZ, name)
502
t = R.gen(0)
503
if self.is_strict() == False:
504
return R(0)
505
return (t+1)**(self.number_of_special_entries()) * t**(self.number_of_boxes())
506
507
508
class GelfandTsetlinPatterns(Parent, UniqueRepresentation):
509
"""
510
Gelfand-Tsetlin patterns.
511
512
INPUT:
513
514
- ``n`` -- The width or depth of the array, also known as the rank
515
516
- ``k`` -- (Default: ``None``) If specified, this is the maximum value that
517
can occur in the patterns
518
519
- ``top_row`` -- (Default: ``None``) If specified, this is the fixed top
520
row of all patterns
521
522
- ``strict`` -- (Default: ``False``) Set to ``True`` if all patterns are
523
strict patterns
524
525
TESTS:
526
527
Check that the number of Gelfand-Tsetlin patterns is equal to the number
528
of semistandard Young tableaux::
529
530
sage: G = GelfandTsetlinPatterns(3,3)
531
sage: c = 0
532
sage: from sage.combinat.crystals.kirillov_reshetikhin import partitions_in_box
533
sage: for p in partitions_in_box(3,3):
534
... S = SemistandardTableaux(p, max_entry=3)
535
... c += S.cardinality()
536
sage: c == G.cardinality()
537
True
538
539
Note that the top row in reverse of the Gelfand-Tsetlin pattern is the
540
shape of the corresponding semistandard Young tableau under the bijection
541
described in :meth:`GelfandTsetlinPattern.to_tableau()`::
542
543
sage: G = GelfandTsetlinPatterns(top_row=[2,2,1])
544
sage: S = SemistandardTableaux([2,2,1], max_entry=3)
545
sage: G.cardinality() == S.cardinality()
546
True
547
"""
548
@staticmethod
549
def __classcall_private__(cls, n=None, k=None, strict=False, top_row=None):
550
"""
551
Return the correct parent based upon the inputs.
552
553
EXAMPLES::
554
555
sage: G = GelfandTsetlinPatterns()
556
sage: G2 = GelfandTsetlinPatterns()
557
sage: G is G2
558
True
559
sage: G = GelfandTsetlinPatterns(3,4, strict=True)
560
sage: G2 = GelfandTsetlinPatterns(int(3),int(4), strict=True)
561
sage: G is G2
562
True
563
sage: G = GelfandTsetlinPatterns(top_row=[3,1,1])
564
sage: G2 = GelfandTsetlinPatterns(top_row=(3,1,1))
565
sage: G is G2
566
True
567
"""
568
if top_row is not None:
569
top_row = tuple(top_row)
570
if any(top_row[i] < top_row[i+1] for i in range(len(top_row)-1)):
571
raise ValueError("The top row must be weakly decreasing")
572
if n is not None and n != len(top_row):
573
raise ValueError("n must be the length of the specified top row")
574
return GelfandTsetlinPatternsTopRow(top_row, strict)
575
return super(GelfandTsetlinPatterns, cls).__classcall__(cls, n, k, strict)
576
577
def __init__(self, n, k, strict):
578
"""
579
Initialize ``self``.
580
581
EXAMPLES::
582
583
sage: G = GelfandTsetlinPatterns()
584
sage: TestSuite(G).run()
585
sage: G = GelfandTsetlinPatterns(3)
586
sage: TestSuite(G).run()
587
sage: G = GelfandTsetlinPatterns(3, 3)
588
sage: TestSuite(G).run()
589
sage: G = GelfandTsetlinPatterns(3, 3, strict=True)
590
sage: TestSuite(G).run()
591
"""
592
self._n = n
593
self._k = k
594
self._strict = strict
595
# Note - if a top row is given, then n and k are not None
596
if k is not None and (n is not None or strict):
597
Parent.__init__(self, category=FiniteEnumeratedSets())
598
else:
599
Parent.__init__(self, category=InfiniteEnumeratedSets())
600
601
def __contains__(self, gt):
602
"""
603
Check to see if ``gt`` is in ``self``.
604
605
EXAMPLES::
606
607
sage: G = GelfandTsetlinPatterns()
608
sage: [[3, 1],[2]] in G
609
True
610
sage: [[2, 3],[4]] in G
611
False
612
sage: [[3, 1],[0]] in G
613
False
614
sage: [] in G
615
True
616
sage: G = GelfandTsetlinPatterns(3,2)
617
sage: [] in G
618
False
619
sage: [[2,0,0],[1,0],[1]] in G
620
True
621
sage: [[0,0],[0]] in G
622
False
623
sage: [[3,0,0],[2,0],[0]] in G
624
False
625
sage: G = GelfandTsetlinPatterns(3,strict=True)
626
sage: [[2,1,0],[2,1],[1]] in G
627
True
628
sage: [[3,0,0],[3,0],[0]] in G
629
False
630
"""
631
if not isinstance(gt, (list, tuple, GelfandTsetlinPattern)):
632
return False
633
# Check if it has the correct width/depth (if applicable)
634
if self._n is not None and len(gt) != self._n:
635
return False
636
# Check if it has the correct maximum value
637
if self._k is not None and any( val > self._k for row in gt for val in row ):
638
return False
639
# Check if it is a GT pattern
640
if not all( gt[i-1][j] >= gt[i][j] >= gt[i-1][j+1]
641
for i in range(1, len(gt)) for j in range(len(gt[i])) ):
642
return False
643
# Check if it is strict if applicable
644
if self._strict and any( gt[i][j] == gt[i][j-1] for i in range(len(gt))
645
for j in range(1, len(gt[i])) ):
646
return False
647
return True
648
649
def _repr_(self):
650
"""
651
Return a string representation of ``self``.
652
653
EXAMPLES::
654
655
sage: GelfandTsetlinPatterns(4)
656
Gelfand-Tsetlin patterns of width 4
657
sage: GelfandTsetlinPatterns(4, 3, strict=True)
658
Strict Gelfand-Tsetlin patterns of width 4 and max value 3
659
sage: G = GelfandTsetlinPatterns(k=3, strict=True); G
660
Strict Gelfand-Tsetlin patterns with max value 3
661
"""
662
base = "Gelfand-Tsetlin patterns"
663
if self._strict:
664
base = "Strict " + base
665
if self._n is not None:
666
if self._k is not None:
667
return base + " of width %s and max value %s"%(self._n, self._k)
668
return base + " of width %s"%self._n
669
if self._k is not None:
670
return base + " with max value %s"%self._k
671
return base
672
673
def _element_constructor_(self, gt):
674
"""
675
Construct an element of ``self`` from ``gt``.
676
677
EXAMPLES::
678
679
sage: G = GelfandTsetlinPatterns(3, 3, strict=True); G
680
Strict Gelfand-Tsetlin patterns of width 3 and max value 3
681
sage: elt = G([[3,2,1],[2,1],[1]]); elt.pp()
682
3 2 1
683
2 1
684
1
685
sage: elt.parent()
686
Strict Gelfand-Tsetlin patterns of width 3 and max value 3
687
"""
688
if isinstance(gt, GelfandTsetlinPattern) and gt.parent() == self:
689
return gt
690
if isinstance(gt, Tableau):
691
gt = [list(x) for x in reversed(gt.to_chain()[1:])]
692
n = len(gt)
693
for i in range(n):
694
while len(gt[i]) < n-i:
695
gt[i].append(0)
696
if self._n is not None:
697
if len(gt) == 0:
698
gt = [[0]]
699
while self._n != len(gt):
700
gt.insert(0, gt[0][:] + [0])
701
return self.element_class(self, gt)
702
return self.element_class(self, list(gt))
703
704
Element = GelfandTsetlinPattern
705
706
def __iter__(self):
707
"""
708
Iterate through ``self`` by using a backtracing algorithm.
709
710
EXAMPLES::
711
712
sage: L = list(GelfandTsetlinPatterns(3,3))
713
sage: c = 0
714
sage: from sage.combinat.crystals.kirillov_reshetikhin import partitions_in_box
715
sage: for p in partitions_in_box(3,3):
716
... S = SemistandardTableaux(p, max_entry=3)
717
... c += S.cardinality()
718
sage: c == len(L)
719
True
720
sage: G = GelfandTsetlinPatterns(3, 3, strict=True)
721
sage: all(x.is_strict() for x in G)
722
True
723
sage: G = GelfandTsetlinPatterns(k=3, strict=True)
724
sage: all(x.is_strict() for x in G)
725
True
726
727
Checking iterator when the set is infinite::
728
729
sage: T = GelfandTsetlinPatterns()
730
sage: it = T.__iter__()
731
sage: [it.next() for i in range(10)]
732
[[],
733
[[1]],
734
[[2]],
735
[[1, 1], [1]],
736
[[3]],
737
[[2, 1], [1]],
738
[[2, 1], [2]],
739
[[1, 1, 1], [1, 1], [1]],
740
[[4]],
741
[[3, 1], [1]]]
742
sage: T = GelfandTsetlinPatterns(k=1)
743
sage: it = T.__iter__()
744
sage: [it.next() for i in range(10)]
745
[[],
746
[[0]],
747
[[1]],
748
[[0, 0], [0]],
749
[[1, 0], [0]],
750
[[1, 0], [1]],
751
[[1, 1], [1]],
752
[[0, 0, 0], [0, 0], [0]],
753
[[1, 0, 0], [0, 0], [0]],
754
[[1, 0, 0], [1, 0], [0]]]
755
756
Check that :trac:`14718` is fixed::
757
758
sage: T = GelfandTsetlinPatterns(1,3)
759
sage: list(T)
760
[[[0]],
761
[[1]],
762
[[2]],
763
[[3]]]
764
"""
765
# Special cases
766
if self._n is None:
767
yield self.element_class(self, [])
768
if self._k is None:
769
# Since both `n` and `k` are none, we need special consideration
770
# while iterating, so we do so by specifying the top row by
771
# using the iterator for partitions
772
n = 1
773
while True:
774
if self._strict:
775
P = Partitions(n, max_slope=-1)
776
else:
777
P = Partitions(n)
778
for p in P:
779
for x in GelfandTsetlinPatterns(top_row=tuple(p), strict=self._strict):
780
yield self.element_class(self, list(x))
781
n += 1
782
return
783
for x in xrange(self._k+1):
784
yield self.element_class(self, [[x]])
785
n = 2
786
while not self._strict or n <= self._k+1:
787
for x in self._list_iter(n):
788
yield self.element_class(self, x)
789
n += 1
790
return
791
if self._n < 0:
792
return
793
if self._n == 0:
794
yield self.element_class(self, [])
795
return
796
if self._n == 1:
797
if self._k is not None:
798
for x in xrange(self._k+1):
799
yield self.element_class(self, [[x]])
800
else:
801
k = 1
802
while True:
803
yield self.element_class(self, [[k]])
804
k += 1
805
return
806
for x in self._list_iter(self._n):
807
yield self.element_class(self, x)
808
809
def _list_iter(self, n):
810
"""
811
Fast iterator which returns Gelfand-Tsetlin patterns of width ``n`` as
812
lists of lists.
813
814
EXAMPLES::
815
816
sage: G = GelfandTsetlinPatterns(3, 1)
817
sage: L = [x for x in G._list_iter(3)]
818
sage: len(L) == G.cardinality()
819
True
820
sage: type(L[0])
821
<type 'list'>
822
"""
823
# Setup the first row
824
iters = [None]*n
825
ret = [None]*n
826
iters[0] = self._top_row_iter(n)
827
ret[0] = iters[0].next()
828
min_pos = 0
829
iters[1] = self._row_iter(ret[0])
830
pos = 1
831
while pos >= min_pos:
832
try:
833
ret[pos] = iters[pos].next()
834
pos += 1
835
# If we've reached 0 width, yield and backstep
836
if pos == n:
837
yield ret[:]
838
pos -= 1
839
continue
840
iters[pos] = self._row_iter(ret[pos-1])
841
except StopIteration:
842
pos -= 1
843
844
def _top_row_iter(self, n):
845
"""
846
Helper iterator for the top row.
847
848
EXAMPLES::
849
850
sage: G = GelfandTsetlinPatterns(3, 1)
851
sage: for x in G._top_row_iter(3): x
852
[0, 0, 0]
853
[1, 0, 0]
854
[1, 1, 0]
855
[1, 1, 1]
856
sage: G = GelfandTsetlinPatterns(3, 2, strict=True)
857
sage: for x in G._top_row_iter(3): x
858
[2, 1, 0]
859
"""
860
row = [-1]*n
861
pos = 0
862
while pos >= 0:
863
if pos == n:
864
yield row[:]
865
pos -= 1
866
continue
867
# If it would create an invalid entry, backstep
868
if ( pos > 0 and (row[pos] >= row[pos-1] \
869
or (self._strict and row[pos] == row[pos-1]-1)) ) \
870
or (self._k is not None and row[pos] >= self._k):
871
row[pos] = -1
872
pos -= 1
873
continue
874
row[pos] += 1
875
pos += 1
876
877
def _row_iter(self, upper_row):
878
"""
879
Helper iterator for any row with a row above it.
880
881
EXAMPLES::
882
883
sage: G = GelfandTsetlinPatterns(3, 4)
884
sage: for x in G._row_iter([4,2,1]): x
885
[2, 1]
886
[2, 2]
887
[3, 1]
888
[3, 2]
889
[4, 1]
890
[4, 2]
891
sage: G = GelfandTsetlinPatterns(3, 2, strict=True)
892
sage: for x in G._row_iter([2, 1, 0]): x
893
[1, 0]
894
[2, 0]
895
[2, 1]
896
"""
897
row = [x-1 for x in upper_row[1:]]
898
row_len = len(row)
899
pos = 0
900
while pos >= 0:
901
if pos == row_len:
902
yield row[:]
903
pos -= 1
904
continue
905
# If it would create an invalid entry, backstep
906
if ( pos > 0 and (row[pos] >= row[pos-1] \
907
or (self._strict and row[pos] == row[pos-1]-1)) ) \
908
or row[pos] >= upper_row[pos] \
909
or (self._k is not None and row[pos] >= self._k):
910
row[pos] = upper_row[pos+1] - 1
911
pos -= 1
912
continue
913
row[pos] += 1
914
pos += 1
915
916
class GelfandTsetlinPatternsTopRow(GelfandTsetlinPatterns):
917
"""
918
Gelfand-Tsetlin patterns with a fixed top row.
919
"""
920
def __init__(self, top_row, strict):
921
"""
922
Initialize ``self``.
923
924
EXAMPLES::
925
926
sage: G = GelfandTsetlinPatterns(top_row=[4,4,3,1])
927
sage: TestSuite(G).run()
928
929
TESTS:
930
931
Check a border case in :trac:`14765`::
932
933
sage: G = GelfandTsetlinPatterns(top_row=[])
934
sage: list(G)
935
[[]]
936
"""
937
self._row = top_row
938
n = len(top_row)
939
if n == 0:
940
k = 0
941
else:
942
k = top_row[0]
943
GelfandTsetlinPatterns.__init__(self, n, k, strict)
944
945
def _repr_(self):
946
"""
947
Return a string representation of ``self``.
948
949
EXAMPLES::
950
951
sage: GelfandTsetlinPatterns(top_row=[4,4,3,1])
952
Gelfand-Tsetlin patterns with top row [4, 4, 3, 1]
953
sage: GelfandTsetlinPatterns(top_row=[5,4,3,1], strict=True)
954
Strict Gelfand-Tsetlin patterns with top row [5, 4, 3, 1]
955
"""
956
base = "Gelfand-Tsetlin patterns with top row %s"%list(self._row)
957
if self._strict:
958
base = "Strict " + base
959
return base
960
961
def __contains__(self, gt):
962
"""
963
Check if ``gt`` is in ``self``.
964
965
EXAMPLES::
966
967
sage: G = GelfandTsetlinPatterns(top_row=[4,4,1])
968
sage: [[4,4,1], [4,2], [3]] in G
969
True
970
sage: [[4,3,1], [4,2], [3]] in G
971
False
972
"""
973
# Check if the the top row matches (if applicable)
974
if tuple(gt[0]) != self._row:
975
return False
976
return GelfandTsetlinPatterns.__contains__(self, gt)
977
978
def __iter__(self):
979
"""
980
Iterate over ``self``.
981
982
EXAMPLES::
983
984
sage: G = GelfandTsetlinPatterns(top_row=[4,2,1])
985
sage: list(G)
986
[[[4, 2, 1], [2, 1], [1]],
987
[[4, 2, 1], [2, 1], [2]],
988
[[4, 2, 1], [2, 2], [2]],
989
[[4, 2, 1], [3, 1], [1]],
990
[[4, 2, 1], [3, 1], [2]],
991
[[4, 2, 1], [3, 1], [3]],
992
[[4, 2, 1], [3, 2], [2]],
993
[[4, 2, 1], [3, 2], [3]],
994
[[4, 2, 1], [4, 1], [1]],
995
[[4, 2, 1], [4, 1], [2]],
996
[[4, 2, 1], [4, 1], [3]],
997
[[4, 2, 1], [4, 1], [4]],
998
[[4, 2, 1], [4, 2], [2]],
999
[[4, 2, 1], [4, 2], [3]],
1000
[[4, 2, 1], [4, 2], [4]]]
1001
"""
1002
# If we enforce strictness, check to see if a specified top row is strict
1003
if self._strict and any(self._row[i] == self._row[i+1] for i in range(self._n-1)):
1004
return
1005
if self._n == 0:
1006
yield self.element_class(self, [])
1007
return
1008
if self._n == 1:
1009
yield self.element_class(self, [list(self._row)])
1010
return
1011
# Setup the first row
1012
iters = [None]*self._n
1013
ret = [None]*self._n
1014
ret[0] = list(self._row)
1015
min_pos = 1
1016
iters[1] = self._row_iter(ret[0])
1017
pos = 1
1018
while pos >= min_pos:
1019
try:
1020
ret[pos] = iters[pos].next()
1021
pos += 1
1022
# If we've reached 0 width, yield and backstep
1023
if pos == self._n:
1024
yield self.element_class(self, ret[:])
1025
pos -= 1
1026
continue
1027
iters[pos] = self._row_iter(ret[pos-1])
1028
except StopIteration:
1029
pos -= 1
1030
1031
def top_row(self):
1032
"""
1033
Return the top row of ``self``.
1034
1035
EXAMPLES::
1036
1037
sage: G = GelfandTsetlinPatterns(top_row=[4,4,3,1])
1038
sage: G.top_row()
1039
(4, 4, 3, 1)
1040
"""
1041
return self._row
1042
1043
def Tokuyama_formula(self, name='t'):
1044
r"""
1045
Return the Tokuyama formula of ``self``.
1046
1047
Following the exposition of [BBF]_, Tokuyama's formula asserts
1048
1049
.. MATH::
1050
1051
\sum_{G} (t+1)^{s(G)} t^{l(G)}
1052
z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2}
1053
= s_{\lambda} (z_1, \ldots, z_{n+1}) \prod_{i<j} (z_j+tz_i),
1054
1055
where the sum is over all strict Gelfand-Tsetlin patterns with fixed
1056
top row `\lambda+\rho`, with `\lambda` a partition with at most
1057
`n+1` parts and `\rho = (n,n-1,\dots,1,0)`, and `s_{\lambda}` is a Schur
1058
function.
1059
1060
INPUT:
1061
1062
- ``name`` -- (Default: ``'t'``) An alternative name for the
1063
variable `t`.
1064
1065
EXAMPLES::
1066
1067
sage: GT = GelfandTsetlinPatterns(top_row=[2,1,0],strict=True)
1068
sage: GT.Tokuyama_formula()
1069
t^3*x1^2*x2 + t^2*x1*x2^2 + t^2*x1^2*x3 + t^2*x1*x2*x3 + t*x1*x2*x3 + t*x2^2*x3 + t*x1*x3^2 + x2*x3^2
1070
sage: GT = GelfandTsetlinPatterns(top_row=[3,2,1],strict=True)
1071
sage: GT.Tokuyama_formula()
1072
t^3*x1^3*x2^2*x3 + t^2*x1^2*x2^3*x3 + t^2*x1^3*x2*x3^2 + t^2*x1^2*x2^2*x3^2 + t*x1^2*x2^2*x3^2 + t*x1*x2^3*x3^2 + t*x1^2*x2*x3^3 + x1*x2^2*x3^3
1073
sage: GT = GelfandTsetlinPatterns(top_row=[1,1,1],strict=True)
1074
sage: GT.Tokuyama_formula()
1075
0
1076
"""
1077
n = self._n
1078
variables = [name] + ["x%d"%i for i in range(1,n+1)]
1079
R = PolynomialRing(ZZ,names=variables)
1080
t = R.gen(0)
1081
x = R.gens()[1:]
1082
GT = GelfandTsetlinPatterns(top_row=self._row, strict=True)
1083
return sum((t+1)**(gt.number_of_special_entries()) * t**(gt.number_of_boxes()) * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT)
1084
1085