Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/composition_tableau.py
8817 views
1
r"""
2
Composition Tableaux
3
4
AUTHORS:
5
6
- Chris Berg, Jeff Ferreira (2012-9): Initial version
7
"""
8
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
9
from sage.sets.non_negative_integers import NonNegativeIntegers
10
from sage.sets.family import Family
11
from sage.misc.misc_c import prod
12
from sage.misc.classcall_metaclass import ClasscallMetaclass
13
from sage.functions.other import factorial
14
from sage.misc.cachefunc import cached_function
15
from sage.structure.element import Element
16
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
17
from sage.structure.parent import Parent
18
from sage.structure.unique_representation import UniqueRepresentation
19
from sage.combinat.composition import Composition, Compositions
20
from sage.combinat.partition import Partition
21
from sage.combinat.combinat import CombinatorialObject
22
from sage.rings.integer import Integer
23
from sage.combinat.backtrack import GenericBacktracker
24
import copy
25
26
class CompositionTableau(CombinatorialObject, Element):
27
r"""
28
A composition tableau.
29
30
A *composition tableau* `t` of shape `I = (I_1, \ldots, I_{\ell})` is an
31
array of boxes in rows, `I_i` boxes in row `i`, filled with positive
32
integers such that:
33
34
1) the entries in the rows of `t` weakly decrease from left to right,
35
2) the left-most column of `t` strictly increase from top to bottom.
36
3) Add zero entries to the rows of `t` until the resulting array is
37
rectangular of shape `\ell \times m`. For `1 \leq i < j \leq \ell,
38
2 \leq k \leq m` and `(t(j,k) \neq 0`, and also if `t(j,k) \geq t(i,k))`
39
implies `t(j,k) > t(i,k-1).`
40
41
INPUT:
42
43
- ``t`` -- A list of lists
44
45
EXAMPLES::
46
47
sage: CompositionTableau([[1],[2,2]])
48
[[1], [2, 2]]
49
sage: CompositionTableau([[1],[3,2],[4,4]])
50
[[1], [3, 2], [4, 4]]
51
sage: CompositionTableau([])
52
[]
53
"""
54
__metaclass__ = ClasscallMetaclass
55
56
@staticmethod
57
def __classcall_private__(self, t):
58
r"""
59
This ensures that a composition tableau is only ever constructed as
60
an ``element_class`` call of an appropriate parent.
61
62
TESTS::
63
64
sage: t = CompositionTableau([[1],[2,2]])
65
sage: TestSuite(t).run()
66
67
sage: t.parent()
68
Composition Tableaux
69
sage: t.category()
70
Category of elements of Composition Tableaux
71
"""
72
if isinstance(t, CompositionTableau):
73
return t
74
return CompositionTableaux_all().element_class(CompositionTableaux_all(), t)
75
76
def __init__(self, parent, t):
77
r"""
78
Initialize a composition tableau.
79
80
TESTS::
81
82
sage: t = CompositionTableaux()([[1],[2,2]])
83
sage: s = CompositionTableaux(3)([[1],[2,2]])
84
sage: s==t
85
True
86
sage: t.parent()
87
Composition Tableaux
88
sage: s.parent()
89
Composition Tableaux of size 3 and maximum entry 3
90
sage: r = CompositionTableaux()(s)
91
sage: r.parent()
92
Composition Tableaux
93
"""
94
if isinstance(t, CompositionTableau):
95
Element.__init__(self, parent)
96
CombinatorialObject.__init__(self, t._list)
97
return
98
99
# CombinatorialObject verifies that t is a list
100
# We must verify t is a list of lists
101
if not all(isinstance(row, list) for row in t):
102
raise ValueError("A composition tableau must be a list of lists.")
103
104
if not map(len,t) in Compositions():
105
raise ValueError("A composition tableau must be a list of non-empty lists.")
106
107
# Verify rows weakly decrease from left to right
108
for row in t:
109
if any(row[i] < row[i+1] for i in range(len(row)-1)):
110
raise ValueError("Rows must weakly decrease from left to right.")
111
112
# Verify leftmost column strictly increases from top to bottom
113
first_col = [row[0] for row in t if t!=[[]]]
114
if any(first_col[i] >= first_col[i+1] for i in range(len(t)-1)):
115
raise ValueError("Leftmost column must strictly increase from top to bottom.")
116
117
# Verify triple condition
118
l = len(t)
119
m = max(map(len,t)+[0])
120
TT = [row+[0]*(m-len(row)) for row in t]
121
for i in range(l):
122
for j in range(i+1,l):
123
for k in range(1,m):
124
if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k-1]:
125
raise ValueError("Triple condition must be satisfied.")
126
127
Element.__init__(self, parent)
128
CombinatorialObject.__init__(self, t)
129
130
def _repr_diagram(self):
131
r"""
132
Return a string representation of ``self`` as an array.
133
134
EXAMPLES::
135
136
sage: t = CompositionTableau([[1],[3,2],[4,4]])
137
sage: print t._repr_diagram()
138
1
139
3 2
140
4 4
141
"""
142
return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in self])
143
144
def __call__(self, *cell):
145
r"""
146
Return the value in the corresponding cell of ``self``.
147
148
EXAMPLES::
149
150
sage: t = CompositionTableau([[1],[3,2],[4,4]])
151
sage: t(1,1)
152
2
153
sage: t(2,0)
154
4
155
sage: t(2,2)
156
Traceback (most recent call last):
157
...
158
IndexError: The cell (2,2) is not contained in [[1], [3, 2], [4, 4]]
159
"""
160
try:
161
i,j = cell
162
except ValueError:
163
i,j = cell[0]
164
165
try:
166
return self[i][j]
167
except IndexError:
168
raise IndexError, "The cell (%d,%d) is not contained in %s"%(i,j,self)
169
170
def pp(self):
171
r"""
172
Return a pretty print string of ``self``.
173
174
EXAMPLES::
175
176
sage: CompositionTableau([[1],[3,2],[4,4]]).pp()
177
1
178
3 2
179
4 4
180
"""
181
print self._repr_diagram()
182
183
def size(self):
184
r"""
185
Return the number of boxes in ``self``.
186
187
EXAMPLES::
188
189
sage: CompositionTableau([[1],[3,2],[4,4]]).size()
190
5
191
"""
192
return sum([len(row) for row in self])
193
194
def weight(self):
195
r"""
196
Return a composition where entry `i` is the number of times that `i` appears in
197
``self``.
198
199
EXAMPLES::
200
201
sage: CompositionTableau([[1],[3,2],[4,4]]).weight()
202
[1, 1, 1, 2, 0]
203
"""
204
w = {i:0 for i in range(1,self.size()+1)}
205
for row in self:
206
for i in row:
207
w[i] += 1
208
return Composition([w[i] for i in range(1,self.size()+1)])
209
210
def descent_set(self):
211
r"""
212
Return the set of all `i` that do *not* have `i+1` appearing strictly
213
to the left of `i` in ``self``.
214
215
EXAMPLES::
216
217
sage: CompositionTableau([[1],[3,2],[4,4]]).descent_set()
218
[1, 3]
219
"""
220
cols = {}
221
for row in self:
222
for (col,i) in enumerate(row):
223
cols[i] = col
224
des_set = [i for i in cols if i+1 in cols and cols[i+1] >= cols[i]]
225
des_set.sort()
226
return des_set
227
228
def descent_composition(self):
229
r"""
230
Return the composition corresponding to the set of all `i` that do
231
not have `i+1` appearing strictly to the left of `i` in ``self``.
232
233
EXAMPLES::
234
235
sage: CompositionTableau([[1],[3,2],[4,4]]).descent_composition()
236
[1, 2, 2]
237
"""
238
return Composition(from_subset=(self.descent_set(), self.size()))
239
240
def shape_composition(self):
241
r"""
242
Return a Composition object which is the shape of ``self``.
243
244
EXAMPLES::
245
246
sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).shape_composition()
247
[2, 2, 3]
248
sage: CompositionTableau([[2,1],[3],[4]]).shape_composition()
249
[2, 1, 1]
250
"""
251
return Composition([len(row) for row in self])
252
253
def shape_partition(self):
254
r"""
255
Return a partition which is the shape of ``self`` sorted into weakly
256
decreasing order.
257
258
EXAMPLES::
259
260
sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).shape_partition()
261
[3, 2, 2]
262
sage: CompositionTableau([[2,1],[3],[4]]).shape_partition()
263
[2, 1, 1]
264
"""
265
return Partition(sorted([len(row) for row in self], reverse=True))
266
267
def is_standard(self):
268
r"""
269
Return ``True`` if ``self`` is a standard composition tableau and
270
``False`` otherwise.
271
272
EXAMPLES::
273
274
sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).is_standard()
275
False
276
sage: CompositionTableau([[2,1],[3],[4]]).is_standard()
277
True
278
"""
279
entries = sum(self,[])
280
return sorted(entries) == range(1, self.size() + 1)
281
282
class CompositionTableaux(UniqueRepresentation, Parent):
283
r"""
284
Composition tableaux.
285
286
INPUT:
287
288
Keyword arguments:
289
290
- ``size`` -- the size of the composition tableaux
291
- ``shape`` -- the shape of the composition tableaux
292
- ``max_entry`` -- the maximum entry for the composition tableaux
293
294
Positional arguments:
295
296
- The first argument is interpreted as ``size`` or ``shape`` depending on
297
whether it is an integer or a composition.
298
299
EXAMPLES::
300
301
sage: CT = CompositionTableaux(3); CT
302
Composition Tableaux of size 3 and maximum entry 3
303
sage: list(CT)
304
[[[1], [2], [3]],
305
[[1], [2, 2]],
306
[[1], [3, 2]],
307
[[1], [3, 3]],
308
[[2], [3, 3]],
309
[[1, 1], [2]],
310
[[1, 1], [3]],
311
[[2, 1], [3]],
312
[[2, 2], [3]],
313
[[1, 1, 1]],
314
[[2, 1, 1]],
315
[[2, 2, 1]],
316
[[2, 2, 2]],
317
[[3, 1, 1]],
318
[[3, 2, 1]],
319
[[3, 2, 2]],
320
[[3, 3, 1]],
321
[[3, 3, 2]],
322
[[3, 3, 3]]]
323
324
sage: CT = CompositionTableaux([1,2,1]); CT
325
Composition tableaux of shape [1, 2, 1] and maximun entry 4
326
sage: list(CT)
327
[[[1], [2, 2], [3]],
328
[[1], [2, 2], [4]],
329
[[1], [3, 2], [4]],
330
[[1], [3, 3], [4]],
331
[[2], [3, 3], [4]]]
332
333
sage: CT = CompositionTableaux(shape=[1,2,1],max_entry=3); CT
334
Composition tableaux of shape [1, 2, 1] and maximun entry 3
335
sage: list(CT)
336
[[[1], [2, 2], [3]]]
337
338
sage: CT = CompositionTableaux(2,max_entry=3); CT
339
Composition Tableaux of size 2 and maximum entry 3
340
sage: list(CT)
341
[[[1], [2]],
342
[[1], [3]],
343
[[2], [3]],
344
[[1, 1]],
345
[[2, 1]],
346
[[2, 2]],
347
[[3, 1]],
348
[[3, 2]],
349
[[3, 3]]]
350
351
sage: CT = CompositionTableaux(0); CT
352
Composition Tableaux of size 0 and maximum entry 0
353
sage: list(CT)
354
[[]]
355
"""
356
@staticmethod
357
def __classcall_private__(cls, *args, **kwargs):
358
r"""
359
This is a factory class which returns the appropriate parent based on
360
arguments. See the documentation for :class:`CompositionTableaux` for
361
more information.
362
363
TESTS::
364
365
sage: CT = CompositionTableaux(3); CT
366
Composition Tableaux of size 3 and maximum entry 3
367
sage: CT = CompositionTableaux(size=3); CT
368
Composition Tableaux of size 3 and maximum entry 3
369
sage: CT = CompositionTableaux([1,2]); CT
370
Composition tableaux of shape [1, 2] and maximun entry 3
371
sage: CT = CompositionTableaux(shape=[1,2]); CT
372
Composition tableaux of shape [1, 2] and maximun entry 3
373
sage: CT = CompositionTableaux(shape=[]); CT
374
Composition tableaux of shape [] and maximun entry 0
375
sage: CT = CompositionTableaux(0); CT
376
Composition Tableaux of size 0 and maximum entry 0
377
sage: CT = CompositionTableaux(max_entry=3); CT
378
Composition tableaux with maximum entry 3
379
sage: CT = CompositionTableaux([1,2],max_entry=3); CT
380
Composition tableaux of shape [1, 2] and maximun entry 3
381
sage: CT = CompositionTableaux(size=2,shape=[1,2]); CT
382
Traceback (most recent call last):
383
...
384
ValueError: size and shape are different sizes
385
"""
386
# Process keyword arguments first
387
n = kwargs.get('n', None)
388
size = kwargs.get('size', n)
389
390
comp = kwargs.get('comp', None)
391
shape = kwargs.get('shape', comp)
392
393
max_entry = kwargs.get('max_entry', None)
394
395
# Process positional arguments
396
if args:
397
# The first arg could be either a size or a shape
398
if isinstance(args[0], (int, Integer)):
399
if size is not None:
400
raise ValueError("size was specified more than once")
401
else:
402
size = args[0]
403
else:
404
if shape is not None:
405
raise ValueError("the shape was specified more than once")
406
shape = args[0]
407
408
# Consistency checks
409
if size is not None:
410
if not isinstance(size, (int, Integer)):
411
raise ValueError("size must be an integer")
412
elif size < 0:
413
raise ValueError("size must be non-negative")
414
415
if shape is not None:
416
# use in (and not isinstance) below so that lists can be used as
417
# shorthand
418
if not shape in Compositions():
419
raise ValueError("shape must be a composition")
420
if any(i == 0 for i in shape):
421
raise ValueError("shape must have non-zero parts")
422
shape = Composition(shape)
423
424
if (size is not None) and (shape is not None):
425
if sum(shape) != size:
426
raise ValueError("size and shape are different sizes")
427
428
if max_entry is not None:
429
if not isinstance(max_entry, (int, Integer)):
430
raise ValueError("max_entry must be an integer")
431
elif max_entry <= 0:
432
raise ValueError("max_entry must be positive")
433
434
# Dispatch to appropriate class
435
if (shape is not None):
436
return CompositionTableaux_shape(shape, max_entry)
437
438
if (size is not None):
439
return CompositionTableaux_size(size, max_entry)
440
441
return CompositionTableaux_all(max_entry)
442
443
def __init__(self, **kwds):
444
r"""
445
Initialize ``self``.
446
447
TESTS::
448
449
sage: CT = CompositionTableaux()
450
sage: TestSuite(CT).run()
451
"""
452
if kwds.has_key('max_entry'):
453
self.max_entry = kwds['max_entry']
454
kwds.pop('max_entry')
455
else:
456
self.max_entry = None
457
super(CompositionTableaux, self).__init__(**kwds)
458
459
Element = CompositionTableau
460
461
def _element_constructor_(self, t):
462
r"""
463
Construct an object from ``t`` as an element of ``self``, if
464
possible.
465
466
INPUT:
467
468
- ``t`` -- data which can be interpreted as a composition tableau
469
470
OUTPUT:
471
472
- The corresponding CompositionTableau object
473
474
TESTS::
475
476
sage: CT = CompositionTableaux(3)
477
sage: CT([[1],[2,2]]).parent() is CT
478
True
479
sage: CT([[1],[1,2]])
480
Traceback (most recent call last):
481
...
482
ValueError: [[1], [1, 2]] is not an element of Composition Tableaux of size 3 and maximum entry 3.
483
"""
484
if not t in self:
485
raise ValueError("%s is not an element of %s."%(t, self))
486
487
return self.element_class(self, t)
488
489
def __contains__(self, T):
490
r"""
491
Return ``True`` if ``T`` can be interpreted as
492
:class:`CompositionTableau`.
493
494
TESTS::
495
496
sage: [[1],[2,2]] in CompositionTableaux(3)
497
True
498
sage: [[1],[2,2]] in CompositionTableaux(shape=[1,2])
499
True
500
sage: CompositionTableau([[1],[2,2]]) in CompositionTableaux()
501
True
502
sage: [[1],[2,2],[2]] in CompositionTableaux()
503
False
504
"""
505
if isinstance(T, CompositionTableau):
506
return True
507
508
# leftmost column of T strictly increases from top to bottom
509
first_col = [row[0] for row in T]
510
if any(first_col[i] >= first_col[i+1] for i in range(len(T)-1)):
511
return False
512
# rows of T weakly decrease from left to right
513
for row in T:
514
if any(row[i] < row[i+1] for i in range(len(row)-1)):
515
return False
516
# for 1 <= i < j <= len(comp), for 2 <= k <= m,
517
# T[j,k] \neq 0 and T[j,k] >= T[i,k] ==> T[j,k] > T[i,k-1]
518
l = len(T)
519
m = max(map(len,T)+[0])
520
TT = [row+[0]*(m-len(row)) for row in T]
521
for i in range(l):
522
for j in range(i+1,l):
523
for k in range(1,m):
524
if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k-1]:
525
return False
526
return True
527
528
class CompositionTableaux_all(CompositionTableaux, DisjointUnionEnumeratedSets):
529
r"""
530
All composition tableaux.
531
"""
532
def __init__(self, max_entry=None):
533
r"""
534
Initialize ``self``.
535
536
TESTS::
537
538
sage: CT = CompositionTableaux()
539
sage: TestSuite(CT).run()
540
"""
541
self.max_entry = max_entry
542
CT_n = lambda n: CompositionTableaux_size(n, max_entry)
543
DisjointUnionEnumeratedSets.__init__(self,
544
Family(NonNegativeIntegers(), CT_n),
545
facade=True, keepkey = False)
546
547
def _repr_(self):
548
r"""
549
TESTS::
550
551
sage: CompositionTableaux(3)
552
Composition Tableaux of size 3 and maximum entry 3
553
554
sage: CompositionTableaux()
555
Composition Tableaux
556
"""
557
if self.max_entry is not None:
558
return "Composition tableaux with maximum entry %s"%str(self.max_entry)
559
return "Composition Tableaux"
560
561
def an_element(self):
562
r"""
563
Return a particular element of ``self``.
564
565
EXAMPLES::
566
567
sage: CT = CompositionTableaux()
568
sage: CT.an_element()
569
[[1, 1], [2]]
570
"""
571
return self.element_class(self, [[1, 1], [2]])
572
573
class CompositionTableaux_size(CompositionTableaux):
574
r"""
575
Composition tableaux of a fixed size `n`.
576
577
INPUT:
578
579
- ``n`` -- a nonnegative integer.
580
- ``max_entry`` -- a nonnegative integer. This keyword argument defaults to ``n``.
581
582
OUTUT:
583
584
- The class of composition tableaux of size ``n``.
585
"""
586
def __init__(self, n, max_entry=None):
587
r"""
588
Initializes the class of composition tableaux of size ``n``.
589
590
TESTS::
591
592
sage: CT = CompositionTableaux(4)
593
sage: TestSuite(CT).run()
594
"""
595
if max_entry is None:
596
max_entry = n
597
super(CompositionTableaux_size, self).__init__(max_entry=max_entry,
598
category=FiniteEnumeratedSets())
599
self.size = n
600
601
def __contains__(self,x):
602
r"""
603
TESTS::
604
605
sage: [[1],[2,2]] in CompositionTableaux(3)
606
True
607
sage: [[1],[2,2]] in CompositionTableaux(4)
608
False
609
"""
610
return CompositionTableaux.__contains__(self, x) and sum(map(len,x)) == self.size
611
612
def __iter__(self):
613
r"""
614
EXAMPLES::
615
616
sage: [t for t in CompositionTableaux(3)]
617
[[[1], [2], [3]],
618
[[1], [2, 2]],
619
[[1], [3, 2]],
620
[[1], [3, 3]],
621
[[2], [3, 3]],
622
[[1, 1], [2]],
623
[[1, 1], [3]],
624
[[2, 1], [3]],
625
[[2, 2], [3]],
626
[[1, 1, 1]],
627
[[2, 1, 1]],
628
[[2, 2, 1]],
629
[[2, 2, 2]],
630
[[3, 1, 1]],
631
[[3, 2, 1]],
632
[[3, 2, 2]],
633
[[3, 3, 1]],
634
[[3, 3, 2]],
635
[[3, 3, 3]]]
636
637
sage: CompositionTableaux(3)[0].parent() is CompositionTableaux(3)
638
True
639
"""
640
for comp in Compositions(self.size):
641
for T in CompositionTableaux_shape(comp,self.max_entry):
642
yield self.element_class(self, T)
643
644
def _repr_(self):
645
r"""
646
TESTS::
647
648
sage: CompositionTableaux(3)
649
Composition Tableaux of size 3 and maximum entry 3
650
"""
651
return "Composition Tableaux of size %s and maximum entry %s"%(str(self.size), str(self.max_entry))
652
653
def _an_element_(self):
654
r"""
655
Return a particular element of ``self``.
656
657
EXAMPLES::
658
659
sage: CT = CompositionTableaux(4)
660
sage: CT.an_element()
661
[[1, 1, 1], [2]]
662
sage: CompositionTableaux(0).an_element()
663
[]
664
sage: CompositionTableaux(1).an_element()
665
[[1]]
666
"""
667
if self.size == 0:
668
return self.element_class(self, [])
669
if self.size == 1:
670
return self.element_class(self,[[1]])
671
672
return self.element_class(self, [[1]*(self.size-1),[2]])
673
674
class CompositionTableaux_shape(CompositionTableaux):
675
r"""
676
Composition tableaux of a fixed shape ``comp`` with a given max entry.
677
678
INPUT:
679
680
- ``comp`` -- a composition.
681
- ``max_entry`` -- a nonnegative integer. This keyword argument defaults
682
to the size of ``comp``.
683
"""
684
def __init__(self, comp, max_entry=None):
685
"""
686
Initialize ``sefl``.
687
688
TESTS::
689
690
sage: CT = CompositionTableaux([1,2])
691
sage: TestSuite(CT).run()
692
693
sage: CT = CompositionTableaux([1,2], max_entry=4)
694
sage: TestSuite(CT).run()
695
"""
696
if max_entry is None:
697
max_entry = sum(comp)
698
super(CompositionTableaux_shape, self).__init__(max_entry = max_entry,
699
category = FiniteEnumeratedSets())
700
self.shape = comp
701
702
def __iter__(self):
703
r"""
704
An iterator for composition tableaux of a given shape.
705
706
EXAMPLES::
707
708
sage: [t for t in CompositionTableaux([1,2])]
709
[[[1], [2, 2]], [[1], [3, 2]], [[1], [3, 3]], [[2], [3, 3]]]
710
sage: [t for t in CompositionTableaux([1,2],max_entry=4)]
711
[[[1], [2, 2]],
712
[[1], [3, 2]],
713
[[1], [3, 3]],
714
[[1], [4, 2]],
715
[[1], [4, 3]],
716
[[1], [4, 4]],
717
[[2], [3, 3]],
718
[[2], [4, 3]],
719
[[2], [4, 4]],
720
[[3], [4, 4]]]
721
"""
722
if sum(self.shape) == 0:
723
yield CompositionTableau([])
724
else:
725
for z in CompositionTableauxBacktracker(self.shape, self.max_entry):
726
yield CompositionTableau(z)
727
728
def __contains__(self, x):
729
r"""
730
TESTS::
731
732
sage: [[2],[4,3]] in CompositionTableaux([1,2])
733
True
734
sage: [[2],[3,2]] in CompositionTableaux([1,2])
735
False
736
"""
737
return CompositionTableaux.__contains__(self, x) and map(len, x) == self.shape
738
739
def _repr_(self):
740
r"""
741
TESTS::
742
743
sage: CompositionTableaux([1,2,1])
744
Composition tableaux of shape [1, 2, 1] and maximun entry 4
745
sage: CompositionTableaux([1,2,1],max_entry=3)
746
Composition tableaux of shape [1, 2, 1] and maximun entry 3
747
"""
748
return "Composition tableaux of shape %s and maximun entry %s"%(str(self.shape), str(self.max_entry))
749
750
def an_element(self):
751
r"""
752
Return a particular element of :class:`CompositionTableaux_shape`.
753
754
EXAMPLES::
755
756
sage: CT = CompositionTableaux([1,2,1])
757
sage: CT.an_element()
758
[[1], [2, 2], [3]]
759
"""
760
if self.shape == []:
761
return self.element_class(self, [])
762
t = [[i]*len for (i,len) in enumerate(self.shape,start=1)]
763
return self.element_class(self, t)
764
765
class CompositionTableauxBacktracker(GenericBacktracker):
766
r"""
767
A backtracker class for generating sets of composition tableaux.
768
"""
769
def __init__(self, shape, max_entry=None):
770
"""
771
EXAMPLES::
772
773
sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker
774
sage: n = CompositionTableauxBacktracker([1,3,2])
775
sage: n._ending_position
776
(2, 1)
777
sage: n._initial_state
778
(0, 0)
779
"""
780
self._shape = shape
781
self._n = sum(shape)
782
self._initial_data = [ [None]*s for s in shape ]
783
if max_entry==None:
784
max_entry=sum(shape)
785
self.max_entry=max_entry
786
787
# The ending position will be at the lowest box which is farthest right
788
ending_row = len(shape)-1
789
ending_col = shape[-1]-1
790
self._ending_position = (ending_row, ending_col)
791
792
# Get the highest box that is farthest left
793
starting_row = 0
794
starting_col = 0
795
796
GenericBacktracker.__init__(self, self._initial_data, (starting_row, starting_col))
797
798
def _rec(self, obj, state):
799
r"""
800
EXAMPLES::
801
802
sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker
803
sage: n = CompositionTableauxBacktracker([1,3,2])
804
sage: obj = [ [None], [None, None, None], [None, None] ]
805
sage: list(n._rec(obj, n._initial_state))
806
[([[1], [None, None, None], [None, None]], (1, 0), False),
807
([[2], [None, None, None], [None, None]], (1, 0), False),
808
([[3], [None, None, None], [None, None]], (1, 0), False),
809
([[4], [None, None, None], [None, None]], (1, 0), False),
810
([[5], [None, None, None], [None, None]], (1, 0), False),
811
([[6], [None, None, None], [None, None]], (1, 0), False)]
812
"""
813
#Append zeros to a copy of obj
814
obj_copy = copy.deepcopy(obj)
815
for a in range(len(obj_copy)):
816
for b in range(len(max(obj_copy))-len(obj_copy[a])):
817
obj_copy[a].append(0)
818
819
#We need to set the i,j^th entry.
820
i, j = state
821
822
#Get the next state
823
new_state = self.get_next_pos(i, j)
824
yld = True if new_state is None else False
825
826
for k in range(1,self.max_entry +1):
827
#We check to make sure that k does not violate the rule weak decrease in rows
828
if j!=0 and obj[i][j-1] < k:
829
continue
830
831
#We check to make sure that k does not violate strict increase in first column
832
if j == 0 and i != 0 and k <= obj[i-1][j]:
833
continue
834
835
#We check to make sure that k does not violate the Triple Rule
836
if j != 0 and i != 0 and any(k == obj_copy[m][j] for m in range(i)):
837
continue
838
if j != 0 and i != 0 and any(obj_copy[m][j] < k and k <= obj_copy[m][j-1] for m in range(i)):
839
continue
840
841
#Fill in the in the i,j box with k
842
obj[i][j] = k
843
obj_copy[i][j] = k
844
845
#Yield the object
846
yield copy.deepcopy(obj), new_state, yld
847
848
def get_next_pos(self, ii, jj):
849
r"""
850
EXAMPLES::
851
852
sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker
853
sage: T = CompositionTableau([[2,1],[5,4,3,2],[6],[7,7,6]])
854
sage: n = CompositionTableauxBacktracker(T.shape_composition())
855
sage: n.get_next_pos(1,1)
856
(1, 2)
857
"""
858
if (ii, jj) == self._ending_position:
859
return None
860
861
for j in range(jj+1, self._shape[ii]):
862
if self._shape[ii] >= j:
863
return ii, j
864
865
return ii+1, 0
866
867
868