From 81b59faf9c967d494bbac3ca16fe41205383f6ca Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 22 Aug 2023 23:10:42 +0200 Subject: [PATCH 1/4] fix cardinality, #36119, #36118, #36116 --- src/sage/combinat/plane_partition.py | 84 ++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index e7cb63842b9..9228fedc490 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -74,6 +74,7 @@ class PlanePartition(ClonableArray, sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: TestSuite(PP).run() + sage: hash(PP) # random """ @staticmethod def __classcall_private__(cls, PP, box_size=None): @@ -118,13 +119,14 @@ def __init__(self, parent, pp, check=True): if isinstance(pp, PlanePartition): ClonableArray.__init__(self, parent, pp, check=False) else: - pp = [list(_) for _ in pp] + pp = [list(row) for row in pp] if pp: for i in reversed(range(len(pp))): while pp[i] and not pp[i][-1]: del pp[i][-1] if not pp[i]: pp.pop(i) + pp = [tuple(row) for row in pp] ClonableArray.__init__(self, parent, pp, check=check) if self.parent()._box is None: if pp: @@ -232,7 +234,7 @@ def _repr_(self) -> str: sage: PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] """ - return "Plane partition {}".format(list(self)) + return "Plane partition {}".format([list(row) for row in self]) def to_tableau(self) -> Tableau: r""" @@ -1089,7 +1091,7 @@ def maximal_boxes(self) -> list: for j, entry in enumerate(row): if (i == len(self)-1 or len(self[i+1])-1 < j or self[i+1][j] < entry) and (j == len(row)-1 or row[j+1] < entry): generate.append([i, j, entry-1]) - return(generate) + return generate def cyclically_rotate(self, preserve_parent=False) -> PP: r""" @@ -1300,6 +1302,10 @@ def __classcall_private__(cls, *args, **kwds): Plane partitions of size 3 sage: PlanePartitions([4,4,4], symmetry='TSSCPP') Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + sage: PlanePartitions(4, symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: the number of boxes may only be specified if no symmetry is required """ symmetry = kwds.get('symmetry', None) box_size = kwds.get('box_size', None) @@ -1310,8 +1316,10 @@ def __classcall_private__(cls, *args, **kwds): if args and box_size is None: # The first arg could be either a size or a box size if isinstance(args[0], (int, Integer)): - return PlanePartitions_n(args[0]) - + if symmetry is None: + return PlanePartitions_n(args[0]) + else: + raise ValueError("the number of boxes may only be specified if no symmetry is required") box_size = args[0] box_size = tuple(box_size) @@ -1445,8 +1453,10 @@ def __init__(self): # super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), PlanePartitions_n), - facade=True, keepkey=False) + Family(NonNegativeIntegers(), + PlanePartitions_n), + facade=True, + keepkey=False) def _repr_(self) -> str: """ @@ -1632,11 +1642,16 @@ def cardinality(self) -> Integer: A = self._box[0] B = self._box[1] C = self._box[2] - return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) + return Integer(prod(i + j + k - 1 + for i in range(1, A + 1) + for j in range(1, B + 1) + for k in range(1, C + 1)) // + prod(i + j + k - 2 for i in range(1, A + 1) for j in range(1, B + 1) for k in range(1, C + 1))) + def random_element(self) -> PP: r""" Return a uniformly random plane partition inside a box. @@ -1708,6 +1723,11 @@ def __iter__(self) -> Iterator: sage: list(PlanePartitions(2)) [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 10) if (PP := PlanePartitions(n))) + True """ from sage.combinat.partition import Partitions @@ -1922,6 +1942,11 @@ def __iter__(self) -> Iterator: Plane partition [[1, 1], [1, 1]], Plane partition [[1, 1], [1]], Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='SPP'))) + True """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) @@ -1946,11 +1971,15 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - left_prod = prod((2*i + c - 1) / (2*i - 1) for i in range(1, a+1)) - right_prod = prod((i + j + c - 1) / (i + j - 1) - for j in range(1, a+1) - for i in range(1, j)) - return Integer(left_prod * right_prod) + left_prod_num = prod(2*i + c - 1 for i in range(1, a+1)) + left_prod_den = prod(2*i - 1 for i in range(1, a+1)) + right_prod_num = prod(i + j + c - 1 + for j in range(1, a+1) + for i in range(1, j)) + right_prod_den = prod(i + j - 1 + for j in range(1, a+1) + for i in range(1, j)) + return Integer(left_prod_num * right_prod_num // left_prod_den // right_prod_den) def random_element(self) -> PP: r""" @@ -2143,6 +2172,11 @@ def __iter__(self) -> Iterator: Plane partition [[2, 2], [2, 1]], Plane partition [[2, 1], [1]], Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='CSPP'))) + True """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) @@ -2321,6 +2355,11 @@ def __iter__(self) -> Iterator: Plane partition [[2, 2], [2, 1]], Plane partition [[2, 1], [1]], Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='TSPP'))) + True """ for A in self.to_poset().antichains_iterator(): yield self.from_antichain(A) @@ -2343,8 +2382,8 @@ def cardinality(self) -> Integer: 66 """ a = self._box[0] - return Integer(prod((i + j + a - 1) / (i + 2*j - 2) - for j in range(1, a+1) for i in range(1, j+1))) + return Integer(prod(i + j + a - 1 for j in range(1, a+1) for i in range(1, j+1)) + // prod(i + 2*j - 2 for j in range(1, a+1) for i in range(1, j+1))) # Class 5 @@ -2412,6 +2451,12 @@ def __iter__(self) -> Iterator: Plane partition [[2], [2], [2]], Plane partition [[2, 1], [2], [1]], Plane partition [[2, 2], [2]]] + + TESTS:: + + sage: PP = PlanePartitions([3,4,5], symmetry='SCPP') + sage: len(set(PP)) == PP.cardinality() + True """ b = self._box[0] a = self._box[1] @@ -3037,9 +3082,9 @@ def from_antichain(self, acl) -> PP: height = N - 1 # generate inner triangle - # FIXME: Make this ierator more efficient + # FIXME: Make this iterator more efficient for i in range(width): - for j in range(min(height, i+1)): + for j in range(i, height): for ac in acl: if ac[0] == i and ac[1] == j: zVal = ac[2] @@ -3129,6 +3174,11 @@ def __iter__(self) -> Iterator: sage: list(PlanePartitions([4,4,4], symmetry='TSSCPP')) [Plane partition [[4, 4, 2, 2], [4, 4, 2, 2], [2, 2], [2, 2]], Plane partition [[4, 4, 3, 2], [4, 3, 2, 1], [3, 2, 1], [2, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(0,11,2) if (PP := PlanePartitions([n]*3, symmetry='TSSCPP'))) + True """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) From 947506e05d7723e7e28d491b5a8d4bc9364bfe9e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 23 Aug 2023 08:08:39 +0200 Subject: [PATCH 2/4] remove extra blank line, remove unused imports, slightly unify cardinality --- src/sage/combinat/plane_partition.py | 51 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 9228fedc490..969f2eee3dd 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -38,7 +38,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer_ring import ZZ -from sage.arith.misc import Sigma, integer_floor as floor, integer_ceil as ceil, binomial, factorial +from sage.arith.misc import Sigma, binomial, factorial from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers @@ -1651,7 +1651,6 @@ def cardinality(self) -> Integer: for j in range(1, B + 1) for k in range(1, C + 1))) - def random_element(self) -> PP: r""" Return a uniformly random plane partition inside a box. @@ -2200,13 +2199,13 @@ def cardinality(self) -> Integer: 132 """ a = self._box[0] - numerator = (prod(3*i - 1 for i in range(1, a+1)) - * prod(i + j + a - 1 for j in range(1, a+1) - for i in range(1, j+1))) - denominator = (prod(3*i - 2 for i in range(1, a+1)) - * prod(2*i + j - 1 for j in range(1, a+1) - for i in range(1, j+1))) - return Integer(numerator // denominator) + num = (prod(3*i - 1 for i in range(1, a + 1)) + * prod(i + j + a - 1 for j in range(1, a + 1) + for i in range(1, j + 1))) + den = (prod(3*i - 2 for i in range(1, a + 1)) + * prod(2*i + j - 1 for j in range(1, a + 1) + for i in range(1, j + 1))) + return Integer(num // den) # Class 4 @@ -2382,8 +2381,9 @@ def cardinality(self) -> Integer: 66 """ a = self._box[0] - return Integer(prod(i + j + a - 1 for j in range(1, a+1) for i in range(1, j+1)) - // prod(i + 2*j - 2 for j in range(1, a+1) for i in range(1, j+1))) + num = prod(i + j + a - 1 for j in range(1, a + 1) for i in range(1, j + 1)) + den = prod(i + 2*j - 2 for j in range(1, a + 1) for i in range(1, j + 1)) + return Integer(num // den) # Class 5 @@ -2740,9 +2740,9 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - return Integer(binomial(c//2 + a - 1, a - 1) + return Integer(binomial(c // 2 + a - 1, a - 1) * prod((c + i + j + 1) / (i + j + 1) - for j in range(1, 1+a-2) for i in range(1, 1+j))) + for j in range(1, a - 1) for i in range(1, 1 + j))) # Class 7 @@ -2837,10 +2837,15 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) - for i in range(1, 1+a//2) - for j in range(1, 1+ceil(a/2)) - for k in range(1, 1+c//2))) + num = prod(i + j + k - 1 + for i in range(1, 1 + a // 2) + for j in range(1, 1 + (a + 1) // 2) + for k in range(1, 1 + c // 2)) + den = prod(i + j + k - 2 + for i in range(1, 1 + a // 2) + for j in range(1, 1 + (a + 1) // 2) + for k in range(1, 1 + c // 2)) + return Integer(num // den) # Class 8 @@ -2914,7 +2919,9 @@ def cardinality(self) -> Integer: 11 """ a = self._box[0] // 2 - return Integer(prod((3*i+1) * factorial(6*i) * factorial(2*i) / (factorial(4*i+1) * factorial(4*i)) for i in range(a))) + num = prod((3*i + 1) * factorial(6*i) * factorial(2*i) for i in range(a)) + den = prod((factorial(4*i + 1) * factorial(4*i)) for i in range(a)) + return Integer(num // den) # Class 9 @@ -2988,7 +2995,9 @@ def cardinality(self) -> Integer: 49 """ a = self._box[0] // 2 - return Integer(prod(factorial(3*i+1)**2 / factorial(a+i)**2 for i in range(a))) + num = prod(factorial(3*i + 1)**2 for i in range(a)) + den = prod(factorial(a + i)**2 for i in range(a)) + return Integer(num // den) # Class 10 @@ -3202,4 +3211,6 @@ def cardinality(self) -> Integer: 7 """ a = self._box[0] // 2 - return Integer(prod(factorial(3*i+1) / factorial(a+i) for i in range(a))) + num = prod(factorial(3*i + 1) for i in range(a)) + den = prod(factorial(a + i) for i in range(a)) + return Integer(num // den) From 676974934b9f69087c9f0bd32a8e511ee766f17e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 23 Aug 2023 15:40:04 +0200 Subject: [PATCH 3/4] fix is_XXX for empty partitions, fix __iter__ for SCPP, improve performance of __iter__ for SSCPP, CSTCPP and CSSCPP --- src/sage/combinat/plane_partition.py | 170 ++++++++++++++++++++------- 1 file changed, 126 insertions(+), 44 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 969f2eee3dd..92630fa55d0 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -879,7 +879,14 @@ def is_SPP(self) -> bool: sage: PP = PlanePartition([[3,2],[2,0],[0,0]]) sage: PP.is_SPP() True + + TESTS:: + + sage: PlanePartition([]).is_SPP() + True """ + if not self: + return True Z = self.z_tableau() c1 = len(Z) c2 = len(Z[0]) @@ -907,6 +914,11 @@ def is_CSPP(self) -> bool: sage: PP = PlanePartition([[3,2,2],[3,1,0],[1,1,0]]) sage: PP.is_CSPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSPP() + True """ if self.z_tableau() == self.y_tableau(): return True @@ -927,6 +939,11 @@ def is_TSPP(self) -> bool: sage: PP = PlanePartition([[3,3,3],[3,3,2],[3,2,1]]) sage: PP.is_TSPP() True + + TESTS:: + + sage: PlanePartition([]).is_TSPP() + True """ return self.is_CSPP() and self.is_SPP() @@ -950,6 +967,11 @@ def is_SCPP(self) -> bool: sage: PP = PlanePartitions([4,4,4])([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) sage: PP.is_SCPP() True + + TESTS:: + + sage: PlanePartition([]).is_SCPP() + True """ return self.z_tableau(tableau=False) == self.complement(tableau_only=True) @@ -965,6 +987,11 @@ def is_TCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,4,2,1],[4,2,0,0],[2,0,0,0]]) sage: PP.is_TCPP() True + + TESTS:: + + sage: PlanePartition([]).is_TCPP() + True """ return self.transpose(True) == self.complement(True) @@ -990,6 +1017,11 @@ def is_SSCPP(self) -> bool: sage: PP = PlanePartition([[4,2,2,2],[2,2,2,2],[2,2,2,2],[2,2,2,0]]) sage: PP.is_SSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_SSCPP() + True """ return self.is_SPP() and self.is_SCPP() @@ -1006,6 +1038,11 @@ def is_CSTCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,3,2,1],[3,2,1,0],[2,1,0,0]]) sage: PP.is_CSTCPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSTCPP() + True """ return self.is_CSPP() and self.is_TCPP() @@ -1022,6 +1059,11 @@ def is_CSSCPP(self) -> bool: sage: PP = PlanePartition([[4,4,4,1],[3,3,2,1],[3,2,1,1],[3,0,0,0]]) sage: PP.is_CSSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSSCPP() + True """ return self.is_CSPP() and self.is_SCPP() @@ -1038,6 +1080,11 @@ def is_TSSCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,3,2,1],[3,2,1,0],[2,1,0,0]]) sage: PP.is_TSSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_TSSCPP() + True """ return self.is_TSPP() and self.is_SCPP() @@ -1609,10 +1656,20 @@ def __iter__(self) -> Iterator: sage: list(PlanePartitions([1,2,1])) [Plane partition [], Plane partition [[1]], Plane partition [[1, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for b in cartesian_product([range(4)]*3) + ....: if (PP := PlanePartitions(b))) + True """ A = self._box[0] B = self._box[1] C = self._box[2] + if not A: + yield self.element_class(self, [], check=False) + return from sage.combinat.tableau import SemistandardTableaux as SST for T in SST([B for i in range(A)], max_entry=C + A): # type:ignore PP = [[0 for _ in range(B)] for _ in range(A)] @@ -1725,7 +1782,7 @@ def __iter__(self) -> Iterator: TESTS:: - sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 10) if (PP := PlanePartitions(n))) + sage: all(len(set(PP)) == PP.cardinality() for n in range(9) if (PP := PlanePartitions(n))) True """ from sage.combinat.partition import Partitions @@ -1944,7 +2001,9 @@ def __iter__(self) -> Iterator: TESTS:: - sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='SPP'))) + sage: all(len(set(PP)) == PP.cardinality() + ....: for a, b in cartesian_product([range(4)]*2) + ....: if (PP := PlanePartitions([a, a, b], symmetry='SPP'))) True """ for acl in self.to_poset().antichains_iterator(): @@ -2174,7 +2233,7 @@ def __iter__(self) -> Iterator: TESTS:: - sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='CSPP'))) + sage: all(len(set(PP)) == PP.cardinality() for n in range(5) if (PP := PlanePartitions([n]*3, symmetry='CSPP'))) True """ for acl in self.to_poset().antichains_iterator(): @@ -2357,11 +2416,11 @@ def __iter__(self) -> Iterator: TESTS:: - sage: all(len(set(PP)) == PP.cardinality() for n in range(1, 5) if (PP := PlanePartitions([n]*3, symmetry='TSPP'))) + sage: all(len(set(PP)) == PP.cardinality() for n in range(5) if (PP := PlanePartitions([n]*3, symmetry='TSPP'))) True """ - for A in self.to_poset().antichains_iterator(): - yield self.from_antichain(A) + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) def cardinality(self) -> Integer: r""" @@ -2457,37 +2516,39 @@ def __iter__(self) -> Iterator: sage: PP = PlanePartitions([3,4,5], symmetry='SCPP') sage: len(set(PP)) == PP.cardinality() True + + sage: all(len(set(PP)) == PP.cardinality() + ....: for b in cartesian_product([range(4)]*3) + ....: if is_even(prod(b)) and (PP := PlanePartitions(b, symmetry='SCPP'))) + True """ b = self._box[0] a = self._box[1] c = self._box[2] def Partitions_inside_lambda(la): - "Iterate over all partitions contained in la with the same number of parts including 0s." - if not la: - yield [] - return - for mu_0 in range(la[0], 0, -1): - new_la = [min(mu_0, la[i]) for i in range(1, len(la))] - for mu in Partitions_inside_lambda(new_la): - yield [mu_0] + mu - yield [0] * len(la) - return + """ + Iterate over all partitions contained in la with the same number + of parts including 0s. + """ + from sage.combinat.partition import Partitions + for k in range(sum(la), -1, -1): + for mu in Partitions(k, outer=la): + yield mu + [0]*(len(la)-len(mu)) def Partitions_inside_lambda_with_smallest_at_least_k(la, k): - "Iterate over all partitions contained in la with the smallest entry at least k." - if not la: - yield [] - return - if la[-1] < k: - yield - return - for mu in Partitions_inside_lambda([val-k for val in la]): + """ + Iterate over all partitions contained in la with the smallest + entry at least k. + """ + for mu in Partitions_inside_lambda([val - k for val in la]): yield [mu[i] + k for i in range(len(la))] - return def possible_middle_row_for_b_odd(a, c): - "Iterate over all possible middle row for SCPP inside box(a,b,c) when b is odd." + """ + Iterate over all possible middle row for SCPP inside box(a,b,c) + when b is odd. + """ if a * c % 2 == 1: yield return @@ -2496,18 +2557,22 @@ def possible_middle_row_for_b_odd(a, c): if not a % 2: la = nu + mu else: - la = nu + [c//2] + mu + la = nu + [c // 2] + mu yield la - return def possible_middle_row_for_b_even(a, c): - "Iterate over all possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even." + """ + Iterate over all possible middle ((b/2)+1)st row for SCPP inside + box(a,b,c) when b is even. + """ for mu in Partitions_inside_lambda([c // 2 for i in range((a+1) // 2)]): + if not mu: + yield [] + continue nu = [c - mu[len(mu)-1-i] for i in range(a // 2)] for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu, mu[0]): la = tau + mu yield la - return def PPs_with_first_row_la_and_with_k_rows(la, k): "Iterate over PPs with first row la and with k rows in total." @@ -2520,7 +2585,6 @@ def PPs_with_first_row_la_and_with_k_rows(la, k): for mu in Partitions_inside_lambda(la): for PP in PPs_with_first_row_la_and_with_k_rows(mu, k-1): yield [la] + PP - return def complement(PP, c): "Return the complement of PP with respect to height c" @@ -2531,18 +2595,19 @@ def complement(PP, c): return [[c - PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] if b % 2 == 1: - for la in possible_middle_row_for_b_odd(a, c): # la is the middle row of SCPP + # la is the middle row of SCPP + for la in possible_middle_row_for_b_odd(a, c): for PP in PPs_with_first_row_la_and_with_k_rows(la, (b+1) // 2): PP_below = PP[1:] PP_above = complement(PP_below, c) yield self.element_class(self, PP_above + [la] + PP_below) else: - for la in possible_middle_row_for_b_even(a, c): # la is the middle ((a/2)+1)st row of SCPP + # la is the middle ((a/2)+1)st row of SCPP + for la in possible_middle_row_for_b_even(a, c): for PP in PPs_with_first_row_la_and_with_k_rows(la, b // 2): PP_below = PP PP_above = complement(PP_below, c) yield self.element_class(self, PP_above + PP_below) - return def cardinality(self) -> Integer: r""" @@ -2718,7 +2783,6 @@ def __iter__(self) -> Iterator: for p in PlanePartitions(self._box): if p.is_TCPP(): yield self.element_class(self, p) - return def cardinality(self) -> Integer: r""" @@ -2741,8 +2805,10 @@ def cardinality(self) -> Integer: a = self._box[0] c = self._box[2] return Integer(binomial(c // 2 + a - 1, a - 1) - * prod((c + i + j + 1) / (i + j + 1) - for j in range(1, a - 1) for i in range(1, 1 + j))) + * prod(c + i + j + 1 + for j in range(1, a - 1) for i in range(1, 1 + j)) + // prod(i + j + 1 + for j in range(1, a - 1) for i in range(1, 1 + j))) # Class 7 @@ -2797,14 +2863,22 @@ def __iter__(self) -> Iterator: EXAMPLES:: sage: list(PlanePartitions([4,4,2], symmetry='SSCPP')) - [Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 1], [1]], + [Plane partition [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], Plane partition [[2, 2, 2, 1], [2, 1, 1], [2, 1, 1], [1]], Plane partition [[2, 2, 1, 1], [2, 2, 1, 1], [1, 1], [1, 1]], + Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 1], [1]], Plane partition [[2, 2, 1, 1], [2, 1, 1, 1], [1, 1, 1], [1, 1]], - Plane partition [[2, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1]], - Plane partition [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]] + Plane partition [[2, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for a, b in cartesian_product([range(5), range(0, 5, 2)]) + ....: if (PP := PlanePartitions([a, a, b], symmetry='SSCPP'))) + True """ - for p in PlanePartitions(self._box): + # any SSCPP is a SPP + for p in PlanePartitions(self._box, symmetry='SPP'): if p.is_SSCPP(): yield self.element_class(self, p) @@ -2896,8 +2970,16 @@ def __iter__(self) -> Iterator: sage: list(PlanePartitions([2,2,2], symmetry='CSTCPP')) [Plane partition [[2, 1], [1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for n in range(0, 5, 2) + ....: if (PP := PlanePartitions([n]*3, symmetry='CSTCPP'))) + True """ - for p in PlanePartitions(self._box): + # any CSTCPP is a TSPP, a SSCPP and a CSSCPP + for p in PlanePartitions(self._box, symmetry='TSPP'): if p.is_CSTCPP(): yield self.element_class(self, p) @@ -2973,7 +3055,8 @@ def __iter__(self) -> Iterator: sage: list(PlanePartitions([2,2,2], symmetry='CSSCPP')) [Plane partition [[2, 1], [1]]] """ - for p in PlanePartitions(self._box): + # any CSSCPP is a SCPP and an CSPP, there are much fewer CSPP + for p in PlanePartitions(self._box, symmetry='CSPP'): if p.is_CSSCPP(): yield self.element_class(self, p) @@ -3191,7 +3274,6 @@ def __iter__(self) -> Iterator: """ for acl in self.to_poset().antichains_iterator(): yield self.from_antichain(acl) - return def cardinality(self) -> Integer: r""" From fb3570c5958c54a8913ffbc1faed8c8b273ca4af Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 23 Aug 2023 15:55:53 +0200 Subject: [PATCH 4/4] remove unnecessary long tags, introduce new long tag for slowest test --- src/sage/combinat/plane_partition.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 92630fa55d0..14d284b77c6 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -669,7 +669,7 @@ def plot(self, show_box=False, colors=None): EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.plot() # optional - sage.plot + sage: PP.plot() # optional - sage.plot Graphics object consisting of 27 graphics primitives """ from sage.functions.trig import cos, sin @@ -766,7 +766,7 @@ def plot3d(self, colors=None): EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.plot3d() # optional - sage.plot + sage: PP.plot3d() # optional - sage.plot Graphics3d Object """ if colors is None: @@ -1491,7 +1491,7 @@ def __init__(self): sage: from sage.combinat.plane_partition import PlanePartitions_all sage: P = PlanePartitions_all() - sage: TestSuite(P).run() # long time + sage: TestSuite(P).run() """ # We manually set these here rather than invoking the super().__init__(). # This is so DisjointUnionEnumeratedSets can make the Parent.__init__() call. @@ -1545,7 +1545,7 @@ def __init__(self, box_size): EXAMPLES:: sage: PP = PlanePartitions([4,3,2]) - sage: TestSuite(PP).run() + sage: TestSuite(PP).run() # long time """ super().__init__(box_size, category=FiniteEnumeratedSets()) @@ -2828,7 +2828,7 @@ def __init__(self, box_size): sage: TestSuite(PP).run() sage: PP = PlanePartitions([4, 4, 2], symmetry='SSCPP') - sage: TestSuite(PP).run() # long time + sage: TestSuite(PP).run() sage: PlanePartitions([4, 2, 2], symmetry='SSCPP') Traceback (most recent call last):