Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/composition.py
4036 views
1
"""
2
Integer compositions
3
4
A composition `c` of a nonnegative integer `n` is a list of positive integers
5
(the *parts* of the compositions) with total sum `n`.
6
7
This module provides tools for manipulating compositions and enumerated
8
sets of compositions.
9
10
EXAMPLES::
11
12
sage: Composition([5, 3, 1, 3])
13
[5, 3, 1, 3]
14
sage: list(Compositions(4))
15
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
16
17
18
AUTHORS:
19
20
- Mike Hansen, Nicolas M. Thiery
21
- MuPAD-Combinat developers (algorithms and design inspiration)
22
"""
23
#*****************************************************************************
24
# Copyright (C) 2007 Mike Hansen <[email protected]>
25
# 2009 Nicolas M. Thiery <nthiery at users.sf.net>
26
#
27
# Distributed under the terms of the GNU General Public License (GPL)
28
# http://www.gnu.org/licenses/
29
#*****************************************************************************
30
31
import sage.combinat.skew_partition
32
from combinat import CombinatorialClass, CombinatorialObject, InfiniteAbstractCombinatorialClass
33
from cartesian_product import CartesianProduct
34
from integer_list import IntegerListsLex
35
import __builtin__
36
from sage.rings.integer import Integer
37
38
def Composition(co=None, descents=None, code=None):
39
"""
40
Integer compositions
41
42
A composition of a nonnegative integer `n` is a list
43
`(i_1,\dots,i_k)` of positive integers with total sum `n`.
44
45
TODO: mathematical definition of descents, code, ...
46
47
EXAMPLES:
48
49
The simplest way to create a composition is by specifying its
50
entries as a list, tuple (or other iterable)::
51
52
sage: Composition([3,1,2])
53
[3, 1, 2]
54
sage: Composition((3,1,2))
55
[3, 1, 2]
56
sage: Composition(i for i in range(2,5))
57
[2, 3, 4]
58
59
You can alternatively create a composition from the list of its
60
descents::
61
62
sage: Composition([1, 1, 3, 4, 3]).descents()
63
[0, 1, 4, 8, 11]
64
sage: Composition(descents=[1,0,4,8,11])
65
[1, 1, 3, 4, 3]
66
67
You can also create a composition from its code::
68
69
sage: Composition([4,1,2,3,5]).to_code()
70
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
71
sage: Composition(code=_)
72
[4, 1, 2, 3, 5]
73
sage: Composition([3,1,2,3,5]).to_code()
74
[1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
75
sage: Composition(code=_)
76
[3, 1, 2, 3, 5]
77
"""
78
79
if descents is not None:
80
if isinstance(descents, tuple):
81
return from_descents(descents[0], nps=descents[1])
82
else:
83
return from_descents(descents)
84
elif code is not None:
85
return from_code(code)
86
elif isinstance(co, Composition_class):
87
return co
88
else:
89
co = list(co)
90
assert(co in Compositions())
91
#raise ValueError, "invalid composition"
92
return Composition_class(co)
93
94
95
class Composition_class(CombinatorialObject):
96
__doc__ = Composition.__doc__
97
98
def conjugate(self):
99
r"""
100
Returns the conjugate of the composition comp.
101
102
Algorithm from mupad-combinat.
103
104
EXAMPLES::
105
106
sage: Composition([1, 1, 3, 1, 2, 1, 3]).conjugate()
107
[1, 1, 3, 3, 1, 3]
108
"""
109
comp = self
110
if comp == []:
111
return Composition([])
112
n = len(comp)
113
coofcp = [sum(comp[:j])-j+1 for j in range(1,n+1)]
114
115
cocjg = []
116
for i in range(n-1):
117
cocjg += [i+1 for _ in range(0, (coofcp[n-i-1]-coofcp[n-i-2]))]
118
cocjg += [n for j in range(coofcp[0])]
119
120
return Composition([cocjg[0]] + [cocjg[i]-cocjg[i-1]+1 for i in range(1,len(cocjg)) ])
121
122
123
def complement(self):
124
"""
125
Returns the complement of the composition co. The complement is the
126
reverse of co's conjugate composition.
127
128
EXAMPLES::
129
130
sage: Composition([1, 1, 3, 1, 2, 1, 3]).conjugate()
131
[1, 1, 3, 3, 1, 3]
132
sage: Composition([1, 1, 3, 1, 2, 1, 3]).complement()
133
[3, 1, 3, 3, 1, 1]
134
"""
135
return Composition([element for element in reversed(self.conjugate())])
136
137
138
def __add__(self, other):
139
"""
140
Returns the concatenation of two compositions.
141
142
EXAMPLES::
143
144
sage: Composition([1, 1, 3]) + Composition([4, 1, 2])
145
[1, 1, 3, 4, 1, 2]
146
147
TESTS::
148
149
sage: Composition([]) + Composition([]) == Composition([])
150
True
151
"""
152
return Composition(list(self)+list(other))
153
154
def size(self):
155
"""
156
Returns the size of the composition, that is the sum of its parts.
157
158
EXAMPLES::
159
160
sage: Composition([7,1,3]).size()
161
11
162
"""
163
return sum(self)
164
165
@staticmethod
166
def sum(compositions):
167
"""
168
Returns the concatenation of the given compositions.
169
170
INPUT:
171
172
- ``compositions`` -- a list (or iterable) of compositions
173
174
EXAMPLES::
175
176
sage: sage.combinat.composition.Composition_class.sum([Composition([1, 1, 3]), Composition([4, 1, 2]), Composition([3,1])])
177
[1, 1, 3, 4, 1, 2, 3, 1]
178
179
Any iterable can be provided as input::
180
181
sage: sage.combinat.composition.Composition_class.sum([Composition([i,i]) for i in [4,1,3]])
182
[4, 4, 1, 1, 3, 3]
183
184
Empty inputs are handled gracefully::
185
186
sage: sage.combinat.composition.Composition_class.sum([]) == Composition([])
187
True
188
"""
189
return sum(compositions, Composition([]))
190
191
def finer(self):
192
"""
193
Returns the set of compositions which are finer than self.
194
195
EXAMPLES::
196
197
sage: C = Composition([3,2]).finer()
198
sage: C.cardinality()
199
8
200
sage: list(C)
201
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 1, 1], [1, 2, 2], [2, 1, 1, 1], [2, 1, 2], [3, 1, 1], [3, 2]]
202
"""
203
return CartesianProduct(*[Compositions(i) for i in self]).map(Composition_class.sum)
204
205
def is_finer(self, co2):
206
"""
207
Returns True if the composition self is finer than the composition
208
co2; otherwise, it returns False.
209
210
EXAMPLES::
211
212
sage: Composition([4,1,2]).is_finer([3,1,3])
213
False
214
sage: Composition([3,1,3]).is_finer([4,1,2])
215
False
216
sage: Composition([1,2,2,1,1,2]).is_finer([5,1,3])
217
True
218
sage: Composition([2,2,2]).is_finer([4,2])
219
True
220
"""
221
co1 = self
222
if sum(co1) != sum(co2):
223
#Error: compositions are not of the same size
224
raise ValueError, "compositions self (= %s) and co2 (= %s) must be of the same size"%(self, co2)
225
226
227
sum1 = 0
228
sum2 = 0
229
i1 = 0
230
for i2 in range(len(co2)):
231
sum2 += co2[i2]
232
while sum1 < sum2:
233
sum1 += co1[i1]
234
i1 += 1
235
if sum1 > sum2:
236
return False
237
238
return True
239
240
def fatten(self, grouping):
241
"""
242
Returns the composition fatter than self, obtained by grouping
243
together consecutive parts according to grouping.
244
245
INPUT:
246
247
- ``grouping`` -- a composition whose sum is the length of self
248
249
EXAMPLES:
250
251
Let us start with the composition::
252
253
sage: c = Composition([4,5,2,7,1])
254
255
With `grouping = (1,\dots,1)`, `c` is left unchanged::
256
257
sage: c.fatten(Composition([1,1,1,1,1]))
258
[4, 5, 2, 7, 1]
259
260
With `grouping = (5)`, this yields the coarser composition above `c`::
261
262
sage: c.fatten(Composition([5]))
263
[19]
264
265
Other values for ``grouping`` yield (all the) other compositions
266
coarser to `c`::
267
268
sage: c.fatten(Composition([2,1,2]))
269
[9, 2, 8]
270
sage: c.fatten(Composition([3,1,1]))
271
[11, 7, 1]
272
273
TESTS::
274
275
sage: Composition([]).fatten(Composition([]))
276
[]
277
sage: c.fatten(Composition([3,1,1])).__class__ == c.__class__
278
True
279
"""
280
result = [None] * len(grouping)
281
j = 0
282
for i in range(len(grouping)):
283
result[i] = sum(self[j:j+grouping[i]])
284
j += grouping[i]
285
return Composition_class(result)
286
287
def fatter(self):
288
"""
289
Returns the set of compositions which are fatter than self.
290
291
Complexity for generation: `O(size(c))` memory, `O(size(result))` time
292
293
EXAMPLES::
294
295
sage: C = Composition([4,5,2]).fatter()
296
sage: C.cardinality()
297
4
298
sage: list(C)
299
[[4, 5, 2], [4, 7], [9, 2], [11]]
300
301
Some extreme cases::
302
303
sage: list(Composition([5]).fatter())
304
[[5]]
305
sage: list(Composition([]).fatter())
306
[[]]
307
sage: list(Composition([1,1,1,1]).fatter()) == list(Compositions(4))
308
True
309
"""
310
return Compositions(len(self)).map(self.fatten)
311
312
def refinement(self, co2):
313
"""
314
Returns the refinement composition of self and co2.
315
316
EXAMPLES::
317
318
sage: Composition([1,2,2,1,1,2]).refinement([5,1,3])
319
[3, 1, 2]
320
"""
321
co1 = self
322
if sum(co1) != sum(co2):
323
#Error: compositions are not of the same size
324
raise ValueError, "compositions self (= %s) and co2 (= %s) must be of the same size"%(self, co2)
325
326
sum1 = 0
327
sum2 = 0
328
i1 = -1
329
result = []
330
for i2 in range(len(co2)):
331
sum2 += co2[i2]
332
i_res = 0
333
while sum1 < sum2:
334
i1 += 1
335
sum1 += co1[i1]
336
i_res += 1
337
338
if sum1 > sum2:
339
return None
340
341
result.append(i_res)
342
343
return Composition(result)
344
345
def major_index(self):
346
"""
347
Returns the major index of the composition co. The major index is
348
defined as the sum of the descents.
349
350
EXAMPLES::
351
352
sage: Composition([1, 1, 3, 1, 2, 1, 3]).major_index()
353
31
354
"""
355
co = self
356
lv = len(co)
357
if lv == 1:
358
return 0
359
else:
360
return sum([(lv-(i+1))*co[i] for i in range(lv)])
361
362
363
def to_code(self):
364
"""
365
Returns the code of the composition self. The code of a composition
366
is a list of length self.size() of 1s and 0s such that there is a 1
367
wherever a new part starts.
368
369
EXAMPLES::
370
371
sage: Composition([4,1,2,3,5]).to_code()
372
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
373
"""
374
375
if self == []:
376
return [0]
377
378
code = []
379
for i in range(len(self)):
380
code += [1] + [0]*(self[i]-1)
381
382
return code
383
384
385
def descents(self, final_descent=False):
386
"""
387
Returns the list of descents of the composition co.
388
389
EXAMPLES::
390
391
sage: Composition([1, 1, 3, 1, 2, 1, 3]).descents()
392
[0, 1, 4, 5, 7, 8, 11]
393
"""
394
s = -1
395
d = []
396
for i in range(len(self)):
397
s += self[i]
398
d += [s]
399
if len(self) != 0 and final_descent:
400
d += [len(self)-1]
401
return d
402
403
404
def peaks(self):
405
"""
406
Returns a list of the peaks of the composition self. The
407
peaks of a composition are the descents which do not
408
immediately follow another descent.
409
410
EXAMPLES::
411
412
sage: Composition([1, 1, 3, 1, 2, 1, 3]).peaks()
413
[4, 7]
414
"""
415
descents = dict((d,True) for d in self.descents())
416
return [i+1 for i in range(len(self))
417
if i not in descents and i+1 in descents]
418
419
def to_skew_partition(self, overlap=1):
420
"""
421
Returns the skew partition obtained from the composition co. The
422
parameter overlap indicates the number of cells that are covered by
423
cells of the previous line.
424
425
EXAMPLES::
426
427
sage: Composition([3,4,1]).to_skew_partition()
428
[[6, 6, 3], [5, 2]]
429
sage: Composition([3,4,1]).to_skew_partition(overlap=0)
430
[[8, 7, 3], [7, 3]]
431
"""
432
outer = []
433
inner = []
434
sum_outer = -1*overlap
435
436
for k in range(len(self)-1):
437
outer += [ self[k]+sum_outer+overlap ]
438
sum_outer += self[k]-overlap
439
inner += [ sum_outer + overlap ]
440
441
if self != []:
442
outer += [self[-1]+sum_outer+overlap]
443
else:
444
return [[],[]]
445
446
return sage.combinat.skew_partition.SkewPartition(
447
[ filter(lambda x: x != 0, [l for l in reversed(outer)]),
448
filter(lambda x: x != 0, [l for l in reversed(inner)])])
449
450
451
##############################################################
452
453
454
def Compositions(n=None, **kwargs):
455
r"""
456
Sets of integer Compositions.
457
458
A composition `c` of a nonnegative integer `n` is a list of
459
positive integers with total sum `n`.
460
461
See also: ``Composition``, ``Partitions``, ``IntegerVectors``
462
463
EXAMPLES:
464
465
There are 8 compositions of 4::
466
467
sage: Compositions(4).cardinality()
468
8
469
470
Here is the list of them::
471
472
sage: list(Compositions(4))
473
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
474
475
You can use the ``.first()`` method to get the 'first' composition of
476
a number::
477
478
sage: Compositions(4).first()
479
[1, 1, 1, 1]
480
481
You can also calculate the 'next' composition given the current
482
one::
483
484
sage: Compositions(4).next([1,1,2])
485
[1, 2, 1]
486
487
488
489
If `n` is not specified, this returns the combinatorial class of
490
all (non-negative) integer compositions::
491
492
sage: Compositions()
493
Compositions of non-negative integers
494
sage: [] in Compositions()
495
True
496
sage: [2,3,1] in Compositions()
497
True
498
sage: [-2,3,1] in Compositions()
499
False
500
501
If n is specified, it returns the class of compositions of n::
502
503
sage: Compositions(3)
504
Compositions of 3
505
sage: list(Compositions(3))
506
[[1, 1, 1], [1, 2], [2, 1], [3]]
507
sage: Compositions(3).cardinality()
508
4
509
510
The following examples show how to test whether or not an object
511
is a composition::
512
513
sage: [3,4] in Compositions()
514
True
515
sage: [3,4] in Compositions(7)
516
True
517
sage: [3,4] in Compositions(5)
518
False
519
520
Similarly, one can check whether or not an object is a composition
521
which satisfies further constraints::
522
523
sage: [4,2] in Compositions(6, inner=[2,2])
524
True
525
sage: [4,2] in Compositions(6, inner=[2,3])
526
False
527
sage: [4,1] in Compositions(5, inner=[2,1], max_slope = 0)
528
True
529
530
Note that the given constraints should be compatible::
531
532
sage: [4,2] in Compositions(6, inner=[2,2], min_part=3) #
533
True
534
535
The options length, min_length, and max_length can be used to set
536
length constraints on the compositions. For example, the
537
compositions of 4 of length equal to, at least, and at most 2 are
538
given by::
539
540
sage: Compositions(4, length=2).list()
541
[[3, 1], [2, 2], [1, 3]]
542
sage: Compositions(4, min_length=2).list()
543
[[3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
544
sage: Compositions(4, max_length=2).list()
545
[[4], [3, 1], [2, 2], [1, 3]]
546
547
Setting both min_length and max_length to the same value is
548
equivalent to setting length to this value::
549
550
sage: Compositions(4, min_length=2, max_length=2).list()
551
[[3, 1], [2, 2], [1, 3]]
552
553
The options inner and outer can be used to set part-by-part
554
containment constraints. The list of compositions of 4 bounded
555
above by [3,1,2] is given by::
556
557
sage: list(Compositions(4, outer=[3,1,2]))
558
[[3, 1], [2, 1, 1], [1, 1, 2]]
559
560
Outer sets max_length to the length of its argument. Moreover, the
561
parts of outer may be infinite to clear the constraint on specific
562
parts. This is the list of compositions of 4 of length at most 3
563
such that the first and third parts are at most 1::
564
565
sage: list(Compositions(4, outer=[1,oo,1]))
566
[[1, 3], [1, 2, 1]]
567
568
This is the list of compositions of 4 bounded below by [1,1,1]::
569
570
sage: list(Compositions(4, inner=[1,1,1]))
571
[[2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
572
573
The options min_slope and max_slope can be used to set constraints
574
on the slope, that is the difference `p[i+1]-p[i]` of two
575
consecutive parts. The following is the list of weakly increasing
576
compositions of 4::
577
578
sage: Compositions(4, min_slope=0).list()
579
[[4], [2, 2], [1, 3], [1, 1, 2], [1, 1, 1, 1]]
580
581
Here are the weakly decreasing ones::
582
583
sage: Compositions(4, max_slope=0).list()
584
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
585
586
587
The following is the list of compositions of 4 such that two
588
consecutive parts differ by at most one::
589
590
sage: Compositions(4, min_slope=-1, max_slope=1).list()
591
[[4], [2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
592
593
The constraints can be combined together in all reasonable ways.
594
This is the list of compositions of 5 of length between 2 and 4
595
such that the difference between consecutive parts is between -2
596
and 1::
597
598
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4).list()
599
[[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [2, 1, 1, 1], [1, 2, 2], [1, 2, 1, 1], [1, 1, 2, 1], [1, 1, 1, 2]]
600
601
We can do the same thing with an outer constraint::
602
603
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4, outer=[2,5,2]).list()
604
[[2, 3], [2, 2, 1], [2, 1, 2], [1, 2, 2]]
605
606
However, providing incoherent constraints may yield strange
607
results. It is up to the user to ensure that the inner and outer
608
compositions themselves satisfy the parts and slope constraints.
609
610
Note that if you specify min_part=0, then the objects produced may
611
have parts equal to zero. This violates the internal assumptions
612
that the Composition class makes. Use at your own risk, or
613
preferably consider using ``IntegerVectors`` instead::
614
615
sage: list(Compositions(2, length=3, min_part=0))
616
doctest:... RuntimeWarning: Currently, setting min_part=0 produces Composition objects which violate internal assumptions. Calling methods on these objects may produce errors or WRONG results!
617
[[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]]
618
619
sage: list(IntegerVectors(2, 3))
620
[[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]]
621
622
The generation algorithm is constant amortized time, and handled
623
by the generic tool ``IntegerListsLex``.
624
625
TESTS::
626
627
sage: C = Compositions(4, length=2)
628
sage: C == loads(dumps(C))
629
True
630
631
sage: Compositions(6, min_part=2, length=3)
632
Compositions of the integer 6 satisfying constraints length=3, min_part=2
633
634
635
sage: [2, 1] in Compositions(3, length=2)
636
True
637
sage: [2,1,2] in Compositions(5, min_part=1)
638
True
639
sage: [2,1,2] in Compositions(5, min_part=2)
640
False
641
642
sage: Compositions(4, length=2).cardinality()
643
3
644
sage: Compositions(4, min_length=2).cardinality()
645
7
646
sage: Compositions(4, max_length=2).cardinality()
647
4
648
sage: Compositions(4, max_part=2).cardinality()
649
5
650
sage: Compositions(4, min_part=2).cardinality()
651
2
652
sage: Compositions(4, outer=[3,1,2]).cardinality()
653
3
654
655
sage: Compositions(4, length=2).list()
656
[[3, 1], [2, 2], [1, 3]]
657
sage: Compositions(4, min_length=2).list()
658
[[3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
659
sage: Compositions(4, max_length=2).list()
660
[[4], [3, 1], [2, 2], [1, 3]]
661
sage: Compositions(4, max_part=2).list()
662
[[2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
663
sage: Compositions(4, min_part=2).list()
664
[[4], [2, 2]]
665
sage: Compositions(4, outer=[3,1,2]).list()
666
[[3, 1], [2, 1, 1], [1, 1, 2]]
667
sage: Compositions(4, outer=[1,oo,1]).list()
668
[[1, 3], [1, 2, 1]]
669
sage: Compositions(4, inner=[1,1,1]).list()
670
[[2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
671
sage: Compositions(4, min_slope=0).list()
672
[[4], [2, 2], [1, 3], [1, 1, 2], [1, 1, 1, 1]]
673
sage: Compositions(4, min_slope=-1, max_slope=1).list()
674
[[4], [2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
675
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4).list()
676
[[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [2, 1, 1, 1], [1, 2, 2], [1, 2, 1, 1], [1, 1, 2, 1], [1, 1, 1, 2]]
677
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4, outer=[2,5,2]).list()
678
[[2, 3], [2, 2, 1], [2, 1, 2], [1, 2, 2]]
679
"""
680
if n is None:
681
assert(len(kwargs) == 0)
682
return Compositions_all()
683
else:
684
if len(kwargs) == 0:
685
if isinstance(n, (int,Integer)):
686
return Compositions_n(n)
687
else:
688
raise ValueError, "n must be an integer"
689
else:
690
# FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute
691
kwargs['name'] = "Compositions of the integer %s satisfying constraints %s"%(n, ", ".join( ["%s=%s"%(key, kwargs[key]) for key in sorted(kwargs.keys())] ))
692
kwargs['element_constructor'] = Composition_class
693
if 'min_part' not in kwargs:
694
kwargs['min_part'] = 1
695
elif kwargs['min_part'] == 0:
696
from warnings import warn
697
warn("Currently, setting min_part=0 produces Composition objects which violate internal assumptions. Calling methods on these objects may produce errors or WRONG results!", RuntimeWarning)
698
699
if 'outer' in kwargs:
700
kwargs['ceiling'] = kwargs['outer']
701
if 'max_length' in kwargs:
702
kwargs['max_length'] = min( len(kwargs['outer']), kwargs['max_length'])
703
else:
704
kwargs['max_length'] = len(kwargs['outer'])
705
del kwargs['outer']
706
707
if 'inner' in kwargs:
708
inner = kwargs['inner']
709
kwargs['floor'] = inner
710
del kwargs['inner']
711
# Should this be handled by integer lists lex?
712
if 'min_length' in kwargs:
713
kwargs['min_length'] = max( len(inner), kwargs['min_length'])
714
else:
715
kwargs['min_length'] = len(inner)
716
return IntegerListsLex(n, **kwargs)
717
718
719
# Allows to unpickle old constrained Compositions_constraints objects.
720
class Compositions_constraints(IntegerListsLex):
721
def __setstate__(self, data):
722
"""
723
TESTS::
724
725
# This is the unpickling sequence for Compositions(4, max_part=2) in sage <= 4.1.1
726
sage: pg_Compositions_constraints = unpickle_global('sage.combinat.composition', 'Compositions_constraints')
727
sage: si = unpickle_newobj(pg_Compositions_constraints, ())
728
sage: pg_make_integer = unpickle_global('sage.rings.integer', 'make_integer')
729
sage: unpickle_build(si, {'constraints':{'max_part':pg_make_integer('2')}, 'n':pg_make_integer('4')})
730
sage: si
731
Integer lists of sum 4 satisfying certain constraints
732
sage: si.list()
733
[[2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
734
"""
735
n = data['n']
736
self.__class__ = IntegerListsLex
737
constraints = {
738
'min_part' : 1,
739
'element_constructor' : Composition_class}
740
constraints.update(data['constraints'])
741
self.__init__(n, **constraints)
742
743
class Compositions_all(InfiniteAbstractCombinatorialClass):
744
def __init__(self):
745
"""
746
TESTS::
747
748
sage: C = Compositions()
749
sage: C == loads(dumps(C))
750
True
751
"""
752
pass
753
def __repr__(self):
754
"""
755
TESTS::
756
757
sage: repr(Compositions())
758
'Compositions of non-negative integers'
759
"""
760
return "Compositions of non-negative integers"
761
762
Element = Composition_class
763
764
def __contains__(self, x):
765
"""
766
TESTS::
767
768
sage: [2,1,3] in Compositions()
769
True
770
sage: [] in Compositions()
771
True
772
sage: [-2,-1] in Compositions()
773
False
774
sage: [0,0] in Compositions()
775
True
776
"""
777
if isinstance(x, Composition_class):
778
return True
779
elif isinstance(x, __builtin__.list):
780
for i in range(len(x)):
781
if not isinstance(x[i], (int, Integer)):
782
return False
783
if x[i] < 0:
784
return False
785
return True
786
else:
787
return False
788
789
def _infinite_cclass_slice(self, n):
790
"""
791
Needed by InfiniteAbstractCombinatorialClass to build __iter__.
792
793
TESTS::
794
795
sage: Compositions()._infinite_cclass_slice(4) == Compositions(4)
796
True
797
sage: it = iter(Compositions()) # indirect doctest
798
sage: [it.next() for i in range(10)]
799
[[], [1], [1, 1], [2], [1, 1, 1], [1, 2], [2, 1], [3], [1, 1, 1, 1], [1, 1, 2]]
800
"""
801
return Compositions_n(n)
802
803
804
class Compositions_n(CombinatorialClass):
805
def __init__(self, n):
806
"""
807
TESTS::
808
809
sage: C = Compositions(3)
810
sage: C == loads(dumps(C))
811
True
812
"""
813
self.n = n
814
815
def __repr__(self):
816
"""
817
TESTS::
818
819
sage: repr(Compositions(3))
820
'Compositions of 3'
821
"""
822
return "Compositions of %s"%self.n
823
824
def __contains__(self, x):
825
"""
826
TESTS::
827
828
sage: [2,1,3] in Compositions(6)
829
True
830
sage: [2,1,2] in Compositions(6)
831
False
832
sage: [] in Compositions(0)
833
True
834
sage: [0] in Compositions(0)
835
True
836
"""
837
return x in Compositions() and sum(x) == self.n
838
839
def cardinality(self):
840
"""
841
TESTS::
842
843
sage: Compositions(3).cardinality()
844
4
845
sage: Compositions(0).cardinality()
846
1
847
"""
848
if self.n >= 1:
849
return 2**(self.n-1)
850
elif self.n == 0:
851
return 1
852
else:
853
return 0
854
855
def list(self):
856
"""
857
TESTS::
858
859
sage: Compositions(4).list()
860
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
861
sage: Compositions(0).list()
862
[[]]
863
"""
864
if self.n == 0:
865
return [Composition_class([])]
866
867
result = []
868
for i in range(1,self.n+1):
869
result += map(lambda x: [i]+x[:], Compositions_n(self.n-i).list())
870
871
return [Composition_class(r) for r in result]
872
873
874
875
876
# Those belong to the Composition class
877
878
def from_descents(descents, nps=None):
879
"""
880
Returns a composition from the list of descents.
881
882
EXAMPLES::
883
884
sage: Composition([1, 1, 3, 4, 3]).descents()
885
[0, 1, 4, 8, 11]
886
sage: sage.combinat.composition.from_descents([1,0,4,8],12)
887
[1, 1, 3, 4, 3]
888
sage: sage.combinat.composition.from_descents([1,0,4,8,11])
889
[1, 1, 3, 4, 3]
890
"""
891
892
d = [x+1 for x in descents]
893
d.sort()
894
895
if d == []:
896
if nps == 0:
897
return []
898
else:
899
return [nps]
900
901
if nps is not None:
902
if nps < max(d):
903
#Error: d is not included in [1,...,nps-1]
904
return None
905
elif nps > max(d):
906
d.append(nps)
907
908
co = [d[0]]
909
for i in range(len(d)-1):
910
co += [ d[i+1]-d[i] ]
911
912
return Composition(co)
913
914
def from_code(code):
915
"""
916
Return the composition from its code.The code of a composition is a
917
list of length self.size() of 1s and 0s such that there is a 1
918
wherever a new part starts.
919
920
EXAMPLES::
921
922
sage: import sage.combinat.composition as composition
923
sage: Composition([4,1,2,3,5]).to_code()
924
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
925
sage: composition.from_code(_)
926
[4, 1, 2, 3, 5]
927
sage: Composition([3,1,2,3,5]).to_code()
928
[1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
929
sage: composition.from_code(_)
930
[3, 1, 2, 3, 5]
931
"""
932
if code == [0]:
933
return []
934
935
L = filter(lambda x: code[x]==1, range(len(code))) #the positions of the letter 1
936
return Composition([L[i]-L[i-1] for i in range(1, len(L))] + [len(code)-L[-1]])
937
938
939