Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/partition.py
4056 views
1
r"""
2
Partitions
3
4
A partition `p` of a nonnegative integer `n` is a
5
non-increasing list of positive integers (the *parts* of the
6
partition) with total sum `n`.
7
8
A partition can be depicted by a diagram made of rows of cells,
9
where the number of cells in the `i^{th}` row starting from
10
the top is the `i^{th}` part of the partition.
11
12
The coordinate system related to a partition applies from the top
13
to the bottom and from left to right. So, the corners of the
14
partition are [[0,4], [1,2], [2,0]].
15
16
AUTHORS:
17
18
- Mike Hansen (2007): initial version
19
20
- Dan Drake (2009-03-28): deprecate RestrictedPartitions and implement
21
Partitions_parts_in
22
23
- Travis Scrimshaw (2012-01-12): Implemented latex function to Partition_class
24
- Travis Scrimshaw (2012-05-09): Fixed Partitions(-1).list() infinite recursion
25
loop by saying Partitions_n is the empty set.
26
27
EXAMPLES:
28
29
There are 5 partitions of the integer 4::
30
31
sage: Partitions(4).cardinality()
32
5
33
sage: Partitions(4).list()
34
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
35
36
We can use the method .first() to get the 'first' partition of a
37
number::
38
39
sage: Partitions(4).first()
40
[4]
41
42
Using the method .next(), we can calculate the 'next' partition.
43
When we are at the last partition, None will be returned::
44
45
sage: Partitions(4).next([4])
46
[3, 1]
47
sage: Partitions(4).next([1,1,1,1]) is None
48
True
49
50
We can use ``iter`` to get an object which iterates over the partitions one
51
by one to save memory. Note that when we do something like
52
``for part in Partitions(4)`` this iterator is used in the background::
53
54
sage: g = iter(Partitions(4))
55
56
::
57
58
sage: g.next()
59
[4]
60
sage: g.next()
61
[3, 1]
62
sage: g.next()
63
[2, 2]
64
sage: for p in Partitions(4): print p
65
[4]
66
[3, 1]
67
[2, 2]
68
[2, 1, 1]
69
[1, 1, 1, 1]
70
71
We can add constraints to to the type of partitions we want. For
72
example, to get all of the partitions of 4 of length 2, we'd do the
73
following::
74
75
sage: Partitions(4, length=2).list()
76
[[3, 1], [2, 2]]
77
78
Here is the list of partitions of length at least 2 and the list of
79
ones with length at most 2::
80
81
sage: Partitions(4, min_length=2).list()
82
[[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
83
sage: Partitions(4, max_length=2).list()
84
[[4], [3, 1], [2, 2]]
85
86
The options min_part and max_part can be used to set constraints
87
on the sizes of all parts. Using max_part, we can select
88
partitions having only 'small' entries. The following is the list
89
of the partitions of 4 with parts at most 2::
90
91
sage: Partitions(4, max_part=2).list()
92
[[2, 2], [2, 1, 1], [1, 1, 1, 1]]
93
94
The min_part options is complementary to max_part and selects
95
partitions having only 'large' parts. Here is the list of all
96
partitions of 4 with each part at least 2::
97
98
sage: Partitions(4, min_part=2).list()
99
[[4], [2, 2]]
100
101
The options inner and outer can be used to set part-by-part
102
constraints. This is the list of partitions of 4 with [3, 1, 1] as
103
an outer bound::
104
105
sage: Partitions(4, outer=[3,1,1]).list()
106
[[3, 1], [2, 1, 1]]
107
108
Outer sets max_length to the length of its argument. Moreover, the
109
parts of outer may be infinite to clear constraints on specific
110
parts. Here is the list of the partitions of 4 of length at most 3
111
such that the second and third part are 1 when they exist::
112
113
sage: Partitions(4, outer=[oo,1,1]).list()
114
[[4], [3, 1], [2, 1, 1]]
115
116
Finally, here are the partitions of 4 with [1,1,1] as an inner
117
bound. Note that inner sets min_length to the length of its
118
argument::
119
120
sage: Partitions(4, inner=[1,1,1]).list()
121
[[2, 1, 1], [1, 1, 1, 1]]
122
123
The options min_slope and max_slope can be used to set
124
constraints on the slope, that is on the difference p[i+1]-p[i] of
125
two consecutive parts. Here is the list of the strictly decreasing
126
partitions of 4::
127
128
sage: Partitions(4, max_slope=-1).list()
129
[[4], [3, 1]]
130
131
The constraints can be combined together in all reasonable ways.
132
Here are all the partitions of 11 of length between 2 and 4 such
133
that the difference between two consecutive parts is between -3 and
134
-1::
135
136
sage: Partitions(11,min_slope=-3,max_slope=-1,min_length=2,max_length=4).list()
137
[[7, 4], [6, 5], [6, 4, 1], [6, 3, 2], [5, 4, 2], [5, 3, 2, 1]]
138
139
Partition objects can also be created individually with the
140
Partition function::
141
142
sage: Partition([2,1])
143
[2, 1]
144
145
Once we have a partition object, then there are a variety of
146
methods that we can use. For example, we can get the conjugate of a
147
partition. Geometrically, the conjugate of a partition is the
148
reflection of that partition through its main diagonal. Of course,
149
this operation is an involution::
150
151
sage: Partition([4,1]).conjugate()
152
[2, 1, 1, 1]
153
sage: Partition([4,1]).conjugate().conjugate()
154
[4, 1]
155
156
If we create a partition with extra zeros at the end, they will be dropped::
157
158
sage: Partition([4,1,0,0])
159
[4, 1]
160
161
The idea of a partition being followed by infinitely many parts of size `0` is
162
consistent with the ``get_part`` method::
163
164
sage: p = Partition([5, 2])
165
sage: p.get_part(0)
166
5
167
sage: p.get_part(10)
168
0
169
170
We can go back and forth between the exponential notations of a
171
partition. The exponential notation can be padded with extra
172
zeros::
173
174
sage: Partition([6,4,4,2,1]).to_exp()
175
[1, 1, 0, 2, 0, 1]
176
sage: Partition(exp=[1,1,0,2,0,1])
177
[6, 4, 4, 2, 1]
178
sage: Partition([6,4,4,2,1]).to_exp(5)
179
[1, 1, 0, 2, 0, 1]
180
sage: Partition([6,4,4,2,1]).to_exp(7)
181
[1, 1, 0, 2, 0, 1, 0]
182
sage: Partition([6,4,4,2,1]).to_exp(10)
183
[1, 1, 0, 2, 0, 1, 0, 0, 0, 0]
184
185
We can get the coordinates of the corners of a partition::
186
187
sage: Partition([4,3,1]).corners()
188
[(0, 3), (1, 2), (2, 0)]
189
190
We can compute the core and quotient of a partition and build
191
the partition back up from them::
192
193
sage: Partition([6,3,2,2]).core(3)
194
[2, 1, 1]
195
sage: Partition([7,7,5,3,3,3,1]).quotient(3)
196
([2], [1], [2, 2, 2])
197
sage: p = Partition([11,5,5,3,2,2,2])
198
sage: p.core(3)
199
[]
200
sage: p.quotient(3)
201
([2, 1], [4], [1, 1, 1])
202
sage: Partition(core=[],quotient=([2, 1], [4], [1, 1, 1]))
203
[11, 5, 5, 3, 2, 2, 2]
204
205
We can compute the Frobenius coordinates (or beta numbers), and go back
206
and forth::
207
208
sage: Partition([7,3,1]).frobenius_coordinates()
209
([6, 1], [2, 0])
210
sage: Partition(frobenius_coordinates=([6,1],[2,0]))
211
[7, 3, 1]
212
sage: all(mu == Partition(frobenius_coordinates=mu.frobenius_coordinates()) for n in range(30)\
213
for mu in Partitions(n))
214
True
215
216
"""
217
#*****************************************************************************
218
# Copyright (C) 2007 Mike Hansen <[email protected]>,
219
#
220
# Distributed under the terms of the GNU General Public License (GPL)
221
# http://www.gnu.org/licenses/
222
#*****************************************************************************
223
224
from sage.interfaces.all import gap, gp
225
from sage.rings.all import QQ, ZZ, infinity, factorial, gcd
226
from sage.misc.all import prod
227
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
228
import sage.combinat.misc as misc
229
import sage.combinat.skew_partition
230
from sage.rings.integer import Integer
231
import __builtin__
232
from combinat import CombinatorialClass, CombinatorialObject, cyclic_permutations_iterator, InfiniteAbstractCombinatorialClass
233
import partitions as partitions_ext
234
from sage.libs.all import pari
235
import tableau
236
import permutation
237
import composition
238
from integer_vector import IntegerVectors
239
from cartesian_product import CartesianProduct
240
from integer_list import IntegerListsLex
241
from sage.misc.misc import deprecation, deprecated_function_alias
242
from sage.misc.prandom import randrange
243
244
def Partition(mu=None, **keyword):
245
"""
246
A partition is a weakly decreasing ordered sequence of non-negative
247
integers. This function returns a Sage partition object which can
248
be specified in one of the following ways::
249
250
* a list (the default)
251
* using exponential notation
252
* by Frobenius coordinates (also called beta numbers)
253
* specifying the core and the quotient
254
* specifying the core and the canonical quotient (TODO)
255
256
See the examples below.
257
258
Sage follows the usual python conventions when dealing with partitions,
259
so that the first part of the partition ``mu=Partition([4,3,2,2])`` is
260
``mu[0]``, the second part is ``mu[1]`` and so on. As is usual, Sage ignores
261
trailing zeros at the end of partitions.
262
263
EXAMPLES::
264
265
sage: Partition([3,2,1])
266
[3, 2, 1]
267
sage: Partition([3,2,1,0])
268
[3, 2, 1]
269
sage: Partition(exp=[2,1,1])
270
[3, 2, 1, 1]
271
sage: Partition(core=[2,1], quotient=[[2,1],[3],[1,1,1]])
272
[11, 5, 5, 3, 2, 2, 2]
273
sage: Partition(frobenius_coordinates=([3,2],[4,0]))
274
[4, 4, 1, 1, 1]
275
sage: [2,1] in Partitions()
276
True
277
sage: [2,1,0] in Partitions()
278
False
279
sage: Partition([1,2,3])
280
Traceback (most recent call last):
281
...
282
ValueError: [1, 2, 3] is not a valid partition
283
"""
284
if mu is not None and len(keyword)==0:
285
mu = [i for i in mu if i != 0]
286
if mu in Partitions_all():
287
return Partition_class(mu)
288
else:
289
raise ValueError, "%s is not a valid partition"%mu
290
elif 'frobenius_coordinates' in keyword and len(keyword)==1:
291
return from_frobenius_coordinates(keyword['frobenius_coordinates'])
292
elif 'exp' in keyword and len(keyword)==1:
293
return from_exp(keyword['exp'])
294
elif 'core' in keyword and 'quotient' in keyword and len(keyword)==2:
295
return from_core_and_quotient(keyword['core'], keyword['quotient'])
296
elif 'core' in keyword and 'canonical_quotient' in keyword and len(keyword)==2:
297
raise NotImplementedError
298
elif 'core_and_quotient' in keyword and len(keyword)==1:
299
deprecation('"core_and_quotient=(*)" is deprecated. Use "core=[*], quotient=[*]" instead.')
300
return from_core_and_quotient(*keyword['core_and_quotient'])
301
else:
302
raise ValueError, 'incorrect syntax for Partition()'
303
304
def from_frobenius_coordinates(frobenius_coordinates):
305
"""
306
Returns a partition from a couple of sequences of Frobenius coordinates
307
308
.. note::
309
310
This function is for internal use only;
311
use Partition(frobenius_coordinates=*) instead.
312
313
EXAMPLES::
314
315
sage: Partition(frobenius_coordinates=([],[]))
316
[]
317
sage: Partition(frobenius_coordinates=([0],[0]))
318
[1]
319
sage: Partition(frobenius_coordinates=([1],[1]))
320
[2, 1]
321
sage: Partition(frobenius_coordinates=([6,3,2],[4,1,0]))
322
[7, 5, 5, 1, 1]
323
"""
324
if len(frobenius_coordinates) <> 2:
325
raise ValueError, '%s is not a valid partition, two sequences of coordinates are needed'%str(frobenius_coordinates)
326
else:
327
a = frobenius_coordinates[0]
328
b = frobenius_coordinates[1]
329
if len(a) <> len(b):
330
raise ValueError, '%s is not a valid partition, the sequences of coordinates need to be the same length'%str(frobenius_coordinates)
331
# should add tests to see if a and b are sorted down, nonnegative and strictly decreasing
332
r = len(a)
333
if r == 0:
334
return Partition([])
335
tmp = [a[i]+i+1 for i in range(r)]
336
# should check that a is strictly decreasing
337
if a[-1] < 0:
338
raise ValueError, '%s is not a partition, no coordinate can be negative'%str(frobenius_coordinates)
339
if b[-1] >= 0:
340
tmp.extend([r]*b[r-1])
341
else:
342
raise ValueError, '%s is not a partition, no coordinate can be negative'%str(frobenius_coordinates)
343
for i in xrange(r-1,0,-1):
344
if b[i-1]-b[i] > 0:
345
tmp.extend([i]*(b[i-1]-b[i]-1))
346
else:
347
raise ValueError, '%s is not a partition, the coordinates need to be strictly decreasing'%str(frobenius_coordinates)
348
return Partition(tmp)
349
350
def from_exp(exp):
351
"""
352
Returns a partition from its list of multiplicities.
353
354
.. note::
355
356
This function is for internal use only;
357
use Partition(exp=*) instead.
358
359
EXAMPLES::
360
361
sage: Partition(exp=[1,2,1])
362
[3, 2, 2, 1]
363
"""
364
p = []
365
for i in reversed(range(len(exp))):
366
p += [i+1]*exp[i]
367
return Partition(p)
368
369
def from_core_and_quotient(core, quotient):
370
"""
371
** This function is being deprecated - use Partition(core=*, quotient=*) instead **
372
373
Returns a partition from its core and quotient.
374
375
Algorithm from mupad-combinat.
376
377
.. note::
378
379
This function is for internal use only;
380
use Partition(core=*, quotient=*) instead.
381
382
EXAMPLES::
383
384
sage: Partition(core=[2,1], quotient=[[2,1],[3],[1,1,1]])
385
[11, 5, 5, 3, 2, 2, 2]
386
387
TESTS:
388
389
We check that #11412 is actually fixed::
390
391
sage: test = lambda x, k: x == Partition(core=x.core(k),
392
... quotient=x.quotient(k))
393
sage: all(test(mu,k) for k in range(1,5)
394
... for n in range(10) for mu in Partitions(n))
395
True
396
sage: test2 = lambda core, mus: (
397
... Partition(core=core, quotient=mus).core(len(mus)) == core
398
... and
399
... Partition(core=core, quotient=mus).quotient(len(mus)) == mus)
400
sage: all(test2(core,tuple(mus)) # long time (5s on sage.math, 2011)
401
... for k in range(1,10)
402
... for n_core in range(10-k)
403
... for core in Partitions(n_core)
404
... if core.core(k) == core
405
... for n_mus in range(10-k)
406
... for mus in PartitionTuples(n_mus,k))
407
True
408
"""
409
length = len(quotient)
410
k = length*max(len(q) for q in quotient) + len(core)
411
# k needs to be large enough. this seems to me like the smallest it can be
412
v = [core[i]-i for i in range(len(core))] + [ -i for i in range(len(core),k) ]
413
w = [ filter(lambda x: (x-i) % length == 0, v) for i in range(1, length+1) ]
414
new_w = []
415
for i in range(length):
416
lw = len(w[i])
417
lq = len(quotient[i])
418
# k needs to be chosen so lw >= lq
419
new_w += [ w[i][j] + length*quotient[i][j] for j in range(lq)]
420
new_w += [ w[i][j] for j in range(lq,lw)]
421
new_w.sort(reverse=True)
422
return Partition([new_w[i]+i for i in range(len(new_w))])
423
424
class Partition_class(CombinatorialObject):
425
426
def _latex_(self):
427
r"""
428
Returns a LaTeX version of self.
429
430
EXAMPLES::
431
432
sage: latex(Partition([2, 1]))
433
{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
434
\raisebox{-.6ex}{$\begin{array}[b]{cc}
435
\cline{1-1}\cline{2-2}
436
\lr{\phantom{x}}&\lr{\phantom{x}}\\
437
\cline{1-1}\cline{2-2}
438
\lr{\phantom{x}}\\
439
\cline{1-1}
440
\end{array}$}
441
}
442
"""
443
if len(self._list) == 0:
444
return "{\\emptyset}"
445
446
from sage.combinat.output import tex_from_array
447
return tex_from_array([ ["\\phantom{x}"]*row_size for row_size in self._list ])
448
449
def ferrers_diagram(self):
450
"""
451
Return the Ferrers diagram of pi.
452
453
INPUT:
454
455
- ``pi`` - a partition, given as a list of integers.
456
457
458
EXAMPLES::
459
460
sage: print Partition([5,5,2,1]).ferrers_diagram()
461
*****
462
*****
463
**
464
*
465
"""
466
return '\n'.join(['*'*p for p in self])
467
468
def pp(self):
469
"""
470
EXAMPLES::
471
472
sage: Partition([5,5,2,1]).pp()
473
*****
474
*****
475
**
476
*
477
"""
478
print self.ferrers_diagram()
479
480
def __div__(self, p):
481
"""
482
Returns the skew partition self/p.
483
484
EXAMPLES::
485
486
sage: p = Partition([3,2,1])
487
sage: p/[1,1]
488
[[3, 2, 1], [1, 1]]
489
sage: p/[3,2,1]
490
[[3, 2, 1], [3, 2, 1]]
491
sage: p/Partition([1,1])
492
[[3, 2, 1], [1, 1]]
493
"""
494
if not self.dominates(p):
495
raise ValueError, "the partition must dominate p"
496
497
return sage.combinat.skew_partition.SkewPartition([self[:], p])
498
499
def power(self, k):
500
"""
501
Returns the cycle type of the `k`-th power of any permutation
502
with cycle type ``self`` (thus describes the powermap of
503
symmetric groups).
504
505
Wraps GAP's PowerPartition.
506
507
EXAMPLES::
508
509
sage: p = Partition([5,3])
510
sage: p.power(1)
511
[5, 3]
512
sage: p.power(2)
513
[5, 3]
514
sage: p.power(3)
515
[5, 1, 1, 1]
516
sage: p.power(4)
517
[5, 3]
518
sage: Partition([3,2,1]).power(3)
519
[2, 1, 1, 1, 1]
520
521
Now let us compare this to the power map on `S_8`::
522
523
sage: G = SymmetricGroup(8)
524
sage: g = G([(1,2,3,4,5),(6,7,8)])
525
sage: g
526
(1,2,3,4,5)(6,7,8)
527
sage: g^2
528
(1,3,5,2,4)(6,8,7)
529
sage: g^3
530
(1,4,2,5,3)
531
sage: g^4
532
(1,5,4,3,2)(6,7,8)
533
"""
534
res = []
535
for i in self:
536
g = gcd(i, k)
537
res.extend( [ZZ(i//g)]*int(g) )
538
res.sort(reverse=True)
539
return Partition_class( res )
540
541
def next(self):
542
"""
543
Returns the partition that lexicographically follows the partition
544
p. If p is the last partition, then it returns False.
545
546
EXAMPLES::
547
548
sage: Partition([4]).next()
549
[3, 1]
550
sage: Partition([1,1,1,1]).next()
551
False
552
"""
553
p = self
554
n = 0
555
m = 0
556
for i in p:
557
n += i
558
m += 1
559
560
next_p = p[:] + [1]*(n - len(p))
561
562
#Check to see if we are at the last (all ones) partition
563
if p == [1]*n:
564
return False
565
566
#
567
#If we are not, then run the ZS1 algorithm.
568
#
569
570
#Let h be the number of non-one entries in the
571
#partition
572
h = 0
573
for i in next_p:
574
if i != 1:
575
h += 1
576
577
if next_p[h-1] == 2:
578
m += 1
579
next_p[h-1] = 1
580
h -= 1
581
else:
582
r = next_p[h-1] - 1
583
t = m - h + 1
584
next_p[h-1] = r
585
586
while t >= r :
587
h += 1
588
next_p[h-1] = r
589
t -= r
590
591
if t == 0:
592
m = h
593
else:
594
m = h + 1
595
if t > 1:
596
h += 1
597
next_p[h-1] = t
598
599
return Partition_class(next_p[:m])
600
601
def size(self):
602
"""
603
Returns the size of partition p.
604
605
EXAMPLES::
606
607
sage: Partition([2,2]).size()
608
4
609
sage: Partition([3,2,1]).size()
610
6
611
"""
612
return sum(self)
613
614
def sign(self):
615
r"""
616
Returns the sign of any permutation with cycle type ``self``.
617
618
This function corresponds to a homomorphism from the symmetric
619
group `S_n` into the cyclic group of order 2, whose kernel
620
is exactly the alternating group `A_n`. Partitions of sign
621
`1` are called even partitions while partitions of sign
622
`-1` are called odd.
623
624
EXAMPLES::
625
626
sage: Partition([5,3]).sign()
627
1
628
sage: Partition([5,2]).sign()
629
-1
630
631
Zolotarev's lemma states that the Legendre symbol
632
`\left(\frac{a}{p}\right)` for an integer
633
`a \pmod p` (`p` a prime number), can be computed
634
as sign(p_a), where sign denotes the sign of a permutation and
635
p_a the permutation of the residue classes `\pmod p`
636
induced by modular multiplication by `a`, provided
637
`p` does not divide `a`.
638
639
We verify this in some examples.
640
641
::
642
643
sage: F = GF(11)
644
sage: a = F.multiplicative_generator();a
645
2
646
sage: plist = [int(a*F(x)) for x in range(1,11)]; plist
647
[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]
648
649
This corresponds to the permutation (1, 2, 4, 8, 5, 10, 9, 7, 3, 6)
650
(acting the set `\{1,2,...,10\}`) and to the partition
651
[10].
652
653
::
654
655
sage: p = PermutationGroupElement('(1, 2, 4, 8, 5, 10, 9, 7, 3, 6)')
656
sage: p.sign()
657
-1
658
sage: Partition([10]).sign()
659
-1
660
sage: kronecker_symbol(11,2)
661
-1
662
663
Now replace `2` by `3`::
664
665
sage: plist = [int(F(3*x)) for x in range(1,11)]; plist
666
[3, 6, 9, 1, 4, 7, 10, 2, 5, 8]
667
sage: range(1,11)
668
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
669
sage: p = PermutationGroupElement('(3,4,8,7,9)')
670
sage: p.sign()
671
1
672
sage: kronecker_symbol(3,11)
673
1
674
sage: Partition([5,1,1,1,1,1]).sign()
675
1
676
677
In both cases, Zolotarev holds.
678
679
REFERENCES:
680
681
- http://en.wikipedia.org/wiki/Zolotarev's_lemma
682
"""
683
return (-1)**(self.size()-self.length())
684
685
def up(self):
686
r"""
687
Returns a generator for partitions that can be obtained from pi by
688
adding a cell.
689
690
EXAMPLES::
691
692
sage: [p for p in Partition([2,1,1]).up()]
693
[[3, 1, 1], [2, 2, 1], [2, 1, 1, 1]]
694
sage: [p for p in Partition([3,2]).up()]
695
[[4, 2], [3, 3], [3, 2, 1]]
696
sage: [p for p in Partition([]).up()]
697
[[1]]
698
"""
699
p = self
700
previous = p.get_part(0) + 1
701
for i, current in enumerate(p):
702
if current < previous:
703
yield Partition(p[:i] + [ p[i] + 1 ] + p[i+1:])
704
previous = current
705
else:
706
yield Partition(p + [1])
707
708
def up_list(self):
709
"""
710
Returns a list of the partitions that can be formed from the
711
partition `p` by adding a cell.
712
713
EXAMPLES::
714
715
sage: Partition([2,1,1]).up_list()
716
[[3, 1, 1], [2, 2, 1], [2, 1, 1, 1]]
717
sage: Partition([3,2]).up_list()
718
[[4, 2], [3, 3], [3, 2, 1]]
719
sage: Partition([]).up_list()
720
[[1]]
721
"""
722
return [p for p in self.up()]
723
724
def down(self):
725
r"""
726
Returns a generator for partitions that can be obtained from p by
727
removing a cell.
728
729
EXAMPLES::
730
731
sage: [p for p in Partition([2,1,1]).down()]
732
[[1, 1, 1], [2, 1]]
733
sage: [p for p in Partition([3,2]).down()]
734
[[2, 2], [3, 1]]
735
sage: [p for p in Partition([3,2,1]).down()]
736
[[2, 2, 1], [3, 1, 1], [3, 2]]
737
738
TESTS: We check that #11435 is actually fixed::
739
740
sage: Partition([]).down_list() #indirect doctest
741
[]
742
"""
743
p = self
744
l = len(p)
745
for i in range(l-1):
746
if p[i] > p[i+1]:
747
yield Partition(p[:i] + [ p[i]-1 ] + p[i+1:])
748
if l >= 1:
749
last = p[-1]
750
if last == 1:
751
yield Partition(p[:-1])
752
else:
753
yield Partition(p[:-1] + [ p[-1] - 1 ])
754
755
756
def down_list(self):
757
"""
758
Returns a list of the partitions that can be obtained from the
759
partition p by removing a cell.
760
761
EXAMPLES::
762
763
sage: Partition([2,1,1]).down_list()
764
[[1, 1, 1], [2, 1]]
765
sage: Partition([3,2]).down_list()
766
[[2, 2], [3, 1]]
767
sage: Partition([3,2,1]).down_list()
768
[[2, 2, 1], [3, 1, 1], [3, 2]]
769
sage: Partition([]).down_list() #checks trac #11435
770
[]
771
"""
772
return [p for p in self.down()]
773
774
def frobenius_coordinates(self):
775
""" Returns a couple of sequences of beta numbers aka Frobenius coordinates of the partition.
776
These are two striclty decreasing sequences of nonnegative integers, of the same length.
777
778
EXAMPLES::
779
sage: Partition([]).frobenius_coordinates()
780
([], [])
781
sage: Partition([1]).frobenius_coordinates()
782
([0], [0])
783
sage: Partition([3,3,3]).frobenius_coordinates()
784
([2, 1, 0], [2, 1, 0])
785
sage: Partition([9,1,1,1,1,1,1]).frobenius_coordinates()
786
([8], [6])
787
788
"""
789
mu = self
790
muconj = mu.conjugate() # Naive implementation
791
if len(mu) <= len(muconj):
792
a = filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(mu)])
793
b = filter(lambda x: x>=0, [muconj[i]-i-1 for i in range(len(a))])
794
else:
795
b = filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(muconj)])
796
a = filter(lambda x: x>=0, [mu[i]-i-1 for i in range(len(b))])
797
return (a,b)
798
799
beta_numbers = frobenius_coordinates
800
801
def frobenius_rank(self):
802
""" Returns the Frobenius rank of the partition, which is the number of cells on the main diagonal.
803
804
EXAMPLES::
805
sage: Partition([]).frobenius_rank()
806
0
807
sage: Partition([1]).frobenius_rank()
808
1
809
sage: Partition([3,3,3]).frobenius_rank()
810
3
811
sage: Partition([9,1,1,1,1,1]).frobenius_rank()
812
1
813
sage: Partition([2,1,1,1,1,1]).frobenius_rank()
814
1
815
sage: Partition([2,2,1,1,1,1]).frobenius_rank()
816
2
817
"""
818
mu = self
819
if mu == []:
820
return 0
821
if len(mu) <= mu[0]:
822
return len(filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(mu)]))
823
else:
824
muconj = mu.conjugate()
825
return len(filter(lambda x: x>=0, [val-i-1 for i, val in enumerate(muconj)]))
826
827
828
def dominates(self, p2):
829
r"""
830
Returns True if partition p1 dominates partitions p2. Otherwise, it
831
returns False.
832
833
EXAMPLES::
834
835
sage: p = Partition([3,2])
836
sage: p.dominates([3,1])
837
True
838
sage: p.dominates([2,2])
839
True
840
sage: p.dominates([2,1,1])
841
True
842
sage: p.dominates([3,3])
843
False
844
sage: p.dominates([4])
845
False
846
sage: Partition([4]).dominates(p)
847
False
848
sage: Partition([]).dominates([1])
849
False
850
sage: Partition([]).dominates([])
851
True
852
sage: Partition([1]).dominates([])
853
True
854
"""
855
p1 = self
856
sum1 = 0
857
sum2 = 0
858
min_length = min(len(p1), len(p2))
859
if min_length == 0:
860
return len(p1) >= len(p2)
861
862
for i in range(min_length):
863
sum1 += p1[i]
864
sum2 += p2[i]
865
if sum2 > sum1:
866
return False
867
return bool(sum(p1) >= sum(p2))
868
869
def cells(self):
870
"""
871
Return the coordinates of the cells of self. Coordinates are given
872
as (row-index, column-index) and are 0 based.
873
874
EXAMPLES::
875
876
sage: Partition([2,2]).cells()
877
[(0, 0), (0, 1), (1, 0), (1, 1)]
878
sage: Partition([3,2]).cells()
879
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
880
"""
881
res = []
882
for i in range(len(self)):
883
for j in range(self[i]):
884
res.append( (i,j) )
885
return res
886
887
888
boxes = deprecated_function_alias(cells,
889
'Sage Version 4.3')
890
891
def generalized_pochhammer_symbol(self, a, alpha):
892
r"""
893
Returns the generalized Pochhammer symbol
894
`(a)_{self}^{(\alpha)}`. This is the product over all
895
cells (i,j) in p of `a - (i-1) / \alpha + j - 1`.
896
897
EXAMPLES::
898
899
sage: Partition([2,2]).generalized_pochhammer_symbol(2,1)
900
12
901
"""
902
res = 1
903
for (i,j) in self.cells():
904
res *= (a - (i-1)/alpha+j-1)
905
return res
906
907
def get_part(self, i, default=Integer(0)):
908
r"""
909
Return the `i^{th}` part of self, or ``default`` if it does not exist.
910
911
EXAMPLES::
912
913
sage: p = Partition([2,1])
914
sage: p.get_part(0), p.get_part(1), p.get_part(2)
915
(2, 1, 0)
916
sage: p.get_part(10,-1)
917
-1
918
sage: Partition([]).get_part(0)
919
0
920
"""
921
if i < len(self._list):
922
return self._list[i]
923
else:
924
return default
925
926
927
def conjugate(self):
928
"""
929
Returns the conjugate partition of the partition ``self``. This
930
is also called the associated partition in the literature.
931
932
EXAMPLES::
933
934
sage: Partition([2,2]).conjugate()
935
[2, 2]
936
sage: Partition([6,3,1]).conjugate()
937
[3, 2, 2, 1, 1, 1]
938
939
The conjugate partition is obtained by transposing the Ferrers
940
diagram of the partition (see :meth:`.ferrers_diagram`)::
941
942
sage: print Partition([6,3,1]).ferrers_diagram()
943
******
944
***
945
*
946
sage: print Partition([6,3,1]).conjugate().ferrers_diagram()
947
***
948
**
949
**
950
*
951
*
952
*
953
"""
954
p = self
955
if p == []:
956
return Partition_class([])
957
else:
958
l = len(p)
959
conj = [l]*p[-1]
960
for i in xrange(l-1,0,-1):
961
conj.extend([i]*(p[i-1] - p[i]))
962
return Partition_class(conj)
963
964
def reading_tableau(self):
965
"""
966
EXAMPLES::
967
968
sage: Partition([3,2,1]).reading_tableau()
969
[[1, 3, 6], [2, 5], [4]]
970
"""
971
st = tableau.StandardTableaux(self).first()
972
word = st.to_word()
973
perm = permutation.Permutation(word)
974
return perm.robinson_schensted()[1]
975
976
associated = deprecated_function_alias(conjugate, "Sage Version 4.4")
977
978
def arm_length(self, i, j):
979
"""
980
Returns the length of the arm of cell (i,j) in partition p.
981
982
INPUT: ``i`` and ``j``: two integers
983
984
OUPUT: an integer or a ValueError
985
986
The arm of cell (i,j) is the cells that appear to the right of cell
987
(i,j). Note that i and j are 0-based indices. If your coordinates are
988
in the form (i,j), use Python's \*-operator.
989
990
EXAMPLES::
991
992
sage: p = Partition([2,2,1])
993
sage: p.arm_length(0, 0)
994
1
995
sage: p.arm_length(0, 1)
996
0
997
sage: p.arm_length(2, 0)
998
0
999
sage: Partition([3,3]).arm_length(0, 0)
1000
2
1001
sage: Partition([3,3]).arm_length(*[0,0])
1002
2
1003
"""
1004
p = self
1005
if i < len(p) and j < p[i]:
1006
return p[i]-(j+1)
1007
else:
1008
raise ValueError, "The cells is not in the diagram"
1009
1010
arm = deprecated_function_alias(arm_length,
1011
'Sage Version 4.3')
1012
1013
def arm_lengths(self, flat=False):
1014
"""
1015
Returns a tableau of shape p where each cell is filled its arm
1016
length. The optional boolean parameter flat provides the option of
1017
returning a flat list.
1018
1019
EXAMPLES::
1020
1021
sage: Partition([2,2,1]).arm_lengths()
1022
[[1, 0], [1, 0], [0]]
1023
sage: Partition([2,2,1]).arm_lengths(flat=True)
1024
[1, 0, 1, 0, 0]
1025
sage: Partition([3,3]).arm_lengths()
1026
[[2, 1, 0], [2, 1, 0]]
1027
sage: Partition([3,3]).arm_lengths(flat=True)
1028
[2, 1, 0, 2, 1, 0]
1029
"""
1030
p = self
1031
res = [[p[i]-(j+1) for j in range(p[i])] for i in range(len(p))]
1032
if flat:
1033
return sum(res, [])
1034
else:
1035
return res
1036
1037
def arm_cells(self, i, j):
1038
r"""
1039
Returns the list of the cells of the arm of cell (i,j) in partition p.
1040
1041
INPUT: ``i`` and ``j``: two integers
1042
1043
OUTPUT: a list of pairs of integers
1044
1045
The arm of cell (i,j) is the boxes that appear to the right of cell
1046
(i,j). Note that i and j are 0-based indices. If your coordinates are
1047
in the form (i,j), use Python's \*-operator.
1048
1049
Examples::
1050
1051
sage: Partition([4,4,3,1]).arm_cells(1,1)
1052
[(1, 2), (1, 3)]
1053
1054
sage: Partition([]).arm_cells(0,0)
1055
Traceback (most recent call last):
1056
...
1057
ValueError: The cells is not in the diagram
1058
1059
"""
1060
p = self
1061
if i < len(p) and j < p[i]:
1062
return [ (i, x) for x in range(j+1, p[i]) ]
1063
else:
1064
raise ValueError, "The cells is not in the diagram"
1065
1066
def leg_length(self, i, j):
1067
"""
1068
Returns the length of the leg of cell (i,j) in partition p.
1069
1070
INPUT: ``i`` and ``j``: two integers
1071
1072
OUPUT: an integer or a ValueError
1073
1074
The leg of cell (i,j) is defined to be the cells below it in partition
1075
p (in English convention). Note that i and j are 0-based. If your
1076
coordinates are in the form (i,j), use Python's \*-operator.
1077
1078
EXAMPLES::
1079
1080
sage: p = Partition([2,2,1])
1081
sage: p.leg_length(0, 0)
1082
2
1083
sage: p.leg_length(0,1)
1084
1
1085
sage: p.leg_length(2,0)
1086
0
1087
sage: Partition([3,3]).leg_length(0, 0)
1088
1
1089
sage: cell = [0,0]; Partition([3,3]).leg_length(*cell)
1090
1
1091
"""
1092
1093
conj = self.conjugate()
1094
if j < len(conj) and i < conj[j]:
1095
return conj[j]-(i+1)
1096
else:
1097
raise ValueError, "The cells is not in the diagram"
1098
1099
leg = deprecated_function_alias(leg_length,
1100
'Sage Version 4.3')
1101
1102
def leg_lengths(self, flat=False):
1103
"""
1104
Returns a tableau of shape p with each cell filled in with its leg
1105
length. The optional boolean parameter flat provides the option of
1106
returning a flat list.
1107
1108
EXAMPLES::
1109
1110
sage: Partition([2,2,1]).leg_lengths()
1111
[[2, 1], [1, 0], [0]]
1112
sage: Partition([2,2,1]).leg_lengths(flat=True)
1113
[2, 1, 1, 0, 0]
1114
sage: Partition([3,3]).leg_lengths()
1115
[[1, 1, 1], [0, 0, 0]]
1116
sage: Partition([3,3]).leg_lengths(flat=True)
1117
[1, 1, 1, 0, 0, 0]
1118
"""
1119
p = self
1120
conj = p.conjugate()
1121
res = [[conj[j]-(i+1) for j in range(p[i])] for i in range(len(p))]
1122
if flat:
1123
return sum(res, [])
1124
else:
1125
return res
1126
1127
def leg_cells(self, i, j):
1128
r"""
1129
Returns the list of the cells of the leg of cell (i,j) in partition p.
1130
1131
INPUT: ``i`` and ``j``: two integers
1132
1133
OUTPUT: a list of pairs of integers
1134
1135
The leg of cell (i,j) is defined to be the cells below it in partition
1136
p (in English convention). Note that i and j are 0-based. If your
1137
coordinates are in the form (i,j), use Python's \*-operator.
1138
1139
Examples::
1140
1141
sage: Partition([4,4,3,1]).leg_cells(1,1)
1142
[(2, 1)]
1143
sage: Partition([4,4,3,1]).leg_cells(0,1)
1144
[(1, 1), (2, 1)]
1145
1146
sage: Partition([]).leg_cells(0,0)
1147
Traceback (most recent call last):
1148
...
1149
ValueError: The cells is not in the diagram
1150
"""
1151
l = self.leg_length(i, j)
1152
return [(x, j) for x in range(i+1, i+l+1)]
1153
1154
def dominate(self, rows=None):
1155
"""
1156
Returns a list of the partitions dominated by n. If n is specified,
1157
then it only returns the ones with = rows rows.
1158
1159
EXAMPLES::
1160
1161
sage: Partition([3,2,1]).dominate()
1162
[[3, 2, 1], [3, 1, 1, 1], [2, 2, 2], [2, 2, 1, 1], [2, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]
1163
sage: Partition([3,2,1]).dominate(rows=3)
1164
[[3, 2, 1], [2, 2, 2]]
1165
"""
1166
#Naive implementation
1167
res = [x for x in Partitions_n(self.size()) if self.dominates(x)]
1168
if rows:
1169
return [x for x in res if len(x) <= rows]
1170
else:
1171
return res
1172
1173
def contains(self, x):
1174
"""
1175
Returns True if p2 is a partition whose Ferrers diagram is
1176
contained in the Ferrers diagram of self
1177
1178
EXAMPLES::
1179
1180
sage: p = Partition([3,2,1])
1181
sage: p.contains([2,1])
1182
True
1183
sage: all(p.contains(mu) for mu in Partitions(3))
1184
True
1185
sage: all(p.contains(mu) for mu in Partitions(4))
1186
False
1187
"""
1188
return len(self) >= len(x) and all(self[i] >= x[i] for i in range(len(x)))
1189
1190
def hook_product(self, a):
1191
"""
1192
Returns the Jack hook-product.
1193
1194
EXAMPLES::
1195
1196
sage: Partition([3,2,1]).hook_product(x)
1197
(x + 2)^2*(2*x + 3)
1198
sage: Partition([2,2]).hook_product(x)
1199
2*(x + 1)*(x + 2)
1200
"""
1201
1202
nu = self.conjugate()
1203
res = 1
1204
for i in range(len(self)):
1205
for j in range(self[i]):
1206
res *= a*(self[i]-j-1)+nu[j]-i
1207
return res
1208
1209
def hook_polynomial(self, q, t):
1210
"""
1211
Returns the two-variable hook polynomial.
1212
1213
EXAMPLES::
1214
1215
sage: R.<q,t> = PolynomialRing(QQ)
1216
sage: a = Partition([2,2]).hook_polynomial(q,t)
1217
sage: a == (1 - t)*(1 - q*t)*(1 - t^2)*(1 - q*t^2)
1218
True
1219
sage: a = Partition([3,2,1]).hook_polynomial(q,t)
1220
sage: a == (1 - t)^3*(1 - q*t^2)^2*(1 - q^2*t^3)
1221
True
1222
"""
1223
nu = self.conjugate()
1224
res = 1
1225
for i in range(len(self)):
1226
for j in range(self[i]):
1227
res *= 1-q**(self[i]-j-1)*t**(nu[j]-i)
1228
return res
1229
1230
1231
def hook_length(self, i, j):
1232
"""
1233
Returns the length of the hook of cell (i,j) in the partition p. The
1234
hook of cell (i,j) is defined as the cells to the right or below (in
1235
the English convention). Note that i and j are 0-based. If your
1236
coordinates are in the form (i,j), use Python's \*-operator.
1237
1238
EXAMPLES::
1239
1240
sage: p = Partition([2,2,1])
1241
sage: p.hook_length(0, 0)
1242
4
1243
sage: p.hook_length(0, 1)
1244
2
1245
sage: p.hook_length(2, 0)
1246
1
1247
sage: Partition([3,3]).hook_length(0, 0)
1248
4
1249
sage: cell = [0,0]; Partition([3,3]).hook_length(*cell)
1250
4
1251
"""
1252
return self.leg_length(i,j)+self.arm_length(i,j)+1
1253
1254
hook = deprecated_function_alias(hook_length,
1255
'Sage Version 4.3')
1256
1257
1258
def hooks(self):
1259
"""
1260
Returns a sorted list of the hook lengths in self.
1261
1262
EXAMPLES::
1263
1264
sage: Partition([3,2,1]).hooks()
1265
[5, 3, 3, 1, 1, 1]
1266
"""
1267
res = []
1268
for row in self.hook_lengths():
1269
res += row
1270
res.sort(reverse=True)
1271
return res
1272
1273
def hook_lengths(self):
1274
r"""
1275
Returns a tableau of shape p with the cells filled in with the
1276
hook lengths.
1277
1278
In each cell, put the sum of one plus the number of cells
1279
horizontally to the right and vertically below the cell (the
1280
hook length).
1281
1282
For example, consider the partition [3,2,1] of 6 with Ferrers
1283
Diagram::
1284
1285
# # #
1286
# #
1287
#
1288
1289
When we fill in the cells with the hook lengths, we obtain::
1290
1291
5 3 1
1292
3 1
1293
1
1294
1295
EXAMPLES::
1296
1297
sage: Partition([2,2,1]).hook_lengths()
1298
[[4, 2], [3, 1], [1]]
1299
sage: Partition([3,3]).hook_lengths()
1300
[[4, 3, 2], [3, 2, 1]]
1301
sage: Partition([3,2,1]).hook_lengths()
1302
[[5, 3, 1], [3, 1], [1]]
1303
sage: Partition([2,2]).hook_lengths()
1304
[[3, 2], [2, 1]]
1305
sage: Partition([5]).hook_lengths()
1306
[[5, 4, 3, 2, 1]]
1307
1308
REFERENCES:
1309
1310
- http://mathworld.wolfram.com/HookLengthFormula.html
1311
"""
1312
p = self
1313
conj = p.conjugate()
1314
return [[p[i]-(i+1)+conj[j]-(j+1)+1 for j in range(p[i])] for i in range(len(p))]
1315
1316
def upper_hook(self, i, j, alpha):
1317
r"""
1318
Returns the upper hook length of the cell (i,j) in self. When alpha
1319
== 1, this is just the normal hook length. As usual, indices are 0
1320
based.
1321
1322
The upper hook length of a cell (i,j) in a partition
1323
`\kappa` is defined by
1324
1325
.. math::
1326
1327
h_*^\kappa(i,j) = \kappa_j^\prime-i+\alpha(\kappa_i - j+1).
1328
1329
1330
1331
EXAMPLES::
1332
1333
sage: p = Partition([2,1])
1334
sage: p.upper_hook(0,0,1)
1335
3
1336
sage: p.hook_length(0,0)
1337
3
1338
sage: [ p.upper_hook(i,j,x) for i,j in p.cells() ]
1339
[2*x + 1, x, x]
1340
"""
1341
p = self
1342
conj = self.conjugate()
1343
return conj[j]-(i+1)+alpha*(p[i]-(j+1)+1)
1344
1345
def upper_hook_lengths(self, alpha):
1346
r"""
1347
Returns the upper hook lengths of the partition. When alpha == 1,
1348
these are just the normal hook lengths.
1349
1350
The upper hook length of a cell (i,j) in a partition
1351
`\kappa` is defined by
1352
1353
.. math::
1354
1355
h_*^\kappa(i,j) = \kappa_j^\prime-i+1+\alpha(\kappa_i - j).
1356
1357
1358
1359
EXAMPLES::
1360
1361
sage: Partition([3,2,1]).upper_hook_lengths(x)
1362
[[3*x + 2, 2*x + 1, x], [2*x + 1, x], [x]]
1363
sage: Partition([3,2,1]).upper_hook_lengths(1)
1364
[[5, 3, 1], [3, 1], [1]]
1365
sage: Partition([3,2,1]).hook_lengths()
1366
[[5, 3, 1], [3, 1], [1]]
1367
"""
1368
p = self
1369
conj = p.conjugate()
1370
return [[conj[j]-(i+1)+alpha*(p[i]-(j+1)+1) for j in range(p[i])] for i in range(len(p))]
1371
1372
def lower_hook(self, i, j, alpha):
1373
r"""
1374
Returns the lower hook length of the cell (i,j) in self. When alpha
1375
== 1, this is just the normal hook length. Indices are 0-based.
1376
1377
The lower hook length of a cell (i,j) in a partition
1378
`\kappa` is defined by
1379
1380
.. math::
1381
1382
h_*^\kappa(i,j) = \kappa_j^\prime-i+1+\alpha(\kappa_i - j).
1383
1384
1385
1386
EXAMPLES::
1387
1388
sage: p = Partition([2,1])
1389
sage: p.lower_hook(0,0,1)
1390
3
1391
sage: p.hook_length(0,0)
1392
3
1393
sage: [ p.lower_hook(i,j,x) for i,j in p.cells() ]
1394
[x + 2, 1, 1]
1395
"""
1396
p = self
1397
conj = self.conjugate()
1398
return conj[j]-(i+1)+1+alpha*(p[i]-(j+1))
1399
1400
1401
def lower_hook_lengths(self, alpha):
1402
r"""
1403
Returns the lower hook lengths of the partition. When alpha == 1,
1404
these are just the normal hook lengths.
1405
1406
The lower hook length of a cell (i,j) in a partition
1407
`\kappa` is defined by
1408
1409
.. math::
1410
1411
h_\kappa^*(i,j) = \kappa_j^\prime-i+\alpha(\kappa_i - j + 1).
1412
1413
1414
1415
EXAMPLES::
1416
1417
sage: Partition([3,2,1]).lower_hook_lengths(x)
1418
[[2*x + 3, x + 2, 1], [x + 2, 1], [1]]
1419
sage: Partition([3,2,1]).lower_hook_lengths(1)
1420
[[5, 3, 1], [3, 1], [1]]
1421
sage: Partition([3,2,1]).hook_lengths()
1422
[[5, 3, 1], [3, 1], [1]]
1423
"""
1424
p = self
1425
conj = p.conjugate()
1426
return [[conj[j]-(i+1)+1+alpha*(p[i]-(j+1)) for j in range(p[i])] for i in range(len(p))]
1427
1428
1429
def weighted_size(self):
1430
"""
1431
Returns sum([i\*p[i] for i in range(len(p))]). It is also the
1432
sum of the leg length of every cell in b, or the sum of
1433
binomial(s[i],2) for s the conjugate partition of p.
1434
1435
EXAMPLES::
1436
1437
sage: Partition([2,2]).weighted_size()
1438
2
1439
sage: Partition([3,3,3]).weighted_size()
1440
9
1441
sage: Partition([5,2]).weighted_size()
1442
2
1443
"""
1444
p = self
1445
return sum([i*p[i] for i in range(len(p))])
1446
1447
1448
def length(self):
1449
"""
1450
Returns the number of parts in self.
1451
1452
EXAMPLES::
1453
1454
sage: Partition([3,2]).length()
1455
2
1456
sage: Partition([2,2,1]).length()
1457
3
1458
sage: Partition([]).length()
1459
0
1460
"""
1461
return len(self)
1462
1463
def to_exp(self, k=0):
1464
"""
1465
Return a list of the multiplicities of the parts of a partition.
1466
Use the optional parameter k to get a return list of length at
1467
least k.
1468
1469
EXAMPLES::
1470
1471
sage: Partition([3,2,2,1]).to_exp()
1472
[1, 2, 1]
1473
sage: Partition([3,2,2,1]).to_exp(5)
1474
[1, 2, 1, 0, 0]
1475
"""
1476
p = self
1477
if len(p) > 0:
1478
k = max(k, p[0])
1479
a = [ 0 ] * (k)
1480
for i in p:
1481
a[i-1] += 1
1482
return a
1483
1484
def evaluation(self):
1485
"""
1486
Returns the evaluation of the partition.
1487
1488
EXAMPLES::
1489
1490
sage: Partition([4,3,1,1]).evaluation()
1491
[2, 0, 1, 1]
1492
"""
1493
return self.to_exp()
1494
1495
def to_exp_dict(self):
1496
"""
1497
Returns a dictionary containing the multiplicities of the
1498
parts of this partition.
1499
1500
EXAMPLES::
1501
1502
sage: p = Partition([4,2,2,1])
1503
sage: d = p.to_exp_dict()
1504
sage: d[4]
1505
1
1506
sage: d[2]
1507
2
1508
sage: d[1]
1509
1
1510
sage: 5 in d
1511
False
1512
"""
1513
d = {}
1514
for part in self:
1515
d[part] = d.get(part, 0) + 1
1516
return d
1517
1518
def centralizer_size(self, t=0, q=0):
1519
r"""
1520
Returns the size of the centralizer of any permutation of cycle type
1521
``self``. If `m_i` is the multiplicity of `i` as a part of `p`, this is given
1522
by
1523
1524
.. math::
1525
1526
\prod_i m_i! i^{m_i}.
1527
1528
Including the optional
1529
parameters `t` and `q` gives the `q`-`t` analog which is the former product
1530
times
1531
1532
.. math::
1533
1534
\prod_{i=1}^{\mathrm{length}(p)} \frac{1 - q^{p_i}}{1 - t^{p_i}}.
1535
1536
EXAMPLES::
1537
1538
sage: Partition([2,2,1]).centralizer_size()
1539
8
1540
sage: Partition([2,2,2]).centralizer_size()
1541
48
1542
1543
REFERENCES:
1544
1545
- Kerber, A. 'Algebraic Combinatorics via Finite Group Action',
1546
1.3 p24
1547
"""
1548
p = self
1549
a = p.to_exp()
1550
size = prod([(i+1)**a[i]*factorial(a[i]) for i in range(len(a))])
1551
size *= prod( [ (1-q**p[i])/(1-t**p[i]) for i in range(len(p)) ] )
1552
1553
return size
1554
1555
def aut(self):
1556
r"""
1557
Returns a factor for the number of permutations with cycle type
1558
``self``. self.aut() returns
1559
`1^{j_1}j_1! \cdots n^{j_n}j_n!` where `j_k`
1560
is the number of parts in self equal to k.
1561
1562
The number of permutations having `p` as a cycle type is
1563
given by
1564
1565
.. math::
1566
1567
\frac{n!}{1^{j_1}j_1! \cdots n^{j_n}j_n!} .
1568
1569
EXAMPLES::
1570
1571
sage: Partition([2,1]).aut()
1572
2
1573
"""
1574
m = self.to_exp()
1575
return prod([(i+1)**m[i]*factorial(m[i]) for i in range(len(m)) if m[i] > 0])
1576
1577
def content(self, i, j):
1578
r"""
1579
Returns the content statistic of the given cell, which is simply
1580
defined by j - i. This doesn't technically depend on the partition,
1581
but is included here because it is often useful in the context of
1582
partitions.
1583
1584
EXAMPLES::
1585
1586
sage: Partition([2,1]).content(0,1)
1587
1
1588
sage: p = Partition([3,2])
1589
sage: sum([p.content(*c) for c in p.cells()])
1590
2
1591
"""
1592
1593
return j - i
1594
1595
def conjugacy_class_size(self):
1596
"""
1597
Returns the size of the conjugacy class of the symmetric group
1598
indexed by the partition p.
1599
1600
EXAMPLES::
1601
1602
sage: Partition([2,2,2]).conjugacy_class_size()
1603
15
1604
sage: Partition([2,2,1]).conjugacy_class_size()
1605
15
1606
sage: Partition([2,1,1]).conjugacy_class_size()
1607
6
1608
1609
REFERENCES:
1610
1611
- Kerber, A. 'Algebraic Combinatorics via Finite Group Action'
1612
1.3 p24
1613
"""
1614
1615
return factorial(sum(self))/self.centralizer_size()
1616
1617
1618
def corners(self):
1619
"""
1620
Returns a list of the corners of the partitions. These are the
1621
positions where we can remove a cell. Indices are of the form (i,j)
1622
where i is the row-index and j is the column-index, and are
1623
0-based.
1624
1625
EXAMPLES::
1626
1627
sage: Partition([3,2,1]).corners()
1628
[(0, 2), (1, 1), (2, 0)]
1629
sage: Partition([3,3,1]).corners()
1630
[(1, 2), (2, 0)]
1631
"""
1632
p = self
1633
if p == []:
1634
return []
1635
1636
lcors = [[0,p[0]-1]]
1637
nn = len(p)
1638
if nn == 1:
1639
return map(tuple, lcors)
1640
1641
lcors_index = 0
1642
for i in range(1, nn):
1643
if p[i] == p[i-1]:
1644
lcors[lcors_index][0] += 1
1645
else:
1646
lcors.append([i,p[i]-1])
1647
lcors_index += 1
1648
1649
return map(tuple, lcors)
1650
1651
1652
def outside_corners(self):
1653
"""
1654
Returns a list of the positions where we can add a cell so that the
1655
shape is still a partition. Indices are of the form (i,j) where i
1656
is the row-index and j is the column-index, and are 0-based.
1657
1658
EXAMPLES::
1659
1660
sage: Partition([2,2,1]).outside_corners()
1661
[(0, 2), (2, 1), (3, 0)]
1662
sage: Partition([2,2]).outside_corners()
1663
[(0, 2), (2, 0)]
1664
sage: Partition([6,3,3,1,1,1]).outside_corners()
1665
[(0, 6), (1, 3), (3, 1), (6, 0)]
1666
sage: Partition([]).outside_corners()
1667
[(0, 0)]
1668
"""
1669
p = self
1670
if p == Partition([]):
1671
return [(0,0)]
1672
res = [ (0, p[0]) ]
1673
for i in range(1, len(p)):
1674
if p[i-1] != p[i]:
1675
res.append((i,p[i]))
1676
res.append((len(p), 0))
1677
1678
return res
1679
1680
def rim(self):
1681
r"""
1682
Returns the rim of ``self``.
1683
1684
The rim of a partition `p` is defined as the cells which belong to
1685
`p` and which are adjacent to cells not in `p`.
1686
1687
EXAMPLES:
1688
1689
The rim of the partition `[5,5,2,1]` consists of the cells marked with
1690
``#`` below::
1691
1692
****#
1693
*####
1694
##
1695
#
1696
1697
sage: Partition([5,5,2,1]).rim()
1698
[(3, 0), (2, 0), (2, 1), (1, 1), (1, 2), (1, 3), (1, 4), (0, 4)]
1699
1700
sage: Partition([2,2,1]).rim()
1701
[(2, 0), (1, 0), (1, 1), (0, 1)]
1702
sage: Partition([2,2]).rim()
1703
[(1, 0), (1, 1), (0, 1)]
1704
sage: Partition([6,3,3,1,1]).rim()
1705
[(4, 0), (3, 0), (2, 0), (2, 1), (2, 2), (1, 2), (0, 2), (0, 3), (0, 4), (0, 5)]
1706
sage: Partition([]).rim()
1707
[]
1708
"""
1709
p = self
1710
res = []
1711
prevLen = 1
1712
for i in range(len(p)-1, -1, -1):
1713
for c in range(prevLen-1, p[i]):
1714
res.append((i,c))
1715
prevLen = p[i]
1716
return res
1717
1718
def outer_rim(self):
1719
"""
1720
Returns the outer rim of ``self``.
1721
1722
The outer rim of a partition `p` is defined as the cells which do not
1723
belong to `p` and which are adjacent to cells in `p`.
1724
1725
EXAMPLES:
1726
1727
The outer rim of the partition `[4,1]` consists of the cells marked
1728
with ``#`` below::
1729
1730
****#
1731
*####
1732
##
1733
1734
sage: Partition([4,1]).outer_rim()
1735
[(2, 0), (2, 1), (1, 1), (1, 2), (1, 3), (1, 4), (0, 4)]
1736
1737
sage: Partition([2,2,1]).outer_rim()
1738
[(3, 0), (3, 1), (2, 1), (2, 2), (1, 2), (0, 2)]
1739
sage: Partition([2,2]).outer_rim()
1740
[(2, 0), (2, 1), (2, 2), (1, 2), (0, 2)]
1741
sage: Partition([6,3,3,1,1]).outer_rim()
1742
[(5, 0), (5, 1), (4, 1), (3, 1), (3, 2), (3, 3), (2, 3), (1, 3), (1, 4), (1, 5), (1, 6), (0, 6)]
1743
sage: Partition([]).outer_rim()
1744
[(0, 0)]
1745
"""
1746
p = self
1747
res = []
1748
prevLen = 0
1749
for i in range(len(p)-1, -1, -1):
1750
for c in range(prevLen, p[i]+1):
1751
res.append((i+1,c))
1752
prevLen = p[i]
1753
res.append((0, prevLen))
1754
return res
1755
1756
def core(self, length):
1757
"""
1758
Returns the core of the partition -- in the literature the core is
1759
commonly referred to as the `k`-core, `p`-core, `r`-core, ... . The
1760
construction of the core can be visualized by repeatedly removing
1761
border strips of size `r` from ``self`` until this is no longer possible.
1762
The remaining partition is the core.
1763
1764
EXAMPLES::
1765
1766
sage: Partition([6,3,2,2]).core(3)
1767
[2, 1, 1]
1768
sage: Partition([]).core(3)
1769
[]
1770
sage: Partition([8,7,7,4,1,1,1,1,1]).core(3)
1771
[2, 1, 1]
1772
1773
TESTS::
1774
1775
sage: Partition([3,3,3,2,1]).core(3)
1776
[]
1777
sage: Partition([10,8,7,7]).core(4)
1778
[]
1779
sage: Partition([21,15,15,9,6,6,6,3,3]).core(3)
1780
[]
1781
"""
1782
p = self
1783
#Normalize the length
1784
remainder = len(p) % length
1785
part = p[:] + [0]*remainder
1786
1787
#Add the canonical vector to the partition
1788
part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)]
1789
1790
for e in range(length):
1791
k = e
1792
for i in reversed(range(1,len(part)+1)):
1793
if part[i-1] % length == e:
1794
part[i-1] = k
1795
k += length
1796
part.sort()
1797
part.reverse()
1798
1799
#Remove the canonical vector
1800
part = [part[i-1]-len(part)+i for i in range(1, len(part)+1)]
1801
#Select the r-core
1802
return Partition_class(filter(lambda x: x != 0, part))
1803
1804
r_core = deprecated_function_alias(core,
1805
'Sage Version 4.3')
1806
1807
def quotient(self, length):
1808
"""
1809
Returns the quotient of the partition -- in the literature the
1810
core is commonly referred to as the `k`-core, `p`-core, `r`-core, ... . The
1811
quotient is a list of `r` partitions, constructed in the following
1812
way. Label each cell in `p` with its content, modulo `r`. Let `R_i` be
1813
the set of rows ending in a cell labelled `i`, and `C_i` be the set of
1814
columns ending in a cell labelled `i`. Then the `j`-th component of the
1815
quotient of `p` is the partition defined by intersecting `R_j` with
1816
`C_j+1`.
1817
1818
EXAMPLES::
1819
1820
sage: Partition([7,7,5,3,3,3,1]).quotient(3)
1821
([2], [1], [2, 2, 2])
1822
1823
TESTS::
1824
1825
sage: Partition([8,7,7,4,1,1,1,1,1]).quotient(3)
1826
([2, 1], [2, 2], [2])
1827
sage: Partition([10,8,7,7]).quotient(4)
1828
([2], [3], [2], [1])
1829
sage: Partition([6,3,3]).quotient(3)
1830
([1], [1], [2])
1831
sage: Partition([3,3,3,2,1]).quotient(3)
1832
([1], [1, 1], [1])
1833
sage: Partition([6,6,6,3,3,3]).quotient(3)
1834
([2, 1], [2, 1], [2, 1])
1835
sage: Partition([21,15,15,9,6,6,6,3,3]).quotient(3)
1836
([5, 2, 1], [5, 2, 1], [7, 3, 2])
1837
sage: Partition([21,15,15,9,6,6,3,3]).quotient(3)
1838
([5, 2], [5, 2, 1], [7, 3, 1])
1839
sage: Partition([14,12,11,10,10,10,10,9,6,4,3,3,2,1]).quotient(5)
1840
([3, 3], [2, 2, 1], [], [3, 3, 3], [1])
1841
1842
sage: all(p == Partition(core=p.core(k), quotient=p.quotient(k))
1843
... for i in range(10) for p in Partitions(i)
1844
... for k in range(1,6))
1845
True
1846
"""
1847
p = self
1848
#Normalize the length
1849
remainder = len(p) % length
1850
part = p[:] + [0]*(length-remainder)
1851
1852
1853
#Add the canonical vector to the partition
1854
part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)]
1855
result = [None]*length
1856
1857
#Reducing vector
1858
for e in range(length):
1859
k = e
1860
tmp = []
1861
for i in reversed(range(len(part))):
1862
if part[i] % length == e:
1863
tmp.append(ZZ((part[i]-k)/length))
1864
k += length
1865
1866
a = [i for i in tmp if i != 0]
1867
a.reverse()
1868
result[e] = a
1869
1870
return tuple(map(Partition_class, result))
1871
1872
r_quotient = deprecated_function_alias(quotient,
1873
'Sage Version 4.3')
1874
1875
def is_core(self, k):
1876
r"""
1877
Tests whether the partition is a `k`-core or not. Visuallly, this can be checked
1878
by trying to remove border strips of size `k` from ``self``. If this is not possible,
1879
then ``self`` is a `k`-core.
1880
1881
EXAMPLES::
1882
1883
sage: p = Partition([12,8,5,5,2,2,1])
1884
sage: p.is_core(4)
1885
False
1886
sage: p.is_core(5)
1887
True
1888
sage: p.is_core(0)
1889
True
1890
"""
1891
return not k in self.hooks()
1892
1893
def k_interior(self, k):
1894
r"""
1895
Returns the partition consisting of the cells of ``self``,
1896
whose hook lengths are greater than `k`.
1897
1898
EXAMPLES::
1899
1900
sage: p = Partition([3,2,1])
1901
sage: p.hook_lengths()
1902
[[5, 3, 1], [3, 1], [1]]
1903
sage: p.k_interior(2)
1904
[2, 1]
1905
sage: p.k_interior(3)
1906
[1]
1907
1908
sage: p = Partition([])
1909
sage: p.k_interior(3)
1910
[]
1911
"""
1912
return Partition([len([i for i in row if i > k])
1913
for row in self.hook_lengths()])
1914
1915
def k_boundary(self, k):
1916
r"""
1917
Returns the skew partition formed by removing the cells of the
1918
`k`-interior, see :meth:`k_interior`.
1919
1920
EXAMPLES::
1921
1922
sage: p = Partition([3,2,1])
1923
sage: p.k_boundary(2)
1924
[[3, 2, 1], [2, 1]]
1925
sage: p.k_boundary(3)
1926
[[3, 2, 1], [1]]
1927
1928
sage: p = Partition([12,8,5,5,2,2,1])
1929
sage: p.k_boundary(4)
1930
[[12, 8, 5, 5, 2, 2, 1], [8, 5, 2, 2]]
1931
"""
1932
# bypass the checks
1933
return sage.combinat.skew_partition.SkewPartition_class(
1934
(self, self.k_interior(k)))
1935
1936
def add_cell(self, i, j = None):
1937
r"""
1938
Returns a partition corresponding to self with a cell added in row
1939
i. i and j are 0-based row and column indices. This does not change
1940
p.
1941
1942
Note that if you have coordinates in a list, you can call this
1943
function with python's \* notation (see the examples below).
1944
1945
EXAMPLES::
1946
1947
sage: Partition([3, 2, 1, 1]).add_cell(0)
1948
[4, 2, 1, 1]
1949
sage: cell = [4, 0]; Partition([3, 2, 1, 1]).add_cell(*cell)
1950
[3, 2, 1, 1, 1]
1951
"""
1952
1953
if j is None:
1954
if i >= len(self):
1955
j = 0
1956
else:
1957
j = self[i]
1958
1959
if (i,j) in self.outside_corners():
1960
pl = self.to_list()
1961
if i == len(pl):
1962
pl.append(1)
1963
else:
1964
pl[i] += 1
1965
return Partition(pl)
1966
1967
raise ValueError, "[%s, %s] is not an addable cell"%(i,j)
1968
1969
add_box = deprecated_function_alias(add_cell,
1970
'Sage Version 4.3')
1971
1972
def remove_cell(self, i, j = None):
1973
"""
1974
Returns the partition obtained by removing a cell at the end of row
1975
i.
1976
1977
EXAMPLES::
1978
1979
sage: Partition([2,2]).remove_cell(1)
1980
[2, 1]
1981
sage: Partition([2,2,1]).remove_cell(2)
1982
[2, 2]
1983
sage: #Partition([2,2]).remove_cell(0)
1984
1985
::
1986
1987
sage: Partition([2,2]).remove_cell(1,1)
1988
[2, 1]
1989
sage: #Partition([2,2]).remove_cell(1,0)
1990
"""
1991
1992
if i >= len(self):
1993
raise ValueError, "i must be less than the length of the partition"
1994
1995
if j is None:
1996
j = self[i] - 1
1997
1998
if (i,j) not in self.corners():
1999
raise ValueError, "[%d,%d] is not a corner of the partition" % (i,j)
2000
2001
if self[i] == 1:
2002
return Partition(self[:-1])
2003
else:
2004
return Partition(self[:i] + [ self[i:i+1][0] - 1 ] + self[i+1:])
2005
2006
remove_box = deprecated_function_alias(remove_cell,
2007
'Sage Version 4.3')
2008
2009
2010
def k_skew(self, k):
2011
r"""
2012
Returns the `k`-skew partition.
2013
2014
The `k`-skew diagram of a `k`-bounded partition is the skew diagram
2015
denoted `\lambda/^k` satisfying the conditions:
2016
2017
1. row i of `\lambda/^k` has length `\lambda_i`
2018
2019
2. no cell in `\lambda/^k` has hook-length exceeding k
2020
2021
3. every square above the diagram of `\lambda/^k` has hook
2022
length exceeding k.
2023
2024
REFERENCES:
2025
2026
- Lapointe, L. and Morse, J. 'Order Ideals in Weak Subposets
2027
of Young's Lattice and Associated Unimodality Conjectures'
2028
2029
EXAMPLES::
2030
2031
sage: p = Partition([4,3,2,2,1,1])
2032
sage: p.k_skew(4)
2033
[[9, 5, 3, 2, 1, 1], [5, 2, 1]]
2034
"""
2035
2036
if len(self) == 0:
2037
return sage.combinat.skew_partition.SkewPartition([[],[]])
2038
2039
if self[0] > k:
2040
raise ValueError, "the partition must be %d-bounded" % k
2041
2042
#Find the k-skew diagram of the partition formed
2043
#by removing the first row
2044
s = Partition(self[1:]).k_skew(k)
2045
2046
s_inner = s.inner()
2047
s_outer = s.outer()
2048
s_conj_rl = s.conjugate().row_lengths()
2049
2050
#Find the leftmost column with less than
2051
# or equal to kdiff cells
2052
kdiff = k - self[0]
2053
2054
if s_outer == []:
2055
spot = 0
2056
else:
2057
spot = s_outer[0]
2058
2059
for i in range(len(s_conj_rl)):
2060
if s_conj_rl[i] <= kdiff:
2061
spot = i
2062
break
2063
2064
outer = [ self[0] + spot ] + s_outer[:]
2065
if spot > 0:
2066
inner = [ spot ] + s_inner[:]
2067
else:
2068
inner = s_inner[:]
2069
2070
return sage.combinat.skew_partition.SkewPartition([outer, inner])
2071
2072
def to_core(self, k):
2073
r"""
2074
Maps the `k`-bounded partition ``self`` to its corresponding `k+1`-core.
2075
2076
See also :meth:`k_skew`.
2077
2078
EXAMPLES::
2079
2080
sage: p = Partition([4,3,2,2,1,1])
2081
sage: c = p.to_core(4); c
2082
[9, 5, 3, 2, 1, 1]
2083
sage: type(c)
2084
<class 'sage.combinat.core.Cores_length_with_category.element_class'>
2085
sage: c.to_bounded_partition() == p
2086
True
2087
"""
2088
return sage.combinat.core.Core(self.k_skew(k)[0],k+1)
2089
2090
def from_kbounded_to_reduced_word(self, k):
2091
r"""
2092
Maps a `k`-bounded partition to a reduced word for an element in
2093
the affine permutation group.
2094
2095
This uses the fact that there is a bijection between `k`-bounded partitions
2096
and `(k+1)`-cores and an action of the affine nilCoxeter algebra of type
2097
`A_k^{(1)}` on `(k+1)`-cores as described in [LM2006]_.
2098
2099
REFERENCES:
2100
2101
.. [LM2006] MR2167475 (2006j:05214)
2102
L. Lapointe, J. Morse. Tableaux on `k+1`-cores, reduced words for affine permutations, and `k`-Schur expansions.
2103
J. Combin. Theory Ser. A 112 (2005), no. 1, 44--81.
2104
2105
EXAMPLES::
2106
2107
sage: p=Partition([2,1,1])
2108
sage: p.from_kbounded_to_reduced_word(2)
2109
[2, 1, 2, 0]
2110
sage: p=Partition([3,1])
2111
sage: p.from_kbounded_to_reduced_word(3)
2112
[3, 2, 1, 0]
2113
sage: p.from_kbounded_to_reduced_word(2)
2114
Traceback (most recent call last):
2115
...
2116
ValueError: the partition must be 2-bounded
2117
sage: p=Partition([])
2118
sage: p.from_kbounded_to_reduced_word(2)
2119
[]
2120
"""
2121
p=self.k_skew(k)[0]
2122
result = []
2123
while p != []:
2124
corners = p.corners()
2125
c = p.content(corners[0][0],corners[0][1])%(k+1)
2126
result.append(Integer(c))
2127
list = [x for x in corners if p.content(x[0],x[1])%(k+1) ==c]
2128
for x in list:
2129
p = p.remove_cell(x[0])
2130
return result
2131
2132
def from_kbounded_to_grassmannian(self, k):
2133
r"""
2134
Maps a `k`-bounded partition to a Grassmannian element in
2135
the affine Weyl group of type `A_k^{(1)}`.
2136
2137
For details, see the documentation of the method
2138
:meth:`from_kbounded_to_reduced_word` .
2139
2140
EXAMPLES::
2141
2142
sage: p=Partition([2,1,1])
2143
sage: p.from_kbounded_to_grassmannian(2)
2144
[-1 1 1]
2145
[-2 2 1]
2146
[-2 1 2]
2147
sage: p=Partition([])
2148
sage: p.from_kbounded_to_grassmannian(2)
2149
[1 0 0]
2150
[0 1 0]
2151
[0 0 1]
2152
"""
2153
from sage.combinat.root_system.weyl_group import WeylGroup
2154
W=WeylGroup(['A',k,1])
2155
return W.from_reduced_word(self.from_kbounded_to_reduced_word(k))
2156
2157
def to_list(self):
2158
r"""
2159
Return self as a list.
2160
2161
EXAMPLES::
2162
2163
sage: p = Partition([2,1]).to_list(); p
2164
[2, 1]
2165
sage: type(p)
2166
<type 'list'>
2167
2168
TESTS::
2169
2170
sage: p = Partition([2,1])
2171
sage: pl = p.to_list()
2172
sage: pl[0] = 0; p
2173
[2, 1]
2174
"""
2175
return self._list[:]
2176
2177
def add_vertical_border_strip(self, k):
2178
"""
2179
Returns a list of all the partitions that can be obtained by adding
2180
a vertical border strip of length k to self.
2181
2182
EXAMPLES::
2183
2184
sage: Partition([]).add_vertical_border_strip(0)
2185
[[]]
2186
sage: Partition([]).add_vertical_border_strip(2)
2187
[[1, 1]]
2188
sage: Partition([2,2]).add_vertical_border_strip(2)
2189
[[3, 3], [3, 2, 1], [2, 2, 1, 1]]
2190
sage: Partition([3,2,2]).add_vertical_border_strip(2)
2191
[[4, 3, 2], [4, 2, 2, 1], [3, 3, 3], [3, 3, 2, 1], [3, 2, 2, 1, 1]]
2192
"""
2193
return [p.conjugate() for p in self.conjugate().add_horizontal_border_strip(k)]
2194
2195
def add_horizontal_border_strip(self, k):
2196
"""
2197
Returns a list of all the partitions that can be obtained by adding
2198
a horizontal border strip of length k to self.
2199
2200
EXAMPLES::
2201
2202
sage: Partition([]).add_horizontal_border_strip(0)
2203
[[]]
2204
sage: Partition([]).add_horizontal_border_strip(2)
2205
[[2]]
2206
sage: Partition([2,2]).add_horizontal_border_strip(2)
2207
[[2, 2, 2], [3, 2, 1], [4, 2]]
2208
sage: Partition([3,2,2]).add_horizontal_border_strip(2)
2209
[[3, 2, 2, 2], [3, 3, 2, 1], [4, 2, 2, 1], [4, 3, 2], [5, 2, 2]]
2210
2211
TODO: reimplement like remove_horizontal_border_strip using IntegerListsLex
2212
"""
2213
conj = self.conjugate().to_list()
2214
shelf = []
2215
res = []
2216
i = 0
2217
while i < len(conj):
2218
tmp = 1
2219
while i+1 < len(conj) and conj[i] == conj[i+1]:
2220
tmp += 1
2221
i += 1
2222
if i == len(conj)-1 and i > 0 and conj[i] != conj[i-1]:
2223
tmp = 1
2224
shelf.append(tmp)
2225
i += 1
2226
2227
#added the last shelf on the right side of
2228
#the first line
2229
shelf.append(k)
2230
2231
#list all of the positions for cells
2232
#filling each self from the left to the right
2233
l = IntegerVectors(k, len(shelf), outer=shelf).list()
2234
for iv in l:
2235
tmp = conj + [0]*k
2236
j = 0
2237
for t in range(len(iv)):
2238
while iv[t] > 0:
2239
tmp[j] += 1
2240
iv[t] -= 1
2241
j += 1
2242
j = sum(shelf[:t+1])
2243
res.append(Partition_class([i for i in tmp if i != 0]).conjugate())
2244
return res
2245
2246
def remove_horizontal_border_strip(self, k):
2247
"""
2248
Returns the partitions obtained from self by removing an
2249
horizontal border strip of length k
2250
2251
EXAMPLES::
2252
2253
sage: Partition([5,3,1]).remove_horizontal_border_strip(0).list()
2254
[[5, 3, 1]]
2255
sage: Partition([5,3,1]).remove_horizontal_border_strip(1).list()
2256
[[5, 3], [5, 2, 1], [4, 3, 1]]
2257
sage: Partition([5,3,1]).remove_horizontal_border_strip(2).list()
2258
[[5, 2], [5, 1, 1], [4, 3], [4, 2, 1], [3, 3, 1]]
2259
sage: Partition([5,3,1]).remove_horizontal_border_strip(3).list()
2260
[[5, 1], [4, 2], [4, 1, 1], [3, 3], [3, 2, 1]]
2261
sage: Partition([5,3,1]).remove_horizontal_border_strip(4).list()
2262
[[4, 1], [3, 2], [3, 1, 1]]
2263
sage: Partition([5,3,1]).remove_horizontal_border_strip(5).list()
2264
[[3, 1]]
2265
sage: Partition([5,3,1]).remove_horizontal_border_strip(6).list()
2266
[]
2267
2268
The result is returned as a combinatorial class::
2269
2270
sage: Partition([5,3,1]).remove_horizontal_border_strip(5)
2271
The subpartitions of [5, 3, 1] obtained by removing an horizontal border strip of length 5
2272
2273
TESTS::
2274
2275
sage: Partition([3,2,2]).remove_horizontal_border_strip(2).list()
2276
[[3, 2], [2, 2, 1]]
2277
sage: Partition([3,2,2]).remove_horizontal_border_strip(2).first().parent()
2278
Partitions...
2279
sage: Partition([]).remove_horizontal_border_strip(0).list()
2280
[[]]
2281
sage: Partition([]).remove_horizontal_border_strip(6).list()
2282
[]
2283
"""
2284
return IntegerListsLex(n = self.size()-k,
2285
min_length = len(self)-1,
2286
max_length = len(self),
2287
floor = self[1:]+[0],
2288
ceiling = self[:],
2289
max_slope = 0,
2290
element_constructor = Partition,
2291
name = "The subpartitions of %s obtained by removing an horizontal border strip of length %s"%(self,k))
2292
2293
def k_conjugate(self, k):
2294
"""
2295
Returns the k-conjugate of the partition.
2296
2297
The k-conjugate is the partition that is given by the columns of
2298
the k-skew diagram of the partition.
2299
2300
EXAMPLES::
2301
2302
sage: p = Partition([4,3,2,2,1,1])
2303
sage: p.k_conjugate(4)
2304
[3, 2, 2, 1, 1, 1, 1, 1, 1]
2305
"""
2306
return Partition(self.k_skew(k).conjugate().row_lengths())
2307
2308
def parent(self):
2309
"""
2310
Returns the combinatorial class of partitions of sum(self).
2311
2312
EXAMPLES::
2313
2314
sage: Partition([3,2,1]).parent()
2315
Partitions of the integer 6
2316
"""
2317
return Partitions(sum(self[:]))
2318
2319
def arms_legs_coeff(self, i, j):
2320
"""
2321
This is a statistic on a cell c=(i,j) in the diagram of partition p
2322
given by
2323
2324
.. math::
2325
2326
[ (1 - q^{arm_length(c)} * t^{leg_length(c) + 1}) ] / [ (1 - q^{arm_length(c) + 1} * t^{leg_length(c)}) ]
2327
2328
2329
2330
EXAMPLES::
2331
2332
sage: Partition([3,2,1]).arms_legs_coeff(1,1)
2333
(-t + 1)/(-q + 1)
2334
sage: Partition([3,2,1]).arms_legs_coeff(0,0)
2335
(-q^2*t^3 + 1)/(-q^3*t^2 + 1)
2336
sage: Partition([3,2,1]).arms_legs_coeff(*[0,0])
2337
(-q^2*t^3 + 1)/(-q^3*t^2 + 1)
2338
"""
2339
QQqt = PolynomialRing(QQ, ['q', 't'])
2340
(q,t) = QQqt.gens()
2341
if i < len(self) and j < self[i]:
2342
res = (1-q**self.arm_length(i,j) * t**(self.leg_length(i,j)+1))
2343
res /= (1-q**(self.arm_length(i,j)+1) * t**self.leg_length(i,j))
2344
return res
2345
else:
2346
return ZZ(1)
2347
2348
def atom(self):
2349
"""
2350
Returns a list of the standard tableaux of size self.size() whose
2351
atom is equal to self.
2352
2353
EXAMPLES::
2354
2355
sage: Partition([2,1]).atom()
2356
[[[1, 2], [3]]]
2357
sage: Partition([3,2,1]).atom()
2358
[[[1, 2, 3, 6], [4, 5]], [[1, 2, 3], [4, 5], [6]]]
2359
"""
2360
res = []
2361
for tab in tableau.StandardTableaux_n(self.size()):
2362
if tab.atom() == self:
2363
res.append(tab)
2364
return res
2365
2366
def k_atom(self, k):
2367
"""
2368
EXAMPLES::
2369
2370
sage: p = Partition([3,2,1])
2371
sage: p.k_atom(1)
2372
[]
2373
sage: p.k_atom(3)
2374
[[[1, 1, 1], [2, 2], [3]],
2375
[[1, 1, 1, 2], [2], [3]],
2376
[[1, 1, 1, 3], [2, 2]],
2377
[[1, 1, 1, 2, 3], [2]]]
2378
sage: Partition([3,2,1]).k_atom(4)
2379
[[[1, 1, 1], [2, 2], [3]], [[1, 1, 1, 3], [2, 2]]]
2380
2381
TESTS::
2382
2383
sage: Partition([1]).k_atom(1)
2384
[[[1]]]
2385
sage: Partition([1]).k_atom(2)
2386
[[[1]]]
2387
sage: Partition([]).k_atom(1)
2388
[[]]
2389
"""
2390
res = [ tableau.Tableau_class([]) ]
2391
for i in range(len(self)):
2392
res = [ x.promotion_operator( self[-i-1] ) for x in res]
2393
res = sum(res, [])
2394
res = [ y.katabolism_projector(Partition_class(self[-i-1:]).k_split(k)) for y in res]
2395
res = [ i for i in res if i !=0 and i != [] ]
2396
return res
2397
2398
def k_split(self, k):
2399
"""
2400
Returns the k-split of self.
2401
2402
EXAMPLES::
2403
2404
sage: Partition([4,3,2,1]).k_split(3)
2405
[]
2406
sage: Partition([4,3,2,1]).k_split(4)
2407
[[4], [3, 2], [1]]
2408
sage: Partition([4,3,2,1]).k_split(5)
2409
[[4, 3], [2, 1]]
2410
sage: Partition([4,3,2,1]).k_split(6)
2411
[[4, 3, 2], [1]]
2412
sage: Partition([4,3,2,1]).k_split(7)
2413
[[4, 3, 2, 1]]
2414
sage: Partition([4,3,2,1]).k_split(8)
2415
[[4, 3, 2, 1]]
2416
"""
2417
if self == []:
2418
return []
2419
elif k < self[0]:
2420
return []
2421
else:
2422
res = []
2423
part = list(self)
2424
while part != [] and part[0]+len(part)-1 >= k:
2425
p = k - part[0]
2426
res.append( part[:p+1] )
2427
part = part[p+1:]
2428
if part != []:
2429
res.append(part)
2430
return res
2431
2432
def jacobi_trudi(self):
2433
"""
2434
EXAMPLES::
2435
2436
sage: part = Partition([3,2,1])
2437
sage: jt = part.jacobi_trudi(); jt
2438
[h[3] h[1] 0]
2439
[h[4] h[2] h[]]
2440
[h[5] h[3] h[1]]
2441
sage: s = SFASchur(QQ)
2442
sage: h = SFAHomogeneous(QQ)
2443
sage: h( s(part) )
2444
h[3, 2, 1] - h[3, 3] - h[4, 1, 1] + h[5, 1]
2445
sage: jt.det()
2446
h[3, 2, 1] - h[3, 3] - h[4, 1, 1] + h[5, 1]
2447
"""
2448
return sage.combinat.skew_partition.SkewPartition([ self, [] ]).jacobi_trudi()
2449
2450
2451
def character_polynomial(self):
2452
r"""
2453
Returns the character polynomial associated to the partition self.
2454
The character polynomial `q_\mu` is defined by
2455
2456
2457
.. math::
2458
2459
q_\mu(x_1, x_2, \ldots, x_k) = \downarrow \sum_{\alpha \vdash k}\frac{ \chi^\mu_\alpha }{1^{a_1}2^{a_2}\cdots k^{a_k}a_1!a_2!\cdots a_k!} \prod_{i=1}^{k} (ix_i-1)^{a_i}
2460
2461
2462
where `a_i` is the multiplicity of `i` in
2463
`\alpha`.
2464
2465
It is computed in the following manner.
2466
2467
1. Expand the Schur function `s_\mu` in the power-sum
2468
basis.
2469
2470
2. Replace each `p_i` with `ix_i-1`
2471
2472
3. Apply the umbral operator `\downarrow` to the resulting
2473
polynomial.
2474
2475
EXAMPLES::
2476
2477
sage: Partition([1]).character_polynomial()
2478
x - 1
2479
sage: Partition([1,1]).character_polynomial()
2480
1/2*x0^2 - 3/2*x0 - x1 + 1
2481
sage: Partition([2,1]).character_polynomial()
2482
1/3*x0^3 - 2*x0^2 + 8/3*x0 - x2
2483
"""
2484
2485
#Create the polynomial ring we will use
2486
k = self.size()
2487
P = PolynomialRing(QQ, k, 'x')
2488
x = P.gens()
2489
2490
#Expand s_mu in the power sum basis
2491
import sf.sfa
2492
s = sf.sfa.SFASchur(QQ)
2493
p = sf.sfa.SFAPower(QQ)
2494
ps_mu = p(s(self))
2495
2496
#Replace each p_i by i*x_i-1
2497
items = ps_mu.monomial_coefficients().items() #items contains a list of (partition, coeff) pairs
2498
partition_to_monomial = lambda part: prod([ (i*x[i-1]-1) for i in part ])
2499
res = [ [partition_to_monomial(mc[0]), mc[1]] for mc in items ]
2500
2501
#Write things in the monomial basis
2502
res = [ prod(pair) for pair in res ]
2503
res = sum( res )
2504
2505
#Apply the umbral operator and return the result
2506
return misc.umbral_operation(res)
2507
2508
2509
##################################################
2510
2511
def number_of_partitions_list(n,k=None):
2512
r"""
2513
This function will be deprecated in a future version of Sage and
2514
eventually removed. Use Partitions(n).cardinality() or Partitions(n,
2515
length=k).cardinality() instead.
2516
2517
Original docstring follows.
2518
2519
Returns the size of partitions_list(n,k).
2520
2521
Wraps GAP's NrPartitions.
2522
2523
It is possible to associate with every partition of the integer n a
2524
conjugacy class of permutations in the symmetric group on n points
2525
and vice versa. Therefore p(n) = NrPartitions(n) is the number of
2526
conjugacy classes of the symmetric group on n points.
2527
2528
``number_of_partitions(n)`` is also available in
2529
PARI, however the speed seems the same until `n` is in the
2530
thousands (in which case PARI is faster).
2531
2532
EXAMPLES::
2533
2534
sage: partition.number_of_partitions_list(10,2)
2535
5
2536
sage: partition.number_of_partitions_list(10)
2537
42
2538
2539
A generating function for p(n) is given by the reciprocal of
2540
Euler's function:
2541
2542
.. math::
2543
2544
\sum_{n=0}^\infty p(n)x^n = \prod_{k=1}^\infty \left(\frac {1}{1-x^k} \right).
2545
2546
2547
Sage verifies that the first several coefficients do instead
2548
agree::
2549
2550
sage: q = PowerSeriesRing(QQ, 'q', default_prec=9).gen()
2551
sage: prod([(1-q^k)^(-1) for k in range(1,9)]) ## partial product of
2552
1 + q + 2*q^2 + 3*q^3 + 5*q^4 + 7*q^5 + 11*q^6 + 15*q^7 + 22*q^8 + O(q^9)
2553
sage: [partition.number_of_partitions_list(k) for k in range(2,10)]
2554
[2, 3, 5, 7, 11, 15, 22, 30]
2555
2556
REFERENCES:
2557
2558
- http://en.wikipedia.org/wiki/Partition\_(number\_theory)
2559
"""
2560
if k is None:
2561
ans=gap.eval("NrPartitions(%s)"%(ZZ(n)))
2562
else:
2563
ans=gap.eval("NrPartitions(%s,%s)"%(ZZ(n),ZZ(k)))
2564
return ZZ(ans)
2565
2566
2567
######################
2568
# Ordered Partitions #
2569
######################
2570
def OrderedPartitions(n, k=None):
2571
"""
2572
Returns the combinatorial class of ordered partitions of n. If k is
2573
specified, then only the ordered partitions of length k are
2574
returned.
2575
2576
.. note::
2577
2578
It is recommended that you use Compositions instead as
2579
OrderedPartitions wraps GAP. See also ordered_partitions.
2580
2581
EXAMPLES::
2582
2583
sage: OrderedPartitions(3)
2584
Ordered partitions of 3
2585
sage: OrderedPartitions(3).list()
2586
[[3], [2, 1], [1, 2], [1, 1, 1]]
2587
sage: OrderedPartitions(3,2)
2588
Ordered partitions of 3 of length 2
2589
sage: OrderedPartitions(3,2).list()
2590
[[2, 1], [1, 2]]
2591
"""
2592
return OrderedPartitions_nk(n,k)
2593
2594
class OrderedPartitions_nk(CombinatorialClass):
2595
def __init__(self, n, k=None):
2596
"""
2597
EXAMPLES::
2598
2599
sage: o = OrderedPartitions(4,2)
2600
sage: o == loads(dumps(o))
2601
True
2602
"""
2603
self.n = n
2604
self.k = k
2605
2606
def __contains__(self, x):
2607
"""
2608
EXAMPLES::
2609
2610
sage: o = OrderedPartitions(4,2)
2611
sage: [2,1] in o
2612
False
2613
sage: [2,2] in o
2614
True
2615
sage: [1,2,1] in o
2616
False
2617
"""
2618
return x in composition.Compositions(self.n, length=self.k)
2619
2620
def __repr__(self):
2621
"""
2622
EXAMPLES::
2623
2624
sage: OrderedPartitions(3).__repr__()
2625
'Ordered partitions of 3'
2626
sage: OrderedPartitions(3,2).__repr__()
2627
'Ordered partitions of 3 of length 2'
2628
"""
2629
string = "Ordered partitions of %s"%self.n
2630
if self.k is not None:
2631
string += " of length %s"%self.k
2632
return string
2633
2634
def list(self):
2635
"""
2636
EXAMPLES::
2637
2638
sage: OrderedPartitions(3).list()
2639
[[3], [2, 1], [1, 2], [1, 1, 1]]
2640
sage: OrderedPartitions(3,2).list()
2641
[[2, 1], [1, 2]]
2642
"""
2643
n = self.n
2644
k = self.k
2645
if self.k is None:
2646
ans=gap.eval("OrderedPartitions(%s)"%(ZZ(n)))
2647
else:
2648
ans=gap.eval("OrderedPartitions(%s,%s)"%(ZZ(n),ZZ(k)))
2649
result = eval(ans.replace('\n',''))
2650
result.reverse()
2651
return result
2652
2653
def cardinality(self):
2654
"""
2655
EXAMPLES::
2656
2657
sage: OrderedPartitions(3).cardinality()
2658
4
2659
sage: OrderedPartitions(3,2).cardinality()
2660
2
2661
"""
2662
n = self.n
2663
k = self.k
2664
if k is None:
2665
ans=gap.eval("NrOrderedPartitions(%s)"%(n))
2666
else:
2667
ans=gap.eval("NrOrderedPartitions(%s,%s)"%(n,k))
2668
return ZZ(ans)
2669
2670
##########################
2671
# Partitions Greatest LE #
2672
##########################
2673
class PartitionsGreatestLE(IntegerListsLex):
2674
"""
2675
Returns the combinatorial class of all (unordered) "restricted"
2676
partitions of the integer n having parts less than or equal to the
2677
integer k.
2678
2679
EXAMPLES::
2680
2681
sage: PartitionsGreatestLE(10,2)
2682
Partitions of 10 having parts less than or equal to 2
2683
sage: PartitionsGreatestLE(10,2).list()
2684
[[2, 2, 2, 2, 2],
2685
[2, 2, 2, 2, 1, 1],
2686
[2, 2, 2, 1, 1, 1, 1],
2687
[2, 2, 1, 1, 1, 1, 1, 1],
2688
[2, 1, 1, 1, 1, 1, 1, 1, 1],
2689
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
2690
2691
sage: [4,3,2,1] in PartitionsGreatestLE(10,2)
2692
False
2693
sage: [2,2,2,2,2] in PartitionsGreatestLE(10,2)
2694
True
2695
sage: PartitionsGreatestLE(10,2).first().parent()
2696
Partitions...
2697
"""
2698
2699
def __init__(self, n, k):
2700
"""
2701
TESTS::
2702
2703
sage: p = PartitionsGreatestLE(10,2)
2704
sage: p == loads(dumps(p))
2705
True
2706
sage: p.n, p.k
2707
(10, 2)
2708
"""
2709
IntegerListsLex.__init__(self, n, max_slope = 0, min_part=1, max_part = k)
2710
self.k = k
2711
2712
def _repr_(self):
2713
"""
2714
TESTS::
2715
2716
sage: PartitionsGreatestLE(10, 2).__repr__()
2717
'Partitions of 10 having parts less than or equal to 2'
2718
"""
2719
return "Partitions of %s having parts less than or equal to %s"%(self.n, self.k)
2720
2721
_element_constructor_ = Partition_class
2722
2723
# For unpickling PartitionsGreatestLE objects created with sage <= 3.4.1
2724
class PartitionsGreatestLE_nk(PartitionsGreatestLE):
2725
def __setstate__(self, data):
2726
r"""
2727
TESTS::
2728
2729
sage: p = loads('x\x9c\x85\x8e\xbd\xaa\xc2@\x10\x85\x89\xff.>\xc4\x94\xda\x04\x15|\x04\xb1\xb1\x90\x0b[\x87I\x18\x935\xc9\xae\xb33\xda\t\xd7\xc2\xf76"biw\x0e\x9c\x9f\xef\xbfW\x08\x96\x94\x16\xa1\xcd\x9dGM\xcf\x18\xd5\xa9\x0b\xde\x1c>Jv\x91PIt\xbf\xcd|m8Y\xdc\xb9w\xe3\xfe\xdc&\xf5\xbb\x1d\x9d/%u^\xa9\xa4hZ\xac)\xfb\x18\x1e\xd8d\xfd\xf8\xe3\xa1\x1df\x1e[\xe2\x91\xdd|\x97!\x1ca\xb5\x84\n\xaf\xdd\x02\xbc\xbe\x05\x1a\x12\x01\xad\xd0C\x88@|\xc1\x064\xc0\x9a\xc7v\x16\xf2\x13\x15\x9a\x15\r\x8a\xf0\xe47\xf9;ixj\x13_u \xd8\x81\x98K\x9e>\x01\x13iVH')
2730
sage: p == PartitionsGreatestLE(10,2)
2731
True
2732
"""
2733
self.__class__ = PartitionsGreatestLE
2734
self.__init__(data['n'], data['k'])
2735
2736
##########################
2737
# Partitions Greatest EQ #
2738
##########################
2739
class PartitionsGreatestEQ(IntegerListsLex):
2740
"""
2741
Returns combinatorial class of all (unordered) "restricted"
2742
partitions of the integer n having its greatest part equal to the
2743
integer k.
2744
2745
EXAMPLES::
2746
2747
sage: PartitionsGreatestEQ(10,2)
2748
Partitions of 10 having greatest part equal to 2
2749
sage: PartitionsGreatestEQ(10,2).list()
2750
[[2, 2, 2, 2, 2],
2751
[2, 2, 2, 2, 1, 1],
2752
[2, 2, 2, 1, 1, 1, 1],
2753
[2, 2, 1, 1, 1, 1, 1, 1],
2754
[2, 1, 1, 1, 1, 1, 1, 1, 1]]
2755
2756
sage: [4,3,2,1] in PartitionsGreatestEQ(10,2)
2757
False
2758
sage: [2,2,2,2,2] in PartitionsGreatestEQ(10,2)
2759
True
2760
sage: [1]*10 in PartitionsGreatestEQ(10,2)
2761
False
2762
2763
sage: PartitionsGreatestEQ(10,2).first().parent()
2764
Partitions...
2765
2766
"""
2767
2768
def __init__(self, n, k):
2769
"""
2770
TESTS::
2771
2772
sage: p = PartitionsGreatestEQ(10,2)
2773
sage: p == loads(dumps(p))
2774
True
2775
sage: p.n, p.k
2776
(10, 2)
2777
"""
2778
IntegerListsLex.__init__(self, n, max_slope = 0, max_part=k, floor = [k])
2779
self.k = k
2780
2781
def _repr_(self):
2782
"""
2783
TESTS::
2784
2785
sage: PartitionsGreatestEQ(10,2).__repr__()
2786
'Partitions of 10 having greatest part equal to 2'
2787
"""
2788
return "Partitions of %s having greatest part equal to %s"%(self.n, self.k)
2789
2790
_element_constructor_ = Partition_class
2791
2792
# For unpickling PartitionsGreatestLE objects created with sage <= 3.4.1
2793
class PartitionsGreatestEQ_nk(PartitionsGreatestEQ):
2794
def __setstate__(self, data):
2795
r"""
2796
TESTS::
2797
2798
sage: p = loads('x\x9c\x85\x8e\xbd\x0e\x820\x14\x85\x03\x8a?\x8d\x0f\xd1Q\x97\x06y\x07\xe3\xaa&\x9d\xc9\xa5\xb9\x96\n\xb4^Z\xdcLt\xf0\xbd\xc5 qt;\'9?\xdf#V\x1e4\n\xe5\x9a\xc2X\x08\xe2\nm0\xc18\xcb\x0e\xa3\xf2\xfb\x16!\xa0\x0f\xbbcn+F\xd1\xe6I\xf1\x9d&k\x19UC\xbb5V{al@\x8d-k\xa0\xc2|44\x95Q\xf6:Q"\x93\xdcB\x834\x93\xe9o\x99\xbb3\xdf\xa6\xbc\x84[\xbf\xc0\xf5\xf7\x87\x7f 8R\x075\x0f\x8eg4\x97+W\\P\x85\\\xd5\xe0=-\xfeC\x0fIFK\x19\xd9\xb2g\x80\x9e\x81u\x85x\x03w\x0eT\xb1')
2799
sage: p == PartitionsGreatestEQ(10,2)
2800
True
2801
"""
2802
self.__class__ = PartitionsGreatestEQ
2803
self.__init__(data['n'], data['k'])
2804
2805
#########################
2806
# Restricted Partitions #
2807
#########################
2808
def RestrictedPartitions(n, S, k=None):
2809
r"""
2810
This function has been deprecated and will be removed in a
2811
future version of Sage; use Partitions() with the ``parts_in``
2812
keyword.
2813
2814
Original docstring follows.
2815
2816
A restricted partition is, like an ordinary partition, an unordered
2817
sum `n = p_1+p_2+\ldots+p_k` of positive integers and is
2818
represented by the list `p = [p_1,p_2,\ldots,p_k]`, in
2819
nonincreasing order. The difference is that here the `p_i`
2820
must be elements from the set `S`, while for ordinary
2821
partitions they may be elements from `[1..n]`.
2822
2823
Returns the list of all restricted partitions of the positive
2824
integer n into sums with k summands with the summands of the
2825
partition coming from the set S. If k is not given all restricted
2826
partitions for all k are returned.
2827
2828
Wraps GAP's RestrictedPartitions.
2829
2830
EXAMPLES::
2831
2832
sage: RestrictedPartitions(5,[3,2,1])
2833
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2834
doctest:...: DeprecationWarning: RestrictedPartitions_nsk is deprecated; use Partitions with the parts_in keyword instead.
2835
Partitions of 5 restricted to the values [1, 2, 3]
2836
sage: RestrictedPartitions(5,[3,2,1]).list()
2837
[[3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
2838
sage: RestrictedPartitions(5,[3,2,1],4)
2839
Partitions of 5 restricted to the values [1, 2, 3] of length 4
2840
sage: RestrictedPartitions(5,[3,2,1],4).list()
2841
[[2, 1, 1, 1]]
2842
"""
2843
import warnings
2844
warnings.resetwarnings()
2845
warnings.warn('RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.', DeprecationWarning, stacklevel=2)
2846
from sage.misc.misc import deprecation
2847
deprecation('RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.')
2848
return RestrictedPartitions_nsk(n, S, k)
2849
2850
class RestrictedPartitions_nsk(CombinatorialClass):
2851
r"""
2852
We are deprecating RestrictedPartitions, so this class should
2853
be deprecated too.
2854
2855
"""
2856
def __init__(self, n, S, k=None):
2857
"""
2858
TESTS::
2859
2860
sage: r = RestrictedPartitions(5,[3,2,1])
2861
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2862
sage: r == loads(dumps(r))
2863
True
2864
"""
2865
import warnings
2866
warnings.resetwarnings()
2867
warnings.warn('RestrictedPartitions_nsk is deprecated; use Partitions with the parts_in keyword instead.', DeprecationWarning, stacklevel=2)
2868
from sage.misc.misc import deprecation
2869
deprecation('RestrictedPartitions_nsk is deprecated; use Partitions with the parts_in keyword instead.')
2870
self.n = n
2871
self.S = S
2872
self.S.sort()
2873
self.k = k
2874
2875
Element = Partition_class
2876
2877
def __contains__(self, x):
2878
"""
2879
EXAMPLES::
2880
2881
sage: [4,1] in RestrictedPartitions(5,[3,2,1])
2882
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2883
False
2884
sage: [3,2] in RestrictedPartitions(5,[3,2,1])
2885
True
2886
sage: [3,2] in RestrictedPartitions(5,[3,2,1],4)
2887
False
2888
sage: [2,1,1,1] in RestrictedPartitions(5,[3,2,1],4)
2889
True
2890
"""
2891
return x in Partitions_n(self.n) and all(i in self.S for i in x) \
2892
and (self.k is None or len(x) == self.k)
2893
2894
def __repr__(self):
2895
"""
2896
EXAMPLES::
2897
2898
sage: RestrictedPartitions(5,[3,2,1]).__repr__()
2899
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2900
'Partitions of 5 restricted to the values [1, 2, 3] '
2901
sage: RestrictedPartitions(5,[3,2,1],4).__repr__()
2902
'Partitions of 5 restricted to the values [1, 2, 3] of length 4'
2903
"""
2904
string = "Partitions of %s restricted to the values %s "%(self.n, self.S)
2905
if self.k is not None:
2906
string += "of length %s" % self.k
2907
return string
2908
2909
def list(self):
2910
r"""
2911
Returns the list of all restricted partitions of the positive
2912
integer n into sums with k summands with the summands of the
2913
partition coming from the set `S`. If k is not given all
2914
restricted partitions for all k are returned.
2915
2916
Wraps GAP's RestrictedPartitions.
2917
2918
EXAMPLES::
2919
2920
sage: RestrictedPartitions(8,[1,3,5,7]).list()
2921
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2922
[[7, 1], [5, 3], [5, 1, 1, 1], [3, 3, 1, 1], [3, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]]
2923
sage: RestrictedPartitions(8,[1,3,5,7],2).list()
2924
[[7, 1], [5, 3]]
2925
"""
2926
n = self.n
2927
k = self.k
2928
S = self.S
2929
if k is None:
2930
ans=gap.eval("RestrictedPartitions(%s,%s)"%(n,S))
2931
else:
2932
ans=gap.eval("RestrictedPartitions(%s,%s,%s)"%(n,S,k))
2933
result = eval(ans)
2934
result.reverse()
2935
return [Partition(p) for p in result]
2936
2937
def cardinality(self):
2938
"""
2939
Returns the size of RestrictedPartitions(n,S,k). Wraps GAP's
2940
NrRestrictedPartitions.
2941
2942
EXAMPLES::
2943
2944
sage: RestrictedPartitions(8,[1,3,5,7]).cardinality()
2945
doctest:...: DeprecationWarning: RestrictedPartitions is deprecated; use Partitions with the parts_in keyword instead.
2946
6
2947
sage: RestrictedPartitions(8,[1,3,5,7],2).cardinality()
2948
2
2949
"""
2950
n = self.n
2951
k = self.k
2952
S = self.S
2953
if k is None:
2954
ans=gap.eval("NrRestrictedPartitions(%s,%s)"%(ZZ(n),S))
2955
else:
2956
ans=gap.eval("NrRestrictedPartitions(%s,%s,%s)"%(ZZ(n),S,ZZ(k)))
2957
return ZZ(ans)
2958
2959
####################
2960
# Partition Tuples #
2961
####################
2962
def PartitionTuples(n,k):
2963
"""
2964
Returns the combinatorial class of k-tuples of partitions of n.
2965
These are are ordered list of k partitions whose sizes add up to
2966
2967
TODO: reimplement in term of species.ProductSpecies and Partitions
2968
2969
These describe the classes and the characters of wreath products of
2970
groups with k conjugacy classes with the symmetric group
2971
`S_n`.
2972
2973
EXAMPLES::
2974
2975
sage: PartitionTuples(4,2)
2976
2-tuples of partitions of 4
2977
sage: PartitionTuples(3,2).list()
2978
[[[3], []],
2979
[[2, 1], []],
2980
[[1, 1, 1], []],
2981
[[2], [1]],
2982
[[1, 1], [1]],
2983
[[1], [2]],
2984
[[1], [1, 1]],
2985
[[], [3]],
2986
[[], [2, 1]],
2987
[[], [1, 1, 1]]]
2988
"""
2989
return PartitionTuples_nk(n,k)
2990
2991
class PartitionTuples_nk(CombinatorialClass):
2992
def __init__(self, n, k):
2993
"""
2994
TESTS::
2995
2996
sage: p = PartitionTuples(4,2)
2997
sage: p == loads(dumps(p))
2998
True
2999
"""
3000
self.n = n
3001
self.k = k
3002
3003
Element = Partition_class
3004
3005
3006
def __contains__(self, x):
3007
"""
3008
EXAMPLES::
3009
3010
sage: [[], [1, 1, 1]] in PartitionTuples(3,2)
3011
True
3012
sage: [[1], [1, 1, 1]] in PartitionTuples(3,2)
3013
False
3014
"""
3015
p = Partitions_all()
3016
return len(x) == self.k and all(i in p for i in x)\
3017
and sum(sum(i) for i in x) == self.n
3018
3019
def __repr__(self):
3020
"""
3021
EXAMPLES::
3022
3023
sage: PartitionTuples(4,2).__repr__()
3024
'2-tuples of partitions of 4'
3025
"""
3026
return "%s-tuples of partitions of %s"%(self.k, self.n)
3027
3028
def __iter__(self):
3029
r"""
3030
Returns an iterator for all k-tuples of partitions which together
3031
form a partition of n.
3032
3033
EXAMPLES::
3034
3035
sage: PartitionTuples(2,0).list() #indirect doctest
3036
[]
3037
sage: PartitionTuples(2,1).list() #indirect doctest
3038
[[[2]], [[1, 1]]]
3039
sage: PartitionTuples(2,2).list() #indirect doctest
3040
[[[2], []], [[1, 1], []], [[1], [1]], [[], [2]], [[], [1, 1]]]
3041
sage: PartitionTuples(3,2).list() #indirect doctest
3042
[[[3], []], [[2, 1], []], [[1, 1, 1], []], [[2], [1]], [[1, 1], [1]], [[1], [2]], [[1], [1, 1]], [[], [3]], [[], [2, 1]], [[], [1, 1, 1]]]
3043
"""
3044
p = [Partitions(i) for i in range(self.n+1)]
3045
for iv in IntegerVectors(self.n,self.k):
3046
for cp in CartesianProduct(*[p[i] for i in iv]):
3047
yield cp
3048
3049
3050
def cardinality(self):
3051
r"""
3052
Returns the number of k-tuples of partitions which together form a
3053
partition of n.
3054
3055
Wraps GAP's NrPartitionTuples.
3056
3057
EXAMPLES::
3058
3059
sage: PartitionTuples(3,2).cardinality()
3060
10
3061
sage: PartitionTuples(8,2).cardinality()
3062
185
3063
3064
Now we compare that with the result of the following GAP
3065
computation::
3066
3067
gap> S8:=Group((1,2,3,4,5,6,7,8),(1,2));
3068
Group([ (1,2,3,4,5,6,7,8), (1,2) ])
3069
gap> C2:=Group((1,2));
3070
Group([ (1,2) ])
3071
gap> W:=WreathProduct(C2,S8);
3072
<permutation group of size 10321920 with 10 generators>
3073
gap> Size(W);
3074
10321920 ## = 2^8*Factorial(8), which is good:-)
3075
gap> Size(ConjugacyClasses(W));
3076
185
3077
"""
3078
return ZZ(gp.eval('polcoeff(1/eta(x)^%s, %s, x)'%(self.k, self.n)))
3079
3080
3081
##############
3082
# Partitions #
3083
##############
3084
3085
def Partitions(n=None, **kwargs):
3086
"""
3087
Partitions(n, \*\*kwargs) returns the combinatorial class of
3088
integer partitions of `n`, subject to the constraints given by the
3089
keywords.
3090
3091
Valid keywords are: ``starting``, ``ending``, ``min_part``,
3092
``max_part``, ``max_length``, ``min_length``, ``length``,
3093
``max_slope``, ``min_slope``, ``inner``, ``outer``, and
3094
``parts_in``. They have the following meanings:
3095
3096
- ``starting=p`` specifies that the partitions should all be greater
3097
than or equal to `p` in reverse lex order.
3098
3099
- ``length=k`` specifies that the partitions have
3100
exactly `k` parts.
3101
3102
- ``min_length=k`` specifies that the partitions have
3103
at least `k` parts.
3104
3105
- ``min_part=k`` specifies that all parts of the
3106
partitions are at least `k`.
3107
3108
- ``outer=p`` specifies that the partitions
3109
be contained inside the partition `p`.
3110
3111
- ``min_slope=k`` specifies that the partitions have slope at least
3112
`k`; the slope is the difference between successive parts.
3113
3114
- ``parts_in=S`` specifies that the partitions have parts in the set
3115
`S`, which can be any sequence of positive integers.
3116
3117
The ``max_*`` versions, along with ``inner`` and ``ending``, work
3118
analogously.
3119
3120
Right now, the ``parts_in``, ``starting``, and ``ending`` keyword
3121
arguments are mutually exclusive, both of each other and of other
3122
keyword arguments. If you specify, say, ``parts_in``, all other
3123
keyword arguments will be ignored; ``starting`` and ``ending`` work
3124
the same way.
3125
3126
EXAMPLES: If no arguments are passed, then the combinatorial class
3127
of all integer partitions is returned.
3128
3129
::
3130
3131
sage: Partitions()
3132
Partitions
3133
sage: [2,1] in Partitions()
3134
True
3135
3136
If an integer `n` is passed, then the combinatorial class of integer
3137
partitions of `n` is returned.
3138
3139
::
3140
3141
sage: Partitions(3)
3142
Partitions of the integer 3
3143
sage: Partitions(3).list()
3144
[[3], [2, 1], [1, 1, 1]]
3145
3146
If ``starting=p`` is passed, then the combinatorial class of partitions
3147
greater than or equal to `p` in lexicographic order is returned.
3148
3149
::
3150
3151
sage: Partitions(3, starting=[2,1])
3152
Partitions of the integer 3 starting with [2, 1]
3153
sage: Partitions(3, starting=[2,1]).list()
3154
[[2, 1], [1, 1, 1]]
3155
3156
If ``ending=p`` is passed, then the combinatorial class of
3157
partitions at most `p` in lexicographic order is returned.
3158
3159
::
3160
3161
sage: Partitions(3, ending=[2,1])
3162
Partitions of the integer 3 ending with [2, 1]
3163
sage: Partitions(3, ending=[2,1]).list()
3164
[[3], [2, 1]]
3165
3166
Using ``max_slope=-1`` yields partitions into distinct parts -- each
3167
part differs from the next by at least 1. Use a different
3168
``max_slope`` to get parts that differ by, say, 2.
3169
3170
::
3171
3172
sage: Partitions(7, max_slope=-1).list()
3173
[[7], [6, 1], [5, 2], [4, 3], [4, 2, 1]]
3174
sage: Partitions(15, max_slope=-1).cardinality()
3175
27
3176
3177
The number of partitions of `n` into odd parts equals the number of
3178
partitions into distinct parts. Let's test that for `n` from 10 to 20.
3179
3180
::
3181
3182
sage: test = lambda n: Partitions(n, max_slope=-1).cardinality() == Partitions(n, parts_in=[1,3..n]).cardinality()
3183
sage: all(test(n) for n in [10..20])
3184
True
3185
3186
The number of partitions of `n` into distinct parts that differ by
3187
at least 2 equals the number of partitions into parts that equal 1
3188
or 4 modulo 5; this is one of the Rogers-Ramanujan identities.
3189
3190
::
3191
3192
sage: test = lambda n: Partitions(n, max_slope=-2).cardinality() == Partitions(n, parts_in=([1,6..n] + [4,9..n])).cardinality()
3193
sage: all(test(n) for n in [10..20])
3194
True
3195
3196
Here are some more examples illustrating ``min_part``, ``max_part``,
3197
and ``length``.
3198
3199
::
3200
3201
sage: Partitions(5,min_part=2)
3202
Partitions of the integer 5 satisfying constraints min_part=2
3203
sage: Partitions(5,min_part=2).list()
3204
[[5], [3, 2]]
3205
3206
::
3207
3208
sage: Partitions(3,max_length=2).list()
3209
[[3], [2, 1]]
3210
3211
::
3212
3213
sage: Partitions(10, min_part=2, length=3).list()
3214
[[6, 2, 2], [5, 3, 2], [4, 4, 2], [4, 3, 3]]
3215
3216
3217
Here are some further examples using various constraints::
3218
3219
sage: [x for x in Partitions(4)]
3220
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
3221
sage: [x for x in Partitions(4, length=2)]
3222
[[3, 1], [2, 2]]
3223
sage: [x for x in Partitions(4, min_length=2)]
3224
[[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
3225
sage: [x for x in Partitions(4, max_length=2)]
3226
[[4], [3, 1], [2, 2]]
3227
sage: [x for x in Partitions(4, min_length=2, max_length=2)]
3228
[[3, 1], [2, 2]]
3229
sage: [x for x in Partitions(4, max_part=2)]
3230
[[2, 2], [2, 1, 1], [1, 1, 1, 1]]
3231
sage: [x for x in Partitions(4, min_part=2)]
3232
[[4], [2, 2]]
3233
sage: [x for x in Partitions(4, outer=[3,1,1])]
3234
[[3, 1], [2, 1, 1]]
3235
sage: [x for x in Partitions(4, outer=[infinity, 1, 1])]
3236
[[4], [3, 1], [2, 1, 1]]
3237
sage: [x for x in Partitions(4, inner=[1,1,1])]
3238
[[2, 1, 1], [1, 1, 1, 1]]
3239
sage: [x for x in Partitions(4, max_slope=-1)]
3240
[[4], [3, 1]]
3241
sage: [x for x in Partitions(4, min_slope=-1)]
3242
[[4], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
3243
sage: [x for x in Partitions(11, max_slope=-1, min_slope=-3, min_length=2, max_length=4)]
3244
[[7, 4], [6, 5], [6, 4, 1], [6, 3, 2], [5, 4, 2], [5, 3, 2, 1]]
3245
sage: [x for x in Partitions(11, max_slope=-1, min_slope=-3, min_length=2, max_length=4, outer=[6,5,2])]
3246
[[6, 5], [6, 4, 1], [6, 3, 2], [5, 4, 2]]
3247
3248
Note that if you specify min_part=0, then the objects produced will have
3249
parts equal to zero which violates some internal assumptions that the
3250
Partition class makes.
3251
3252
::
3253
3254
sage: [x for x in Partitions(4, length=3, min_part=0)]
3255
doctest:... RuntimeWarning: Currently, setting min_part=0 produces Partition objects which violate internal assumptions. Calling methods on these objects may produce errors or WRONG results!
3256
[[4, 0, 0], [3, 1, 0], [2, 2, 0], [2, 1, 1]]
3257
sage: [x for x in Partitions(4, min_length=3, min_part=0)]
3258
[[4, 0, 0], [3, 1, 0], [2, 2, 0], [2, 1, 1], [1, 1, 1, 1]]
3259
3260
Except for very special cases, counting is done by brute force iteration
3261
through all the partitions. However the iteration itself has a reasonable
3262
complexity (constant memory, constant amortized time), which allow for
3263
manipulating large partitions::
3264
3265
sage: Partitions(1000, max_length=1).list()
3266
[[1000]]
3267
3268
In particular, getting the first element is also constant time::
3269
3270
sage: Partitions(30, max_part=29).first()
3271
[29, 1]
3272
3273
TESTS::
3274
3275
sage: P = Partitions(5, min_part=2)
3276
sage: P == loads(dumps(P))
3277
True
3278
3279
sage: repr( Partitions(5, min_part=2) )
3280
'Partitions of the integer 5 satisfying constraints min_part=2'
3281
3282
sage: P = Partitions(5, min_part=2)
3283
sage: P.first().parent()
3284
Partitions...
3285
sage: [2,1] in P
3286
False
3287
sage: [2,2,1] in P
3288
False
3289
sage: [3,2] in P
3290
True
3291
"""
3292
if n is None:
3293
assert(len(kwargs) == 0)
3294
return Partitions_all()
3295
else:
3296
if len(kwargs) == 0:
3297
if isinstance(n, (int,Integer)):
3298
return Partitions_n(n)
3299
else:
3300
raise ValueError, "n must be an integer"
3301
else:
3302
# FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute
3303
kwargs['name'] = "Partitions of the integer %s satisfying constraints %s"%(n, ", ".join( ["%s=%s"%(key, kwargs[key]) for key in sorted(kwargs.keys())] ))
3304
kwargs['element_constructor'] = Partition_class
3305
if 'parts_in' in kwargs:
3306
return Partitions_parts_in(n, kwargs['parts_in'])
3307
elif 'starting' in kwargs:
3308
return Partitions_starting(n, kwargs['starting'])
3309
elif 'ending' in kwargs:
3310
return Partitions_ending(n, kwargs['ending'])
3311
else:
3312
if 'min_part' not in kwargs:
3313
kwargs['min_part'] = 1
3314
elif kwargs['min_part'] == 0:
3315
from warnings import warn
3316
warn("Currently, setting min_part=0 produces Partition objects which violate internal assumptions. Calling methods on these objects may produce errors or WRONG results!", RuntimeWarning)
3317
3318
if 'max_slope' not in kwargs:
3319
kwargs['max_slope'] = 0
3320
if 'outer' in kwargs:
3321
kwargs['ceiling'] = kwargs['outer']
3322
if 'max_length' in kwargs:
3323
kwargs['max_length'] = min( len(kwargs['outer']), kwargs['max_length'])
3324
else:
3325
kwargs['max_length'] = len(kwargs['outer'])
3326
del kwargs['outer']
3327
3328
if 'inner' in kwargs:
3329
inner = kwargs['inner']
3330
kwargs['floor'] = lambda i: inner[i] if i < len(inner) else 0
3331
if 'min_length' in kwargs:
3332
kwargs['min_length'] = max( len(inner), kwargs['min_length'])
3333
else:
3334
kwargs['min_length'] = len(inner)
3335
del kwargs['inner']
3336
return IntegerListsLex(n, **kwargs)
3337
# return Partitions_constraints(n, **kwargs)
3338
3339
3340
# Allows to pickle old constrained Partitions_constraints objects.
3341
class Partitions_constraints(IntegerListsLex):
3342
def __setstate__(self, data):
3343
r"""
3344
TESTS::
3345
3346
sage: dmp = 'x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+H,*\xc9,\xc9\xcc\xcf\xe3\n\x80\xb1\x8a\xe3\x93\x81DIQbf^I1W!\xa3fc!Sm!\xb3F(7\x92x!Km!k(GnbE<\xc8\x88B6\x88\xb9E\x99y\xe9\xc5z@\x05\xa9\xe9\xa9E\\\xb9\x89\xd9\xa9\xf10N!{(\xa3QkP!Gq(c^\x06\x90c\x0c\xe4p\x96&\xe9\x01\x00\xc2\xe53\xfd'
3347
sage: sp = loads(dmp); sp
3348
Integer lists of sum 3 satisfying certain constraints
3349
sage: sp.list()
3350
[[2, 1], [1, 1, 1]]
3351
"""
3352
n = data['n']
3353
self.__class__ = IntegerListsLex
3354
constraints = {'max_slope' : 0,
3355
'min_part' : 1,
3356
'element_constructor' : Partition_class}
3357
constraints.update(data['constraints'])
3358
self.__init__(n, **constraints)
3359
3360
3361
class Partitions_all(InfiniteAbstractCombinatorialClass):
3362
def __init__(self):
3363
"""
3364
TESTS::
3365
3366
sage: P = Partitions()
3367
sage: P == loads(dumps(P))
3368
True
3369
"""
3370
pass
3371
3372
Element = Partition_class
3373
3374
3375
def cardinality(self):
3376
"""
3377
Returns the number of integer partitions.
3378
3379
EXAMPLES::
3380
3381
sage: Partitions().cardinality()
3382
+Infinity
3383
"""
3384
return infinity
3385
3386
def __contains__(self, x):
3387
"""
3388
TESTS::
3389
3390
sage: P = Partitions()
3391
sage: Partition([2,1]) in P
3392
True
3393
sage: [2,1] in P
3394
True
3395
sage: [3,2,1] in P
3396
True
3397
sage: [1,2] in P
3398
False
3399
sage: [] in P
3400
True
3401
sage: [0] in P
3402
False
3403
"""
3404
if isinstance(x, Partition_class):
3405
return True
3406
elif isinstance(x, __builtin__.list):
3407
for i in range(len(x)):
3408
if not isinstance(x[i], (int, Integer)):
3409
return False
3410
if x[i] <= 0:
3411
return False
3412
if i == 0:
3413
prev = x[i]
3414
continue
3415
if x[i] > prev:
3416
return False
3417
prev = x[i]
3418
return True
3419
else:
3420
return False
3421
3422
def __repr__(self):
3423
"""
3424
TESTS::
3425
3426
sage: repr(Partitions())
3427
'Partitions'
3428
"""
3429
return "Partitions"
3430
3431
def _infinite_cclass_slice(self, n):
3432
"""
3433
Needed by InfiniteAbstractCombinatorialClass to build __iter__.
3434
3435
TESTS:
3436
sage: Partitions()._infinite_cclass_slice(4) == Partitions(4)
3437
True
3438
sage: it = iter(Partitions()) # indirect doctest
3439
sage: [it.next() for i in range(10)]
3440
[[], [1], [2], [1, 1], [3], [2, 1], [1, 1, 1], [4], [3, 1], [2, 2]]
3441
"""
3442
return Partitions_n(n)
3443
3444
3445
3446
3447
3448
class Partitions_n(CombinatorialClass):
3449
Element = Partition_class
3450
def __init__(self, n):
3451
"""
3452
TESTS::
3453
3454
sage: p = Partitions(5)
3455
sage: p == loads(dumps(p))
3456
True
3457
"""
3458
self.n = n
3459
3460
def __contains__(self, x):
3461
"""
3462
TESTS::
3463
3464
sage: p = Partitions(5)
3465
sage: [2,1] in p
3466
False
3467
sage: [2,2,1] in p
3468
True
3469
sage: [3,2] in p
3470
True
3471
"""
3472
return x in Partitions_all() and sum(x)==self.n
3473
3474
def __repr__(self):
3475
"""
3476
TESTS::
3477
3478
sage: repr( Partitions(5) )
3479
'Partitions of the integer 5'
3480
"""
3481
return "Partitions of the integer %s"%self.n
3482
3483
def _an_element_(self):
3484
"""
3485
Returns a partition in ``self``.
3486
3487
EXAMPLES::
3488
3489
sage: Partitions(4)._an_element_()
3490
[3, 1]
3491
sage: Partitions(0)._an_element_()
3492
[]
3493
sage: Partitions(1)._an_element_()
3494
[1]
3495
"""
3496
if self.n == 0:
3497
lst = []
3498
elif self.n == 1:
3499
lst = [1]
3500
else:
3501
lst = [self.n-1, 1]
3502
return self._element_constructor_(lst)
3503
3504
def cardinality(self, algorithm='default'):
3505
r"""
3506
INPUT:
3507
3508
- ``algorithm``
3509
3510
- (default: ``default``)
3511
3512
- ``'bober'`` - use Jonathan Bober's implementation (*very*
3513
fast, but relatively new)
3514
3515
- ``'gap'`` - use GAP (VERY *slow*)
3516
3517
- ``'pari'`` - use PARI. Speed seems the same as GAP until
3518
`n` is in the thousands, in which case PARI is faster.
3519
3520
- ``'default'`` - ``'bober'`` when k is not specified;
3521
otherwise use ``'gap'``.
3522
3523
Use the function ``partitions(n)`` to return a
3524
generator over all partitions of `n`.
3525
3526
It is possible to associate with every partition of the integer n a
3527
conjugacy class of permutations in the symmetric group on n points
3528
and vice versa. Therefore p(n) = NrPartitions(n) is the number of
3529
conjugacy classes of the symmetric group on n points.
3530
3531
EXAMPLES::
3532
3533
sage: v = Partitions(5).list(); v
3534
[[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
3535
sage: len(v)
3536
7
3537
sage: Partitions(5).cardinality(algorithm='gap')
3538
7
3539
sage: Partitions(5).cardinality(algorithm='pari')
3540
7
3541
sage: Partitions(5).cardinality(algorithm='bober')
3542
7
3543
3544
The input must be a nonnegative integer or a ValueError is raised.
3545
3546
::
3547
3548
sage: Partitions(10).cardinality()
3549
42
3550
sage: Partitions(3).cardinality()
3551
3
3552
sage: Partitions(10).cardinality()
3553
42
3554
sage: Partitions(3).cardinality(algorithm='pari')
3555
3
3556
sage: Partitions(10).cardinality(algorithm='pari')
3557
42
3558
sage: Partitions(40).cardinality()
3559
37338
3560
sage: Partitions(100).cardinality()
3561
190569292
3562
3563
A generating function for p(n) is given by the reciprocal of
3564
Euler's function:
3565
3566
3567
.. math::
3568
3569
\sum_{n=0}^\infty p(n)x^n = \prod_{k=1}^\infty \left(\frac {1}{1-x^k} \right).
3570
3571
3572
3573
We use Sage to verify that the first several coefficients do
3574
instead agree::
3575
3576
sage: q = PowerSeriesRing(QQ, 'q', default_prec=9).gen()
3577
sage: prod([(1-q^k)^(-1) for k in range(1,9)]) ## partial product of
3578
1 + q + 2*q^2 + 3*q^3 + 5*q^4 + 7*q^5 + 11*q^6 + 15*q^7 + 22*q^8 + O(q^9)
3579
sage: [Partitions(k) .cardinality()for k in range(2,10)]
3580
[2, 3, 5, 7, 11, 15, 22, 30]
3581
3582
REFERENCES:
3583
3584
- http://en.wikipedia.org/wiki/Partition\_(number\_theory)
3585
"""
3586
return number_of_partitions(self.n, algorithm=algorithm)
3587
3588
3589
def random_element(self, measure = 'uniform'):
3590
"""
3591
Returns a random partitions of `n` for the specified measure.
3592
3593
INPUT:
3594
3595
- ``measure`` -
3596
3597
- ``uniform`` - (default) pick a element for the uniform mesure.
3598
see :meth:`random_element_uniform`
3599
3600
- ``Plancherel`` - use plancherel measure.
3601
see :meth:`random_element_plancherel`
3602
3603
EXAMPLES::
3604
3605
sage: Partitions(5).random_element() # random
3606
[2, 1, 1, 1]
3607
sage: Partitions(5).random_element(measure='Plancherel') # random
3608
[2, 1, 1, 1]
3609
"""
3610
if measure == 'uniform':
3611
return self.random_element_uniform()
3612
elif measure == 'Plancherel':
3613
return self.random_element_plancherel()
3614
else:
3615
raise ValueError("Unkown measure: %s"%(measure))
3616
3617
def random_element_uniform(self):
3618
"""
3619
Returns a random partitions of `n` with uniform probability.
3620
3621
EXAMPLES::
3622
3623
sage: Partitions(5).random_element_uniform() # random
3624
[2, 1, 1, 1]
3625
sage: Partitions(20).random_element_uniform() # random
3626
[9, 3, 3, 2, 2, 1]
3627
3628
TESTS::
3629
3630
sage: all(Part.random_element_uniform() in Part
3631
... for Part in map(Partitions, range(10)))
3632
True
3633
3634
ALGORITHM:
3635
3636
- It is a python Implementation of RANDPAR, see [nw] below. The
3637
complexity is unkown, there may be better algorithms. TODO: Check
3638
in Knuth AOCP4.
3639
3640
- There is also certainly a lot of room for optimizations, see
3641
comments in the code.
3642
3643
REFERENCES:
3644
3645
- [nw] Nijenhuis, Wilf, Combinatorial Algorithms, Academic Press (1978).
3646
3647
AUTHOR:
3648
3649
- Florent Hivert (2009-11-23)
3650
"""
3651
n = self.n
3652
res = [] # A dictionary of multiplicities could be faster.
3653
while n > 0:
3654
# Choose a pair d,j = 1,2..., with d*j <= n with probability
3655
# d*numpart(n-d*j) / n / numpart(n)
3656
# and add d^j to the result partition. The resulting partitions is
3657
# equiprobable.
3658
3659
# The following could be made faster by a clever use of floats
3660
rand = randrange(0, n*_numpart(n)) # cached number_of_partition
3661
3662
# It is better to start by the j = 1 pairs because they are the
3663
# most probable. Maybe there is an even more clever order.
3664
for j in range(1, n+1):
3665
d = 1
3666
r = n-j # n - d*j
3667
while r >= 0:
3668
rand -= d * _numpart(r)
3669
if rand < 0: break
3670
d +=1
3671
r -= j
3672
else:
3673
continue
3674
break
3675
res.extend([d]*j)
3676
n = r
3677
res.sort(reverse=True)
3678
return Partition(res)
3679
3680
def random_element_plancherel(self):
3681
"""
3682
Returns a random partitions of `n`.
3683
3684
EXAMPLES::
3685
3686
sage: Partitions(5).random_element_plancherel() # random
3687
[2, 1, 1, 1]
3688
sage: Partitions(20).random_element_plancherel() # random
3689
[9, 3, 3, 2, 2, 1]
3690
3691
TESTS::
3692
3693
sage: all(Part.random_element_plancherel() in Part
3694
... for Part in map(Partitions, range(10)))
3695
True
3696
3697
ALGORITHM:
3698
3699
- insert by robinson-schensted a uniform random permutations of n and
3700
returns the shape of the resulting tableau. The complexity is
3701
`O(n\ln(n))` which is likely optimal. However, the implementation
3702
could be optimized.
3703
3704
AUTHOR:
3705
3706
- Florent Hivert (2009-11-23)
3707
"""
3708
return permutation.Permutations(self.n).random_element().left_tableau().shape()
3709
3710
def first(self):
3711
"""
3712
Returns the lexicographically first partition of a positive integer
3713
n. This is the partition [n].
3714
3715
EXAMPLES::
3716
3717
sage: Partitions(4).first()
3718
[4]
3719
"""
3720
return Partition([self.n])
3721
3722
def last(self):
3723
"""
3724
Returns the lexicographically last partition of the positive
3725
integer n. This is the all-ones partition.
3726
3727
EXAMPLES::
3728
3729
sage: Partitions(4).last()
3730
[1, 1, 1, 1]
3731
"""
3732
3733
return Partition_class([1]*self.n)
3734
3735
3736
def __iter__(self):
3737
"""
3738
An iterator for the partitions of n.
3739
3740
EXAMPLES::
3741
3742
sage: [x for x in Partitions(4)]
3743
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
3744
"""
3745
for p in self._fast_iterator():
3746
yield Partition_class(p)
3747
3748
3749
def _fast_iterator(self):
3750
"""
3751
A fast iterator for the partitions of n which returns lists and not
3752
partition types.
3753
3754
EXAMPLES::
3755
3756
sage: p = Partitions(4)
3757
sage: it = p._fast_iterator()
3758
sage: it.next()
3759
[4]
3760
sage: type(_)
3761
<type 'list'>
3762
sage: Partitions(-1).list()
3763
[]
3764
"""
3765
# If n is less than 0, there are no partitions
3766
if self.n < 0:
3767
return
3768
3769
# base case of the recursion: zero is the sum of the empty tuple
3770
if self.n == 0:
3771
yield []
3772
return
3773
3774
# modify the partitions of n-1 to form the partitions of n
3775
for p in Partitions_n(self.n-1)._fast_iterator():
3776
if p and (len(p) < 2 or p[-2] > p[-1]):
3777
yield p[:-1] + [p[-1] + 1]
3778
yield p + [1]
3779
3780
3781
class Partitions_parts_in(CombinatorialClass):
3782
Element = Partition_class
3783
def __init__(self, n, parts):
3784
"""
3785
TESTS::
3786
3787
sage: p = Partitions(5, parts_in=[1,2,3])
3788
sage: p == loads(dumps(p))
3789
True
3790
"""
3791
self.n = ZZ(n)
3792
self.parts = sorted(parts)
3793
3794
def __contains__(self, x):
3795
"""
3796
TESTS::
3797
3798
sage: p = Partitions(5, parts_in=[1,2])
3799
sage: [2,1,1,1] in p
3800
True
3801
sage: [4,1] in p
3802
False
3803
"""
3804
return (x in Partitions_all() and sum(x) == self.n and
3805
all(p in self.parts for p in x))
3806
3807
def __repr__(self):
3808
"""
3809
TESTS::
3810
3811
sage: repr(Partitions(5, parts_in=[1,2,3]))
3812
'Partitions of the integer 5 with parts in [1, 2, 3]'
3813
"""
3814
return "Partitions of the integer %s with parts in %s" % (self.n, self.parts)
3815
3816
def cardinality(self):
3817
r"""
3818
Return the number of partitions with parts in `S`. Wraps GAP's
3819
``NrRestrictedPartitions``.
3820
3821
EXAMPLES::
3822
3823
sage: Partitions(15, parts_in=[2,3,7]).cardinality()
3824
5
3825
3826
If you can use all parts 1 through `n`, we'd better get `p(n)`::
3827
3828
sage: Partitions(20, parts_in=[1..20]).cardinality() == Partitions(20).cardinality()
3829
True
3830
3831
TESTS:
3832
3833
Let's check the consistency of GAP's function and our own
3834
algorithm that actually generates the partitions.
3835
3836
::
3837
3838
sage: ps = Partitions(15, parts_in=[1,2,3])
3839
sage: ps.cardinality() == len(ps.list())
3840
True
3841
sage: ps = Partitions(15, parts_in=[])
3842
sage: ps.cardinality() == len(ps.list())
3843
True
3844
sage: ps = Partitions(3000, parts_in=[50,100,500,1000])
3845
sage: ps.cardinality() == len(ps.list())
3846
True
3847
sage: ps = Partitions(10, parts_in=[3,6,9])
3848
sage: ps.cardinality() == len(ps.list())
3849
True
3850
sage: ps = Partitions(0, parts_in=[1,2])
3851
sage: ps.cardinality() == len(ps.list())
3852
True
3853
"""
3854
# GAP complains if you give it an empty list
3855
if self.parts:
3856
return ZZ(gap.eval("NrRestrictedPartitions(%s,%s)" % (ZZ(self.n), self.parts)))
3857
else:
3858
return Integer(self.n == 0)
3859
3860
def first(self):
3861
"""
3862
Return the lexicographically first partition of a positive
3863
integer `n` with the specified parts, or None if no such
3864
partition exists.
3865
3866
EXAMPLES::
3867
3868
sage: Partitions(9, parts_in=[3,4]).first()
3869
[3, 3, 3]
3870
sage: Partitions(6, parts_in=[1..6]).first()
3871
[6]
3872
sage: Partitions(30, parts_in=[4,7,8,10,11]).first()
3873
[11, 11, 8]
3874
"""
3875
try:
3876
return Partition_class(self._findfirst(self.n, self.parts[:]))
3877
except TypeError:
3878
return None
3879
3880
def _findfirst(self, n, parts):
3881
"""
3882
TESTS::
3883
3884
sage: p = Partitions(9, parts_in=[3,4])
3885
sage: p._findfirst(p.n, p.parts[:])
3886
[3, 3, 3]
3887
sage: p._findfirst(0, p.parts[:])
3888
[]
3889
sage: p._findfirst(p.n, [10])
3890
3891
"""
3892
if n == 0:
3893
return []
3894
else:
3895
while parts:
3896
p = parts.pop()
3897
for k in range(n.quo_rem(p)[0], 0, -1):
3898
try:
3899
return k * [p] + self._findfirst(n - k * p, parts[:])
3900
except TypeError:
3901
pass
3902
3903
def last(self):
3904
"""
3905
Returns the lexicographically last partition of the positive
3906
integer `n` with the specified parts, or None if no such
3907
partition exists.
3908
3909
EXAMPLES::
3910
3911
sage: Partitions(15, parts_in=[2,3]).last()
3912
[3, 2, 2, 2, 2, 2, 2]
3913
sage: Partitions(30, parts_in=[4,7,8,10,11]).last()
3914
[7, 7, 4, 4, 4, 4]
3915
sage: Partitions(10, parts_in=[3,6]).last() is None
3916
True
3917
sage: Partitions(50, parts_in=[11,12,13]).last()
3918
[13, 13, 12, 12]
3919
sage: Partitions(30, parts_in=[4,7,8,10,11]).last()
3920
[7, 7, 4, 4, 4, 4]
3921
3922
TESTS::
3923
3924
sage: Partitions(6, parts_in=[1..6]).last()
3925
[1, 1, 1, 1, 1, 1]
3926
sage: Partitions(0, parts_in=[]).last()
3927
[]
3928
sage: Partitions(50, parts_in=[11,12]).last() is None
3929
True
3930
"""
3931
try:
3932
return Partition_class(self._findlast(self.n, self.parts))
3933
except TypeError:
3934
return None
3935
3936
def _findlast(self, n, parts):
3937
"""
3938
Return the lexicographically largest partition of `n` using the
3939
given parts, or None if no such partition exists. This function
3940
is not intended to be called directly.
3941
3942
INPUT:
3943
3944
- ``n``: nonnegative integer
3945
- ``parts``: a sorted list of positive integers.
3946
3947
OUTPUT::
3948
3949
A list of integers in weakly decreasing order, or None. The
3950
output is just a list, not a Partition object.
3951
3952
EXAMPLES::
3953
3954
sage: ps = Partitions(1, parts_in=[1])
3955
sage: ps._findlast(15, [2,3])
3956
[3, 2, 2, 2, 2, 2, 2]
3957
sage: ps._findlast(9, [2,4]) is None
3958
True
3959
sage: ps._findlast(0, [])
3960
[]
3961
sage: ps._findlast(100, [9,17,31])
3962
[31, 17, 17, 17, 9, 9]
3963
"""
3964
if n < 0:
3965
return None
3966
elif n == 0:
3967
return []
3968
elif parts != []:
3969
p = parts[0]
3970
q, r = n.quo_rem(p)
3971
if r == 0:
3972
return [p] * q
3973
# If the smallest part doesn't divide n, try using the next
3974
# largest part
3975
else:
3976
for i, p in enumerate(parts[1:]):
3977
rest = self._findlast(n - p, parts[:i+2])
3978
if rest is not None:
3979
return [p] + rest
3980
# If we get to here, nothing ever worked, so there's no such
3981
# partitions, and we return None.
3982
return None
3983
3984
3985
def __iter__(self):
3986
"""
3987
An iterator a list of the partitions of n.
3988
3989
EXAMPLES::
3990
3991
sage: [x for x in Partitions(4)]
3992
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
3993
"""
3994
for p in self._fast_iterator(self.n, self.parts[:]):
3995
yield Partition_class(p)
3996
3997
3998
def _fast_iterator(self, n, parts):
3999
"""
4000
A fast iterator for the partitions of n which returns lists and
4001
not partition types. This function is not intended to be called
4002
directly.
4003
4004
INPUT:
4005
4006
- ``n``: nonnegative integer.
4007
4008
- ``parts``: a list of parts to use. This list will be
4009
destroyed, so pass things here with ``foo[:]`` (or something
4010
equivalent) if you want to preserve your list. In particular,
4011
the __iter__ method needs to use ``self.parts[:]``, or else we
4012
forget which parts we're using!
4013
4014
OUTPUT:
4015
4016
A generator object for partitions of `n` with parts in
4017
``parts``.
4018
4019
If the parts in ``parts`` are sorted in increasing order, this
4020
function returns weakly decreasing lists. If ``parts`` is not
4021
sorted, your lists won't be, either.
4022
4023
EXAMPLES::
4024
4025
sage: p = Partitions(4)
4026
sage: it = p._fast_iterator()
4027
sage: it.next()
4028
[4]
4029
sage: type(_)
4030
<type 'list'>
4031
"""
4032
if n == 0:
4033
yield []
4034
else:
4035
while parts:
4036
p = parts.pop()
4037
for k in range(n.quo_rem(p)[0], 0, -1):
4038
for q in self._fast_iterator(n - k * p, parts[:]):
4039
yield k * [p] + q
4040
4041
class Partitions_starting(CombinatorialClass):
4042
def __init__(self, n, starting_partition):
4043
"""
4044
EXAMPLES::
4045
4046
sage: Partitions(3, starting=[2,1])
4047
Partitions of the integer 3 starting with [2, 1]
4048
sage: Partitions(3, starting=[2,1]).list()
4049
[[2, 1], [1, 1, 1]]
4050
4051
TESTS::
4052
4053
sage: p = Partitions(3, starting=[2,1])
4054
sage: p == loads(dumps(p))
4055
True
4056
"""
4057
self.n = n
4058
self._starting = Partition(starting_partition)
4059
4060
def __repr__(self):
4061
"""
4062
EXAMPLES::
4063
4064
sage: Partitions(3, starting=[2,1]).__repr__()
4065
'Partitions of the integer 3 starting with [2, 1]'
4066
"""
4067
return "Partitions of the integer %s starting with %s"%(self.n, self._starting)
4068
4069
def __contains__(self, x):
4070
"""
4071
EXAMPLES::
4072
4073
sage: p = Partitions(3, starting=[2,1])
4074
sage: [1,1] in p
4075
False
4076
sage: [2,1] in p
4077
True
4078
sage: [1,1,1] in p
4079
True
4080
sage: [3] in p
4081
False
4082
"""
4083
return x in Partitions_n(self.n) and x <= self._starting
4084
4085
def first(self):
4086
"""
4087
EXAMPLES::
4088
4089
sage: Partitions(3, starting=[2,1]).first()
4090
[2, 1]
4091
"""
4092
return self._starting
4093
4094
def next(self, part):
4095
"""
4096
EXAMPLES::
4097
4098
sage: Partitions(3, starting=[2,1]).next(Partition([2,1]))
4099
[1, 1, 1]
4100
"""
4101
return part.next()
4102
4103
class Partitions_ending(CombinatorialClass):
4104
def __init__(self, n, ending_partition):
4105
"""
4106
EXAMPLES::
4107
4108
sage: Partitions(4, ending=[1,1,1,1]).list()
4109
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
4110
sage: Partitions(4, ending=[2,2]).list()
4111
[[4], [3, 1], [2, 2]]
4112
sage: Partitions(4, ending=[4]).list()
4113
[[4]]
4114
4115
TESTS::
4116
4117
sage: p = Partitions(4, ending=[1,1,1,1])
4118
sage: p == loads(dumps(p))
4119
True
4120
"""
4121
self.n = n
4122
self._ending = Partition(ending_partition)
4123
4124
def __repr__(self):
4125
"""
4126
EXAMPLES::
4127
4128
sage: Partitions(4, ending=[1,1,1,1]).__repr__()
4129
'Partitions of the integer 4 ending with [1, 1, 1, 1]'
4130
"""
4131
return "Partitions of the integer %s ending with %s"%(self.n, self._ending)
4132
4133
def __contains__(self, x):
4134
"""
4135
EXAMPLES::
4136
4137
sage: p = Partitions(4, ending=[2,2])
4138
sage: [4] in p
4139
True
4140
sage: [2,1,1] in p
4141
False
4142
sage: [2,1] in p
4143
False
4144
"""
4145
return x in Partitions_n(self.n) and x >= self._ending
4146
4147
def first(self):
4148
"""
4149
EXAMPLES::
4150
4151
sage: Partitions(4, ending=[1,1,1,1]).first()
4152
[4]
4153
"""
4154
return Partition_class([self.n])
4155
4156
def next(self, part):
4157
"""
4158
EXAMPLES::
4159
4160
sage: Partitions(4, ending=[1,1,1,1]).next(Partition([4]))
4161
[3, 1]
4162
sage: Partitions(4, ending=[1,1,1,1]).next(Partition([1,1,1,1])) is None
4163
True
4164
"""
4165
if part == self._ending:
4166
return None
4167
else:
4168
return part.next()
4169
4170
4171
def PartitionsInBox(h, w):
4172
"""
4173
Returns the combinatorial class of partitions that fit in a h by w
4174
box.
4175
4176
EXAMPLES::
4177
4178
sage: PartitionsInBox(2,2)
4179
Integer partitions which fit in a 2 x 2 box
4180
sage: PartitionsInBox(2,2).list()
4181
[[], [1], [1, 1], [2], [2, 1], [2, 2]]
4182
"""
4183
return PartitionsInBox_hw(h, w)
4184
4185
class PartitionsInBox_hw(CombinatorialClass):
4186
def __init__(self, h, w):
4187
"""
4188
TESTS::
4189
4190
sage: p = PartitionsInBox(2,2)
4191
sage: p == loads(dumps(p))
4192
True
4193
"""
4194
self.h = h
4195
self.w = w
4196
self._name = "Integer partitions which fit in a %s x %s box" % (self.h, self.w)
4197
4198
Element = Partition_class
4199
4200
def __contains__(self, x):
4201
"""
4202
EXAMPLES::
4203
4204
sage: [] in PartitionsInBox(2,2)
4205
True
4206
sage: [2,1] in PartitionsInBox(2,2)
4207
True
4208
sage: [3,1] in PartitionsInBox(2,2)
4209
False
4210
sage: [2,1,1] in PartitionsInBox(2,2)
4211
False
4212
"""
4213
return x in Partitions_all() and len(x) <= self.h \
4214
and (len(x) == 0 or x[0] <= self.w)
4215
4216
def list(self):
4217
"""
4218
Returns a list of all the partitions inside a box of height h and
4219
width w.
4220
4221
EXAMPLES::
4222
4223
sage: PartitionsInBox(2,2).list()
4224
[[], [1], [1, 1], [2], [2, 1], [2, 2]]
4225
4226
TESTS::
4227
4228
sage: type(PartitionsInBox(0,0)[0]) # check for 10890
4229
<class 'sage.combinat.partition.Partition_class'>
4230
"""
4231
h = self.h
4232
w = self.w
4233
if h == 0:
4234
return [Partition([])]
4235
else:
4236
l = [[i] for i in range(0, w+1)]
4237
add = lambda x: [ x+[i] for i in range(0, x[-1]+1)]
4238
for i in range(h-1):
4239
new_list = []
4240
for element in l:
4241
new_list += add(element)
4242
l = new_list
4243
4244
return [Partition(filter(lambda x: x!=0, p)) for p in l]
4245
4246
4247
#########################################################################
4248
4249
#### partitions
4250
4251
def partitions_set(S,k=None, use_file=True):
4252
r"""
4253
An unordered partition of a set `S` is a set of pairwise
4254
disjoint nonempty subsets with union `S` and is represented
4255
by a sorted list of such subsets.
4256
4257
partitions_set returns the list of all unordered partitions of the
4258
list `S` of increasing positive integers into k pairwise
4259
disjoint nonempty sets. If k is omitted then all partitions are
4260
returned.
4261
4262
The Bell number `B_n`, named in honor of Eric Temple Bell,
4263
is the number of different partitions of a set with n elements.
4264
4265
.. warning::
4266
4267
Wraps GAP - hence S must be a list of objects that have string
4268
representations that can be interpreted by the GAP
4269
interpreter. If mset consists of at all complicated Sage
4270
objects, this function does *not* do what you expect. See
4271
SetPartitions in ``combinat/set_partition``.
4272
4273
.. warning::
4274
4275
This function is inefficient. The runtime is dominated by
4276
parsing the output from GAP.
4277
4278
Wraps GAP's PartitionsSet.
4279
4280
EXAMPLES::
4281
4282
sage: S = [1,2,3,4]
4283
sage: partitions_set(S,2)
4284
[[[1], [2, 3, 4]],
4285
[[1, 2], [3, 4]],
4286
[[1, 2, 3], [4]],
4287
[[1, 2, 4], [3]],
4288
[[1, 3], [2, 4]],
4289
[[1, 3, 4], [2]],
4290
[[1, 4], [2, 3]]]
4291
4292
REFERENCES:
4293
4294
- http://en.wikipedia.org/wiki/Partition_of_a_set
4295
"""
4296
if k is None:
4297
ans=gap("PartitionsSet(%s)"%S).str(use_file=use_file)
4298
else:
4299
ans=gap("PartitionsSet(%s,%s)"%(S,k)).str(use_file=use_file)
4300
return eval(ans)
4301
4302
def number_of_partitions_set(S,k):
4303
r"""
4304
Returns the size of ``partitions_set(S,k)``. Wraps
4305
GAP's NrPartitionsSet.
4306
4307
The Stirling number of the second kind is the number of partitions
4308
of a set of size n into k blocks.
4309
4310
EXAMPLES::
4311
4312
sage: mset = [1,2,3,4]
4313
sage: number_of_partitions_set(mset,2)
4314
7
4315
sage: stirling_number2(4,2)
4316
7
4317
4318
REFERENCES
4319
4320
- http://en.wikipedia.org/wiki/Partition_of_a_set
4321
"""
4322
if k is None:
4323
ans=gap.eval("NrPartitionsSet(%s)"%S)
4324
else:
4325
ans=gap.eval("NrPartitionsSet(%s,%s)"%(S,ZZ(k)))
4326
return ZZ(ans)
4327
4328
def partitions_list(n,k=None):
4329
r"""
4330
This function will be deprecated in a future version of Sage and
4331
eventually removed. Use Partitions(n).list() or Partitions(n,
4332
length=k).list() instead.
4333
4334
Original docstring follows.
4335
4336
An unordered partition of `n` is an unordered sum
4337
`n = p_1+p_2 +\ldots+ p_k` of positive integers and is
4338
represented by the list `p = [p_1,p_2,\ldots,p_k]`, in
4339
nonincreasing order, i.e., `p1\geq p_2 ...\geq p_k`.
4340
4341
INPUT:
4342
4343
4344
- ``n, k`` - positive integer
4345
4346
4347
``partitions_list(n,k)`` returns the list of all
4348
(unordered) partitions of the positive integer n into sums with k
4349
summands. If k is omitted then all partitions are returned.
4350
4351
Do not call partitions_list with an n much larger than 40, in
4352
which case there are 37338 partitions, since the list will simply
4353
become too large.
4354
4355
Wraps GAP's Partitions.
4356
4357
EXAMPLES::
4358
4359
sage: partitions_list(10,2)
4360
[[5, 5], [6, 4], [7, 3], [8, 2], [9, 1]]
4361
sage: partitions_list(5)
4362
[[1, 1, 1, 1, 1], [2, 1, 1, 1], [2, 2, 1], [3, 1, 1], [3, 2], [4, 1], [5]]
4363
"""
4364
n = ZZ(n)
4365
if n <= 0:
4366
raise ValueError, "n (=%s) must be a positive integer"%n
4367
if k is None:
4368
ans=gap.eval("Partitions(%s)"%(n))
4369
else:
4370
ans=gap.eval("Partitions(%s,%s)"%(n,k))
4371
return eval(ans.replace('\n',''))
4372
4373
4374
def number_of_partitions(n,k=None, algorithm='default'):
4375
r"""
4376
Returns the size of partitions_list(n,k).
4377
4378
INPUT:
4379
4380
4381
- ``n`` - an integer
4382
4383
- ``k`` - (default: None); if specified, instead
4384
returns the cardinality of the set of all (unordered) partitions of
4385
the positive integer n into sums with k summands.
4386
4387
- ``algorithm`` - (default: 'default')
4388
4389
- ``'default'`` - If k is not None, then use Gap (very
4390
slow). If k is None, use Jonathan Bober's highly optimized
4391
implementation (this is the fastest code in the world for this
4392
problem).
4393
4394
- ``'bober'`` - use Jonathan Bober's implementation
4395
4396
- ``'gap'`` - use GAP (VERY *slow*)
4397
4398
- ``'pari'`` - use PARI. Speed seems the same as GAP until
4399
`n` is in the thousands, in which case PARI is
4400
faster. *But* PARI has a bug, e.g., on 64-bit Linux
4401
PARI-2.3.2 outputs numbpart(147007)%1000 as 536 when it should
4402
be 533!. So do not use this option.
4403
4404
4405
IMPLEMENTATION: Wraps GAP's NrPartitions or PARI's numbpart
4406
function.
4407
4408
Use the function ``partitions(n)`` to return a
4409
generator over all partitions of `n`.
4410
4411
It is possible to associate with every partition of the integer n a
4412
conjugacy class of permutations in the symmetric group on n points
4413
and vice versa. Therefore p(n) = NrPartitions(n) is the number of
4414
conjugacy classes of the symmetric group on n points.
4415
4416
EXAMPLES::
4417
4418
sage: v = list(partitions(5)); v
4419
[(1, 1, 1, 1, 1), (1, 1, 1, 2), (1, 2, 2), (1, 1, 3), (2, 3), (1, 4), (5,)]
4420
sage: len(v)
4421
7
4422
sage: number_of_partitions(5, algorithm='gap')
4423
7
4424
sage: number_of_partitions(5, algorithm='pari')
4425
7
4426
sage: number_of_partitions(5, algorithm='bober')
4427
7
4428
4429
The input must be a nonnegative integer or a ValueError is raised.
4430
4431
::
4432
4433
sage: number_of_partitions(-5)
4434
Traceback (most recent call last):
4435
...
4436
ValueError: n (=-5) must be a nonnegative integer
4437
4438
::
4439
4440
sage: number_of_partitions(10,2)
4441
5
4442
sage: number_of_partitions(10)
4443
42
4444
sage: number_of_partitions(3)
4445
3
4446
sage: number_of_partitions(10)
4447
42
4448
sage: number_of_partitions(3, algorithm='pari')
4449
3
4450
sage: number_of_partitions(10, algorithm='pari')
4451
42
4452
sage: number_of_partitions(40)
4453
37338
4454
sage: number_of_partitions(100)
4455
190569292
4456
sage: number_of_partitions(100000)
4457
27493510569775696512677516320986352688173429315980054758203125984302147328114964173055050741660736621590157844774296248940493063070200461792764493033510116079342457190155718943509725312466108452006369558934464248716828789832182345009262853831404597021307130674510624419227311238999702284408609370935531629697851569569892196108480158600569421098519
4458
4459
A generating function for p(n) is given by the reciprocal of
4460
Euler's function:
4461
4462
4463
.. math::
4464
4465
\sum_{n=0}^\infty p(n)x^n = \prod_{k=1}^\infty \left(\frac {1}{1-x^k} \right).
4466
4467
4468
4469
We use Sage to verify that the first several coefficients do
4470
instead agree::
4471
4472
sage: q = PowerSeriesRing(QQ, 'q', default_prec=9).gen()
4473
sage: prod([(1-q^k)^(-1) for k in range(1,9)]) ## partial product of
4474
1 + q + 2*q^2 + 3*q^3 + 5*q^4 + 7*q^5 + 11*q^6 + 15*q^7 + 22*q^8 + O(q^9)
4475
sage: [number_of_partitions(k) for k in range(2,10)]
4476
[2, 3, 5, 7, 11, 15, 22, 30]
4477
4478
REFERENCES:
4479
4480
- http://en.wikipedia.org/wiki/Partition\_(number\_theory)
4481
4482
TESTS::
4483
4484
sage: n = 500 + randint(0,500)
4485
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4486
True
4487
sage: n = 1500 + randint(0,1500)
4488
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4489
True
4490
sage: n = 1000000 + randint(0,1000000)
4491
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4492
True
4493
sage: n = 1000000 + randint(0,1000000)
4494
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4495
True
4496
sage: n = 1000000 + randint(0,1000000)
4497
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4498
True
4499
sage: n = 1000000 + randint(0,1000000)
4500
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4501
True
4502
sage: n = 1000000 + randint(0,1000000)
4503
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4504
True
4505
sage: n = 1000000 + randint(0,1000000)
4506
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0
4507
True
4508
sage: n = 100000000 + randint(0,100000000)
4509
sage: number_of_partitions( n - (n % 385) + 369) % 385 == 0 # long time (4s on sage.math, 2011)
4510
True
4511
4512
Another consistency test for n up to 500::
4513
4514
sage: len([n for n in [1..500] if number_of_partitions(n) != number_of_partitions(n,algorithm='pari')])
4515
0
4516
"""
4517
n = ZZ(n)
4518
if n < 0:
4519
raise ValueError, "n (=%s) must be a nonnegative integer"%n
4520
elif n == 0:
4521
return ZZ(1)
4522
4523
if algorithm == 'default':
4524
if k is None:
4525
algorithm = 'bober'
4526
else:
4527
algorithm = 'gap'
4528
4529
if algorithm == 'gap':
4530
if k is None:
4531
ans=gap.eval("NrPartitions(%s)"%(ZZ(n)))
4532
else:
4533
ans=gap.eval("NrPartitions(%s,%s)"%(ZZ(n),ZZ(k)))
4534
return ZZ(ans)
4535
4536
if k is not None:
4537
raise ValueError, "only the GAP algorithm works if k is specified."
4538
4539
if algorithm == 'bober':
4540
return partitions_ext.number_of_partitions(n)
4541
4542
elif algorithm == 'pari':
4543
return ZZ(pari(ZZ(n)).numbpart())
4544
4545
raise ValueError, "unknown algorithm '%s'"%algorithm
4546
4547
4548
# Some function e.g.: Partitions(n).random() heavily use number_of_partitions
4549
# so I'm caching the result
4550
from sage.misc.all import cached_function
4551
_numpart = cached_function(number_of_partitions)
4552
4553
def partitions(n):
4554
r"""
4555
Generator of all the partitions of the integer `n`.
4556
4557
INPUT:
4558
4559
4560
- ``n`` - int
4561
4562
4563
To compute the number of partitions of `n` use
4564
``number_of_partitions(n)``.
4565
4566
EXAMPLES::
4567
4568
sage: partitions(3)
4569
<generator object partitions at 0x...>
4570
sage: list(partitions(3))
4571
[(1, 1, 1), (1, 2), (3,)]
4572
4573
AUTHORS:
4574
4575
- Adapted from David Eppstein, Jan Van lent, George Yoshida;
4576
Python Cookbook 2, Recipe 19.16.
4577
"""
4578
n = ZZ(n)
4579
# base case of the recursion: zero is the sum of the empty tuple
4580
if n == 0:
4581
yield ( )
4582
return
4583
# modify the partitions of n-1 to form the partitions of n
4584
for p in partitions(n-1):
4585
yield (1,) + p
4586
if p and (len(p) < 2 or p[1] > p[0]):
4587
yield (p[0] + 1,) + p[1:]
4588
4589
def cyclic_permutations_of_partition(partition):
4590
"""
4591
Returns all combinations of cyclic permutations of each cell of the
4592
partition.
4593
4594
AUTHORS:
4595
4596
- Robert L. Miller
4597
4598
EXAMPLES::
4599
4600
sage: from sage.combinat.partition import cyclic_permutations_of_partition
4601
sage: cyclic_permutations_of_partition([[1,2,3,4],[5,6,7]])
4602
[[[1, 2, 3, 4], [5, 6, 7]],
4603
[[1, 2, 4, 3], [5, 6, 7]],
4604
[[1, 3, 2, 4], [5, 6, 7]],
4605
[[1, 3, 4, 2], [5, 6, 7]],
4606
[[1, 4, 2, 3], [5, 6, 7]],
4607
[[1, 4, 3, 2], [5, 6, 7]],
4608
[[1, 2, 3, 4], [5, 7, 6]],
4609
[[1, 2, 4, 3], [5, 7, 6]],
4610
[[1, 3, 2, 4], [5, 7, 6]],
4611
[[1, 3, 4, 2], [5, 7, 6]],
4612
[[1, 4, 2, 3], [5, 7, 6]],
4613
[[1, 4, 3, 2], [5, 7, 6]]]
4614
4615
Note that repeated elements are not considered equal::
4616
4617
sage: cyclic_permutations_of_partition([[1,2,3],[4,4,4]])
4618
[[[1, 2, 3], [4, 4, 4]],
4619
[[1, 3, 2], [4, 4, 4]],
4620
[[1, 2, 3], [4, 4, 4]],
4621
[[1, 3, 2], [4, 4, 4]]]
4622
"""
4623
return list(cyclic_permutations_of_partition_iterator(partition))
4624
4625
def cyclic_permutations_of_partition_iterator(partition):
4626
"""
4627
Iterates over all combinations of cyclic permutations of each cell
4628
of the partition.
4629
4630
AUTHORS:
4631
4632
- Robert L. Miller
4633
4634
EXAMPLES::
4635
4636
sage: from sage.combinat.partition import cyclic_permutations_of_partition
4637
sage: list(cyclic_permutations_of_partition_iterator([[1,2,3,4],[5,6,7]]))
4638
[[[1, 2, 3, 4], [5, 6, 7]],
4639
[[1, 2, 4, 3], [5, 6, 7]],
4640
[[1, 3, 2, 4], [5, 6, 7]],
4641
[[1, 3, 4, 2], [5, 6, 7]],
4642
[[1, 4, 2, 3], [5, 6, 7]],
4643
[[1, 4, 3, 2], [5, 6, 7]],
4644
[[1, 2, 3, 4], [5, 7, 6]],
4645
[[1, 2, 4, 3], [5, 7, 6]],
4646
[[1, 3, 2, 4], [5, 7, 6]],
4647
[[1, 3, 4, 2], [5, 7, 6]],
4648
[[1, 4, 2, 3], [5, 7, 6]],
4649
[[1, 4, 3, 2], [5, 7, 6]]]
4650
4651
Note that repeated elements are not considered equal::
4652
4653
sage: list(cyclic_permutations_of_partition_iterator([[1,2,3],[4,4,4]]))
4654
[[[1, 2, 3], [4, 4, 4]],
4655
[[1, 3, 2], [4, 4, 4]],
4656
[[1, 2, 3], [4, 4, 4]],
4657
[[1, 3, 2], [4, 4, 4]]]
4658
"""
4659
if len(partition) == 1:
4660
for i in cyclic_permutations_iterator(partition[0]):
4661
yield [i]
4662
else:
4663
for right in cyclic_permutations_of_partition_iterator(partition[1:]):
4664
for perm in cyclic_permutations_iterator(partition[0]):
4665
yield [perm] + right
4666
4667
def ferrers_diagram(pi):
4668
"""
4669
Return the Ferrers diagram of pi.
4670
4671
INPUT:
4672
4673
4674
- ``pi`` - a partition, given as a list of integers.
4675
4676
4677
EXAMPLES::
4678
4679
sage: print Partition([5,5,2,1]).ferrers_diagram()
4680
*****
4681
*****
4682
**
4683
*
4684
"""
4685
from sage.misc.misc import deprecation
4686
deprecation('"ferrers_diagram deprecated. Use Partition(pi).ferrers_diagram() instead')
4687
return Partition(pi).ferrers_diagram()
4688
4689
4690
def ordered_partitions(n,k=None):
4691
r"""
4692
An ordered partition of `n` is an ordered sum
4693
4694
.. math::
4695
4696
n = p_1+p_2 + \cdots + p_k
4697
4698
4699
of positive integers and is represented by the list
4700
`p = [p_1,p_2,\cdots ,p_k]`. If `k` is omitted
4701
then all ordered partitions are returned.
4702
4703
``ordered_partitions(n,k)`` returns the list of all
4704
(ordered) partitions of the positive integer n into sums with k
4705
summands.
4706
4707
Do not call ``ordered_partitions`` with an n much
4708
larger than 15, since the list will simply become too large.
4709
4710
Wraps GAP's OrderedPartitions.
4711
4712
The number of ordered partitions `T_n` of
4713
`\{ 1, 2, ..., n \}` has the generating function is
4714
4715
.. math::
4716
4717
\sum_n {T_n \over n!} x^n = {1 \over 2-e^x}.
4718
4719
4720
4721
EXAMPLES::
4722
4723
sage: ordered_partitions(10,2)
4724
[[1, 9], [2, 8], [3, 7], [4, 6], [5, 5], [6, 4], [7, 3], [8, 2], [9, 1]]
4725
4726
::
4727
4728
sage: ordered_partitions(4)
4729
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
4730
4731
REFERENCES:
4732
4733
- http://en.wikipedia.org/wiki/Ordered_partition_of_a_set
4734
"""
4735
if k is None:
4736
ans=gap.eval("OrderedPartitions(%s)"%(ZZ(n)))
4737
else:
4738
ans=gap.eval("OrderedPartitions(%s,%s)"%(ZZ(n),ZZ(k)))
4739
return eval(ans.replace('\n',''))
4740
4741
def number_of_ordered_partitions(n,k=None):
4742
"""
4743
Returns the size of ordered_partitions(n,k). Wraps GAP's
4744
NrOrderedPartitions.
4745
4746
It is possible to associate with every partition of the integer n a
4747
conjugacy class of permutations in the symmetric group on n points
4748
and vice versa. Therefore p(n) = NrPartitions(n) is the number of
4749
conjugacy classes of the symmetric group on n points.
4750
4751
EXAMPLES::
4752
4753
sage: number_of_ordered_partitions(10,2)
4754
9
4755
sage: number_of_ordered_partitions(15)
4756
16384
4757
"""
4758
if k is None:
4759
ans=gap.eval("NrOrderedPartitions(%s)"%(n))
4760
else:
4761
ans=gap.eval("NrOrderedPartitions(%s,%s)"%(n,k))
4762
return ZZ(ans)
4763
4764
def partitions_greatest(n,k):
4765
"""
4766
Returns the list of all (unordered) "restricted" partitions of the
4767
integer n having parts less than or equal to the integer k.
4768
4769
Wraps GAP's PartitionsGreatestLE.
4770
4771
EXAMPLES::
4772
4773
sage: partitions_greatest(10,2)
4774
[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
4775
[2, 1, 1, 1, 1, 1, 1, 1, 1],
4776
[2, 2, 1, 1, 1, 1, 1, 1],
4777
[2, 2, 2, 1, 1, 1, 1],
4778
[2, 2, 2, 2, 1, 1],
4779
[2, 2, 2, 2, 2]]
4780
"""
4781
return eval(gap.eval("PartitionsGreatestLE(%s,%s)"%(ZZ(n),ZZ(k))))
4782
4783
def partitions_greatest_eq(n,k):
4784
"""
4785
Returns the list of all (unordered) "restricted" partitions of the
4786
integer n having at least one part equal to the integer k.
4787
4788
Wraps GAP's PartitionsGreatestEQ.
4789
4790
EXAMPLES::
4791
4792
sage: partitions_greatest_eq(10,2)
4793
[[2, 1, 1, 1, 1, 1, 1, 1, 1],
4794
[2, 2, 1, 1, 1, 1, 1, 1],
4795
[2, 2, 2, 1, 1, 1, 1],
4796
[2, 2, 2, 2, 1, 1],
4797
[2, 2, 2, 2, 2]]
4798
"""
4799
ans = gap.eval("PartitionsGreatestEQ(%s,%s)"%(n,k))
4800
return eval(ans)
4801
4802
def partitions_restricted(n,S,k=None):
4803
r"""
4804
This function will be deprecated in a future version of Sage and
4805
eventually removed. Use RestrictedPartitions(n, S, k).list()
4806
instead.
4807
4808
Original docstring follows.
4809
4810
A restricted partition is, like an ordinary partition, an unordered
4811
sum `n = p_1+p_2+\ldots+p_k` of positive integers and is
4812
represented by the list `p = [p_1,p_2,\ldots,p_k]`, in
4813
nonincreasing order. The difference is that here the `p_i`
4814
must be elements from the set `S`, while for ordinary
4815
partitions they may be elements from `[1..n]`.
4816
4817
Returns the list of all restricted partitions of the positive
4818
integer n into sums with k summands with the summands of the
4819
partition coming from the set `S`. If k is not given all
4820
restricted partitions for all k are returned.
4821
4822
Wraps GAP's RestrictedPartitions.
4823
4824
EXAMPLES::
4825
4826
sage: partitions_restricted(8,[1,3,5,7])
4827
[[1, 1, 1, 1, 1, 1, 1, 1],
4828
[3, 1, 1, 1, 1, 1],
4829
[3, 3, 1, 1],
4830
[5, 1, 1, 1],
4831
[5, 3],
4832
[7, 1]]
4833
sage: partitions_restricted(8,[1,3,5,7],2)
4834
[[5, 3], [7, 1]]
4835
"""
4836
if k is None:
4837
ans=gap.eval("RestrictedPartitions(%s,%s)"%(n,S))
4838
else:
4839
ans=gap.eval("RestrictedPartitions(%s,%s,%s)"%(n,S,k))
4840
return eval(ans)
4841
4842
def number_of_partitions_restricted(n,S,k=None):
4843
"""
4844
This function will be deprecated in a future version of Sage and
4845
eventually removed. Use RestrictedPartitions(n, S, k).cardinality()
4846
instead.
4847
4848
Original docstring follows.
4849
4850
Returns the size of partitions_restricted(n,S,k). Wraps GAP's
4851
NrRestrictedPartitions.
4852
4853
EXAMPLES::
4854
4855
sage: number_of_partitions_restricted(8,[1,3,5,7])
4856
6
4857
sage: number_of_partitions_restricted(8,[1,3,5,7],2)
4858
2
4859
"""
4860
if k is None:
4861
ans=gap.eval("NrRestrictedPartitions(%s,%s)"%(ZZ(n),S))
4862
else:
4863
ans=gap.eval("NrRestrictedPartitions(%s,%s,%s)"%(ZZ(n),S,ZZ(k)))
4864
return ZZ(ans)
4865
4866
def partitions_tuples(n,k):
4867
"""
4868
partition_tuples( n, k ) returns the list of all k-tuples of
4869
partitions which together form a partition of n.
4870
4871
k-tuples of partitions describe the classes and the characters of
4872
wreath products of groups with k conjugacy classes with the
4873
symmetric group `S_n`.
4874
4875
Wraps GAP's PartitionTuples.
4876
4877
EXAMPLES::
4878
4879
sage: partitions_tuples(3,2)
4880
[[[1, 1, 1], []],
4881
[[1, 1], [1]],
4882
[[1], [1, 1]],
4883
[[], [1, 1, 1]],
4884
[[2, 1], []],
4885
[[1], [2]],
4886
[[2], [1]],
4887
[[], [2, 1]],
4888
[[3], []],
4889
[[], [3]]]
4890
"""
4891
ans=gap.eval("PartitionTuples(%s,%s)"%(ZZ(n),ZZ(k)))
4892
return eval(ans)
4893
4894
def number_of_partitions_tuples(n,k):
4895
r"""
4896
number_of_partition_tuples( n, k ) returns the number of
4897
partition_tuples(n,k).
4898
4899
Wraps GAP's NrPartitionTuples.
4900
4901
EXAMPLES::
4902
4903
sage: number_of_partitions_tuples(3,2)
4904
10
4905
sage: number_of_partitions_tuples(8,2)
4906
185
4907
4908
Now we compare that with the result of the following GAP
4909
computation::
4910
4911
gap> S8:=Group((1,2,3,4,5,6,7,8),(1,2));
4912
Group([ (1,2,3,4,5,6,7,8), (1,2) ])
4913
gap> C2:=Group((1,2));
4914
Group([ (1,2) ])
4915
gap> W:=WreathProduct(C2,S8);
4916
<permutation group of size 10321920 with 10 generators>
4917
gap> Size(W);
4918
10321920 ## = 2^8*Factorial(8), which is good:-)
4919
gap> Size(ConjugacyClasses(W));
4920
185
4921
"""
4922
ans=gap.eval("NrPartitionTuples(%s,%s)"%(ZZ(n),ZZ(k)))
4923
return ZZ(ans)
4924
4925
def partition_power(pi,k):
4926
"""
4927
partition_power( pi, k ) returns the partition corresponding to
4928
the `k`-th power of a permutation with cycle structure ``pi``
4929
(thus describes the powermap of symmetric groups).
4930
4931
Wraps GAP's PowerPartition.
4932
4933
EXAMPLES::
4934
4935
sage: partition_power([5,3],1)
4936
[5, 3]
4937
sage: partition_power([5,3],2)
4938
[5, 3]
4939
sage: partition_power([5,3],3)
4940
[5, 1, 1, 1]
4941
sage: partition_power([5,3],4)
4942
[5, 3]
4943
4944
Now let us compare this to the power map on `S_8`::
4945
4946
sage: G = SymmetricGroup(8)
4947
sage: g = G([(1,2,3,4,5),(6,7,8)])
4948
sage: g
4949
(1,2,3,4,5)(6,7,8)
4950
sage: g^2
4951
(1,3,5,2,4)(6,8,7)
4952
sage: g^3
4953
(1,4,2,5,3)
4954
sage: g^4
4955
(1,5,4,3,2)(6,7,8)
4956
"""
4957
ans=gap.eval("PowerPartition(%s,%s)"%(pi,ZZ(k)))
4958
return eval(ans)
4959
4960
def partition_sign(pi):
4961
r"""
4962
** This function is being deprecated -- use Partition(*).sign() instead. **
4963
4964
Partition( pi ).sign() returns the sign of a permutation with cycle
4965
structure given by the partition pi.
4966
4967
This function corresponds to a homomorphism from the symmetric
4968
group `S_n` into the cyclic group of order 2, whose kernel
4969
is exactly the alternating group `A_n`. Partitions of sign
4970
`1` are called even partitions while partitions of sign
4971
`-1` are called odd.
4972
4973
This function is deprecated: use Partition( pi ).sign() instead.
4974
4975
EXAMPLES::
4976
4977
sage: Partition([5,3]).sign()
4978
1
4979
sage: Partition([5,2]).sign()
4980
-1
4981
4982
Zolotarev's lemma states that the Legendre symbol
4983
`\left(\frac{a}{p}\right)` for an integer
4984
`a \pmod p` (`p` a prime number), can be computed
4985
as sign(p_a), where sign denotes the sign of a permutation and
4986
p_a the permutation of the residue classes `\pmod p`
4987
induced by modular multiplication by `a`, provided
4988
`p` does not divide `a`.
4989
4990
We verify this in some examples.
4991
4992
::
4993
4994
sage: F = GF(11)
4995
sage: a = F.multiplicative_generator();a
4996
2
4997
sage: plist = [int(a*F(x)) for x in range(1,11)]; plist
4998
[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]
4999
5000
This corresponds to the permutation (1, 2, 4, 8, 5, 10, 9, 7, 3, 6)
5001
(acting the set `\{1,2,...,10\}`) and to the partition
5002
[10].
5003
5004
::
5005
5006
sage: p = PermutationGroupElement('(1, 2, 4, 8, 5, 10, 9, 7, 3, 6)')
5007
sage: p.sign()
5008
-1
5009
sage: Partition([10]).sign()
5010
-1
5011
sage: kronecker_symbol(11,2)
5012
-1
5013
5014
Now replace `2` by `3`::
5015
5016
sage: plist = [int(F(3*x)) for x in range(1,11)]; plist
5017
[3, 6, 9, 1, 4, 7, 10, 2, 5, 8]
5018
sage: range(1,11)
5019
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
5020
sage: p = PermutationGroupElement('(3,4,8,7,9)')
5021
sage: p.sign()
5022
1
5023
sage: kronecker_symbol(3,11)
5024
1
5025
sage: Partition([5,1,1,1,1,1]).sign()
5026
1
5027
5028
In both cases, Zolotarev holds.
5029
5030
REFERENCES:
5031
5032
- http://en.wikipedia.org/wiki/Zolotarev's_lemma
5033
"""
5034
from sage.misc.misc import deprecation
5035
deprecation('"partition_sign deprecated. Use Partition(pi).sign() instead')
5036
return Partition(pi).sign()
5037
5038
def partition_associated(pi):
5039
"""
5040
** This function is being deprecated -- use Partition(*).conjugate() instead. **
5041
5042
partition_associated( pi ) returns the "associated" (also called
5043
"conjugate" in the literature) partition of the partition pi which
5044
is obtained by transposing the corresponding Ferrers diagram.
5045
5046
EXAMPLES::
5047
5048
sage: Partition([2,2]).conjugate()
5049
[2, 2]
5050
sage: Partition([6,3,1]).conjugate()
5051
[3, 2, 2, 1, 1, 1]
5052
sage: print Partition([6,3,1]).ferrers_diagram()
5053
******
5054
***
5055
*
5056
sage: print Partition([6,3,1]).conjugate().ferrers_diagram()
5057
***
5058
**
5059
**
5060
*
5061
*
5062
*
5063
"""
5064
from sage.misc.misc import deprecation
5065
deprecation('"partition_associated deprecated. Use Partition(pi).conjugte() instead')
5066
return Partition(pi).conjugate()
5067
5068
5069