Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/core.py
8815 views
1
"""
2
Cores
3
4
A `k`-core is a partition from which no rim hook of size `k` can be removed.
5
Alternatively, a `k`-core is an integer partition such that the Ferrers
6
diagram for the partition contains no cells with a hook of size (a
7
multiple of) `k`.
8
9
Authors:
10
11
- Anne Schilling and Mike Zabrocki (2011): initial version
12
- Travis Scrimshaw (2012): Added latex output for Core class
13
"""
14
#*****************************************************************************
15
# Copyright (C) 2011 Anne Schilling <anne at math.ucdavis.edu>
16
# Mike Zabrocki <zabrocki at mathstat.yorku.ca>
17
#
18
# Distributed under the terms of the GNU General Public License (GPL)
19
#
20
# This code is distributed in the hope that it will be useful,
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23
# General Public License for more details.
24
#
25
# The full text of the GPL is available at:
26
#
27
# http://www.gnu.org/licenses/
28
#****************************************************************************
29
30
from sage.misc.classcall_metaclass import ClasscallMetaclass
31
from sage.structure.unique_representation import UniqueRepresentation
32
from sage.structure.parent import Parent
33
from sage.structure.element import Element
34
from sage.combinat.partition import Partitions, Partition
35
from sage.combinat.combinat import CombinatorialObject
36
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
37
from sage.functions.other import floor
38
from sage.combinat.combinatorial_map import combinatorial_map
39
40
class Core(CombinatorialObject, Element):
41
r"""
42
A `k`-core is an integer partition from which no rim hook of size `k`
43
can be removed.
44
45
EXAMPLES::
46
47
sage: c = Core([2,1],4); c
48
[2, 1]
49
sage: c = Core([3,1],4); c
50
Traceback (most recent call last):
51
...
52
ValueError: [3, 1] is not a 4-core
53
"""
54
55
__metaclass__ = ClasscallMetaclass
56
57
@staticmethod
58
def __classcall_private__(cls, part, k):
59
r"""
60
Implements the shortcut ``Core(part, k)`` to ``Cores(k,l)(part)``
61
where `l` is the length of the core.
62
63
TESTS::
64
65
sage: c = Core([2,1],4); c
66
[2, 1]
67
sage: c.parent()
68
4-Cores of length 3
69
sage: type(c)
70
<class 'sage.combinat.core.Cores_length_with_category.element_class'>
71
72
sage: Core([2,1],3)
73
Traceback (most recent call last):
74
...
75
ValueError: [2, 1] is not a 3-core
76
"""
77
if isinstance(part, cls):
78
return part
79
part = Partition(part)
80
if not part.is_core(k):
81
raise ValueError("%s is not a %s-core"%(part, k))
82
l = sum(part.k_boundary(k).row_lengths())
83
return Cores(k, l)(part)
84
85
def __init__(self, parent, core):
86
"""
87
TESTS::
88
89
sage: C = Cores(4,3)
90
sage: c = C([2,1]); c
91
[2, 1]
92
sage: type(c)
93
<class 'sage.combinat.core.Cores_length_with_category.element_class'>
94
sage: c.parent()
95
4-Cores of length 3
96
sage: TestSuite(c).run()
97
98
sage: C = Cores(3,3)
99
sage: C([2,1])
100
Traceback (most recent call last):
101
...
102
ValueError: [2, 1] is not a 3-core
103
"""
104
k = parent.k
105
part = Partition(core)
106
if not part.is_core(k):
107
raise ValueError("%s is not a %s-core"%(part, k))
108
CombinatorialObject.__init__(self, core)
109
Element.__init__(self, parent)
110
111
def _latex_(self):
112
"""
113
Outputs the LaTeX representation of this core as a partition. See the
114
``_latex_()`` method of :class:`Partition`.
115
116
EXAMPLES::
117
118
sage: c = Core([2,1],4)
119
sage: latex(c)
120
{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
121
\raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
122
\lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
123
\lr{\phantom{x}}\\\cline{1-1}
124
\end{array}$}
125
}
126
"""
127
return self.to_partition()._latex_()
128
129
def k(self):
130
r"""
131
Returns `k` of the `k`-core ``self``.
132
133
EXAMPLES::
134
135
sage: c = Core([2,1],4)
136
sage: c.k()
137
4
138
"""
139
return self.parent().k
140
141
@combinatorial_map(name="to partition")
142
def to_partition(self):
143
r"""
144
Turns the core ``self`` into the partition identical to ``self``.
145
146
EXAMPLES::
147
148
sage: mu = Core([2,1,1],3)
149
sage: mu.to_partition()
150
[2, 1, 1]
151
"""
152
return Partition(self)
153
154
@combinatorial_map(name="to bounded partition")
155
def to_bounded_partition(self):
156
r"""
157
Bijection between `k`-cores and `(k-1)`-bounded partitions.
158
159
Maps the `k`-core ``self`` to the corresponding `(k-1)`-bounded partition.
160
This bijection is achieved by deleting all cells in ``self`` of hook length
161
greater than `k`.
162
163
EXAMPLES::
164
165
sage: gamma = Core([9,5,3,2,1,1], 5)
166
sage: gamma.to_bounded_partition()
167
[4, 3, 2, 2, 1, 1]
168
"""
169
k_boundary = self.to_partition().k_boundary(self.k())
170
return Partition(k_boundary.row_lengths())
171
172
def size(self):
173
r"""
174
Returns the size of ``self`` as a partition.
175
176
EXAMPLES::
177
178
sage: Core([2,1],4).size()
179
3
180
sage: Core([4,2],3).size()
181
6
182
"""
183
return self.to_partition().size()
184
185
def length(self):
186
r"""
187
Returns the length of ``self``.
188
189
The length of a `k`-core is the size of the corresponding `(k-1)`-bounded partition
190
which agrees with the length of the corresponding Grassmannian element,
191
see :meth:`to_grassmannian`.
192
193
EXAMPLES::
194
195
sage: c = Core([4,2],3); c.length()
196
4
197
sage: c.to_grassmannian().length()
198
4
199
200
sage: Core([9,5,3,2,1,1], 5).length()
201
13
202
"""
203
return self.to_bounded_partition().size()
204
205
def to_grassmannian(self):
206
r"""
207
Bijection between `k`-cores and Grassmannian elements in the affine Weyl group of type `A_{k-1}^{(1)}`.
208
209
For further details, see the documentation of the method
210
:meth:`~sage.combinat.partition.Partition.from_kbounded_to_reduced_word` and
211
:meth:`~sage.combinat.partition.Partition.from_kbounded_to_grassmannian`.
212
213
EXAMPLES::
214
215
sage: c = Core([3,1,1],3)
216
sage: w = c.to_grassmannian(); w
217
[-1 1 1]
218
[-2 2 1]
219
[-2 1 2]
220
sage: c.parent()
221
3-Cores of length 4
222
sage: w.parent()
223
Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root space)
224
225
sage: c = Core([],3)
226
sage: c.to_grassmannian()
227
[1 0 0]
228
[0 1 0]
229
[0 0 1]
230
"""
231
return self.to_bounded_partition().from_kbounded_to_grassmannian(self.k()-1)
232
233
def affine_symmetric_group_simple_action(self, i):
234
r"""
235
Returns the action of the simple transposition `s_i` of the affine symmetric group on ``self``.
236
237
This gives the action of the affine symmetric group of type `A_k^{(1)}` on the `k`-core
238
``self``. If ``self`` has outside (resp. inside) corners of content `i` modulo `k`, then
239
these corners are added (resp. removed). Otherwise the action is trivial.
240
241
EXAMPLES::
242
243
sage: c = Core([4,2],3)
244
sage: c.affine_symmetric_group_simple_action(0)
245
[3, 1]
246
sage: c.affine_symmetric_group_simple_action(1)
247
[5, 3, 1]
248
sage: c.affine_symmetric_group_simple_action(2)
249
[4, 2]
250
251
This action corresponds to the left action by the `i`-th simple reflection in the affine
252
symmetric group::
253
254
sage: c = Core([4,2],3)
255
sage: W = c.to_grassmannian().parent()
256
sage: i=0
257
sage: c.affine_symmetric_group_simple_action(i).to_grassmannian() == W.simple_reflection(i)*c.to_grassmannian()
258
True
259
sage: i=1
260
sage: c.affine_symmetric_group_simple_action(i).to_grassmannian() == W.simple_reflection(i)*c.to_grassmannian()
261
True
262
"""
263
mu = self.to_partition()
264
corners = mu.outside_corners()
265
corners = [ p for p in corners if mu.content(p[0],p[1])%self.k()==i ]
266
if corners == []:
267
corners = mu.corners()
268
corners = [ p for p in corners if mu.content(p[0],p[1])%self.k()==i ]
269
if corners == []:
270
return self
271
for p in corners:
272
mu = mu.remove_cell(p[0])
273
else:
274
for p in corners:
275
mu = mu.add_cell(p[0])
276
return Core(mu, self.k())
277
278
def affine_symmetric_group_action(self, w, transposition = False):
279
r"""
280
Returns the (left) action of the affine symmetric group on ``self``.
281
282
INPUT:
283
284
- ``w`` is a tupe of integers `[w_1,\ldots,w_m]` with `0\le w_j<k`.
285
If transposition is set to be True, then `w = [w_0,w_1]` is
286
interpreted as a transposition `t_{w_0, w_1}`
287
(see :meth:`_transposition_to_reduced_word`).
288
289
The output is the (left) action of the product of the corresponding simple transpositions
290
on ``self``, that is `s_{w_1} \cdots s_{w_m}(self)`. See :meth:`affine_symmetric_group_simple_action`.
291
292
EXAMPLES::
293
294
sage: c = Core([4,2],3)
295
sage: c.affine_symmetric_group_action([0,1,0,2,1])
296
[8, 6, 4, 2]
297
sage: c.affine_symmetric_group_action([0,2], transposition=True)
298
[4, 2, 1, 1]
299
300
sage: c = Core([11,8,5,5,3,3,1,1,1],4)
301
sage: c.affine_symmetric_group_action([2,5],transposition=True)
302
[11, 8, 7, 6, 5, 4, 3, 2, 1]
303
"""
304
c = self
305
if transposition:
306
w = self._transposition_to_reduced_word(w)
307
w.reverse()
308
for i in w:
309
c = c.affine_symmetric_group_simple_action(i)
310
return c
311
312
def _transposition_to_reduced_word(self, t):
313
r"""
314
Converts the transposition `t = [r,s]` to a reduced word.
315
316
INPUT:
317
318
- a tuple `[r,s]` such that `r` and `s` are not equivalent mod `k`
319
320
OUTPUT:
321
322
- a list of integers in `\{0,1,\ldots,k-1\}` representing a reduced word for the transposition `t`
323
324
EXAMPLE::
325
326
sage: c = Core([],4)
327
sage: c._transposition_to_reduced_word([2, 5])
328
[2, 3, 0, 3, 2]
329
sage: c._transposition_to_reduced_word([2, 5]) == c._transposition_to_reduced_word([5,2])
330
True
331
sage: c._transposition_to_reduced_word([2, 2])
332
Traceback (most recent call last):
333
...
334
ValueError: t_0 and t_1 cannot be equal mod k
335
336
sage: c = Core([],30)
337
sage: c._transposition_to_reduced_word([4, 12])
338
[4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4]
339
340
sage: c = Core([],3)
341
sage: c._transposition_to_reduced_word([4, 12])
342
[1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 1]
343
"""
344
k = self.k()
345
if (t[0]-t[1])%k == 0:
346
raise ValueError("t_0 and t_1 cannot be equal mod k")
347
if t[0] > t[1]:
348
return self._transposition_to_reduced_word([t[1],t[0]])
349
else:
350
return [i%k for i in range(t[0],t[1]-floor((t[1]-t[0])/k))] + [(t[1]-floor((t[1]-t[0])/k)-2-i)%(k) for i in
351
range(t[1]-floor((t[1]-t[0])/k)-t[0]-1)]
352
353
def weak_le(self, other):
354
r"""
355
Weak order comparison on cores.
356
357
INPUT:
358
359
- ``other`` -- another `k`-core
360
361
OUTPUT: a boolean
362
363
Returns whether ``self`` <= ``other`` in weak order.
364
365
EXAMPLES::
366
367
sage: c = Core([4,2],3)
368
sage: x = Core([5,3,1],3)
369
sage: c.weak_le(x)
370
True
371
sage: c.weak_le([5,3,1])
372
True
373
374
sage: x = Core([4,2,2,1,1],3)
375
sage: c.weak_le(x)
376
False
377
378
sage: x = Core([5,3,1],6)
379
sage: c.weak_le(x)
380
Traceback (most recent call last):
381
...
382
ValueError: The two cores do not have the same k
383
"""
384
if type(self) == type(other):
385
if self.k() != other.k():
386
raise ValueError("The two cores do not have the same k")
387
else:
388
other = Core(other, self.k())
389
w = self.to_grassmannian()
390
v = other.to_grassmannian()
391
return w.weak_le(v, side='left')
392
393
def weak_covers(self):
394
r"""
395
Returns a list of all elements that cover ``self`` in weak order.
396
397
EXAMPLES::
398
399
sage: c = Core([1],3)
400
sage: c.weak_covers()
401
[[2], [1, 1]]
402
403
sage: c = Core([4,2],3)
404
sage: c.weak_covers()
405
[[5, 3, 1]]
406
"""
407
w = self.to_grassmannian()
408
S = w.upper_covers(side='left')
409
S = [x for x in S if x.is_affine_grassmannian()]
410
return [ x.affine_grassmannian_to_core() for x in set(S) ]
411
412
def strong_le(self, other):
413
r"""
414
Strong order (Bruhat) comparison on cores.
415
416
INPUT:
417
418
- ``other`` -- another `k`-core
419
420
OUTPUT: a boolean
421
422
Returns whether ``self`` <= ``other`` in Bruhat (or strong) order.
423
424
EXAMPLES::
425
426
sage: c = Core([4,2],3)
427
sage: x = Core([4,2,2,1,1],3)
428
sage: c.strong_le(x)
429
True
430
sage: c.strong_le([4,2,2,1,1])
431
True
432
433
sage: x = Core([4,1],4)
434
sage: c.strong_le(x)
435
Traceback (most recent call last):
436
...
437
ValueError: The two cores do not have the same k
438
"""
439
if type(self) == type(other):
440
if self.k()!=other.k():
441
raise ValueError("The two cores do not have the same k")
442
else:
443
other = Core(other, self.k())
444
return other.contains(self)
445
446
def contains(self, other):
447
r"""
448
Checks whether ``self`` contains ``other``.
449
450
INPUT:
451
452
- ``other`` -- another `k`-core or a list
453
454
OUTPUT: a boolean
455
456
Returns ``True`` if the Ferrers diagram of ``self`` contains the
457
Ferrers diagram of other.
458
459
EXAMPLES::
460
461
sage: c = Core([4,2],3)
462
sage: x = Core([4,2,2,1,1],3)
463
sage: x.contains(c)
464
True
465
sage: c.contains(x)
466
False
467
"""
468
la = self.to_partition()
469
mu = Core(other, self.k()).to_partition()
470
return la.contains(mu)
471
472
def strong_covers(self):
473
r"""
474
Returns a list of all elements that cover ``self`` in strong order.
475
476
EXAMPLES::
477
478
sage: c = Core([1],3)
479
sage: c.strong_covers()
480
[[2], [1, 1]]
481
sage: c = Core([4,2],3)
482
sage: c.strong_covers()
483
[[5, 3, 1], [4, 2, 1, 1]]
484
"""
485
S = Cores(self.k(), length=self.length()+1)
486
return [ ga for ga in S if ga.contains(self) ]
487
488
def strong_down_list(self):
489
r"""
490
Returns a list of all elements that are covered by ``self`` in strong order.
491
492
EXAMPLES::
493
494
sage: c = Core([1],3)
495
sage: c.strong_down_list()
496
[[]]
497
sage: c = Core([5,3,1],3)
498
sage: c.strong_down_list()
499
[[4, 2], [3, 1, 1]]
500
"""
501
if self==[]:
502
return []
503
return [ga for ga in Cores(self.k(), length=self.length()-1) if self.contains(ga)]
504
505
def Cores(k, length = None, **kwargs):
506
r"""
507
A `k`-core is a partition from which no rim hook of size `k` can be removed.
508
Alternatively, a `k`-core is an integer partition such that the Ferrers
509
diagram for the partition contains no cells with a hook of size (a multiple of) `k`.
510
511
The `k`-cores generally have two notions of size which are
512
useful for different applications. One is the number of cells in the
513
Ferrers diagram with hook less than `k`, the other is the total
514
number of cells of the Ferrers diagram. In the implementation in
515
Sage, the first of notion is referred to as the ``length`` of the `k`-core
516
and the second is the ``size`` of the `k`-core. The class
517
of Cores requires that either the size or the length of the elements in
518
the class is specified.
519
520
EXAMPLES:
521
522
We create the set of the `4`-cores of length `6`. Here the length of a `k`-core is the size
523
of the corresponding `(k-1)`-bounded partition, see also :meth:`~sage.combinat.core.Core.length`::
524
525
sage: C = Cores(4, 6); C
526
4-Cores of length 6
527
sage: C.list()
528
[[6, 3], [5, 2, 1], [4, 1, 1, 1], [4, 2, 2], [3, 3, 1, 1], [3, 2, 1, 1, 1], [2, 2, 2, 1, 1, 1]]
529
sage: C.cardinality()
530
7
531
sage: C.an_element()
532
[6, 3]
533
534
We may also list the set of `4`-cores of size `6`, where the size is the number of boxes in the
535
core, see also :meth:`~sage.combinat.core.Core.size`::
536
537
sage: C = Cores(4, size=6); C
538
4-Cores of size 6
539
sage: C.list()
540
[[4, 1, 1], [3, 2, 1], [3, 1, 1, 1]]
541
sage: C.cardinality()
542
3
543
sage: C.an_element()
544
[4, 1, 1]
545
"""
546
if length is None and 'size' in kwargs:
547
return Cores_size(k,kwargs['size'])
548
elif length is not None:
549
return Cores_length(k,length)
550
else:
551
raise ValueError("You need to either specify the length or size of the cores considered!")
552
553
class Cores_length(UniqueRepresentation, Parent):
554
r"""
555
The class of `k`-cores of length `n`.
556
"""
557
558
def __init__(self, k, n):
559
"""
560
TESTS::
561
562
sage: C = Cores(3, 4)
563
sage: TestSuite(C).run()
564
565
"""
566
self.k = k
567
self.n = n
568
Parent.__init__(self, category = FiniteEnumeratedSets())
569
570
def _repr_(self):
571
"""
572
TESTS::
573
574
sage: repr(Cores(4, 3)) #indirect doctest
575
'4-Cores of length 3'
576
"""
577
return "%s-Cores of length %s"%(self.k,self.n)
578
579
def list(self):
580
r"""
581
Returns the list of all `k`-cores of length `n`.
582
583
EXAMPLES::
584
585
sage: C = Cores(3,4)
586
sage: C.list()
587
[[4, 2], [3, 1, 1], [2, 2, 1, 1]]
588
"""
589
return [la.to_core(self.k-1) for la in Partitions(self.n, max_part=self.k-1)]
590
591
def from_partition(self, part):
592
r"""
593
Converts the partition ``part`` into a core (as the identity map).
594
595
This is the inverse method to :meth:`~sage.combinat.core.Core.to_partition`.
596
597
EXAMPLES::
598
599
sage: C = Cores(3,4)
600
sage: c = C.from_partition([4,2]); c
601
[4, 2]
602
603
sage: mu = Partition([2,1,1])
604
sage: C = Cores(3,3)
605
sage: C.from_partition(mu).to_partition() == mu
606
True
607
608
sage: mu = Partition([])
609
sage: C = Cores(3,0)
610
sage: C.from_partition(mu).to_partition() == mu
611
True
612
"""
613
return Core(part, self.k)
614
615
Element = Core
616
617
618
class Cores_size(UniqueRepresentation, Parent):
619
r"""
620
The class of `k`-cores of size `n`.
621
"""
622
623
def __init__(self, k, n):
624
"""
625
TESTS::
626
627
sage: C = Cores(3, size = 4)
628
sage: TestSuite(C).run()
629
"""
630
self.k = k
631
self.n = n
632
Parent.__init__(self, category = FiniteEnumeratedSets())
633
634
def _repr_(self):
635
"""
636
TESTS::
637
638
sage: repr(Cores(4, size = 3)) #indirect doctest
639
'4-Cores of size 3'
640
"""
641
return "%s-Cores of size %s"%(self.k,self.n)
642
643
def list(self):
644
r"""
645
Returns the list of all `k`-cores of size `n`.
646
647
EXAMPLES::
648
649
sage: C = Cores(3, size = 4)
650
sage: C.list()
651
[[3, 1], [2, 1, 1]]
652
"""
653
k_cores = filter(lambda x: x.is_core(self.k), Partitions(self.n))
654
return [ Core(x, self.k) for x in k_cores ]
655
656
def from_partition(self, part):
657
r"""
658
Converts the partition ``part`` into a core (as the identity map).
659
660
This is the inverse method to :meth:`to_partition`.
661
662
EXAMPLES::
663
664
sage: C = Cores(3,size=4)
665
sage: c = C.from_partition([2,1,1]); c
666
[2, 1, 1]
667
668
sage: mu = Partition([2,1,1])
669
sage: C = Cores(3,size=4)
670
sage: C.from_partition(mu).to_partition() == mu
671
True
672
673
sage: mu = Partition([])
674
sage: C = Cores(3,size=0)
675
sage: C.from_partition(mu).to_partition() == mu
676
True
677
"""
678
return Core(part, self.k)
679
680
Element = Core
681
682